Commit 72e65f7e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull power supply and reset updates from Sebastian Reichel:
 "Miscellaneous small fixes and improvements all over the place.

  Nothing stands out in particular"

* tag 'for-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (30 commits)
  power: supply: bq25890: Fix initial setting of the F_CONV_RATE field
  power: supply: bq25890: Fix race causing oops at boot
  power: supply: bq27xxx: Fix kernel crash on IRQ handler register error
  power: bq25890: add return values to error messages
  power: supply: axp288-charger: Simplify axp288_get_charger_health()
  power: supply: axp288-charger: Remove unnecessary is_present and is_online helpers
  power: supply: axp288-charger: Add depends on IOSF_MBIO to Kconfig
  power: supply: ab8500_bmdata: Use standard phandle
  dt-bindings: power: supply: ab8500: Standard monitored-battery
  power: supply: axp288_charger: Fix missing mutex_init()
  power: supply: max17042_battery: Prevent int underflow in set_soc_threshold
  power: supply: max17042_battery: Clear status bits in interrupt handler
  MAINTAINERS: power: supply: max17040: add entry with reviewers
  MAINTAINERS: power: supply: max17042: add entry with reviewers
  power: supply: max17040: fix null-ptr-deref in max17040_probe()
  power: supply: rt5033_battery: Change voltage values to µV
  power: supply: axp288-charger: Optimize register reading method
  dt-bindings: power: Bindings for Samsung batteries
  power: supply: cpcap-battery: use device_get_match_data() to simplify code
  power: supply: max17042_battery: fix typo in MAX17042_IAvg_empty
  ...
parents c1e2e035 22ad4f99
......@@ -480,6 +480,19 @@ Description:
Valid values: Represented in microvolts
What: /sys/class/power_supply/<supply_name>/cycle_count
Date: January 2010
Contact: linux-pm@vger.kernel.org
Description:
Reports the number of full charge + discharge cycles the
battery has undergone.
Access: Read
Valid values:
Integer > 0: representing full cycles
Integer = 0: cycle_count info is not available
**USB Properties**
What: /sys/class/power_supply/<supply_name>/input_current_limit
......
......@@ -62,7 +62,7 @@ required:
- compatible
- reg
additionalProperties: false
unevaluatedProperties: false
examples:
- |
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/supply/samsung,battery.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung SDI Batteries
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
description: |
Samsung SDI (Samsung Digital Interface) batteries are all different versions
of lithium ion chemistry devices used for mobile phones, laptops and other
portable electronics. The batteries are adapted to a specific product and
the physical restrictions make it impossible to use another battery with the
product, so product device trees can specify these batteries. Operating
systems should determine hardware characteristics of the batteries from the
compatible string.
properties:
compatible:
oneOf:
- const: samsung,eb-l1m7flu
description: 3.8V 1500 mAh battery used in Samsung GT-I8190
- const: samsung,eb425161la
description: 3.8V 1500 mAh battery used in Samsung SGH-T599 and SGH-I407
- const: samsung,eb425161lu
description: 3.8V 1500 mAh battery used in Samsung GT-I8160
- const: samsung,eb485159lu
description: 3.8V 1700 mAh battery used in Samsung GT-S7710
- const: samsung,eb535151vu
description: 3.8V 1500 mAh battery used in Samsung GT-I9070
- const: samsung,eb585157lu
description: 3.8V 2000 mAh battery used in Samsung GT-I8530
required:
- compatible
additionalProperties: false
examples:
- |
power {
#address-cells = <1>;
#size-cells = <0>;
battery: battery {
compatible = "samsung,eb425161la";
};
charger@11 {
reg = <0x11>;
monitored-battery = <&battery>;
};
};
......@@ -17,10 +17,14 @@ properties:
compatible:
const: stericsson,ab8500-btemp
battery:
monitored-battery:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to battery node
battery:
$ref: /schemas/types.yaml#/definitions/phandle
deprecated: true
interrupts:
maxItems: 5
......@@ -42,7 +46,7 @@ properties:
required:
- compatible
- battery
- monitored-battery
- interrupts
- interrupt-names
- io-channels
......@@ -56,7 +60,7 @@ examples:
pmic {
battery-temperature {
compatible = "stericsson,ab8500-btemp";
battery = <&ab8500_battery>;
monitored-battery = <&battery>;
interrupts = <20 IRQ_TYPE_LEVEL_HIGH>,
<80 IRQ_TYPE_LEVEL_HIGH>,
<83 IRQ_TYPE_LEVEL_HIGH>,
......
......@@ -17,13 +17,17 @@ properties:
compatible:
const: stericsson,ab8500-chargalg
battery:
monitored-battery:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to battery node
battery:
$ref: /schemas/types.yaml#/definitions/phandle
deprecated: true
required:
- compatible
- battery
- monitored-battery
additionalProperties: false
......@@ -32,6 +36,6 @@ examples:
pmic {
charging-algorithm {
compatible = "stericsson,ab8500-chargalg";
battery = <&ab8500_battery>;
monitored-battery = <&ab8500_battery>;
};
};
......@@ -17,10 +17,14 @@ properties:
compatible:
const: stericsson,ab8500-charger
battery:
monitored-battery:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to battery node
battery:
$ref: /schemas/types.yaml#/definitions/phandle
deprecated: true
vddadc-supply:
description: Supply for USB and Main charger
......@@ -66,7 +70,7 @@ properties:
required:
- compatible
- battery
- monitored-battery
- vddadc-supply
- interrupts
- interrupt-names
......@@ -81,7 +85,7 @@ examples:
pmic {
charger {
compatible = "stericsson,ab8500-charger";
battery = <&ab8500_battery>;
monitored-battery = <&battery>;
vddadc-supply = <&ab8500_ldo_tvout_reg>;
interrupts = <10 IRQ_TYPE_LEVEL_HIGH>,
<11 IRQ_TYPE_LEVEL_HIGH>,
......
......@@ -17,10 +17,14 @@ properties:
compatible:
const: stericsson,ab8500-fg
battery:
monitored-battery:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to battery node
battery:
$ref: /schemas/types.yaml#/definitions/phandle
deprecated: true
interrupts:
maxItems: 5
......@@ -41,7 +45,7 @@ properties:
required:
- compatible
- battery
- monitored-battery
- interrupts
- interrupt-names
- io-channels
......@@ -55,7 +59,7 @@ examples:
pmic {
fuel-gauge {
compatible = "stericsson,ab8500-fg";
battery = <&ab8500_battery>;
monitored-battery = <&battery>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>,
<8 IRQ_TYPE_LEVEL_HIGH>,
<28 IRQ_TYPE_LEVEL_HIGH>,
......
......@@ -11508,6 +11508,27 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.yaml
F: drivers/iio/proximity/mb1232.c
MAXIM MAX17040 FAMILY FUEL GAUGE DRIVERS
R: Iskren Chernev <iskren.chernev@gmail.com>
R: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
R: Marek Szyprowski <m.szyprowski@samsung.com>
R: Matheus Castello <matheus@castello.eng.br>
L: linux-pm@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml
F: drivers/power/supply/max17040_battery.c
MAXIM MAX17042 FAMILY FUEL GAUGE DRIVERS
R: Hans de Goede <hdegoede@redhat.com>
R: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
R: Marek Szyprowski <m.szyprowski@samsung.com>
R: Sebastian Krzyszkowiak <sebastian.krzyszkowiak@puri.sm>
R: Purism Kernel Team <kernel@puri.sm>
L: linux-pm@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml
F: drivers/power/supply/max17042_battery.c
MAXIM MAX77650 PMIC MFD DRIVER
M: Bartosz Golaszewski <brgl@bgdev.pl>
L: linux-kernel@vger.kernel.org
......
......@@ -193,7 +193,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
return -ENOMEM;
reset->rstc_base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
if (!reset->rstc_base) {
if (IS_ERR(reset->rstc_base)) {
dev_err(&pdev->dev, "Could not map reset controller address\n");
return -ENODEV;
}
......@@ -203,7 +203,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
for_each_matching_node_and_match(np, at91_ramc_of_match, &match) {
reset->ramc_lpr = (u32)match->data;
reset->ramc_base[idx] = devm_of_iomap(&pdev->dev, np, 0, NULL);
if (!reset->ramc_base[idx]) {
if (IS_ERR(reset->ramc_base[idx])) {
dev_err(&pdev->dev, "Could not map ram controller address\n");
of_node_put(np);
return -ENODEV;
......
......@@ -94,7 +94,6 @@ static struct ltc2952_poweroff *ltc2952_data;
*/
static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
{
ktime_t now;
int state;
struct ltc2952_poweroff *data = to_ltc2952(timer, timer_wde);
......@@ -104,8 +103,7 @@ static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
state = gpiod_get_value(data->gpio_watchdog);
gpiod_set_value(data->gpio_watchdog, !state);
now = hrtimer_cb_get_time(timer);
hrtimer_forward(timer, now, data->wde_interval);
hrtimer_forward_now(timer, data->wde_interval);
return HRTIMER_RESTART;
}
......
......@@ -351,7 +351,7 @@ config AXP20X_POWER
config AXP288_CHARGER
tristate "X-Powers AXP288 Charger"
depends on MFD_AXP20X && EXTCON_AXP288
depends on MFD_AXP20X && EXTCON_AXP288 && IOSF_MBI
help
Say yes here to have support X-Power AXP288 power management IC (PMIC)
integrated charger.
......@@ -366,20 +366,22 @@ config AXP288_FUEL_GAUGE
over/under temperature.
config BATTERY_MAX17040
tristate "Maxim MAX17040 Fuel Gauge"
tristate "Maxim MAX17040/17041/17043 family Fuel Gauge"
depends on I2C
select REGMAP_I2C
help
Maxim models with ModelGauge are fuel-gauge systems for lithium-ion
(Li+) batteries in handheld and portable equipment, including
max17040, max17041, max17043, max17044, max17048, max17049, max17058,
max17059. It is also included in some batteries like max77836.
Driver supports Maxim fuel-gauge systems for lithium-ion (Li+)
batteries used mainly in handheld and portable equipment.
Supported devices: max17040, max17041, max17043, max17044, max17048,
max17049, max17058, max17059, max77836.
Driver supports reporting SOC (State of Charge, i.e capacity),
voltage and configurable low-SOC wakeup interrupt.
Driver can be build as a module (max17040_battery).
config BATTERY_MAX17042
tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge"
tristate "Maxim MAX17042/17047/17050/8997/8966 family Fuel Gauge"
depends on I2C
select REGMAP_I2C
help
......@@ -387,8 +389,11 @@ config BATTERY_MAX17042
in handheld and portable equipment. The MAX17042 is configured
to operate with a single lithium cell. MAX8997 and MAX8966 are
multi-function devices that include fuel gauages that are compatible
with MAX17042. This driver also supports max17047/50 chips which are
improved version of max17042.
with MAX17042.
Supported devices: max8966, max8997, max17042, max17047, max17050,
max17055, max77693, max77849.
Driver can be build as a module (max17042_battery).
config BATTERY_MAX1721X
tristate "MAX17211/MAX17215 standalone gas-gauge"
......
......@@ -497,8 +497,7 @@ int ab8500_bm_of_probe(struct device *dev,
const char *btech;
int i;
/* get phandle to 'battery-info' node */
battery_node = of_parse_phandle(np, "battery", 0);
battery_node = of_parse_phandle(np, "monitored-battery", 0);
if (!battery_node) {
dev_err(dev, "battery node or reference missing\n");
return -EINVAL;
......
......@@ -22,6 +22,7 @@
#include <linux/mfd/axp20x.h>
#include <linux/extcon.h>
#include <linux/dmi.h>
#include <asm/iosf_mbi.h>
#define PS_STAT_VBUS_TRIGGER BIT(0)
#define PS_STAT_BAT_CHRG_DIR BIT(2)
......@@ -95,6 +96,8 @@
#define CV_4200MV 4200 /* 4200mV */
#define CV_4350MV 4350 /* 4350mV */
#define AXP288_REG_UPDATE_INTERVAL (60 * HZ)
#define AXP288_EXTCON_DEV_NAME "axp288_extcon"
#define USB_HOST_EXTCON_HID "INT3496"
#define USB_HOST_EXTCON_NAME "INT3496:00"
......@@ -118,6 +121,7 @@ struct axp288_chrg_info {
struct regmap_irq_chip_data *regmap_irqc;
int irq[CHRG_INTR_END];
struct power_supply *psy_usb;
struct mutex lock;
/* OTG/Host mode */
struct {
......@@ -138,6 +142,12 @@ struct axp288_chrg_info {
int cv;
int max_cc;
int max_cv;
unsigned long last_updated;
unsigned int input_status;
unsigned int op_mode;
unsigned int backend_control;
bool valid;
};
static inline int axp288_charger_set_cc(struct axp288_chrg_info *info, int cc)
......@@ -197,11 +207,8 @@ static inline int axp288_charger_set_cv(struct axp288_chrg_info *info, int cv)
static int axp288_charger_get_vbus_inlmt(struct axp288_chrg_info *info)
{
unsigned int val;
int ret;
ret = regmap_read(info->regmap, AXP20X_CHRG_BAK_CTRL, &val);
if (ret < 0)
return ret;
val = info->backend_control;
val >>= CHRG_VBUS_ILIM_BIT_POS;
switch (val) {
......@@ -295,63 +302,19 @@ static int axp288_charger_enable_charger(struct axp288_chrg_info *info,
return ret;
}
static int axp288_charger_is_present(struct axp288_chrg_info *info)
{
int ret, present = 0;
unsigned int val;
ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
if (ret < 0)
return ret;
if (val & PS_STAT_VBUS_PRESENT)
present = 1;
return present;
}
static int axp288_charger_is_online(struct axp288_chrg_info *info)
{
int ret, online = 0;
unsigned int val;
ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
if (ret < 0)
return ret;
if (val & PS_STAT_VBUS_VALID)
online = 1;
return online;
}
static int axp288_get_charger_health(struct axp288_chrg_info *info)
{
int ret, pwr_stat, chrg_stat;
int health = POWER_SUPPLY_HEALTH_UNKNOWN;
unsigned int val;
ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
if ((ret < 0) || !(val & PS_STAT_VBUS_PRESENT))
goto health_read_fail;
if (!(info->input_status & PS_STAT_VBUS_PRESENT))
return POWER_SUPPLY_HEALTH_UNKNOWN;
if (!(info->input_status & PS_STAT_VBUS_VALID))
return POWER_SUPPLY_HEALTH_DEAD;
else if (info->op_mode & CHRG_STAT_PMIC_OTP)
return POWER_SUPPLY_HEALTH_OVERHEAT;
else if (info->op_mode & CHRG_STAT_BAT_SAFE_MODE)
return POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
else
pwr_stat = val;
ret = regmap_read(info->regmap, AXP20X_PWR_OP_MODE, &val);
if (ret < 0)
goto health_read_fail;
else
chrg_stat = val;
if (!(pwr_stat & PS_STAT_VBUS_VALID))
health = POWER_SUPPLY_HEALTH_DEAD;
else if (chrg_stat & CHRG_STAT_PMIC_OTP)
health = POWER_SUPPLY_HEALTH_OVERHEAT;
else if (chrg_stat & CHRG_STAT_BAT_SAFE_MODE)
health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
else
health = POWER_SUPPLY_HEALTH_GOOD;
health_read_fail:
return health;
return POWER_SUPPLY_HEALTH_GOOD;
}
static int axp288_charger_usb_set_property(struct power_supply *psy,
......@@ -362,30 +325,86 @@ static int axp288_charger_usb_set_property(struct power_supply *psy,
int ret = 0;
int scaled_val;
mutex_lock(&info->lock);
switch (psp) {
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
scaled_val = min(val->intval, info->max_cc);
scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
ret = axp288_charger_set_cc(info, scaled_val);
if (ret < 0)
if (ret < 0) {
dev_warn(&info->pdev->dev, "set charge current failed\n");
goto out;
}
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
scaled_val = min(val->intval, info->max_cv);
scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
ret = axp288_charger_set_cv(info, scaled_val);
if (ret < 0)
if (ret < 0) {
dev_warn(&info->pdev->dev, "set charge voltage failed\n");
goto out;
}
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = axp288_charger_set_vbus_inlmt(info, val->intval);
if (ret < 0)
if (ret < 0) {
dev_warn(&info->pdev->dev, "set input current limit failed\n");
goto out;
}
info->valid = false;
break;
default:
ret = -EINVAL;
}
out:
mutex_unlock(&info->lock);
return ret;
}
static int axp288_charger_reg_readb(struct axp288_chrg_info *info, int reg, unsigned int *ret_val)
{
int ret;
ret = regmap_read(info->regmap, reg, ret_val);
if (ret < 0) {
dev_err(&info->pdev->dev, "Error %d on reading value from register 0x%04x\n",
ret,
reg);
return ret;
}
return 0;
}
static int axp288_charger_usb_update_property(struct axp288_chrg_info *info)
{
int ret = 0;
if (info->valid && time_before(jiffies, info->last_updated + AXP288_REG_UPDATE_INTERVAL))
return 0;
dev_dbg(&info->pdev->dev, "Charger updating register values...\n");
ret = iosf_mbi_block_punit_i2c_access();
if (ret < 0)
return ret;
ret = axp288_charger_reg_readb(info, AXP20X_PWR_INPUT_STATUS, &info->input_status);
if (ret < 0)
goto out;
ret = axp288_charger_reg_readb(info, AXP20X_PWR_OP_MODE, &info->op_mode);
if (ret < 0)
goto out;
ret = axp288_charger_reg_readb(info, AXP20X_CHRG_BAK_CTRL, &info->backend_control);
if (ret < 0)
goto out;
info->last_updated = jiffies;
info->valid = true;
out:
iosf_mbi_unblock_punit_i2c_access();
return ret;
}
......@@ -396,6 +415,11 @@ static int axp288_charger_usb_get_property(struct power_supply *psy,
struct axp288_chrg_info *info = power_supply_get_drvdata(psy);
int ret;
mutex_lock(&info->lock);
ret = axp288_charger_usb_update_property(info);
if (ret < 0)
goto out;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
/* Check for OTG case first */
......@@ -403,10 +427,7 @@ static int axp288_charger_usb_get_property(struct power_supply *psy,
val->intval = 0;
break;
}
ret = axp288_charger_is_present(info);
if (ret < 0)
return ret;
val->intval = ret;
val->intval = (info->input_status & PS_STAT_VBUS_PRESENT) ? 1 : 0;
break;
case POWER_SUPPLY_PROP_ONLINE:
/* Check for OTG case first */
......@@ -414,10 +435,7 @@ static int axp288_charger_usb_get_property(struct power_supply *psy,
val->intval = 0;
break;
}
ret = axp288_charger_is_online(info);
if (ret < 0)
return ret;
val->intval = ret;
val->intval = (info->input_status & PS_STAT_VBUS_VALID) ? 1 : 0;
break;
case POWER_SUPPLY_PROP_HEALTH:
val->intval = axp288_get_charger_health(info);
......@@ -435,16 +453,15 @@ static int axp288_charger_usb_get_property(struct power_supply *psy,
val->intval = info->max_cv * 1000;
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = axp288_charger_get_vbus_inlmt(info);
if (ret < 0)
return ret;
val->intval = ret;
val->intval = axp288_charger_get_vbus_inlmt(info);
break;
default:
return -EINVAL;
ret = -EINVAL;
}
return 0;
out:
mutex_unlock(&info->lock);
return ret;
}
static int axp288_charger_property_is_writeable(struct power_supply *psy,
......@@ -540,7 +557,9 @@ static irqreturn_t axp288_charger_irq_thread_handler(int irq, void *dev)
dev_warn(&info->pdev->dev, "Spurious Interrupt!!!\n");
goto out;
}
mutex_lock(&info->lock);
info->valid = false;
mutex_unlock(&info->lock);
power_supply_changed(info->psy_usb);
out:
return IRQ_HANDLED;
......@@ -613,6 +632,9 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work)
if (!(val & PS_STAT_VBUS_VALID)) {
dev_dbg(&info->pdev->dev, "USB charger disconnected\n");
axp288_charger_enable_charger(info, false);
mutex_lock(&info->lock);
info->valid = false;
mutex_unlock(&info->lock);
power_supply_changed(info->psy_usb);
return;
}
......@@ -644,6 +666,9 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work)
dev_err(&info->pdev->dev,
"error setting current limit (%d)\n", ret);
mutex_lock(&info->lock);
info->valid = false;
mutex_unlock(&info->lock);
power_supply_changed(info->psy_usb);
}
......@@ -817,6 +842,7 @@ static int axp288_charger_probe(struct platform_device *pdev)
if (!info)
return -ENOMEM;
mutex_init(&info->lock);
info->pdev = pdev;
info->regmap = axp20x->regmap;
info->regmap_irqc = axp20x->regmap_irqc;
......
......@@ -682,16 +682,16 @@ static int bq25890_hw_init(struct bq25890_device *bq)
}
}
/* Configure ADC for continuous conversions when charging */
ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
ret = bq25890_get_chip_state(bq, &bq->state);
if (ret < 0) {
dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
dev_dbg(bq->dev, "Get state failed %d\n", ret);
return ret;
}
ret = bq25890_get_chip_state(bq, &bq->state);
/* Configure ADC for continuous conversions when charging */
ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
if (ret < 0) {
dev_dbg(bq->dev, "Get state failed %d\n", ret);
dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
return ret;
}
......@@ -734,8 +734,9 @@ static int bq25890_power_supply_init(struct bq25890_device *bq)
psy_cfg.supplied_to = bq25890_charger_supplied_to;
psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
bq->charger = power_supply_register(bq->dev, &bq25890_power_supply_desc,
&psy_cfg);
bq->charger = devm_power_supply_register(bq->dev,
&bq25890_power_supply_desc,
&psy_cfg);
return PTR_ERR_OR_ZERO(bq->charger);
}
......@@ -788,13 +789,13 @@ static int bq25890_get_chip_version(struct bq25890_device *bq)
id = bq25890_field_read(bq, F_PN);
if (id < 0) {
dev_err(bq->dev, "Cannot read chip ID.\n");
dev_err(bq->dev, "Cannot read chip ID: %d\n", id);
return id;
}
rev = bq25890_field_read(bq, F_DEV_REV);
if (rev < 0) {
dev_err(bq->dev, "Cannot read chip revision.\n");
dev_err(bq->dev, "Cannot read chip revision: %d\n", rev);
return rev;
}
......@@ -837,10 +838,9 @@ static int bq25890_irq_probe(struct bq25890_device *bq)
struct gpio_desc *irq;
irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN);
if (IS_ERR(irq)) {
dev_err(bq->dev, "Could not probe irq pin.\n");
return PTR_ERR(irq);
}
if (IS_ERR(irq))
return dev_err_probe(bq->dev, PTR_ERR(irq),
"Could not probe irq pin.\n");
return gpiod_to_irq(irq);
}
......@@ -929,34 +929,33 @@ static int bq25890_probe(struct i2c_client *client,
mutex_init(&bq->lock);
bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config);
if (IS_ERR(bq->rmap)) {
dev_err(dev, "failed to allocate register map\n");
return PTR_ERR(bq->rmap);
}
if (IS_ERR(bq->rmap))
return dev_err_probe(dev, PTR_ERR(bq->rmap),
"failed to allocate register map\n");
for (i = 0; i < ARRAY_SIZE(bq25890_reg_fields); i++) {
const struct reg_field *reg_fields = bq25890_reg_fields;
bq->rmap_fields[i] = devm_regmap_field_alloc(dev, bq->rmap,
reg_fields[i]);
if (IS_ERR(bq->rmap_fields[i])) {
dev_err(dev, "cannot allocate regmap field\n");
return PTR_ERR(bq->rmap_fields[i]);
}
if (IS_ERR(bq->rmap_fields[i]))
return dev_err_probe(dev, PTR_ERR(bq->rmap_fields[i]),
"cannot allocate regmap field\n");
}
i2c_set_clientdata(client, bq);
ret = bq25890_get_chip_version(bq);
if (ret) {
dev_err(dev, "Cannot read chip ID or unknown chip.\n");
dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret);
return ret;
}
if (!dev->platform_data) {
ret = bq25890_fw_probe(bq);
if (ret < 0) {
dev_err(dev, "Cannot read device properties.\n");
dev_err(dev, "Cannot read device properties: %d\n",
ret);
return ret;
}
} else {
......@@ -965,7 +964,7 @@ static int bq25890_probe(struct i2c_client *client,
ret = bq25890_hw_init(bq);
if (ret < 0) {
dev_err(dev, "Cannot initialize the chip.\n");
dev_err(dev, "Cannot initialize the chip: %d\n", ret);
return ret;
}
......@@ -985,22 +984,22 @@ static int bq25890_probe(struct i2c_client *client,
usb_register_notifier(bq->usb_phy, &bq->usb_nb);
}
ret = bq25890_power_supply_init(bq);
if (ret < 0) {
dev_err(dev, "Failed to register power supply\n");
goto err_unregister_usb_notifier;
}
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq25890_irq_handler_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
BQ25890_IRQ_PIN, bq);
if (ret)
goto irq_fail;
ret = bq25890_power_supply_init(bq);
if (ret < 0) {
dev_err(dev, "Failed to register power supply\n");
goto irq_fail;
}
goto err_unregister_usb_notifier;
return 0;
irq_fail:
err_unregister_usb_notifier:
if (!IS_ERR_OR_NULL(bq->usb_phy))
usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
......@@ -1011,8 +1010,6 @@ static int bq25890_remove(struct i2c_client *client)
{
struct bq25890_device *bq = i2c_get_clientdata(client);
power_supply_unregister(bq->charger);
if (!IS_ERR_OR_NULL(bq->usb_phy))
usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
......
......@@ -187,7 +187,8 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
dev_err(&client->dev,
"Unable to register IRQ %d error %d\n",
client->irq, ret);
return ret;
bq27xxx_battery_teardown(di);
goto err_failed;
}
}
......
......@@ -1026,20 +1026,13 @@ static const struct power_supply_desc cpcap_charger_battery_desc = {
static int cpcap_battery_probe(struct platform_device *pdev)
{
struct cpcap_battery_ddata *ddata;
const struct of_device_id *match;
struct power_supply_config psy_cfg = {};
int error;
const struct cpcap_battery_config *cfg;
match = of_match_device(of_match_ptr(cpcap_battery_id_table),
&pdev->dev);
if (!match)
return -EINVAL;
if (!match->data) {
dev_err(&pdev->dev, "no configuration data found\n");
cfg = device_get_match_data(&pdev->dev);
if (!cfg)
return -ENODEV;
}
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
......@@ -1047,7 +1040,7 @@ static int cpcap_battery_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ddata->irq_list);
ddata->dev = &pdev->dev;
memcpy(&ddata->config, match->data, sizeof(ddata->config));
memcpy(&ddata->config, cfg, sizeof(ddata->config));
ddata->reg = dev_get_regmap(ddata->dev->parent, NULL);
if (!ddata->reg)
......
......@@ -449,6 +449,8 @@ static int max17040_probe(struct i2c_client *client,
chip->client = client;
chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
if (IS_ERR(chip->regmap))
return PTR_ERR(chip->regmap);
chip_id = (enum chip_id) id->driver_data;
if (client->dev.of_node) {
ret = max17040_get_of_data(chip);
......
......@@ -313,7 +313,10 @@ static int max17042_get_property(struct power_supply *psy,
val->intval = data * 625 / 8;
break;
case POWER_SUPPLY_PROP_CAPACITY:
ret = regmap_read(map, MAX17042_RepSOC, &data);
if (chip->pdata->enable_current_sense)
ret = regmap_read(map, MAX17042_RepSOC, &data);
else
ret = regmap_read(map, MAX17042_VFSOC, &data);
if (ret < 0)
return ret;
......@@ -783,7 +786,7 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) ||
(chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
(chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) {
max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty);
max17042_override_por(map, MAX17042_IAvg_empty, config->iavg_empty);
max17042_override_por(map, MAX17042_TempNom, config->temp_nom);
max17042_override_por(map, MAX17042_TempLim, config->temp_lim);
max17042_override_por(map, MAX17042_FCTC, config->fctc);
......@@ -857,7 +860,8 @@ static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off)
regmap_read(map, MAX17042_RepSOC, &soc);
soc >>= 8;
soc_tr = (soc + off) << 8;
soc_tr |= (soc - off);
if (off < soc)
soc_tr |= soc - off;
regmap_write(map, MAX17042_SALRT_Th, soc_tr);
}
......@@ -876,6 +880,10 @@ static irqreturn_t max17042_thread_handler(int id, void *dev)
max17042_set_soc_threshold(chip, 1);
}
/* we implicitly handle all alerts via power_supply_changed */
regmap_clear_bits(chip->regmap, MAX17042_STATUS,
0xFFFF & ~(STATUS_POR_BIT | STATUS_BST_BIT));
power_supply_changed(chip->battery);
return IRQ_HANDLED;
}
......
......@@ -951,6 +951,22 @@ void power_supply_unreg_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(power_supply_unreg_notifier);
static bool psy_has_property(const struct power_supply_desc *psy_desc,
enum power_supply_property psp)
{
bool found = false;
int i;
for (i = 0; i < psy_desc->num_properties; i++) {
if (psy_desc->properties[i] == psp) {
found = true;
break;
}
}
return found;
}
#ifdef CONFIG_THERMAL
static int power_supply_read_temp(struct thermal_zone_device *tzd,
int *temp)
......@@ -977,24 +993,23 @@ static struct thermal_zone_device_ops psy_tzd_ops = {
static int psy_register_thermal(struct power_supply *psy)
{
int i, ret;
int ret;
if (psy->desc->no_thermal)
return 0;
/* Register battery zone device psy reports temperature */
for (i = 0; i < psy->desc->num_properties; i++) {
if (psy->desc->properties[i] == POWER_SUPPLY_PROP_TEMP) {
psy->tzd = thermal_zone_device_register(psy->desc->name,
0, 0, psy, &psy_tzd_ops, NULL, 0, 0);
if (IS_ERR(psy->tzd))
return PTR_ERR(psy->tzd);
ret = thermal_zone_device_enable(psy->tzd);
if (ret)
thermal_zone_device_unregister(psy->tzd);
return ret;
}
if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
psy->tzd = thermal_zone_device_register(psy->desc->name,
0, 0, psy, &psy_tzd_ops, NULL, 0, 0);
if (IS_ERR(psy->tzd))
return PTR_ERR(psy->tzd);
ret = thermal_zone_device_enable(psy->tzd);
if (ret)
thermal_zone_device_unregister(psy->tzd);
return ret;
}
return 0;
}
......@@ -1065,18 +1080,14 @@ static const struct thermal_cooling_device_ops psy_tcd_ops = {
static int psy_register_cooler(struct power_supply *psy)
{
int i;
/* Register for cooling device if psy can control charging */
for (i = 0; i < psy->desc->num_properties; i++) {
if (psy->desc->properties[i] ==
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) {
psy->tcd = thermal_cooling_device_register(
(char *)psy->desc->name,
psy, &psy_tcd_ops);
return PTR_ERR_OR_ZERO(psy->tcd);
}
if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT)) {
psy->tcd = thermal_cooling_device_register(
(char *)psy->desc->name,
psy, &psy_tcd_ops);
return PTR_ERR_OR_ZERO(psy->tcd);
}
return 0;
}
......@@ -1114,7 +1125,7 @@ __power_supply_register(struct device *parent,
{
struct device *dev;
struct power_supply *psy;
int i, rc;
int rc;
if (!parent)
pr_warn("%s: Expected proper parent device for '%s'\n",
......@@ -1123,11 +1134,9 @@ __power_supply_register(struct device *parent,
if (!desc || !desc->name || !desc->properties || !desc->num_properties)
return ERR_PTR(-EINVAL);
for (i = 0; i < desc->num_properties; ++i) {
if ((desc->properties[i] == POWER_SUPPLY_PROP_USB_TYPE) &&
(!desc->usb_types || !desc->num_usb_types))
return ERR_PTR(-EINVAL);
}
if (psy_has_property(desc, POWER_SUPPLY_PROP_USB_TYPE) &&
(!desc->usb_types || !desc->num_usb_types))
return ERR_PTR(-EINVAL);
psy = kzalloc(sizeof(*psy), GFP_KERNEL);
if (!psy)
......
......@@ -60,7 +60,7 @@ static int rt5033_battery_get_watt_prop(struct i2c_client *client,
regmap_read(battery->regmap, regh, &msb);
regmap_read(battery->regmap, regl, &lsb);
ret = ((msb << 4) + (lsb >> 4)) * 1250 / 1000;
ret = ((msb << 4) + (lsb >> 4)) * 1250;
return ret;
}
......
......@@ -234,7 +234,7 @@ static struct chg_map chg_times[] = {
{ 510, 15 << WM831X_CHG_TIME_SHIFT },
};
static void wm831x_battey_apply_config(struct wm831x *wm831x,
static void wm831x_battery_apply_config(struct wm831x *wm831x,
struct chg_map *map, int count, int val,
int *reg, const char *name,
const char *units)
......@@ -281,24 +281,24 @@ static void wm831x_config_battery(struct wm831x *wm831x)
if (pdata->fast_enable)
reg1 |= WM831X_CHG_FAST;
wm831x_battey_apply_config(wm831x, trickle_ilims,
wm831x_battery_apply_config(wm831x, trickle_ilims,
ARRAY_SIZE(trickle_ilims),
pdata->trickle_ilim, &reg2,
"trickle charge current limit", "mA");
wm831x_battey_apply_config(wm831x, vsels, ARRAY_SIZE(vsels),
wm831x_battery_apply_config(wm831x, vsels, ARRAY_SIZE(vsels),
pdata->vsel, &reg2,
"target voltage", "mV");
wm831x_battey_apply_config(wm831x, fast_ilims, ARRAY_SIZE(fast_ilims),
wm831x_battery_apply_config(wm831x, fast_ilims, ARRAY_SIZE(fast_ilims),
pdata->fast_ilim, &reg2,
"fast charge current limit", "mA");
wm831x_battey_apply_config(wm831x, eoc_iterms, ARRAY_SIZE(eoc_iterms),
wm831x_battery_apply_config(wm831x, eoc_iterms, ARRAY_SIZE(eoc_iterms),
pdata->eoc_iterm, &reg1,
"end of charge current threshold", "mA");
wm831x_battey_apply_config(wm831x, chg_times, ARRAY_SIZE(chg_times),
wm831x_battery_apply_config(wm831x, chg_times, ARRAY_SIZE(chg_times),
pdata->timeout, &reg2,
"charger timeout", "min");
......
......@@ -78,7 +78,7 @@ enum max17042_register {
MAX17042_T_empty = 0x34,
MAX17042_FullCAP0 = 0x35,
MAX17042_LAvg_empty = 0x36,
MAX17042_IAvg_empty = 0x36,
MAX17042_FCTC = 0x37,
MAX17042_RCOMP0 = 0x38,
MAX17042_TempCo = 0x39,
......@@ -221,7 +221,7 @@ struct max17042_config_data {
u16 fullcap; /* 0x10 */
u16 fullcapnom; /* 0x23 */
u16 socempty; /* 0x33 */
u16 lavg_empty; /* 0x36 */
u16 iavg_empty; /* 0x36 */
u16 dqacc; /* 0x45 */
u16 dpacc; /* 0x46 */
u16 qrtbl00; /* 0x12 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment