From 0188155a234bf77c7588bdedf3b77cc87bfeb7df Mon Sep 17 00:00:00 2001 From: Michael Heinemann Date: Fri, 7 Jul 2017 16:23:54 +0200 Subject: power: supply: sbs-battery: correct capacity mode selection bits The capacity mode bit is bit 15. Currently it is written as default initialized enum and never shifted. This leads to a behaviour where the BATTERY_MODE is not correctly recognized and set again. This commit initializes the enum accordingly. Signed-off-by: Michael Heinemann Tested-by: Phil Reid Signed-off-by: Sebastian Reichel --- drivers/power/supply/sbs-battery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index f7059459f0fb..e8065af085bd 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -60,8 +60,8 @@ enum { #define BATTERY_MODE_OFFSET 0x03 #define BATTERY_MODE_MASK 0x8000 enum sbs_battery_mode { - BATTERY_MODE_AMPS, - BATTERY_MODE_WATTS + BATTERY_MODE_AMPS = 0, + BATTERY_MODE_WATTS = 0x8000 }; /* manufacturer access defines */ -- cgit v1.2.3 From 8b35bf5927b1e89e9b2f9ddbd701bd9b27456e78 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 21 Jul 2017 18:14:37 +0200 Subject: power: supply: cpcap-charger: add OMAP_USB2 dependency When CONFIG_OMAP_USB2 is set to 'm' and the charger driver is built-in, we get this link failure: drivers/power/supply/cpcap-charger.o: In function `cpcap_charger_probe': cpcap-charger.c:(.text+0x48c): undefined reference to `omap_usb2_set_comparator' drivers/power/supply/cpcap-charger.o: In function `cpcap_charger_remove': cpcap-charger.c:(.text+0x774): undefined reference to `omap_usb2_set_comparator' This adds a dependency to prevent that problem, while still allowing compile-testing with the OMAP_USB2 driver completely disabled. Fixes: 0c9888e3c192 ("power: supply: cpcap-charger: Add minimal CPCAP PMIC battery charger") Signed-off-by: Arnd Bergmann Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/power') diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 969f5005669c..765f9ac0a4e7 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -365,6 +365,7 @@ config BATTERY_RX51 config CHARGER_CPCAP tristate "CPCAP PMIC Charger Driver" depends on MFD_CPCAP && IIO + depends on OMAP_USB2 || (!OMAP_USB2 && COMPILE_TEST) default MFD_CPCAP help Say Y to enable support for CPCAP PMIC charger driver for Motorola -- cgit v1.2.3 From 648b8eba20d0bdce9de41df97677e70aa53693ea Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 16 Jul 2017 20:52:20 +0300 Subject: power: supply: act8945a_charger: fix of_irq_get() error check of_irq_get() may return any negative error number as well as 0 on failure, while the driver only checks for -EPROBE_DEFER, blithely continuing with the call to devm_request_irq() -- that function expects *unsigned int*, so would probably fail anyway when a large IRQ number resulting from a conversion of a negative error number is passed to it... This, however, is incorrect behavior -- error number is not IRQ number. Check for 'irq <= 0' instead and return -ENXIO from probe if of_irq_get() returned 0. Fixes: a09209acd6a8 ("power: supply: act8945a_charger: Add status change update support") Signed-off-by: Sergei Shtylyov Signed-off-by: Sebastian Reichel --- drivers/power/supply/act8945a_charger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index d1eb2e359532..8e117b31ba79 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -596,9 +596,9 @@ static int act8945a_charger_probe(struct platform_device *pdev) return ret; irq = of_irq_get(pdev->dev.of_node, 0); - if (irq == -EPROBE_DEFER) { + if (irq <= 0) { dev_err(&pdev->dev, "failed to find IRQ number\n"); - return -EPROBE_DEFER; + return irq ?: -ENXIO; } ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, -- cgit v1.2.3 From 2f04cd2a9b13f9d8681248f49e907051b1f1426e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 18 Jul 2017 16:43:24 -0500 Subject: power: reset: Convert to using %pOF instead of full_name Now that we have a custom printf format specifier, convert users of full_name to use %pOF instead. This is preparation to remove storing of the full path string for each node. Signed-off-by: Rob Herring Cc: Nicolas Ferre Cc: Sebastian Reichel Cc: linux-pm@vger.kernel.org Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-sama5d2_shdwc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index 55fce8b75245..31080c254124 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -171,8 +171,8 @@ static u32 at91_shdwc_get_wakeup_input(struct platform_device *pdev, for_each_child_of_node(np, cnp) { if (of_property_read_u32(cnp, "reg", &wk_input)) { - dev_warn(&pdev->dev, "reg property is missing for %s\n", - cnp->full_name); + dev_warn(&pdev->dev, "reg property is missing for %pOF\n", + cnp); continue; } -- cgit v1.2.3 From 980092efd497dd691438e086dd929c1b04ecc529 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 12 Jul 2017 17:13:22 +0530 Subject: power: supply: constify attribute_group structures. attribute_groups are not supposed to change at runtime. All functions working with attribute_groups provided by work with const attribute_group. So mark the non-const structs as const. File size before: text data bss dec hex filename 2673 400 0 3073 c01 power/supply/pcf50633-charger.o File size After adding 'const': text data bss dec hex filename 2737 336 0 3073 bed power/supply/pcf50633-charger.o Signed-off-by: Arvind Yadav Signed-off-by: Sebastian Reichel --- drivers/power/supply/pcf50633-charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/pcf50633-charger.c b/drivers/power/supply/pcf50633-charger.c index b3c1873ad84d..1ad7ccce6075 100644 --- a/drivers/power/supply/pcf50633-charger.c +++ b/drivers/power/supply/pcf50633-charger.c @@ -254,7 +254,7 @@ static struct attribute *pcf50633_mbc_sysfs_entries[] = { NULL, }; -static struct attribute_group mbc_attr_group = { +static const struct attribute_group mbc_attr_group = { .name = NULL, /* put in device directory */ .attrs = pcf50633_mbc_sysfs_entries, }; -- cgit v1.2.3 From 10e48b7d73487114bdd13bc1ebd10b6ba62de25b Mon Sep 17 00:00:00 2001 From: "Alex A. Mihaylov" Date: Thu, 6 Jul 2017 16:10:16 +0300 Subject: power: supply: Add support for MAX1721x standalone fuel gauge The MAX17211 monitor a single cell pack. The MAX17215 monitor and balance a 2S or 3S pack or monitor a multiple-series cell pack. Both device use 1-Wire interfce. Signed-off-by: Alex A. Mihaylov Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 13 + drivers/power/supply/Makefile | 1 + drivers/power/supply/max1721x_battery.c | 448 ++++++++++++++++++++++++++++++++ 3 files changed, 462 insertions(+) create mode 100644 drivers/power/supply/max1721x_battery.c (limited to 'drivers/power') diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 969f5005669c..15c80c7f8f9e 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -313,6 +313,19 @@ config BATTERY_MAX17042 with MAX17042. This driver also supports max17047/50 chips which are improved version of max17042. +config BATTERY_MAX1721X + tristate "MAX17211/MAX17215 standalone gas-gauge" + depends on W1 + select REGMAP_W1 + help + MAX1721x is fuel-gauge systems for lithium-ion (Li+) batteries + in handheld and portable equipment. MAX17211 used with single cell + battery. MAX17215 designed for muticell battery. Both them have + OneWire (W1) host interface. + + Say Y here to enable support for the MAX17211/MAX17215 standalone + battery gas-gauge. + config BATTERY_Z2 tristate "Z2 battery driver" depends on I2C && MACH_ZIPIT2 diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index a41f40957847..509131673355 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_CHARGER_DA9150) += da9150-charger.o obj-$(CONFIG_BATTERY_DA9150) += da9150-fg.o obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o +obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o obj-$(CONFIG_BATTERY_Z2) += z2_battery.o obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o diff --git a/drivers/power/supply/max1721x_battery.c b/drivers/power/supply/max1721x_battery.c new file mode 100644 index 000000000000..9ee601a03d9b --- /dev/null +++ b/drivers/power/supply/max1721x_battery.c @@ -0,0 +1,448 @@ +/* + * 1-Wire implementation for Maxim Semiconductor + * MAX7211/MAX17215 stanalone fuel gauge chip + * + * Copyright (C) 2017 Radioavionica Corporation + * Author: Alex A. Mihaylov + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + */ + +#include +#include +#include +#include +#include + +#define W1_MAX1721X_FAMILY_ID 0x26 +#define DEF_DEV_NAME_MAX17211 "MAX17211" +#define DEF_DEV_NAME_MAX17215 "MAX17215" +#define DEF_DEV_NAME_UNKNOWN "UNKNOWN" +#define DEF_MFG_NAME "MAXIM" + +#define PSY_MAX_NAME_LEN 32 + +/* Number of valid register addresses in W1 mode */ +#define MAX1721X_MAX_REG_NR 0x1EF + +/* Factory settings (nonvilatile registers) (W1 specific) */ +#define MAX1721X_REG_NRSENSE 0x1CF /* RSense in 10^-5 Ohm */ +/* Strings */ +#define MAX1721X_REG_MFG_STR 0x1CC +#define MAX1721X_REG_MFG_NUMB 3 +#define MAX1721X_REG_DEV_STR 0x1DB +#define MAX1721X_REG_DEV_NUMB 5 +/* HEX Strings */ +#define MAX1721X_REG_SER_HEX 0x1D8 + +/* MAX172XX Output Registers for W1 chips */ +#define MAX172XX_REG_STATUS 0x000 /* status reg */ +#define MAX172XX_BAT_PRESENT (1<<4) /* battery connected bit */ +#define MAX172XX_REG_DEVNAME 0x021 /* chip config */ +#define MAX172XX_DEV_MASK 0x000F /* chip type mask */ +#define MAX172X1_DEV 0x0001 +#define MAX172X5_DEV 0x0005 +#define MAX172XX_REG_TEMP 0x008 /* Temperature */ +#define MAX172XX_REG_BATT 0x0DA /* Battery voltage */ +#define MAX172XX_REG_CURRENT 0x00A /* Actual current */ +#define MAX172XX_REG_AVGCURRENT 0x00B /* Average current */ +#define MAX172XX_REG_REPSOC 0x006 /* Percentage of charge */ +#define MAX172XX_REG_DESIGNCAP 0x018 /* Design capacity */ +#define MAX172XX_REG_REPCAP 0x005 /* Average capacity */ +#define MAX172XX_REG_TTE 0x011 /* Time to empty */ +#define MAX172XX_REG_TTF 0x020 /* Time to full */ + +struct max17211_device_info { + char name[PSY_MAX_NAME_LEN]; + struct power_supply *bat; + struct power_supply_desc bat_desc; + struct device *w1_dev; + struct regmap *regmap; + /* battery design format */ + unsigned int rsense; /* in tenths uOhm */ + char DeviceName[2 * MAX1721X_REG_DEV_NUMB + 1]; + char ManufacturerName[2 * MAX1721X_REG_MFG_NUMB + 1]; + char SerialNumber[13]; /* see get_sn_str() later for comment */ +}; + +/* Convert regs value to power_supply units */ + +static inline int max172xx_time_to_ps(unsigned int reg) +{ + return reg * 5625 / 1000; /* in sec. */ +} + +static inline int max172xx_percent_to_ps(unsigned int reg) +{ + return reg / 256; /* in percent from 0 to 100 */ +} + +static inline int max172xx_voltage_to_ps(unsigned int reg) +{ + return reg * 1250; /* in uV */ +} + +static inline int max172xx_capacity_to_ps(unsigned int reg) +{ + return reg * 500; /* in uAh */ +} + +/* + * Current and temperature is signed values, so unsigned regs + * value must be converted to signed type + */ + +static inline int max172xx_temperature_to_ps(unsigned int reg) +{ + int val = (int16_t)(reg); + + return val * 10 / 256; /* in tenths of deg. C */ +} + +/* + * Calculating current registers resolution: + * + * RSense stored in 10^-5 Ohm, so mesaurment voltage must be + * in 10^-11 Volts for get current in uA. + * 16 bit current reg fullscale +/-51.2mV is 102400 uV. + * So: 102400 / 65535 * 10^5 = 156252 + */ +static inline int max172xx_current_to_voltage(unsigned int reg) +{ + int val = (int16_t)(reg); + + return val * 156252; +} + + +static inline struct max17211_device_info * +to_device_info(struct power_supply *psy) +{ + return power_supply_get_drvdata(psy); +} + +static int max1721x_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max17211_device_info *info = to_device_info(psy); + unsigned int reg = 0; + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + /* + * POWER_SUPPLY_PROP_PRESENT will always readable via + * sysfs interface. Value return 0 if battery not + * present or unaccesable via W1. + */ + val->intval = + regmap_read(info->regmap, MAX172XX_REG_STATUS, + ®) ? 0 : !(reg & MAX172XX_BAT_PRESENT); + break; + case POWER_SUPPLY_PROP_CAPACITY: + ret = regmap_read(info->regmap, MAX172XX_REG_REPSOC, ®); + val->intval = max172xx_percent_to_ps(reg); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = regmap_read(info->regmap, MAX172XX_REG_BATT, ®); + val->intval = max172xx_voltage_to_ps(reg); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + ret = regmap_read(info->regmap, MAX172XX_REG_DESIGNCAP, ®); + val->intval = max172xx_capacity_to_ps(reg); + break; + case POWER_SUPPLY_PROP_CHARGE_AVG: + ret = regmap_read(info->regmap, MAX172XX_REG_REPCAP, ®); + val->intval = max172xx_capacity_to_ps(reg); + break; + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: + ret = regmap_read(info->regmap, MAX172XX_REG_TTE, ®); + val->intval = max172xx_time_to_ps(reg); + break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: + ret = regmap_read(info->regmap, MAX172XX_REG_TTF, ®); + val->intval = max172xx_time_to_ps(reg); + break; + case POWER_SUPPLY_PROP_TEMP: + ret = regmap_read(info->regmap, MAX172XX_REG_TEMP, ®); + val->intval = max172xx_temperature_to_ps(reg); + break; + /* We need signed current, so must cast info->rsense to signed type */ + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret = regmap_read(info->regmap, MAX172XX_REG_CURRENT, ®); + val->intval = + max172xx_current_to_voltage(reg) / (int)info->rsense; + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + ret = regmap_read(info->regmap, MAX172XX_REG_AVGCURRENT, ®); + val->intval = + max172xx_current_to_voltage(reg) / (int)info->rsense; + break; + /* + * Strings already received and inited by probe. + * We do dummy read for check battery still available. + */ + case POWER_SUPPLY_PROP_MODEL_NAME: + ret = regmap_read(info->regmap, MAX1721X_REG_DEV_STR, ®); + val->strval = info->DeviceName; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + ret = regmap_read(info->regmap, MAX1721X_REG_MFG_STR, ®); + val->strval = info->ManufacturerName; + break; + case POWER_SUPPLY_PROP_SERIAL_NUMBER: + ret = regmap_read(info->regmap, MAX1721X_REG_SER_HEX, ®); + val->strval = info->SerialNumber; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static enum power_supply_property max1721x_battery_props[] = { + /* int */ + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_AVG, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, + POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_AVG, + /* strings */ + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_SERIAL_NUMBER, +}; + +static int get_string(struct max17211_device_info *info, + uint16_t reg, uint8_t nr, char *str) +{ + unsigned int val; + + if (!str || !(reg == MAX1721X_REG_MFG_STR || + reg == MAX1721X_REG_DEV_STR)) + return -EFAULT; + + while (nr--) { + if (regmap_read(info->regmap, reg++, &val)) + return -EFAULT; + *str++ = val>>8 & 0x00FF; + *str++ = val & 0x00FF; + } + return 0; +} + +/* Maxim say: Serial number is a hex string up to 12 hex characters */ +static int get_sn_string(struct max17211_device_info *info, char *str) +{ + unsigned int val[3]; + + if (!str) + return -EFAULT; + + if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &val[0])) + return -EFAULT; + if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 1, &val[1])) + return -EFAULT; + if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 2, &val[2])) + return -EFAULT; + + snprintf(str, 13, "%04X%04X%04X", val[0], val[1], val[2]); + return 0; +} + +/* + * MAX1721x registers description for w1-regmap + */ +static const struct regmap_range max1721x_allow_range[] = { + regmap_reg_range(0, 0xDF), /* volatile data */ + regmap_reg_range(0x180, 0x1DF), /* non-volatile memory */ + regmap_reg_range(0x1E0, 0x1EF), /* non-volatile history (unused) */ +}; + +static const struct regmap_range max1721x_deny_range[] = { + /* volatile data unused registers */ + regmap_reg_range(0x24, 0x26), + regmap_reg_range(0x30, 0x31), + regmap_reg_range(0x33, 0x34), + regmap_reg_range(0x37, 0x37), + regmap_reg_range(0x3B, 0x3C), + regmap_reg_range(0x40, 0x41), + regmap_reg_range(0x43, 0x44), + regmap_reg_range(0x47, 0x49), + regmap_reg_range(0x4B, 0x4C), + regmap_reg_range(0x4E, 0xAF), + regmap_reg_range(0xB1, 0xB3), + regmap_reg_range(0xB5, 0xB7), + regmap_reg_range(0xBF, 0xD0), + regmap_reg_range(0xDB, 0xDB), + /* hole between volatile and non-volatile registers */ + regmap_reg_range(0xE0, 0x17F), +}; + +static const struct regmap_access_table max1721x_regs = { + .yes_ranges = max1721x_allow_range, + .n_yes_ranges = ARRAY_SIZE(max1721x_allow_range), + .no_ranges = max1721x_deny_range, + .n_no_ranges = ARRAY_SIZE(max1721x_deny_range), +}; + +/* + * Model Gauge M5 Algorithm output register + * Volatile data (must not be cached) + */ +static const struct regmap_range max1721x_volatile_allow[] = { + regmap_reg_range(0, 0xDF), +}; + +static const struct regmap_access_table max1721x_volatile_regs = { + .yes_ranges = max1721x_volatile_allow, + .n_yes_ranges = ARRAY_SIZE(max1721x_volatile_allow), +}; + +/* + * W1-regmap config + */ +static const struct regmap_config max1721x_regmap_w1_config = { + .reg_bits = 16, + .val_bits = 16, + .rd_table = &max1721x_regs, + .volatile_table = &max1721x_volatile_regs, + .max_register = MAX1721X_MAX_REG_NR, +}; + +static int devm_w1_max1721x_add_device(struct w1_slave *sl) +{ + struct power_supply_config psy_cfg = {}; + struct max17211_device_info *info; + + info = devm_kzalloc(&sl->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + sl->family_data = (void *)info; + info->w1_dev = &sl->dev; + + /* + * power_supply class battery name translated from W1 slave device + * unical ID (look like 26-0123456789AB) to "max1721x-0123456789AB\0" + * so, 26 (device family) correcpondent to max1721x devices. + * Device name still unical for any numbers connected devices. + */ + snprintf(info->name, sizeof(info->name), + "max1721x-%012X", (unsigned int)sl->reg_num.id); + info->bat_desc.name = info->name; + + /* + * FixMe: battery device name exceed max len for thermal_zone device + * name and translation to thermal_zone must be disabled. + */ + info->bat_desc.no_thermal = true; + info->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; + info->bat_desc.properties = max1721x_battery_props; + info->bat_desc.num_properties = ARRAY_SIZE(max1721x_battery_props); + info->bat_desc.get_property = max1721x_battery_get_property; + psy_cfg.drv_data = info; + + /* regmap init */ + info->regmap = devm_regmap_init_w1(info->w1_dev, + &max1721x_regmap_w1_config); + if (IS_ERR(info->regmap)) { + int err = PTR_ERR(info->regmap); + + dev_err(info->w1_dev, "Failed to allocate register map: %d\n", + err); + return err; + } + + /* rsense init */ + info->rsense = 0; + if (regmap_read(info->regmap, MAX1721X_REG_NRSENSE, &info->rsense)) { + dev_err(info->w1_dev, "Can't read RSense. Hardware error.\n"); + return -ENODEV; + } + + if (!info->rsense) { + dev_warn(info->w1_dev, "RSenese not calibrated, set 10 mOhms!\n"); + info->rsense = 1000; /* in regs in 10^-5 */ + } + dev_info(info->w1_dev, "RSense: %d mOhms.\n", info->rsense / 100); + + if (get_string(info, MAX1721X_REG_MFG_STR, + MAX1721X_REG_MFG_NUMB, info->ManufacturerName)) { + dev_err(info->w1_dev, "Can't read manufacturer. Hardware error.\n"); + return -ENODEV; + } + + if (!info->ManufacturerName[0]) + strncpy(info->ManufacturerName, DEF_MFG_NAME, + 2 * MAX1721X_REG_MFG_NUMB); + + if (get_string(info, MAX1721X_REG_DEV_STR, + MAX1721X_REG_DEV_NUMB, info->DeviceName)) { + dev_err(info->w1_dev, "Can't read device. Hardware error.\n"); + return -ENODEV; + } + if (!info->DeviceName[0]) { + unsigned int dev_name; + + if (regmap_read(info->regmap, + MAX172XX_REG_DEVNAME, &dev_name)) { + dev_err(info->w1_dev, "Can't read device name reg.\n"); + return -ENODEV; + } + + switch (dev_name & MAX172XX_DEV_MASK) { + case MAX172X1_DEV: + strncpy(info->DeviceName, DEF_DEV_NAME_MAX17211, + 2 * MAX1721X_REG_DEV_NUMB); + break; + case MAX172X5_DEV: + strncpy(info->DeviceName, DEF_DEV_NAME_MAX17215, + 2 * MAX1721X_REG_DEV_NUMB); + break; + default: + strncpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN, + 2 * MAX1721X_REG_DEV_NUMB); + } + } + + if (get_sn_string(info, info->SerialNumber)) { + dev_err(info->w1_dev, "Can't read serial. Hardware error.\n"); + return -ENODEV; + } + + info->bat = devm_power_supply_register(&sl->dev, &info->bat_desc, + &psy_cfg); + if (IS_ERR(info->bat)) { + dev_err(info->w1_dev, "failed to register battery\n"); + return PTR_ERR(info->bat); + } + + return 0; +} + +static struct w1_family_ops w1_max1721x_fops = { + .add_slave = devm_w1_max1721x_add_device, +}; + +static struct w1_family w1_max1721x_family = { + .fid = W1_MAX1721X_FAMILY_ID, + .fops = &w1_max1721x_fops, +}; + +module_w1_family(w1_max1721x_family); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alex A. Mihaylov "); +MODULE_DESCRIPTION("Maxim MAX17211/MAX17215 Fuel Gauage IC driver"); +MODULE_ALIAS("w1-family-" __stringify(W1_MAX1721X_FAMILY_ID)); -- cgit v1.2.3 From 6d1eebc99bd5ed17ad6d8554be7b76bde2238e4a Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Tue, 11 Jul 2017 17:43:41 +0800 Subject: power: supply: sbs-battery: Remove FSF mailing address from comments checkpatch issued an error in having the FSF address in the comment. As address may change and Linux already includes a copy. Signed-off-by: Phil Reid Signed-off-by: Sebastian Reichel --- drivers/power/supply/sbs-battery.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index e8065af085bd..f3489856af18 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -12,10 +12,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -- cgit v1.2.3 From b70f0a28966082d5392f90c2d4cb1514a2d65ac6 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Tue, 11 Jul 2017 17:43:42 +0800 Subject: power: supply: sbs-battery: sort includes Sort the header includes prior to adding to the list. Signed-off-by: Phil Reid Signed-off-by: Sebastian Reichel --- drivers/power/supply/sbs-battery.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index f3489856af18..a5eacc4b35e3 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -14,19 +14,18 @@ * more details. */ -#include -#include -#include #include -#include +#include #include -#include +#include #include -#include +#include +#include #include -#include - #include +#include +#include +#include enum { REG_MANUFACTURER_DATA, -- cgit v1.2.3 From adcf04c9f8fce54e65f11bae2fbd37c1282ef128 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Tue, 11 Jul 2017 17:43:43 +0800 Subject: power: supply: sbs-battery: Add delay when changing capacity mode bit At least with the Inspired Energy compatible batteries a delay is required after setting the capacity mode bit from amp to watts or the reverse. Setting the bit and then immediately pooling the status register results in an unknown error being returned in the register. Add the delay results in and ok status being return. This was also seen when reading the charge and energy registers where the wrong value was returned for the requested mode. Signed-off-by: Phil Reid Tested-by: Michael Heinemann Signed-off-by: Sebastian Reichel --- drivers/power/supply/sbs-battery.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/power') diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index a5eacc4b35e3..b19a73176910 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -14,6 +14,7 @@ * more details. */ +#include #include #include #include @@ -527,6 +528,8 @@ static enum sbs_battery_mode sbs_set_battery_mode(struct i2c_client *client, if (ret < 0) return ret; + usleep_range(1000, 2000); + return original_val & BATTERY_MODE_MASK; } -- cgit v1.2.3 From 63e67c5769c23e0af729ecc2d28e4326f3a67a08 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Sun, 16 Jul 2017 11:33:06 +0200 Subject: power: supply: ltc2941-battery-gauge: Prepare for LTC2942 and LTC2944 In order to support LTC2942 which has temperature registers at different offsets than LTC2943 use following register naming scheme (prefixes): - LTC294X_ common registers - LTC2942_ chips specific registers - LTC2943_ specific registers LTC2944 is compatible with LTC2943 but uses different constants to compute voltage and current, so replace num_regs misused for device indentification with real device id to discriminate between those two. There are no functional changes. Signed-off-by: Ladislav Michl Acked-by: Dragos Bogdan Tested-by: Dragos Bogdan Signed-off-by: Sebastian Reichel --- drivers/power/supply/ltc2941-battery-gauge.c | 63 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 32 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c index 7efb908f4451..b0de448a226b 100644 --- a/drivers/power/supply/ltc2941-battery-gauge.c +++ b/drivers/power/supply/ltc2941-battery-gauge.c @@ -34,16 +34,19 @@ enum ltc294x_reg { LTC294X_REG_CONTROL = 0x01, LTC294X_REG_ACC_CHARGE_MSB = 0x02, LTC294X_REG_ACC_CHARGE_LSB = 0x03, - LTC294X_REG_THRESH_HIGH_MSB = 0x04, - LTC294X_REG_THRESH_HIGH_LSB = 0x05, - LTC294X_REG_THRESH_LOW_MSB = 0x06, - LTC294X_REG_THRESH_LOW_LSB = 0x07, - LTC294X_REG_VOLTAGE_MSB = 0x08, - LTC294X_REG_VOLTAGE_LSB = 0x09, - LTC294X_REG_CURRENT_MSB = 0x0E, - LTC294X_REG_CURRENT_LSB = 0x0F, - LTC294X_REG_TEMPERATURE_MSB = 0x14, - LTC294X_REG_TEMPERATURE_LSB = 0x15, + LTC294X_REG_VOLTAGE_MSB = 0x08, + LTC294X_REG_VOLTAGE_LSB = 0x09, + LTC2942_REG_TEMPERATURE_MSB = 0x0C, + LTC2942_REG_TEMPERATURE_LSB = 0x0D, + LTC2943_REG_CURRENT_MSB = 0x0E, + LTC2943_REG_CURRENT_LSB = 0x0F, + LTC2943_REG_TEMPERATURE_MSB = 0x14, + LTC2943_REG_TEMPERATURE_LSB = 0x15, +}; + +enum ltc294x_id { + LTC2941_ID, + LTC2943_ID, }; #define LTC2943_REG_CONTROL_MODE_MASK (BIT(7) | BIT(6)) @@ -54,15 +57,12 @@ enum ltc294x_reg { ((x << 3) & LTC294X_REG_CONTROL_PRESCALER_MASK) #define LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED 0 -#define LTC2941_NUM_REGS 0x08 -#define LTC2943_NUM_REGS 0x18 - struct ltc294x_info { struct i2c_client *client; /* I2C Client pointer */ struct power_supply *supply; /* Supply pointer */ struct power_supply_desc supply_desc; /* Supply description */ struct delayed_work work; /* Work scheduler */ - unsigned long num_regs; /* Number of registers (chip type) */ + enum ltc294x_id id; /* Chip type */ int charge; /* Last charge register content */ int r_sense; /* mOhm */ int Qlsb; /* nAh */ @@ -146,7 +146,7 @@ static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp) control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) | LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED; /* Put the 2943 into "monitor" mode, so it measures every 10 sec */ - if (info->num_regs == LTC2943_NUM_REGS) + if (info->id == LTC2941_ID) control |= LTC2943_REG_CONTROL_MODE_SCAN; if (value != control) { @@ -263,7 +263,7 @@ static int ltc294x_get_current(const struct ltc294x_info *info, int *val) s32 value; ret = ltc294x_read_regs(info->client, - LTC294X_REG_CURRENT_MSB, &datar[0], 2); + LTC2943_REG_CURRENT_MSB, &datar[0], 2); value = (datar[0] << 8) | datar[1]; value -= 0x7FFF; /* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm, @@ -280,7 +280,7 @@ static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val) u32 value; ret = ltc294x_read_regs(info->client, - LTC294X_REG_TEMPERATURE_MSB, &datar[0], 2); + LTC2943_REG_TEMPERATURE_MSB, &datar[0], 2); value = (datar[0] << 8) | datar[1]; /* Full-scale is 510 Kelvin, convert to centidegrees */ *val = (((51000 * value) / 0xFFFF) - 27215); @@ -357,8 +357,8 @@ static enum power_supply_property ltc294x_properties[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CURRENT_NOW, }; static int ltc294x_i2c_remove(struct i2c_client *client) @@ -388,7 +388,7 @@ static int ltc294x_i2c_probe(struct i2c_client *client, np = of_node_get(client->dev.of_node); - info->num_regs = (unsigned long)of_device_get_match_data(&client->dev); + info->id = (enum ltc294x_id)of_device_get_match_data(&client->dev); info->supply_desc.name = np->name; /* r_sense can be negative, when sense+ is connected to the battery @@ -409,7 +409,7 @@ static int ltc294x_i2c_probe(struct i2c_client *client, prescaler_exp = LTC2941_MAX_PRESCALER_EXP; } - if (info->num_regs == LTC2943_NUM_REGS) { + if (info->id == LTC2943_ID) { if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP) prescaler_exp = LTC2943_MAX_PRESCALER_EXP; info->Qlsb = ((340 * 50000) / r_sense) / @@ -424,18 +424,17 @@ static int ltc294x_i2c_probe(struct i2c_client *client, info->client = client; info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY; info->supply_desc.properties = ltc294x_properties; - if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB) + switch (info->id) { + case LTC2943_ID: info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties); - else if (info->num_regs >= LTC294X_REG_CURRENT_LSB) - info->supply_desc.num_properties = - ARRAY_SIZE(ltc294x_properties) - 1; - else if (info->num_regs >= LTC294X_REG_VOLTAGE_LSB) - info->supply_desc.num_properties = - ARRAY_SIZE(ltc294x_properties) - 2; - else + break; + case LTC2941_ID: + default: info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties) - 3; + break; + } info->supply_desc.get_property = ltc294x_get_property; info->supply_desc.set_property = ltc294x_set_property; info->supply_desc.property_is_writeable = ltc294x_property_is_writeable; @@ -492,8 +491,8 @@ static SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume); static const struct i2c_device_id ltc294x_i2c_id[] = { - {"ltc2941", LTC2941_NUM_REGS}, - {"ltc2943", LTC2943_NUM_REGS}, + { "ltc2941", LTC2941_ID, }, + { "ltc2943", LTC2943_ID, }, { }, }; MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id); @@ -501,11 +500,11 @@ MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id); static const struct of_device_id ltc294x_i2c_of_match[] = { { .compatible = "lltc,ltc2941", - .data = (void *)LTC2941_NUM_REGS + .data = (void *)LTC2941_ID, }, { .compatible = "lltc,ltc2943", - .data = (void *)LTC2943_NUM_REGS + .data = (void *)LTC2943_ID, }, { }, }; -- cgit v1.2.3 From a65df832f96588debbbdd93d392a4ff77d5d237c Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Sun, 16 Jul 2017 11:34:00 +0200 Subject: power: supply: ltc2941-battery-gauge: Add LTC2942 support LTC2942 is pin compatible with LTC2941 providing additional informations about battery voltage and temperature. It can be runtime detected using bit A7 in the Status register. Signed-off-by: Ladislav Michl Acked-by: Rob Herring Acked-by: Dragos Bogdan Tested-by: Dragos Bogdan Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/supply/ltc2941.txt | 15 ++-- drivers/power/supply/ltc2941-battery-gauge.c | 80 ++++++++++++++++++---- 2 files changed, 75 insertions(+), 20 deletions(-) (limited to 'drivers/power') diff --git a/Documentation/devicetree/bindings/power/supply/ltc2941.txt b/Documentation/devicetree/bindings/power/supply/ltc2941.txt index a9d7aa60558b..8ec10366295d 100644 --- a/Documentation/devicetree/bindings/power/supply/ltc2941.txt +++ b/Documentation/devicetree/bindings/power/supply/ltc2941.txt @@ -1,13 +1,14 @@ -binding for LTC2941 and LTC2943 battery gauges +binding for LTC2941, LTC2942 and LTC2943 battery gauges -Both the LTC2941 and LTC2943 measure battery capacity. -The LTC2943 is compatible with the LTC2941, it adds voltage and -temperature monitoring, and uses a slightly different conversion -formula for the charge counter. +All chips measure battery capacity. +The LTC2942 is pin compatible with the LTC2941, it adds voltage and +temperature monitoring, and is runtime detected. LTC2943 is software +compatible, uses a slightly different conversion formula for the +charge counter and adds voltage, current and temperature monitoring. Required properties: -- compatible: Should contain "lltc,ltc2941" or "lltc,ltc2943" which also - indicates the type of I2C chip attached. +- compatible: Should contain "lltc,ltc2941", "lltc,ltc2942" or "lltc,ltc2943" + which also indicates the type of I2C chip attached. - reg: The 7-bit I2C address. - lltc,resistor-sense: The sense resistor value in milli-ohms. Can be a 32-bit negative value when the battery has been connected to the wrong end of the diff --git a/drivers/power/supply/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c index b0de448a226b..42ff4e3daf35 100644 --- a/drivers/power/supply/ltc2941-battery-gauge.c +++ b/drivers/power/supply/ltc2941-battery-gauge.c @@ -1,5 +1,5 @@ /* - * I2C client/driver for the Linear Technology LTC2941 and LTC2943 + * I2C client/driver for the Linear Technology LTC2941, LTC2942 and LTC2943 * Battery Gas Gauge IC * * Copyright (C) 2014 Topic Embedded Systems @@ -46,11 +46,14 @@ enum ltc294x_reg { enum ltc294x_id { LTC2941_ID, + LTC2942_ID, LTC2943_ID, }; -#define LTC2943_REG_CONTROL_MODE_MASK (BIT(7) | BIT(6)) -#define LTC2943_REG_CONTROL_MODE_SCAN BIT(7) +#define LTC2941_REG_STATUS_CHIP_ID BIT(7) + +#define LTC2942_REG_CONTROL_MODE_SCAN (BIT(7) | BIT(6)) +#define LTC2943_REG_CONTROL_MODE_SCAN BIT(7) #define LTC294X_REG_CONTROL_PRESCALER_MASK (BIT(5) | BIT(4) | BIT(3)) #define LTC294X_REG_CONTROL_SHUTDOWN_MASK (BIT(0)) #define LTC294X_REG_CONTROL_PRESCALER_SET(x) \ @@ -145,9 +148,17 @@ static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp) control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) | LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED; - /* Put the 2943 into "monitor" mode, so it measures every 10 sec */ - if (info->id == LTC2941_ID) + /* Put device into "monitor" mode */ + switch (info->id) { + case LTC2942_ID: /* 2942 measures every 2 sec */ + control |= LTC2942_REG_CONTROL_MODE_SCAN; + break; + case LTC2943_ID: /* 2943 measures every 10 sec */ control |= LTC2943_REG_CONTROL_MODE_SCAN; + break; + default: + break; + } if (value != control) { ret = ltc294x_write_regs(info->client, @@ -252,7 +263,19 @@ static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val) ret = ltc294x_read_regs(info->client, LTC294X_REG_VOLTAGE_MSB, &datar[0], 2); value = (datar[0] << 8) | datar[1]; - *val = ((value * 23600) / 0xFFFF) * 1000; /* in uV */ + switch (info->id) { + case LTC2943_ID: + value *= 23600 * 2; + value /= 0xFFFF; + value *= 1000 / 2; + break; + default: + value *= 6000 * 10; + value /= 0xFFFF; + value *= 1000 / 10; + break; + } + *val = value; return ret; } @@ -275,15 +298,22 @@ static int ltc294x_get_current(const struct ltc294x_info *info, int *val) static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val) { + enum ltc294x_reg reg; int ret; u8 datar[2]; u32 value; - ret = ltc294x_read_regs(info->client, - LTC2943_REG_TEMPERATURE_MSB, &datar[0], 2); - value = (datar[0] << 8) | datar[1]; - /* Full-scale is 510 Kelvin, convert to centidegrees */ - *val = (((51000 * value) / 0xFFFF) - 27215); + if (info->id == LTC2942_ID) { + reg = LTC2942_REG_TEMPERATURE_MSB; + value = 60000; /* Full-scale is 600 Kelvin */ + } else { + reg = LTC2943_REG_TEMPERATURE_MSB; + value = 51000; /* Full-scale is 510 Kelvin */ + } + ret = ltc294x_read_regs(info->client, reg, &datar[0], 2); + value *= (datar[0] << 8) | datar[1]; + /* Convert to centidegrees */ + *val = value / 0xFFFF - 27215; return ret; } @@ -375,10 +405,11 @@ static int ltc294x_i2c_probe(struct i2c_client *client, { struct power_supply_config psy_cfg = {}; struct ltc294x_info *info; + struct device_node *np; int ret; u32 prescaler_exp; s32 r_sense; - struct device_node *np; + u8 status; info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) @@ -421,6 +452,20 @@ static int ltc294x_i2c_probe(struct i2c_client *client, (128 / (1 << prescaler_exp)); } + /* Read status register to check for LTC2942 */ + if (info->id == LTC2941_ID || info->id == LTC2942_ID) { + ret = ltc294x_read_regs(client, LTC294X_REG_STATUS, &status, 1); + if (ret < 0) { + dev_err(&client->dev, + "Could not read status register\n"); + return ret; + } + if (status & LTC2941_REG_STATUS_CHIP_ID) + info->id = LTC2941_ID; + else + info->id = LTC2942_ID; + } + info->client = client; info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY; info->supply_desc.properties = ltc294x_properties; @@ -429,6 +474,10 @@ static int ltc294x_i2c_probe(struct i2c_client *client, info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties); break; + case LTC2942_ID: + info->supply_desc.num_properties = + ARRAY_SIZE(ltc294x_properties) - 1; + break; case LTC2941_ID: default: info->supply_desc.num_properties = @@ -492,6 +541,7 @@ static SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume); static const struct i2c_device_id ltc294x_i2c_id[] = { { "ltc2941", LTC2941_ID, }, + { "ltc2942", LTC2942_ID, }, { "ltc2943", LTC2943_ID, }, { }, }; @@ -502,6 +552,10 @@ static const struct of_device_id ltc294x_i2c_of_match[] = { .compatible = "lltc,ltc2941", .data = (void *)LTC2941_ID, }, + { + .compatible = "lltc,ltc2942", + .data = (void *)LTC2942_ID, + }, { .compatible = "lltc,ltc2943", .data = (void *)LTC2943_ID, @@ -524,5 +578,5 @@ module_i2c_driver(ltc294x_driver); MODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems"); MODULE_AUTHOR("Mike Looijmans, Topic Embedded Products"); -MODULE_DESCRIPTION("LTC2941/LTC2943 Battery Gas Gauge IC driver"); +MODULE_DESCRIPTION("LTC2941/LTC2942/LTC2943 Battery Gas Gauge IC driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 17825ff6ec6db23892e61a1496abf7d737afe9e7 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Sun, 16 Jul 2017 11:35:32 +0200 Subject: power: supply: ltc2941-battery-gauge: Add LTC2944 support LTC2944 is compatible with LTC2943, but uses different voltage and current computing constants. Signed-off-by: Dragos Bogdan Signed-off-by: Ladislav Michl Tested-by: Dragos Bogdan Acked-by: Rob Herring Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/supply/ltc2941.txt | 12 +++++----- drivers/power/supply/ltc2941-battery-gauge.c | 27 ++++++++++++++++++---- 2 files changed, 28 insertions(+), 11 deletions(-) (limited to 'drivers/power') diff --git a/Documentation/devicetree/bindings/power/supply/ltc2941.txt b/Documentation/devicetree/bindings/power/supply/ltc2941.txt index 8ec10366295d..3b9ba147b041 100644 --- a/Documentation/devicetree/bindings/power/supply/ltc2941.txt +++ b/Documentation/devicetree/bindings/power/supply/ltc2941.txt @@ -1,14 +1,14 @@ -binding for LTC2941, LTC2942 and LTC2943 battery gauges +binding for LTC2941, LTC2942, LTC2943 and LTC2944 battery gauges All chips measure battery capacity. The LTC2942 is pin compatible with the LTC2941, it adds voltage and -temperature monitoring, and is runtime detected. LTC2943 is software -compatible, uses a slightly different conversion formula for the -charge counter and adds voltage, current and temperature monitoring. +temperature monitoring, and is runtime detected. LTC2943 and LTC2944 +is software compatible, uses a slightly different conversion formula +for the charge counter and adds voltage, current and temperature monitoring. Required properties: -- compatible: Should contain "lltc,ltc2941", "lltc,ltc2942" or "lltc,ltc2943" - which also indicates the type of I2C chip attached. +- compatible: Should contain "lltc,ltc2941", "lltc,ltc2942", "lltc,ltc2943" + or "lltc,ltc2944" which also indicates the type of I2C chip attached. - reg: The 7-bit I2C address. - lltc,resistor-sense: The sense resistor value in milli-ohms. Can be a 32-bit negative value when the battery has been connected to the wrong end of the diff --git a/drivers/power/supply/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c index 42ff4e3daf35..08e4fd9ee607 100644 --- a/drivers/power/supply/ltc2941-battery-gauge.c +++ b/drivers/power/supply/ltc2941-battery-gauge.c @@ -1,6 +1,6 @@ /* - * I2C client/driver for the Linear Technology LTC2941, LTC2942 and LTC2943 - * Battery Gas Gauge IC + * I2C client/driver for the Linear Technology LTC2941, LTC2942, LTC2943 + * and LTC2944 Battery Gas Gauge IC * * Copyright (C) 2014 Topic Embedded Systems * @@ -48,6 +48,7 @@ enum ltc294x_id { LTC2941_ID, LTC2942_ID, LTC2943_ID, + LTC2944_ID, }; #define LTC2941_REG_STATUS_CHIP_ID BIT(7) @@ -153,7 +154,8 @@ static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp) case LTC2942_ID: /* 2942 measures every 2 sec */ control |= LTC2942_REG_CONTROL_MODE_SCAN; break; - case LTC2943_ID: /* 2943 measures every 10 sec */ + case LTC2943_ID: + case LTC2944_ID: /* 2943 and 2944 measure every 10 sec */ control |= LTC2943_REG_CONTROL_MODE_SCAN; break; default: @@ -269,6 +271,11 @@ static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val) value /= 0xFFFF; value *= 1000 / 2; break; + case LTC2944_ID: + value *= 70800 / 5*4; + value /= 0xFFFF; + value *= 1000 * 5/4; + break; default: value *= 6000 * 10; value /= 0xFFFF; @@ -289,10 +296,14 @@ static int ltc294x_get_current(const struct ltc294x_info *info, int *val) LTC2943_REG_CURRENT_MSB, &datar[0], 2); value = (datar[0] << 8) | datar[1]; value -= 0x7FFF; + if (info->id == LTC2944_ID) + value *= 64000; + else + value *= 60000; /* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm, * the formula below keeps everything in s32 range while preserving * enough digits */ - *val = 1000 * ((60000 * value) / (info->r_sense * 0x7FFF)); /* in uA */ + *val = 1000 * (value / (info->r_sense * 0x7FFF)); /* in uA */ return ret; } @@ -470,6 +481,7 @@ static int ltc294x_i2c_probe(struct i2c_client *client, info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY; info->supply_desc.properties = ltc294x_properties; switch (info->id) { + case LTC2944_ID: case LTC2943_ID: info->supply_desc.num_properties = ARRAY_SIZE(ltc294x_properties); @@ -543,6 +555,7 @@ static const struct i2c_device_id ltc294x_i2c_id[] = { { "ltc2941", LTC2941_ID, }, { "ltc2942", LTC2942_ID, }, { "ltc2943", LTC2943_ID, }, + { "ltc2944", LTC2944_ID, }, { }, }; MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id); @@ -560,6 +573,10 @@ static const struct of_device_id ltc294x_i2c_of_match[] = { .compatible = "lltc,ltc2943", .data = (void *)LTC2943_ID, }, + { + .compatible = "lltc,ltc2944", + .data = (void *)LTC2944_ID, + }, { }, }; MODULE_DEVICE_TABLE(of, ltc294x_i2c_of_match); @@ -578,5 +595,5 @@ module_i2c_driver(ltc294x_driver); MODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems"); MODULE_AUTHOR("Mike Looijmans, Topic Embedded Products"); -MODULE_DESCRIPTION("LTC2941/LTC2942/LTC2943 Battery Gas Gauge IC driver"); +MODULE_DESCRIPTION("LTC2941/LTC2942/LTC2943/LTC2944 Battery Gas Gauge IC driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 55a9db679183bcf85a6e5c44a4f92f158bb6f03d Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 19 Jul 2017 12:04:06 -0500 Subject: power: supply: move HDQ interface for bq27xxx from w1 to power/supply MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HDQ interface driver should be in this folder just like the I2C interface driver. Move this driver out of drivers/w1/slave and into drivers/power/supply. Signed-off-by: Andrew F. Davis Acked-by: Pali Rohár Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 9 +++ drivers/power/supply/Makefile | 1 + drivers/power/supply/bq27xxx_battery_hdq.c | 115 ++++++++++++++++++++++++++++ drivers/w1/slaves/Kconfig | 6 -- drivers/w1/slaves/Makefile | 1 - drivers/w1/slaves/w1_bq27000.c | 117 ----------------------------- 6 files changed, 125 insertions(+), 124 deletions(-) create mode 100644 drivers/power/supply/bq27xxx_battery_hdq.c delete mode 100644 drivers/w1/slaves/w1_bq27000.c (limited to 'drivers/power') diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 969f5005669c..af6397224a82 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -198,6 +198,15 @@ config BATTERY_BQ27XXX_I2C Say Y here to enable support for batteries with BQ27xxx chips connected over an I2C bus. +config BATTERY_BQ27XXX_HDQ + tristate "BQ27xxx HDQ support" + depends on BATTERY_BQ27XXX + depends on W1 + default y + help + Say Y here to enable support for batteries with BQ27xxx chips + connected over an HDQ bus. + config BATTERY_BQ27XXX_DT_UPDATES_NVM bool "BQ27xxx support for update of NVM/flash data memory" depends on BATTERY_BQ27XXX_I2C diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index a41f40957847..946a5e6be860 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o obj-$(CONFIG_CHARGER_SBS) += sbs-charger.o obj-$(CONFIG_BATTERY_BQ27XXX) += bq27xxx_battery.o obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o +obj-$(CONFIG_BATTERY_BQ27XXX_HDQ) += bq27xxx_battery_hdq.o obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o obj-$(CONFIG_CHARGER_DA9150) += da9150-charger.o diff --git a/drivers/power/supply/bq27xxx_battery_hdq.c b/drivers/power/supply/bq27xxx_battery_hdq.c new file mode 100644 index 000000000000..f4df67eb9d2c --- /dev/null +++ b/drivers/power/supply/bq27xxx_battery_hdq.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define W1_FAMILY_BQ27000 0x01 + +#define HDQ_CMD_READ (0) +#define HDQ_CMD_WRITE (1<<7) + +static int F_ID; +module_param(F_ID, int, S_IRUSR); +MODULE_PARM_DESC(F_ID, "1-wire slave FID for BQ device"); + +static int w1_bq27000_read(struct device *dev, unsigned int reg) +{ + u8 val; + struct w1_slave *sl = container_of(dev->parent, struct w1_slave, dev); + + mutex_lock(&sl->master->bus_mutex); + w1_write_8(sl->master, HDQ_CMD_READ | reg); + val = w1_read_8(sl->master); + mutex_unlock(&sl->master->bus_mutex); + + return val; +} + +static struct bq27xxx_platform_data bq27000_battery_info = { + .read = w1_bq27000_read, + .name = "bq27000-battery", + .chip = BQ27000, +}; + +static int w1_bq27000_add_slave(struct w1_slave *sl) +{ + int ret; + struct platform_device *pdev; + + pdev = platform_device_alloc("bq27000-battery", -1); + if (!pdev) { + ret = -ENOMEM; + return ret; + } + ret = platform_device_add_data(pdev, + &bq27000_battery_info, + sizeof(bq27000_battery_info)); + if (ret) + goto pdev_add_failed; + pdev->dev.parent = &sl->dev; + + ret = platform_device_add(pdev); + if (ret) + goto pdev_add_failed; + + dev_set_drvdata(&sl->dev, pdev); + + goto success; + +pdev_add_failed: + platform_device_put(pdev); +success: + return ret; +} + +static void w1_bq27000_remove_slave(struct w1_slave *sl) +{ + struct platform_device *pdev = dev_get_drvdata(&sl->dev); + + platform_device_unregister(pdev); +} + +static struct w1_family_ops w1_bq27000_fops = { + .add_slave = w1_bq27000_add_slave, + .remove_slave = w1_bq27000_remove_slave, +}; + +static struct w1_family w1_bq27000_family = { + .fid = W1_FAMILY_BQ27000, + .fops = &w1_bq27000_fops, +}; + +static int __init w1_bq27000_init(void) +{ + if (F_ID) + w1_bq27000_family.fid = F_ID; + + return w1_register_family(&w1_bq27000_family); +} + +static void __exit w1_bq27000_exit(void) +{ + w1_unregister_family(&w1_bq27000_family); +} + +module_init(w1_bq27000_init); +module_exit(w1_bq27000_exit); + +MODULE_AUTHOR("Texas Instruments Ltd"); +MODULE_DESCRIPTION("HDQ/1-wire slave driver bq27000 battery monitor chip"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_BQ27000)); diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index fb68465908f2..dc4437683956 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -140,10 +140,4 @@ config W1_SLAVE_DS28E04 If you are unsure, say N. -config W1_SLAVE_BQ27000 - tristate "BQ27000 slave support" - help - Say Y here if you want to use a hdq - bq27000 slave support. - endmenu diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index 54c63e420302..e59441a5e157 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile @@ -15,5 +15,4 @@ obj-$(CONFIG_W1_SLAVE_DS2438) += w1_ds2438.o obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o -obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o diff --git a/drivers/w1/slaves/w1_bq27000.c b/drivers/w1/slaves/w1_bq27000.c deleted file mode 100644 index 8046ac45381a..000000000000 --- a/drivers/w1/slaves/w1_bq27000.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * drivers/w1/slaves/w1_bq27000.c - * - * Copyright (C) 2007 Texas Instruments, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define W1_FAMILY_BQ27000 0x01 - -#define HDQ_CMD_READ (0) -#define HDQ_CMD_WRITE (1<<7) - -static int F_ID; -module_param(F_ID, int, S_IRUSR); -MODULE_PARM_DESC(F_ID, "1-wire slave FID for BQ device"); - -static int w1_bq27000_read(struct device *dev, unsigned int reg) -{ - u8 val; - struct w1_slave *sl = container_of(dev->parent, struct w1_slave, dev); - - mutex_lock(&sl->master->bus_mutex); - w1_write_8(sl->master, HDQ_CMD_READ | reg); - val = w1_read_8(sl->master); - mutex_unlock(&sl->master->bus_mutex); - - return val; -} - -static struct bq27xxx_platform_data bq27000_battery_info = { - .read = w1_bq27000_read, - .name = "bq27000-battery", - .chip = BQ27000, -}; - -static int w1_bq27000_add_slave(struct w1_slave *sl) -{ - int ret; - struct platform_device *pdev; - - pdev = platform_device_alloc("bq27000-battery", -1); - if (!pdev) { - ret = -ENOMEM; - return ret; - } - ret = platform_device_add_data(pdev, - &bq27000_battery_info, - sizeof(bq27000_battery_info)); - if (ret) - goto pdev_add_failed; - pdev->dev.parent = &sl->dev; - - ret = platform_device_add(pdev); - if (ret) - goto pdev_add_failed; - - dev_set_drvdata(&sl->dev, pdev); - - goto success; - -pdev_add_failed: - platform_device_put(pdev); -success: - return ret; -} - -static void w1_bq27000_remove_slave(struct w1_slave *sl) -{ - struct platform_device *pdev = dev_get_drvdata(&sl->dev); - - platform_device_unregister(pdev); -} - -static struct w1_family_ops w1_bq27000_fops = { - .add_slave = w1_bq27000_add_slave, - .remove_slave = w1_bq27000_remove_slave, -}; - -static struct w1_family w1_bq27000_family = { - .fid = W1_FAMILY_BQ27000, - .fops = &w1_bq27000_fops, -}; - -static int __init w1_bq27000_init(void) -{ - if (F_ID) - w1_bq27000_family.fid = F_ID; - - return w1_register_family(&w1_bq27000_family); -} - -static void __exit w1_bq27000_exit(void) -{ - w1_unregister_family(&w1_bq27000_family); -} - -module_init(w1_bq27000_init); -module_exit(w1_bq27000_exit); - -MODULE_AUTHOR("Texas Instruments Ltd"); -MODULE_DESCRIPTION("HDQ/1-wire slave driver bq27000 battery monitor chip"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_BQ27000)); -- cgit v1.2.3 From 67bd22c09ac1b54b5f42445783d2dc8e011f7a71 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 19 Jul 2017 12:04:07 -0500 Subject: power: supply: bq27xxx: move platform driver code into bq27xxx_battery_hdq.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the BQ27xxx driver was originally written the w1 subsystem only allowed device drivers for w1 attached devices to live in the w1 subsystem. Kernel driver subsystems expect that the driver for a device live in the directory of the subsystem for which it implements functionality, not in the directory of the bus that it is attached. To work around this, the BQ27xxx driver was implemented as a platform device driver and the interface driver would instantiate this device from within the w1 directory, then pass a w1 read callback as platform data. As we can now have the w1 interface driver in the power/supply directory (like we do already with the i2c interface driver) we can remove this middle-layer platform driver. Signed-off-by: Andrew F. Davis Acked-by: Pali Rohár Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 104 ----------------------- drivers/power/supply/bq27xxx_battery_hdq.c | 130 +++++++++++++++++------------ include/linux/power/bq27xxx_battery.h | 17 ---- 3 files changed, 75 insertions(+), 176 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index ed44439d0112..079083b31293 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1938,110 +1938,6 @@ void bq27xxx_battery_teardown(struct bq27xxx_device_info *di) } EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); -static int bq27xxx_battery_platform_read(struct bq27xxx_device_info *di, u8 reg, - bool single) -{ - struct device *dev = di->dev; - struct bq27xxx_platform_data *pdata = dev->platform_data; - unsigned int timeout = 3; - int upper, lower; - int temp; - - if (!single) { - /* Make sure the value has not changed in between reading the - * lower and the upper part */ - upper = pdata->read(dev, reg + 1); - do { - temp = upper; - if (upper < 0) - return upper; - - lower = pdata->read(dev, reg); - if (lower < 0) - return lower; - - upper = pdata->read(dev, reg + 1); - } while (temp != upper && --timeout); - - if (timeout == 0) - return -EIO; - - return (upper << 8) | lower; - } - - return pdata->read(dev, reg); -} - -static int bq27xxx_battery_platform_probe(struct platform_device *pdev) -{ - struct bq27xxx_device_info *di; - struct bq27xxx_platform_data *pdata = pdev->dev.platform_data; - - if (!pdata) { - dev_err(&pdev->dev, "no platform_data supplied\n"); - return -EINVAL; - } - - if (!pdata->read) { - dev_err(&pdev->dev, "no hdq read callback supplied\n"); - return -EINVAL; - } - - if (!pdata->chip) { - dev_err(&pdev->dev, "no device supplied\n"); - return -EINVAL; - } - - di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); - if (!di) - return -ENOMEM; - - platform_set_drvdata(pdev, di); - - di->dev = &pdev->dev; - di->chip = pdata->chip; - di->name = pdata->name ?: dev_name(&pdev->dev); - di->bus.read = bq27xxx_battery_platform_read; - - return bq27xxx_battery_setup(di); -} - -static int bq27xxx_battery_platform_remove(struct platform_device *pdev) -{ - struct bq27xxx_device_info *di = platform_get_drvdata(pdev); - - bq27xxx_battery_teardown(di); - - return 0; -} - -static const struct platform_device_id bq27xxx_battery_platform_id_table[] = { - { "bq27000-battery", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(platform, bq27xxx_battery_platform_id_table); - -#ifdef CONFIG_OF -static const struct of_device_id bq27xxx_battery_platform_of_match_table[] = { - { .compatible = "ti,bq27000" }, - {}, -}; -MODULE_DEVICE_TABLE(of, bq27xxx_battery_platform_of_match_table); -#endif - -static struct platform_driver bq27xxx_battery_platform_driver = { - .probe = bq27xxx_battery_platform_probe, - .remove = bq27xxx_battery_platform_remove, - .driver = { - .name = "bq27000-battery", - .of_match_table = of_match_ptr(bq27xxx_battery_platform_of_match_table), - }, - .id_table = bq27xxx_battery_platform_id_table, -}; -module_platform_driver(bq27xxx_battery_platform_driver); - -MODULE_ALIAS("platform:bq27000-battery"); - MODULE_AUTHOR("Rodolfo Giometti "); MODULE_DESCRIPTION("BQ27xxx battery monitor driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/power/supply/bq27xxx_battery_hdq.c b/drivers/power/supply/bq27xxx_battery_hdq.c index f4df67eb9d2c..9aff896c9802 100644 --- a/drivers/power/supply/bq27xxx_battery_hdq.c +++ b/drivers/power/supply/bq27xxx_battery_hdq.c @@ -1,10 +1,16 @@ /* - * Copyright (C) 2007 Texas Instruments, Inc. + * BQ27xxx battery monitor HDQ/1-wire driver * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. + * Copyright (C) 2007-2017 Texas Instruments Incorporated - http://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 + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include @@ -19,17 +25,16 @@ #define W1_FAMILY_BQ27000 0x01 -#define HDQ_CMD_READ (0) -#define HDQ_CMD_WRITE (1<<7) +#define HDQ_CMD_READ (0 << 7) +#define HDQ_CMD_WRITE (1 << 7) static int F_ID; module_param(F_ID, int, S_IRUSR); -MODULE_PARM_DESC(F_ID, "1-wire slave FID for BQ device"); +MODULE_PARM_DESC(F_ID, "1-wire slave FID for BQ27xxx device"); -static int w1_bq27000_read(struct device *dev, unsigned int reg) +static int w1_bq27000_read(struct w1_slave *sl, unsigned int reg) { u8 val; - struct w1_slave *sl = container_of(dev->parent, struct w1_slave, dev); mutex_lock(&sl->master->bus_mutex); w1_write_8(sl->master, HDQ_CMD_READ | reg); @@ -39,77 +44,92 @@ static int w1_bq27000_read(struct device *dev, unsigned int reg) return val; } -static struct bq27xxx_platform_data bq27000_battery_info = { - .read = w1_bq27000_read, - .name = "bq27000-battery", - .chip = BQ27000, -}; - -static int w1_bq27000_add_slave(struct w1_slave *sl) +static int bq27xxx_battery_hdq_read(struct bq27xxx_device_info *di, u8 reg, + bool single) { - int ret; - struct platform_device *pdev; - - pdev = platform_device_alloc("bq27000-battery", -1); - if (!pdev) { - ret = -ENOMEM; - return ret; + struct w1_slave *sl = dev_to_w1_slave(di->dev); + unsigned int timeout = 3; + int upper, lower; + int temp; + + if (!single) { + /* + * Make sure the value has not changed in between reading the + * lower and the upper part + */ + upper = w1_bq27000_read(sl, reg + 1); + do { + temp = upper; + if (upper < 0) + return upper; + + lower = w1_bq27000_read(sl, reg); + if (lower < 0) + return lower; + + upper = w1_bq27000_read(sl, reg + 1); + } while (temp != upper && --timeout); + + if (timeout == 0) + return -EIO; + + return (upper << 8) | lower; } - ret = platform_device_add_data(pdev, - &bq27000_battery_info, - sizeof(bq27000_battery_info)); - if (ret) - goto pdev_add_failed; - pdev->dev.parent = &sl->dev; - ret = platform_device_add(pdev); - if (ret) - goto pdev_add_failed; + return w1_bq27000_read(sl, reg); +} - dev_set_drvdata(&sl->dev, pdev); +static int bq27xxx_battery_hdq_add_slave(struct w1_slave *sl) +{ + struct bq27xxx_device_info *di; + + di = devm_kzalloc(&sl->dev, sizeof(*di), GFP_KERNEL); + if (!di) + return -ENOMEM; - goto success; + dev_set_drvdata(&sl->dev, di); -pdev_add_failed: - platform_device_put(pdev); -success: - return ret; + di->dev = &sl->dev; + di->chip = BQ27000; + di->name = "bq27000-battery"; + di->bus.read = bq27xxx_battery_hdq_read; + + return bq27xxx_battery_setup(di); } -static void w1_bq27000_remove_slave(struct w1_slave *sl) +static void bq27xxx_battery_hdq_remove_slave(struct w1_slave *sl) { - struct platform_device *pdev = dev_get_drvdata(&sl->dev); + struct bq27xxx_device_info *di = dev_get_drvdata(&sl->dev); - platform_device_unregister(pdev); + bq27xxx_battery_teardown(di); } -static struct w1_family_ops w1_bq27000_fops = { - .add_slave = w1_bq27000_add_slave, - .remove_slave = w1_bq27000_remove_slave, +static struct w1_family_ops bq27xxx_battery_hdq_fops = { + .add_slave = bq27xxx_battery_hdq_add_slave, + .remove_slave = bq27xxx_battery_hdq_remove_slave, }; -static struct w1_family w1_bq27000_family = { +static struct w1_family bq27xxx_battery_hdq_family = { .fid = W1_FAMILY_BQ27000, - .fops = &w1_bq27000_fops, + .fops = &bq27xxx_battery_hdq_fops, }; -static int __init w1_bq27000_init(void) +static int __init bq27xxx_battery_hdq_init(void) { if (F_ID) - w1_bq27000_family.fid = F_ID; + bq27xxx_battery_hdq_family.fid = F_ID; - return w1_register_family(&w1_bq27000_family); + return w1_register_family(&bq27xxx_battery_hdq_family); } +module_init(bq27xxx_battery_hdq_init); -static void __exit w1_bq27000_exit(void) +static void __exit bq27xxx_battery_hdq_exit(void) { - w1_unregister_family(&w1_bq27000_family); + w1_unregister_family(&bq27xxx_battery_hdq_family); } - -module_init(w1_bq27000_init); -module_exit(w1_bq27000_exit); +module_exit(bq27xxx_battery_hdq_exit); MODULE_AUTHOR("Texas Instruments Ltd"); -MODULE_DESCRIPTION("HDQ/1-wire slave driver bq27000 battery monitor chip"); +MODULE_DESCRIPTION("BQ27xxx battery monitor HDQ/1-wire driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_BQ27000)); diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index 11e11685dd1d..89890437f9ab 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -20,23 +20,6 @@ enum bq27xxx_chip { BQ27421, /* bq27421, bq27425, bq27441, bq27621 */ }; -/** - * struct bq27xxx_plaform_data - Platform data for bq27xxx devices - * @name: Name of the battery. - * @chip: Chip class number of this device. - * @read: HDQ read callback. - * This function should provide access to the HDQ bus the battery is - * connected to. - * The first parameter is a pointer to the battery device, the second the - * register to be read. The return value should either be the content of - * the passed register or an error value. - */ -struct bq27xxx_platform_data { - const char *name; - enum bq27xxx_chip chip; - int (*read)(struct device *dev, unsigned int); -}; - struct bq27xxx_device_info; struct bq27xxx_access_methods { int (*read)(struct bq27xxx_device_info *di, u8 reg, bool single); -- cgit v1.2.3 From 16ac345b15529995a6ca0109ad41f96e3db82e56 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 2 Aug 2017 15:59:38 +0530 Subject: power: supply: add const to bin_attribute structures Add const to bin_attribute structures as they are only passed to the functions sysfs_{remove/create}_bin_file or device_{remove/create}_bin_file. The corresponding parameters passed are of type const, so declare the structures to be const. Done using Coccinelle: @m disable optional_qualifier@ identifier s; position p; @@ static struct bin_attribute s@p={...}; @okay1@ position p; identifier m.s; @@ ( sysfs_create_bin_file(...,&s@p,...) | sysfs_remove_bin_file(...,&s@p,...) ) @bad@ position p!={m.p,okay1.p}; identifier m.s; @@ s@p @change depends on !bad disable optional_qualifier@ identifier m.s; @@ static +const struct bin_attribute s={...}; Same script was modified for device_{create/remove}_bin_file functions. Signed-off-by: Bhumika Goyal Signed-off-by: Sebastian Reichel --- drivers/power/supply/ds2780_battery.c | 4 ++-- drivers/power/supply/ds2781_battery.c | 4 ++-- drivers/power/supply/olpc_battery.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/ds2780_battery.c b/drivers/power/supply/ds2780_battery.c index 8edd4aa5f475..e5d81b493c45 100644 --- a/drivers/power/supply/ds2780_battery.c +++ b/drivers/power/supply/ds2780_battery.c @@ -663,7 +663,7 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp, return count; } -static struct bin_attribute ds2780_param_eeprom_bin_attr = { +static const struct bin_attribute ds2780_param_eeprom_bin_attr = { .attr = { .name = "param_eeprom", .mode = S_IRUGO | S_IWUSR, @@ -708,7 +708,7 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp, return count; } -static struct bin_attribute ds2780_user_eeprom_bin_attr = { +static const struct bin_attribute ds2780_user_eeprom_bin_attr = { .attr = { .name = "user_eeprom", .mode = S_IRUGO | S_IWUSR, diff --git a/drivers/power/supply/ds2781_battery.c b/drivers/power/supply/ds2781_battery.c index 4400402f9ec5..efe83ef8670c 100644 --- a/drivers/power/supply/ds2781_battery.c +++ b/drivers/power/supply/ds2781_battery.c @@ -665,7 +665,7 @@ static ssize_t ds2781_write_param_eeprom_bin(struct file *filp, return count; } -static struct bin_attribute ds2781_param_eeprom_bin_attr = { +static const struct bin_attribute ds2781_param_eeprom_bin_attr = { .attr = { .name = "param_eeprom", .mode = S_IRUGO | S_IWUSR, @@ -711,7 +711,7 @@ static ssize_t ds2781_write_user_eeprom_bin(struct file *filp, return count; } -static struct bin_attribute ds2781_user_eeprom_bin_attr = { +static const struct bin_attribute ds2781_user_eeprom_bin_attr = { .attr = { .name = "user_eeprom", .mode = S_IRUGO | S_IWUSR, diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c index 9e29b1321648..fc20ca368e55 100644 --- a/drivers/power/supply/olpc_battery.c +++ b/drivers/power/supply/olpc_battery.c @@ -535,7 +535,7 @@ static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj, return count; } -static struct bin_attribute olpc_bat_eeprom = { +static const struct bin_attribute olpc_bat_eeprom = { .attr = { .name = "eeprom", .mode = S_IRUGO, -- cgit v1.2.3 From 46cecd130d553f7340d033a4019839e9c018200d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 6 Aug 2017 18:23:52 +0200 Subject: power: supply: Fix power_supply_am_i_supplied to return -ENODEV when apropriate Commit 2848e039c562 ("power: supply: Make power_supply_am_i_supplied return -ENODEV if there are no suppliers") was supposed to make power_supply_am_i_supplied() return -ENODEV when there are no supplies which supply the supply passed to it. But instead it will only return -ENODEV when there are no supplies at all as data->count++; is incremented on every call of the iterator, rather then only when __power_supply_is_supplied_by returns true. This commit fixes this. Fixes: 2848e039c562 ("power: supply: Make power_supply_am_i_supplied ...") Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 540d3e0aa011..0741fcef3b44 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -314,11 +314,12 @@ static int __power_supply_am_i_supplied(struct device *dev, void *_data) struct power_supply *epsy = dev_get_drvdata(dev); struct psy_am_i_supplied_data *data = _data; - data->count++; - if (__power_supply_is_supplied_by(epsy, data->psy)) + if (__power_supply_is_supplied_by(epsy, data->psy)) { + data->count++; if (!epsy->desc->get_property(epsy, POWER_SUPPLY_PROP_ONLINE, &ret)) return ret.intval; + } return 0; } -- cgit v1.2.3 From 096fc160b706237b6643a15a8e13690de238af0f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 7 Aug 2017 00:37:55 +0200 Subject: power: supply: charger-manager: Fix a NULL pointer dereference in 'charger_manager_probe()' 'devm_kzalloc()' can return NULL. Return -ENOMEM in this case in order to avoid a NULL pointer dereference later on. Signed-off-by: Christophe JAILLET Signed-off-by: Sebastian Reichel --- drivers/power/supply/charger-manager.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/power') diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index adc3761831e1..52a49857e20f 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -1645,6 +1645,8 @@ static int charger_manager_probe(struct platform_device *pdev) /* Initialize alarm timer */ if (alarmtimer_get_rtcdev()) { cm_timer = devm_kzalloc(cm->dev, sizeof(*cm_timer), GFP_KERNEL); + if (!cm_timer) + return -ENOMEM; alarm_init(cm_timer, ALARM_BOOTTIME, cm_timer_func); } -- cgit v1.2.3 From 0299484e4ddc330f3a64f7310683e673a25e6482 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 7 Aug 2017 00:37:56 +0200 Subject: power: supply: charger-manager: Fix a comment Update a comment which is no more up to date since commit 2ed9e9b653095. Signed-off-by: Christophe JAILLET Signed-off-by: Sebastian Reichel --- drivers/power/supply/charger-manager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index 52a49857e20f..83c08c8e2c32 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -1651,8 +1651,8 @@ static int charger_manager_probe(struct platform_device *pdev) } /* - * The following two do not need to be errors. - * Users may intentionally ignore those two features. + * Some of the following do not need to be errors. + * Users may intentionally ignore those features. */ if (desc->fullbatt_uV == 0) { dev_info(&pdev->dev, "Ignoring full-battery voltage threshold as it is not supplied\n"); -- cgit v1.2.3 From 18a89d5c7ce873e5d813a135bf4e12d75b9d95c7 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 7 Aug 2017 00:37:57 +0200 Subject: power: supply: charger-manager: Slighly simplify code Use 'sizeof(*var)' instead of the equivalent 'sizeof(data structure type)' because it is less verbose. Signed-off-by: Christophe JAILLET Signed-off-by: Sebastian Reichel --- drivers/power/supply/charger-manager.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index 83c08c8e2c32..6502fa7c2106 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -1632,8 +1632,7 @@ static int charger_manager_probe(struct platform_device *pdev) return -ENODEV; } - cm = devm_kzalloc(&pdev->dev, - sizeof(struct charger_manager), GFP_KERNEL); + cm = devm_kzalloc(&pdev->dev, sizeof(*cm), GFP_KERNEL); if (!cm) return -ENOMEM; -- cgit v1.2.3 From 810e006a82c9482d0353abe37cea68ddf6d76896 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 11 Aug 2017 22:52:12 +0100 Subject: power: supply: lp8788: Make several arrays static const * const Don't populate various read only arrays on the stack but make them static const, making the object code smaller and saves 148 bytes overall: Before: text data bss dec hex filename 11940 4496 64 16500 4074 lp8788-charger.o After: text data bss dec hex filename 11472 4816 64 16352 3fe0 lp8788-charger.o Signed-off-by: Colin Ian King Signed-off-by: Sebastian Reichel --- drivers/power/supply/lp8788-charger.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c index 677f7c40b25a..0f3432795f3c 100644 --- a/drivers/power/supply/lp8788-charger.c +++ b/drivers/power/supply/lp8788-charger.c @@ -626,7 +626,7 @@ static ssize_t lp8788_show_charger_status(struct device *dev, { struct lp8788_charger *pchg = dev_get_drvdata(dev); enum lp8788_charging_state state; - char *desc[LP8788_MAX_CHG_STATE] = { + static const char * const desc[LP8788_MAX_CHG_STATE] = { [LP8788_OFF] = "CHARGER OFF", [LP8788_WARM_UP] = "WARM UP", [LP8788_LOW_INPUT] = "LOW INPUT STATE", @@ -650,8 +650,10 @@ static ssize_t lp8788_show_eoc_time(struct device *dev, struct device_attribute *attr, char *buf) { struct lp8788_charger *pchg = dev_get_drvdata(dev); - char *stime[] = { "400ms", "5min", "10min", "15min", - "20min", "25min", "30min", "No timeout" }; + static const char * const stime[] = { + "400ms", "5min", "10min", "15min", + "20min", "25min", "30min", "No timeout" + }; u8 val; lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val); @@ -665,9 +667,13 @@ static ssize_t lp8788_show_eoc_level(struct device *dev, struct device_attribute *attr, char *buf) { struct lp8788_charger *pchg = dev_get_drvdata(dev); - char *abs_level[] = { "25mA", "49mA", "75mA", "98mA" }; - char *relative_level[] = { "5%", "10%", "15%", "20%" }; - char *level; + static const char * const abs_level[] = { + "25mA", "49mA", "75mA", "98mA" + }; + static const char * const relative_level[] = { + "5%", "10%", "15%", "20%" + }; + const char *level; u8 val; u8 mode; -- cgit v1.2.3 From e21162029a57d3fe657e1eae12283702360cd5c5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 14 Aug 2017 22:18:10 +0200 Subject: power: supply: max17042_battery: Add support for ACPI enumeration Some x86 devices enumerate a max17047 fuel-gauge through a MAX17047 ACPI firmware-node, add support for this. Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/max17042_battery.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index aecaaa2b0586..b2ddb7eb69c6 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -22,6 +22,7 @@ * This driver is based on max17040_battery.c */ +#include #include #include #include @@ -982,6 +983,8 @@ static int max17042_probe(struct i2c_client *client, struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); const struct power_supply_desc *max17042_desc = &max17042_psy_desc; struct power_supply_config psy_cfg = {}; + const struct acpi_device_id *acpi_id; + struct device *dev = &client->dev; struct max17042_chip *chip; int ret; int i; @@ -995,7 +998,15 @@ static int max17042_probe(struct i2c_client *client, return -ENOMEM; chip->client = client; - chip->chip_type = id->driver_data; + if (id) { + chip->chip_type = id->driver_data; + } else { + acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!acpi_id) + return -ENODEV; + + chip->chip_type = acpi_id->driver_data; + } chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config); if (IS_ERR(chip->regmap)) { dev_err(&client->dev, "Failed to initialize regmap\n"); @@ -1104,6 +1115,14 @@ static int max17042_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(max17042_pm_ops, max17042_suspend, max17042_resume); +#ifdef CONFIG_ACPI +static const struct acpi_device_id max17042_acpi_match[] = { + { "MAX17047", MAXIM_DEVICE_TYPE_MAX17047 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, max17042_acpi_match); +#endif + #ifdef CONFIG_OF static const struct of_device_id max17042_dt_match[] = { { .compatible = "maxim,max17042" }, @@ -1125,6 +1144,7 @@ MODULE_DEVICE_TABLE(i2c, max17042_id); static struct i2c_driver max17042_i2c_driver = { .driver = { .name = "max17042", + .acpi_match_table = ACPI_PTR(max17042_acpi_match), .of_match_table = of_match_ptr(max17042_dt_match), .pm = &max17042_pm_ops, }, -- cgit v1.2.3 From a865a155568fcfbc51cf16ad150834e1443b5d2a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 14 Aug 2017 22:18:11 +0200 Subject: power: supply: max17042_battery: Fix ACPI interrupt issues On some x86/ACPI boards the DSDT defines an ACPI event handler for the max17047 IRQ, this causes several problems: 1) We need to share the IRQ to avoid an error getting it 2) Even of we are willing to share, we may fail to share because some DSDTs claim it exclusivly 3) If we are unable to share the IRQ, or the IRQ is only listed as an ACPI event source and not in the max1704 firmware node, then the charge threshold IRQ (which is used to give an IRQ every 1 percent charge change) becomes a problem, the ACPI event handler will not update this to the next 1 percent threshold, so the IRQ keeps firing and we get an IRQ storm pegging 1 CPU core. This happens despite the max17042 driver not setting the charge threshold because Windows uses it and leaves it set on reboot. So if we are unable to get the IRQ we need to reprogram the charge threshold to its disabled setting. This commit fixes al of the above, while at it it also makes the error msg when being unable to get the IRQ consistent with other messages. Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/max17042_battery.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index b2ddb7eb69c6..18a44e4ed6ff 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -1050,11 +1050,18 @@ static int max17042_probe(struct i2c_client *client, } if (client->irq) { + unsigned int flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + + /* + * On ACPI systems the IRQ may be handled by ACPI-event code, + * so we need to share (if the ACPI code is willing to share). + */ + if (acpi_id) + flags |= IRQF_SHARED | IRQF_PROBE_SHARED; + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, - max17042_thread_handler, - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, + max17042_thread_handler, flags, chip->battery->desc->name, chip); if (!ret) { @@ -1064,10 +1071,13 @@ static int max17042_probe(struct i2c_client *client, max17042_set_soc_threshold(chip, 1); } else { client->irq = 0; - dev_err(&client->dev, "%s(): cannot get IRQ\n", - __func__); + if (ret != -EBUSY) + dev_err(&client->dev, "Failed to get IRQ\n"); } } + /* Not able to update the charge threshold when exceeded? -> disable */ + if (!client->irq) + regmap_write(chip->regmap, MAX17042_SALRT_Th, 0xff00); regmap_read(chip->regmap, MAX17042_STATUS, &val); if (val & STATUS_POR_BIT) { -- cgit v1.2.3 From c023b90699c820452093e7f24fb9058900971fda Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 21 Aug 2017 17:13:12 +0530 Subject: power: supply: make device_attribute const Make these const as they are only passed as an argument to the function device_create_file and device_remove_file and the corresponding arguments are of type const. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Sebastian Reichel --- drivers/power/supply/olpc_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c index fc20ca368e55..3bc2eea7b3b7 100644 --- a/drivers/power/supply/olpc_battery.c +++ b/drivers/power/supply/olpc_battery.c @@ -559,7 +559,7 @@ static ssize_t olpc_bat_error_read(struct device *dev, return sprintf(buf, "%d\n", ec_byte); } -static struct device_attribute olpc_bat_error = { +static const struct device_attribute olpc_bat_error = { .attr = { .name = "error", .mode = S_IRUGO, -- cgit v1.2.3 From 1e743997fb9a56cbb34591f5fe88a74c14b8688d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 26 Aug 2017 19:22:32 +0200 Subject: power: supply: core: Delete two error messages for a failed memory allocation in power_supply_check_supplies() Omit extra messages for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 0741fcef3b44..df5374afd214 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -259,18 +259,14 @@ static int power_supply_check_supplies(struct power_supply *psy) /* All supplies found, allocate char ** array for filling */ psy->supplied_from = devm_kzalloc(&psy->dev, sizeof(psy->supplied_from), GFP_KERNEL); - if (!psy->supplied_from) { - dev_err(&psy->dev, "Couldn't allocate memory for supply list\n"); + if (!psy->supplied_from) return -ENOMEM; - } *psy->supplied_from = devm_kzalloc(&psy->dev, sizeof(char *) * (cnt - 1), GFP_KERNEL); - if (!*psy->supplied_from) { - dev_err(&psy->dev, "Couldn't allocate memory for supply list\n"); + if (!*psy->supplied_from) return -ENOMEM; - } return power_supply_populate_supplied_from(psy); } -- cgit v1.2.3 From 4f1e0cb78810afab889fc407ff18c112663a1579 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 29 Aug 2017 11:27:28 +0200 Subject: power: supply: max17042_battery: Fix compiler warning Fix drivers/power/supply/max17042_battery.c:1059:6: warning: 'acpi_id' may be used uninitialized in this function. No idea why my gcc version did not catch this. Reported-by: kbuild test robot Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/max17042_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index 18a44e4ed6ff..5b556a13f517 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -983,7 +983,7 @@ static int max17042_probe(struct i2c_client *client, struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); const struct power_supply_desc *max17042_desc = &max17042_psy_desc; struct power_supply_config psy_cfg = {}; - const struct acpi_device_id *acpi_id; + const struct acpi_device_id *acpi_id = NULL; struct device *dev = &client->dev; struct max17042_chip *chip; int ret; -- cgit v1.2.3 From c3142dd8bedb8b78ee13c885dd92093fc8a50277 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 15 Aug 2017 22:04:56 +0200 Subject: power: supply: Add power_supply_set_input_current_limit_from_supplier helper On some devices the USB Type-C port power (USB PD 2.0) negotiation is done by a separate port-controller IC, while the current limit is controlled through another (charger) IC. It has been decided to model this by modelling the external Type-C power brick (adapter/charger) as a power-supply class device which supplies the charger-IC, with its voltage-now and current-max representing the negotiated voltage and max current draw. This commit adds a power_supply_set_input_current_limit_from_supplier helper function which charger power-supply drivers can call to get the max-current from their supplier and have this applied through their set_property call-back to their input-current-limit. Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 41 ++++++++++++++++++++++++++++++++ include/linux/power_supply.h | 2 ++ 2 files changed, 43 insertions(+) (limited to 'drivers/power') diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index df5374afd214..02c6340ae36f 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -371,6 +371,47 @@ int power_supply_is_system_supplied(void) } EXPORT_SYMBOL_GPL(power_supply_is_system_supplied); +static int __power_supply_get_supplier_max_current(struct device *dev, + void *data) +{ + union power_supply_propval ret = {0,}; + struct power_supply *epsy = dev_get_drvdata(dev); + struct power_supply *psy = data; + + if (__power_supply_is_supplied_by(epsy, psy)) + if (!epsy->desc->get_property(epsy, + POWER_SUPPLY_PROP_CURRENT_MAX, + &ret)) + return ret.intval; + + return 0; +} + +int power_supply_set_input_current_limit_from_supplier(struct power_supply *psy) +{ + union power_supply_propval val = {0,}; + int curr; + + if (!psy->desc->set_property) + return -EINVAL; + + /* + * This function is not intended for use with a supply with multiple + * suppliers, we simply pick the first supply to report a non 0 + * max-current. + */ + curr = class_for_each_device(power_supply_class, NULL, psy, + __power_supply_get_supplier_max_current); + if (curr <= 0) + return (curr == 0) ? -ENODEV : curr; + + val.intval = curr; + + return psy->desc->set_property(psy, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val); +} +EXPORT_SYMBOL_GPL(power_supply_set_input_current_limit_from_supplier); + int power_supply_set_battery_charged(struct power_supply *psy) { if (atomic_read(&psy->use_cnt) >= 0 && diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index de89066b72b1..79e90b3d3288 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -332,6 +332,8 @@ extern int power_supply_get_battery_info(struct power_supply *psy, struct power_supply_battery_info *info); extern void power_supply_changed(struct power_supply *psy); extern int power_supply_am_i_supplied(struct power_supply *psy); +extern int power_supply_set_input_current_limit_from_supplier( + struct power_supply *psy); extern int power_supply_set_battery_charged(struct power_supply *psy); #ifdef CONFIG_POWER_SUPPLY -- cgit v1.2.3 From 74229f938434a8a48c01a39ab9f82ffc27faa7da Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 15 Aug 2017 22:04:58 +0200 Subject: power: supply: bq24190_charger: Add input_current_limit property Export the input current limit of the charger as a POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT property on the charger power_supply class device. Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index d5a707e14526..7360f4259e63 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -865,6 +865,33 @@ static int bq24190_charger_set_voltage(struct bq24190_dev_info *bdi, ARRAY_SIZE(bq24190_cvc_vreg_values), val->intval); } +static int bq24190_charger_get_iinlimit(struct bq24190_dev_info *bdi, + union power_supply_propval *val) +{ + int iinlimit, ret; + + ret = bq24190_get_field_val(bdi, BQ24190_REG_ISC, + BQ24190_REG_ISC_IINLIM_MASK, + BQ24190_REG_ISC_IINLIM_SHIFT, + bq24190_isc_iinlim_values, + ARRAY_SIZE(bq24190_isc_iinlim_values), &iinlimit); + if (ret < 0) + return ret; + + val->intval = iinlimit; + return 0; +} + +static int bq24190_charger_set_iinlimit(struct bq24190_dev_info *bdi, + const union power_supply_propval *val) +{ + return bq24190_set_field_val(bdi, BQ24190_REG_ISC, + BQ24190_REG_ISC_IINLIM_MASK, + BQ24190_REG_ISC_IINLIM_SHIFT, + bq24190_isc_iinlim_values, + ARRAY_SIZE(bq24190_isc_iinlim_values), val->intval); +} + static int bq24190_charger_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { @@ -905,6 +932,9 @@ static int bq24190_charger_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: ret = bq24190_charger_get_voltage_max(bdi, val); break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = bq24190_charger_get_iinlimit(bdi, val); + break; case POWER_SUPPLY_PROP_SCOPE: val->intval = POWER_SUPPLY_SCOPE_SYSTEM; ret = 0; @@ -956,6 +986,9 @@ static int bq24190_charger_set_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: ret = bq24190_charger_set_voltage(bdi, val); break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = bq24190_charger_set_iinlimit(bdi, val); + break; default: ret = -EINVAL; } @@ -977,6 +1010,7 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_TYPE: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: ret = 1; break; default: @@ -996,6 +1030,7 @@ static enum power_supply_property bq24190_charger_properties[] = { POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, -- cgit v1.2.3 From 64b46b7b87fc44081f320ce0bb0c5278489cfc0e Mon Sep 17 00:00:00 2001 From: Liam Breck Date: Mon, 28 Aug 2017 14:23:45 -0700 Subject: power: supply: bq24190_charger: Add ti,bq24192i to devicetree table bq24192i was previously only in ID table, so add it to DT table. Cc: Tony Lindgren Cc: Hans de Goede Signed-off-by: Liam Breck Acked-by: Tony Lindgren Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 7360f4259e63..4cb5741cbb46 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -1771,6 +1771,7 @@ MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids); #ifdef CONFIG_OF static const struct of_device_id bq24190_of_match[] = { { .compatible = "ti,bq24190", }, + { .compatible = "ti,bq24192i", }, { }, }; MODULE_DEVICE_TABLE(of, bq24190_of_match); -- cgit v1.2.3 From 9aade6d8f9d0fd086068fc390c6f6c0ce98ea07a Mon Sep 17 00:00:00 2001 From: Liam Breck Date: Wed, 23 Aug 2017 20:36:13 -0700 Subject: power: supply: bq27xxx: Create single chip data table To support new features which require different data for each chip, we unify the bq27xxx_regs and bq27xxx_battery_props tables into a single one. No functional changes to the driver. Signed-off-by: Liam Breck Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 121 ++++++++++++++++----------------- 1 file changed, 60 insertions(+), 61 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 079083b31293..00322ccf09b5 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -132,8 +132,8 @@ enum bq27xxx_reg_index { [BQ27XXX_DM_CKSUM] = 0x60 /* Register mappings */ -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { - [BQ27000] = { +static u8 + bq27000_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, @@ -157,7 +157,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, }, - [BQ27010] = { + bq27010_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, @@ -181,7 +181,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, }, - [BQ2750X] = { + bq2750x_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x28, @@ -201,7 +201,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = INVALID_REG_ADDR, BQ27XXX_DM_REG_ROWS, }, - [BQ2751X] = { + bq2751x_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x28, @@ -221,7 +221,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = INVALID_REG_ADDR, BQ27XXX_DM_REG_ROWS, }, - [BQ27500] = { + bq27500_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, @@ -241,7 +241,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - [BQ27510G1] = { + bq27510g1_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, @@ -261,7 +261,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - [BQ27510G2] = { + bq27510g2_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, @@ -281,7 +281,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - [BQ27510G3] = { + bq27510g3_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x28, @@ -301,7 +301,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = INVALID_REG_ADDR, BQ27XXX_DM_REG_ROWS, }, - [BQ27520G1] = { + bq27520g1_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, @@ -321,7 +321,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - [BQ27520G2] = { + bq27520g2_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x36, @@ -341,7 +341,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - [BQ27520G3] = { + bq27520g3_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x36, @@ -361,7 +361,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - [BQ27520G4] = { + bq27520g4_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x28, @@ -381,7 +381,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = INVALID_REG_ADDR, BQ27XXX_DM_REG_ROWS, }, - [BQ27530] = { + bq27530_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x32, @@ -401,7 +401,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - [BQ27541] = { + bq27541_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x28, @@ -421,7 +421,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - [BQ27545] = { + bq27545_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x28, @@ -441,7 +441,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - [BQ27421] = { + bq27421_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x02, [BQ27XXX_REG_INT_TEMP] = 0x1e, @@ -460,10 +460,9 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_DCAP] = 0x3c, [BQ27XXX_REG_AP] = 0x18, BQ27XXX_DM_REG_ROWS, - }, -}; + }; -static enum power_supply_property bq27000_battery_props[] = { +static enum power_supply_property bq27000_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -485,7 +484,7 @@ static enum power_supply_property bq27000_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27010_battery_props[] = { +static enum power_supply_property bq27010_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -505,7 +504,7 @@ static enum power_supply_property bq27010_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq2750x_battery_props[] = { +static enum power_supply_property bq2750x_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -523,7 +522,7 @@ static enum power_supply_property bq2750x_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq2751x_battery_props[] = { +static enum power_supply_property bq2751x_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -541,7 +540,7 @@ static enum power_supply_property bq2751x_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27500_battery_props[] = { +static enum power_supply_property bq27500_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -562,7 +561,7 @@ static enum power_supply_property bq27500_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27510g1_battery_props[] = { +static enum power_supply_property bq27510g1_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -583,7 +582,7 @@ static enum power_supply_property bq27510g1_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27510g2_battery_props[] = { +static enum power_supply_property bq27510g2_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -604,7 +603,7 @@ static enum power_supply_property bq27510g2_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27510g3_battery_props[] = { +static enum power_supply_property bq27510g3_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -622,7 +621,7 @@ static enum power_supply_property bq27510g3_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27520g1_battery_props[] = { +static enum power_supply_property bq27520g1_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -642,7 +641,7 @@ static enum power_supply_property bq27520g1_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27520g2_battery_props[] = { +static enum power_supply_property bq27520g2_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -663,7 +662,7 @@ static enum power_supply_property bq27520g2_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27520g3_battery_props[] = { +static enum power_supply_property bq27520g3_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -683,7 +682,7 @@ static enum power_supply_property bq27520g3_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27520g4_battery_props[] = { +static enum power_supply_property bq27520g4_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -700,7 +699,7 @@ static enum power_supply_property bq27520g4_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27530_battery_props[] = { +static enum power_supply_property bq27530_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -718,7 +717,7 @@ static enum power_supply_property bq27530_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27541_battery_props[] = { +static enum power_supply_property bq27541_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -737,7 +736,7 @@ static enum power_supply_property bq27541_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27545_battery_props[] = { +static enum power_supply_property bq27545_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -755,7 +754,7 @@ static enum power_supply_property bq27545_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27421_battery_props[] = { +static enum power_supply_property bq27421_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -770,32 +769,32 @@ static enum power_supply_property bq27421_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -#define BQ27XXX_PROP(_id, _prop) \ - [_id] = { \ - .props = _prop, \ - .size = ARRAY_SIZE(_prop), \ - } +#define BQ27XXX_DATA(ref) { \ + .regs = ref##_regs, \ + .props = ref##_props, \ + .props_size = ARRAY_SIZE(ref##_props) } static struct { + u8 *regs; enum power_supply_property *props; - size_t size; -} bq27xxx_battery_props[] = { - BQ27XXX_PROP(BQ27000, bq27000_battery_props), - BQ27XXX_PROP(BQ27010, bq27010_battery_props), - BQ27XXX_PROP(BQ2750X, bq2750x_battery_props), - BQ27XXX_PROP(BQ2751X, bq2751x_battery_props), - BQ27XXX_PROP(BQ27500, bq27500_battery_props), - BQ27XXX_PROP(BQ27510G1, bq27510g1_battery_props), - BQ27XXX_PROP(BQ27510G2, bq27510g2_battery_props), - BQ27XXX_PROP(BQ27510G3, bq27510g3_battery_props), - BQ27XXX_PROP(BQ27520G1, bq27520g1_battery_props), - BQ27XXX_PROP(BQ27520G2, bq27520g2_battery_props), - BQ27XXX_PROP(BQ27520G3, bq27520g3_battery_props), - BQ27XXX_PROP(BQ27520G4, bq27520g4_battery_props), - BQ27XXX_PROP(BQ27530, bq27530_battery_props), - BQ27XXX_PROP(BQ27541, bq27541_battery_props), - BQ27XXX_PROP(BQ27545, bq27545_battery_props), - BQ27XXX_PROP(BQ27421, bq27421_battery_props), + size_t props_size; +} bq27xxx_chip_data[] = { + [BQ27000] = BQ27XXX_DATA(bq27000), + [BQ27010] = BQ27XXX_DATA(bq27010), + [BQ2750X] = BQ27XXX_DATA(bq2750x), + [BQ2751X] = BQ27XXX_DATA(bq2751x), + [BQ27500] = BQ27XXX_DATA(bq27500), + [BQ27510G1] = BQ27XXX_DATA(bq27510g1), + [BQ27510G2] = BQ27XXX_DATA(bq27510g2), + [BQ27510G3] = BQ27XXX_DATA(bq27510g3), + [BQ27520G1] = BQ27XXX_DATA(bq27520g1), + [BQ27520G2] = BQ27XXX_DATA(bq27520g2), + [BQ27520G3] = BQ27XXX_DATA(bq27520g3), + [BQ27520G4] = BQ27XXX_DATA(bq27520g4), + [BQ27530] = BQ27XXX_DATA(bq27530), + [BQ27541] = BQ27XXX_DATA(bq27541), + [BQ27545] = BQ27XXX_DATA(bq27545), + [BQ27421] = BQ27XXX_DATA(bq27421), }; static DEFINE_MUTEX(bq27xxx_list_lock); @@ -1884,7 +1883,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); mutex_init(&di->lock); - di->regs = bq27xxx_regs[di->chip]; + di->regs = bq27xxx_chip_data[di->chip].regs; psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL); if (!psy_desc) @@ -1892,8 +1891,8 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) psy_desc->name = di->name; psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; - psy_desc->properties = bq27xxx_battery_props[di->chip].props; - psy_desc->num_properties = bq27xxx_battery_props[di->chip].size; + psy_desc->properties = bq27xxx_chip_data[di->chip].props; + psy_desc->num_properties = bq27xxx_chip_data[di->chip].props_size; psy_desc->get_property = bq27xxx_battery_get_property; psy_desc->external_power_changed = bq27xxx_external_power_changed; -- cgit v1.2.3 From 3a731c6414c94012328f485b4b1bb88ed841f9eb Mon Sep 17 00:00:00 2001 From: Liam Breck Date: Wed, 23 Aug 2017 20:36:14 -0700 Subject: power: supply: bq27xxx: Add chip IDs for previously shadowed chips For the existing features, these chips act like others already ID'd, so they had false but functional IDs. We will be adding features which require correct IDs, so the following IDs are added: BQ2752X, 531, 542, 546, 742, 425, 441, 621 Chip-specific features are now tracked by BQ27XXX_O_* flags in di->opts. No functional changes to the driver. Signed-off-by: Liam Breck Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 120 +++++++++++++++++------------ drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++-- include/linux/power/bq27xxx_battery.h | 9 +++ 3 files changed, 86 insertions(+), 59 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 00322ccf09b5..cf0f19e2a639 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -221,6 +221,7 @@ static u8 [BQ27XXX_REG_AP] = INVALID_REG_ADDR, BQ27XXX_DM_REG_ROWS, }, +#define bq2752x_regs bq2751x_regs bq27500_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, @@ -401,6 +402,7 @@ static u8 [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, +#define bq27531_regs bq27530_regs bq27541_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, @@ -421,6 +423,9 @@ static u8 [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, +#define bq27542_regs bq27541_regs +#define bq27546_regs bq27541_regs +#define bq27742_regs bq27541_regs bq27545_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, @@ -461,6 +466,9 @@ static u8 [BQ27XXX_REG_AP] = 0x18, BQ27XXX_DM_REG_ROWS, }; +#define bq27425_regs bq27421_regs +#define bq27441_regs bq27421_regs +#define bq27621_regs bq27421_regs static enum power_supply_property bq27000_props[] = { POWER_SUPPLY_PROP_STATUS, @@ -539,6 +547,7 @@ static enum power_supply_property bq2751x_props[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_MANUFACTURER, }; +#define bq2752x_props bq2751x_props static enum power_supply_property bq27500_props[] = { POWER_SUPPLY_PROP_STATUS, @@ -716,6 +725,7 @@ static enum power_supply_property bq27530_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_MANUFACTURER, }; +#define bq27531_props bq27530_props static enum power_supply_property bq27541_props[] = { POWER_SUPPLY_PROP_STATUS, @@ -735,6 +745,9 @@ static enum power_supply_property bq27541_props[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_MANUFACTURER, }; +#define bq27542_props bq27541_props +#define bq27546_props bq27541_props +#define bq27742_props bq27541_props static enum power_supply_property bq27545_props[] = { POWER_SUPPLY_PROP_STATUS, @@ -768,33 +781,50 @@ static enum power_supply_property bq27421_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_MANUFACTURER, }; +#define bq27425_props bq27421_props +#define bq27441_props bq27421_props +#define bq27621_props bq27421_props -#define BQ27XXX_DATA(ref) { \ +#define BQ27XXX_O_ZERO 0x00000001 +#define BQ27XXX_O_OTDC 0x00000002 +#define BQ27XXX_O_UTOT 0x00000004 + +#define BQ27XXX_DATA(ref, opt) { \ + .opts = (opt), \ .regs = ref##_regs, \ .props = ref##_props, \ .props_size = ARRAY_SIZE(ref##_props) } static struct { + u32 opts; u8 *regs; enum power_supply_property *props; size_t props_size; } bq27xxx_chip_data[] = { - [BQ27000] = BQ27XXX_DATA(bq27000), - [BQ27010] = BQ27XXX_DATA(bq27010), - [BQ2750X] = BQ27XXX_DATA(bq2750x), - [BQ2751X] = BQ27XXX_DATA(bq2751x), - [BQ27500] = BQ27XXX_DATA(bq27500), - [BQ27510G1] = BQ27XXX_DATA(bq27510g1), - [BQ27510G2] = BQ27XXX_DATA(bq27510g2), - [BQ27510G3] = BQ27XXX_DATA(bq27510g3), - [BQ27520G1] = BQ27XXX_DATA(bq27520g1), - [BQ27520G2] = BQ27XXX_DATA(bq27520g2), - [BQ27520G3] = BQ27XXX_DATA(bq27520g3), - [BQ27520G4] = BQ27XXX_DATA(bq27520g4), - [BQ27530] = BQ27XXX_DATA(bq27530), - [BQ27541] = BQ27XXX_DATA(bq27541), - [BQ27545] = BQ27XXX_DATA(bq27545), - [BQ27421] = BQ27XXX_DATA(bq27421), + [BQ27000] = BQ27XXX_DATA(bq27000, BQ27XXX_O_ZERO), + [BQ27010] = BQ27XXX_DATA(bq27010, BQ27XXX_O_ZERO), + [BQ2750X] = BQ27XXX_DATA(bq2750x, BQ27XXX_O_OTDC), + [BQ2751X] = BQ27XXX_DATA(bq2751x, BQ27XXX_O_OTDC), + [BQ2752X] = BQ27XXX_DATA(bq2752x, BQ27XXX_O_OTDC), + [BQ27500] = BQ27XXX_DATA(bq27500, BQ27XXX_O_OTDC), + [BQ27510G1] = BQ27XXX_DATA(bq27510g1, BQ27XXX_O_OTDC), + [BQ27510G2] = BQ27XXX_DATA(bq27510g2, BQ27XXX_O_OTDC), + [BQ27510G3] = BQ27XXX_DATA(bq27510g3, BQ27XXX_O_OTDC), + [BQ27520G1] = BQ27XXX_DATA(bq27520g1, BQ27XXX_O_OTDC), + [BQ27520G2] = BQ27XXX_DATA(bq27520g2, BQ27XXX_O_OTDC), + [BQ27520G3] = BQ27XXX_DATA(bq27520g3, BQ27XXX_O_OTDC), + [BQ27520G4] = BQ27XXX_DATA(bq27520g4, BQ27XXX_O_OTDC), + [BQ27530] = BQ27XXX_DATA(bq27530, BQ27XXX_O_UTOT), + [BQ27531] = BQ27XXX_DATA(bq27531, BQ27XXX_O_UTOT), + [BQ27541] = BQ27XXX_DATA(bq27541, BQ27XXX_O_OTDC), + [BQ27542] = BQ27XXX_DATA(bq27542, BQ27XXX_O_OTDC), + [BQ27546] = BQ27XXX_DATA(bq27546, BQ27XXX_O_OTDC), + [BQ27742] = BQ27XXX_DATA(bq27742, BQ27XXX_O_OTDC), + [BQ27545] = BQ27XXX_DATA(bq27545, BQ27XXX_O_OTDC), + [BQ27421] = BQ27XXX_DATA(bq27421, BQ27XXX_O_UTOT), + [BQ27425] = BQ27XXX_DATA(bq27425, BQ27XXX_O_UTOT), + [BQ27441] = BQ27XXX_DATA(bq27441, BQ27XXX_O_UTOT), + [BQ27621] = BQ27XXX_DATA(bq27621, BQ27XXX_O_UTOT), }; static DEFINE_MUTEX(bq27xxx_list_lock); @@ -1327,7 +1357,7 @@ static int bq27xxx_battery_read_soc(struct bq27xxx_device_info *di) { int soc; - if (di->chip == BQ27000 || di->chip == BQ27010) + if (di->opts & BQ27XXX_O_ZERO) soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true); else soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false); @@ -1353,7 +1383,7 @@ static int bq27xxx_battery_read_charge(struct bq27xxx_device_info *di, u8 reg) return charge; } - if (di->chip == BQ27000 || di->chip == BQ27010) + if (di->opts & BQ27XXX_O_ZERO) charge *= BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; else charge *= 1000; @@ -1369,7 +1399,7 @@ static inline int bq27xxx_battery_read_nac(struct bq27xxx_device_info *di) { int flags; - if (di->chip == BQ27000 || di->chip == BQ27010) { + if (di->opts & BQ27XXX_O_ZERO) { flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true); if (flags >= 0 && (flags & BQ27000_FLAG_CI)) return -ENODATA; @@ -1395,7 +1425,7 @@ static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di) { int dcap; - if (di->chip == BQ27000 || di->chip == BQ27010) + if (di->opts & BQ27XXX_O_ZERO) dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true); else dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false); @@ -1405,7 +1435,7 @@ static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di) return dcap; } - if (di->chip == BQ27000 || di->chip == BQ27010) + if (di->opts & BQ27XXX_O_ZERO) dcap = (dcap << 8) * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; else dcap *= 1000; @@ -1427,7 +1457,7 @@ static int bq27xxx_battery_read_energy(struct bq27xxx_device_info *di) return ae; } - if (di->chip == BQ27000 || di->chip == BQ27010) + if (di->opts & BQ27XXX_O_ZERO) ae *= BQ27XXX_POWER_CONSTANT / BQ27XXX_RS; else ae *= 1000; @@ -1449,7 +1479,7 @@ static int bq27xxx_battery_read_temperature(struct bq27xxx_device_info *di) return temp; } - if (di->chip == BQ27000 || di->chip == BQ27010) + if (di->opts & BQ27XXX_O_ZERO) temp = 5 * temp / 2; return temp; @@ -1506,7 +1536,7 @@ static int bq27xxx_battery_read_pwr_avg(struct bq27xxx_device_info *di) return tval; } - if (di->chip == BQ27000 || di->chip == BQ27010) + if (di->opts & BQ27XXX_O_ZERO) return (tval * BQ27XXX_POWER_CONSTANT) / BQ27XXX_RS; else return tval; @@ -1517,26 +1547,12 @@ static int bq27xxx_battery_read_pwr_avg(struct bq27xxx_device_info *di) */ static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags) { - switch (di->chip) { - case BQ2750X: - case BQ2751X: - case BQ27500: - case BQ27510G1: - case BQ27510G2: - case BQ27510G3: - case BQ27520G1: - case BQ27520G2: - case BQ27520G3: - case BQ27520G4: - case BQ27541: - case BQ27545: + if (di->opts & BQ27XXX_O_OTDC) return flags & (BQ27XXX_FLAG_OTC | BQ27XXX_FLAG_OTD); - case BQ27530: - case BQ27421: + if (di->opts & BQ27XXX_O_UTOT) return flags & BQ27XXX_FLAG_OT; - default: - return false; - } + + return false; } /* @@ -1544,7 +1560,7 @@ static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags) */ static bool bq27xxx_battery_undertemp(struct bq27xxx_device_info *di, u16 flags) { - if (di->chip == BQ27530 || di->chip == BQ27421) + if (di->opts & BQ27XXX_O_UTOT) return flags & BQ27XXX_FLAG_UT; return false; @@ -1555,7 +1571,7 @@ static bool bq27xxx_battery_undertemp(struct bq27xxx_device_info *di, u16 flags) */ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) { - if (di->chip == BQ27000 || di->chip == BQ27010) + if (di->opts & BQ27XXX_O_ZERO) return flags & (BQ27000_FLAG_EDV1 | BQ27000_FLAG_EDVF); else return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF); @@ -1568,7 +1584,7 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) { int flags; - bool has_singe_flag = di->chip == BQ27000 || di->chip == BQ27010; + bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); if (flags < 0) { @@ -1590,8 +1606,8 @@ static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) void bq27xxx_battery_update(struct bq27xxx_device_info *di) { struct bq27xxx_reg_cache cache = {0, }; - bool has_ci_flag = di->chip == BQ27000 || di->chip == BQ27010; - bool has_singe_flag = di->chip == BQ27000 || di->chip == BQ27010; + bool has_ci_flag = di->opts & BQ27XXX_O_ZERO; + bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); if ((cache.flags & 0xff) == 0xff) @@ -1669,7 +1685,7 @@ static int bq27xxx_battery_current(struct bq27xxx_device_info *di, return curr; } - if (di->chip == BQ27000 || di->chip == BQ27010) { + if (di->opts & BQ27XXX_O_ZERO) { flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true); if (flags & BQ27000_FLAG_CHGS) { dev_dbg(di->dev, "negative current!\n"); @@ -1690,7 +1706,7 @@ static int bq27xxx_battery_status(struct bq27xxx_device_info *di, { int status; - if (di->chip == BQ27000 || di->chip == BQ27010) { + if (di->opts & BQ27XXX_O_ZERO) { if (di->cache.flags & BQ27000_FLAG_FC) status = POWER_SUPPLY_STATUS_FULL; else if (di->cache.flags & BQ27000_FLAG_CHGS) @@ -1718,7 +1734,7 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di, { int level; - if (di->chip == BQ27000 || di->chip == BQ27010) { + if (di->opts & BQ27XXX_O_ZERO) { if (di->cache.flags & BQ27000_FLAG_FC) level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; else if (di->cache.flags & BQ27000_FLAG_EDV1) @@ -1883,7 +1899,9 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); mutex_init(&di->lock); + di->regs = bq27xxx_chip_data[di->chip].regs; + di->opts = bq27xxx_chip_data[di->chip].opts; psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL); if (!psy_desc) diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index a5972214f074..0b11ed472f33 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = { { "bq27210", BQ27010 }, { "bq27500", BQ2750X }, { "bq27510", BQ2751X }, - { "bq27520", BQ2751X }, + { "bq27520", BQ2752X }, { "bq27500-1", BQ27500 }, { "bq27510g1", BQ27510G1 }, { "bq27510g2", BQ27510G2 }, @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = { { "bq27520g3", BQ27520G3 }, { "bq27520g4", BQ27520G4 }, { "bq27530", BQ27530 }, - { "bq27531", BQ27530 }, + { "bq27531", BQ27531 }, { "bq27541", BQ27541 }, - { "bq27542", BQ27541 }, - { "bq27546", BQ27541 }, - { "bq27742", BQ27541 }, + { "bq27542", BQ27542 }, + { "bq27546", BQ27546 }, + { "bq27742", BQ27742 }, { "bq27545", BQ27545 }, { "bq27421", BQ27421 }, - { "bq27425", BQ27421 }, - { "bq27441", BQ27421 }, - { "bq27621", BQ27421 }, + { "bq27425", BQ27425 }, + { "bq27441", BQ27441 }, + { "bq27621", BQ27621 }, {}, }; MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table); diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index 89890437f9ab..e48e7a4e9cd6 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -6,6 +6,7 @@ enum bq27xxx_chip { BQ27010, /* bq27010, bq27210 */ BQ2750X, /* bq27500 deprecated alias */ BQ2751X, /* bq27510, bq27520 deprecated alias */ + BQ2752X, BQ27500, /* bq27500/1 */ BQ27510G1, /* bq27510G1 */ BQ27510G2, /* bq27510G2 */ @@ -15,9 +16,16 @@ enum bq27xxx_chip { BQ27520G3, /* bq27520G3 */ BQ27520G4, /* bq27520G4 */ BQ27530, /* bq27530, bq27531 */ + BQ27531, BQ27541, /* bq27541, bq27542, bq27546, bq27742 */ + BQ27542, + BQ27546, + BQ27742, BQ27545, /* bq27545 */ BQ27421, /* bq27421, bq27425, bq27441, bq27621 */ + BQ27425, + BQ27441, + BQ27621, }; struct bq27xxx_device_info; @@ -47,6 +55,7 @@ struct bq27xxx_device_info { int id; enum bq27xxx_chip chip; bool ram_chip; + u32 opts; const char *name; struct bq27xxx_dm_reg *dm_regs; u32 unseal_key; -- cgit v1.2.3 From 05045379b2740686020618c8cfd4b517cff9f918 Mon Sep 17 00:00:00 2001 From: Liam Breck Date: Wed, 23 Aug 2017 20:36:15 -0700 Subject: power: supply: bq27xxx: Enable data memory update for certain chips Support data memory update on BQ27425. Parameters from TI datasheets are also provided for BQ27500, 545, 421, 441, 621; however these are commented out, as they are not tested. Add BQ27XXX_O_CFGUP & _O_RAM for use in bq27xxx_chip_data[n].opts and by data memory update functions. Signed-off-by: Liam Breck Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 175 ++++++++++++++++++++++++--------- include/linux/power/bq27xxx_battery.h | 1 - 2 files changed, 126 insertions(+), 50 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index cf0f19e2a639..cf3e8a173bc6 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -58,8 +58,6 @@ #include -#define DRIVER_VERSION "1.2.0" - #define BQ27XXX_MANUFACTURER "Texas Instruments" /* BQ27XXX Flags */ @@ -785,46 +783,138 @@ static enum power_supply_property bq27421_props[] = { #define bq27441_props bq27421_props #define bq27621_props bq27421_props +struct bq27xxx_dm_reg { + u8 subclass_id; + u8 offset; + u8 bytes; + u16 min, max; +}; + +enum bq27xxx_dm_reg_id { + BQ27XXX_DM_DESIGN_CAPACITY = 0, + BQ27XXX_DM_DESIGN_ENERGY, + BQ27XXX_DM_TERMINATE_VOLTAGE, +}; + +#define bq27000_dm_regs 0 +#define bq27010_dm_regs 0 +#define bq2750x_dm_regs 0 +#define bq2751x_dm_regs 0 +#define bq2752x_dm_regs 0 + +#if 0 /* not yet tested */ +static struct bq27xxx_dm_reg bq27500_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 10, 2, 0, 65535 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { }, /* missing on chip */ + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 }, +}; +#else +#define bq27500_dm_regs 0 +#endif + +/* todo create data memory definitions from datasheets and test on chips */ +#define bq27510g1_dm_regs 0 +#define bq27510g2_dm_regs 0 +#define bq27510g3_dm_regs 0 +#define bq27520g1_dm_regs 0 +#define bq27520g2_dm_regs 0 +#define bq27520g3_dm_regs 0 +#define bq27520g4_dm_regs 0 +#define bq27530_dm_regs 0 +#define bq27531_dm_regs 0 +#define bq27541_dm_regs 0 +#define bq27542_dm_regs 0 +#define bq27546_dm_regs 0 +#define bq27742_dm_regs 0 + +#if 0 /* not yet tested */ +static struct bq27xxx_dm_reg bq27545_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 23, 2, 0, 32767 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { 48, 25, 2, 0, 32767 }, + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800, 3700 }, +}; +#else +#define bq27545_dm_regs 0 +#endif + +#if 0 /* not yet tested */ +static struct bq27xxx_dm_reg bq27421_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 8000 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500, 3700 }, +}; +#else +#define bq27421_dm_regs 0 +#endif + +static struct bq27xxx_dm_reg bq27425_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 12, 2, 0, 32767 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 14, 2, 0, 32767 }, + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800, 3700 }, +}; + +#if 0 /* not yet tested */ +#define bq27441_dm_regs bq27421_dm_regs +#else +#define bq27441_dm_regs 0 +#endif + +#if 0 /* not yet tested */ +static struct bq27xxx_dm_reg bq27621_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 3, 2, 0, 8000 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 5, 2, 0, 32767 }, + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500, 3700 }, +}; +#else +#define bq27621_dm_regs 0 +#endif + #define BQ27XXX_O_ZERO 0x00000001 #define BQ27XXX_O_OTDC 0x00000002 #define BQ27XXX_O_UTOT 0x00000004 +#define BQ27XXX_O_CFGUP 0x00000008 +#define BQ27XXX_O_RAM 0x00000010 -#define BQ27XXX_DATA(ref, opt) { \ +#define BQ27XXX_DATA(ref, key, opt) { \ .opts = (opt), \ + .unseal_key = key, \ .regs = ref##_regs, \ + .dm_regs = ref##_dm_regs, \ .props = ref##_props, \ .props_size = ARRAY_SIZE(ref##_props) } static struct { u32 opts; + u32 unseal_key; u8 *regs; + struct bq27xxx_dm_reg *dm_regs; enum power_supply_property *props; size_t props_size; } bq27xxx_chip_data[] = { - [BQ27000] = BQ27XXX_DATA(bq27000, BQ27XXX_O_ZERO), - [BQ27010] = BQ27XXX_DATA(bq27010, BQ27XXX_O_ZERO), - [BQ2750X] = BQ27XXX_DATA(bq2750x, BQ27XXX_O_OTDC), - [BQ2751X] = BQ27XXX_DATA(bq2751x, BQ27XXX_O_OTDC), - [BQ2752X] = BQ27XXX_DATA(bq2752x, BQ27XXX_O_OTDC), - [BQ27500] = BQ27XXX_DATA(bq27500, BQ27XXX_O_OTDC), - [BQ27510G1] = BQ27XXX_DATA(bq27510g1, BQ27XXX_O_OTDC), - [BQ27510G2] = BQ27XXX_DATA(bq27510g2, BQ27XXX_O_OTDC), - [BQ27510G3] = BQ27XXX_DATA(bq27510g3, BQ27XXX_O_OTDC), - [BQ27520G1] = BQ27XXX_DATA(bq27520g1, BQ27XXX_O_OTDC), - [BQ27520G2] = BQ27XXX_DATA(bq27520g2, BQ27XXX_O_OTDC), - [BQ27520G3] = BQ27XXX_DATA(bq27520g3, BQ27XXX_O_OTDC), - [BQ27520G4] = BQ27XXX_DATA(bq27520g4, BQ27XXX_O_OTDC), - [BQ27530] = BQ27XXX_DATA(bq27530, BQ27XXX_O_UTOT), - [BQ27531] = BQ27XXX_DATA(bq27531, BQ27XXX_O_UTOT), - [BQ27541] = BQ27XXX_DATA(bq27541, BQ27XXX_O_OTDC), - [BQ27542] = BQ27XXX_DATA(bq27542, BQ27XXX_O_OTDC), - [BQ27546] = BQ27XXX_DATA(bq27546, BQ27XXX_O_OTDC), - [BQ27742] = BQ27XXX_DATA(bq27742, BQ27XXX_O_OTDC), - [BQ27545] = BQ27XXX_DATA(bq27545, BQ27XXX_O_OTDC), - [BQ27421] = BQ27XXX_DATA(bq27421, BQ27XXX_O_UTOT), - [BQ27425] = BQ27XXX_DATA(bq27425, BQ27XXX_O_UTOT), - [BQ27441] = BQ27XXX_DATA(bq27441, BQ27XXX_O_UTOT), - [BQ27621] = BQ27XXX_DATA(bq27621, BQ27XXX_O_UTOT), + [BQ27000] = BQ27XXX_DATA(bq27000, 0 , BQ27XXX_O_ZERO), + [BQ27010] = BQ27XXX_DATA(bq27010, 0 , BQ27XXX_O_ZERO), + [BQ2750X] = BQ27XXX_DATA(bq2750x, 0 , BQ27XXX_O_OTDC), + [BQ2751X] = BQ27XXX_DATA(bq2751x, 0 , BQ27XXX_O_OTDC), + [BQ2752X] = BQ27XXX_DATA(bq2752x, 0 , BQ27XXX_O_OTDC), + [BQ27500] = BQ27XXX_DATA(bq27500, 0x04143672, BQ27XXX_O_OTDC), + [BQ27510G1] = BQ27XXX_DATA(bq27510g1, 0 , BQ27XXX_O_OTDC), + [BQ27510G2] = BQ27XXX_DATA(bq27510g2, 0 , BQ27XXX_O_OTDC), + [BQ27510G3] = BQ27XXX_DATA(bq27510g3, 0 , BQ27XXX_O_OTDC), + [BQ27520G1] = BQ27XXX_DATA(bq27520g1, 0 , BQ27XXX_O_OTDC), + [BQ27520G2] = BQ27XXX_DATA(bq27520g2, 0 , BQ27XXX_O_OTDC), + [BQ27520G3] = BQ27XXX_DATA(bq27520g3, 0 , BQ27XXX_O_OTDC), + [BQ27520G4] = BQ27XXX_DATA(bq27520g4, 0 , BQ27XXX_O_OTDC), + [BQ27530] = BQ27XXX_DATA(bq27530, 0 , BQ27XXX_O_UTOT), + [BQ27531] = BQ27XXX_DATA(bq27531, 0 , BQ27XXX_O_UTOT), + [BQ27541] = BQ27XXX_DATA(bq27541, 0 , BQ27XXX_O_OTDC), + [BQ27542] = BQ27XXX_DATA(bq27542, 0 , BQ27XXX_O_OTDC), + [BQ27546] = BQ27XXX_DATA(bq27546, 0 , BQ27XXX_O_OTDC), + [BQ27742] = BQ27XXX_DATA(bq27742, 0 , BQ27XXX_O_OTDC), + [BQ27545] = BQ27XXX_DATA(bq27545, 0x04143672, BQ27XXX_O_OTDC), + [BQ27421] = BQ27XXX_DATA(bq27421, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), + [BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP), + [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), }; static DEFINE_MUTEX(bq27xxx_list_lock); @@ -834,13 +924,6 @@ static LIST_HEAD(bq27xxx_battery_devices); #define BQ27XXX_DM_SZ 32 -struct bq27xxx_dm_reg { - u8 subclass_id; - u8 offset; - u8 bytes; - u16 min, max; -}; - /** * struct bq27xxx_dm_buf - chip data memory buffer * @class: data memory subclass_id @@ -873,12 +956,6 @@ static inline u16 *bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf, return NULL; } -enum bq27xxx_dm_reg_id { - BQ27XXX_DM_DESIGN_CAPACITY = 0, - BQ27XXX_DM_DESIGN_ENERGY, - BQ27XXX_DM_TERMINATE_VOLTAGE, -}; - static const char * const bq27xxx_dm_reg_name[] = { [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity", [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy", @@ -1121,9 +1198,9 @@ static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di, } #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM - if (!di->ram_chip && !bq27xxx_dt_to_nvm) { + if (!(di->opts & BQ27XXX_O_RAM) && !bq27xxx_dt_to_nvm) { #else - if (!di->ram_chip) { + if (!(di->opts & BQ27XXX_O_RAM)) { #endif /* devicetree and NVM differ; defer to NVM */ dev_warn(di->dev, "%s has %u; update to %u disallowed " @@ -1159,7 +1236,7 @@ static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info *di, bool a return ret; } while (!!(ret & BQ27XXX_FLAG_CFGUP) != active && --try); - if (!try) { + if (!try && di->chip != BQ27425) { // 425 has a bug dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", active); return -EINVAL; } @@ -1191,7 +1268,7 @@ static inline int bq27xxx_battery_soft_reset(struct bq27xxx_device_info *di) static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di, struct bq27xxx_dm_buf *buf) { - bool cfgup = di->chip == BQ27421; /* assume related chips need cfgupdate */ + bool cfgup = di->opts & BQ27XXX_O_CFGUP; int ret; if (!buf->dirty) @@ -1290,7 +1367,7 @@ static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, bq27xxx_battery_seal(di); - if (updated && di->chip != BQ27421) { /* not a cfgupdate chip, so reset */ + if (updated && !(di->opts & BQ27XXX_O_CFGUP)) { bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false); BQ27XXX_MSLEEP(300); /* reset time is not documented */ } @@ -1900,8 +1977,10 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); mutex_init(&di->lock); - di->regs = bq27xxx_chip_data[di->chip].regs; - di->opts = bq27xxx_chip_data[di->chip].opts; + di->regs = bq27xxx_chip_data[di->chip].regs; + di->unseal_key = bq27xxx_chip_data[di->chip].unseal_key; + di->dm_regs = bq27xxx_chip_data[di->chip].dm_regs; + di->opts = bq27xxx_chip_data[di->chip].opts; psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL); if (!psy_desc) @@ -1920,8 +1999,6 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) return PTR_ERR(di->bat); } - dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION); - bq27xxx_battery_settings(di); bq27xxx_battery_update(di); diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index e48e7a4e9cd6..43194e02c1ee 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -54,7 +54,6 @@ struct bq27xxx_device_info { struct device *dev; int id; enum bq27xxx_chip chip; - bool ram_chip; u32 opts; const char *name; struct bq27xxx_dm_reg *dm_regs; -- cgit v1.2.3 From 1059361fb69b6cae4464560763b594304983e229 Mon Sep 17 00:00:00 2001 From: Liam Breck Date: Wed, 23 Aug 2017 20:36:17 -0700 Subject: power: supply: bq27xxx: Remove duplicate chip data arrays BQ2751X & BQ27510G3 have identical regs & props. BQ2750X & BQ27510G3 have identical props. BQ27500 & BQ27510G1 & BQ27510G2 have identical regs & props. BQ27500 & BQ27520G2 have identical props. Remove the duplicate arrays. No functional changes to the driver. Signed-off-by: Liam Breck Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 169 ++------------------------------- 1 file changed, 10 insertions(+), 159 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index cf3e8a173bc6..527dc2558fd2 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -199,27 +199,8 @@ static u8 [BQ27XXX_REG_AP] = INVALID_REG_ADDR, BQ27XXX_DM_REG_ROWS, }, - bq2751x_regs[BQ27XXX_REG_MAX] = { - [BQ27XXX_REG_CTRL] = 0x00, - [BQ27XXX_REG_TEMP] = 0x06, - [BQ27XXX_REG_INT_TEMP] = 0x28, - [BQ27XXX_REG_VOLT] = 0x08, - [BQ27XXX_REG_AI] = 0x14, - [BQ27XXX_REG_FLAGS] = 0x0a, - [BQ27XXX_REG_TTE] = 0x16, - [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTES] = 0x1a, - [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, - [BQ27XXX_REG_NAC] = 0x0c, - [BQ27XXX_REG_FCC] = 0x12, - [BQ27XXX_REG_CYCT] = 0x1e, - [BQ27XXX_REG_AE] = INVALID_REG_ADDR, - [BQ27XXX_REG_SOC] = 0x20, - [BQ27XXX_REG_DCAP] = 0x2e, - [BQ27XXX_REG_AP] = INVALID_REG_ADDR, - BQ27XXX_DM_REG_ROWS, - }, -#define bq2752x_regs bq2751x_regs +#define bq2751x_regs bq27510g3_regs +#define bq2752x_regs bq27510g3_regs bq27500_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, @@ -240,46 +221,8 @@ static u8 [BQ27XXX_REG_AP] = 0x24, BQ27XXX_DM_REG_ROWS, }, - bq27510g1_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] = 0x1c, - [BQ27XXX_REG_TTECP] = 0x26, - [BQ27XXX_REG_NAC] = 0x0c, - [BQ27XXX_REG_FCC] = 0x12, - [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = 0x22, - [BQ27XXX_REG_SOC] = 0x2c, - [BQ27XXX_REG_DCAP] = 0x3c, - [BQ27XXX_REG_AP] = 0x24, - BQ27XXX_DM_REG_ROWS, - }, - bq27510g2_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] = 0x1c, - [BQ27XXX_REG_TTECP] = 0x26, - [BQ27XXX_REG_NAC] = 0x0c, - [BQ27XXX_REG_FCC] = 0x12, - [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = 0x22, - [BQ27XXX_REG_SOC] = 0x2c, - [BQ27XXX_REG_DCAP] = 0x3c, - [BQ27XXX_REG_AP] = 0x24, - BQ27XXX_DM_REG_ROWS, - }, +#define bq27510g1_regs bq27500_regs +#define bq27510g2_regs bq27500_regs bq27510g3_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, @@ -510,42 +453,9 @@ static enum power_supply_property bq27010_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq2750x_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_TECHNOLOGY, - POWER_SUPPLY_PROP_CHARGE_FULL, - POWER_SUPPLY_PROP_CHARGE_NOW, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, - POWER_SUPPLY_PROP_CYCLE_COUNT, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_MANUFACTURER, -}; - -static enum power_supply_property bq2751x_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_TECHNOLOGY, - POWER_SUPPLY_PROP_CHARGE_FULL, - POWER_SUPPLY_PROP_CHARGE_NOW, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, - POWER_SUPPLY_PROP_CYCLE_COUNT, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_MANUFACTURER, -}; -#define bq2752x_props bq2751x_props +#define bq2750x_props bq27510g3_props +#define bq2751x_props bq27510g3_props +#define bq2752x_props bq27510g3_props static enum power_supply_property bq27500_props[] = { POWER_SUPPLY_PROP_STATUS, @@ -567,48 +477,8 @@ static enum power_supply_property bq27500_props[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_MANUFACTURER, }; - -static enum power_supply_property bq27510g1_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_NOW, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, - POWER_SUPPLY_PROP_CYCLE_COUNT, - POWER_SUPPLY_PROP_ENERGY_NOW, - POWER_SUPPLY_PROP_POWER_AVG, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_MANUFACTURER, -}; - -static enum power_supply_property bq27510g2_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_NOW, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, - POWER_SUPPLY_PROP_CYCLE_COUNT, - POWER_SUPPLY_PROP_ENERGY_NOW, - POWER_SUPPLY_PROP_POWER_AVG, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_MANUFACTURER, -}; +#define bq27510g1_props bq27500_props +#define bq27510g2_props bq27500_props static enum power_supply_property bq27510g3_props[] = { POWER_SUPPLY_PROP_STATUS, @@ -648,26 +518,7 @@ static enum power_supply_property bq27520g1_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27520g2_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_NOW, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, - POWER_SUPPLY_PROP_CYCLE_COUNT, - POWER_SUPPLY_PROP_ENERGY_NOW, - POWER_SUPPLY_PROP_POWER_AVG, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_MANUFACTURER, -}; +#define bq27520g2_props bq27500_props static enum power_supply_property bq27520g3_props[] = { POWER_SUPPLY_PROP_STATUS, -- cgit v1.2.3 From a4c7590b8dc44919574fd316db89423197584350 Mon Sep 17 00:00:00 2001 From: Liam Breck Date: Mon, 28 Aug 2017 14:23:47 -0700 Subject: power: supply: bq24190_charger: Enable devicetree config Add get_config(). Rename set_mode_host() to set_config(). Call get_config() and hw_init() after power_supply_register(). No functional changes. Cc: Hans de Goede Signed-off-by: Liam Breck Acked-by: Tony Lindgren Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 56 ++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 20 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 4cb5741cbb46..6e651fe2743f 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -504,15 +504,7 @@ static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi) static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {} #endif -/* - * According to the "Host Mode and default Mode" section of the - * manual, a write to any register causes the bq24190 to switch - * from default mode to host mode. It will switch back to default - * mode after a WDT timeout unless the WDT is turned off as well. - * So, by simply turning off the WDT, we accomplish both with the - * same write. - */ -static int bq24190_set_mode_host(struct bq24190_dev_info *bdi) +static int bq24190_set_config(struct bq24190_dev_info *bdi) { int ret; u8 v; @@ -523,9 +515,22 @@ static int bq24190_set_mode_host(struct bq24190_dev_info *bdi) bdi->watchdog = ((v & BQ24190_REG_CTTC_WATCHDOG_MASK) >> BQ24190_REG_CTTC_WATCHDOG_SHIFT); + + /* + * According to the "Host Mode and default Mode" section of the + * manual, a write to any register causes the bq24190 to switch + * from default mode to host mode. It will switch back to default + * mode after a WDT timeout unless the WDT is turned off as well. + * So, by simply turning off the WDT, we accomplish both with the + * same write. + */ v &= ~BQ24190_REG_CTTC_WATCHDOG_MASK; - return bq24190_write(bdi, BQ24190_REG_CTTC, v); + ret = bq24190_write(bdi, BQ24190_REG_CTTC, v); + if (ret < 0) + return ret; + + return 0; } static int bq24190_register_reset(struct bq24190_dev_info *bdi) @@ -1495,13 +1500,18 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi) if (ret < 0) return ret; - ret = bq24190_set_mode_host(bdi); + ret = bq24190_set_config(bdi); if (ret < 0) return ret; return bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg); } +static int bq24190_get_config(struct bq24190_dev_info *bdi) +{ + return 0; +} + static int bq24190_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1532,7 +1542,7 @@ static int bq24190_probe(struct i2c_client *client, i2c_set_clientdata(client, bdi); - if (!client->irq) { + if (client->irq <= 0) { dev_err(dev, "Can't get irq info\n"); return -EINVAL; } @@ -1565,12 +1575,6 @@ static int bq24190_probe(struct i2c_client *client, goto out_pmrt; } - ret = bq24190_hw_init(bdi); - if (ret < 0) { - dev_err(dev, "Hardware init failed\n"); - goto out_pmrt; - } - charger_cfg.drv_data = bdi; charger_cfg.supplied_to = bq24190_charger_supplied_to; charger_cfg.num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to), @@ -1595,8 +1599,20 @@ static int bq24190_probe(struct i2c_client *client, } } + ret = bq24190_get_config(bdi); + if (ret < 0) { + dev_err(dev, "Can't get devicetree config\n"); + goto out_charger; + } + + ret = bq24190_hw_init(bdi); + if (ret < 0) { + dev_err(dev, "Hardware init failed\n"); + goto out_charger; + } + ret = bq24190_sysfs_create_group(bdi); - if (ret) { + if (ret < 0) { dev_err(dev, "Can't create sysfs entries\n"); goto out_charger; } @@ -1739,7 +1755,7 @@ static __maybe_unused int bq24190_pm_resume(struct device *dev) } bq24190_register_reset(bdi); - bq24190_set_mode_host(bdi); + bq24190_set_config(bdi); bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg); if (error >= 0) { -- cgit v1.2.3 From 8412a5bea72a787a170d5cc6902d0b8e8514c010 Mon Sep 17 00:00:00 2001 From: Liam Breck Date: Mon, 28 Aug 2017 14:23:48 -0700 Subject: power: supply: bq24190_charger: Add property system-minimum-microvolt Set minimum system voltage limit obtained from device property. Cc: Hans de Goede Acked-by: Tony Lindgren Signed-off-by: Liam Breck Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 6e651fe2743f..a12d263aea8a 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -43,6 +43,8 @@ #define BQ24190_REG_POC_CHG_CONFIG_OTG 0x2 #define BQ24190_REG_POC_SYS_MIN_MASK (BIT(3) | BIT(2) | BIT(1)) #define BQ24190_REG_POC_SYS_MIN_SHIFT 1 +#define BQ24190_REG_POC_SYS_MIN_MIN 3000 +#define BQ24190_REG_POC_SYS_MIN_MAX 3700 #define BQ24190_REG_POC_BOOST_LIM_MASK BIT(0) #define BQ24190_REG_POC_BOOST_LIM_SHIFT 0 @@ -159,6 +161,7 @@ struct bq24190_dev_info { char model_name[I2C_NAME_SIZE]; bool initialized; bool irq_event; + u16 sys_min; struct mutex f_reg_lock; u8 f_reg; u8 ss_reg; @@ -530,6 +533,16 @@ static int bq24190_set_config(struct bq24190_dev_info *bdi) if (ret < 0) return ret; + if (bdi->sys_min) { + v = bdi->sys_min / 100 - 30; // manual section 9.5.1.2, table 9 + ret = bq24190_write_mask(bdi, BQ24190_REG_POC, + BQ24190_REG_POC_SYS_MIN_MASK, + BQ24190_REG_POC_SYS_MIN_SHIFT, + v); + if (ret < 0) + return ret; + } + return 0; } @@ -1509,6 +1522,18 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi) static int bq24190_get_config(struct bq24190_dev_info *bdi) { + const char * const s = "ti,system-minimum-microvolt"; + int v; + + if (device_property_read_u32(bdi->dev, s, &v) == 0) { + v /= 1000; + if (v >= BQ24190_REG_POC_SYS_MIN_MIN + && v <= BQ24190_REG_POC_SYS_MIN_MAX) + bdi->sys_min = v; + else + dev_warn(bdi->dev, "invalid value for %s: %u\n", s, v); + } + return 0; } -- cgit v1.2.3 From 14e1a131b5ebc4ed7d166f08d1a669d4ce6d2760 Mon Sep 17 00:00:00 2001 From: Liam Breck Date: Mon, 28 Aug 2017 14:23:49 -0700 Subject: power: supply: bq24190_charger: Add power_supply_battery_info support Set pre-charge and charge-term current, obtained from power_supply_battery_info. Add sysfs attributes precharge_current & charge_term_current. Cc: Hans de Goede Acked-by: Tony Lindgren Signed-off-by: Liam Breck Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 87 ++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index a12d263aea8a..fa711c106b63 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -59,9 +59,13 @@ #define BQ24190_REG_PCTCC_IPRECHG_MASK (BIT(7) | BIT(6) | BIT(5) | \ BIT(4)) #define BQ24190_REG_PCTCC_IPRECHG_SHIFT 4 +#define BQ24190_REG_PCTCC_IPRECHG_MIN 128 +#define BQ24190_REG_PCTCC_IPRECHG_MAX 2048 #define BQ24190_REG_PCTCC_ITERM_MASK (BIT(3) | BIT(2) | BIT(1) | \ BIT(0)) #define BQ24190_REG_PCTCC_ITERM_SHIFT 0 +#define BQ24190_REG_PCTCC_ITERM_MIN 128 +#define BQ24190_REG_PCTCC_ITERM_MAX 2048 #define BQ24190_REG_CVC 0x04 /* Charge Voltage Control */ #define BQ24190_REG_CVC_VREG_MASK (BIT(7) | BIT(6) | BIT(5) | \ @@ -162,6 +166,8 @@ struct bq24190_dev_info { bool initialized; bool irq_event; u16 sys_min; + u16 iprechg; + u16 iterm; struct mutex f_reg_lock; u8 f_reg; u8 ss_reg; @@ -543,6 +549,26 @@ static int bq24190_set_config(struct bq24190_dev_info *bdi) return ret; } + if (bdi->iprechg) { + v = bdi->iprechg / 128 - 1; // manual section 9.5.1.4, table 11 + ret = bq24190_write_mask(bdi, BQ24190_REG_PCTCC, + BQ24190_REG_PCTCC_IPRECHG_MASK, + BQ24190_REG_PCTCC_IPRECHG_SHIFT, + v); + if (ret < 0) + return ret; + } + + if (bdi->iterm) { + v = bdi->iterm / 128 - 1; // manual section 9.5.1.4, table 11 + ret = bq24190_write_mask(bdi, BQ24190_REG_PCTCC, + BQ24190_REG_PCTCC_ITERM_MASK, + BQ24190_REG_PCTCC_ITERM_SHIFT, + v); + if (ret < 0) + return ret; + } + return 0; } @@ -791,6 +817,38 @@ static int bq24190_charger_set_temp_alert_max(struct bq24190_dev_info *bdi, return bq24190_battery_set_temp_alert_max(bdi, val); } +static int bq24190_charger_get_precharge(struct bq24190_dev_info *bdi, + union power_supply_propval *val) +{ + u8 v; + int ret; + + ret = bq24190_read_mask(bdi, BQ24190_REG_PCTCC, + BQ24190_REG_PCTCC_IPRECHG_MASK, + BQ24190_REG_PCTCC_IPRECHG_SHIFT, &v); + if (ret < 0) + return ret; + + val->intval = ++v * 128 * 1000; + return 0; +} + +static int bq24190_charger_get_charge_term(struct bq24190_dev_info *bdi, + union power_supply_propval *val) +{ + u8 v; + int ret; + + ret = bq24190_read_mask(bdi, BQ24190_REG_PCTCC, + BQ24190_REG_PCTCC_ITERM_MASK, + BQ24190_REG_PCTCC_ITERM_SHIFT, &v); + if (ret < 0) + return ret; + + val->intval = ++v * 128 * 1000; + return 0; +} + static int bq24190_charger_get_current(struct bq24190_dev_info *bdi, union power_supply_propval *val) { @@ -938,6 +996,12 @@ static int bq24190_charger_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: ret = bq24190_charger_get_temp_alert_max(bdi, val); break; + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + ret = bq24190_charger_get_precharge(bdi, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + ret = bq24190_charger_get_charge_term(bdi, val); + break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: ret = bq24190_charger_get_current(bdi, val); break; @@ -1044,6 +1108,8 @@ static enum power_supply_property bq24190_charger_properties[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_TEMP_ALERT_MAX, + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, @@ -1523,6 +1589,7 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi) static int bq24190_get_config(struct bq24190_dev_info *bdi) { const char * const s = "ti,system-minimum-microvolt"; + struct power_supply_battery_info info = {}; int v; if (device_property_read_u32(bdi->dev, s, &v) == 0) { @@ -1534,6 +1601,25 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi) dev_warn(bdi->dev, "invalid value for %s: %u\n", s, v); } + if (bdi->dev->of_node && + !power_supply_get_battery_info(bdi->charger, &info)) { + v = info.precharge_current_ua / 1000; + if (v >= BQ24190_REG_PCTCC_IPRECHG_MIN + && v <= BQ24190_REG_PCTCC_IPRECHG_MAX) + bdi->iprechg = v; + else + dev_warn(bdi->dev, "invalid value for battery:precharge-current-microamp: %d\n", + v); + + v = info.charge_term_current_ua / 1000; + if (v >= BQ24190_REG_PCTCC_ITERM_MIN + && v <= BQ24190_REG_PCTCC_ITERM_MAX) + bdi->iterm = v; + else + dev_warn(bdi->dev, "invalid value for battery:charge-term-current-microamp: %d\n", + v); + } + return 0; } @@ -1601,6 +1687,7 @@ static int bq24190_probe(struct i2c_client *client, } charger_cfg.drv_data = bdi; + charger_cfg.of_node = dev->of_node; charger_cfg.supplied_to = bq24190_charger_supplied_to; charger_cfg.num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to), bdi->charger = power_supply_register(dev, &bq24190_charger_desc, -- cgit v1.2.3 From 66b6bef2c4e06f8c7a0030445766bf868110c5a1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 30 Aug 2017 11:48:11 +0200 Subject: power: supply: bq24190_charger: Export 5V boost converter as regulator Register the 5V boost converter as a regulator named "usb_otg_vbus". This commit also adds support for bq24190_platform_data, through which non device-tree platforms can pass the regulator_init_data (containing mappings for the consumer amongst other things). Signed-off-by: Hans de Goede Acked-by: Tony Lindgren Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 112 +++++++++++++++++++++++++++++++++ include/linux/power/bq24190_charger.h | 18 ++++++ 2 files changed, 130 insertions(+) create mode 100644 include/linux/power/bq24190_charger.h (limited to 'drivers/power') diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index fa711c106b63..e606a078b0dd 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -513,6 +516,111 @@ static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi) static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {} #endif +#ifdef CONFIG_REGULATOR +static int bq24190_set_charge_mode(struct regulator_dev *dev, u8 val) +{ + struct bq24190_dev_info *bdi = rdev_get_drvdata(dev); + int ret; + + ret = pm_runtime_get_sync(bdi->dev); + if (ret < 0) { + dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", ret); + pm_runtime_put_noidle(bdi->dev); + return ret; + } + + ret = bq24190_write_mask(bdi, BQ24190_REG_POC, + BQ24190_REG_POC_CHG_CONFIG_MASK, + BQ24190_REG_POC_CHG_CONFIG_SHIFT, val); + + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); + + return ret; +} + +static int bq24190_vbus_enable(struct regulator_dev *dev) +{ + return bq24190_set_charge_mode(dev, BQ24190_REG_POC_CHG_CONFIG_OTG); +} + +static int bq24190_vbus_disable(struct regulator_dev *dev) +{ + return bq24190_set_charge_mode(dev, BQ24190_REG_POC_CHG_CONFIG_CHARGE); +} + +static int bq24190_vbus_is_enabled(struct regulator_dev *dev) +{ + struct bq24190_dev_info *bdi = rdev_get_drvdata(dev); + int ret; + u8 val; + + ret = pm_runtime_get_sync(bdi->dev); + if (ret < 0) { + dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", ret); + pm_runtime_put_noidle(bdi->dev); + return ret; + } + + ret = bq24190_read_mask(bdi, BQ24190_REG_POC, + BQ24190_REG_POC_CHG_CONFIG_MASK, + BQ24190_REG_POC_CHG_CONFIG_SHIFT, &val); + + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); + + return ret ? ret : val == BQ24190_REG_POC_CHG_CONFIG_OTG; +} + +static const struct regulator_ops bq24190_vbus_ops = { + .enable = bq24190_vbus_enable, + .disable = bq24190_vbus_disable, + .is_enabled = bq24190_vbus_is_enabled, +}; + +static const struct regulator_desc bq24190_vbus_desc = { + .name = "usb_otg_vbus", + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &bq24190_vbus_ops, + .fixed_uV = 5000000, + .n_voltages = 1, +}; + +static const struct regulator_init_data bq24190_vbus_init_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, +}; + +static int bq24190_register_vbus_regulator(struct bq24190_dev_info *bdi) +{ + struct bq24190_platform_data *pdata = bdi->dev->platform_data; + struct regulator_config cfg = { }; + struct regulator_dev *reg; + int ret = 0; + + cfg.dev = bdi->dev; + if (pdata && pdata->regulator_init_data) + cfg.init_data = pdata->regulator_init_data; + else + cfg.init_data = &bq24190_vbus_init_data; + cfg.driver_data = bdi; + reg = devm_regulator_register(bdi->dev, &bq24190_vbus_desc, &cfg); + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + dev_err(bdi->dev, "Can't register regulator: %d\n", ret); + } + + return ret; +} +#else +static int bq24190_register_vbus_regulator(struct bq24190_dev_info *bdi) +{ + return 0; +} +#endif + static int bq24190_set_config(struct bq24190_dev_info *bdi) { int ret; @@ -1740,6 +1848,10 @@ static int bq24190_probe(struct i2c_client *client, goto out_sysfs; } + ret = bq24190_register_vbus_regulator(bdi); + if (ret < 0) + goto out_sysfs; + if (bdi->extcon) { INIT_DELAYED_WORK(&bdi->extcon_work, bq24190_extcon_work); bdi->extcon_nb.notifier_call = bq24190_extcon_event; diff --git a/include/linux/power/bq24190_charger.h b/include/linux/power/bq24190_charger.h new file mode 100644 index 000000000000..45ce7f116a91 --- /dev/null +++ b/include/linux/power/bq24190_charger.h @@ -0,0 +1,18 @@ +/* + * Platform data for the TI bq24190 battery charger driver. + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _BQ24190_CHARGER_H_ +#define _BQ24190_CHARGER_H_ + +#include + +struct bq24190_platform_data { + const struct regulator_init_data *regulator_init_data; +}; + +#endif -- cgit v1.2.3 From 18f8e6f695ac6ea879f610702d9bb04a42d1793c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 30 Aug 2017 11:48:12 +0200 Subject: power: supply: bq24190_charger: Get input_current_limit from our supplier On some devices the USB Type-C port power (USB PD 2.0) negotiation is done by a separate port-controller IC, while the current limit is controlled through another (charger) IC. It has been decided to model this by modelling the external Type-C power brick (adapter/charger) as a power-supply class device which supplies the charger-IC, with its voltage-now and current-max representing the negotiated voltage and max current draw. This commit adds support for this to the bq24190_charger driver by adding an external_power_changed callback and calling power_supply_set_input_current_limit_from_supplier from this callback. This callback will only get called if the bq24190 has a parent-supply. Note this replaces the functionality to get the current-limit from an extcon device, which will be removed in a follow-up commit. Signed-off-by: Hans de Goede Tony Lindgren Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index e606a078b0dd..35ff406aca48 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -165,6 +165,7 @@ struct bq24190_dev_info { struct extcon_dev *extcon; struct notifier_block extcon_nb; struct delayed_work extcon_work; + struct delayed_work input_current_limit_work; char model_name[I2C_NAME_SIZE]; bool initialized; bool irq_event; @@ -1210,6 +1211,32 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy, return ret; } +static void bq24190_input_current_limit_work(struct work_struct *work) +{ + struct bq24190_dev_info *bdi = + container_of(work, struct bq24190_dev_info, + input_current_limit_work.work); + + power_supply_set_input_current_limit_from_supplier(bdi->charger); +} + +/* Sync the input-current-limit with our parent supply (if we have one) */ +static void bq24190_charger_external_power_changed(struct power_supply *psy) +{ + struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); + + /* + * The Power-Good detection may take up to 220ms, sometimes + * the external charger detection is quicker, and the bq24190 will + * reset to iinlim based on its own charger detection (which is not + * hooked up when using external charger detection) resulting in a + * too low default 500mA iinlim. Delay setting the input-current-limit + * for 300ms to avoid this. + */ + queue_delayed_work(system_wq, &bdi->input_current_limit_work, + msecs_to_jiffies(300)); +} + static enum power_supply_property bq24190_charger_properties[] = { POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_HEALTH, @@ -1240,6 +1267,7 @@ static const struct power_supply_desc bq24190_charger_desc = { .get_property = bq24190_charger_get_property, .set_property = bq24190_charger_set_property, .property_is_writeable = bq24190_charger_property_is_writeable, + .external_power_changed = bq24190_charger_external_power_changed, }; /* Battery power supply property routines */ @@ -1758,6 +1786,8 @@ static int bq24190_probe(struct i2c_client *client, mutex_init(&bdi->f_reg_lock); bdi->f_reg = 0; bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */ + INIT_DELAYED_WORK(&bdi->input_current_limit_work, + bq24190_input_current_limit_work); i2c_set_clientdata(client, bdi); -- cgit v1.2.3 From 5d01fd38a3b01ca2112a689d70f7ecec40d952ee Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Thu, 31 Aug 2017 08:59:50 +0200 Subject: power: supply: bq27xxx: enable writing capacity values for bq27421 Tested on Pyra prototype with bq27421. Signed-off-by: H. Nikolaus Schaller Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 527dc2558fd2..51f0961ecf3e 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -688,15 +688,11 @@ static struct bq27xxx_dm_reg bq27545_dm_regs[] = { #define bq27545_dm_regs 0 #endif -#if 0 /* not yet tested */ static struct bq27xxx_dm_reg bq27421_dm_regs[] = { [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 8000 }, [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500, 3700 }, }; -#else -#define bq27421_dm_regs 0 -#endif static struct bq27xxx_dm_reg bq27425_dm_regs[] = { [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 12, 2, 0, 32767 }, -- cgit v1.2.3