From patchwork Sun Oct 25 23:01:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1387347 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=AJBcDoQ5; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CKD4d4MSfz9sT6 for ; Mon, 26 Oct 2020 10:02:09 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1419706AbgJYXCD (ORCPT ); Sun, 25 Oct 2020 19:02:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41866 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1420347AbgJYXCC (ORCPT ); Sun, 25 Oct 2020 19:02:02 -0400 Received: from mail-lf1-x143.google.com (mail-lf1-x143.google.com [IPv6:2a00:1450:4864:20::143]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 430D8C061755; Sun, 25 Oct 2020 16:02:02 -0700 (PDT) Received: by mail-lf1-x143.google.com with SMTP id d24so9479324lfa.8; Sun, 25 Oct 2020 16:02:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=uupHzSrvUEtYcD/DIawVysd4yXQgmE4vD+y7+qxt6Iw=; b=AJBcDoQ58mATFLwlTwTItRFWQVcmqQ1tIZ2NQfKF0yDc/9iGdIjrOfEqx1eR4rOQdl Oab5qCdqCpN/fMQZK+ULorciKa+yhEXvMIpnwEcVUmkMKHeqnXbq0Hc9hMr1lB7KyF3M +3PB1poin9SXAsjJOju2O1XC7UhKDsFr8h/JMUgkPd5gpNAmPw3AMDwtCTlh9sRGb2AU HxCwKuAja7Z88O8cRtBVztRrCk82vLapY9TBU5D0UFuJqWhmxadMsVYWXbohV+AlKk2T WO7LDJ6n49CCMnrT6Az01xOxPaOpWLkc2Qfzi65NL0S9wBHLy1y8wZtYtg4fcBY2wE9i 5SDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=uupHzSrvUEtYcD/DIawVysd4yXQgmE4vD+y7+qxt6Iw=; b=E9uDUK4UyQHEbNqdIemZF52iSJuba1H1tr8AswDblk+2NCWs2brYLRUQKR2fjxcHIy fyv4oDyKU19mf0DVYFvNvUxsLs8NYb5Es8v70g0oARcco9arEz+dlTLNuCZTo1L99/V8 /pqvhGiuit10JRFzeh9R7bB5NDzYVeyz4Vu7f803WGYUO3f4+b/DkHzHOvCf+2EuHHcg IOd/kduvXoDnHrFTqwVgXe1GrH2pnwLNBMKh9QXGB6bS+dKuIMjwy3DO1tIbrPyBFcU7 BNGflSsWRmsSmdFlRYMqyCCLQuXWLyF71XOWktD5VgwA/gmTO2+HjZveY+Vvk3aEcO1e rUfw== X-Gm-Message-State: AOAM5302VFfIate0a2+PpMg0nW1AWpfaGMulDdETJzS0O/Imn30VKbeW UzKgZrqtSUgy/IZMmaGJ2p4= X-Google-Smtp-Source: ABdhPJyugY4FZ2dj6El1LLMqB/8omgv03JXh5ZB9dfebD8am/dPh14Egk8eK7tDgkZZdE5/3Dl8wpQ== X-Received: by 2002:a05:6512:3225:: with SMTP id f5mr3824479lfe.441.1603666920731; Sun, 25 Oct 2020 16:02:00 -0700 (PDT) Received: from localhost.localdomain (109-252-193-186.dynamic.spd-mgts.ru. [109.252.193.186]) by smtp.gmail.com with ESMTPSA id j16sm949619ljh.48.2020.10.25.16.01.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 Oct 2020 16:02:00 -0700 (PDT) From: Dmitry Osipenko To: Lee Jones , Rob Herring , Thierry Reding , Jonathan Hunter , Dan Murphy , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH RESEND v4 1/4] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding Date: Mon, 26 Oct 2020 02:01:50 +0300 Message-Id: <20201025230153.11729-2-digetx@gmail.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20201025230153.11729-1-digetx@gmail.com> References: <20201025230153.11729-1-digetx@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Add binding document for the ENE KB930 Embedded Controller. Reviewed-by: Rob Herring Signed-off-by: Dmitry Osipenko --- .../devicetree/bindings/mfd/ene-kb930.yaml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/ene-kb930.yaml diff --git a/Documentation/devicetree/bindings/mfd/ene-kb930.yaml b/Documentation/devicetree/bindings/mfd/ene-kb930.yaml new file mode 100644 index 000000000000..635c8966ca22 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/ene-kb930.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/ene-kb930.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ENE KB930 Embedded Controller bindings + +description: | + This binding describes the ENE KB930 Embedded Controller attached to an + I2C bus. + +maintainers: + - Dmitry Osipenko + +properties: + compatible: + items: + - enum: + - acer,a500-iconia-ec # Acer A500 Iconia tablet device + - enum: + - ene,kb930 + reg: + maxItems: 1 + + monitored-battery: true + power-supplies: true + system-power-controller: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + battery: battery-cell { + compatible = "simple-battery"; + charge-full-design-microamp-hours = <3260000>; + energy-full-design-microwatt-hours = <24000000>; + operating-range-celsius = <0 40>; + }; + + mains: ac-adapter { + compatible = "gpio-charger"; + charger-type = "mains"; + gpios = <&gpio 125 0>; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + embedded-controller@58 { + compatible = "acer,a500-iconia-ec", "ene,kb930"; + reg = <0x58>; + + system-power-controller; + + monitored-battery = <&battery>; + power-supplies = <&mains>; + }; + }; + +... From patchwork Sun Oct 25 23:01:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1387351 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=IuX4bdcv; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CKD4r2wj3z9sTD for ; Mon, 26 Oct 2020 10:02:20 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1420383AbgJYXCR (ORCPT ); Sun, 25 Oct 2020 19:02:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41870 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1420354AbgJYXCD (ORCPT ); Sun, 25 Oct 2020 19:02:03 -0400 Received: from mail-lf1-x143.google.com (mail-lf1-x143.google.com [IPv6:2a00:1450:4864:20::143]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 19B60C061755; Sun, 25 Oct 2020 16:02:03 -0700 (PDT) Received: by mail-lf1-x143.google.com with SMTP id a7so9461100lfk.9; Sun, 25 Oct 2020 16:02:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=YqWlegA0ek+s5nygUqKUAivUmzlJL24s2FNozZ5HuxA=; b=IuX4bdcvq95NVSSbcKgg1EuqCNkjwRm3mloJ0zHjuiRAgRNc+CtqPf5w9u1cTqhws7 ewf48bVmuA80UrZUN0XyVkO9mWvPM1aTZzL9boe+3IrThvPqVKYv9blu20n1ghgxsljZ Er1M4Pm1XutNqxds4vC/eRGiX/KsD8VQV9ClsX/YnN1T8xpiK4Uwqvw2gju0IAn8t0jX D7OWh8j9V2fUpJlQaouiauAoxWJPUf5KGz1H5EX/KeYCsa3ZRnnRUyZIlsytkK8zOt+Q KA2y4Cf8LcIVm8fYFD6xKJK7DGyf6HlhrpkJBVdwKlkUzjn3vHCeTuDngRFNL1/KOfBD PGJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=YqWlegA0ek+s5nygUqKUAivUmzlJL24s2FNozZ5HuxA=; b=AN2ZMtJ7YPMWcPsh1STDPTWc2r9ihXxzT2pWB15z+vMz2YannyQM4IJU7YGpfDNPVC r7UrO+ic5w9T0MB5Hb5Q/V7mN0ZfsmmznCtwKzopDUkKGkBW3talhaBVfZIPkHMuKXVQ bv3eykASElVO7COtlDtLaFYG7oNP2nF0jFnv3OXa1OE3oaSnk4G1Yxr8Q4JgXl0tNbJ/ t5T6TbPXgdJQX/kzW5QqQObSpxvCCi0aE7KvWmK/jsfey1l74hDibiyD1ytoadhxs64Z CUa3eu+CSi0jt4irHXqXwSGL2YZyh+r+rEa+YYB6b1GLIsnWyaDdwlJ1dWTUU/V99w/0 o+BQ== X-Gm-Message-State: AOAM533J/ezXnpk5KRSckHL9rsGABILVbdJqkR/k6BCMTbAtXgxBQ+SV SbLq/MhopqlvutflWKlTRRE= X-Google-Smtp-Source: ABdhPJzVbYLU9U+xsQkP89pQFKoFHjKOTZ0Vg395iSUNCEirdnXGkRRPP/tYXSyRGFJu23YAptALcQ== X-Received: by 2002:a19:6514:: with SMTP id z20mr3859746lfb.456.1603666921588; Sun, 25 Oct 2020 16:02:01 -0700 (PDT) Received: from localhost.localdomain (109-252-193-186.dynamic.spd-mgts.ru. [109.252.193.186]) by smtp.gmail.com with ESMTPSA id j16sm949619ljh.48.2020.10.25.16.02.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 Oct 2020 16:02:01 -0700 (PDT) From: Dmitry Osipenko To: Lee Jones , Rob Herring , Thierry Reding , Jonathan Hunter , Dan Murphy , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH RESEND v4 2/4] mfd: Add driver for Embedded Controller found on Acer Iconia Tab A500 Date: Mon, 26 Oct 2020 02:01:51 +0300 Message-Id: <20201025230153.11729-3-digetx@gmail.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20201025230153.11729-1-digetx@gmail.com> References: <20201025230153.11729-1-digetx@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Acer Iconia Tab A500 is an Android tablet device, it has ENE KB930 Embedded Controller which provides battery-gauge, LED, GPIO and some other functions. The EC uses firmware that is specifically customized for Acer A500. This patch adds MFD driver for the Embedded Controller which allows to power-off / reboot the A500 device, it also provides a common register read/write API that will be used by the sub-devices. Signed-off-by: Dmitry Osipenko --- drivers/mfd/Kconfig | 12 +++ drivers/mfd/Makefile | 1 + drivers/mfd/acer-ec-a500.c | 203 +++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 drivers/mfd/acer-ec-a500.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 8b99a13669bf..527ba5054d80 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2097,6 +2097,18 @@ config MFD_KHADAS_MCU additional drivers must be enabled in order to use the functionality of the device. +config MFD_ACER_A500_EC + tristate "Embedded Controller driver for Acer Iconia Tab A500" + depends on I2C + depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST + select MFD_CORE + select REGMAP + help + Support for Acer Iconia Tab A500 Embedded Controller. + + The controller itself is ENE KB930, it is running firmware + customized for the specific needs of the Acer A500 hardware. + menu "Multimedia Capabilities Port drivers" depends on ARCH_SA1100 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 1780019d2474..7bfc57c8b363 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -263,6 +263,7 @@ obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o obj-$(CONFIG_MFD_STMFX) += stmfx.o obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o +obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o diff --git a/drivers/mfd/acer-ec-a500.c b/drivers/mfd/acer-ec-a500.c new file mode 100644 index 000000000000..2785a6d9bcc4 --- /dev/null +++ b/drivers/mfd/acer-ec-a500.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MFD driver for Acer Iconia Tab A500 Embedded Controller. + * + * Copyright 2020 GRATE-driver project. + * + * Based on downstream driver from Acer Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define A500_EC_I2C_ERR_TIMEOUT 500 +#define A500_EC_POWER_CMD_TIMEOUT 1000 + +enum { + REG_CURRENT_NOW = 0x03, + REG_SHUTDOWN = 0x52, + REG_WARM_REBOOT = 0x54, + REG_COLD_REBOOT = 0x55, +}; + +static struct i2c_client *a500_ec_client_pm_off; + +static int a500_ec_read(void *context, const void *reg_buf, size_t reg_size, + void *val_buf, size_t val_sizel) +{ + struct i2c_client *client = context; + unsigned int reg, retries = 5; + u16 *ret_val = val_buf; + s32 ret = 0; + + if (reg_size != 1 || val_sizel != 2) + return -EOPNOTSUPP; + + reg = *(u8 *)reg_buf; + + while (retries-- > 0) { + ret = i2c_smbus_read_word_data(client, reg); + if (ret >= 0) + break; + + msleep(A500_EC_I2C_ERR_TIMEOUT); + } + + if (ret < 0) { + dev_err(&client->dev, "read 0x%x failed: %d\n", reg, ret); + return ret; + } + + *ret_val = ret; + + if (reg == REG_CURRENT_NOW) + fsleep(10000); + + return 0; +} + +static int a500_ec_write(void *context, const void *data, size_t count) +{ + struct i2c_client *client = context; + unsigned int reg, val, retries = 5; + s32 ret = 0; + + if (count != 3) + return -EOPNOTSUPP; + + reg = *(u8 *)(data + 0); + val = *(u16 *)(data + 1); + + while (retries-- > 0) { + ret = i2c_smbus_write_word_data(client, reg, val); + if (ret >= 0) + break; + + msleep(A500_EC_I2C_ERR_TIMEOUT); + } + + if (ret < 0) { + dev_err(&client->dev, "write 0x%x failed: %d\n", reg, ret); + return ret; + } + + return 0; +} + +static const struct regmap_config a500_ec_regmap_config = { + .name = "KB930", + .reg_bits = 8, + .val_bits = 16, + .max_register = 0xff, +}; + +static const struct regmap_bus a500_ec_regmap_bus = { + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_LITTLE, + .write = a500_ec_write, + .read = a500_ec_read, + .max_raw_read = 2, +}; + +static void a500_ec_poweroff(void) +{ + i2c_smbus_write_word_data(a500_ec_client_pm_off, REG_SHUTDOWN, 0); + + mdelay(A500_EC_POWER_CMD_TIMEOUT); +} + +static int a500_ec_restart_notify(struct notifier_block *this, + unsigned long reboot_mode, void *data) +{ + if (reboot_mode == REBOOT_WARM) + i2c_smbus_write_word_data(a500_ec_client_pm_off, + REG_WARM_REBOOT, 0); + else + i2c_smbus_write_word_data(a500_ec_client_pm_off, + REG_COLD_REBOOT, 1); + + mdelay(A500_EC_POWER_CMD_TIMEOUT); + + return NOTIFY_DONE; +} + +static struct notifier_block a500_ec_restart_handler = { + .notifier_call = a500_ec_restart_notify, + .priority = 200, +}; + +static const struct mfd_cell a500_ec_cells[] = { + { .name = "acer-a500-iconia-battery", }, + { .name = "acer-a500-iconia-leds", }, +}; + +static int a500_ec_probe(struct i2c_client *client) +{ + struct regmap *rmap; + int err; + + rmap = devm_regmap_init(&client->dev, &a500_ec_regmap_bus, + client, &a500_ec_regmap_config); + if (IS_ERR(rmap)) + return PTR_ERR(rmap); + + /* register battery and LED sub-devices */ + err = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, + a500_ec_cells, ARRAY_SIZE(a500_ec_cells), + NULL, 0, NULL); + if (err) { + dev_err(&client->dev, "failed to add sub-devices: %d\n", err); + return err; + } + + /* set up power management functions */ + if (of_device_is_system_power_controller(client->dev.of_node)) { + a500_ec_client_pm_off = client; + + err = register_restart_handler(&a500_ec_restart_handler); + if (err) + return err; + + if (!pm_power_off) + pm_power_off = a500_ec_poweroff; + } + + return 0; +} + +static int a500_ec_remove(struct i2c_client *client) +{ + if (of_device_is_system_power_controller(client->dev.of_node)) { + if (pm_power_off == a500_ec_poweroff) + pm_power_off = NULL; + + unregister_restart_handler(&a500_ec_restart_handler); + } + + return 0; +} + +static const struct of_device_id a500_ec_match[] = { + { .compatible = "acer,a500-iconia-ec" }, + { } +}; +MODULE_DEVICE_TABLE(of, a500_ec_match); + +static struct i2c_driver a500_ec_driver = { + .driver = { + .name = "acer-a500-embedded-controller", + .of_match_table = a500_ec_match, + }, + .probe_new = a500_ec_probe, + .remove = a500_ec_remove, +}; +module_i2c_driver(a500_ec_driver); + +MODULE_DESCRIPTION("Acer Iconia Tab A500 Embedded Controller driver"); +MODULE_AUTHOR("Dmitry Osipenko "); +MODULE_LICENSE("GPL"); From patchwork Sun Oct 25 23:01:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1387348 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=BHaaZ9DK; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CKD4f0DH7z9sTL for ; Mon, 26 Oct 2020 10:02:10 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1420363AbgJYXCH (ORCPT ); Sun, 25 Oct 2020 19:02:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41876 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1420359AbgJYXCG (ORCPT ); Sun, 25 Oct 2020 19:02:06 -0400 Received: from mail-lf1-x141.google.com (mail-lf1-x141.google.com [IPv6:2a00:1450:4864:20::141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 114DEC0613CE; Sun, 25 Oct 2020 16:02:04 -0700 (PDT) Received: by mail-lf1-x141.google.com with SMTP id h6so9473762lfj.3; Sun, 25 Oct 2020 16:02:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=77w4yjZmIJQHDCRHik6uDl4VQaZFvsvn77X3uS2Z2NE=; b=BHaaZ9DKLqcCh2jkjYGhz434hBE2VdOW4cAj3l+Obm3VnanJvkS+vFIFsy7E17j9kq WXnPbpvsdkGBdRVIzdj5e9tKjfI6bR1b3pc537ksgxanEO3+XlanClc5EQDzWW4Foo8a n2Wblh9b0AssNFkok6HbdQixJnGm1hh31SKhBQWBodvGHiw9doWGRoOIcaR5g8L4VevJ 5JCSzAwEhnVgJSLH+h6yNRFgZlB2wijTidxJF5x9z7YFLh1tKM1T3sHu2TxmI9zWTNIz iCU9ETRFEFD3wFBamTIftlCCFNFCQnvRgB299OZtIYEbb7ybFWya52e4CU4nrxHYS8ug 0K6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=77w4yjZmIJQHDCRHik6uDl4VQaZFvsvn77X3uS2Z2NE=; b=B72kP6vvVKovT7FOUBaAIRh1N4zliTyaHEv2uihZPOlqhYLUmZ+qEXuQYRliQPVdhw K1eZWCWQvmNk9MR5r+xigfMpSq3vfSc1VS9PLMt1LkbV07B2LoCfWzzPOpWiDDAh240f p5/KXFtt577//0ZuFwBHpCx9B/uPmO2ayq/xdvtvLonsyZmuRBc/NXDX/s8K5d5q9K5W YiLNoaqNhY3zoJ5ehKSXu4Z+mpgLt2AdCMoilSrMWVzve8o7K1fxQJjVY3uvH+ewIriW 7puILQabWxFAqhXCiQGw6hTV+mDSUb0n5JZvD2/9frP9dfWsYxlF+gLQlnWxjZ/tjHeJ 5kYg== X-Gm-Message-State: AOAM532sdGC14FyTRMeaJhHza97fOddjfm6W8mT2Esxel+i7Z6dG8Clc O47dgZnvOHbyiPTxYlmdgqBgBRQ0XdI= X-Google-Smtp-Source: ABdhPJxAa31jrgB2UdZLtXbtojn8R893rlNT07YqHYwlbg8j8cBFrQcnDCGZOvTkvZAog4Hj14BDFQ== X-Received: by 2002:ac2:5c4c:: with SMTP id s12mr3704185lfp.174.1603666922533; Sun, 25 Oct 2020 16:02:02 -0700 (PDT) Received: from localhost.localdomain (109-252-193-186.dynamic.spd-mgts.ru. [109.252.193.186]) by smtp.gmail.com with ESMTPSA id j16sm949619ljh.48.2020.10.25.16.02.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 Oct 2020 16:02:02 -0700 (PDT) From: Dmitry Osipenko To: Lee Jones , Rob Herring , Thierry Reding , Jonathan Hunter , Dan Murphy , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH RESEND v4 3/4] power: supply: Add battery gauge driver for Acer Iconia Tab A500 Date: Mon, 26 Oct 2020 02:01:52 +0300 Message-Id: <20201025230153.11729-4-digetx@gmail.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20201025230153.11729-1-digetx@gmail.com> References: <20201025230153.11729-1-digetx@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org This patch adds battery gauge driver for Acer Iconia Tab A500 device. The battery gauge function is provided via the Embedded Controller, which is found on the Acer A500. Reviewed-by: Sebastian Reichel Signed-off-by: Dmitry Osipenko --- drivers/power/supply/Kconfig | 6 + drivers/power/supply/Makefile | 1 + drivers/power/supply/acer_a500_battery.c | 297 +++++++++++++++++++++++ 3 files changed, 304 insertions(+) create mode 100644 drivers/power/supply/acer_a500_battery.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index eec646c568b7..bc493173ddbc 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -774,4 +774,10 @@ config RN5T618_POWER This driver can also be built as a module. If so, the module will be called rn5t618_power. +config BATTERY_ACER_A500 + tristate "Acer Iconia Tab A500 battery driver" + depends on MFD_ACER_A500_EC + help + Say Y to include support for Acer Iconia Tab A500 battery fuel gauge. + endif # POWER_SUPPLY diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index dd4b86318cd9..0607a3d64c0f 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -98,3 +98,4 @@ obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o +obj-$(CONFIG_BATTERY_ACER_A500) += acer_a500_battery.o diff --git a/drivers/power/supply/acer_a500_battery.c b/drivers/power/supply/acer_a500_battery.c new file mode 100644 index 000000000000..93135933c8af --- /dev/null +++ b/drivers/power/supply/acer_a500_battery.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Battery driver for Acer Iconia Tab A500. + * + * Copyright 2020 GRATE-driver project. + * + * Based on downstream driver from Acer Inc. + * Based on NVIDIA Gas Gauge driver for SBS Compliant Batteries. + * + * Copyright (c) 2010, NVIDIA Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include + +enum { + REG_CAPACITY, + REG_VOLTAGE, + REG_CURRENT, + REG_DESIGN_CAPACITY, + REG_TEMPERATURE, +}; + +#define EC_DATA(_reg, _psp) { \ + .psp = POWER_SUPPLY_PROP_ ## _psp, \ + .reg = _reg, \ +} + +static const struct battery_register { + enum power_supply_property psp; + unsigned int reg; +} ec_data[] = { + [REG_CAPACITY] = EC_DATA(0x00, CAPACITY), + [REG_VOLTAGE] = EC_DATA(0x01, VOLTAGE_NOW), + [REG_CURRENT] = EC_DATA(0x03, CURRENT_NOW), + [REG_DESIGN_CAPACITY] = EC_DATA(0x08, CHARGE_FULL_DESIGN), + [REG_TEMPERATURE] = EC_DATA(0x0a, TEMP), +}; + +static const enum power_supply_property a500_battery_properties[] = { + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + +struct a500_battery { + struct delayed_work poll_work; + struct power_supply *psy; + struct regmap *rmap; + unsigned int capacity; +}; + +static bool a500_battery_update_capacity(struct a500_battery *bat) +{ + unsigned int capacity; + int err; + + err = regmap_read(bat->rmap, ec_data[REG_CAPACITY].reg, &capacity); + if (err) + return false; + + /* capacity can be >100% even if max value is 100% */ + capacity = min(capacity, 100u); + + if (bat->capacity != capacity) { + bat->capacity = capacity; + return true; + } + + return false; +} + +static int a500_battery_get_status(struct a500_battery *bat) +{ + if (bat->capacity < 100) { + if (power_supply_am_i_supplied(bat->psy)) + return POWER_SUPPLY_STATUS_CHARGING; + else + return POWER_SUPPLY_STATUS_DISCHARGING; + } + + return POWER_SUPPLY_STATUS_FULL; +} + +static void a500_battery_unit_adjustment(struct device *dev, + enum power_supply_property psp, + union power_supply_propval *val) +{ + const unsigned int base_unit_conversion = 1000; + const unsigned int temp_kelvin_to_celsius = 2731; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval *= base_unit_conversion; + break; + + case POWER_SUPPLY_PROP_TEMP: + val->intval -= temp_kelvin_to_celsius; + break; + + case POWER_SUPPLY_PROP_PRESENT: + val->intval = !!val->intval; + break; + + default: + dev_dbg(dev, + "%s: no need for unit conversion %d\n", __func__, psp); + } +} + +static int a500_battery_get_ec_data_index(struct device *dev, + enum power_supply_property psp) +{ + unsigned int i; + + /* + * DESIGN_CAPACITY register always returns a non-zero value if + * battery is connected and zero if disconnected, hence we'll use + * it for judging the battery presence. + */ + if (psp == POWER_SUPPLY_PROP_PRESENT) + psp = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; + + for (i = 0; i < ARRAY_SIZE(ec_data); i++) + if (psp == ec_data[i].psp) + return i; + + dev_dbg(dev, "%s: invalid property %u\n", __func__, psp); + + return -EINVAL; +} + +static int a500_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct a500_battery *bat = power_supply_get_drvdata(psy); + struct device *dev = psy->dev.parent; + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = a500_battery_get_status(bat); + break; + + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + + case POWER_SUPPLY_PROP_CAPACITY: + a500_battery_update_capacity(bat); + val->intval = bat->capacity; + break; + + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + case POWER_SUPPLY_PROP_PRESENT: + case POWER_SUPPLY_PROP_TEMP: + ret = a500_battery_get_ec_data_index(dev, psp); + if (ret < 0) + break; + + ret = regmap_read(bat->rmap, ec_data[ret].reg, &val->intval); + break; + + default: + dev_err(dev, "%s: invalid property %u\n", __func__, psp); + return -EINVAL; + } + + if (!ret) { + /* convert units to match requirements of power supply class */ + a500_battery_unit_adjustment(dev, psp, val); + } + + dev_dbg(dev, "%s: property = %d, value = %x\n", + __func__, psp, val->intval); + + /* return NODATA for properties if battery not presents */ + if (ret) + return -ENODATA; + + return 0; +} + +static void a500_battery_poll_work(struct work_struct *work) +{ + struct a500_battery *bat; + bool capacity_changed; + + bat = container_of(work, struct a500_battery, poll_work.work); + capacity_changed = a500_battery_update_capacity(bat); + + if (capacity_changed) + power_supply_changed(bat->psy); + + /* continuously send uevent notification */ + schedule_delayed_work(&bat->poll_work, 30 * HZ); +} + +static const struct power_supply_desc a500_battery_desc = { + .name = "ec-battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = a500_battery_properties, + .get_property = a500_battery_get_property, + .num_properties = ARRAY_SIZE(a500_battery_properties), + .external_power_changed = power_supply_changed, +}; + +static int a500_battery_probe(struct platform_device *pdev) +{ + struct power_supply_config psy_cfg = {}; + struct a500_battery *bat; + + bat = devm_kzalloc(&pdev->dev, sizeof(*bat), GFP_KERNEL); + if (!bat) + return -ENOMEM; + + platform_set_drvdata(pdev, bat); + + psy_cfg.of_node = pdev->dev.parent->of_node; + psy_cfg.drv_data = bat; + + bat->rmap = dev_get_regmap(pdev->dev.parent, "KB930"); + if (!bat->rmap) + return -EINVAL; + + bat->psy = devm_power_supply_register_no_ws(&pdev->dev, + &a500_battery_desc, + &psy_cfg); + if (IS_ERR(bat->psy)) + return dev_err_probe(&pdev->dev, PTR_ERR(bat->psy), + "failed to register battery\n"); + + INIT_DELAYED_WORK(&bat->poll_work, a500_battery_poll_work); + schedule_delayed_work(&bat->poll_work, HZ); + + return 0; +} + +static int a500_battery_remove(struct platform_device *pdev) +{ + struct a500_battery *bat = dev_get_drvdata(&pdev->dev); + + cancel_delayed_work_sync(&bat->poll_work); + + return 0; +} + +static int __maybe_unused a500_battery_suspend(struct device *dev) +{ + struct a500_battery *bat = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&bat->poll_work); + + return 0; +} + +static int __maybe_unused a500_battery_resume(struct device *dev) +{ + struct a500_battery *bat = dev_get_drvdata(dev); + + schedule_delayed_work(&bat->poll_work, HZ); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(a500_battery_pm_ops, + a500_battery_suspend, a500_battery_resume); + +static struct platform_driver a500_battery_driver = { + .driver = { + .name = "acer-a500-iconia-battery", + .pm = &a500_battery_pm_ops, + }, + .probe = a500_battery_probe, + .remove = a500_battery_remove, +}; +module_platform_driver(a500_battery_driver); + +MODULE_DESCRIPTION("Battery gauge driver for Acer Iconia Tab A500"); +MODULE_AUTHOR("Dmitry Osipenko "); +MODULE_ALIAS("platform:acer-a500-iconia-battery"); +MODULE_LICENSE("GPL"); From patchwork Sun Oct 25 23:01:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1387349 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=bWrAJRoI; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CKD4k2Yshz9sT6 for ; Mon, 26 Oct 2020 10:02:14 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1420367AbgJYXCI (ORCPT ); Sun, 25 Oct 2020 19:02:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41880 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1420347AbgJYXCF (ORCPT ); Sun, 25 Oct 2020 19:02:05 -0400 Received: from mail-lf1-x143.google.com (mail-lf1-x143.google.com [IPv6:2a00:1450:4864:20::143]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E51C0C0613D0; Sun, 25 Oct 2020 16:02:04 -0700 (PDT) Received: by mail-lf1-x143.google.com with SMTP id a7so9461161lfk.9; Sun, 25 Oct 2020 16:02:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=A4jvJLNRl5Rus88Pe6yoUdqX7U2UtFHR9HWnEH2FGao=; b=bWrAJRoIe/SdHvtJParQapNN61WM14ZwkxmpzYOvQ7MalOvTC+zvfOrTEv8WSeNwYR VgXbvPWi0s0pgdb4HucRveayHco8KLJy7mnsprPZIpz+c0jSVjVAE1XVwQ4fs2iYlVW3 qfrqYozy46t+mtqBHdTE7a6KesxD7d1oa6Y63IpKsZ5detb7nm64cufHRMEqIXdW3Qpk iFmZtCO5+2o2j1Q7dUUGZzxN+byOyzpdePKInBdkHyLnK6IhzFY3JT6SlwDi3juYIock yVheL8zYPL6dfz7+9jvCRKqYB4jqJB+FlGPLLo62QSb94y/6sahEkKqONnPjueuhUJOd wO8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=A4jvJLNRl5Rus88Pe6yoUdqX7U2UtFHR9HWnEH2FGao=; b=BvQ3JBiclmTDxGKR7pzhGRSVS2usPlVcr6MzJdHB3MSKUNQXA/UEdhQdsHhIMI0odt BQqvbCEkApJCBQSNTXz+h9hSmVPUrVsRQkq5tWoIaPfvLqWlvHZZRUO6rXMK30tZyw1O 7fr2h5oxcd/Ri/OKLUYtOYVTCdhm5QZe7hvocnp5fARHTL0kaDPNtV2mPXk1MZldyod5 TF6uNlfTSCuJWuoDdfTJPRuDH2YuRY+WmO/5I99ZtHY4B2SJxTQKzCkAGuejKRKmL1LY 2WIlSV78b93Y2GGqwxskzkBFSYeGjffMSu8zx81bYpXQXxsuev6tlu7m+GyWHPVlMATx 3Zlw== X-Gm-Message-State: AOAM533AAbD++Uan4njKcccd9F8n5hXZ7QFoU8Jtb3XzNmeyTnf4AjuS 7NZNGAAICQyuQtqZsn9RKys= X-Google-Smtp-Source: ABdhPJzFShGHnktOW5DkqTmDfBkPbAip5YSz6AMw9q3iufpT4y7RXw7iavuJlF/CT9O9q2/zxq48EA== X-Received: by 2002:a05:6512:313c:: with SMTP id p28mr3742790lfd.310.1603666923476; Sun, 25 Oct 2020 16:02:03 -0700 (PDT) Received: from localhost.localdomain (109-252-193-186.dynamic.spd-mgts.ru. [109.252.193.186]) by smtp.gmail.com with ESMTPSA id j16sm949619ljh.48.2020.10.25.16.02.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 Oct 2020 16:02:03 -0700 (PDT) From: Dmitry Osipenko To: Lee Jones , Rob Herring , Thierry Reding , Jonathan Hunter , Dan Murphy , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH RESEND v4 4/4] ARM: tegra: acer-a500: Add Embedded Controller Date: Mon, 26 Oct 2020 02:01:53 +0300 Message-Id: <20201025230153.11729-5-digetx@gmail.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20201025230153.11729-1-digetx@gmail.com> References: <20201025230153.11729-1-digetx@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org This patch adds device-tree node for the Embedded Controller which is found on the Picasso board. The Embedded Controller itself is ENE KB930, it provides functions like battery-gauge/LED/GPIO/etc and it uses firmware that is specifically customized for the Acer A500 device. Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra20-acer-a500-picasso.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts index f5c1591c8ea8..480a2221bf58 100644 --- a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts +++ b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts @@ -512,6 +512,16 @@ panel_ddc: i2c@1 { reg = <1>; #address-cells = <1>; #size-cells = <0>; + + embedded-controller@58 { + compatible = "acer,a500-iconia-ec", "ene,kb930"; + reg = <0x58>; + + system-power-controller; + + monitored-battery = <&bat1010>; + power-supplies = <&mains>; + }; }; }; @@ -794,6 +804,13 @@ backlight: backlight { default-brightness-level = <20>; }; + bat1010: battery-2s1p { + compatible = "simple-battery"; + charge-full-design-microamp-hours = <3260000>; + energy-full-design-microwatt-hours = <24000000>; + operating-range-celsius = <0 40>; + }; + /* PMIC has a built-in 32KHz oscillator which is used by PMC */ clk32k_in: clock@0 { compatible = "fixed-clock";