From 307b0d631d133318b9af9a43ea748e46a1a3b1ed Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 17 Jun 2020 12:23:04 +0200 Subject: dt-bindings: power: supply: bq25890: Indent example with tabs Fix example indentation to tabs to follow generic Linux coding style. This avoids copying the space indentation to DTS when re-using the example. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/supply/bq25890.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/bq25890.txt b/Documentation/devicetree/bindings/power/supply/bq25890.txt index dc9c8f76e06c..51ecc756521f 100644 --- a/Documentation/devicetree/bindings/power/supply/bq25890.txt +++ b/Documentation/devicetree/bindings/power/supply/bq25890.txt @@ -36,17 +36,17 @@ Optional properties: Example: bq25890 { - compatible = "ti,bq25890"; - reg = <0x6a>; + compatible = "ti,bq25890"; + reg = <0x6a>; - ti,battery-regulation-voltage = <4200000>; - ti,charge-current = <1000000>; - ti,termination-current = <50000>; - ti,precharge-current = <128000>; - ti,minimum-sys-voltage = <3600000>; - ti,boost-voltage = <5000000>; - ti,boost-max-current = <1000000>; + ti,battery-regulation-voltage = <4200000>; + ti,charge-current = <1000000>; + ti,termination-current = <50000>; + ti,precharge-current = <128000>; + ti,minimum-sys-voltage = <3600000>; + ti,boost-voltage = <5000000>; + ti,boost-max-current = <1000000>; - ti,use-ilim-pin; - ti,thermal-regulation-threshold = <120>; + ti,use-ilim-pin; + ti,thermal-regulation-threshold = <120>; }; -- cgit v1.2.3 From 0768e6e4934e239f1a7f8ba83150a7c46765bb3e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 17 Jun 2020 12:23:05 +0200 Subject: dt-bindings: power: supply: bq25890: Document required interrupt The driver requires interrupts (fails probe if it is not provided) so document this requirement in bindings. Fixes: 4aeae9cb0dad ("power_supply: Add support for TI BQ25890 charger chip") Cc: Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- Documentation/devicetree/bindings/power/supply/bq25890.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/bq25890.txt b/Documentation/devicetree/bindings/power/supply/bq25890.txt index 51ecc756521f..3b4c69a7fa70 100644 --- a/Documentation/devicetree/bindings/power/supply/bq25890.txt +++ b/Documentation/devicetree/bindings/power/supply/bq25890.txt @@ -10,6 +10,7 @@ Required properties: * "ti,bq25895" * "ti,bq25896" - reg: integer, i2c address of the device. +- interrupts: interrupt line; - ti,battery-regulation-voltage: integer, maximum charging voltage (in uV); - ti,charge-current: integer, maximum charging current (in uA); - ti,termination-current: integer, charge will be terminated when current in @@ -39,6 +40,9 @@ bq25890 { compatible = "ti,bq25890"; reg = <0x6a>; + interrupt-parent = <&gpio1>; + interrupts = <16 IRQ_TYPE_EDGE_FALLING>; + ti,battery-regulation-voltage = <4200000>; ti,charge-current = <1000000>; ti,termination-current = <50000>; -- cgit v1.2.3 From 224941c9424fd840bd54d2df8dbe84d1e4aa35af Mon Sep 17 00:00:00 2001 From: Wang Qing Date: Fri, 12 Jun 2020 14:55:54 +0800 Subject: power: supply: use kobj_to_dev Use kobj_to_dev() API instead of open-coded container_of(). Signed-off-by: Wang Qing Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index bc79560229b5..af0cad253f52 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -343,7 +343,7 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj, struct attribute *attr, int attrno) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct power_supply *psy = dev_get_drvdata(dev); umode_t mode = S_IRUSR | S_IRGRP | S_IROTH; int i; -- cgit v1.2.3 From 596f4785f498baf28be2d5dec067695d85457b09 Mon Sep 17 00:00:00 2001 From: Keyur Patel Date: Tue, 9 Jun 2020 18:50:35 -0400 Subject: power: supply: axp20x_usb_power: fix spelling mistake Fix typo: "triger" --> "trigger" Signed-off-by: Keyur Patel Acked-by: Chen-Yu Tsai Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp20x_usb_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index 4fde24b5f35a..d01dc0332edc 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -78,7 +78,7 @@ static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power) /* * Polling is only necessary while VBUS is offline. While online, a * present->absent transition implies an online->offline transition - * and will triger the VBUS_REMOVAL IRQ. + * and will trigger the VBUS_REMOVAL IRQ. */ if (power->axp20x_id >= AXP221_ID && !power->online) return true; -- cgit v1.2.3 From dad980f13243281b8231a1a3365ce380f312f825 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 6 Jun 2020 00:43:58 +0200 Subject: dt-bindings: power: supply: gpio-charger: convert to yaml Convert the gpio-charger bindings from text format to new YAML based representation. Reviewed-by: Linus Walleij Reviewed-by: Rob Herring Signed-off-by: Sebastian Reichel --- .../bindings/power/supply/gpio-charger.txt | 31 ------------ .../bindings/power/supply/gpio-charger.yaml | 58 ++++++++++++++++++++++ 2 files changed, 58 insertions(+), 31 deletions(-) delete mode 100644 Documentation/devicetree/bindings/power/supply/gpio-charger.txt create mode 100644 Documentation/devicetree/bindings/power/supply/gpio-charger.yaml diff --git a/Documentation/devicetree/bindings/power/supply/gpio-charger.txt b/Documentation/devicetree/bindings/power/supply/gpio-charger.txt deleted file mode 100644 index 0fb33b2c62a6..000000000000 --- a/Documentation/devicetree/bindings/power/supply/gpio-charger.txt +++ /dev/null @@ -1,31 +0,0 @@ -gpio-charger - -Required properties : - - compatible : "gpio-charger" - - gpios : GPIO indicating the charger presence. - See GPIO binding in bindings/gpio/gpio.txt . - - charger-type : power supply type, one of - unknown - battery - ups - mains - usb-sdp (USB standard downstream port) - usb-dcp (USB dedicated charging port) - usb-cdp (USB charging downstream port) - usb-aca (USB accessory charger adapter) - -Optional properties: - - charge-status-gpios: GPIO indicating whether a battery is charging. - -Example: - - usb_charger: charger { - compatible = "gpio-charger"; - charger-type = "usb-sdp"; - gpios = <&gpd 28 GPIO_ACTIVE_LOW>; - charge-status-gpios = <&gpc 27 GPIO_ACTIVE_LOW>; - }; - - battery { - power-supplies = <&usb_charger>; - }; diff --git a/Documentation/devicetree/bindings/power/supply/gpio-charger.yaml b/Documentation/devicetree/bindings/power/supply/gpio-charger.yaml new file mode 100644 index 000000000000..78b167c62ab1 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/gpio-charger.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/gpio-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: simple battery chargers only communicating through GPIOs + +maintainers: + - Sebastian Reichel + +description: + This binding is for all chargers, which are working more or less + autonomously, only providing some status GPIOs and possibly some + GPIOs for limited control over the charging process. + +properties: + compatible: + const: gpio-charger + + charger-type: + enum: + - unknown + - battery + - ups + - mains + - usb-sdp # USB standard downstream port + - usb-dcp # USB dedicated charging port + - usb-cdp # USB charging downstream port + - usb-aca # USB accessory charger adapter + description: + Type of the charger, e.g. "mains" for a wall charger. + + gpios: + maxItems: 1 + description: GPIO indicating the charger presence + + charge-status-gpios: + maxItems: 1 + description: GPIO indicating the charging status + +required: + - compatible + - gpios + +additionalProperties: false + +examples: + - | + #include + + charger { + compatible = "gpio-charger"; + charger-type = "usb-sdp"; + + gpios = <&gpd 28 GPIO_ACTIVE_LOW>; + charge-status-gpios = <&gpc 27 GPIO_ACTIVE_LOW>; + }; -- cgit v1.2.3 From 1d85f6d1b0c11f15ec2b1a9719da8118f3f94e64 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 6 Jun 2020 00:43:59 +0200 Subject: power: supply: gpio-charger: Make gpios optional While strongly recommended, not all devices have a gpio to detect if the charger is connected. This moves the 'gpios' from required to optional section. This also modifies error handling for the GPIO a bit: We no longer fallback to pdata, if a GPIO is specified using GPIO descriptor tables. This is a bit cleaner and does not have any real impact: There are only two mainline pdata users (arm/mach-sa1100/collie.c, arm/mach-pxa/tosa.c) and none of them specify the GPIO via gpiod descriptor tables. Once both have been converted the driver's support for specifying GPIOs numbers in pdata will be dropped. Reviewed-by: Linus Walleij Acked-by: Rob Herring Signed-off-by: Sebastian Reichel --- .../bindings/power/supply/gpio-charger.yaml | 7 +++- drivers/power/supply/gpio-charger.c | 38 ++++++++++++++-------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/gpio-charger.yaml b/Documentation/devicetree/bindings/power/supply/gpio-charger.yaml index 78b167c62ab1..30eabbb14ef3 100644 --- a/Documentation/devicetree/bindings/power/supply/gpio-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/gpio-charger.yaml @@ -41,7 +41,12 @@ properties: required: - compatible - - gpios + +anyOf: + - required: + - gpios + - required: + - charge-status-gpios additionalProperties: false diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c index 1b959c7f8b0e..875735d50716 100644 --- a/drivers/power/supply/gpio-charger.c +++ b/drivers/power/supply/gpio-charger.c @@ -112,9 +112,14 @@ static int gpio_charger_get_irq(struct device *dev, void *dev_id, return irq; } +/* + * The entries will be overwritten by driver's probe routine depending + * on the available features. This list ensures, that the array is big + * enough for all optional features. + */ static enum power_supply_property gpio_charger_properties[] = { POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_STATUS /* Must always be last in the array. */ + POWER_SUPPLY_PROP_STATUS, }; static int gpio_charger_probe(struct platform_device *pdev) @@ -128,6 +133,7 @@ static int gpio_charger_probe(struct platform_device *pdev) int charge_status_irq; unsigned long flags; int ret; + int num_props = 0; if (!pdata && !dev->of_node) { dev_err(dev, "No platform data\n"); @@ -142,13 +148,13 @@ static int gpio_charger_probe(struct platform_device *pdev) * This will fetch a GPIO descriptor from device tree, ACPI or * boardfile descriptor tables. It's good to try this first. */ - gpio_charger->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN); + gpio_charger->gpiod = devm_gpiod_get_optional(dev, NULL, GPIOD_IN); /* - * If this fails and we're not using device tree, try the - * legacy platform data method. + * Fallback to legacy platform data method, if no GPIO is specified + * using boardfile descriptor tables. */ - if (IS_ERR(gpio_charger->gpiod) && !dev->of_node) { + if (!gpio_charger->gpiod && pdata) { /* Non-DT: use legacy GPIO numbers */ if (!gpio_is_valid(pdata->gpio)) { dev_err(dev, "Invalid gpio pin in pdata\n"); @@ -173,17 +179,23 @@ static int gpio_charger_probe(struct platform_device *pdev) return PTR_ERR(gpio_charger->gpiod); } + if (gpio_charger->gpiod) { + gpio_charger_properties[num_props] = POWER_SUPPLY_PROP_ONLINE; + num_props++; + } + charge_status = devm_gpiod_get_optional(dev, "charge-status", GPIOD_IN); - gpio_charger->charge_status = charge_status; - if (IS_ERR(gpio_charger->charge_status)) - return PTR_ERR(gpio_charger->charge_status); + if (IS_ERR(charge_status)) + return PTR_ERR(charge_status); + if (charge_status) { + gpio_charger->charge_status = charge_status; + gpio_charger_properties[num_props] = POWER_SUPPLY_PROP_STATUS; + num_props++; + } charger_desc = &gpio_charger->charger_desc; charger_desc->properties = gpio_charger_properties; - charger_desc->num_properties = ARRAY_SIZE(gpio_charger_properties); - /* Remove POWER_SUPPLY_PROP_STATUS from the supported properties. */ - if (!gpio_charger->charge_status) - charger_desc->num_properties -= 1; + charger_desc->num_properties = num_props; charger_desc->get_property = gpio_charger_get_property; psy_cfg.of_node = dev->of_node; @@ -269,6 +281,6 @@ static struct platform_driver gpio_charger_driver = { module_platform_driver(gpio_charger_driver); MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO"); +MODULE_DESCRIPTION("Driver for chargers only communicating via GPIO(s)"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:gpio-charger"); -- cgit v1.2.3 From 05e0430971543e6aeb328df1226dc52930171445 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 6 Jun 2020 01:06:24 +0200 Subject: power: supply: sbs-battery: use i2c_smbus_read_block_data() The SBS battery implements SMBus block reads. Currently the driver "emulates" this by doing an I2C byte read for the length followed by an I2C block read. The I2C subsystem actually provides a proper API for doing SMBus block reads, which can and should be used instead. The current implementation does not properly handle packet error checking (PEC). Not all upstream systems using sbs-battery have I2C bus drivers supporting I2C_M_RECV_LEN, so old implementation is kept as fallback to keep things working. But this prints a warning, which hopefully results in people implementing support for it. Tested-by: Marek Szyprowski Signed-off-by: Sebastian Reichel --- drivers/power/supply/sbs-battery.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index 83b9924033bd..74221b9279a9 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -263,8 +263,7 @@ static int sbs_read_word_data(struct i2c_client *client, u8 address) return ret; } -static int sbs_read_string_data(struct i2c_client *client, u8 address, - char *values) +static int sbs_read_string_data_fallback(struct i2c_client *client, u8 address, char *values) { struct sbs_info *chip = i2c_get_clientdata(client); s32 ret = 0, block_length = 0; @@ -274,6 +273,8 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address, retries_length = chip->i2c_retry_count; retries_block = chip->i2c_retry_count; + dev_warn_once(&client->dev, "I2C adapter does not support I2C_FUNC_SMBUS_READ_BLOCK_DATA.\n"); + /* Adapter needs to support these two functions */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | @@ -329,6 +330,32 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address, return ret; } +static int sbs_read_string_data(struct i2c_client *client, u8 address, char *values) +{ + struct sbs_info *chip = i2c_get_clientdata(client); + int retries = chip->i2c_retry_count; + int ret = 0; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) + return sbs_read_string_data_fallback(client, address, values); + + while (retries > 0) { + ret = i2c_smbus_read_block_data(client, address, values); + if (ret >= 0) + break; + retries--; + } + + if (ret < 0) { + dev_dbg(&client->dev, "failed to read block 0x%x: %d\n", address, ret); + return ret; + } + + /* add string termination */ + values[ret] = '\0'; + return ret; +} + static int sbs_write_word_data(struct i2c_client *client, u8 address, u16 value) { -- cgit v1.2.3 From 7222bd603dd2fe607794acd0c53025da1dbde21f Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 6 Jun 2020 01:06:25 +0200 Subject: power: supply: sbs-battery: add PEC support SBS batteries optionally have support for PEC. This enables PEC handling based on the implemented SBS version as suggested by the standard. The support for PEC is re-evaluated when the battery is hotplugged into the system, since there might be systems supporting batteries from different SBS generations. Tested-by: Marek Szyprowski Signed-off-by: Sebastian Reichel --- drivers/power/supply/sbs-battery.c | 64 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index 74221b9279a9..49c3508a6b79 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -51,6 +51,14 @@ enum { REG_CHARGE_VOLTAGE, }; +#define REG_ADDR_SPEC_INFO 0x1A +#define SPEC_INFO_VERSION_MASK GENMASK(7, 4) +#define SPEC_INFO_VERSION_SHIFT 4 + +#define SBS_VERSION_1_0 1 +#define SBS_VERSION_1_1 2 +#define SBS_VERSION_1_1_WITH_PEC 3 + #define REG_ADDR_MANUFACTURE_DATE 0x1B /* Battery Mode defines */ @@ -224,14 +232,57 @@ exit: static int sbs_update_presence(struct sbs_info *chip, bool is_present) { + struct i2c_client *client = chip->client; + int retries = chip->i2c_retry_count; + s32 ret = 0; + u8 version; + if (chip->is_present == is_present) return 0; if (!is_present) { chip->is_present = false; + /* Disable PEC when no device is present */ + client->flags &= ~I2C_CLIENT_PEC; return 0; } + /* Check if device supports packet error checking and use it */ + while (retries > 0) { + ret = i2c_smbus_read_word_data(client, REG_ADDR_SPEC_INFO); + if (ret >= 0) + break; + + /* + * Some batteries trigger the detection pin before the + * I2C bus is properly connected. This works around the + * issue. + */ + msleep(100); + + retries--; + } + + if (ret < 0) { + dev_dbg(&client->dev, "failed to read spec info: %d\n", ret); + + /* fallback to old behaviour */ + client->flags &= ~I2C_CLIENT_PEC; + chip->is_present = true; + + return ret; + } + + version = (ret & SPEC_INFO_VERSION_MASK) >> SPEC_INFO_VERSION_SHIFT; + + if (version == SBS_VERSION_1_1_WITH_PEC) + client->flags |= I2C_CLIENT_PEC; + else + client->flags &= ~I2C_CLIENT_PEC; + + dev_dbg(&client->dev, "PEC: %s\n", (client->flags & I2C_CLIENT_PEC) ? + "enabled" : "disabled"); + if (!chip->is_present && is_present && !chip->charger_broadcasts) sbs_disable_charger_broadcasts(chip); @@ -273,7 +324,8 @@ static int sbs_read_string_data_fallback(struct i2c_client *client, u8 address, retries_length = chip->i2c_retry_count; retries_block = chip->i2c_retry_count; - dev_warn_once(&client->dev, "I2C adapter does not support I2C_FUNC_SMBUS_READ_BLOCK_DATA.\n"); + dev_warn_once(&client->dev, "I2C adapter does not support I2C_FUNC_SMBUS_READ_BLOCK_DATA.\n" + "Fallback method does not support PEC.\n"); /* Adapter needs to support these two functions */ if (!i2c_check_functionality(client->adapter, @@ -336,8 +388,14 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address, char *val int retries = chip->i2c_retry_count; int ret = 0; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) - return sbs_read_string_data_fallback(client, address, values); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { + bool pec = client->flags & I2C_CLIENT_PEC; + client->flags &= ~I2C_CLIENT_PEC; + ret = sbs_read_string_data_fallback(client, address, values); + if (pec) + client->flags |= I2C_CLIENT_PEC; + return ret; + } while (retries > 0) { ret = i2c_smbus_read_block_data(client, address, values); -- cgit v1.2.3 From 1a37a039711610dd53ec03d8cab9e81875338225 Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Mon, 25 May 2020 19:05:40 +0800 Subject: power: supply: bq24190_charger: Fix runtime PM imbalance on error pm_runtime_get_sync() increments the runtime PM usage counter even it returns an error code. Thus a pairing decrement is needed on the error handling path to keep the counter balanced. Signed-off-by: Dinghao Liu Reviewed-by: Rafael J. Wysocki Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 4540e913057f..d14186525e1e 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -481,8 +481,10 @@ static ssize_t bq24190_sysfs_store(struct device *dev, return ret; ret = pm_runtime_get_sync(bdi->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(bdi->dev); return ret; + } ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v); if (ret) -- cgit v1.2.3 From 5d809cb28056221e1b13459f7a2ddfa28305b74f Mon Sep 17 00:00:00 2001 From: Jonathan Bakker Date: Sat, 16 May 2020 15:35:44 -0700 Subject: power: supply: max8998_charger: Correct ONLINE and add STATUS props The ONLINE prop should be when the charger is present (ie able to charge), however, it was for when it was actually charging or not. Instead, add the STATUS prop to show whether charging is actually going on or not. The magic numbers have been ported from a downstream kernel for the SGH-T959V. Signed-off-by: Jonathan Bakker Signed-off-by: Sebastian Reichel --- drivers/power/supply/max8998_charger.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/max8998_charger.c b/drivers/power/supply/max8998_charger.c index 9a926c7c0f22..c26023b19f26 100644 --- a/drivers/power/supply/max8998_charger.c +++ b/drivers/power/supply/max8998_charger.c @@ -23,6 +23,7 @@ struct max8998_battery_data { static enum power_supply_property max8998_battery_props[] = { POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */ POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */ + POWER_SUPPLY_PROP_STATUS, /* charger is charging/discharging/full */ }; /* Note that the charger control is done by a current regulator "CHARGER" */ @@ -49,10 +50,28 @@ static int max8998_battery_get_property(struct power_supply *psy, ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, ®); if (ret) return ret; - if (reg & (1 << 3)) - val->intval = 0; - else + + if (reg & (1 << 5)) val->intval = 1; + else + val->intval = 0; + + break; + case POWER_SUPPLY_PROP_STATUS: + ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, ®); + if (ret) + return ret; + + if (!(reg & (1 << 5))) { + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + } else { + if (reg & (1 << 6)) + val->intval = POWER_SUPPLY_STATUS_FULL; + else if (reg & (1 << 3)) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + } break; default: return -EINVAL; -- cgit v1.2.3 From 98cc1b93724aa85bd828269855d48d884c702726 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 20 Jul 2020 15:43:57 -0500 Subject: power_supply: Add additional health properties to the header Add HEALTH_WARM, HEALTH_COOL and HEALTH_HOT to the health enum. HEALTH_WARM, HEALTH_COOL, and HEALTH_HOT properties are taken from JEITA specification JISC8712:2015 Acked-by: Andrew F. Davis Tested-by: Guru Das Srinagesh Signed-off-by: Dan Murphy Signed-off-by: Sebastian Reichel --- Documentation/ABI/testing/sysfs-class-power | 3 ++- drivers/power/supply/power_supply_sysfs.c | 3 +++ include/linux/power_supply.h | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index 216d61a22f1e..40213c73bc9c 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -205,7 +205,8 @@ Description: Valid values: "Unknown", "Good", "Overheat", "Dead", "Over voltage", "Unspecified failure", "Cold", "Watchdog timer expire", "Safety timer expire", - "Over current", "Calibration required" + "Over current", "Calibration required", "Warm", + "Cool", "Hot" What: /sys/class/power_supply//precharge_current Date: June 2017 diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index af0cad253f52..b903cb4dca2b 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -101,6 +101,9 @@ static const char * const POWER_SUPPLY_HEALTH_TEXT[] = { [POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE] = "Safety timer expire", [POWER_SUPPLY_HEALTH_OVERCURRENT] = "Over current", [POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED] = "Calibration required", + [POWER_SUPPLY_HEALTH_WARM] = "Warm", + [POWER_SUPPLY_HEALTH_COOL] = "Cool", + [POWER_SUPPLY_HEALTH_HOT] = "Hot", }; static const char * const POWER_SUPPLY_TECHNOLOGY_TEXT[] = { diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index ac1345a48ad0..b5ee35d3c304 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -62,6 +62,9 @@ enum { POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE, POWER_SUPPLY_HEALTH_OVERCURRENT, POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED, + POWER_SUPPLY_HEALTH_WARM, + POWER_SUPPLY_HEALTH_COOL, + POWER_SUPPLY_HEALTH_HOT, }; enum { -- cgit v1.2.3 From 8f7bda7a666df40d8e6d590159c30498795f413a Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Mon, 20 Jul 2020 15:43:59 -0500 Subject: dt-bindings: power: Add the bindings for the bq2515x family of chargers. The BQ2515X family of devices are highly integrated battery management ICs that integrate the most common functions for wearable devices namely a charger, an output voltage rail, ADC for battery and system monitoring, and a push-button controller. Datasheets: http://www.ti.com/lit/ds/symlink/bq25150.pdf http://www.ti.com/lit/ds/symlink/bq25155.pdf Reviewed-by: Rob Herring Signed-off-by: Ricardo Rivera-Matos Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/supply/bq2515x.yaml | 93 ++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/bq2515x.yaml diff --git a/Documentation/devicetree/bindings/power/supply/bq2515x.yaml b/Documentation/devicetree/bindings/power/supply/bq2515x.yaml new file mode 100644 index 000000000000..75a56773be4a --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/bq2515x.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright (C) 2020 Texas Instruments Incorporated +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/power/supply/bq2515x.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: TI bq2515x 500-mA Linear charger family + +maintainers: + - Dan Murphy + - Ricardo Rivera-Matos + +description: | + The BQ2515x family is a highly integrated battery charge management IC that + integrates the most common functions for wearable devices, namely a charger, + an output voltage rail, ADC for battery and system monitoring, and + push-button controller. + + Specifications about the charger can be found at: + http://www.ti.com/lit/ds/symlink/bq25150.pdf + http://www.ti.com/lit/ds/symlink/bq25155.pdf + +properties: + compatible: + enum: + - ti,bq25150 + - ti,bq25155 + + reg: + maxItems: 1 + description: I2C address of the charger. + + ac-detect-gpios: + description: | + GPIO used for connecting the bq2515x device PG (AC Detect) + pin. + maxItems: 1 + + reset-gpios: + description: GPIO used for hardware reset. + maxItems: 1 + + powerdown-gpios: + description: GPIO used for low power mode of IC. + maxItems: 1 + + charge-enable-gpios: + description: GPIO used to turn on and off charging. + maxItems: 1 + + input-current-limit-microamp: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Maximum input current in micro Amps. + minimum: 50000 + maximum: 500000 + + monitored-battery: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to the battery node being monitored + +required: + - compatible + - reg + - monitored-battery + +additionalProperties: false + +examples: + - | + bat: battery { + compatible = "simple-battery"; + constant-charge-current-max-microamp = <50000>; + precharge-current-microamp = <2500>; + constant-charge-voltage-max-microvolt = <4000000>; + }; + #include + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + bq25150: charger@6b { + compatible = "ti,bq25150"; + reg = <0x6b>; + monitored-battery = <&bat>; + input-current-limit-microamp = <100000>; + + ac-detect-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + powerdown-gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + charge-enable-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + }; + }; -- cgit v1.2.3 From 44908459275e056bf43054d503adee7e3a6c9f2f Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Mon, 20 Jul 2020 15:44:00 -0500 Subject: power: supply: bq25150 introduce the bq25150 Introduce the bq2515x family of chargers. The BQ2515X family of devices are highly integrated battery management ICs that integrate the most common functions for wearable devices namely a charger, an output voltage rail, ADC for battery and system monitoring, and a push-button controller. Datasheets: bq25150 - http://www.ti.com/lit/ds/symlink/bq25150.pdf bq25155 - http://www.ti.com/lit/ds/symlink/bq25155.pdf Signed-off-by: Ricardo Rivera-Matos Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 13 + drivers/power/supply/Makefile | 1 + drivers/power/supply/bq2515x_charger.c | 1169 ++++++++++++++++++++++++++++++++ 3 files changed, 1183 insertions(+) create mode 100644 drivers/power/supply/bq2515x_charger.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 44d3c8512fb8..faf2830aa152 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -610,6 +610,19 @@ config CHARGER_BQ24735 help Say Y to enable support for the TI BQ24735 battery charger. +config CHARGER_BQ2515X + tristate "TI BQ2515X battery charger family" + depends on I2C + depends on GPIOLIB || COMPILE_TEST + select REGMAP_I2C + help + Say Y to enable support for the TI BQ2515X family of battery + charging integrated circuits. The BQ2515X are highly integrated + battery charge management ICs that integrate the most common + functions for wearable devices, namely a charger, an output voltage + rail, ADC for battery and system monitoring, and push-button + controller. + config CHARGER_BQ25890 tristate "TI BQ25890 battery charger driver" depends on I2C diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index b9644663e435..b3c694a65114 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o +obj-$(CONFIG_CHARGER_BQ2515X) += bq2515x_charger.o obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o diff --git a/drivers/power/supply/bq2515x_charger.c b/drivers/power/supply/bq2515x_charger.c new file mode 100644 index 000000000000..63e8e317af56 --- /dev/null +++ b/drivers/power/supply/bq2515x_charger.c @@ -0,0 +1,1169 @@ +// SPDX-License-Identifier: GPL-2.0 +// BQ2515X Battery Charger Driver +// Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BQ2515X_MANUFACTURER "Texas Instruments" + +#define BQ2515X_STAT0 0x00 +#define BQ2515X_STAT1 0x01 +#define BQ2515X_STAT2 0x02 +#define BQ2515X_FLAG0 0x03 +#define BQ2515X_FLAG1 0x04 +#define BQ2515X_FLAG2 0x05 +#define BQ2515X_FLAG3 0x06 +#define BQ2515X_MASK0 0x07 +#define BQ2515X_MASK1 0x08 +#define BQ2515X_MASK2 0x09 +#define BQ2515X_MASK3 0x0a +#define BQ2515X_VBAT_CTRL 0x12 +#define BQ2515X_ICHG_CTRL 0x13 +#define BQ2515X_PCHRGCTRL 0x14 +#define BQ2515X_TERMCTRL 0x15 +#define BQ2515X_BUVLO 0x16 +#define BQ2515X_CHARGERCTRL0 0x17 +#define BQ2515X_CHARGERCTRL1 0x18 +#define BQ2515X_ILIMCTRL 0x19 +#define BQ2515X_LDOCTRL 0x1d +#define BQ2515X_MRCTRL 0x30 +#define BQ2515X_ICCTRL0 0x35 +#define BQ2515X_ICCTRL1 0x36 +#define BQ2515X_ICCTRL2 0x37 +#define BQ2515X_ADCCTRL0 0x40 +#define BQ2515X_ADCCTRL1 0x41 +#define BQ2515X_ADC_VBAT_M 0x42 +#define BQ2515X_ADC_VBAT_L 0x43 +#define BQ2515X_ADC_TS_M 0x44 +#define BQ2515X_ADC_TS_L 0x45 +#define BQ2515X_ADC_ICHG_M 0x46 +#define BQ2515X_ADC_ICHG_L 0x47 +#define BQ2515X_ADC_ADCIN_M 0x48 +#define BQ2515X_ADC_ADCIN_L 0x49 +#define BQ2515X_ADC_VIN_M 0x4a +#define BQ2515X_ADC_VIN_L 0x4b +#define BQ2515X_ADC_PMID_M 0x4c +#define BQ2515X_ADC_PMID_L 0x4d +#define BQ2515X_ADC_IIN_M 0x4e +#define BQ2515X_ADC_IIN_L 0x4f +#define BQ2515X_ADC_COMP1_M 0x52 +#define BQ2515X_ADC_COMP1_L 0X53 +#define BQ2515X_ADC_COMP2_M 0X54 +#define BQ2515X_ADC_COMP2_L 0x55 +#define BQ2515X_ADC_COMP3_M 0x56 +#define BQ2515X_ADC_COMP3_L 0x57 +#define BQ2515X_ADC_READ_EN 0x58 +#define BQ2515X_TS_FASTCHGCTRL 0x61 +#define BQ2515X_TS_COLD 0x62 +#define BQ2515X_TS_COOL 0x63 +#define BQ2515X_TS_WARM 0x64 +#define BQ2515X_TS_HOT 0x65 +#define BQ2515X_DEVICE_ID 0x6f + +#define BQ2515X_DEFAULT_ICHG_UA 10000 +#define BQ25150_DEFAULT_ILIM_UA 100000 +#define BQ25155_DEFAULT_ILIM_UA 500000 +#define BQ2515X_DEFAULT_VBAT_REG_UV 4200000 +#define BQ2515X_DEFAULT_IPRECHARGE_UA 2500 + +#define BQ2515X_DIVISOR 65536 +#define BQ2515X_VBAT_BASE_VOLT 3600000 +#define BQ2515X_VBAT_REG_MAX 4600000 +#define BQ2515X_VBAT_REG_MIN 3600000 +#define BQ2515X_VBAT_STEP_UV 10000 +#define BQ2515X_UV_FACTOR 1000000 +#define BQ2515X_VBAT_MULTIPLIER 6 +#define BQ2515X_ICHG_DIVISOR 52429 +#define BQ2515X_ICHG_CURR_STEP_THRESH_UA 318750 +#define BQ2515X_ICHG_MIN_UA 0 +#define BQ2515X_ICHG_MAX_UA 500000 +#define BQ2515X_ICHG_RNG_1B0_UA 1250 +#define BQ2515X_ICHG_RNG_1B1_UA 2500 +#define BQ2515X_VLOWV_SEL_1B0_UV 3000000 +#define BQ2515X_VLOWV_SEL_1B1_UV 2800000 +#define BQ2515X_PRECHRG_ICHRG_RNGE_1875_UA 18750 +#define BQ2515X_PRECHRG_ICHRG_RNGE_3750_UA 37500 +#define BQ2515X_TWAKE2_MIN_US 1700000 +#define BQ2515X_TWAKE2_MAX_US 2300000 + +#define BQ2515X_ILIM_150MA 0x2 +#define BQ2515X_ILIM_MASK 0x7 +#define BQ2515X_ILIM_MIN 50000 +#define BQ2515X_ILIM_MAX 600000 +#define BQ2515X_HEALTH_MASK 0xf +#define BQ2515X_ICHGRNG_MASK 0x80 +#define BQ2515X_STAT0_MASK 0x0f +#define BQ2515X_STAT1_MASK 0x1f +#define BQ2515X_PRECHARGE_MASK 0x1f + +#define BQ2515X_TS_HOT_STAT BIT(0) +#define BQ2515X_TS_WARM_STAT BIT(1) +#define BQ2515X_TS_COOL_STAT BIT(2) +#define BQ2515X_TS_COLD_STAT BIT(3) +#define BQ2515X_SAFETY_TIMER_EXP BIT(5) + +#define BQ2515X_EN_VBAT_READ BIT(3) +#define BQ2515X_EN_ICHG_READ BIT(5) + +#define BQ2515X_VIN_GOOD BIT(0) +#define BQ2515X_CHRG_DONE BIT(5) +#define BQ2515X_CV_CHRG_MODE BIT(6) + +#define BQ2515X_VIN_OVP_FAULT_STAT BIT(7) + +#define BQ2515X_WATCHDOG_DISABLE BIT(4) + +#define BQ2515X_ICHARGE_RANGE BIT(7) + +#define BQ2515X_VLOWV_SEL BIT(5) + +#define BQ2515X_CHARGER_DISABLE BIT(0) + +#define BQ2515X_HWRESET_14S_WD BIT(1) + +static const int bq2515x_ilim_lvl_values[] = { + 50000, 100000, 150000, 200000, 300000, 400000, 500000, 600000 +}; + +/** + * struct bq2515x_init_data - + * @ilim: input current limit + * @ichg: fast charge current + * @vbatreg: battery regulation voltage + * @iprechg: precharge current + */ +struct bq2515x_init_data { + int ilim; + int ichg; + int vbatreg; + int iprechg; +}; + +enum bq2515x_id { + BQ25150, + BQ25155, +}; + +/** + * struct bq2515x_device - + * @mains: mains properties + * @battery: battery properties + * @regmap: register map structure + * @dev: device structure + * + * @reset_gpio: manual reset (MR) pin + * @powerdown_gpio: low power mode pin + * @ac_detect_gpio: power good (PG) pin + * @ce_gpio: charge enable (CE) pin + * + * @model_name: string value describing device model + * @device_id: value of device_id + * @mains_online: boolean value indicating power supply online + * + * @bq2515x_init_data init_data: charger initialization data structure + */ +struct bq2515x_device { + struct power_supply *mains; + struct power_supply *battery; + struct regmap *regmap; + struct device *dev; + + struct gpio_desc *reset_gpio; + struct gpio_desc *powerdown_gpio; + struct gpio_desc *ac_detect_gpio; + struct gpio_desc *ce_gpio; + + char model_name[I2C_NAME_SIZE]; + int device_id; + bool mains_online; + + struct bq2515x_init_data init_data; +}; + +static struct reg_default bq25150_reg_defaults[] = { + {BQ2515X_FLAG0, 0x0}, + {BQ2515X_FLAG1, 0x0}, + {BQ2515X_FLAG2, 0x0}, + {BQ2515X_FLAG3, 0x0}, + {BQ2515X_MASK0, 0x0}, + {BQ2515X_MASK1, 0x0}, + {BQ2515X_MASK2, 0x71}, + {BQ2515X_MASK3, 0x0}, + {BQ2515X_VBAT_CTRL, 0x3C}, + {BQ2515X_ICHG_CTRL, 0x8}, + {BQ2515X_PCHRGCTRL, 0x2}, + {BQ2515X_TERMCTRL, 0x14}, + {BQ2515X_BUVLO, 0x0}, + {BQ2515X_CHARGERCTRL0, 0x82}, + {BQ2515X_CHARGERCTRL1, 0x42}, + {BQ2515X_ILIMCTRL, 0x1}, + {BQ2515X_LDOCTRL, 0xB0}, + {BQ2515X_MRCTRL, 0x2A}, + {BQ2515X_ICCTRL0, 0x10}, + {BQ2515X_ICCTRL1, 0x0}, + {BQ2515X_ICCTRL2, 0x0}, + {BQ2515X_ADCCTRL0, 0x2}, + {BQ2515X_ADCCTRL1, 0x40}, + {BQ2515X_ADC_COMP1_M, 0x23}, + {BQ2515X_ADC_COMP1_L, 0x20}, + {BQ2515X_ADC_COMP2_M, 0x38}, + {BQ2515X_ADC_COMP2_L, 0x90}, + {BQ2515X_ADC_COMP3_M, 0x0}, + {BQ2515X_ADC_COMP3_L, 0x0}, + {BQ2515X_ADC_READ_EN, 0x0}, + {BQ2515X_TS_FASTCHGCTRL, 0x34}, + {BQ2515X_TS_COLD, 0x7C}, + {BQ2515X_TS_COOL, 0x6D}, + {BQ2515X_TS_WARM, 0x38}, + {BQ2515X_TS_HOT, 0x27}, + {BQ2515X_DEVICE_ID, 0x20}, +}; + +static struct reg_default bq25155_reg_defaults[] = { + {BQ2515X_FLAG0, 0x0}, + {BQ2515X_FLAG1, 0x0}, + {BQ2515X_FLAG2, 0x0}, + {BQ2515X_FLAG3, 0x0}, + {BQ2515X_MASK0, 0x0}, + {BQ2515X_MASK1, 0x0}, + {BQ2515X_MASK2, 0x71}, + {BQ2515X_MASK3, 0x0}, + {BQ2515X_VBAT_CTRL, 0x3C}, + {BQ2515X_ICHG_CTRL, 0x8}, + {BQ2515X_PCHRGCTRL, 0x2}, + {BQ2515X_TERMCTRL, 0x14}, + {BQ2515X_BUVLO, 0x0}, + {BQ2515X_CHARGERCTRL0, 0x82}, + {BQ2515X_CHARGERCTRL1, 0xC2}, + {BQ2515X_ILIMCTRL, 0x6}, + {BQ2515X_LDOCTRL, 0xB0}, + {BQ2515X_MRCTRL, 0x2A}, + {BQ2515X_ICCTRL0, 0x10}, + {BQ2515X_ICCTRL1, 0x0}, + {BQ2515X_ICCTRL2, 0x40}, + {BQ2515X_ADCCTRL0, 0x2}, + {BQ2515X_ADCCTRL1, 0x40}, + {BQ2515X_ADC_COMP1_M, 0x23}, + {BQ2515X_ADC_COMP1_L, 0x20}, + {BQ2515X_ADC_COMP2_M, 0x38}, + {BQ2515X_ADC_COMP2_L, 0x90}, + {BQ2515X_ADC_COMP3_M, 0x0}, + {BQ2515X_ADC_COMP3_L, 0x0}, + {BQ2515X_ADC_READ_EN, 0x0}, + {BQ2515X_TS_FASTCHGCTRL, 0x34}, + {BQ2515X_TS_COLD, 0x7C}, + {BQ2515X_TS_COOL, 0x6D}, + {BQ2515X_TS_WARM, 0x38}, + {BQ2515X_TS_HOT, 0x27}, + {BQ2515X_DEVICE_ID, 0x35}, +}; + +static int bq2515x_wake_up(struct bq2515x_device *bq2515x) +{ + int ret; + int val; + + /* Read the STAT register if we can read it then the device is out + * of ship mode. If the register cannot be read then attempt to wake + * it up and enable the ADC. + */ + ret = regmap_read(bq2515x->regmap, BQ2515X_STAT0, &val); + if (ret) + return ret; + + /* Need to toggle LP and bring device out of ship mode. The device + * will exit the ship mode when the MR pin is held low for at least + * t_WAKE2 as shown in section 8.3.7.1 of the datasheet. + */ + gpiod_set_value_cansleep(bq2515x->powerdown_gpio, 0); + + gpiod_set_value_cansleep(bq2515x->reset_gpio, 0); + usleep_range(BQ2515X_TWAKE2_MIN_US, BQ2515X_TWAKE2_MAX_US); + gpiod_set_value_cansleep(bq2515x->reset_gpio, 1); + + return regmap_write(bq2515x->regmap, BQ2515X_ADC_READ_EN, + (BQ2515X_EN_VBAT_READ | BQ2515X_EN_ICHG_READ)); +} + +static int bq2515x_update_ps_status(struct bq2515x_device *bq2515x) +{ + bool dc = false; + unsigned int val; + int ret; + + if (bq2515x->ac_detect_gpio) + val = gpiod_get_value_cansleep(bq2515x->ac_detect_gpio); + else { + ret = regmap_read(bq2515x->regmap, BQ2515X_STAT0, &val); + if (ret) + return ret; + } + + dc = val & BQ2515X_VIN_GOOD; + + ret = bq2515x->mains_online != dc; + + bq2515x->mains_online = dc; + + return ret; +} + +static int bq2515x_disable_watchdog_timers(struct bq2515x_device *bq2515x) +{ + int ret; + + ret = regmap_update_bits(bq2515x->regmap, BQ2515X_CHARGERCTRL0, + BQ2515X_WATCHDOG_DISABLE, BQ2515X_WATCHDOG_DISABLE); + if (ret) + return ret; + + return regmap_update_bits(bq2515x->regmap, BQ2515X_ICCTRL2, + BQ2515X_HWRESET_14S_WD, 0); +} + +static int bq2515x_get_battery_voltage_now(struct bq2515x_device *bq2515x) +{ + int ret; + int vbat_msb; + int vbat_lsb; + uint32_t vbat_measurement; + + if (!bq2515x->mains_online) + bq2515x_wake_up(bq2515x); + + ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_VBAT_M, &vbat_msb); + if (ret) + return ret; + + ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_VBAT_L, &vbat_lsb); + if (ret) + return ret; + + vbat_measurement = (vbat_msb << 8) | vbat_lsb; + + return vbat_measurement * (BQ2515X_UV_FACTOR / BQ2515X_DIVISOR) * + BQ2515X_VBAT_MULTIPLIER; +} + +static int bq2515x_get_battery_current_now(struct bq2515x_device *bq2515x) +{ + int ret; + int ichg_msb; + int ichg_lsb; + uint32_t ichg_measurement; + u16 ichg_multiplier = BQ2515X_ICHG_RNG_1B0_UA; + unsigned int ichg_reg_code, reg_code; + unsigned int icharge_range = 0, pchrgctrl; + unsigned int buvlo, vlowv_sel, vlowv = BQ2515X_VLOWV_SEL_1B0_UV; + + if (!bq2515x->mains_online) + return -ENODATA; + + ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_ICHG_M, &ichg_msb); + if (ret) + return ret; + + ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_ICHG_L, &ichg_lsb); + if (ret) + return ret; + + ichg_measurement = (ichg_msb << 8) | ichg_lsb; + + ret = regmap_read(bq2515x->regmap, BQ2515X_BUVLO, &buvlo); + if (ret) + return ret; + + vlowv_sel = buvlo & BQ2515X_VLOWV_SEL; + + if (vlowv_sel) + vlowv = BQ2515X_VLOWV_SEL_1B1_UV; + + if (bq2515x_get_battery_voltage_now(bq2515x) < vlowv) { + ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, + &pchrgctrl); + if (ret) + return ret; + + reg_code = pchrgctrl & BQ2515X_PRECHARGE_MASK; + } else { + ret = regmap_read(bq2515x->regmap, BQ2515X_ICHG_CTRL, + &ichg_reg_code); + if (ret) + return ret; + + reg_code = ichg_reg_code; + } + + ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl); + if (ret) + return ret; + + icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE; + + if (icharge_range) + ichg_multiplier = BQ2515X_ICHG_RNG_1B1_UA; + + return reg_code * (ichg_multiplier * ichg_measurement / + BQ2515X_ICHG_DIVISOR); +} + +static bool bq2515x_get_charge_disable(struct bq2515x_device *bq2515x) +{ + int ret; + int ce_pin; + int icctrl2; + int charger_disable; + + ce_pin = gpiod_get_value_cansleep(bq2515x->ce_gpio); + + ret = regmap_read(bq2515x->regmap, BQ2515X_ICCTRL2, &icctrl2); + if (ret) + return ret; + + charger_disable = icctrl2 & BQ2515X_CHARGER_DISABLE; + + if (charger_disable || ce_pin) + return true; + + return false; +} + +static int bq2515x_set_charge_disable(struct bq2515x_device *bq2515x, int val) +{ + gpiod_set_value_cansleep(bq2515x->ce_gpio, val); + + return regmap_update_bits(bq2515x->regmap, BQ2515X_ICCTRL2, + BQ2515X_CHARGER_DISABLE, val); +} + +static int bq2515x_get_const_charge_current(struct bq2515x_device *bq2515x) +{ + int ret; + u16 ichg_multiplier = BQ2515X_ICHG_RNG_1B0_UA; + unsigned int ichg_reg_code; + unsigned int pchrgctrl; + unsigned int icharge_range; + + ret = regmap_read(bq2515x->regmap, BQ2515X_ICHG_CTRL, &ichg_reg_code); + if (ret) + return ret; + + ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl); + if (ret) + return ret; + + icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE; + + if (icharge_range) + ichg_multiplier = BQ2515X_ICHG_RNG_1B1_UA; + + return ichg_reg_code * ichg_multiplier; +} + +static int bq2515x_set_const_charge_current(struct bq2515x_device *bq2515x, + int val) +{ + int ret; + unsigned int ichg_reg_code; + u16 ichg_multiplier = BQ2515X_ICHG_RNG_1B0_UA; + unsigned int icharge_range = 0; + + if (val > BQ2515X_ICHG_MAX_UA || val < BQ2515X_ICHG_MIN_UA) + return -EINVAL; + + if (val > BQ2515X_ICHG_CURR_STEP_THRESH_UA) { + ichg_multiplier = BQ2515X_ICHG_RNG_1B1_UA; + icharge_range = BQ2515X_ICHARGE_RANGE; + } + + bq2515x_set_charge_disable(bq2515x, 1); + + ret = regmap_update_bits(bq2515x->regmap, BQ2515X_PCHRGCTRL, + BQ2515X_ICHARGE_RANGE, icharge_range); + if (ret) + return ret; + + ichg_reg_code = val / ichg_multiplier; + + ret = regmap_write(bq2515x->regmap, BQ2515X_ICHG_CTRL, ichg_reg_code); + if (ret) + return ret; + + return bq2515x_set_charge_disable(bq2515x, 0); +} + +static int bq2515x_get_precharge_current(struct bq2515x_device *bq2515x) +{ + int ret; + unsigned int pchrgctrl; + unsigned int icharge_range; + u16 precharge_multiplier = BQ2515X_ICHG_RNG_1B0_UA; + unsigned int precharge_reg_code; + + ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl); + if (ret) + return ret; + + icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE; + + if (icharge_range) + precharge_multiplier = BQ2515X_ICHG_RNG_1B1_UA; + + precharge_reg_code = pchrgctrl & BQ2515X_PRECHARGE_MASK; + + return precharge_reg_code * precharge_multiplier; +} + +static int bq2515x_set_precharge_current(struct bq2515x_device *bq2515x, + int val) +{ + int ret; + unsigned int pchrgctrl; + unsigned int icharge_range; + unsigned int precharge_reg_code; + unsigned int precharge_multiplier = BQ2515X_ICHG_RNG_1B0_UA; + unsigned int precharge_max_ua = BQ2515X_PRECHRG_ICHRG_RNGE_1875_UA; + + ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl); + if (ret) + return ret; + + icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE; + + if (icharge_range) { + precharge_max_ua = BQ2515X_PRECHRG_ICHRG_RNGE_3750_UA; + precharge_multiplier = BQ2515X_ICHG_RNG_1B1_UA; + } else { + precharge_max_ua = BQ2515X_PRECHRG_ICHRG_RNGE_1875_UA; + precharge_multiplier = BQ2515X_ICHG_RNG_1B0_UA; + } + if (val > precharge_max_ua || val < BQ2515X_ICHG_MIN_UA) + return -EINVAL; + + precharge_reg_code = val / precharge_multiplier; + + ret = bq2515x_set_charge_disable(bq2515x, 1); + if (ret) + return ret; + + ret = regmap_update_bits(bq2515x->regmap, BQ2515X_PCHRGCTRL, + BQ2515X_PRECHARGE_MASK, precharge_reg_code); + if (ret) + return ret; + + return bq2515x_set_charge_disable(bq2515x, 0); +} + +static int bq2515x_charging_status(struct bq2515x_device *bq2515x, + union power_supply_propval *val) +{ + bool status0_no_fault; + bool status1_no_fault; + bool ce_status; + bool charge_done; + unsigned int status; + int ret; + + if (!bq2515x->mains_online) { + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + return 0; + } + + ret = regmap_read(bq2515x->regmap, BQ2515X_STAT0, &status); + if (ret) + return ret; + + /* + * The code block below is used to determine if any faults from the + * STAT0 register are disbaling charging or if the charge has completed + * according to the CHARGE_DONE_STAT bit. + */ + if (((status & BQ2515X_STAT0_MASK) == true) & + ((status & BQ2515X_CHRG_DONE) == false)) { + status0_no_fault = true; + charge_done = false; + } else if (status & BQ2515X_CHRG_DONE) { + charge_done = true; + status0_no_fault = false; + } else { + status0_no_fault = false; + charge_done = false; + } + + ret = regmap_read(bq2515x->regmap, BQ2515X_STAT1, &status); + if (ret) + return ret; + /* + * The code block below is used to determine if any faults from the + * STAT1 register are disbaling charging + */ + if ((status & BQ2515X_STAT1_MASK) == false) + status1_no_fault = true; + else + status1_no_fault = false; + + ce_status = (!bq2515x_get_charge_disable(bq2515x)); + + /* + * If there are no faults and charging is enabled, then status is + * charging. Otherwise, if charging is complete, then status is full. + * Otherwise, if a fault exists or charging is disabled, then status is + * not charging + */ + if (status0_no_fault & status1_no_fault & ce_status) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else if (charge_done) + val->intval = POWER_SUPPLY_STATUS_FULL; + else if (!(status0_no_fault & status1_no_fault & ce_status)) + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + + return 0; +} + +static int bq2515x_get_batt_reg(struct bq2515x_device *bq2515x) +{ + int vbat_reg_code; + int ret; + + ret = regmap_read(bq2515x->regmap, BQ2515X_VBAT_CTRL, &vbat_reg_code); + if (ret) + return ret; + + return BQ2515X_VBAT_BASE_VOLT + vbat_reg_code * BQ2515X_VBAT_STEP_UV; +} + +static int bq2515x_set_batt_reg(struct bq2515x_device *bq2515x, int val) +{ + int vbat_reg_code; + + if (val > BQ2515X_VBAT_REG_MAX || val < BQ2515X_VBAT_REG_MIN) + return -EINVAL; + + vbat_reg_code = (val - BQ2515X_VBAT_BASE_VOLT) / BQ2515X_VBAT_STEP_UV; + + return regmap_write(bq2515x->regmap, BQ2515X_VBAT_CTRL, vbat_reg_code); +} + +static int bq2515x_get_ilim_lvl(struct bq2515x_device *bq2515x) +{ + int ret; + int ilimctrl; + + ret = regmap_read(bq2515x->regmap, BQ2515X_ILIMCTRL, &ilimctrl); + if (ret) + return ret; + + return bq2515x_ilim_lvl_values[ilimctrl & BQ2515X_ILIM_MASK]; +} + +static int bq2515x_set_ilim_lvl(struct bq2515x_device *bq2515x, int val) +{ + int i = 0; + unsigned int array_size = ARRAY_SIZE(bq2515x_ilim_lvl_values); + + for (i = array_size - 1; i > 0; i--) { + if (val >= bq2515x_ilim_lvl_values[i]) + break; + } + return regmap_write(bq2515x->regmap, BQ2515X_ILIMCTRL, i); +} + +static int bq2515x_power_supply_property_is_writeable(struct power_supply *psy, + enum power_supply_property prop) +{ + switch (prop) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + return true; + default: + return false; + } +} + +static int bq2515x_charger_get_health(struct bq2515x_device *bq2515x, + union power_supply_propval *val) +{ + int health = POWER_SUPPLY_HEALTH_GOOD; + int ret; + unsigned int stat1; + unsigned int flag3; + + if (!bq2515x->mains_online) + bq2515x_wake_up(bq2515x); + + ret = regmap_read(bq2515x->regmap, BQ2515X_FLAG3, &flag3); + if (ret) + return ret; + + ret = regmap_read(bq2515x->regmap, BQ2515X_STAT1, &stat1); + if (ret) + return ret; + + if (stat1 & BQ2515X_HEALTH_MASK) { + switch (stat1 & BQ2515X_HEALTH_MASK) { + case BQ2515X_TS_HOT_STAT: + health = POWER_SUPPLY_HEALTH_HOT; + break; + case BQ2515X_TS_WARM_STAT: + health = POWER_SUPPLY_HEALTH_WARM; + break; + case BQ2515X_TS_COOL_STAT: + health = POWER_SUPPLY_HEALTH_COOL; + break; + case BQ2515X_TS_COLD_STAT: + health = POWER_SUPPLY_HEALTH_COLD; + break; + default: + health = POWER_SUPPLY_HEALTH_UNKNOWN; + break; + } + } + + if (stat1 & BQ2515X_VIN_OVP_FAULT_STAT) + health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + + if (flag3 & BQ2515X_SAFETY_TIMER_EXP) + health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; + + val->intval = health; + return 0; +} + +static int bq2515x_mains_set_property(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + struct bq2515x_device *bq2515x = power_supply_get_drvdata(psy); + int ret; + + switch (prop) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = bq2515x_set_batt_reg(bq2515x, val->intval); + break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = bq2515x_set_const_charge_current(bq2515x, val->intval); + break; + + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = bq2515x_set_ilim_lvl(bq2515x, val->intval); + break; + + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + ret = bq2515x_set_precharge_current(bq2515x, val->intval); + break; + + default: + return -EINVAL; + } + + return ret; +} + +static int bq2515x_mains_get_property(struct power_supply *psy, + enum power_supply_property prop, + union power_supply_propval *val) +{ + struct bq2515x_device *bq2515x = power_supply_get_drvdata(psy); + int ret = 0; + + switch (prop) { + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = bq2515x_get_const_charge_current(bq2515x); + if (ret < 0) + return ret; + + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = bq2515x_get_batt_reg(bq2515x); + if (ret < 0) + return ret; + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + ret = bq2515x_get_precharge_current(bq2515x); + if (ret < 0) + return ret; + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_ONLINE: + val->intval = bq2515x->mains_online; + break; + + case POWER_SUPPLY_PROP_HEALTH: + ret = bq2515x_charger_get_health(bq2515x, val); + if (ret) + val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; + break; + + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = bq2515x_get_ilim_lvl(bq2515x); + if (ret < 0) + return ret; + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = bq2515x->model_name; + break; + + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = BQ2515X_MANUFACTURER; + break; + + case POWER_SUPPLY_PROP_STATUS: + ret = bq2515x_charging_status(bq2515x, val); + if (ret) + return ret; + break; + + default: + return -EINVAL; + } + + return ret; +} + +static int bq2515x_battery_get_property(struct power_supply *psy, + enum power_supply_property prop, + union power_supply_propval *val) +{ + struct bq2515x_device *bq2515x = power_supply_get_drvdata(psy); + int ret; + + ret = bq2515x_update_ps_status(bq2515x); + if (ret) + return ret; + + switch (prop) { + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + ret = bq2515x->init_data.vbatreg; + if (ret < 0) + return ret; + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + ret = bq2515x->init_data.ichg; + if (ret < 0) + return ret; + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = bq2515x_get_battery_voltage_now(bq2515x); + if (ret < 0) + return ret; + val->intval = ret; + break; + + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret = bq2515x_get_battery_current_now(bq2515x); + if (ret < 0) + return ret; + val->intval = ret; + break; + + default: + return -EINVAL; + } + return 0; +} + +static enum power_supply_property bq2515x_battery_properties[] = { + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, +}; + +static enum power_supply_property bq2515x_mains_properties[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, +}; + +static struct power_supply_desc bq2515x_mains_desc = { + .name = "bq2515x-mains", + .type = POWER_SUPPLY_TYPE_MAINS, + .get_property = bq2515x_mains_get_property, + .set_property = bq2515x_mains_set_property, + .properties = bq2515x_mains_properties, + .num_properties = ARRAY_SIZE(bq2515x_mains_properties), + .property_is_writeable = bq2515x_power_supply_property_is_writeable, +}; + +static struct power_supply_desc bq2515x_battery_desc = { + .name = "bq2515x-battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .get_property = bq2515x_battery_get_property, + .properties = bq2515x_battery_properties, + .num_properties = ARRAY_SIZE(bq2515x_battery_properties), + .property_is_writeable = bq2515x_power_supply_property_is_writeable, +}; + +static int bq2515x_power_supply_register(struct bq2515x_device *bq2515x, + struct device *dev, struct power_supply_config psy_cfg) +{ + bq2515x->mains = devm_power_supply_register(bq2515x->dev, + &bq2515x_mains_desc, + &psy_cfg); + if (IS_ERR(bq2515x->mains)) + return -EINVAL; + + bq2515x->battery = devm_power_supply_register(bq2515x->dev, + &bq2515x_battery_desc, + &psy_cfg); + if (IS_ERR(bq2515x->battery)) + return -EINVAL; + + return 0; +} + +static int bq2515x_hw_init(struct bq2515x_device *bq2515x) +{ + int ret; + struct power_supply_battery_info bat_info = { }; + + ret = bq2515x_disable_watchdog_timers(bq2515x); + if (ret) + return ret; + + if (bq2515x->init_data.ilim) { + ret = bq2515x_set_ilim_lvl(bq2515x, bq2515x->init_data.ilim); + if (ret) + return ret; + } + + ret = power_supply_get_battery_info(bq2515x->mains, &bat_info); + if (ret) { + dev_warn(bq2515x->dev, "battery info missing, default values will be applied\n"); + + bq2515x->init_data.ichg = BQ2515X_DEFAULT_ICHG_UA; + + bq2515x->init_data.vbatreg = BQ2515X_DEFAULT_VBAT_REG_UV; + + bq2515x->init_data.iprechg = BQ2515X_DEFAULT_IPRECHARGE_UA; + + } else { + bq2515x->init_data.ichg = + bat_info.constant_charge_current_max_ua; + + bq2515x->init_data.vbatreg = + bat_info.constant_charge_voltage_max_uv; + + bq2515x->init_data.iprechg = + bat_info.precharge_current_ua; + } + + ret = bq2515x_set_const_charge_current(bq2515x, + bq2515x->init_data.ichg); + if (ret) + return ret; + + ret = bq2515x_set_batt_reg(bq2515x, bq2515x->init_data.vbatreg); + if (ret) + return ret; + + return bq2515x_set_precharge_current(bq2515x, + bq2515x->init_data.iprechg); +} + +static int bq2515x_read_properties(struct bq2515x_device *bq2515x) +{ + int ret; + + ret = device_property_read_u32(bq2515x->dev, + "input-current-limit-microamp", + &bq2515x->init_data.ilim); + if (ret) { + switch (bq2515x->device_id) { + case BQ25150: + bq2515x->init_data.ilim = BQ25150_DEFAULT_ILIM_UA; + break; + case BQ25155: + bq2515x->init_data.ilim = BQ25155_DEFAULT_ILIM_UA; + break; + } + } + + bq2515x->ac_detect_gpio = devm_gpiod_get_optional(bq2515x->dev, + "ac-detect", GPIOD_IN); + if (IS_ERR(bq2515x->ac_detect_gpio)) { + ret = PTR_ERR(bq2515x->ac_detect_gpio); + dev_err(bq2515x->dev, "Failed to get ac detect"); + return ret; + } + + bq2515x->reset_gpio = devm_gpiod_get_optional(bq2515x->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(bq2515x->reset_gpio)) { + ret = PTR_ERR(bq2515x->reset_gpio); + dev_err(bq2515x->dev, "Failed to get reset"); + return ret; + } + + bq2515x->powerdown_gpio = devm_gpiod_get_optional(bq2515x->dev, + "powerdown", GPIOD_OUT_LOW); + if (IS_ERR(bq2515x->powerdown_gpio)) { + ret = PTR_ERR(bq2515x->powerdown_gpio); + dev_err(bq2515x->dev, "Failed to get powerdown"); + return ret; + } + + bq2515x->ce_gpio = devm_gpiod_get_optional(bq2515x->dev, + "charge-enable", + GPIOD_OUT_LOW); + if (IS_ERR(bq2515x->ce_gpio)) { + ret = PTR_ERR(bq2515x->ce_gpio); + dev_err(bq2515x->dev, "Failed to get ce"); + return ret; + } + + return 0; +} + +static bool bq2515x_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BQ2515X_STAT0 ... BQ2515X_FLAG3: + case BQ2515X_ADC_VBAT_M ... BQ2515X_ADC_IIN_L: + return true; + default: + return false; + } +} + +static const struct regmap_config bq25150_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = BQ2515X_DEVICE_ID, + .reg_defaults = bq25150_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(bq25150_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .volatile_reg = bq2515x_volatile_register, +}; + +static const struct regmap_config bq25155_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = BQ2515X_DEVICE_ID, + .reg_defaults = bq25155_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(bq25155_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .volatile_reg = bq2515x_volatile_register, +}; + +static int bq2515x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct bq2515x_device *bq2515x; + struct power_supply_config charger_cfg = {}; + int ret; + + bq2515x = devm_kzalloc(dev, sizeof(*bq2515x), GFP_KERNEL); + if (!bq2515x) + return -ENOMEM; + + bq2515x->dev = dev; + + strncpy(bq2515x->model_name, id->name, I2C_NAME_SIZE); + + bq2515x->device_id = id->driver_data; + + switch (bq2515x->device_id) { + case BQ25150: + bq2515x->regmap = devm_regmap_init_i2c(client, + &bq25150_regmap_config); + break; + case BQ25155: + bq2515x->regmap = devm_regmap_init_i2c(client, + &bq25155_regmap_config); + break; + } + + if (IS_ERR(bq2515x->regmap)) { + dev_err(dev, "failed to allocate register map\n"); + return PTR_ERR(bq2515x->regmap); + } + + i2c_set_clientdata(client, bq2515x); + + charger_cfg.drv_data = bq2515x; + charger_cfg.of_node = dev->of_node; + + ret = bq2515x_read_properties(bq2515x); + if (ret) { + dev_err(dev, "Failed to read device tree properties %d\n", + ret); + return ret; + } + + ret = bq2515x_power_supply_register(bq2515x, dev, charger_cfg); + if (ret) { + dev_err(dev, "failed to register power supply\n"); + return ret; + } + + ret = bq2515x_hw_init(bq2515x); + if (ret) { + dev_err(dev, "Cannot initialize the chip\n"); + return ret; + } + + return 0; +} + +static const struct i2c_device_id bq2515x_i2c_ids[] = { + { "bq25150", BQ25150, }, + { "bq25155", BQ25155, }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, bq2515x_i2c_ids); + +static const struct of_device_id bq2515x_of_match[] = { + { .compatible = "ti,bq25150", }, + { .compatible = "ti,bq25155", }, + { }, +}; +MODULE_DEVICE_TABLE(of, bq2515x_of_match); + +static struct i2c_driver bq2515x_driver = { + .driver = { + .name = "bq2515x-charger", + .of_match_table = bq2515x_of_match, + }, + .probe = bq2515x_probe, + .id_table = bq2515x_i2c_ids, +}; +module_i2c_driver(bq2515x_driver); + +MODULE_AUTHOR("Dan Murphy "); +MODULE_AUTHOR("Ricardo Rivera-Matos "); +MODULE_DESCRIPTION("BQ2515X charger driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From f03a3497fbf865d8eeab6d3cfc677f778862b435 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sat, 18 Jul 2020 11:43:40 +0200 Subject: power: reset: keystone-reset: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Signed-off-by: Sebastian Reichel --- drivers/power/reset/keystone-reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c index ad11faae19c5..211eeef0c81a 100644 --- a/drivers/power/reset/keystone-reset.c +++ b/drivers/power/reset/keystone-reset.c @@ -2,7 +2,7 @@ /* * TI keystone reboot driver * - * Copyright (C) 2014 Texas Instruments Incorporated. http://www.ti.com/ + * Copyright (C) 2014 Texas Instruments Incorporated. https://www.ti.com/ * * Author: Ivan Khoronzhuk */ -- cgit v1.2.3 From 9d832cd36c606e176f06eaf97f0c54b02359d95a Mon Sep 17 00:00:00 2001 From: Yongqiang Liu Date: Thu, 16 Jul 2020 16:58:49 +0800 Subject: power: Convert to DEFINE_SHOW_ATTRIBUTE Use DEFINE_SHOW_ATTRIBUTE macro to simplify the code. Signed-off-by: Yongqiang Liu Signed-off-by: Sebastian Reichel --- drivers/power/supply/da9030_battery.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/power/supply/da9030_battery.c b/drivers/power/supply/da9030_battery.c index 88582423b87d..0deba48d22d3 100644 --- a/drivers/power/supply/da9030_battery.c +++ b/drivers/power/supply/da9030_battery.c @@ -172,17 +172,7 @@ static int bat_debug_show(struct seq_file *s, void *data) return 0; } -static int debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, bat_debug_show, inode->i_private); -} - -static const struct file_operations bat_debug_fops = { - .open = debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(bat_debug); static struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger) { -- cgit v1.2.3 From ab92ffd5f6ac3ebd4a7650ef906702ab86127b45 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 15 Jul 2020 18:30:01 -0700 Subject: power: fix duplicated words in bq2415x_charger.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the doubled word "for". Change "It it" to "If it". Signed-off-by: Randy Dunlap Cc: linux-pm@vger.kernel.org Acked-by: Pali Rohár Signed-off-by: Sebastian Reichel --- include/linux/power/bq2415x_charger.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/power/bq2415x_charger.h b/include/linux/power/bq2415x_charger.h index 4ca08321e251..f3c267f2a467 100644 --- a/include/linux/power/bq2415x_charger.h +++ b/include/linux/power/bq2415x_charger.h @@ -14,8 +14,8 @@ * value is -1 then default chip value (specified in datasheet) will be * used. * - * Value resistor_sense is needed for for configuring charge and - * termination current. It it is less or equal to zero, configuring charge + * Value resistor_sense is needed for configuring charge and + * termination current. If it is less or equal to zero, configuring charge * and termination current will not be possible. * * For automode support is needed to provide name of power supply device -- cgit v1.2.3 From af60459a543483c5ad155a92daa8c3a6c00a0829 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 24 Jul 2020 20:21:47 +0800 Subject: math64: New DIV_S64_ROUND_CLOSEST helper Provide DIV_S64_ROUND_CLOSEST helper which uses div_s64 to perform division rounded to the closest integer using signed 64bit dividend and signed 32bit divisor. Signed-off-by: Chunyan Zhang Signed-off-by: Sebastian Reichel --- include/linux/math64.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/linux/math64.h b/include/linux/math64.h index 11a267413e8e..cd0693989436 100644 --- a/include/linux/math64.h +++ b/include/linux/math64.h @@ -279,4 +279,23 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor) #define DIV64_U64_ROUND_CLOSEST(dividend, divisor) \ ({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); }) +/* + * DIV_S64_ROUND_CLOSEST - signed 64bit divide with 32bit divisor rounded to nearest integer + * @dividend: signed 64bit dividend + * @divisor: signed 32bit divisor + * + * Divide signed 64bit dividend by signed 32bit divisor + * and round to closest integer. + * + * Return: dividend / divisor rounded to nearest integer + */ +#define DIV_S64_ROUND_CLOSEST(dividend, divisor)( \ +{ \ + s64 __x = (dividend); \ + s32 __d = (divisor); \ + ((__x > 0) == (__d > 0)) ? \ + div_s64((__x + (__d / 2)), __d) : \ + div_s64((__x - (__d / 2)), __d); \ +} \ +) #endif /* _LINUX_MATH64_H */ -- cgit v1.2.3 From ac31585fca317b29b6b7093a5a6775137a852f94 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 24 Jul 2020 20:21:48 +0800 Subject: power: supply: sc27xx: prevent adc * 1000 from overflow The input parameter is int type, cause adc * 1000 could overflow. Change to use s64 to avoid this issue. Signed-off-by: Chen Yongzhi Signed-off-by: Chunyan Zhang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index be42e814ea34..9c627618c224 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -133,14 +134,14 @@ static const char * const sc27xx_charger_supply_name[] = { "sc2723_charger", }; -static int sc27xx_fgu_adc_to_current(struct sc27xx_fgu_data *data, int adc) +static int sc27xx_fgu_adc_to_current(struct sc27xx_fgu_data *data, s64 adc) { - return DIV_ROUND_CLOSEST(adc * 1000, data->cur_1000ma_adc); + return DIV_S64_ROUND_CLOSEST(adc * 1000, data->cur_1000ma_adc); } -static int sc27xx_fgu_adc_to_voltage(struct sc27xx_fgu_data *data, int adc) +static int sc27xx_fgu_adc_to_voltage(struct sc27xx_fgu_data *data, s64 adc) { - return DIV_ROUND_CLOSEST(adc * 1000, data->vol_1000mv_adc); + return DIV_S64_ROUND_CLOSEST(adc * 1000, data->vol_1000mv_adc); } static int sc27xx_fgu_voltage_to_adc(struct sc27xx_fgu_data *data, int vol) -- cgit v1.2.3 From a7f79f99541eff4e6bcae0014eb08d3019337565 Mon Sep 17 00:00:00 2001 From: Daniel González Cabanelas Date: Wed, 15 Jul 2020 15:35:14 +0200 Subject: power: reset: add driver for LinkStation power off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some Buffalo LinkStations perform the power off operation, at restart time, depending on the state of an output pin (LED2/INTn) at the ethernet PHY. This pin is also used to wake the machine when a WoL packet is received by the PHY. The driver is required by the Buffalo LinkStation LS421DE (ARM MVEBU), and other models. Without it, the board remains forever halted if a power off command is executed, unless the PSU is disconnected and connected again. Add the driver to provide the power off function and also make the WoL feature to be available. Signed-off-by: Daniel González Cabanelas Signed-off-by: Sebastian Reichel --- drivers/power/reset/Kconfig | 11 +++ drivers/power/reset/Makefile | 1 + drivers/power/reset/linkstation-poweroff.c | 136 +++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 drivers/power/reset/linkstation-poweroff.c diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index f07b982c8dff..0a1fb5c74f83 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -99,6 +99,17 @@ config POWER_RESET_HISI help Reboot support for Hisilicon boards. +config POWER_RESET_LINKSTATION + tristate "Buffalo LinkStation power-off driver" + depends on ARCH_MVEBU || COMPILE_TEST + depends on OF_MDIO && PHYLIB + help + This driver supports turning off some Buffalo LinkStations by + setting an output pin at the ethernet PHY to the correct state. + It also makes the device compatible with the WoL function. + + Say Y here if you have a Buffalo LinkStation LS421D/E. + config POWER_RESET_MSM bool "Qualcomm MSM power-off driver" depends on ARCH_QCOM diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 5710ca469517..c51eceba9ea3 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_POWER_RESET_GEMINI_POWEROFF) += gemini-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o +obj-${CONFIG_POWER_RESET_LINKSTATION} += linkstation-poweroff.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o obj-$(CONFIG_POWER_RESET_OXNAS) += oxnas-restart.o diff --git a/drivers/power/reset/linkstation-poweroff.c b/drivers/power/reset/linkstation-poweroff.c new file mode 100644 index 000000000000..39e89baedb5f --- /dev/null +++ b/drivers/power/reset/linkstation-poweroff.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LinkStation power off restart driver + * Copyright (C) 2020 Daniel González Cabanelas + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Defines from the eth phy Marvell driver */ +#define MII_MARVELL_COPPER_PAGE 0 +#define MII_MARVELL_LED_PAGE 3 +#define MII_MARVELL_WOL_PAGE 17 +#define MII_MARVELL_PHY_PAGE 22 + +#define MII_PHY_LED_CTRL 16 +#define MII_88E1318S_PHY_LED_TCR 18 +#define MII_88E1318S_PHY_WOL_CTRL 16 +#define MII_M1011_IEVENT 19 + +#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) +#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) +#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) +#define LED2_FORCE_ON (0x8 << 8) +#define LEDMASK GENMASK(11,8) + +static struct phy_device *phydev; + +static void mvphy_reg_intn(u16 data) +{ + int rc = 0, saved_page; + + saved_page = phy_select_page(phydev, MII_MARVELL_LED_PAGE); + if (saved_page < 0) + goto err; + + /* Force manual LED2 control to let INTn work */ + __phy_modify(phydev, MII_PHY_LED_CTRL, LEDMASK, LED2_FORCE_ON); + + /* Set the LED[2]/INTn pin to the required state */ + __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, + MII_88E1318S_PHY_LED_TCR_FORCE_INT, + MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | data); + + if (!data) { + /* Clear interrupts to ensure INTn won't be holded in high state */ + __phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_MARVELL_COPPER_PAGE); + __phy_read(phydev, MII_M1011_IEVENT); + + /* If WOL was enabled and a magic packet was received before powering + * off, we won't be able to wake up by sending another magic packet. + * Clear WOL status. + */ + __phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_MARVELL_WOL_PAGE); + __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL, + MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); + } +err: + rc = phy_restore_page(phydev, saved_page, rc); + if (rc < 0) + dev_err(&phydev->mdio.dev, "Write register failed, %d\n", rc); +} + +static int linkstation_reboot_notifier(struct notifier_block *nb, + unsigned long action, void *unused) +{ + if (action == SYS_RESTART) + mvphy_reg_intn(MII_88E1318S_PHY_LED_TCR_FORCE_INT); + + return NOTIFY_DONE; +} + +static struct notifier_block linkstation_reboot_nb = { + .notifier_call = linkstation_reboot_notifier, +}; + +static void linkstation_poweroff(void) +{ + unregister_reboot_notifier(&linkstation_reboot_nb); + mvphy_reg_intn(0); + + kernel_restart("Power off"); +} + +static const struct of_device_id ls_poweroff_of_match[] = { + { .compatible = "buffalo,ls421d" }, + { .compatible = "buffalo,ls421de" }, + { }, +}; + +static int __init linkstation_poweroff_init(void) +{ + struct mii_bus *bus; + struct device_node *dn; + + dn = of_find_matching_node(NULL, ls_poweroff_of_match); + if (!dn) + return -ENODEV; + of_node_put(dn); + + dn = of_find_node_by_name(NULL, "mdio"); + if (!dn) + return -ENODEV; + + bus = of_mdio_find_bus(dn); + of_node_put(dn); + if (!bus) + return -EPROBE_DEFER; + + phydev = phy_find_first(bus); + if (!phydev) + return -EPROBE_DEFER; + + register_reboot_notifier(&linkstation_reboot_nb); + pm_power_off = linkstation_poweroff; + + return 0; +} + +static void __exit linkstation_poweroff_exit(void) +{ + pm_power_off = NULL; + unregister_reboot_notifier(&linkstation_reboot_nb); +} + +module_init(linkstation_poweroff_init); +module_exit(linkstation_poweroff_exit); + +MODULE_AUTHOR("Daniel González Cabanelas "); +MODULE_DESCRIPTION("LinkStation power off driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 81bd45fc36e3d01db66c17fa5ed5f39a61e67477 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 13 Jul 2020 21:16:38 +0200 Subject: power: supply: bq2xxxx: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov [also update recently added ti.com http links] Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq2415x_charger.c | 16 +++++----- drivers/power/supply/bq24257_charger.c | 6 ++-- drivers/power/supply/bq2515x_charger.c | 2 +- drivers/power/supply/bq27xxx_battery.c | 50 +++++++++++++++--------------- drivers/power/supply/bq27xxx_battery_hdq.c | 2 +- drivers/power/supply/bq27xxx_battery_i2c.c | 2 +- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/power/supply/bq2415x_charger.c b/drivers/power/supply/bq2415x_charger.c index a1f00ae1c180..5724001e66b9 100644 --- a/drivers/power/supply/bq2415x_charger.c +++ b/drivers/power/supply/bq2415x_charger.c @@ -5,14 +5,14 @@ * Copyright (C) 2011-2013 Pali Rohár * * Datasheets: - * http://www.ti.com/product/bq24150 - * http://www.ti.com/product/bq24150a - * http://www.ti.com/product/bq24152 - * http://www.ti.com/product/bq24153 - * http://www.ti.com/product/bq24153a - * http://www.ti.com/product/bq24155 - * http://www.ti.com/product/bq24157s - * http://www.ti.com/product/bq24158 + * https://www.ti.com/product/bq24150 + * https://www.ti.com/product/bq24150a + * https://www.ti.com/product/bq24152 + * https://www.ti.com/product/bq24153 + * https://www.ti.com/product/bq24153a + * https://www.ti.com/product/bq24155 + * https://www.ti.com/product/bq24157s + * https://www.ti.com/product/bq24158 */ #include diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c index eb151687beb3..8e60cb0f3c3f 100644 --- a/drivers/power/supply/bq24257_charger.c +++ b/drivers/power/supply/bq24257_charger.c @@ -5,9 +5,9 @@ * Copyright (C) 2015 Intel Corporation * * Datasheets: - * http://www.ti.com/product/bq24250 - * http://www.ti.com/product/bq24251 - * http://www.ti.com/product/bq24257 + * https://www.ti.com/product/bq24250 + * https://www.ti.com/product/bq24251 + * https://www.ti.com/product/bq24257 */ #include diff --git a/drivers/power/supply/bq2515x_charger.c b/drivers/power/supply/bq2515x_charger.c index 63e8e317af56..36b0c8c98d40 100644 --- a/drivers/power/supply/bq2515x_charger.c +++ b/drivers/power/supply/bq2515x_charger.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // BQ2515X Battery Charger Driver -// Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ +// Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/ #include #include diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 942c92127b6d..acaafed037be 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -18,31 +18,31 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Datasheets: - * http://www.ti.com/product/bq27000 - * http://www.ti.com/product/bq27200 - * http://www.ti.com/product/bq27010 - * http://www.ti.com/product/bq27210 - * http://www.ti.com/product/bq27500 - * http://www.ti.com/product/bq27510-g1 - * http://www.ti.com/product/bq27510-g2 - * http://www.ti.com/product/bq27510-g3 - * http://www.ti.com/product/bq27520-g1 - * http://www.ti.com/product/bq27520-g2 - * http://www.ti.com/product/bq27520-g3 - * http://www.ti.com/product/bq27520-g4 - * http://www.ti.com/product/bq27530-g1 - * http://www.ti.com/product/bq27531-g1 - * http://www.ti.com/product/bq27541-g1 - * http://www.ti.com/product/bq27542-g1 - * http://www.ti.com/product/bq27546-g1 - * http://www.ti.com/product/bq27742-g1 - * http://www.ti.com/product/bq27545-g1 - * http://www.ti.com/product/bq27421-g1 - * http://www.ti.com/product/bq27425-g1 - * http://www.ti.com/product/bq27426 - * http://www.ti.com/product/bq27411-g1 - * http://www.ti.com/product/bq27441-g1 - * http://www.ti.com/product/bq27621-g1 + * https://www.ti.com/product/bq27000 + * https://www.ti.com/product/bq27200 + * https://www.ti.com/product/bq27010 + * https://www.ti.com/product/bq27210 + * https://www.ti.com/product/bq27500 + * https://www.ti.com/product/bq27510-g1 + * https://www.ti.com/product/bq27510-g2 + * https://www.ti.com/product/bq27510-g3 + * https://www.ti.com/product/bq27520-g1 + * https://www.ti.com/product/bq27520-g2 + * https://www.ti.com/product/bq27520-g3 + * https://www.ti.com/product/bq27520-g4 + * https://www.ti.com/product/bq27530-g1 + * https://www.ti.com/product/bq27531-g1 + * https://www.ti.com/product/bq27541-g1 + * https://www.ti.com/product/bq27542-g1 + * https://www.ti.com/product/bq27546-g1 + * https://www.ti.com/product/bq27742-g1 + * https://www.ti.com/product/bq27545-g1 + * https://www.ti.com/product/bq27421-g1 + * https://www.ti.com/product/bq27425-g1 + * https://www.ti.com/product/bq27426 + * https://www.ti.com/product/bq27411-g1 + * https://www.ti.com/product/bq27441-g1 + * https://www.ti.com/product/bq27621-g1 */ #include diff --git a/drivers/power/supply/bq27xxx_battery_hdq.c b/drivers/power/supply/bq27xxx_battery_hdq.c index 9aff896c9802..29771967df2e 100644 --- a/drivers/power/supply/bq27xxx_battery_hdq.c +++ b/drivers/power/supply/bq27xxx_battery_hdq.c @@ -1,7 +1,7 @@ /* * BQ27xxx battery monitor HDQ/1-wire driver * - * Copyright (C) 2007-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2007-2017 Texas Instruments Incorporated - https://www.ti.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 2677c38a8a42..8e114a7abfc9 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -1,7 +1,7 @@ /* * BQ27xxx battery monitor I2C driver * - * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * * This program is free software; you can redistribute it and/or modify -- cgit v1.2.3 From ccf193dee1f0fff55b556928591f7818bac1b3b1 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 12 Jul 2020 12:23:51 -0700 Subject: power: supply: check if calc_soc succeeded in pm860x_init_battery clang static analysis flags this error 88pm860x_battery.c:522:19: warning: Assigned value is garbage or undefined [core.uninitialized.Assign] info->start_soc = soc; ^ ~~~ soc is set by calling calc_soc. But calc_soc can return without setting soc. So check the return status and bail similarly to other checks in pm860x_init_battery and initialize soc to silence the warning. Fixes: a830d28b48bf ("power_supply: Enable battery-charger for 88pm860x") Signed-off-by: Tom Rix Signed-off-by: Sebastian Reichel --- drivers/power/supply/88pm860x_battery.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/88pm860x_battery.c b/drivers/power/supply/88pm860x_battery.c index 1308f3a185f3..590da88a17a2 100644 --- a/drivers/power/supply/88pm860x_battery.c +++ b/drivers/power/supply/88pm860x_battery.c @@ -433,7 +433,7 @@ static void pm860x_init_battery(struct pm860x_battery_info *info) int ret; int data; int bat_remove; - int soc; + int soc = 0; /* measure enable on GPADC1 */ data = MEAS1_GP1; @@ -496,7 +496,9 @@ static void pm860x_init_battery(struct pm860x_battery_info *info) } mutex_unlock(&info->lock); - calc_soc(info, OCV_MODE_ACTIVE, &soc); + ret = calc_soc(info, OCV_MODE_ACTIVE, &soc); + if (ret < 0) + goto out; data = pm860x_reg_read(info->i2c, PM8607_POWER_UP_LOG); bat_remove = data & BAT_WU_LOG; -- cgit v1.2.3 From 2f38dc4d9190cd97b8ceb88be5b835ee5feb44d1 Mon Sep 17 00:00:00 2001 From: Matheus Castello Date: Sun, 5 Jul 2020 21:10:03 -0300 Subject: power: supply: max17040: Add POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN Adds the property POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN to export the chip->low_soc_alert and add the property as writeable, implementing max17040_prop_writeable and max17040_set_property, so with that the user space can readjust the alerts. Signed-off-by: Matheus Castello Signed-off-by: Sebastian Reichel --- drivers/power/supply/max17040_battery.c | 51 +++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index 48aa44665e2f..6cb31b9a958d 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c @@ -69,6 +69,9 @@ static int max17040_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: val->intval = chip->soc; break; + case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN: + val->intval = chip->low_soc_alert; + break; default: return -EINVAL; } @@ -256,19 +259,57 @@ static int max17040_enable_alert_irq(struct max17040_chip *chip) return ret; } +static int max17040_prop_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN: + return 1; + default: + return 0; + } +} + +static int max17040_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct max17040_chip *chip = power_supply_get_drvdata(psy); + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN: + /* alert threshold can be programmed from 1% up to 32% */ + if ((val->intval < 1) || (val->intval > 32)) { + ret = -EINVAL; + break; + } + ret = max17040_set_low_soc_alert(chip->client, val->intval); + chip->low_soc_alert = val->intval; + break; + default: + ret = -EINVAL; + } + + return ret; +} + static enum power_supply_property max17040_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN, }; static const struct power_supply_desc max17040_battery_desc = { - .name = "battery", - .type = POWER_SUPPLY_TYPE_BATTERY, - .get_property = max17040_get_property, - .properties = max17040_battery_props, - .num_properties = ARRAY_SIZE(max17040_battery_props), + .name = "battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .get_property = max17040_get_property, + .set_property = max17040_set_property, + .property_is_writeable = max17040_prop_writeable, + .properties = max17040_battery_props, + .num_properties = ARRAY_SIZE(max17040_battery_props), }; static int max17040_probe(struct i2c_client *client, -- cgit v1.2.3 From 466bf93153b871f9fed93aea1389673c17d253e7 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 2 Jul 2020 16:58:52 +0800 Subject: power: supply: rt5033_battery: Fix error code in rt5033_battery_probe() In the function rt5033_battery_probe(), it should return -ENOMEM instead of -EINVAL when call function devm_kzalloc() failed. Signed-off-by: Peng Fan Signed-off-by: Sebastian Reichel --- drivers/power/supply/rt5033_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c index d8667a9fc49b..f330452341f0 100644 --- a/drivers/power/supply/rt5033_battery.c +++ b/drivers/power/supply/rt5033_battery.c @@ -125,7 +125,7 @@ static int rt5033_battery_probe(struct i2c_client *client, battery = devm_kzalloc(&client->dev, sizeof(*battery), GFP_KERNEL); if (!battery) - return -EINVAL; + return -ENOMEM; battery->client = client; battery->regmap = devm_regmap_init_i2c(client, -- cgit v1.2.3 From 471dec8023d14e2b6e817b811a37b65e3cc0661a Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Tue, 28 Jul 2020 15:08:12 -0500 Subject: dt-bindings: power: Convert battery.txt to battery.yaml Convert the battery.txt file to yaml and fix up the examples. Signed-off-by: Dan Murphy Reviewed-by: Rob Herring [Fixed the regex for ocv-capacity-table and the DT example for it] Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/supply/battery.txt | 86 +----------- .../devicetree/bindings/power/supply/battery.yaml | 144 +++++++++++++++++++++ 2 files changed, 145 insertions(+), 85 deletions(-) create mode 100644 Documentation/devicetree/bindings/power/supply/battery.yaml diff --git a/Documentation/devicetree/bindings/power/supply/battery.txt b/Documentation/devicetree/bindings/power/supply/battery.txt index 5e29595edd74..a9f80cc49068 100644 --- a/Documentation/devicetree/bindings/power/supply/battery.txt +++ b/Documentation/devicetree/bindings/power/supply/battery.txt @@ -1,87 +1,3 @@ -Battery Characteristics - -The devicetree battery node provides static battery characteristics. -In smart batteries, these are typically stored in non-volatile memory -on a fuel gauge chip. The battery node should be used where there is -no appropriate non-volatile memory, or it is unprogrammed/incorrect. - -Upstream dts files should not include battery nodes, unless the battery -represented cannot easily be replaced in the system by one of a -different type. This prevents unpredictable, potentially harmful, -behavior should a replacement that changes the battery type occur -without a corresponding update to the dtb. +The contents of this file has been moved to battery.yaml Please note that not all charger drivers respect all of the properties. - -Required Properties: - - compatible: Must be "simple-battery" - -Optional Properties: - - over-voltage-threshold-microvolt: battery over-voltage limit - - re-charge-voltage-microvolt: limit to automatically start charging again - - voltage-min-design-microvolt: drained battery voltage - - voltage-max-design-microvolt: fully charged battery voltage - - energy-full-design-microwatt-hours: battery design energy - - charge-full-design-microamp-hours: battery design capacity - - trickle-charge-current-microamp: current for trickle-charge phase - - precharge-current-microamp: current for pre-charge phase - - precharge-upper-limit-microvolt: limit when to change to constant charging - - charge-term-current-microamp: current for charge termination phase - - constant-charge-current-max-microamp: maximum constant input current - - constant-charge-voltage-max-microvolt: maximum constant input voltage - - factory-internal-resistance-micro-ohms: battery factory internal resistance - - ocv-capacity-table-0: An array providing the open circuit voltage (OCV) - of the battery and corresponding battery capacity percent, which is used - to look up battery capacity according to current OCV value. And the open - circuit voltage unit is microvolt. - - ocv-capacity-table-1: Same as ocv-capacity-table-0 - ...... - - ocv-capacity-table-n: Same as ocv-capacity-table-0 - - ocv-capacity-celsius: An array containing the temperature in degree Celsius, - for each of the battery capacity lookup table. The first temperature value - specifies the OCV table 0, and the second temperature value specifies the - OCV table 1, and so on. - - resistance-temp-table: An array providing the temperature in degree Celsius - and corresponding battery internal resistance percent, which is used to look - up the resistance percent according to current temperature to get a accurate - batterty internal resistance in different temperatures. - -Battery properties are named, where possible, for the corresponding -elements in enum power_supply_property, defined in -https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/power_supply.h - -Batteries must be referenced by chargers and/or fuel-gauges -using a phandle. The phandle's property should be named -"monitored-battery". - -Example: - - bat: battery { - compatible = "simple-battery"; - voltage-min-design-microvolt = <3200000>; - voltage-max-design-microvolt = <4200000>; - energy-full-design-microwatt-hours = <5290000>; - charge-full-design-microamp-hours = <1430000>; - precharge-current-microamp = <256000>; - charge-term-current-microamp = <128000>; - constant-charge-current-max-microamp = <900000>; - constant-charge-voltage-max-microvolt = <4200000>; - factory-internal-resistance-micro-ohms = <250000>; - ocv-capacity-celsius = <(-10) 0 10>; - ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...; - ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...; - ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...; - resistance-temp-table = <20 100>, <10 90>, <0 80>, <(-10) 60>; - }; - - charger: charger@11 { - .... - monitored-battery = <&bat>; - ... - }; - - fuel_gauge: fuel-gauge@22 { - .... - monitored-battery = <&bat>; - ... - }; diff --git a/Documentation/devicetree/bindings/power/supply/battery.yaml b/Documentation/devicetree/bindings/power/supply/battery.yaml new file mode 100644 index 000000000000..932b736ce5c0 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/battery.yaml @@ -0,0 +1,144 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/battery.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Battery Characteristics + +maintainers: + - Sebastian Reichel + +description: | + The devicetree battery node provides static battery characteristics. + In smart batteries, these are typically stored in non-volatile memory + on a fuel gauge chip. The battery node should be used where there is + no appropriate non-volatile memory, or it is unprogrammed/incorrect. + + Upstream dts files should not include battery nodes, unless the battery + represented cannot easily be replaced in the system by one of a + different type. This prevents unpredictable, potentially harmful, + behavior should a replacement that changes the battery type occur + without a corresponding update to the dtb. + + Battery properties are named, where possible, for the corresponding elements + in enum power_supply_property, defined in include/linux/power_supply.h + + Batteries must be referenced by chargers and/or fuel-gauges using a phandle. + The phandle's property should be named "monitored-battery". + +properties: + compatible: + const: simple-battery + + over-voltage-threshold-microvolt: + description: battery over-voltage limit + + re-charge-voltage-microvolt: + description: limit to automatically start charging again + + voltage-min-design-microvolt: + description: drained battery voltage + + voltage-max-design-microvolt: + description: fully charged battery voltage + + energy-full-design-microwatt-hours: + description: battery design energy + + charge-full-design-microamp-hours: + description: battery design capacity + + trickle-charge-current-microamp: + description: current for trickle-charge phase + + precharge-current-microamp: + description: current for pre-charge phase + + precharge-upper-limit-microvolt: + description: limit when to change to constant charging + + charge-term-current-microamp: + description: current for charge termination phase + + constant-charge-current-max-microamp: + description: maximum constant input current + + constant-charge-voltage-max-microvolt: + description: maximum constant input voltage + + factory-internal-resistance-micro-ohms: + description: battery factory internal resistance + + resistance-temp-table: + description: | + An array providing the temperature in degree Celsius + and corresponding battery internal resistance percent, which is used to + look up the resistance percent according to current temperature to get an + accurate batterty internal resistance in different temperatures. + + ocv-capacity-celsius: + description: | + An array containing the temperature in degree Celsius, + for each of the battery capacity lookup table. + +required: + - compatible + +patternProperties: + '^ocv-capacity-table-[0-9]+$': + $ref: /schemas/types.yaml#/definitions/uint32-matrix + description: | + An array providing the open circuit voltage (OCV) + of the battery and corresponding battery capacity percent, which is used + to look up battery capacity according to current OCV value. And the open + circuit voltage unit is microvolt. + maxItems: 100 + items: + items: + - description: open circuit voltage (OCV) in microvolts + - description: battery capacity percent + maximum: 100 + +additionalProperties: false + +examples: + - | + power { + #address-cells = <1>; + #size-cells = <0>; + + battery: battery { + compatible = "simple-battery"; + over-voltage-threshold-microvolt = <4500000>; + re-charge-voltage-microvolt = <250000>; + voltage-min-design-microvolt = <3200000>; + voltage-max-design-microvolt = <4200000>; + energy-full-design-microwatt-hours = <5290000>; + charge-full-design-microamp-hours = <1430000>; + precharge-current-microamp = <256000>; + precharge-upper-limit-microvolt = <2500000>; + charge-term-current-microamp = <128000>; + constant-charge-current-max-microamp = <900000>; + constant-charge-voltage-max-microvolt = <4200000>; + factory-internal-resistance-micro-ohms = <250000>; + ocv-capacity-celsius = <(-10) 0 10>; + /* table for -10 degree Celsius */ + ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>; + /* table for 0 degree Celsius */ + ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>; + /* table for 10 degree Celsius */ + ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>; + resistance-temp-table = <20 100>, <10 90>, <0 80>, <(-10) 60>; + }; + + charger@11 { + reg = <0x11>; + monitored-battery = <&battery>; + }; + + fuel-gauge@22 { + reg = <0x22>; + monitored-battery = <&battery>; + }; + }; -- cgit v1.2.3 From 362fd2ecc3f118b09a56a54752c5310ebb9f7c54 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 29 Jul 2020 09:43:47 +0200 Subject: power: supply: cpcap-battery: Fix kerneldoc of cpcap_battery_read_accumulated() Fix W=1 compile warnings (invalid kerneldoc): drivers/power/supply/cpcap-battery.c:292: warning: Function parameter or member 'ccd' not described in 'cpcap_battery_read_accumulated' drivers/power/supply/cpcap-battery.c:292: warning: Excess function parameter 'regs' description in 'cpcap_battery_read_accumulated' Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/supply/cpcap-battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c index 6e9392901b0a..90eba364664b 100644 --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -274,7 +274,7 @@ static int cpcap_battery_cc_to_ua(struct cpcap_battery_ddata *ddata, /** * cpcap_battery_read_accumulated - reads cpcap coulomb counter * @ddata: device driver data - * @regs: coulomb counter values + * @ccd: coulomb counter values * * Based on Motorola mapphone kernel function data_read_regs(). * Looking at the registers, the coulomb counter seems similar to -- cgit v1.2.3 From 152ee3d1afbee08c88dc37048ee26a3edacbef90 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 29 Jul 2020 09:43:48 +0200 Subject: power: supply: Fix kerneldoc of power_supply_temp2resist_simple() Fix W=1 compile warnings (invalid kerneldoc): drivers/power/supply/power_supply_core.c:747: warning: Function parameter or member 'temp' not described in 'power_supply_temp2resist_simple' drivers/power/supply/power_supply_core.c:747: warning: Excess function parameter 'ocv' description in 'power_supply_temp2resist_simple' Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 02b37fe6061c..595e030034d4 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -733,7 +733,7 @@ EXPORT_SYMBOL_GPL(power_supply_put_battery_info); * percent * @table: Pointer to battery resistance temperature table * @table_len: The table length - * @ocv: Current temperature + * @temp: Current temperature * * This helper function is used to look up battery internal resistance percent * according to current temperature value from the resistance temperature table, -- cgit v1.2.3 From c365ee561ee343b587df9f5ba191c1a090d4f43e Mon Sep 17 00:00:00 2001 From: LH Lin Date: Wed, 29 Jul 2020 20:14:00 +0800 Subject: power: supply: test_power: Fix battery_current initial value Since default battery_status is POWER_SUPPLY_STATUS_DISCHARGING, we should change default battery_current to a negative value. Signed-off-by: LH Lin Signed-off-by: Sebastian Reichel --- drivers/power/supply/test_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_power.c index b3c05ff05783..04acd76bbaa1 100644 --- a/drivers/power/supply/test_power.c +++ b/drivers/power/supply/test_power.c @@ -34,7 +34,7 @@ static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; static int battery_capacity = 50; static int battery_voltage = 3300; static int battery_charge_counter = -1000; -static int battery_current = 1600; +static int battery_current = -1600; static bool module_initialized; -- cgit v1.2.3 From 36d1b6997dd6a4f3be194dde6553c3dcc2f7f07a Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 29 Jul 2020 13:31:42 -0500 Subject: dt-bindings: power: Add BQ27Z561 compatible Add the Texas Instruments bq27z561 battery monitor to the bq27xxx binding. Acked-by: Rob Herring Signed-off-by: Dan Murphy Signed-off-by: Sebastian Reichel --- Documentation/devicetree/bindings/power/supply/bq27xxx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml b/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml index 03d1020a2e47..0aa33590ac24 100644 --- a/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml @@ -49,6 +49,7 @@ properties: - ti,bq27426 - ti,bq27441 - ti,bq27621 + - ti,bq27z561 reg: maxItems: 1 -- cgit v1.2.3 From 6f24ff97e3231a5303841c5196a6f460f8485eb4 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 29 Jul 2020 13:31:43 -0500 Subject: power: supply: bq27xxx_battery: Add the BQ27Z561 Battery monitor Add the Texas Instruments BQ27Z561 battery monitor. The register address map is laid out the same as compared to other devices within the file. The battery status register has differing bits to determine if the battery is full, discharging or dead. Signed-off-by: Dan Murphy Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 68 +++++++++++++++++++++++++++++- drivers/power/supply/bq27xxx_battery_i2c.c | 2 + include/linux/power/bq27xxx_battery.h | 1 + 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index acaafed037be..a05b9a2d112d 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -43,6 +43,7 @@ * https://www.ti.com/product/bq27411-g1 * https://www.ti.com/product/bq27441-g1 * https://www.ti.com/product/bq27621-g1 + * https://www.ti.com/product/bq27z561 */ #include @@ -79,6 +80,11 @@ #define BQ27000_FLAG_FC BIT(5) #define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ +/* BQ27Z561 has different layout for Flags register */ +#define BQ27Z561_FLAG_FDC BIT(4) /* Battery fully discharged */ +#define BQ27Z561_FLAG_FC BIT(5) /* Battery fully charged */ +#define BQ27Z561_FLAG_DIS_CH BIT(6) /* Battery is discharging */ + /* control register params */ #define BQ27XXX_SEALED 0x20 #define BQ27XXX_SET_CFGUPDATE 0x13 @@ -431,12 +437,32 @@ static u8 [BQ27XXX_REG_DCAP] = 0x3c, [BQ27XXX_REG_AP] = 0x18, BQ27XXX_DM_REG_ROWS, - }; + }, #define bq27411_regs bq27421_regs #define bq27425_regs bq27421_regs #define bq27426_regs bq27421_regs #define bq27441_regs bq27421_regs #define bq27621_regs bq27421_regs + bq27z561_regs[BQ27XXX_REG_MAX] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x22, + BQ27XXX_DM_REG_ROWS, + }; static enum power_supply_property bq27000_props[] = { POWER_SUPPLY_PROP_STATUS, @@ -672,6 +698,25 @@ static enum power_supply_property bq27421_props[] = { #define bq27441_props bq27421_props #define bq27621_props bq27421_props +static enum power_supply_property bq27z561_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + struct bq27xxx_dm_reg { u8 subclass_id; u8 offset; @@ -767,11 +812,14 @@ static struct bq27xxx_dm_reg bq27621_dm_regs[] = { #define bq27621_dm_regs 0 #endif +#define bq27z561_dm_regs 0 + #define BQ27XXX_O_ZERO 0x00000001 #define BQ27XXX_O_OTDC 0x00000002 /* has OTC/OTD overtemperature flags */ #define BQ27XXX_O_UTOT 0x00000004 /* has OT overtemperature flag */ #define BQ27XXX_O_CFGUP 0x00000008 #define BQ27XXX_O_RAM 0x00000010 +#define BQ27Z561_O_BITS 0x00000020 #define BQ27XXX_DATA(ref, key, opt) { \ .opts = (opt), \ @@ -816,6 +864,7 @@ static struct { [BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), + [BQ27Z561] = BQ27XXX_DATA(bq27z561, 0 , BQ27Z561_O_BITS), }; static DEFINE_MUTEX(bq27xxx_list_lock); @@ -1551,6 +1600,8 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) { if (di->opts & BQ27XXX_O_ZERO) return flags & (BQ27000_FLAG_EDV1 | BQ27000_FLAG_EDVF); + else if (di->opts & BQ27Z561_O_BITS) + return flags & BQ27Z561_FLAG_FDC; else return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF); } @@ -1595,6 +1646,7 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di) cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); + cache.charge_full = bq27xxx_battery_read_fcc(di); cache.capacity = bq27xxx_battery_read_soc(di); if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) @@ -1682,6 +1734,13 @@ static int bq27xxx_battery_status(struct bq27xxx_device_info *di, status = POWER_SUPPLY_STATUS_NOT_CHARGING; else status = POWER_SUPPLY_STATUS_DISCHARGING; + } else if (di->opts & BQ27Z561_O_BITS) { + if (di->cache.flags & BQ27Z561_FLAG_FC) + status = POWER_SUPPLY_STATUS_FULL; + else if (di->cache.flags & BQ27Z561_FLAG_DIS_CH) + status = POWER_SUPPLY_STATUS_DISCHARGING; + else + status = POWER_SUPPLY_STATUS_CHARGING; } else { if (di->cache.flags & BQ27XXX_FLAG_FC) status = POWER_SUPPLY_STATUS_FULL; @@ -1710,6 +1769,13 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di, level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; else level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; + } else if (di->opts & BQ27Z561_O_BITS) { + if (di->cache.flags & BQ27Z561_FLAG_FC) + level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; + else if (di->cache.flags & BQ27Z561_FLAG_FDC) + level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + else + level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; } else { if (di->cache.flags & BQ27XXX_FLAG_FC) level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 8e114a7abfc9..15f4e75786ab 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -253,6 +253,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = { { "bq27426", BQ27426 }, { "bq27441", BQ27441 }, { "bq27621", BQ27621 }, + { "bq27z561", BQ27Z561 }, {}, }; MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table); @@ -286,6 +287,7 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = { { .compatible = "ti,bq27426" }, { .compatible = "ti,bq27441" }, { .compatible = "ti,bq27621" }, + { .compatible = "ti,bq27z561" }, {}, }; MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table); diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index 507c5e214c42..1f6ea5d5063d 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -30,6 +30,7 @@ enum bq27xxx_chip { BQ27426, BQ27441, BQ27621, + BQ27Z561, }; struct bq27xxx_device_info; -- cgit v1.2.3 From 0827425db7a65259db50c188a26aa2ad74a3cc3a Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 29 Jul 2020 13:31:44 -0500 Subject: dt-bindings: power: Add BQ28z610 compatible Add the Texas Instruments bq28z610 battery monitor to the bq27xxx binding. Acked-by: Rob Herring Signed-off-by: Dan Murphy Signed-off-by: Sebastian Reichel --- Documentation/devicetree/bindings/power/supply/bq27xxx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml b/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml index 0aa33590ac24..82f682705f44 100644 --- a/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml @@ -50,6 +50,7 @@ properties: - ti,bq27441 - ti,bq27621 - ti,bq27z561 + - ti,bq28z610 reg: maxItems: 1 -- cgit v1.2.3 From 707d678a5c7c5e80d1caac6c6b021171f5ecde58 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 29 Jul 2020 13:31:45 -0500 Subject: power: supply: bq27xxx_battery: Add the BQ28z610 Battery monitor Add the Texas Instruments BQ28z610 battery monitor. The register address map is laid out the same as compared to other devices within the file. The battery status register bits are similar to the bq27z561 but they are different compared to other fuel gauge devices within this file. Signed-off-by: Dan Murphy Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 42 ++++++++++++++++++++++++++++++ drivers/power/supply/bq27xxx_battery_i2c.c | 2 ++ include/linux/power/bq27xxx_battery.h | 1 + 3 files changed, 45 insertions(+) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index a05b9a2d112d..a123f6e21f08 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -44,6 +44,7 @@ * https://www.ti.com/product/bq27441-g1 * https://www.ti.com/product/bq27621-g1 * https://www.ti.com/product/bq27z561 + * https://www.ti.com/product/bq28z610 */ #include @@ -462,6 +463,26 @@ static u8 [BQ27XXX_REG_DCAP] = 0x3c, [BQ27XXX_REG_AP] = 0x22, BQ27XXX_DM_REG_ROWS, + }, + bq28z610_regs[BQ27XXX_REG_MAX] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x22, + BQ27XXX_DM_REG_ROWS, }; static enum power_supply_property bq27000_props[] = { @@ -717,6 +738,25 @@ static enum power_supply_property bq27z561_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; +static enum power_supply_property bq28z610_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + struct bq27xxx_dm_reg { u8 subclass_id; u8 offset; @@ -813,6 +853,7 @@ static struct bq27xxx_dm_reg bq27621_dm_regs[] = { #endif #define bq27z561_dm_regs 0 +#define bq28z610_dm_regs 0 #define BQ27XXX_O_ZERO 0x00000001 #define BQ27XXX_O_OTDC 0x00000002 /* has OTC/OTD overtemperature flags */ @@ -865,6 +906,7 @@ static struct { [BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27Z561] = BQ27XXX_DATA(bq27z561, 0 , BQ27Z561_O_BITS), + [BQ28Z610] = BQ27XXX_DATA(bq28z610, 0 , BQ27Z561_O_BITS), }; static DEFINE_MUTEX(bq27xxx_list_lock); diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 15f4e75786ab..ab02456d69e5 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -254,6 +254,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = { { "bq27441", BQ27441 }, { "bq27621", BQ27621 }, { "bq27z561", BQ27Z561 }, + { "bq28z610", BQ28Z610 }, {}, }; MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table); @@ -288,6 +289,7 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = { { .compatible = "ti,bq27441" }, { .compatible = "ti,bq27621" }, { .compatible = "ti,bq27z561" }, + { .compatible = "ti,bq28z610" }, {}, }; MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table); diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index 1f6ea5d5063d..987d9652aa4e 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -31,6 +31,7 @@ enum bq27xxx_chip { BQ27441, BQ27621, BQ27Z561, + BQ28Z610, }; struct bq27xxx_device_info; -- cgit v1.2.3 From 46cbd0b05799e8234b719d18f3a4b27679c4c92e Mon Sep 17 00:00:00 2001 From: Crag Wang Date: Thu, 30 Jul 2020 11:26:09 +0800 Subject: power: supply: wilco_ec: Add long life charging mode This is a long life mode set in the factory for extended warranty battery, the power charging rate is customized so that battery at work last longer. Presently switching to a different battery charging mode is through EC PID 0x0710 to configure the battery firmware, this operation will be blocked by EC with failure code 0x01 when PLL mode is already in use. Signed-off-by: Crag Wang Reviewed-by: Mario Limonciello Signed-off-by: Sebastian Reichel --- Documentation/ABI/testing/sysfs-class-power-wilco | 4 ++++ drivers/power/supply/power_supply_sysfs.c | 1 + drivers/power/supply/wilco-charger.c | 5 +++++ include/linux/power_supply.h | 1 + 4 files changed, 11 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-power-wilco b/Documentation/ABI/testing/sysfs-class-power-wilco index da1d6ffe5e3c..84fde1d0ada0 100644 --- a/Documentation/ABI/testing/sysfs-class-power-wilco +++ b/Documentation/ABI/testing/sysfs-class-power-wilco @@ -14,6 +14,10 @@ Description: Charging begins when level drops below charge_control_start_threshold, and ceases when level is above charge_control_end_threshold. + Long Life: Customized charge rate for last longer battery life. + On Wilco device this mode is pre-configured in the factory + through EC's private PID. Swiching to a different mode will + be denied by Wilco EC when Long Life mode is enabled. What: /sys/class/power_supply/wilco-charger/charge_control_start_threshold Date: April 2019 diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index b903cb4dca2b..3d383086018c 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -87,6 +87,7 @@ static const char * const POWER_SUPPLY_CHARGE_TYPE_TEXT[] = { [POWER_SUPPLY_CHARGE_TYPE_STANDARD] = "Standard", [POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE] = "Adaptive", [POWER_SUPPLY_CHARGE_TYPE_CUSTOM] = "Custom", + [POWER_SUPPLY_CHARGE_TYPE_LONGLIFE] = "Long Life", }; static const char * const POWER_SUPPLY_HEALTH_TEXT[] = { diff --git a/drivers/power/supply/wilco-charger.c b/drivers/power/supply/wilco-charger.c index b3c6d7cdd731..98ade073ef05 100644 --- a/drivers/power/supply/wilco-charger.c +++ b/drivers/power/supply/wilco-charger.c @@ -27,6 +27,7 @@ enum charge_mode { CHARGE_MODE_AC = 3, /* Mostly AC use, used for Trickle */ CHARGE_MODE_AUTO = 4, /* Used for Adaptive */ CHARGE_MODE_CUSTOM = 5, /* Used for Custom */ + CHARGE_MODE_LONGLIFE = 6, /* Used for Long Life */ }; #define CHARGE_LOWER_LIMIT_MIN 50 @@ -48,6 +49,8 @@ static int psp_val_to_charge_mode(int psp_val) return CHARGE_MODE_AUTO; case POWER_SUPPLY_CHARGE_TYPE_CUSTOM: return CHARGE_MODE_CUSTOM; + case POWER_SUPPLY_CHARGE_TYPE_LONGLIFE: + return CHARGE_MODE_LONGLIFE; default: return -EINVAL; } @@ -67,6 +70,8 @@ static int charge_mode_to_psp_val(enum charge_mode mode) return POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE; case CHARGE_MODE_CUSTOM: return POWER_SUPPLY_CHARGE_TYPE_CUSTOM; + case CHARGE_MODE_LONGLIFE: + return POWER_SUPPLY_CHARGE_TYPE_LONGLIFE; default: return -EINVAL; } diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index b5ee35d3c304..97cc4b85bf61 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -48,6 +48,7 @@ enum { POWER_SUPPLY_CHARGE_TYPE_STANDARD, /* normal speed */ POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE, /* dynamically adjusted speed */ POWER_SUPPLY_CHARGE_TYPE_CUSTOM, /* use CHARGE_CONTROL_* props */ + POWER_SUPPLY_CHARGE_TYPE_LONGLIFE, /* slow speed, longer life */ }; enum { -- cgit v1.2.3