diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-08 09:24:00 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-08 09:24:00 -0800 |
commit | 1cabd3e0bd88d7ba9854cbb9213ef40eccad603b (patch) | |
tree | 8890e9a901073608cf4cd00334d72b8b70e98057 /drivers | |
parent | 7427e28688ed48b0a9484c4035f86e836d9787a2 (diff) | |
parent | 655ab0bc462d1ae2aa344b1ecf35ca1a3ed726dc (diff) |
Merge tag 'for-v5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply
Pull power supply and reset updates from Sebastian Reichel:
"Nothing too fancy in the power-supply subsystem this time. There are
less patches than usual, since I did not have enough time to review
them in time. The good news is, that all patches have been in
linux-next for more than two weeks and there are no complicated
cross-subsystem patchsets this time!
Summary:
- at91-reset: add sam9x60 support
- sc27xx: improve capacity logic
- goldfish_battery: enhance driver by adding many new properties
- isp1704: drop platform data and migrate to gpiod
- misc small fixes and improvements"
* tag 'for-v5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (25 commits)
power: reset: at91-reset: add support for sam9x60 SoC
dt-bindings: arm: atmel: add new sam9x60 reset controller binding
dt-bindings: arm: atmel: add missing samx7 to reset controller
max17042_battery: fix potential use-after-free on device remove
power: supply: core: Add a field to support battery max voltage
dt-bindings: power: supply: Add voltage-max-design-microvolt property
bq27x00: use cached flags
power: supply: ds2782: fix possible use-after-free on remove
power: supply: bq25890: show max charge current/voltage as configured
power: supply: sc27xx: Fix capacity saving function
power: supply: sc27xx: Fix the incorrect formula when converting capacity to coulomb counter
power: supply: sc27xx: Add one property to read charge voltage
dt-bindings: power: sc27xx: Add one IIO channel to read charge voltage
drivers: power: supply: goldfish_battery: Add support for reading more properties
power: supply: charger-manager: Fix trivial language typos
cpcap-charger: generate events for userspace
power: supply: remove some duplicated includes
power: twl4030: fix a missing check of return value
drivers: power: supply: goldfish_battery: Use tabs for alignment
drivers: power: supply: goldfish_battery: Fix alignment
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/reset/at91-reset.c | 13 | ||||
-rw-r--r-- | drivers/power/supply/axp288_fuel_gauge.c | 14 | ||||
-rw-r--r-- | drivers/power/supply/bq25890_charger.c | 4 | ||||
-rw-r--r-- | drivers/power/supply/bq27xxx_battery.c | 20 | ||||
-rw-r--r-- | drivers/power/supply/charger-manager.c | 18 | ||||
-rw-r--r-- | drivers/power/supply/cpcap-charger.c | 1 | ||||
-rw-r--r-- | drivers/power/supply/ds2782_battery.c | 8 | ||||
-rw-r--r-- | drivers/power/supply/goldfish_battery.c | 88 | ||||
-rw-r--r-- | drivers/power/supply/isp1704_charger.c | 60 | ||||
-rw-r--r-- | drivers/power/supply/max17042_battery.c | 10 | ||||
-rw-r--r-- | drivers/power/supply/power_supply_core.c | 5 | ||||
-rw-r--r-- | drivers/power/supply/sc27xx_fuel_gauge.c | 95 | ||||
-rw-r--r-- | drivers/power/supply/twl4030_charger.c | 4 |
13 files changed, 212 insertions, 128 deletions
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index f44a9ffcc2ab..44ca983a49a1 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -44,6 +44,9 @@ enum reset_type { RESET_TYPE_WATCHDOG = 2, RESET_TYPE_SOFTWARE = 3, RESET_TYPE_USER = 4, + RESET_TYPE_CPU_FAIL = 6, + RESET_TYPE_XTAL_FAIL = 7, + RESET_TYPE_ULP2 = 8, }; static void __iomem *at91_ramc_base[2], *at91_rstc_base; @@ -164,6 +167,15 @@ static void __init at91_reset_status(struct platform_device *pdev) case RESET_TYPE_USER: reason = "user reset"; break; + case RESET_TYPE_CPU_FAIL: + reason = "CPU clock failure detection"; + break; + case RESET_TYPE_XTAL_FAIL: + reason = "32.768 kHz crystal failure detection"; + break; + case RESET_TYPE_ULP2: + reason = "ULP2 reset"; + break; default: reason = "unknown reset"; break; @@ -183,6 +195,7 @@ static const struct of_device_id at91_reset_of_match[] = { { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart }, { .compatible = "atmel,samx7-rstc", .data = samx7_restart }, + { .compatible = "microchip,sam9x60-rstc", .data = samx7_restart }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, at91_reset_of_match); diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 084c8ba9749d..9ff2461820d8 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -307,22 +307,12 @@ static int fuel_gauge_debug_show(struct seq_file *s, void *data) return 0; } -static int debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, fuel_gauge_debug_show, inode->i_private); -} - -static const struct file_operations fg_debug_fops = { - .open = debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(fuel_gauge_debug); static void fuel_gauge_create_debugfs(struct axp288_fg_info *info) { info->debug_file = debugfs_create_file("fuelgauge", 0666, NULL, - info, &fg_debug_fops); + info, &fuel_gauge_debug_fops); } static void fuel_gauge_remove_debugfs(struct axp288_fg_info *info) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 3f6fb49c956c..66991e6f75d9 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -436,7 +436,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: - val->intval = bq25890_tables[TBL_ICHG].rt.max; + val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: @@ -454,7 +454,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: - val->intval = bq25890_tables[TBL_VREG].rt.max; + val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); break; case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 6dbbe95844a3..29b3a4056865 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1555,27 +1555,14 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF); } -/* - * Read flag register. - * Return < 0 if something fails. - */ static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) { - int flags; - bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; - - flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); - if (flags < 0) { - dev_err(di->dev, "error reading flag register:%d\n", flags); - return flags; - } - /* Unlikely but important to return first */ - if (unlikely(bq27xxx_battery_overtemp(di, flags))) + if (unlikely(bq27xxx_battery_overtemp(di, di->cache.flags))) return POWER_SUPPLY_HEALTH_OVERHEAT; - if (unlikely(bq27xxx_battery_undertemp(di, flags))) + if (unlikely(bq27xxx_battery_undertemp(di, di->cache.flags))) return POWER_SUPPLY_HEALTH_COLD; - if (unlikely(bq27xxx_battery_dead(di, flags))) + if (unlikely(bq27xxx_battery_dead(di, di->cache.flags))) return POWER_SUPPLY_HEALTH_DEAD; return POWER_SUPPLY_HEALTH_GOOD; @@ -1612,6 +1599,7 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di) cache.capacity = bq27xxx_battery_read_soc(di); if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) cache.energy = bq27xxx_battery_read_energy(di); + di->cache.flags = cache.flags; cache.health = bq27xxx_battery_read_health(di); } if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index 38be91f21cc4..2e8db5e6de0b 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -4,7 +4,7 @@ * * This driver enables to monitor battery health and control charger * during suspend-to-mem. - * Charger manager depends on other devices. register this later than + * Charger manager depends on other devices. Register this later than * the depending devices. * * This program is free software; you can redistribute it and/or modify @@ -29,7 +29,7 @@ #include <linux/thermal.h> /* - * Default termperature threshold for charging. + * Default temperature threshold for charging. * Every temperature units are in tenth of centigrade. */ #define CM_DEFAULT_RECHARGE_TEMP_DIFF 50 @@ -356,7 +356,7 @@ static bool is_polling_required(struct charger_manager *cm) * Note that Charger Manager keeps the charger enabled regardless whether * the charger is charging or not (because battery is full or no external * power source exists) except when CM needs to disable chargers forcibly - * bacause of emergency causes; when the battery is overheated or too cold. + * because of emergency causes; when the battery is overheated or too cold. */ static int try_charger_enable(struct charger_manager *cm, bool enable) { @@ -643,7 +643,7 @@ static int cm_check_thermal_status(struct charger_manager *cm) if (ret) { /* FIXME: * No information of battery temperature might - * occur hazadous result. We have to handle it + * occur hazardous result. We have to handle it * depending on battery type. */ dev_err(cm->dev, "Failed to get battery temperature\n"); @@ -693,7 +693,7 @@ static bool _cm_monitor(struct charger_manager *cm) uevent_notify(cm, default_event_names[temp_alrt]); /* - * Check whole charging duration and discharing duration + * Check whole charging duration and discharging duration * after full-batt. */ } else if (!cm->emergency_stop && check_charging_duration(cm)) { @@ -866,7 +866,7 @@ static void battout_handler(struct charger_manager *cm) } /** - * misc_event_handler - Handler for other evnets + * misc_event_handler - Handler for other events * @cm: the Charger Manager representing the battery. * @type: the Charger Manager representing the battery. */ @@ -1218,7 +1218,7 @@ static int charger_extcon_init(struct charger_manager *cm, } /** - * charger_manager_register_extcon - Register extcon device to recevie state + * charger_manager_register_extcon - Register extcon device to receive state * of charger cable. * @cm: the Charger Manager representing the battery. * @@ -1538,7 +1538,7 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev) of_property_read_u32(np, "cm-discharging-max", &desc->discharging_max_duration_ms); - /* battery charger regualtors */ + /* battery charger regulators */ desc->num_charger_regulators = of_get_child_count(np); if (desc->num_charger_regulators) { struct charger_regulator *chg_regs; @@ -1801,7 +1801,7 @@ static int charger_manager_probe(struct platform_device *pdev) /* * Charger-manager have to check the charging state right after - * tialization of charger-manager and then update current charging + * initialization of charger-manager and then update current charging * state. */ cm_monitor(); diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index c843eaff8ad0..c3ed7b476676 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -458,6 +458,7 @@ static void cpcap_usb_detect(struct work_struct *work) goto out_err; } + power_supply_changed(ddata->usb); return; out_err: diff --git a/drivers/power/supply/ds2782_battery.c b/drivers/power/supply/ds2782_battery.c index 019c58493e3d..04b0fe7d7d62 100644 --- a/drivers/power/supply/ds2782_battery.c +++ b/drivers/power/supply/ds2782_battery.c @@ -319,17 +319,17 @@ static void ds278x_power_supply_init(struct power_supply_desc *battery) static int ds278x_battery_remove(struct i2c_client *client) { struct ds278x_info *info = i2c_get_clientdata(client); + int id = info->id; power_supply_unregister(info->battery); + cancel_delayed_work_sync(&info->bat_work); kfree(info->battery_desc.name); + kfree(info); mutex_lock(&battery_lock); - idr_remove(&battery_id, info->id); + idr_remove(&battery_id, id); mutex_unlock(&battery_lock); - cancel_delayed_work(&info->bat_work); - - kfree(info); return 0; } diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c index f5c525e4482a..ad969d9fc981 100644 --- a/drivers/power/supply/goldfish_battery.c +++ b/drivers/power/supply/goldfish_battery.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL /* * Power supply driver for the goldfish emulator * @@ -5,15 +6,6 @@ * Copyright (C) 2012 Intel, Inc. * Copyright (C) 2013 Intel, Inc. * Author: Mike Lockwood <lockwood@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> @@ -40,27 +32,30 @@ struct goldfish_battery_data { #define GOLDFISH_BATTERY_WRITE(data, addr, x) \ (writel(x, data->reg_base + addr)) -/* - * Temporary variable used between goldfish_battery_probe() and - * goldfish_battery_open(). - */ -static struct goldfish_battery_data *battery_data; - enum { /* status register */ - BATTERY_INT_STATUS = 0x00, + BATTERY_INT_STATUS = 0x00, /* set this to enable IRQ */ - BATTERY_INT_ENABLE = 0x04, - - BATTERY_AC_ONLINE = 0x08, - BATTERY_STATUS = 0x0C, - BATTERY_HEALTH = 0x10, - BATTERY_PRESENT = 0x14, - BATTERY_CAPACITY = 0x18, + BATTERY_INT_ENABLE = 0x04, + + BATTERY_AC_ONLINE = 0x08, + BATTERY_STATUS = 0x0C, + BATTERY_HEALTH = 0x10, + BATTERY_PRESENT = 0x14, + BATTERY_CAPACITY = 0x18, + BATTERY_VOLTAGE = 0x1C, + BATTERY_TEMP = 0x20, + BATTERY_CHARGE_COUNTER = 0x24, + BATTERY_VOLTAGE_MAX = 0x28, + BATTERY_CURRENT_MAX = 0x2C, + BATTERY_CURRENT_NOW = 0x30, + BATTERY_CURRENT_AVG = 0x34, + BATTERY_CHARGE_FULL_UAH = 0x38, + BATTERY_CYCLE_COUNT = 0x40, BATTERY_STATUS_CHANGED = 1U << 0, AC_STATUS_CHANGED = 1U << 1, - BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED, + BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED, }; @@ -75,6 +70,12 @@ static int goldfish_ac_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_ONLINE: val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE); break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_VOLTAGE_MAX); + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_MAX); + break; default: ret = -EINVAL; break; @@ -105,6 +106,29 @@ static int goldfish_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY); break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_VOLTAGE); + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_TEMP); + break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + val->intval = GOLDFISH_BATTERY_READ(data, + BATTERY_CHARGE_COUNTER); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_NOW); + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_AVG); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + val->intval = GOLDFISH_BATTERY_READ(data, + BATTERY_CHARGE_FULL_UAH); + break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CYCLE_COUNT); + break; default: ret = -EINVAL; break; @@ -119,10 +143,19 @@ static enum power_supply_property goldfish_battery_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CYCLE_COUNT, }; static enum power_supply_property goldfish_ac_props[] = { POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_CURRENT_MAX, }; static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id) @@ -193,8 +226,9 @@ static int goldfish_battery_probe(struct platform_device *pdev) return -ENODEV; } - ret = devm_request_irq(&pdev->dev, data->irq, goldfish_battery_interrupt, - IRQF_SHARED, pdev->name, data); + ret = devm_request_irq(&pdev->dev, data->irq, + goldfish_battery_interrupt, + IRQF_SHARED, pdev->name, data); if (ret) return ret; @@ -212,7 +246,6 @@ static int goldfish_battery_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, data); - battery_data = data; GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); return 0; @@ -224,7 +257,6 @@ static int goldfish_battery_remove(struct platform_device *pdev) power_supply_unregister(data->battery); power_supply_unregister(data->ac); - battery_data = NULL; return 0; } diff --git a/drivers/power/supply/isp1704_charger.c b/drivers/power/supply/isp1704_charger.c index 95af5f305838..a63cb5dcfa08 100644 --- a/drivers/power/supply/isp1704_charger.c +++ b/drivers/power/supply/isp1704_charger.c @@ -30,13 +30,12 @@ #include <linux/power_supply.h> #include <linux/delay.h> #include <linux/of.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/usb/otg.h> #include <linux/usb/ulpi.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> -#include <linux/power/isp1704_charger.h> /* Vendor specific Power Control register */ #define ISP1704_PWR_CTRL 0x3d @@ -60,6 +59,7 @@ struct isp1704_charger { struct device *dev; struct power_supply *psy; struct power_supply_desc psy_desc; + struct gpio_desc *enable_gpio; struct usb_phy *phy; struct notifier_block nb; struct work_struct work; @@ -81,18 +81,9 @@ static inline int isp1704_write(struct isp1704_charger *isp, u32 reg, u32 val) return usb_phy_io_write(isp->phy, val, reg); } -/* - * Disable/enable the power from the isp1704 if a function for it - * has been provided with platform data. - */ static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on) { - struct isp1704_charger_data *board = isp->dev->platform_data; - - if (board && board->set_power) - board->set_power(on); - else if (board) - gpio_set_value(board->enable_gpio, on); + gpiod_set_value(isp->enable_gpio, on); } /* @@ -405,46 +396,19 @@ static int isp1704_charger_probe(struct platform_device *pdev) int ret = -ENODEV; struct power_supply_config psy_cfg = {}; - struct isp1704_charger_data *pdata = dev_get_platdata(&pdev->dev); - struct device_node *np = pdev->dev.of_node; - - if (np) { - int gpio = of_get_named_gpio(np, "nxp,enable-gpio", 0); - - if (gpio < 0) { - dev_err(&pdev->dev, "missing DT GPIO nxp,enable-gpio\n"); - return gpio; - } - - pdata = devm_kzalloc(&pdev->dev, - sizeof(struct isp1704_charger_data), GFP_KERNEL); - if (!pdata) { - ret = -ENOMEM; - goto fail0; - } - pdata->enable_gpio = gpio; - - dev_info(&pdev->dev, "init gpio %d\n", pdata->enable_gpio); - - ret = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio, - GPIOF_OUT_INIT_HIGH, "isp1704_reset"); - if (ret) { - dev_err(&pdev->dev, "gpio request failed\n"); - goto fail0; - } - } - - if (!pdata) { - dev_err(&pdev->dev, "missing platform data!\n"); - return -ENODEV; - } - - isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); if (!isp) return -ENOMEM; - if (np) + isp->enable_gpio = devm_gpiod_get(&pdev->dev, "nxp,enable", + GPIOD_OUT_HIGH); + if (IS_ERR(isp->enable_gpio)) { + ret = PTR_ERR(isp->enable_gpio); + dev_err(&pdev->dev, "Could not get reset gpio: %d\n", ret); + return ret; + } + + if (pdev->dev.of_node) isp->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); else isp->phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index 2a8d75e5e930..581c6bd23388 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -995,6 +995,13 @@ static const struct power_supply_desc max17042_no_current_sense_psy_desc = { .num_properties = ARRAY_SIZE(max17042_battery_props) - 2, }; +static void max17042_stop_work(void *data) +{ + struct max17042_chip *chip = data; + + cancel_work_sync(&chip->work); +} + static int max17042_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1101,6 +1108,9 @@ static int max17042_probe(struct i2c_client *client, regmap_read(chip->regmap, MAX17042_STATUS, &val); if (val & STATUS_POR_BIT) { INIT_WORK(&chip->work, max17042_init_worker); + ret = devm_add_action(&client->dev, max17042_stop_work, chip); + if (ret) + return ret; schedule_work(&chip->work); } else { chip->init_complete = 1; diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 569790ea6917..c917a8b43b2b 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -156,8 +156,6 @@ static void power_supply_deferred_register_work(struct work_struct *work) } #ifdef CONFIG_OF -#include <linux/of.h> - static int __power_supply_populate_supplied_from(struct device *dev, void *data) { @@ -575,6 +573,7 @@ int power_supply_get_battery_info(struct power_supply *psy, info->energy_full_design_uwh = -EINVAL; info->charge_full_design_uah = -EINVAL; info->voltage_min_design_uv = -EINVAL; + info->voltage_max_design_uv = -EINVAL; info->precharge_current_ua = -EINVAL; info->charge_term_current_ua = -EINVAL; info->constant_charge_current_max_ua = -EINVAL; @@ -615,6 +614,8 @@ int power_supply_get_battery_info(struct power_supply *psy, &info->charge_full_design_uah); of_property_read_u32(battery_np, "voltage-min-design-microvolt", &info->voltage_min_design_uv); + of_property_read_u32(battery_np, "voltage-max-design-microvolt", + &info->voltage_max_design_uv); of_property_read_u32(battery_np, "precharge-current-microamp", &info->precharge_current_ua); of_property_read_u32(battery_np, "charge-term-current-microamp", diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 76da1895b782..24895cc3b41e 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -72,6 +72,7 @@ * @lock: protect the structure * @gpiod: GPIO for battery detection * @channel: IIO channel to get battery temperature + * @charge_chan: IIO channel to get charge voltage * @internal_resist: the battery internal resistance in mOhm * @total_cap: the total capacity of the battery in mAh * @init_cap: the initial capacity of the battery in mAh @@ -92,6 +93,7 @@ struct sc27xx_fgu_data { struct mutex lock; struct gpio_desc *gpiod; struct iio_channel *channel; + struct iio_channel *charge_chan; bool bat_present; int internal_resist; int total_cap; @@ -169,10 +171,37 @@ static int sc27xx_fgu_save_boot_mode(struct sc27xx_fgu_data *data, if (ret) return ret; + /* + * Since the user area registers are put on power always-on region, + * then these registers changing time will be a little long. Thus + * here we should delay 200us to wait until values are updated + * successfully according to the datasheet. + */ + udelay(200); + + ret = regmap_update_bits(data->regmap, + data->base + SC27XX_FGU_USER_AREA_SET, + SC27XX_FGU_MODE_AREA_MASK, + boot_mode << SC27XX_FGU_MODE_AREA_SHIFT); + if (ret) + return ret; + + /* + * Since the user area registers are put on power always-on region, + * then these registers changing time will be a little long. Thus + * here we should delay 200us to wait until values are updated + * successfully according to the datasheet. + */ + udelay(200); + + /* + * According to the datasheet, we should set the USER_AREA_CLEAR to 0 to + * make the user area data available, otherwise we can not save the user + * area data. + */ return regmap_update_bits(data->regmap, - data->base + SC27XX_FGU_USER_AREA_SET, - SC27XX_FGU_MODE_AREA_MASK, - boot_mode << SC27XX_FGU_MODE_AREA_SHIFT); + data->base + SC27XX_FGU_USER_AREA_CLEAR, + SC27XX_FGU_MODE_AREA_MASK, 0); } static int sc27xx_fgu_save_last_cap(struct sc27xx_fgu_data *data, int cap) @@ -186,9 +215,36 @@ static int sc27xx_fgu_save_last_cap(struct sc27xx_fgu_data *data, int cap) if (ret) return ret; + /* + * Since the user area registers are put on power always-on region, + * then these registers changing time will be a little long. Thus + * here we should delay 200us to wait until values are updated + * successfully according to the datasheet. + */ + udelay(200); + + ret = regmap_update_bits(data->regmap, + data->base + SC27XX_FGU_USER_AREA_SET, + SC27XX_FGU_CAP_AREA_MASK, cap); + if (ret) + return ret; + + /* + * Since the user area registers are put on power always-on region, + * then these registers changing time will be a little long. Thus + * here we should delay 200us to wait until values are updated + * successfully according to the datasheet. + */ + udelay(200); + + /* + * According to the datasheet, we should set the USER_AREA_CLEAR to 0 to + * make the user area data available, otherwise we can not save the user + * area data. + */ return regmap_update_bits(data->regmap, - data->base + SC27XX_FGU_USER_AREA_SET, - SC27XX_FGU_CAP_AREA_MASK, cap); + data->base + SC27XX_FGU_USER_AREA_CLEAR, + SC27XX_FGU_CAP_AREA_MASK, 0); } static int sc27xx_fgu_read_last_cap(struct sc27xx_fgu_data *data, int *cap) @@ -391,6 +447,18 @@ static int sc27xx_fgu_get_vbat_ocv(struct sc27xx_fgu_data *data, int *val) return 0; } +static int sc27xx_fgu_get_charge_vol(struct sc27xx_fgu_data *data, int *val) +{ + int ret, vol; + + ret = iio_read_channel_processed(data->charge_chan, &vol); + if (ret < 0) + return ret; + + *val = vol * 1000; + return 0; +} + static int sc27xx_fgu_get_temp(struct sc27xx_fgu_data *data, int *temp) { return iio_read_channel_processed(data->channel, temp); @@ -502,6 +570,14 @@ static int sc27xx_fgu_get_property(struct power_supply *psy, val->intval = value; break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = sc27xx_fgu_get_charge_vol(data, &value); + if (ret) + goto error; + + val->intval = value; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_CURRENT_AVG: ret = sc27xx_fgu_get_current(data, &value); @@ -567,6 +643,7 @@ static enum power_supply_property sc27xx_fgu_props[] = { POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, }; static const struct power_supply_desc sc27xx_fgu_desc = { @@ -708,7 +785,7 @@ static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity) * Convert current capacity (mAh) to coulomb counter according to the * formula: 1 mAh =3.6 coulomb. */ - return DIV_ROUND_CLOSEST(cur_cap * 36, 10); + return DIV_ROUND_CLOSEST(cur_cap * 36 * data->cur_1000ma_adc, 10); } static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data) @@ -907,6 +984,12 @@ static int sc27xx_fgu_probe(struct platform_device *pdev) return PTR_ERR(data->channel); } + data->charge_chan = devm_iio_channel_get(&pdev->dev, "charge-vol"); + if (IS_ERR(data->charge_chan)) { + dev_err(&pdev->dev, "failed to get charge IIO channel\n"); + return PTR_ERR(data->charge_chan); + } + data->gpiod = devm_gpiod_get(&pdev->dev, "bat-detect", GPIOD_IN); if (IS_ERR(data->gpiod)) { dev_err(&pdev->dev, "failed to get battery detection GPIO\n"); diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index 0e202d4273fb..4299873a1118 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -809,7 +809,9 @@ static int twl4030_bci_get_property(struct power_supply *psy, is_charging = state & TWL4030_MSTATEC_AC; if (!is_charging) { u8 s; - twl4030_bci_read(TWL4030_BCIMDEN, &s); + ret = twl4030_bci_read(TWL4030_BCIMDEN, &s); + if (ret < 0) + return ret; if (psy->desc->type == POWER_SUPPLY_TYPE_USB) is_charging = s & 1; else |