summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/reset/Kconfig4
-rw-r--r--drivers/power/reset/as3722-poweroff.c2
-rw-r--r--drivers/power/reset/at91-reset.c5
-rw-r--r--drivers/power/reset/at91-sama5d2_shdwc.c2
-rw-r--r--drivers/power/reset/gpio-poweroff.c8
-rw-r--r--drivers/power/reset/keystone-reset.c18
-rw-r--r--drivers/power/reset/ltc2952-poweroff.c8
-rw-r--r--drivers/power/sequencing/pwrseq-qcom-wcn.c29
-rw-r--r--drivers/power/supply/88pm860x_battery.c4
-rw-r--r--drivers/power/supply/Kconfig21
-rw-r--r--drivers/power/supply/Makefile3
-rw-r--r--drivers/power/supply/ab8500_btemp.c5
-rw-r--r--drivers/power/supply/ab8500_chargalg.c14
-rw-r--r--drivers/power/supply/ab8500_charger.c9
-rw-r--r--drivers/power/supply/ab8500_fg.c33
-rw-r--r--drivers/power/supply/acer_a500_battery.c3
-rw-r--r--drivers/power/supply/act8945a_charger.c2
-rw-r--r--drivers/power/supply/apm_power.c6
-rw-r--r--drivers/power/supply/axp20x_ac_power.c2
-rw-r--r--drivers/power/supply/axp20x_battery.c23
-rw-r--r--drivers/power/supply/axp20x_usb_power.c4
-rw-r--r--drivers/power/supply/bd99954-charger.c4
-rw-r--r--drivers/power/supply/bq2415x_charger.c38
-rw-r--r--drivers/power/supply/bq24190_charger.c31
-rw-r--r--drivers/power/supply/bq24257_charger.c10
-rw-r--r--drivers/power/supply/bq24735-charger.c2
-rw-r--r--drivers/power/supply/bq2515x_charger.c6
-rw-r--r--drivers/power/supply/bq256xx_charger.c2
-rw-r--r--drivers/power/supply/bq25890_charger.c2
-rw-r--r--drivers/power/supply/bq25980_charger.c8
-rw-r--r--drivers/power/supply/bq27xxx_battery.c81
-rw-r--r--drivers/power/supply/bq27xxx_battery_i2c.c13
-rw-r--r--drivers/power/supply/charger-manager.c3
-rw-r--r--drivers/power/supply/collie_battery.c1
-rw-r--r--drivers/power/supply/cpcap-battery.c2
-rw-r--r--drivers/power/supply/cpcap-charger.c5
-rw-r--r--drivers/power/supply/cros_charge-control.c200
-rw-r--r--drivers/power/supply/da9030_battery.c6
-rw-r--r--drivers/power/supply/ds2760_battery.c60
-rw-r--r--drivers/power/supply/ds2780_battery.c24
-rw-r--r--drivers/power/supply/ds2781_battery.c24
-rw-r--r--drivers/power/supply/ds2782_battery.c89
-rw-r--r--drivers/power/supply/generic-adc-battery.c2
-rw-r--r--drivers/power/supply/gpio-charger.c19
-rw-r--r--drivers/power/supply/ingenic-battery.c2
-rw-r--r--drivers/power/supply/ip5xxx_power.c571
-rw-r--r--drivers/power/supply/lego_ev3_battery.c3
-rw-r--r--drivers/power/supply/lt3651-charger.c2
-rw-r--r--drivers/power/supply/ltc4162-l-charger.c444
-rw-r--r--drivers/power/supply/max17040_battery.c5
-rw-r--r--drivers/power/supply/max17042_battery.c205
-rw-r--r--drivers/power/supply/max1720x_battery.c117
-rw-r--r--drivers/power/supply/max77650-charger.c2
-rw-r--r--drivers/power/supply/max77693_charger.c2
-rw-r--r--drivers/power/supply/max77705_charger.c589
-rw-r--r--drivers/power/supply/max8903_charger.c2
-rw-r--r--drivers/power/supply/mm8013.c4
-rw-r--r--drivers/power/supply/mt6360_charger.c2
-rw-r--r--drivers/power/supply/mt6370-charger.c3
-rw-r--r--drivers/power/supply/olpc_battery.c15
-rw-r--r--drivers/power/supply/pcf50633-charger.c466
-rw-r--r--drivers/power/supply/pm8916_bms_vm.c2
-rw-r--r--drivers/power/supply/pm8916_lbc.c2
-rw-r--r--drivers/power/supply/power_supply.h31
-rw-r--r--drivers/power/supply/power_supply_core.c290
-rw-r--r--drivers/power/supply/power_supply_hwmon.c50
-rw-r--r--drivers/power/supply/power_supply_sysfs.c194
-rw-r--r--drivers/power/supply/qcom_battmgr.c5
-rw-r--r--drivers/power/supply/qcom_pmi8998_charger.c2
-rw-r--r--drivers/power/supply/qcom_smbb.c2
-rw-r--r--drivers/power/supply/rk817_charger.c2
-rw-r--r--drivers/power/supply/rt5033_battery.c2
-rw-r--r--drivers/power/supply/rt5033_charger.c3
-rw-r--r--drivers/power/supply/rt9455_charger.c4
-rw-r--r--drivers/power/supply/rt9467-charger.c2
-rw-r--r--drivers/power/supply/rt9471.c2
-rw-r--r--drivers/power/supply/sbs-battery.c7
-rw-r--r--drivers/power/supply/sbs-charger.c2
-rw-r--r--drivers/power/supply/sbs-manager.c2
-rw-r--r--drivers/power/supply/sc2731_charger.c2
-rw-r--r--drivers/power/supply/sc27xx_fuel_gauge.c8
-rw-r--r--drivers/power/supply/smb347-charger.c4
-rw-r--r--drivers/power/supply/stc3117_fuel_gauge.c612
-rw-r--r--drivers/power/supply/surface_battery.c4
-rw-r--r--drivers/power/supply/test_power.c113
-rw-r--r--drivers/power/supply/tps65090-charger.c2
-rw-r--r--drivers/power/supply/tps65217_charger.c2
-rw-r--r--drivers/power/supply/ucs1002_power.c2
-rw-r--r--drivers/power/supply/ug3105_battery.c4
89 files changed, 3313 insertions, 1315 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index f5fc33a8bf44..60bf0ca64cf3 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -26,7 +26,7 @@ config POWER_RESET_AT91_POWEROFF
config POWER_RESET_AT91_RESET
tristate "Atmel AT91 reset driver"
depends on ARCH_AT91
- default SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAMA5
+ default SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAM9X7 || SOC_SAMA5
help
This driver supports restart for Atmel AT91SAM9 and SAMA5
SoCs
@@ -34,7 +34,7 @@ config POWER_RESET_AT91_RESET
config POWER_RESET_AT91_SAMA5D2_SHDWC
tristate "Atmel AT91 SAMA5D2-Compatible shutdown controller driver"
depends on ARCH_AT91
- default SOC_SAM9X60 || SOC_SAMA5
+ default SOC_SAM9X60 || SOC_SAM9X7 || SOC_SAMA5
help
This driver supports the alternate shutdown controller for some Atmel
SAMA5 SoCs. It is present for example on SAMA5D2 SoC.
diff --git a/drivers/power/reset/as3722-poweroff.c b/drivers/power/reset/as3722-poweroff.c
index bb26fa6fa67c..8075382cbc36 100644
--- a/drivers/power/reset/as3722-poweroff.c
+++ b/drivers/power/reset/as3722-poweroff.c
@@ -57,8 +57,6 @@ static int as3722_poweroff_probe(struct platform_device *pdev)
SYS_OFF_PRIO_DEFAULT,
as3722_pm_power_off,
as3722_poweroff);
-
- return 0;
}
static struct platform_driver as3722_poweroff_driver = {
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 036b18a1f90f..511f5a8f8961 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -129,12 +129,11 @@ static int at91_reset(struct notifier_block *this, unsigned long mode,
" str %4, [%0, %6]\n\t"
/* Disable SDRAM1 accesses */
"1: tst %1, #0\n\t"
- " beq 2f\n\t"
" strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
/* Power down SDRAM1 */
" strne %4, [%1, %6]\n\t"
/* Reset CPU */
- "2: str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
+ " str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
" b .\n\t"
:
@@ -145,7 +144,7 @@ static int at91_reset(struct notifier_block *this, unsigned long mode,
"r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
"r" (reset->data->reset_args),
"r" (reset->ramc_lpr)
- : "r4");
+ );
return NOTIFY_DONE;
}
diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c
index edb0df86aff4..e9fe08ee3812 100644
--- a/drivers/power/reset/at91-sama5d2_shdwc.c
+++ b/drivers/power/reset/at91-sama5d2_shdwc.c
@@ -326,6 +326,8 @@ static const struct of_device_id at91_pmc_ids[] = {
{ .compatible = "atmel,sama5d2-pmc" },
{ .compatible = "microchip,sam9x60-pmc" },
{ .compatible = "microchip,sama7g5-pmc" },
+ { .compatible = "microchip,sam9x7-pmc" },
+ { .compatible = "microchip,sama7d65-pmc" },
{ /* Sentinel. */ }
};
diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c
index 52cfeee2cb28..3eaae352ffb9 100644
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -44,7 +44,13 @@ static int gpio_poweroff_do_poweroff(struct sys_off_data *data)
/* give it some time */
mdelay(gpio_poweroff->timeout_ms);
- WARN_ON(1);
+ /*
+ * If code reaches this point, it means that gpio-poweroff has failed
+ * to actually power off the system.
+ * Warn the user that the attempt to poweroff via gpio-poweroff
+ * has gone wrong.
+ */
+ WARN(1, "Failed to poweroff via gpio-poweroff mechanism\n");
return NOTIFY_DONE;
}
diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c
index cfaa54ced0d0..d9268d150e1f 100644
--- a/drivers/power/reset/keystone-reset.c
+++ b/drivers/power/reset/keystone-reset.c
@@ -87,26 +87,16 @@ static int rsctrl_probe(struct platform_device *pdev)
return -ENODEV;
/* get regmaps */
- pllctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pll");
+ pllctrl_regs = syscon_regmap_lookup_by_phandle_args(np, "ti,syscon-pll",
+ 1, &rspll_offset);
if (IS_ERR(pllctrl_regs))
return PTR_ERR(pllctrl_regs);
- devctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
+ devctrl_regs = syscon_regmap_lookup_by_phandle_args(np, "ti,syscon-dev",
+ 1, &rsmux_offset);
if (IS_ERR(devctrl_regs))
return PTR_ERR(devctrl_regs);
- ret = of_property_read_u32_index(np, "ti,syscon-pll", 1, &rspll_offset);
- if (ret) {
- dev_err(dev, "couldn't read the reset pll offset!\n");
- return -EINVAL;
- }
-
- ret = of_property_read_u32_index(np, "ti,syscon-dev", 1, &rsmux_offset);
- if (ret) {
- dev_err(dev, "couldn't read the rsmux offset!\n");
- return -EINVAL;
- }
-
/* set soft/hard reset */
val = of_property_read_bool(np, "ti,soft-reset");
val = val ? RSCFG_RSTYPE_SOFT : RSCFG_RSTYPE_HARD;
diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c
index 1a6fc8d38e20..90c664d344d0 100644
--- a/drivers/power/reset/ltc2952-poweroff.c
+++ b/drivers/power/reset/ltc2952-poweroff.c
@@ -162,11 +162,11 @@ static void ltc2952_poweroff_default(struct ltc2952_poweroff *data)
data->wde_interval = 300L * NSEC_PER_MSEC;
data->trigger_delay = ktime_set(2, 500L * NSEC_PER_MSEC);
- hrtimer_init(&data->timer_trigger, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- data->timer_trigger.function = ltc2952_poweroff_timer_trigger;
+ hrtimer_setup(&data->timer_trigger, ltc2952_poweroff_timer_trigger, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
- hrtimer_init(&data->timer_wde, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- data->timer_wde.function = ltc2952_poweroff_timer_wde;
+ hrtimer_setup(&data->timer_wde, ltc2952_poweroff_timer_wde, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
}
static int ltc2952_poweroff_init(struct platform_device *pdev)
diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c
index 682a9beac69e..e8f5030f2639 100644
--- a/drivers/power/sequencing/pwrseq-qcom-wcn.c
+++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c
@@ -272,6 +272,24 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_qca6390_of_data = {
.targets = pwrseq_qcom_wcn_targets,
};
+static const char *const pwrseq_wcn6750_vregs[] = {
+ "vddaon",
+ "vddasd",
+ "vddpmu",
+ "vddrfa0p8",
+ "vddrfa1p2",
+ "vddrfa1p7",
+ "vddrfa2p2",
+};
+
+static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn6750_of_data = {
+ .vregs = pwrseq_wcn6750_vregs,
+ .num_vregs = ARRAY_SIZE(pwrseq_wcn6750_vregs),
+ .pwup_delay_ms = 50,
+ .gpio_enable_delay_ms = 5,
+ .targets = pwrseq_qcom_wcn_targets,
+};
+
static const char *const pwrseq_wcn6855_vregs[] = {
"vddio",
"vddaon",
@@ -378,6 +396,13 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(ctx->bt_gpio),
"Failed to get the Bluetooth enable GPIO\n");
+ /*
+ * FIXME: This should actually be GPIOD_OUT_LOW, but doing so would
+ * cause the WLAN power to be toggled, resulting in PCIe link down.
+ * Since the PCIe controller driver is not handling link down currently,
+ * the device becomes unusable. So we need to keep this workaround until
+ * the link down handling is implemented in the controller driver.
+ */
ctx->wlan_gpio = devm_gpiod_get_optional(dev, "wlan-enable",
GPIOD_ASIS);
if (IS_ERR(ctx->wlan_gpio))
@@ -431,6 +456,10 @@ static const struct of_device_id pwrseq_qcom_wcn_of_match[] = {
.compatible = "qcom,wcn7850-pmu",
.data = &pwrseq_wcn7850_of_data,
},
+ {
+ .compatible = "qcom,wcn6750-pmu",
+ .data = &pwrseq_wcn6750_of_data,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, pwrseq_qcom_wcn_of_match);
diff --git a/drivers/power/supply/88pm860x_battery.c b/drivers/power/supply/88pm860x_battery.c
index b7938fbb24a5..edae1e843c51 100644
--- a/drivers/power/supply/88pm860x_battery.c
+++ b/drivers/power/supply/88pm860x_battery.c
@@ -14,6 +14,7 @@
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/power_supply.h>
+#include <linux/string_choices.h>
#include <linux/mfd/88pm860x.h>
#include <linux/delay.h>
@@ -503,8 +504,7 @@ static void pm860x_init_battery(struct pm860x_battery_info *info)
data = pm860x_reg_read(info->i2c, PM8607_POWER_UP_LOG);
bat_remove = data & BAT_WU_LOG;
- dev_dbg(info->dev, "battery wake up? %s\n",
- bat_remove != 0 ? "yes" : "no");
+ dev_dbg(info->dev, "battery wake up? %s\n", str_yes_no(bat_remove));
/* restore SOC from RTC domain register */
if (bat_remove == 0) {
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 9f2eef6787f7..8dbd39afa43c 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -449,12 +449,6 @@ config CHARGER_88PM860X
help
Say Y here to enable charger for Marvell 88PM860x chip.
-config CHARGER_PCF50633
- tristate "NXP PCF50633 MBC"
- depends on MFD_PCF50633
- help
- Say Y to include support for NXP PCF50633 Main Battery Charger.
-
config BATTERY_RX51
tristate "Nokia RX-51 (N900) battery driver"
depends on TWL4030_MADC
@@ -583,6 +577,12 @@ config CHARGER_MAX77693
help
Say Y to enable support for the Maxim MAX77693 battery charger.
+config CHARGER_MAX77705
+ tristate "Maxim MAX77705 battery charger driver"
+ depends on MFD_MAX77705
+ help
+ Say Y to enable support for the Maxim MAX77705 battery charger.
+
config CHARGER_MAX77976
tristate "Maxim MAX77976 battery charger driver"
depends on I2C
@@ -918,6 +918,15 @@ config FUEL_GAUGE_SC27XX
Say Y here to enable support for fuel gauge with SC27XX
PMIC chips.
+config FUEL_GAUGE_STC3117
+ tristate "STMicroelectronics STC3117 fuel gauge driver"
+ depends on CRC8
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y here to enable support for fuel gauge with STC3117
+ chip.
+
config CHARGER_UCS1002
tristate "Microchip UCS1002 USB Port Power Controller"
depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 59c4a9f40d28..61677be328b0 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -62,7 +62,6 @@ obj-$(CONFIG_CHARGER_RT9467) += rt9467-charger.o
obj-$(CONFIG_CHARGER_RT9471) += rt9471.o
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
-obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o ab8500_chargalg.o
obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o
@@ -80,6 +79,7 @@ obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o
obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
+obj-$(CONFIG_CHARGER_MAX77705) += max77705_charger.o
obj-$(CONFIG_CHARGER_MAX77976) += max77976_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
@@ -108,6 +108,7 @@ obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o
obj-$(CONFIG_CHARGER_CROS_PCHG) += cros_peripheral_charger.o
obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
+obj-$(CONFIG_FUEL_GAUGE_STC3117) += stc3117_fuel_gauge.o
obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o
obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c
index 37039e28fc4b..b00c84fbc33c 100644
--- a/drivers/power/supply/ab8500_btemp.c
+++ b/drivers/power/supply/ab8500_btemp.c
@@ -540,10 +540,9 @@ static int ab8500_btemp_get_property(struct power_supply *psy,
return 0;
}
-static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data)
+static int ab8500_btemp_get_ext_psy_data(struct power_supply *ext, void *data)
{
struct power_supply *psy;
- struct power_supply *ext = dev_get_drvdata(dev);
const char **supplicants = (const char **)ext->supplied_to;
struct ab8500_btemp *di;
union power_supply_propval ret;
@@ -617,7 +616,7 @@ static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data)
*/
static void ab8500_btemp_external_power_changed(struct power_supply *psy)
{
- power_supply_for_each_device(psy, ab8500_btemp_get_ext_psy_data);
+ power_supply_for_each_psy(psy, ab8500_btemp_get_ext_psy_data);
}
/* ab8500 btemp driver interrupts and their respective isr */
diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c
index 14e1b448bd39..dc6c8b0dd1cf 100644
--- a/drivers/power/supply/ab8500_chargalg.c
+++ b/drivers/power/supply/ab8500_chargalg.c
@@ -844,10 +844,9 @@ static void handle_maxim_chg_curr(struct ab8500_chargalg *di)
}
}
-static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data)
+static int ab8500_chargalg_get_ext_psy_data(struct power_supply *ext, void *data)
{
struct power_supply *psy;
- struct power_supply *ext = dev_get_drvdata(dev);
const char **supplicants = (const char **)ext->supplied_to;
struct ab8500_chargalg *di;
union power_supply_propval ret;
@@ -1231,7 +1230,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
int ret;
/* Collect data from all power_supply class devices */
- power_supply_for_each_device(di->chargalg_psy, ab8500_chargalg_get_ext_psy_data);
+ power_supply_for_each_psy(di->chargalg_psy, ab8500_chargalg_get_ext_psy_data);
ab8500_chargalg_end_of_charge(di);
ab8500_chargalg_check_temp(di);
@@ -1788,13 +1787,12 @@ static int ab8500_chargalg_probe(struct platform_device *pdev)
psy_cfg.drv_data = di;
/* Initilialize safety timer */
- hrtimer_init(&di->safety_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- di->safety_timer.function = ab8500_chargalg_safety_timer_expired;
+ hrtimer_setup(&di->safety_timer, ab8500_chargalg_safety_timer_expired, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
/* Initilialize maintenance timer */
- hrtimer_init(&di->maintenance_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- di->maintenance_timer.function =
- ab8500_chargalg_maintenance_timer_expired;
+ hrtimer_setup(&di->maintenance_timer, ab8500_chargalg_maintenance_timer_expired,
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL);
/* Init work for chargalg */
INIT_DEFERRABLE_WORK(&di->chargalg_periodic_work,
diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c
index cece8d6753ac..5f4537766e5b 100644
--- a/drivers/power/supply/ab8500_charger.c
+++ b/drivers/power/supply/ab8500_charger.c
@@ -1894,10 +1894,9 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger,
return ret;
}
-static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data)
+static int ab8500_charger_get_ext_psy_data(struct power_supply *ext, void *data)
{
struct power_supply *psy;
- struct power_supply *ext = dev_get_drvdata(dev);
const char **supplicants = (const char **)ext->supplied_to;
struct ab8500_charger *di;
union power_supply_propval ret;
@@ -1961,7 +1960,7 @@ static void ab8500_charger_check_vbat_work(struct work_struct *work)
struct ab8500_charger *di = container_of(work,
struct ab8500_charger, check_vbat_work.work);
- power_supply_for_each_device(&di->usb_chg, ab8500_charger_get_ext_psy_data);
+ power_supply_for_each_psy(&di->usb_chg, ab8500_charger_get_ext_psy_data);
/* First run old_vbat is 0. */
if (di->old_vbat == 0)
@@ -3495,11 +3494,11 @@ static int ab8500_charger_probe(struct platform_device *pdev)
di->invalid_charger_detect_state = 0;
/* AC and USB supply config */
- ac_psy_cfg.of_node = np;
+ ac_psy_cfg.fwnode = dev_fwnode(dev);
ac_psy_cfg.supplied_to = supply_interface;
ac_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
ac_psy_cfg.drv_data = &di->ac_chg;
- usb_psy_cfg.of_node = np;
+ usb_psy_cfg.fwnode = dev_fwnode(dev);
usb_psy_cfg.supplied_to = supply_interface;
usb_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
usb_psy_cfg.drv_data = &di->usb_chg;
diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c
index 78871a2143de..9dd99722667a 100644
--- a/drivers/power/supply/ab8500_fg.c
+++ b/drivers/power/supply/ab8500_fg.c
@@ -2174,10 +2174,9 @@ static int ab8500_fg_get_property(struct power_supply *psy,
return 0;
}
-static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
+static int ab8500_fg_get_ext_psy_data(struct power_supply *ext, void *data)
{
struct power_supply *psy;
- struct power_supply *ext = dev_get_drvdata(dev);
const char **supplicants = (const char **)ext->supplied_to;
struct ab8500_fg *di;
struct power_supply_battery_info *bi;
@@ -2402,7 +2401,7 @@ out:
*/
static void ab8500_fg_external_power_changed(struct power_supply *psy)
{
- power_supply_for_each_device(psy, ab8500_fg_get_ext_psy_data);
+ power_supply_for_each_psy(psy, ab8500_fg_get_ext_psy_data);
}
/**
@@ -2575,7 +2574,7 @@ static ssize_t ab8505_powercut_flagtime_read(struct device *dev,
{
int ret;
u8 reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
@@ -2598,7 +2597,7 @@ static ssize_t ab8505_powercut_flagtime_write(struct device *dev,
{
int ret;
int reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
if (kstrtoint(buf, 10, &reg_value))
@@ -2625,7 +2624,7 @@ static ssize_t ab8505_powercut_maxtime_read(struct device *dev,
{
int ret;
u8 reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
@@ -2649,7 +2648,7 @@ static ssize_t ab8505_powercut_maxtime_write(struct device *dev,
{
int ret;
int reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
if (kstrtoint(buf, 10, &reg_value))
@@ -2676,7 +2675,7 @@ static ssize_t ab8505_powercut_restart_read(struct device *dev,
{
int ret;
u8 reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
@@ -2699,7 +2698,7 @@ static ssize_t ab8505_powercut_restart_write(struct device *dev,
{
int ret;
int reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
if (kstrtoint(buf, 10, &reg_value))
@@ -2727,7 +2726,7 @@ static ssize_t ab8505_powercut_timer_read(struct device *dev,
{
int ret;
u8 reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
@@ -2750,7 +2749,7 @@ static ssize_t ab8505_powercut_restart_counter_read(struct device *dev,
{
int ret;
u8 reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
@@ -2773,7 +2772,7 @@ static ssize_t ab8505_powercut_read(struct device *dev,
{
int ret;
u8 reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
@@ -2794,7 +2793,7 @@ static ssize_t ab8505_powercut_write(struct device *dev,
{
int ret;
int reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
if (kstrtoint(buf, 10, &reg_value))
@@ -2822,7 +2821,7 @@ static ssize_t ab8505_powercut_flag_read(struct device *dev,
int ret;
u8 reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
@@ -2845,7 +2844,7 @@ static ssize_t ab8505_powercut_debounce_read(struct device *dev,
{
int ret;
u8 reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
@@ -2868,7 +2867,7 @@ static ssize_t ab8505_powercut_debounce_write(struct device *dev,
{
int ret;
int reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
if (kstrtoint(buf, 10, &reg_value))
@@ -2895,7 +2894,7 @@ static ssize_t ab8505_powercut_enable_status_read(struct device *dev,
{
int ret;
u8 reg_value;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
diff --git a/drivers/power/supply/acer_a500_battery.c b/drivers/power/supply/acer_a500_battery.c
index 39d85b11a13c..daf01dc8025b 100644
--- a/drivers/power/supply/acer_a500_battery.c
+++ b/drivers/power/supply/acer_a500_battery.c
@@ -17,6 +17,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
+#include <linux/property.h>
enum {
REG_CAPACITY,
@@ -231,7 +232,7 @@ static int a500_battery_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bat);
- psy_cfg.of_node = pdev->dev.parent->of_node;
+ psy_cfg.fwnode = dev_fwnode(pdev->dev.parent);
psy_cfg.drv_data = bat;
psy_cfg.no_wakeup_source = true;
diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c
index b2b82f97a471..3901a02f326a 100644
--- a/drivers/power/supply/act8945a_charger.c
+++ b/drivers/power/supply/act8945a_charger.c
@@ -614,7 +614,7 @@ static int act8945a_charger_probe(struct platform_device *pdev)
if (ret)
return -EINVAL;
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = charger;
charger->psy = devm_power_supply_register(&pdev->dev,
diff --git a/drivers/power/supply/apm_power.c b/drivers/power/supply/apm_power.c
index 8ef1b6f1f787..9236e0078578 100644
--- a/drivers/power/supply/apm_power.c
+++ b/drivers/power/supply/apm_power.c
@@ -42,11 +42,11 @@ struct find_bat_param {
int max_energy;
};
-static int __find_main_battery(struct device *dev, void *data)
+static int __find_main_battery(struct power_supply *psy, void *data)
{
struct find_bat_param *bp = (struct find_bat_param *)data;
- bp->bat = dev_get_drvdata(dev);
+ bp->bat = psy;
if (bp->bat->desc->use_for_apm) {
/* nice, we explicitly asked to report this battery. */
@@ -79,7 +79,7 @@ static void find_main_battery(void)
main_battery = NULL;
bp.main = main_battery;
- error = power_supply_for_each_device(&bp, __find_main_battery);
+ error = power_supply_for_each_psy(&bp, __find_main_battery);
if (error) {
main_battery = bp.main;
return;
diff --git a/drivers/power/supply/axp20x_ac_power.c b/drivers/power/supply/axp20x_ac_power.c
index e5733cb9e19e..5f6ea416fa30 100644
--- a/drivers/power/supply/axp20x_ac_power.c
+++ b/drivers/power/supply/axp20x_ac_power.c
@@ -364,7 +364,7 @@ static int axp20x_ac_power_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, power);
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = power;
power->supply = devm_power_supply_register(&pdev->dev,
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
index 3c3158f31a48..50ca8e110085 100644
--- a/drivers/power/supply/axp20x_battery.c
+++ b/drivers/power/supply/axp20x_battery.c
@@ -89,6 +89,8 @@
#define AXP717_BAT_CC_MIN_UA 0
#define AXP717_BAT_CC_MAX_UA 3008000
+#define AXP717_TS_PIN_DISABLE BIT(4)
+
struct axp20x_batt_ps;
struct axp_data {
@@ -117,6 +119,7 @@ struct axp20x_batt_ps {
/* Maximum constant charge current */
unsigned int max_ccc;
const struct axp_data *data;
+ bool ts_disable;
};
static int axp20x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
@@ -984,6 +987,24 @@ static void axp717_set_battery_info(struct platform_device *pdev,
int ccc = info->constant_charge_current_max_ua;
int val;
+ axp_batt->ts_disable = (device_property_read_bool(axp_batt->dev,
+ "x-powers,no-thermistor"));
+
+ /*
+ * Under rare conditions an incorrectly programmed efuse for
+ * the temp sensor on the PMIC may trigger a fault condition.
+ * Allow users to hard-code if the ts pin is not used to work
+ * around this problem. Note that this requires the battery
+ * be correctly defined in the device tree with a monitored
+ * battery node.
+ */
+ if (axp_batt->ts_disable) {
+ regmap_update_bits(axp_batt->regmap,
+ AXP717_TS_PIN_CFG,
+ AXP717_TS_PIN_DISABLE,
+ AXP717_TS_PIN_DISABLE);
+ }
+
if (vmin > 0 && axp717_set_voltage_min_design(axp_batt, vmin))
dev_err(&pdev->dev,
"couldn't set voltage_min_design\n");
@@ -1090,7 +1111,7 @@ static int axp20x_power_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, axp20x_batt);
psy_cfg.drv_data = axp20x_batt;
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
axp20x_batt->data = (struct axp_data *)of_device_get_match_data(dev);
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index 9722912268fe..e75d1e377ac1 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -492,7 +492,7 @@ static int axp717_usb_power_set_input_current_limit(struct axp20x_usb_power *pow
if (power->max_input_cur && (intval > power->max_input_cur)) {
dev_warn(power->dev,
- "reqested current %d clamped to max current %d\n",
+ "requested current %d clamped to max current %d\n",
intval, power->max_input_cur);
intval = power->max_input_cur;
}
@@ -1011,7 +1011,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
return ret;
}
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = power;
power->supply = devm_power_supply_register(&pdev->dev,
diff --git a/drivers/power/supply/bd99954-charger.c b/drivers/power/supply/bd99954-charger.c
index 54bf88262510..d03a70cf8406 100644
--- a/drivers/power/supply/bd99954-charger.c
+++ b/drivers/power/supply/bd99954-charger.c
@@ -156,7 +156,7 @@ static const struct regmap_config bd9995x_regmap_config = {
.reg_stride = 1,
.max_register = 3 * 0x100,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.ranges = regmap_range_cfg,
.num_ranges = ARRAY_SIZE(regmap_range_cfg),
@@ -982,7 +982,7 @@ static int bd9995x_probe(struct i2c_client *client)
bd->client = client;
bd->dev = dev;
psy_cfg.drv_data = bd;
- psy_cfg.of_node = dev->of_node;
+ psy_cfg.fwnode = dev_fwnode(dev);
mutex_init(&bd->lock);
diff --git a/drivers/power/supply/bq2415x_charger.c b/drivers/power/supply/bq2415x_charger.c
index 25e28dac900d..9e3b9181ee76 100644
--- a/drivers/power/supply/bq2415x_charger.c
+++ b/drivers/power/supply/bq2415x_charger.c
@@ -171,6 +171,7 @@ struct bq2415x_device {
char *name;
int autotimer; /* 1 - if driver automatically reset timer, 0 - not */
int automode; /* 1 - enabled, 0 - disabled; -1 - not supported */
+ int charge_status;
int id;
};
@@ -835,11 +836,13 @@ static int bq2415x_notifier_call(struct notifier_block *nb,
if (!bq2415x_update_reported_mode(bq, prop.intval))
return NOTIFY_OK;
+ power_supply_changed(bq->charger);
+
/* if automode is not enabled do not tell about reported_mode */
if (bq->automode < 1)
return NOTIFY_OK;
- schedule_delayed_work(&bq->work, 0);
+ mod_delayed_work(system_wq, &bq->work, 0);
return NOTIFY_OK;
}
@@ -889,12 +892,19 @@ static void bq2415x_timer_work(struct work_struct *work)
int ret;
int error;
int boost;
+ int charge;
if (bq->automode > 0 && (bq->reported_mode != bq->mode)) {
sysfs_notify(&bq->charger->dev.kobj, NULL, "reported_mode");
bq2415x_set_mode(bq, bq->reported_mode);
}
+ charge = bq2415x_exec_command(bq, BQ2415X_CHARGE_STATUS);
+ if (bq->charge_status != charge) {
+ power_supply_changed(bq->charger);
+ bq->charge_status = charge;
+ }
+
if (!bq->autotimer)
return;
@@ -1050,7 +1060,7 @@ static ssize_t bq2415x_sysfs_show_status(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
enum bq2415x_command command;
int ret;
@@ -1083,7 +1093,7 @@ static ssize_t bq2415x_sysfs_set_timer(struct device *dev,
const char *buf,
size_t count)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
int ret = 0;
@@ -1104,7 +1114,7 @@ static ssize_t bq2415x_sysfs_show_timer(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
if (bq->timer_error)
@@ -1128,7 +1138,7 @@ static ssize_t bq2415x_sysfs_set_mode(struct device *dev,
const char *buf,
size_t count)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
enum bq2415x_mode mode;
int ret = 0;
@@ -1180,7 +1190,7 @@ static ssize_t bq2415x_sysfs_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
ssize_t ret = 0;
@@ -1217,7 +1227,7 @@ static ssize_t bq2415x_sysfs_show_reported_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
if (bq->automode < 0)
@@ -1245,7 +1255,7 @@ static ssize_t bq2415x_sysfs_set_registers(struct device *dev,
const char *buf,
size_t count)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
ssize_t ret = 0;
unsigned int reg;
@@ -1280,7 +1290,7 @@ static ssize_t bq2415x_sysfs_show_registers(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
ssize_t ret = 0;
@@ -1298,7 +1308,7 @@ static ssize_t bq2415x_sysfs_set_limit(struct device *dev,
const char *buf,
size_t count)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
long val;
int ret;
@@ -1329,7 +1339,7 @@ static ssize_t bq2415x_sysfs_show_limit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
int ret;
@@ -1357,7 +1367,7 @@ static ssize_t bq2415x_sysfs_set_enable(struct device *dev,
const char *buf,
size_t count)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
enum bq2415x_command command;
long val;
@@ -1392,7 +1402,7 @@ static ssize_t bq2415x_sysfs_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
enum bq2415x_command command;
int ret;
@@ -1487,7 +1497,7 @@ static int bq2415x_power_supply_init(struct bq2415x_device *bq)
char revstr[8];
struct power_supply_config psy_cfg = {
.drv_data = bq,
- .of_node = bq->dev->of_node,
+ .fwnode = dev_fwnode(bq->dev),
.attr_grp = bq2415x_sysfs_groups,
};
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index c47f32f152e6..f0d97ab45bd8 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -152,6 +152,7 @@
#define BQ24296_REG_VPRS_PN_MASK (BIT(7) | BIT(6) | BIT(5))
#define BQ24296_REG_VPRS_PN_SHIFT 5
#define BQ24296_REG_VPRS_PN_24296 0x1
+#define BQ24296_REG_VPRS_PN_24297 0x3
#define BQ24190_REG_VPRS_TS_PROFILE_MASK BIT(2)
#define BQ24190_REG_VPRS_TS_PROFILE_SHIFT 2
#define BQ24190_REG_VPRS_DEV_REG_MASK (BIT(1) | BIT(0))
@@ -208,6 +209,7 @@ enum bq24190_chip {
BQ24192i,
BQ24196,
BQ24296,
+ BQ24297,
};
/*
@@ -422,7 +424,7 @@ static struct bq24190_sysfs_field_info bq24190_sysfs_field_tbl[] = {
BQ24190_SYSFS_FIELD_RO(watchdog, CTTC, WATCHDOG),
BQ24190_SYSFS_FIELD_RW(en_timer, CTTC, EN_TIMER),
BQ24190_SYSFS_FIELD_RW(chg_timer, CTTC, CHG_TIMER),
- BQ24190_SYSFS_FIELD_RW(jeta_iset, CTTC, JEITA_ISET),
+ BQ24190_SYSFS_FIELD_RW(jeita_iset, CTTC, JEITA_ISET),
BQ24190_SYSFS_FIELD_RW(bat_comp, ICTRC, BAT_COMP),
BQ24190_SYSFS_FIELD_RW(vclamp, ICTRC, VCLAMP),
BQ24190_SYSFS_FIELD_RW(treg, ICTRC, TREG),
@@ -480,7 +482,7 @@ static struct bq24190_sysfs_field_info *bq24190_sysfs_field_lookup(
static ssize_t bq24190_sysfs_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
struct bq24190_sysfs_field_info *info;
ssize_t count;
@@ -510,7 +512,7 @@ static ssize_t bq24190_sysfs_show(struct device *dev,
static ssize_t bq24190_sysfs_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
struct bq24190_sysfs_field_info *info;
int ret;
@@ -1319,6 +1321,7 @@ static int bq24190_charger_get_property(struct power_supply *psy,
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ case POWER_SUPPLY_PROP_CHARGE_TYPES:
ret = bq24190_charger_get_charge_type(bdi, val);
break;
case POWER_SUPPLY_PROP_HEALTH:
@@ -1399,6 +1402,7 @@ static int bq24190_charger_set_property(struct power_supply *psy,
ret = bq24190_charger_set_temp_alert_max(bdi, val);
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ case POWER_SUPPLY_PROP_CHARGE_TYPES:
ret = bq24190_charger_set_charge_type(bdi, val);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
@@ -1427,6 +1431,7 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy,
case POWER_SUPPLY_PROP_ONLINE:
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ case POWER_SUPPLY_PROP_CHARGE_TYPES:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
@@ -1475,6 +1480,7 @@ static void bq24190_charger_external_power_changed(struct power_supply *psy)
static enum power_supply_property bq24190_charger_properties[] = {
POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_CHARGE_TYPES,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_STATUS,
@@ -1504,6 +1510,9 @@ static const struct power_supply_desc bq24190_charger_desc = {
.set_property = bq24190_charger_set_property,
.property_is_writeable = bq24190_charger_property_is_writeable,
.external_power_changed = bq24190_charger_external_power_changed,
+ .charge_types = BIT(POWER_SUPPLY_CHARGE_TYPE_NONE) |
+ BIT(POWER_SUPPLY_CHARGE_TYPE_TRICKLE) |
+ BIT(POWER_SUPPLY_CHARGE_TYPE_FAST),
};
/* Battery power supply property routines */
@@ -1897,6 +1906,7 @@ static int bq24296_check_chip(struct bq24190_dev_info *bdi)
switch (v) {
case BQ24296_REG_VPRS_PN_24296:
+ case BQ24296_REG_VPRS_PN_24297:
break;
default:
dev_err(bdi->dev, "Error unknown model: 0x%02x\n", v);
@@ -2033,6 +2043,17 @@ static const struct bq24190_chip_info bq24190_chip_info_tbl[] = {
.get_ntc_status = bq24296_charger_get_ntc_status,
.set_otg_vbus = bq24296_set_otg_vbus,
},
+ [BQ24297] = {
+ .ichg_array_size = BQ24296_CCC_ICHG_VALUES_LEN,
+#ifdef CONFIG_REGULATOR
+ .vbus_desc = &bq24296_vbus_desc,
+#endif
+ .check_chip = bq24296_check_chip,
+ .set_chg_config = bq24296_battery_set_chg_config,
+ .ntc_fault_mask = BQ24296_REG_F_NTC_FAULT_MASK,
+ .get_ntc_status = bq24296_charger_get_ntc_status,
+ .set_otg_vbus = bq24296_set_otg_vbus,
+ },
};
static int bq24190_probe(struct i2c_client *client)
@@ -2096,7 +2117,7 @@ static int bq24190_probe(struct i2c_client *client)
#endif
charger_cfg.drv_data = bdi;
- charger_cfg.of_node = dev->of_node;
+ charger_cfg.fwnode = dev_fwnode(dev);
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,
@@ -2289,6 +2310,7 @@ static const struct i2c_device_id bq24190_i2c_ids[] = {
{ "bq24192i", (kernel_ulong_t)&bq24190_chip_info_tbl[BQ24192i] },
{ "bq24196", (kernel_ulong_t)&bq24190_chip_info_tbl[BQ24196] },
{ "bq24296", (kernel_ulong_t)&bq24190_chip_info_tbl[BQ24296] },
+ { "bq24297", (kernel_ulong_t)&bq24190_chip_info_tbl[BQ24297] },
{ },
};
MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
@@ -2299,6 +2321,7 @@ static const struct of_device_id bq24190_of_match[] = {
{ .compatible = "ti,bq24192i", .data = &bq24190_chip_info_tbl[BQ24192i] },
{ .compatible = "ti,bq24196", .data = &bq24190_chip_info_tbl[BQ24196] },
{ .compatible = "ti,bq24296", .data = &bq24190_chip_info_tbl[BQ24296] },
+ { .compatible = "ti,bq24297", .data = &bq24190_chip_info_tbl[BQ24297] },
{ },
};
MODULE_DEVICE_TABLE(of, bq24190_of_match);
diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c
index 801d0d2c5f2e..766eecb35694 100644
--- a/drivers/power/supply/bq24257_charger.c
+++ b/drivers/power/supply/bq24257_charger.c
@@ -113,7 +113,7 @@ static const struct regmap_config bq24257_regmap_config = {
.val_bits = 8,
.max_register = BQ24257_REG_7,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = bq24257_is_volatile_reg,
};
@@ -759,7 +759,7 @@ static ssize_t bq24257_show_ovp_voltage(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
return sysfs_emit(buf, "%u\n", bq24257_vovp_map[bq->init_data.vovp]);
@@ -769,7 +769,7 @@ static ssize_t bq24257_show_in_dpm_voltage(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
return sysfs_emit(buf, "%u\n", bq24257_vindpm_map[bq->init_data.vindpm]);
@@ -779,7 +779,7 @@ static ssize_t bq24257_sysfs_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
int ret;
@@ -801,7 +801,7 @@ static ssize_t bq24257_sysfs_set_enable(struct device *dev,
const char *buf,
size_t count)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
long val;
int ret;
diff --git a/drivers/power/supply/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c
index 73a7fc867b03..637e0da65f87 100644
--- a/drivers/power/supply/bq24735-charger.c
+++ b/drivers/power/supply/bq24735-charger.c
@@ -402,7 +402,7 @@ static int bq24735_charger_probe(struct i2c_client *client)
psy_cfg.supplied_to = charger->pdata->supplied_to;
psy_cfg.num_supplicants = charger->pdata->num_supplicants;
- psy_cfg.of_node = client->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&client->dev);
psy_cfg.drv_data = charger;
i2c_set_clientdata(client, charger);
diff --git a/drivers/power/supply/bq2515x_charger.c b/drivers/power/supply/bq2515x_charger.c
index a3424f67f2b1..437bff5bc420 100644
--- a/drivers/power/supply/bq2515x_charger.c
+++ b/drivers/power/supply/bq2515x_charger.c
@@ -1060,7 +1060,7 @@ static const struct regmap_config bq25150_regmap_config = {
.max_register = BQ2515X_DEVICE_ID,
.reg_defaults = bq25150_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(bq25150_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = bq2515x_volatile_register,
};
@@ -1071,7 +1071,7 @@ static const struct regmap_config bq25155_regmap_config = {
.max_register = BQ2515X_DEVICE_ID,
.reg_defaults = bq25155_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(bq25155_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = bq2515x_volatile_register,
};
@@ -1102,7 +1102,7 @@ static int bq2515x_probe(struct i2c_client *client)
i2c_set_clientdata(client, bq2515x);
charger_cfg.drv_data = bq2515x;
- charger_cfg.of_node = dev->of_node;
+ charger_cfg.fwnode = dev_fwnode(dev);
ret = bq2515x_read_properties(bq2515x);
if (ret) {
diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c
index 5514d1896bb8..9f9b6019f8e1 100644
--- a/drivers/power/supply/bq256xx_charger.c
+++ b/drivers/power/supply/bq256xx_charger.c
@@ -1657,7 +1657,7 @@ static int bq256xx_parse_dt(struct bq256xx_device *bq,
int ret = 0;
psy_cfg->drv_data = bq;
- psy_cfg->of_node = dev->of_node;
+ psy_cfg->fwnode = dev_fwnode(dev);
ret = device_property_read_u32(bq->dev, "ti,watchdog-timeout-ms",
&bq->watchdog_timer);
diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c
index 2f5ceaf00b94..868e86e1749b 100644
--- a/drivers/power/supply/bq25890_charger.c
+++ b/drivers/power/supply/bq25890_charger.c
@@ -164,7 +164,7 @@ static const struct regmap_config bq25890_regmap_config = {
.val_bits = 8,
.max_register = 0x14,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.wr_table = &bq25890_writeable_regs,
.volatile_table = &bq25890_volatile_regs,
diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c
index 0c5e2938bb36..4ff76e3dddf6 100644
--- a/drivers/power/supply/bq25980_charger.c
+++ b/drivers/power/supply/bq25980_charger.c
@@ -932,7 +932,7 @@ static const struct regmap_config bq25980_regmap_config = {
.max_register = BQ25980_CHRGR_CTRL_6,
.reg_defaults = bq25980_reg_defs,
.num_reg_defaults = ARRAY_SIZE(bq25980_reg_defs),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = bq25980_is_volatile_reg,
};
@@ -943,7 +943,7 @@ static const struct regmap_config bq25975_regmap_config = {
.max_register = BQ25980_CHRGR_CTRL_6,
.reg_defaults = bq25975_reg_defs,
.num_reg_defaults = ARRAY_SIZE(bq25975_reg_defs),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = bq25980_is_volatile_reg,
};
@@ -954,7 +954,7 @@ static const struct regmap_config bq25960_regmap_config = {
.max_register = BQ25980_CHRGR_CTRL_6,
.reg_defaults = bq25960_reg_defs,
.num_reg_defaults = ARRAY_SIZE(bq25960_reg_defs),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = bq25980_is_volatile_reg,
};
@@ -1057,7 +1057,7 @@ static int bq25980_power_supply_init(struct bq25980_device *bq,
struct device *dev)
{
struct power_supply_config psy_cfg = { .drv_data = bq,
- .of_node = dev->of_node, };
+ .fwnode = dev_fwnode(dev), };
psy_cfg.supplied_to = bq25980_charger_supplied_to;
psy_cfg.num_supplicants = ARRAY_SIZE(bq25980_charger_supplied_to);
diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index 40c5ac7a1118..93dcebbe1141 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -123,6 +123,8 @@ enum bq27xxx_reg_index {
BQ27XXX_DM_BLOCK, /* Data Block */
BQ27XXX_DM_DATA, /* Block Data */
BQ27XXX_DM_CKSUM, /* Block Data Checksum */
+ BQ27XXX_REG_SEDVF, /* End-of-discharge Voltage */
+ BQ27XXX_REG_PKCFG, /* Pack Configuration */
BQ27XXX_REG_MAX, /* sentinel */
};
@@ -159,6 +161,8 @@ static u8
[BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
[BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
[BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
+ [BQ27XXX_REG_SEDVF] = 0x77,
+ [BQ27XXX_REG_PKCFG] = 0x7C,
},
bq27010_regs[BQ27XXX_REG_MAX] = {
[BQ27XXX_REG_CTRL] = 0x00,
@@ -184,6 +188,8 @@ static u8
[BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
[BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
[BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
+ [BQ27XXX_REG_SEDVF] = 0x77,
+ [BQ27XXX_REG_PKCFG] = 0x7C,
},
bq2750x_regs[BQ27XXX_REG_MAX] = {
[BQ27XXX_REG_CTRL] = 0x00,
@@ -579,6 +585,8 @@ static enum power_supply_property bq27000_props[] = {
POWER_SUPPLY_PROP_POWER_AVG,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
};
static enum power_supply_property bq27010_props[] = {
@@ -599,6 +607,8 @@ static enum power_supply_property bq27010_props[] = {
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
};
#define bq2750x_props bq27510g3_props
@@ -1913,7 +1923,6 @@ static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di)
cache.flags = -1; /* read error */
if (cache.flags >= 0) {
cache.capacity = bq27xxx_battery_read_soc(di);
- di->cache.flags = cache.flags;
/*
* On gauges with signed current reporting the current must be
@@ -2039,6 +2048,65 @@ static int bq27xxx_battery_voltage(struct bq27xxx_device_info *di,
return 0;
}
+/*
+ * Return the design maximum battery Voltage in microvolts, or < 0 if something
+ * fails. The programmed value of the maximum battery voltage is determined by
+ * QV0 and QV1 (bits 5 and 6) in the Pack Configuration register.
+ */
+static int bq27xxx_battery_read_dmax_volt(struct bq27xxx_device_info *di,
+ union power_supply_propval *val)
+{
+ int reg_val, qv;
+
+ if (di->voltage_max_design > 0) {
+ val->intval = di->voltage_max_design;
+ return 0;
+ }
+
+ reg_val = bq27xxx_read(di, BQ27XXX_REG_PKCFG, true);
+ if (reg_val < 0) {
+ dev_err(di->dev, "error reading design max voltage\n");
+ return reg_val;
+ }
+
+ qv = (reg_val >> 5) & 0x3;
+ val->intval = 3968000 + 48000 * qv;
+
+ di->voltage_max_design = val->intval;
+
+ return 0;
+}
+
+/*
+ * Return the design minimum battery Voltage in microvolts
+ * Or < 0 if something fails.
+ */
+static int bq27xxx_battery_read_dmin_volt(struct bq27xxx_device_info *di,
+ union power_supply_propval *val)
+{
+ int volt;
+
+ /* We only have to read design minimum voltage once */
+ if (di->voltage_min_design > 0) {
+ val->intval = di->voltage_min_design;
+ return 0;
+ }
+
+ volt = bq27xxx_read(di, BQ27XXX_REG_SEDVF, true);
+ if (volt < 0) {
+ dev_err(di->dev, "error reading design min voltage\n");
+ return volt;
+ }
+
+ /* SEDVF = Design EDVF / 8 - 256 */
+ val->intval = volt * 8000 + 2048000;
+
+ /* Save for later reads */
+ di->voltage_min_design = val->intval;
+
+ return 0;
+}
+
static int bq27xxx_simple_value(int value,
union power_supply_propval *val)
{
@@ -2063,7 +2131,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
mutex_unlock(&di->lock);
if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0)
- return -ENODEV;
+ return di->cache.flags;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
@@ -2119,8 +2187,13 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
* power_supply_battery_info visible in sysfs.
*/
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
- case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
return -EINVAL;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ ret = bq27xxx_battery_read_dmin_volt(di, val);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ ret = bq27xxx_battery_read_dmax_volt(di, val);
+ break;
case POWER_SUPPLY_PROP_CYCLE_COUNT:
ret = bq27xxx_battery_read_cyct(di, val);
break;
@@ -2162,7 +2235,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
{
struct power_supply_desc *psy_desc;
struct power_supply_config psy_cfg = {
- .of_node = di->dev->of_node,
+ .fwnode = dev_fwnode(di->dev),
.drv_data = di,
.no_wakeup_source = true,
};
diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
index ba0d22d90429..868e95f0887e 100644
--- a/drivers/power/supply/bq27xxx_battery_i2c.c
+++ b/drivers/power/supply/bq27xxx_battery_i2c.c
@@ -6,6 +6,7 @@
* Andrew F. Davis <afd@ti.com>
*/
+#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -31,6 +32,7 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
struct i2c_msg msg[2];
u8 data[2];
int ret;
+ int retry = 0;
if (!client->adapter)
return -ENODEV;
@@ -47,7 +49,16 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
else
msg[1].len = 2;
- ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ do {
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (ret == -EBUSY && ++retry < 3) {
+ /* sleep 10 milliseconds when busy */
+ usleep_range(10000, 11000);
+ continue;
+ }
+ break;
+ } while (1);
+
if (ret < 0)
return ret;
diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c
index a69faef444c0..c49e0e4d02f7 100644
--- a/drivers/power/supply/charger-manager.c
+++ b/drivers/power/supply/charger-manager.c
@@ -22,6 +22,7 @@
#include <linux/platform_device.h>
#include <linux/power/charger-manager.h>
#include <linux/regulator/consumer.h>
+#include <linux/string_choices.h>
#include <linux/sysfs.h>
#include <linux/of.h>
#include <linux/thermal.h>
@@ -1088,7 +1089,7 @@ static ssize_t charger_state_show(struct device *dev,
if (!charger->externally_control)
state = regulator_is_enabled(charger->consumer);
- return sysfs_emit(buf, "%s\n", state ? "enabled" : "disabled");
+ return sysfs_emit(buf, "%s\n", str_enabled_disabled(state));
}
static ssize_t charger_externally_control_show(struct device *dev,
diff --git a/drivers/power/supply/collie_battery.c b/drivers/power/supply/collie_battery.c
index 68390bd1004f..3daf7befc0bf 100644
--- a/drivers/power/supply/collie_battery.c
+++ b/drivers/power/supply/collie_battery.c
@@ -440,6 +440,7 @@ err_put_gpio_full:
static void collie_bat_remove(struct ucb1x00_dev *dev)
{
+ device_init_wakeup(&ucb->dev, 0);
free_irq(gpiod_to_irq(collie_bat_main.gpio_full), &collie_bat_main);
power_supply_unregister(collie_bat_bu.psy);
power_supply_unregister(collie_bat_main.psy);
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c
index 813037c00ded..8106d1edcbc2 100644
--- a/drivers/power/supply/cpcap-battery.c
+++ b/drivers/power/supply/cpcap-battery.c
@@ -1130,7 +1130,7 @@ static int cpcap_battery_probe(struct platform_device *pdev)
if (error)
return error;
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = ddata;
ddata->psy = devm_power_supply_register(ddata->dev,
diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c
index 7781b45a67a7..13300dc60baf 100644
--- a/drivers/power/supply/cpcap-charger.c
+++ b/drivers/power/supply/cpcap-charger.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
@@ -515,7 +516,7 @@ static void cpcap_charger_vbus_work(struct work_struct *work)
out_err:
cpcap_charger_update_state(ddata, POWER_SUPPLY_STATUS_UNKNOWN);
dev_err(ddata->dev, "%s could not %s vbus: %i\n", __func__,
- ddata->vbus_enabled ? "enable" : "disable", error);
+ str_enable_disable(ddata->vbus_enabled), error);
}
static int cpcap_charger_set_vbus(struct phy_companion *comparator,
@@ -901,7 +902,7 @@ static int cpcap_charger_probe(struct platform_device *pdev)
atomic_set(&ddata->active, 1);
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = ddata;
psy_cfg.supplied_to = cpcap_charger_supplied_to;
psy_cfg.num_supplicants = ARRAY_SIZE(cpcap_charger_supplied_to);
diff --git a/drivers/power/supply/cros_charge-control.c b/drivers/power/supply/cros_charge-control.c
index 9b0a7500296b..02d5bdbe2e8d 100644
--- a/drivers/power/supply/cros_charge-control.c
+++ b/drivers/power/supply/cros_charge-control.c
@@ -20,13 +20,6 @@
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE) | \
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE))
-enum CROS_CHCTL_ATTR {
- CROS_CHCTL_ATTR_START_THRESHOLD,
- CROS_CHCTL_ATTR_END_THRESHOLD,
- CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR,
- _CROS_CHCTL_ATTR_COUNT
-};
-
/*
* Semantics of data *returned* from the EC API and Linux sysfs differ
* slightly, also the v1 API can not return any data.
@@ -38,18 +31,13 @@ enum CROS_CHCTL_ATTR {
*/
struct cros_chctl_priv {
+ struct device *dev;
struct cros_ec_device *cros_ec;
struct acpi_battery_hook battery_hook;
struct power_supply *hooked_battery;
u8 cmd_version;
- /* The callbacks need to access this priv structure.
- * As neither the struct device nor power_supply are under the drivers
- * control, embed the attributes within priv to use with container_of().
- */
- struct device_attribute device_attrs[_CROS_CHCTL_ATTR_COUNT];
- struct attribute *attributes[_CROS_CHCTL_ATTR_COUNT];
- struct attribute_group group;
+ const struct power_supply_ext *psy_ext;
struct mutex lock; /* protects fields below and cros_ec */
enum power_supply_charge_behaviour current_behaviour;
@@ -119,26 +107,39 @@ static int cros_chctl_configure_ec(struct cros_chctl_priv *priv)
return cros_chctl_send_charge_control_cmd(priv->cros_ec, priv->cmd_version, &req);
}
-static struct cros_chctl_priv *cros_chctl_attr_to_priv(struct attribute *attr,
- enum CROS_CHCTL_ATTR idx)
+static int cros_chctl_psy_ext_get_prop(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
{
- struct device_attribute *dev_attr = container_of(attr, struct device_attribute, attr);
+ struct cros_chctl_priv *priv = data;
- return container_of(dev_attr, struct cros_chctl_priv, device_attrs[idx]);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:
+ val->intval = priv->current_start_threshold;
+ return 0;
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+ val->intval = priv->current_end_threshold;
+ return 0;
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ val->intval = priv->current_behaviour;
+ return 0;
+ default:
+ return -EINVAL;
+ }
}
-static ssize_t cros_chctl_store_threshold(struct device *dev, struct cros_chctl_priv *priv,
- int is_end_threshold, const char *buf, size_t count)
+static int cros_chctl_psy_ext_set_threshold(struct cros_chctl_priv *priv,
+ enum power_supply_property psp,
+ int val)
{
- int ret, val;
+ int ret;
- ret = kstrtoint(buf, 10, &val);
- if (ret < 0)
- return ret;
if (val < 0 || val > 100)
return -EINVAL;
- if (is_end_threshold) {
+ if (psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) {
/* Start threshold is not exposed, use fixed value */
if (priv->cmd_version == 2)
priv->current_start_threshold = val == 100 ? 0 : val;
@@ -158,93 +159,73 @@ static ssize_t cros_chctl_store_threshold(struct device *dev, struct cros_chctl_
return ret;
}
- return count;
-}
-
-static ssize_t charge_control_start_threshold_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_START_THRESHOLD);
-
- guard(mutex)(&priv->lock);
- return sysfs_emit(buf, "%u\n", (unsigned int)priv->current_start_threshold);
+ return 0;
}
-static ssize_t charge_control_start_threshold_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_START_THRESHOLD);
-
- guard(mutex)(&priv->lock);
- return cros_chctl_store_threshold(dev, priv, 0, buf, count);
-}
-static ssize_t charge_control_end_threshold_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+static int cros_chctl_psy_ext_set_prop(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_END_THRESHOLD);
+ struct cros_chctl_priv *priv = data;
+ int ret;
guard(mutex)(&priv->lock);
- return sysfs_emit(buf, "%u\n", (unsigned int)priv->current_end_threshold);
-}
-
-static ssize_t charge_control_end_threshold_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_END_THRESHOLD);
- guard(mutex)(&priv->lock);
- return cros_chctl_store_threshold(dev, priv, 1, buf, count);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+ return cros_chctl_psy_ext_set_threshold(priv, psp, val->intval);
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ priv->current_behaviour = val->intval;
+ ret = cros_chctl_configure_ec(priv);
+ if (ret < 0)
+ return ret;
+ return 0;
+ default:
+ return -EINVAL;
+ }
}
-static ssize_t charge_behaviour_show(struct device *dev, struct device_attribute *attr, char *buf)
+static int cros_chctl_psy_prop_is_writeable(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp)
{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR);
-
- guard(mutex)(&priv->lock);
- return power_supply_charge_behaviour_show(dev, EC_CHARGE_CONTROL_BEHAVIOURS,
- priv->current_behaviour, buf);
+ return true;
}
-static ssize_t charge_behaviour_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(&attr->attr,
- CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR);
- int ret;
-
- ret = power_supply_charge_behaviour_parse(EC_CHARGE_CONTROL_BEHAVIOURS, buf);
- if (ret < 0)
- return ret;
-
- guard(mutex)(&priv->lock);
- priv->current_behaviour = ret;
+#define DEFINE_CROS_CHCTL_POWER_SUPPLY_EXTENSION(_name, ...) \
+ static const enum power_supply_property _name ## _props[] = { \
+ __VA_ARGS__, \
+ }; \
+ \
+ static const struct power_supply_ext _name = { \
+ .name = "cros-charge-control", \
+ .properties = _name ## _props, \
+ .num_properties = ARRAY_SIZE(_name ## _props), \
+ .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS, \
+ .get_property = cros_chctl_psy_ext_get_prop, \
+ .set_property = cros_chctl_psy_ext_set_prop, \
+ .property_is_writeable = cros_chctl_psy_prop_is_writeable, \
+ }
- ret = cros_chctl_configure_ec(priv);
- if (ret < 0)
- return ret;
+DEFINE_CROS_CHCTL_POWER_SUPPLY_EXTENSION(cros_chctl_psy_ext_v1,
+ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR
+);
- return count;
-}
+DEFINE_CROS_CHCTL_POWER_SUPPLY_EXTENSION(cros_chctl_psy_ext_v2,
+ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD
+);
-static umode_t cros_chtl_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
-{
- struct cros_chctl_priv *priv = cros_chctl_attr_to_priv(attr, n);
-
- if (n == CROS_CHCTL_ATTR_START_THRESHOLD && priv->cmd_version < 3)
- return 0;
- else if (n == CROS_CHCTL_ATTR_END_THRESHOLD && priv->cmd_version < 2)
- return 0;
-
- return attr->mode;
-}
+DEFINE_CROS_CHCTL_POWER_SUPPLY_EXTENSION(cros_chctl_psy_ext_v3,
+ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD
+);
static int cros_chctl_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
{
@@ -254,7 +235,7 @@ static int cros_chctl_add_battery(struct power_supply *battery, struct acpi_batt
return 0;
priv->hooked_battery = battery;
- return device_add_group(&battery->dev, &priv->group);
+ return power_supply_register_extension(battery, priv->psy_ext, priv->dev, priv);
}
static int cros_chctl_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
@@ -262,7 +243,7 @@ static int cros_chctl_remove_battery(struct power_supply *battery, struct acpi_b
struct cros_chctl_priv *priv = container_of(hook, struct cros_chctl_priv, battery_hook);
if (priv->hooked_battery == battery) {
- device_remove_group(&battery->dev, &priv->group);
+ power_supply_unregister_extension(battery, priv->psy_ext);
priv->hooked_battery = NULL;
}
@@ -288,7 +269,6 @@ static int cros_chctl_probe(struct platform_device *pdev)
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
struct cros_ec_device *cros_ec = ec_dev->ec_dev;
struct cros_chctl_priv *priv;
- size_t i;
int ret;
ret = cros_chctl_fwk_charge_control_versions(cros_ec);
@@ -321,19 +301,15 @@ static int cros_chctl_probe(struct platform_device *pdev)
dev_dbg(dev, "Command version: %u\n", (unsigned int)priv->cmd_version);
+ priv->dev = dev;
priv->cros_ec = cros_ec;
- priv->device_attrs[CROS_CHCTL_ATTR_START_THRESHOLD] =
- (struct device_attribute)__ATTR_RW(charge_control_start_threshold);
- priv->device_attrs[CROS_CHCTL_ATTR_END_THRESHOLD] =
- (struct device_attribute)__ATTR_RW(charge_control_end_threshold);
- priv->device_attrs[CROS_CHCTL_ATTR_CHARGE_BEHAVIOUR] =
- (struct device_attribute)__ATTR_RW(charge_behaviour);
- for (i = 0; i < _CROS_CHCTL_ATTR_COUNT; i++) {
- sysfs_attr_init(&priv->device_attrs[i].attr);
- priv->attributes[i] = &priv->device_attrs[i].attr;
- }
- priv->group.is_visible = cros_chtl_attr_is_visible;
- priv->group.attrs = priv->attributes;
+
+ if (priv->cmd_version == 1)
+ priv->psy_ext = &cros_chctl_psy_ext_v1;
+ else if (priv->cmd_version == 2)
+ priv->psy_ext = &cros_chctl_psy_ext_v2;
+ else
+ priv->psy_ext = &cros_chctl_psy_ext_v3;
priv->battery_hook.name = dev_name(dev);
priv->battery_hook.add_battery = cros_chctl_add_battery;
diff --git a/drivers/power/supply/da9030_battery.c b/drivers/power/supply/da9030_battery.c
index 34328f5d556e..d25279c26030 100644
--- a/drivers/power/supply/da9030_battery.c
+++ b/drivers/power/supply/da9030_battery.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
+#include <linux/string_choices.h>
#include <linux/mfd/da903x.h>
#include <linux/debugfs.h>
@@ -138,7 +139,7 @@ static int bat_debug_show(struct seq_file *s, void *data)
{
struct da9030_charger *charger = s->private;
- seq_printf(s, "charger is %s\n", charger->is_on ? "on" : "off");
+ seq_printf(s, "charger is %s\n", str_on_off(charger->is_on));
if (charger->chdet) {
seq_printf(s, "iset = %dmA, vset = %dmV\n",
charger->mA, charger->mV);
@@ -501,8 +502,7 @@ static int da9030_battery_probe(struct platform_device *pdev)
/* 10 seconds between monitor runs unless platform defines other
interval */
- charger->interval = msecs_to_jiffies(
- (pdata->batmon_interval ? : 10) * 1000);
+ charger->interval = secs_to_jiffies(pdata->batmon_interval ? : 10);
charger->charge_milliamp = pdata->charge_milliamp;
charger->charge_millivolt = pdata->charge_millivolt;
diff --git a/drivers/power/supply/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c
index 7cf4ea06b500..5badf58c6edb 100644
--- a/drivers/power/supply/ds2760_battery.c
+++ b/drivers/power/supply/ds2760_battery.c
@@ -112,7 +112,6 @@ struct ds2760_device_info {
struct power_supply_desc bat_desc;
struct workqueue_struct *monitor_wqueue;
struct delayed_work monitor_work;
- struct delayed_work set_charged_work;
struct notifier_block pm_notifier;
};
@@ -195,22 +194,22 @@ static int w1_ds2760_recall_eeprom(struct device *dev, int addr)
}
static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr, char *buf,
+ const struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
return w1_ds2760_read(dev, buf, off, count);
}
-static BIN_ATTR_RO(w1_slave, DS2760_DATA_SIZE);
+static const BIN_ATTR_RO(w1_slave, DS2760_DATA_SIZE);
-static struct bin_attribute *w1_ds2760_bin_attrs[] = {
+static const struct bin_attribute *const w1_ds2760_bin_attrs[] = {
&bin_attr_w1_slave,
NULL,
};
static const struct attribute_group w1_ds2760_group = {
- .bin_attrs = w1_ds2760_bin_attrs,
+ .bin_attrs_new = w1_ds2760_bin_attrs,
};
static const struct attribute_group *w1_ds2760_groups[] = {
@@ -489,50 +488,6 @@ static void ds2760_battery_external_power_changed(struct power_supply *psy)
}
-static void ds2760_battery_set_charged_work(struct work_struct *work)
-{
- char bias;
- struct ds2760_device_info *di = container_of(work,
- struct ds2760_device_info, set_charged_work.work);
-
- dev_dbg(di->dev, "%s\n", __func__);
-
- ds2760_battery_read_status(di);
-
- /* When we get notified by external circuitry that the battery is
- * considered fully charged now, we know that there is no current
- * flow any more. However, the ds2760's internal current meter is
- * too inaccurate to rely on - spec say something ~15% failure.
- * Hence, we use the current offset bias register to compensate
- * that error.
- */
-
- if (!power_supply_am_i_supplied(di->bat))
- return;
-
- bias = (signed char) di->current_raw +
- (signed char) di->raw[DS2760_CURRENT_OFFSET_BIAS];
-
- dev_dbg(di->dev, "%s: bias = %d\n", __func__, bias);
-
- w1_ds2760_write(di->dev, &bias, DS2760_CURRENT_OFFSET_BIAS, 1);
- w1_ds2760_store_eeprom(di->dev, DS2760_EEPROM_BLOCK1);
- w1_ds2760_recall_eeprom(di->dev, DS2760_EEPROM_BLOCK1);
-
- /* Write to the di->raw[] buffer directly - the CURRENT_OFFSET_BIAS
- * value won't be read back by ds2760_battery_read_status() */
- di->raw[DS2760_CURRENT_OFFSET_BIAS] = bias;
-}
-
-static void ds2760_battery_set_charged(struct power_supply *psy)
-{
- struct ds2760_device_info *di = power_supply_get_drvdata(psy);
-
- /* postpone the actual work by 20 secs. This is for debouncing GPIO
- * signals and to let the current value settle. See AN4188. */
- mod_delayed_work(di->monitor_wqueue, &di->set_charged_work, HZ * 20);
-}
-
static int ds2760_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -692,17 +647,15 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
di->bat_desc.set_property = ds2760_battery_set_property;
di->bat_desc.property_is_writeable =
ds2760_battery_property_is_writeable;
- di->bat_desc.set_charged = ds2760_battery_set_charged;
di->bat_desc.external_power_changed =
ds2760_battery_external_power_changed;
psy_cfg.drv_data = di;
+ psy_cfg.fwnode = dev_fwnode(dev);
if (dev->of_node) {
u32 tmp;
- psy_cfg.of_node = dev->of_node;
-
if (!of_property_read_bool(dev->of_node, "maxim,pmod-enabled"))
pmod_enabled = true;
@@ -747,8 +700,6 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
}
INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
- INIT_DELAYED_WORK(&di->set_charged_work,
- ds2760_battery_set_charged_work);
di->monitor_wqueue = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
if (!di->monitor_wqueue) {
retval = -ESRCH;
@@ -774,7 +725,6 @@ static void w1_ds2760_remove_slave(struct w1_slave *sl)
unregister_pm_notifier(&di->pm_notifier);
cancel_delayed_work_sync(&di->monitor_work);
- cancel_delayed_work_sync(&di->set_charged_work);
destroy_workqueue(di->monitor_wqueue);
}
diff --git a/drivers/power/supply/ds2780_battery.c b/drivers/power/supply/ds2780_battery.c
index 1e7f297f6cb1..dd9ac7a32967 100644
--- a/drivers/power/supply/ds2780_battery.c
+++ b/drivers/power/supply/ds2780_battery.c
@@ -621,7 +621,7 @@ static ssize_t ds2780_set_pio_pin(struct device *dev,
static ssize_t ds2780_read_param_eeprom_bin(struct file *filp,
struct kobject *kobj,
- struct bin_attribute *bin_attr,
+ const struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
@@ -634,7 +634,7 @@ static ssize_t ds2780_read_param_eeprom_bin(struct file *filp,
static ssize_t ds2780_write_param_eeprom_bin(struct file *filp,
struct kobject *kobj,
- struct bin_attribute *bin_attr,
+ const struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
@@ -654,19 +654,19 @@ 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,
},
.size = DS2780_PARAM_EEPROM_SIZE,
- .read = ds2780_read_param_eeprom_bin,
- .write = ds2780_write_param_eeprom_bin,
+ .read_new = ds2780_read_param_eeprom_bin,
+ .write_new = ds2780_write_param_eeprom_bin,
};
static ssize_t ds2780_read_user_eeprom_bin(struct file *filp,
struct kobject *kobj,
- struct bin_attribute *bin_attr,
+ const struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
@@ -679,7 +679,7 @@ static ssize_t ds2780_read_user_eeprom_bin(struct file *filp,
static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
struct kobject *kobj,
- struct bin_attribute *bin_attr,
+ const struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
@@ -699,14 +699,14 @@ 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,
},
.size = DS2780_USER_EEPROM_SIZE,
- .read = ds2780_read_user_eeprom_bin,
- .write = ds2780_write_user_eeprom_bin,
+ .read_new = ds2780_read_user_eeprom_bin,
+ .write_new = ds2780_write_user_eeprom_bin,
};
static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2780_get_pmod_enabled,
@@ -726,7 +726,7 @@ static struct attribute *ds2780_sysfs_attrs[] = {
NULL
};
-static struct bin_attribute *ds2780_sysfs_bin_attrs[] = {
+static const struct bin_attribute *const ds2780_sysfs_bin_attrs[] = {
&ds2780_param_eeprom_bin_attr,
&ds2780_user_eeprom_bin_attr,
NULL
@@ -734,7 +734,7 @@ static struct bin_attribute *ds2780_sysfs_bin_attrs[] = {
static const struct attribute_group ds2780_sysfs_group = {
.attrs = ds2780_sysfs_attrs,
- .bin_attrs = ds2780_sysfs_bin_attrs,
+ .bin_attrs_new = ds2780_sysfs_bin_attrs,
};
static const struct attribute_group *ds2780_sysfs_groups[] = {
diff --git a/drivers/power/supply/ds2781_battery.c b/drivers/power/supply/ds2781_battery.c
index c4f8ccc687f9..8a1f1f9835e0 100644
--- a/drivers/power/supply/ds2781_battery.c
+++ b/drivers/power/supply/ds2781_battery.c
@@ -623,7 +623,7 @@ static ssize_t ds2781_set_pio_pin(struct device *dev,
static ssize_t ds2781_read_param_eeprom_bin(struct file *filp,
struct kobject *kobj,
- struct bin_attribute *bin_attr,
+ const struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
@@ -636,7 +636,7 @@ static ssize_t ds2781_read_param_eeprom_bin(struct file *filp,
static ssize_t ds2781_write_param_eeprom_bin(struct file *filp,
struct kobject *kobj,
- struct bin_attribute *bin_attr,
+ const struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
@@ -656,19 +656,19 @@ 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,
},
.size = DS2781_PARAM_EEPROM_SIZE,
- .read = ds2781_read_param_eeprom_bin,
- .write = ds2781_write_param_eeprom_bin,
+ .read_new = ds2781_read_param_eeprom_bin,
+ .write_new = ds2781_write_param_eeprom_bin,
};
static ssize_t ds2781_read_user_eeprom_bin(struct file *filp,
struct kobject *kobj,
- struct bin_attribute *bin_attr,
+ const struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
@@ -682,7 +682,7 @@ static ssize_t ds2781_read_user_eeprom_bin(struct file *filp,
static ssize_t ds2781_write_user_eeprom_bin(struct file *filp,
struct kobject *kobj,
- struct bin_attribute *bin_attr,
+ const struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
@@ -702,14 +702,14 @@ 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,
},
.size = DS2781_USER_EEPROM_SIZE,
- .read = ds2781_read_user_eeprom_bin,
- .write = ds2781_write_user_eeprom_bin,
+ .read_new = ds2781_read_user_eeprom_bin,
+ .write_new = ds2781_write_user_eeprom_bin,
};
static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2781_get_pmod_enabled,
@@ -729,7 +729,7 @@ static struct attribute *ds2781_sysfs_attrs[] = {
NULL
};
-static struct bin_attribute *ds2781_sysfs_bin_attrs[] = {
+static const struct bin_attribute *const ds2781_sysfs_bin_attrs[] = {
&ds2781_param_eeprom_bin_attr,
&ds2781_user_eeprom_bin_attr,
NULL,
@@ -737,7 +737,7 @@ static struct bin_attribute *ds2781_sysfs_bin_attrs[] = {
static const struct attribute_group ds2781_sysfs_group = {
.attrs = ds2781_sysfs_attrs,
- .bin_attrs = ds2781_sysfs_bin_attrs,
+ .bin_attrs_new = ds2781_sysfs_bin_attrs,
};
diff --git a/drivers/power/supply/ds2782_battery.c b/drivers/power/supply/ds2782_battery.c
index 85aa9c465aa4..cae95d35d398 100644
--- a/drivers/power/supply/ds2782_battery.c
+++ b/drivers/power/supply/ds2782_battery.c
@@ -11,6 +11,7 @@
* UEvent sending added by Evgeny Romanov <romanov@neurosoft.ru>
*/
+#include <linux/devm-helpers.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -57,14 +58,12 @@ struct ds278x_info {
struct power_supply_desc battery_desc;
const struct ds278x_battery_ops *ops;
struct delayed_work bat_work;
- int id;
int rsns;
int capacity;
int status; /* State Of Charge */
};
-static DEFINE_IDR(battery_id);
-static DEFINE_MUTEX(battery_lock);
+static DEFINE_IDA(battery_id);
static inline int ds278x_read_reg(struct ds278x_info *info, int reg, u8 *val)
{
@@ -312,21 +311,6 @@ static void ds278x_power_supply_init(struct power_supply_desc *battery)
battery->external_power_changed = NULL;
}
-static void 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, id);
- mutex_unlock(&battery_lock);
-}
-
#ifdef CONFIG_PM_SLEEP
static int ds278x_suspend(struct device *dev)
@@ -368,6 +352,13 @@ static const struct ds278x_battery_ops ds278x_ops[] = {
}
};
+static void ds278x_free_ida(void *data)
+{
+ int num = (uintptr_t)data;
+
+ ida_free(&battery_id, num);
+}
+
static int ds278x_battery_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -387,32 +378,27 @@ static int ds278x_battery_probe(struct i2c_client *client)
}
/* Get an ID for this battery */
- mutex_lock(&battery_lock);
- ret = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
- mutex_unlock(&battery_lock);
- if (ret < 0)
- goto fail_id;
- num = ret;
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
- ret = -ENOMEM;
- goto fail_info;
- }
+ num = ida_alloc(&battery_id, GFP_KERNEL);
+ if (num < 0)
+ return num;
+ ret = devm_add_action_or_reset(&client->dev, ds278x_free_ida, (void *)(uintptr_t)num);
+ if (ret)
+ return ret;
- info->battery_desc.name = kasprintf(GFP_KERNEL, "%s-%d",
- client->name, num);
- if (!info->battery_desc.name) {
- ret = -ENOMEM;
- goto fail_name;
- }
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->battery_desc.name = devm_kasprintf(&client->dev, GFP_KERNEL,
+ "%s-%d", client->name, num);
+ if (!info->battery_desc.name)
+ return -ENOMEM;
if (id->driver_data == DS2786)
info->rsns = pdata->rsns;
i2c_set_clientdata(client, info);
info->client = client;
- info->id = num;
info->ops = &ds278x_ops[id->driver_data];
ds278x_power_supply_init(&info->battery_desc);
psy_cfg.drv_data = info;
@@ -420,30 +406,20 @@ static int ds278x_battery_probe(struct i2c_client *client)
info->capacity = 100;
info->status = POWER_SUPPLY_STATUS_FULL;
- INIT_DELAYED_WORK(&info->bat_work, ds278x_bat_work);
-
- info->battery = power_supply_register(&client->dev,
- &info->battery_desc, &psy_cfg);
+ info->battery = devm_power_supply_register(&client->dev,
+ &info->battery_desc,
+ &psy_cfg);
if (IS_ERR(info->battery)) {
dev_err(&client->dev, "failed to register battery\n");
- ret = PTR_ERR(info->battery);
- goto fail_register;
- } else {
- schedule_delayed_work(&info->bat_work, DS278x_DELAY);
+ return PTR_ERR(info->battery);
}
- return 0;
+ ret = devm_delayed_work_autocancel(&client->dev, &info->bat_work, ds278x_bat_work);
+ if (ret)
+ return ret;
+ schedule_delayed_work(&info->bat_work, DS278x_DELAY);
-fail_register:
- kfree(info->battery_desc.name);
-fail_name:
- kfree(info);
-fail_info:
- mutex_lock(&battery_lock);
- idr_remove(&battery_id, num);
- mutex_unlock(&battery_lock);
-fail_id:
- return ret;
+ return 0;
}
static const struct i2c_device_id ds278x_id[] = {
@@ -459,7 +435,6 @@ static struct i2c_driver ds278x_battery_driver = {
.pm = &ds278x_battery_pm_ops,
},
.probe = ds278x_battery_probe,
- .remove = ds278x_battery_remove,
.id_table = ds278x_id,
};
module_i2c_driver(ds278x_battery_driver);
diff --git a/drivers/power/supply/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c
index d5d215f5ad8b..f5f2566b3a32 100644
--- a/drivers/power/supply/generic-adc-battery.c
+++ b/drivers/power/supply/generic-adc-battery.c
@@ -166,7 +166,7 @@ static int gab_probe(struct platform_device *pdev)
if (!adc_bat)
return -ENOMEM;
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = adc_bat;
psy_desc = &adc_bat->psy_desc;
psy_desc->name = dev_name(&pdev->dev);
diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c
index 6139f736ecbe..1b2da9b5fb65 100644
--- a/drivers/power/supply/gpio-charger.c
+++ b/drivers/power/supply/gpio-charger.c
@@ -195,6 +195,8 @@ static int init_charge_current_limit(struct device *dev,
{
int i, len;
u32 cur_limit = U32_MAX;
+ bool set_def_limit;
+ u32 def_limit;
gpio_charger->current_limit_gpios = devm_gpiod_get_array_optional(dev,
"charge-current-limit", GPIOD_OUT_LOW);
@@ -228,6 +230,9 @@ static int init_charge_current_limit(struct device *dev,
if (len < 0)
return len;
+ set_def_limit = !device_property_read_u32(dev,
+ "charge-current-limit-default-microamp",
+ &def_limit);
for (i=0; i < gpio_charger->current_limit_map_size; i++) {
if (gpio_charger->current_limit_map[i].limit_ua > cur_limit) {
dev_err(dev, "charge-current-limit-mapping not sorted by current in descending order\n");
@@ -235,8 +240,16 @@ static int init_charge_current_limit(struct device *dev,
}
cur_limit = gpio_charger->current_limit_map[i].limit_ua;
+ if (set_def_limit && def_limit == cur_limit) {
+ set_charge_current_limit(gpio_charger, cur_limit);
+ return 0;
+ }
}
+ if (set_def_limit)
+ dev_warn(dev, "charge-current-limit-default-microamp %u not listed in charge-current-limit-mapping\n",
+ def_limit);
+
/* default to smallest current limitation for safety reasons */
len = gpio_charger->current_limit_map_size - 1;
set_charge_current_limit(gpio_charger,
@@ -320,7 +333,7 @@ static int gpio_charger_probe(struct platform_device *pdev)
charger_desc->property_is_writeable =
gpio_charger_property_is_writeable;
- psy_cfg.of_node = dev->of_node;
+ psy_cfg.fwnode = dev_fwnode(dev);
psy_cfg.drv_data = gpio_charger;
if (pdata) {
@@ -353,7 +366,9 @@ static int gpio_charger_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, gpio_charger);
- device_init_wakeup(dev, 1);
+ ret = devm_device_init_wakeup(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init wakeup\n");
return 0;
}
diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c
index 0a40f425c277..b111c7ce2be3 100644
--- a/drivers/power/supply/ingenic-battery.c
+++ b/drivers/power/supply/ingenic-battery.c
@@ -146,7 +146,7 @@ static int ingenic_battery_probe(struct platform_device *pdev)
desc->num_properties = ARRAY_SIZE(ingenic_battery_properties);
desc->get_property = ingenic_battery_get_property;
psy_cfg.drv_data = bat;
- psy_cfg.of_node = dev->of_node;
+ psy_cfg.fwnode = dev_fwnode(dev);
bat->battery = devm_power_supply_register(dev, desc, &psy_cfg);
if (IS_ERR(bat->battery))
diff --git a/drivers/power/supply/ip5xxx_power.c b/drivers/power/supply/ip5xxx_power.c
index 82263646ddc6..24eea7a91b30 100644
--- a/drivers/power/supply/ip5xxx_power.c
+++ b/drivers/power/supply/ip5xxx_power.c
@@ -7,76 +7,154 @@
#include <linux/power_supply.h>
#include <linux/regmap.h>
-#define IP5XXX_SYS_CTL0 0x01
-#define IP5XXX_SYS_CTL0_WLED_DET_EN BIT(4)
-#define IP5XXX_SYS_CTL0_WLED_EN BIT(3)
-#define IP5XXX_SYS_CTL0_BOOST_EN BIT(2)
-#define IP5XXX_SYS_CTL0_CHARGER_EN BIT(1)
-#define IP5XXX_SYS_CTL1 0x02
-#define IP5XXX_SYS_CTL1_LIGHT_SHDN_EN BIT(1)
-#define IP5XXX_SYS_CTL1_LOAD_PWRUP_EN BIT(0)
-#define IP5XXX_SYS_CTL2 0x0c
-#define IP5XXX_SYS_CTL2_LIGHT_SHDN_TH GENMASK(7, 3)
-#define IP5XXX_SYS_CTL3 0x03
-#define IP5XXX_SYS_CTL3_LONG_PRESS_TIME_SEL GENMASK(7, 6)
-#define IP5XXX_SYS_CTL3_BTN_SHDN_EN BIT(5)
-#define IP5XXX_SYS_CTL4 0x04
-#define IP5XXX_SYS_CTL4_SHDN_TIME_SEL GENMASK(7, 6)
-#define IP5XXX_SYS_CTL4_VIN_PULLOUT_BOOST_EN BIT(5)
-#define IP5XXX_SYS_CTL5 0x07
-#define IP5XXX_SYS_CTL5_NTC_DIS BIT(6)
-#define IP5XXX_SYS_CTL5_WLED_MODE_SEL BIT(1)
-#define IP5XXX_SYS_CTL5_BTN_SHDN_SEL BIT(0)
-#define IP5XXX_CHG_CTL1 0x22
-#define IP5XXX_CHG_CTL1_BOOST_UVP_SEL GENMASK(3, 2)
-#define IP5XXX_CHG_CTL2 0x24
-#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL GENMASK(6, 5)
-#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_2V (0x0 << 5)
-#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_3V (0x1 << 5)
-#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_35V (0x2 << 5)
-#define IP5XXX_CHG_CTL2_CONST_VOLT_SEL GENMASK(2, 1)
-#define IP5XXX_CHG_CTL4 0x26
-#define IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN BIT(6)
-#define IP5XXX_CHG_CTL4A 0x25
-#define IP5XXX_CHG_CTL4A_CONST_CUR_SEL GENMASK(4, 0)
-#define IP5XXX_MFP_CTL0 0x51
-#define IP5XXX_MFP_CTL1 0x52
-#define IP5XXX_GPIO_CTL2 0x53
-#define IP5XXX_GPIO_CTL2A 0x54
-#define IP5XXX_GPIO_CTL3 0x55
-#define IP5XXX_READ0 0x71
-#define IP5XXX_READ0_CHG_STAT GENMASK(7, 5)
-#define IP5XXX_READ0_CHG_STAT_IDLE (0x0 << 5)
-#define IP5XXX_READ0_CHG_STAT_TRICKLE (0x1 << 5)
-#define IP5XXX_READ0_CHG_STAT_CONST_VOLT (0x2 << 5)
-#define IP5XXX_READ0_CHG_STAT_CONST_CUR (0x3 << 5)
-#define IP5XXX_READ0_CHG_STAT_CONST_VOLT_STOP (0x4 << 5)
-#define IP5XXX_READ0_CHG_STAT_FULL (0x5 << 5)
-#define IP5XXX_READ0_CHG_STAT_TIMEOUT (0x6 << 5)
-#define IP5XXX_READ0_CHG_OP BIT(4)
-#define IP5XXX_READ0_CHG_END BIT(3)
-#define IP5XXX_READ0_CONST_VOLT_TIMEOUT BIT(2)
-#define IP5XXX_READ0_CHG_TIMEOUT BIT(1)
-#define IP5XXX_READ0_TRICKLE_TIMEOUT BIT(0)
-#define IP5XXX_READ0_TIMEOUT GENMASK(2, 0)
-#define IP5XXX_READ1 0x72
-#define IP5XXX_READ1_WLED_PRESENT BIT(7)
-#define IP5XXX_READ1_LIGHT_LOAD BIT(6)
-#define IP5XXX_READ1_VIN_OVERVOLT BIT(5)
-#define IP5XXX_READ2 0x77
-#define IP5XXX_READ2_BTN_PRESS BIT(3)
-#define IP5XXX_READ2_BTN_LONG_PRESS BIT(1)
-#define IP5XXX_READ2_BTN_SHORT_PRESS BIT(0)
-#define IP5XXX_BATVADC_DAT0 0xa2
-#define IP5XXX_BATVADC_DAT1 0xa3
-#define IP5XXX_BATIADC_DAT0 0xa4
-#define IP5XXX_BATIADC_DAT1 0xa5
-#define IP5XXX_BATOCV_DAT0 0xa8
-#define IP5XXX_BATOCV_DAT1 0xa9
+#define IP5XXX_BAT_TYPE_4_2V 0x0
+#define IP5XXX_BAT_TYPE_4_3V 0x1
+#define IP5XXX_BAT_TYPE_4_35V 0x2
+#define IP5XXX_BAT_TYPE_4_4V 0x3
+#define IP5XXX_CHG_STAT_IDLE 0x0
+#define IP5XXX_CHG_STAT_TRICKLE 0x1
+#define IP5XXX_CHG_STAT_CONST_VOLT 0x2
+#define IP5XXX_CHG_STAT_CONST_CUR 0x3
+#define IP5XXX_CHG_STAT_CONST_VOLT_STOP 0x4
+#define IP5XXX_CHG_STAT_FULL 0x5
+#define IP5XXX_CHG_STAT_TIMEOUT 0x6
struct ip5xxx {
struct regmap *regmap;
bool initialized;
+ struct {
+ struct {
+ /* Charger enable */
+ struct regmap_field *enable;
+ /* Constant voltage value */
+ struct regmap_field *const_volt_sel;
+ /* Constant current value */
+ struct regmap_field *const_curr_sel;
+ /* Charger status */
+ struct regmap_field *status;
+ /* Charging ended flag */
+ struct regmap_field *chg_end;
+ /* Timeout flags (CV, charge, trickle) */
+ struct regmap_field *timeout;
+ /* Overvoltage limit */
+ struct regmap_field *vin_overvolt;
+ } charger;
+ struct {
+ /* Boost converter enable */
+ struct regmap_field *enable;
+ struct {
+ /* Light load shutdown enable */
+ struct regmap_field *enable;
+ /* Light load shutdown current limit */
+ struct regmap_field *i_limit;
+ } light_load_shutdown;
+ /* Automatic powerup on increased load */
+ struct regmap_field *load_powerup_en;
+ /* Automatic powerup on VIN pull-out */
+ struct regmap_field *vin_pullout_en;
+ /* Undervoltage limit */
+ struct regmap_field *undervolt_limit;
+ /* Light load status flag */
+ struct regmap_field *light_load_status;
+ } boost;
+ struct {
+ /* NTC disable */
+ struct regmap_field *ntc_dis;
+ /* Battery voltage type */
+ struct regmap_field *type;
+ /* Battery voltage autoset from Vset pin */
+ struct regmap_field *vset_en;
+ struct {
+ /* Battery measurement registers */
+ struct ip5xxx_battery_adc_regs {
+ struct regmap_field *low;
+ struct regmap_field *high;
+ } volt, curr, open_volt;
+ } adc;
+ } battery;
+ struct {
+ /* Double/long press shutdown enable */
+ struct regmap_field *shdn_enable;
+ /* WLED activation: double press or long press */
+ struct regmap_field *wled_mode;
+ /* Shutdown activation: double press or long press */
+ struct regmap_field *shdn_mode;
+ /* Long press time */
+ struct regmap_field *long_press_time;
+ /* Button pressed */
+ struct regmap_field *pressed;
+ /* Button long-pressed */
+ struct regmap_field *long_pressed;
+ /* Button short-pressed */
+ struct regmap_field *short_pressed;
+ } btn;
+ struct {
+ /* WLED enable */
+ struct regmap_field *enable;
+ /* WLED detect */
+ struct regmap_field *detect_en;
+ /* WLED present */
+ struct regmap_field *present;
+ } wled;
+ } regs;
+
+ /* Maximum supported battery voltage (via regs.battery.type) */
+ int vbat_max;
+ /* Scaling constants for regs.boost.undervolt_limit */
+ struct {
+ int setpoint;
+ int microvolts_per_bit;
+ } boost_undervolt;
+ /* Scaling constants for regs.charger.const_curr_sel */
+ struct {
+ int setpoint;
+ } const_curr;
+ /* Whether regs.charger.chg_end is inverted */
+ u8 chg_end_inverted;
+};
+
+#define REG_FIELD_UNSUPPORTED { .lsb = 1 }
+/* Register fields layout. Unsupported registers marked as { .lsb = 1 } */
+struct ip5xxx_regfield_config {
+ const struct reg_field charger_enable;
+ const struct reg_field charger_const_volt_sel;
+ const struct reg_field charger_const_curr_sel;
+ const struct reg_field charger_status;
+ const struct reg_field charger_chg_end;
+ const struct reg_field charger_timeout;
+ const struct reg_field charger_vin_overvolt;
+ const struct reg_field boost_enable;
+ const struct reg_field boost_llshdn_enable;
+ const struct reg_field boost_llshdn_i_limit;
+ const struct reg_field boost_load_powerup_en;
+ const struct reg_field boost_vin_pullout_en;
+ const struct reg_field boost_undervolt_limit;
+ const struct reg_field boost_light_load_status;
+ const struct reg_field battery_ntc_dis;
+ const struct reg_field battery_type;
+ const struct reg_field battery_vset_en;
+ const struct reg_field battery_adc_volt_low;
+ const struct reg_field battery_adc_volt_high;
+ const struct reg_field battery_adc_curr_low;
+ const struct reg_field battery_adc_curr_high;
+ const struct reg_field battery_adc_ovolt_low;
+ const struct reg_field battery_adc_ovolt_high;
+ const struct reg_field btn_shdn_enable;
+ const struct reg_field btn_wled_mode;
+ const struct reg_field btn_shdn_mode;
+ const struct reg_field btn_long_press_time;
+ const struct reg_field btn_pressed;
+ const struct reg_field btn_long_pressed;
+ const struct reg_field btn_short_pressed;
+ const struct reg_field wled_enable;
+ const struct reg_field wled_detect_en;
+ const struct reg_field wled_present;
+
+ int vbat_max;
+ int boost_undervolt_setpoint;
+ int boost_undervolt_uv_per_bit;
+ int const_curr_setpoint;
+ u8 chg_end_inverted;
};
/*
@@ -87,24 +165,30 @@ struct ip5xxx {
* 2) Attempt the initialization sequence on each subsequent register access
* until it succeeds.
*/
-static int ip5xxx_read(struct ip5xxx *ip5xxx, unsigned int reg,
+static int ip5xxx_read(struct ip5xxx *ip5xxx, struct regmap_field *field,
unsigned int *val)
{
int ret;
- ret = regmap_read(ip5xxx->regmap, reg, val);
+ if (!field)
+ return -EOPNOTSUPP;
+
+ ret = regmap_field_read(field, val);
if (ret)
ip5xxx->initialized = false;
return ret;
}
-static int ip5xxx_update_bits(struct ip5xxx *ip5xxx, unsigned int reg,
- unsigned int mask, unsigned int val)
+static int ip5xxx_write(struct ip5xxx *ip5xxx, struct regmap_field *field,
+ unsigned int val)
{
int ret;
- ret = regmap_update_bits(ip5xxx->regmap, reg, mask, val);
+ if (!field)
+ return -EOPNOTSUPP;
+
+ ret = regmap_field_write(field, val);
if (ret)
ip5xxx->initialized = false;
@@ -123,28 +207,26 @@ static int ip5xxx_initialize(struct power_supply *psy)
* Disable shutdown under light load.
* Enable power on when under load.
*/
- ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL1,
- IP5XXX_SYS_CTL1_LIGHT_SHDN_EN |
- IP5XXX_SYS_CTL1_LOAD_PWRUP_EN,
- IP5XXX_SYS_CTL1_LOAD_PWRUP_EN);
+ if (ip5xxx->regs.boost.light_load_shutdown.enable) {
+ ret = ip5xxx_write(ip5xxx, ip5xxx->regs.boost.light_load_shutdown.enable, 0);
+ if (ret)
+ return ret;
+ }
+ ret = ip5xxx_write(ip5xxx, ip5xxx->regs.boost.load_powerup_en, 1);
if (ret)
return ret;
/*
* Enable shutdown after a long button press (as configured below).
*/
- ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL3,
- IP5XXX_SYS_CTL3_BTN_SHDN_EN,
- IP5XXX_SYS_CTL3_BTN_SHDN_EN);
+ ret = ip5xxx_write(ip5xxx, ip5xxx->regs.btn.shdn_enable, 1);
if (ret)
return ret;
/*
* Power on automatically when VIN is removed.
*/
- ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL4,
- IP5XXX_SYS_CTL4_VIN_PULLOUT_BOOST_EN,
- IP5XXX_SYS_CTL4_VIN_PULLOUT_BOOST_EN);
+ ret = ip5xxx_write(ip5xxx, ip5xxx->regs.boost.vin_pullout_en, 1);
if (ret)
return ret;
@@ -152,12 +234,15 @@ static int ip5xxx_initialize(struct power_supply *psy)
* Enable the NTC.
* Configure the button for two presses => LED, long press => shutdown.
*/
- ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL5,
- IP5XXX_SYS_CTL5_NTC_DIS |
- IP5XXX_SYS_CTL5_WLED_MODE_SEL |
- IP5XXX_SYS_CTL5_BTN_SHDN_SEL,
- IP5XXX_SYS_CTL5_WLED_MODE_SEL |
- IP5XXX_SYS_CTL5_BTN_SHDN_SEL);
+ if (ip5xxx->regs.battery.ntc_dis) {
+ ret = ip5xxx_write(ip5xxx, ip5xxx->regs.battery.ntc_dis, 0);
+ if (ret)
+ return ret;
+ }
+ ret = ip5xxx_write(ip5xxx, ip5xxx->regs.btn.wled_mode, 1);
+ if (ret)
+ return ret;
+ ret = ip5xxx_write(ip5xxx, ip5xxx->regs.btn.shdn_mode, 1);
if (ret)
return ret;
@@ -186,24 +271,37 @@ static int ip5xxx_battery_get_status(struct ip5xxx *ip5xxx, int *val)
unsigned int rval;
int ret;
- ret = ip5xxx_read(ip5xxx, IP5XXX_READ0, &rval);
+ if (!ip5xxx->regs.charger.status) {
+ // Fall-back to Charging Ended bit
+ ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.chg_end, &rval);
+ if (ret)
+ return ret;
+
+ if (rval == ip5xxx->chg_end_inverted)
+ *val = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ return 0;
+ }
+
+ ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.status, &rval);
if (ret)
return ret;
- switch (rval & IP5XXX_READ0_CHG_STAT) {
- case IP5XXX_READ0_CHG_STAT_IDLE:
+ switch (rval) {
+ case IP5XXX_CHG_STAT_IDLE:
*val = POWER_SUPPLY_STATUS_DISCHARGING;
break;
- case IP5XXX_READ0_CHG_STAT_TRICKLE:
- case IP5XXX_READ0_CHG_STAT_CONST_CUR:
- case IP5XXX_READ0_CHG_STAT_CONST_VOLT:
+ case IP5XXX_CHG_STAT_TRICKLE:
+ case IP5XXX_CHG_STAT_CONST_CUR:
+ case IP5XXX_CHG_STAT_CONST_VOLT:
*val = POWER_SUPPLY_STATUS_CHARGING;
break;
- case IP5XXX_READ0_CHG_STAT_CONST_VOLT_STOP:
- case IP5XXX_READ0_CHG_STAT_FULL:
+ case IP5XXX_CHG_STAT_CONST_VOLT_STOP:
+ case IP5XXX_CHG_STAT_FULL:
*val = POWER_SUPPLY_STATUS_FULL;
break;
- case IP5XXX_READ0_CHG_STAT_TIMEOUT:
+ case IP5XXX_CHG_STAT_TIMEOUT:
*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
default:
@@ -218,22 +316,22 @@ static int ip5xxx_battery_get_charge_type(struct ip5xxx *ip5xxx, int *val)
unsigned int rval;
int ret;
- ret = ip5xxx_read(ip5xxx, IP5XXX_READ0, &rval);
+ ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.status, &rval);
if (ret)
return ret;
- switch (rval & IP5XXX_READ0_CHG_STAT) {
- case IP5XXX_READ0_CHG_STAT_IDLE:
- case IP5XXX_READ0_CHG_STAT_CONST_VOLT_STOP:
- case IP5XXX_READ0_CHG_STAT_FULL:
- case IP5XXX_READ0_CHG_STAT_TIMEOUT:
+ switch (rval) {
+ case IP5XXX_CHG_STAT_IDLE:
+ case IP5XXX_CHG_STAT_CONST_VOLT_STOP:
+ case IP5XXX_CHG_STAT_FULL:
+ case IP5XXX_CHG_STAT_TIMEOUT:
*val = POWER_SUPPLY_CHARGE_TYPE_NONE;
break;
- case IP5XXX_READ0_CHG_STAT_TRICKLE:
+ case IP5XXX_CHG_STAT_TRICKLE:
*val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
break;
- case IP5XXX_READ0_CHG_STAT_CONST_CUR:
- case IP5XXX_READ0_CHG_STAT_CONST_VOLT:
+ case IP5XXX_CHG_STAT_CONST_CUR:
+ case IP5XXX_CHG_STAT_CONST_VOLT:
*val = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
break;
default:
@@ -248,11 +346,11 @@ static int ip5xxx_battery_get_health(struct ip5xxx *ip5xxx, int *val)
unsigned int rval;
int ret;
- ret = ip5xxx_read(ip5xxx, IP5XXX_READ0, &rval);
+ ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.timeout, &rval);
if (ret)
return ret;
- if (rval & IP5XXX_READ0_TIMEOUT)
+ if (rval)
*val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
else
*val = POWER_SUPPLY_HEALTH_GOOD;
@@ -265,7 +363,7 @@ static int ip5xxx_battery_get_voltage_max(struct ip5xxx *ip5xxx, int *val)
unsigned int rval;
int ret;
- ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL2, &rval);
+ ret = ip5xxx_read(ip5xxx, ip5xxx->regs.battery.type, &rval);
if (ret)
return ret;
@@ -273,16 +371,19 @@ static int ip5xxx_battery_get_voltage_max(struct ip5xxx *ip5xxx, int *val)
* It is not clear what this will return if
* IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN is not set...
*/
- switch (rval & IP5XXX_CHG_CTL2_BAT_TYPE_SEL) {
- case IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_2V:
+ switch (rval) {
+ case IP5XXX_BAT_TYPE_4_2V:
*val = 4200000;
break;
- case IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_3V:
+ case IP5XXX_BAT_TYPE_4_3V:
*val = 4300000;
break;
- case IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_35V:
+ case IP5XXX_BAT_TYPE_4_35V:
*val = 4350000;
break;
+ case IP5XXX_BAT_TYPE_4_4V:
+ *val = 4400000;
+ break;
default:
return -EINVAL;
}
@@ -291,16 +392,16 @@ static int ip5xxx_battery_get_voltage_max(struct ip5xxx *ip5xxx, int *val)
}
static int ip5xxx_battery_read_adc(struct ip5xxx *ip5xxx,
- u8 lo_reg, u8 hi_reg, int *val)
+ struct ip5xxx_battery_adc_regs *regs, int *val)
{
unsigned int hi, lo;
int ret;
- ret = ip5xxx_read(ip5xxx, lo_reg, &lo);
+ ret = ip5xxx_read(ip5xxx, regs->low, &lo);
if (ret)
return ret;
- ret = ip5xxx_read(ip5xxx, hi_reg, &hi);
+ ret = ip5xxx_read(ip5xxx, regs->high, &hi);
if (ret)
return ret;
@@ -335,33 +436,35 @@ static int ip5xxx_battery_get_property(struct power_supply *psy,
return ip5xxx_battery_get_voltage_max(ip5xxx, &val->intval);
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATVADC_DAT0,
- IP5XXX_BATVADC_DAT1, &raw);
+ ret = ip5xxx_battery_read_adc(ip5xxx, &ip5xxx->regs.battery.adc.volt, &raw);
+ if (ret)
+ return ret;
val->intval = 2600000 + DIV_ROUND_CLOSEST(raw * 26855, 100);
return 0;
case POWER_SUPPLY_PROP_VOLTAGE_OCV:
- ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATOCV_DAT0,
- IP5XXX_BATOCV_DAT1, &raw);
+ ret = ip5xxx_battery_read_adc(ip5xxx, &ip5xxx->regs.battery.adc.open_volt, &raw);
+ if (ret)
+ return ret;
val->intval = 2600000 + DIV_ROUND_CLOSEST(raw * 26855, 100);
return 0;
case POWER_SUPPLY_PROP_CURRENT_NOW:
- ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATIADC_DAT0,
- IP5XXX_BATIADC_DAT1, &raw);
+ ret = ip5xxx_battery_read_adc(ip5xxx, &ip5xxx->regs.battery.adc.curr, &raw);
+ if (ret)
+ return ret;
val->intval = DIV_ROUND_CLOSEST(raw * 149197, 200);
return 0;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
- ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL4A, &rval);
+ ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.const_curr_sel, &rval);
if (ret)
return ret;
- rval &= IP5XXX_CHG_CTL4A_CONST_CUR_SEL;
- val->intval = 100000 * rval;
+ val->intval = ip5xxx->const_curr.setpoint + 100000 * rval;
return 0;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
@@ -373,12 +476,11 @@ static int ip5xxx_battery_get_property(struct power_supply *psy,
if (ret)
return ret;
- ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL2, &rval);
+ ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.const_volt_sel, &rval);
if (ret)
return ret;
- rval &= IP5XXX_CHG_CTL2_CONST_VOLT_SEL;
- val->intval = vmax + 14000 * (rval >> 1);
+ val->intval = vmax + 14000 * rval;
return 0;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
@@ -399,30 +501,36 @@ static int ip5xxx_battery_set_voltage_max(struct ip5xxx *ip5xxx, int val)
unsigned int rval;
int ret;
+ if (val > ip5xxx->vbat_max)
+ return -EINVAL;
+
switch (val) {
case 4200000:
- rval = IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_2V;
+ rval = IP5XXX_BAT_TYPE_4_2V;
break;
case 4300000:
- rval = IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_3V;
+ rval = IP5XXX_BAT_TYPE_4_3V;
break;
case 4350000:
- rval = IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_35V;
+ rval = IP5XXX_BAT_TYPE_4_35V;
+ break;
+ case 4400000:
+ rval = IP5XXX_BAT_TYPE_4_4V;
break;
default:
return -EINVAL;
}
- ret = ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL2,
- IP5XXX_CHG_CTL2_BAT_TYPE_SEL, rval);
+ ret = ip5xxx_write(ip5xxx, ip5xxx->regs.battery.type, rval);
if (ret)
return ret;
- ret = ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL4,
- IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN,
- IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN);
- if (ret)
- return ret;
+ /* Don't try to auto-detect battery type, even if the IC could */
+ if (ip5xxx->regs.battery.vset_en) {
+ ret = ip5xxx_write(ip5xxx, ip5xxx->regs.battery.vset_en, 1);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -443,7 +551,7 @@ static int ip5xxx_battery_set_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_STATUS:
switch (val->intval) {
case POWER_SUPPLY_STATUS_CHARGING:
- rval = IP5XXX_SYS_CTL0_CHARGER_EN;
+ rval = 1;
break;
case POWER_SUPPLY_STATUS_DISCHARGING:
case POWER_SUPPLY_STATUS_NOT_CHARGING:
@@ -452,25 +560,22 @@ static int ip5xxx_battery_set_property(struct power_supply *psy,
default:
return -EINVAL;
}
- return ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL0,
- IP5XXX_SYS_CTL0_CHARGER_EN, rval);
+ return ip5xxx_write(ip5xxx, ip5xxx->regs.charger.enable, rval);
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
return ip5xxx_battery_set_voltage_max(ip5xxx, val->intval);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
- rval = val->intval / 100000;
- return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL4A,
- IP5XXX_CHG_CTL4A_CONST_CUR_SEL, rval);
+ rval = (val->intval - ip5xxx->const_curr.setpoint) / 100000;
+ return ip5xxx_write(ip5xxx, ip5xxx->regs.charger.const_curr_sel, rval);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax);
if (ret)
return ret;
- rval = ((val->intval - vmax) / 14000) << 1;
- return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL2,
- IP5XXX_CHG_CTL2_CONST_VOLT_SEL, rval);
+ rval = (val->intval - vmax) / 14000;
+ return ip5xxx_write(ip5xxx, ip5xxx->regs.charger.const_volt_sel, rval);
default:
return -EINVAL;
@@ -515,20 +620,20 @@ static int ip5xxx_boost_get_property(struct power_supply *psy,
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
- ret = ip5xxx_read(ip5xxx, IP5XXX_SYS_CTL0, &rval);
+ ret = ip5xxx_read(ip5xxx, ip5xxx->regs.boost.enable, &rval);
if (ret)
return ret;
- val->intval = !!(rval & IP5XXX_SYS_CTL0_BOOST_EN);
+ val->intval = !!rval;
return 0;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
- ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL1, &rval);
+ ret = ip5xxx_read(ip5xxx, ip5xxx->regs.boost.undervolt_limit, &rval);
if (ret)
return ret;
- rval &= IP5XXX_CHG_CTL1_BOOST_UVP_SEL;
- val->intval = 4530000 + 100000 * (rval >> 2);
+ val->intval = ip5xxx->boost_undervolt.setpoint +
+ ip5xxx->boost_undervolt.microvolts_per_bit * rval;
return 0;
default:
@@ -550,14 +655,12 @@ static int ip5xxx_boost_set_property(struct power_supply *psy,
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
- rval = val->intval ? IP5XXX_SYS_CTL0_BOOST_EN : 0;
- return ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL0,
- IP5XXX_SYS_CTL0_BOOST_EN, rval);
+ return ip5xxx_write(ip5xxx, ip5xxx->regs.boost.enable, !!val->intval);
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
- rval = ((val->intval - 4530000) / 100000) << 2;
- return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL1,
- IP5XXX_CHG_CTL1_BOOST_UVP_SEL, rval);
+ rval = (val->intval - ip5xxx->boost_undervolt.setpoint) /
+ ip5xxx->boost_undervolt.microvolts_per_bit;
+ return ip5xxx_write(ip5xxx, ip5xxx->regs.boost.undervolt_limit, rval);
default:
return -EINVAL;
@@ -583,11 +686,149 @@ static const struct power_supply_desc ip5xxx_boost_desc = {
static const struct regmap_config ip5xxx_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = IP5XXX_BATOCV_DAT1,
+ .max_register = 0xa9,
+};
+
+static struct ip5xxx_regfield_config ip51xx_fields = {
+ .charger_enable = REG_FIELD(0x01, 1, 1),
+ .charger_const_volt_sel = REG_FIELD(0x24, 1, 2),
+ .charger_const_curr_sel = REG_FIELD(0x25, 0, 4),
+ .charger_status = REG_FIELD(0x71, 5, 7),
+ .charger_chg_end = REG_FIELD(0x71, 3, 3),
+ .charger_timeout = REG_FIELD(0x71, 0, 2),
+ .charger_vin_overvolt = REG_FIELD(0x72, 5, 5),
+ .boost_enable = REG_FIELD(0x01, 2, 2),
+ .boost_llshdn_enable = REG_FIELD(0x02, 1, 1),
+ .boost_llshdn_i_limit = REG_FIELD(0x0c, 3, 7),
+ .boost_load_powerup_en = REG_FIELD(0x02, 0, 0),
+ .boost_vin_pullout_en = REG_FIELD(0x04, 5, 5),
+ .boost_undervolt_limit = REG_FIELD(0x22, 2, 3),
+ .boost_light_load_status = REG_FIELD(0x72, 6, 6),
+ .battery_ntc_dis = REG_FIELD(0x07, 6, 6),
+ .battery_type = REG_FIELD(0x24, 5, 6),
+ .battery_vset_en = REG_FIELD(0x26, 6, 6),
+ .battery_adc_volt_low = REG_FIELD(0xa2, 0, 7),
+ .battery_adc_volt_high = REG_FIELD(0xa3, 0, 5),
+ .battery_adc_curr_low = REG_FIELD(0xa4, 0, 7),
+ .battery_adc_curr_high = REG_FIELD(0xa5, 0, 5),
+ .battery_adc_ovolt_low = REG_FIELD(0xa8, 0, 7),
+ .battery_adc_ovolt_high = REG_FIELD(0xa9, 0, 5),
+ .btn_shdn_enable = REG_FIELD(0x03, 5, 5),
+ .btn_wled_mode = REG_FIELD(0x07, 1, 1),
+ .btn_shdn_mode = REG_FIELD(0x07, 0, 0),
+ .btn_long_press_time = REG_FIELD(0x03, 6, 7),
+ .btn_pressed = REG_FIELD(0x77, 3, 3),
+ .btn_long_pressed = REG_FIELD(0x77, 1, 1),
+ .btn_short_pressed = REG_FIELD(0x77, 0, 0),
+ .wled_enable = REG_FIELD(0x01, 3, 3),
+ .wled_detect_en = REG_FIELD(0x01, 4, 4),
+ .wled_present = REG_FIELD(0x72, 7, 7),
+
+ .vbat_max = 4350000,
+ .boost_undervolt_setpoint = 4530000,
+ .boost_undervolt_uv_per_bit = 100000,
+};
+
+static struct ip5xxx_regfield_config ip5306_fields = {
+ .charger_enable = REG_FIELD(0x00, 4, 4),
+ .charger_const_volt_sel = REG_FIELD(0x22, 0, 1),
+ .charger_const_curr_sel = REG_FIELD(0x24, 0, 4),
+ .charger_status = REG_FIELD_UNSUPPORTED, // other bits...
+ .charger_chg_end = REG_FIELD(0x71, 3, 3),
+ .charger_timeout = REG_FIELD_UNSUPPORTED,
+ .charger_vin_overvolt = REG_FIELD_UNSUPPORTED,
+ .boost_enable = REG_FIELD(0x00, 5, 5),
+ .boost_llshdn_enable = REG_FIELD_UNSUPPORTED,
+ .boost_llshdn_i_limit = REG_FIELD_UNSUPPORTED,
+ .boost_load_powerup_en = REG_FIELD(0x00, 2, 2),
+ .boost_vin_pullout_en = REG_FIELD(0x01, 2, 2),
+ .boost_undervolt_limit = REG_FIELD(0x21, 2, 4),
+ .boost_light_load_status = REG_FIELD(0x72, 2, 2),
+ .battery_ntc_dis = REG_FIELD_UNSUPPORTED,
+ .battery_type = REG_FIELD(0x22, 2, 3),
+ .battery_vset_en = REG_FIELD_UNSUPPORTED,
+ .battery_adc_volt_low = REG_FIELD_UNSUPPORTED,
+ .battery_adc_volt_high = REG_FIELD_UNSUPPORTED,
+ .battery_adc_curr_low = REG_FIELD_UNSUPPORTED,
+ .battery_adc_curr_high = REG_FIELD_UNSUPPORTED,
+ .battery_adc_ovolt_low = REG_FIELD_UNSUPPORTED,
+ .battery_adc_ovolt_high = REG_FIELD_UNSUPPORTED,
+ .btn_shdn_enable = REG_FIELD(0x00, 0, 0),
+ .btn_wled_mode = REG_FIELD(0x01, 6, 6),
+ .btn_shdn_mode = REG_FIELD(0x01, 7, 7),
+ .btn_long_press_time = REG_FIELD(0x02, 4, 4), // +1s
+ .btn_pressed = REG_FIELD_UNSUPPORTED,
+ /* TODO: double press */
+ .btn_long_pressed = REG_FIELD(0x77, 1, 1),
+ .btn_short_pressed = REG_FIELD(0x77, 0, 0),
+ .wled_enable = REG_FIELD_UNSUPPORTED,
+ .wled_detect_en = REG_FIELD_UNSUPPORTED,
+ .wled_present = REG_FIELD_UNSUPPORTED,
+
+ .vbat_max = 4400000,
+ .boost_undervolt_setpoint = 4450000,
+ .boost_undervolt_uv_per_bit = 50000,
+ .const_curr_setpoint = 50000,
+ .chg_end_inverted = 1,
};
+#define ip5xxx_setup_reg(_field, _reg) \
+ do { \
+ if (likely(cfg->_field.lsb <= cfg->_field.msb)) { \
+ struct regmap_field *_tmp = devm_regmap_field_alloc(dev, \
+ ip5xxx->regmap, cfg->_field); \
+ if (!IS_ERR(_tmp)) \
+ ip5xxx->regs._reg = _tmp; \
+ } \
+ } while (0)
+
+static void ip5xxx_setup_regs(struct device *dev, struct ip5xxx *ip5xxx,
+ const struct ip5xxx_regfield_config *cfg)
+{
+ ip5xxx_setup_reg(charger_enable, charger.enable);
+ ip5xxx_setup_reg(charger_const_volt_sel, charger.const_volt_sel);
+ ip5xxx_setup_reg(charger_const_curr_sel, charger.const_curr_sel);
+ ip5xxx_setup_reg(charger_status, charger.status);
+ ip5xxx_setup_reg(charger_chg_end, charger.chg_end);
+ ip5xxx_setup_reg(charger_timeout, charger.timeout);
+ ip5xxx_setup_reg(charger_vin_overvolt, charger.vin_overvolt);
+ ip5xxx_setup_reg(boost_enable, boost.enable);
+ ip5xxx_setup_reg(boost_llshdn_enable, boost.light_load_shutdown.enable);
+ ip5xxx_setup_reg(boost_llshdn_i_limit, boost.light_load_shutdown.i_limit);
+ ip5xxx_setup_reg(boost_load_powerup_en, boost.load_powerup_en);
+ ip5xxx_setup_reg(boost_vin_pullout_en, boost.vin_pullout_en);
+ ip5xxx_setup_reg(boost_undervolt_limit, boost.undervolt_limit);
+ ip5xxx_setup_reg(boost_light_load_status, boost.light_load_status);
+ ip5xxx_setup_reg(battery_ntc_dis, battery.ntc_dis);
+ ip5xxx_setup_reg(battery_type, battery.type);
+ ip5xxx_setup_reg(battery_vset_en, battery.vset_en);
+ ip5xxx_setup_reg(battery_adc_volt_low, battery.adc.volt.low);
+ ip5xxx_setup_reg(battery_adc_volt_high, battery.adc.volt.high);
+ ip5xxx_setup_reg(battery_adc_curr_low, battery.adc.curr.low);
+ ip5xxx_setup_reg(battery_adc_curr_high, battery.adc.curr.high);
+ ip5xxx_setup_reg(battery_adc_ovolt_low, battery.adc.open_volt.low);
+ ip5xxx_setup_reg(battery_adc_ovolt_high, battery.adc.open_volt.high);
+ ip5xxx_setup_reg(btn_shdn_enable, btn.shdn_enable);
+ ip5xxx_setup_reg(btn_wled_mode, btn.wled_mode);
+ ip5xxx_setup_reg(btn_shdn_mode, btn.shdn_mode);
+ ip5xxx_setup_reg(btn_long_press_time, btn.long_press_time);
+ ip5xxx_setup_reg(btn_pressed, btn.pressed);
+ ip5xxx_setup_reg(btn_long_pressed, btn.long_pressed);
+ ip5xxx_setup_reg(btn_short_pressed, btn.short_pressed);
+ ip5xxx_setup_reg(wled_enable, wled.enable);
+ ip5xxx_setup_reg(wled_detect_en, wled.detect_en);
+ ip5xxx_setup_reg(wled_present, wled.present);
+
+ ip5xxx->vbat_max = cfg->vbat_max;
+ ip5xxx->boost_undervolt.setpoint = cfg->boost_undervolt_setpoint;
+ ip5xxx->boost_undervolt.microvolts_per_bit = cfg->boost_undervolt_uv_per_bit;
+ ip5xxx->const_curr.setpoint = cfg->const_curr_setpoint;
+ ip5xxx->chg_end_inverted = cfg->chg_end_inverted;
+}
+
static int ip5xxx_power_probe(struct i2c_client *client)
{
+ const struct ip5xxx_regfield_config *fields;
struct power_supply_config psy_cfg = {};
struct device *dev = &client->dev;
struct power_supply *psy;
@@ -601,7 +842,10 @@ static int ip5xxx_power_probe(struct i2c_client *client)
if (IS_ERR(ip5xxx->regmap))
return PTR_ERR(ip5xxx->regmap);
- psy_cfg.of_node = dev->of_node;
+ fields = i2c_get_match_data(client) ?: &ip51xx_fields;
+ ip5xxx_setup_regs(dev, ip5xxx, fields);
+
+ psy_cfg.fwnode = dev_fwnode(dev);
psy_cfg.drv_data = ip5xxx;
psy = devm_power_supply_register(dev, &ip5xxx_battery_desc, &psy_cfg);
@@ -616,10 +860,11 @@ static int ip5xxx_power_probe(struct i2c_client *client)
}
static const struct of_device_id ip5xxx_power_of_match[] = {
- { .compatible = "injoinic,ip5108" },
- { .compatible = "injoinic,ip5109" },
- { .compatible = "injoinic,ip5207" },
- { .compatible = "injoinic,ip5209" },
+ { .compatible = "injoinic,ip5108", .data = &ip51xx_fields },
+ { .compatible = "injoinic,ip5109", .data = &ip51xx_fields },
+ { .compatible = "injoinic,ip5207", .data = &ip51xx_fields },
+ { .compatible = "injoinic,ip5209", .data = &ip51xx_fields },
+ { .compatible = "injoinic,ip5306", .data = &ip5306_fields },
{ }
};
MODULE_DEVICE_TABLE(of, ip5xxx_power_of_match);
diff --git a/drivers/power/supply/lego_ev3_battery.c b/drivers/power/supply/lego_ev3_battery.c
index 9085de0ae1b2..28454de05761 100644
--- a/drivers/power/supply/lego_ev3_battery.c
+++ b/drivers/power/supply/lego_ev3_battery.c
@@ -23,6 +23,7 @@
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
+#include <linux/property.h>
struct lego_ev3_battery {
struct iio_channel *iio_v;
@@ -198,7 +199,7 @@ static int lego_ev3_battery_probe(struct platform_device *pdev)
batt->v_min = 48000000;
}
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = batt;
batt->psy = devm_power_supply_register(dev, &lego_ev3_battery_desc,
diff --git a/drivers/power/supply/lt3651-charger.c b/drivers/power/supply/lt3651-charger.c
index 8de500ffad95..ebfbdbcb7683 100644
--- a/drivers/power/supply/lt3651-charger.c
+++ b/drivers/power/supply/lt3651-charger.c
@@ -131,7 +131,7 @@ static int lt3651_charger_probe(struct platform_device *pdev)
charger_desc->properties = lt3651_charger_properties;
charger_desc->num_properties = ARRAY_SIZE(lt3651_charger_properties);
charger_desc->get_property = lt3651_charger_get_property;
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = lt3651_charger;
lt3651_charger->charger = devm_power_supply_register(&pdev->dev,
diff --git a/drivers/power/supply/ltc4162-l-charger.c b/drivers/power/supply/ltc4162-l-charger.c
index 2e4bc74e1c4a..9dd74fa9552d 100644
--- a/drivers/power/supply/ltc4162-l-charger.c
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -1,9 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.
+ * Driver for Analog Devices (Linear Technology)
+ * LTC4162-L 35V/3.2A Multi-Cell Lithium-Ion Step-Down Battery Charger
+ * LTC4162-F 35V/3.2A Multi-Cell LiFePO4 Step-Down Battery Charger
+ * LTC4162-S 35V/3.2A Lead-Acid Step-Down Battery Charger
+ * LTC4015 35V/3.2A Multichemistry Buck Battery Charger Controller
* Copyright (C) 2020, Topic Embedded Products
*/
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/of.h>
@@ -47,6 +52,20 @@
#define LTC4162L_VBAT_FILT 0x47
#define LTC4162L_INPUT_UNDERVOLTAGE_DAC 0x4B
+#define LTC4162L_CHEM_MASK GENMASK(11, 8)
+
+enum ltc4162_chem {
+ ltc4162_lad,
+ ltc4162_l42,
+ ltc4162_l41,
+ ltc4162_l40,
+ ltc4162_fad,
+ ltc4162_ffs,
+ ltc4162_fst,
+ ltc4162_sst = 8,
+ ltc4162_sad,
+};
+
/* Enumeration as in datasheet. Individual bits are mutually exclusive. */
enum ltc4162l_state {
battery_detection = 2048,
@@ -75,10 +94,28 @@ enum ltc4162l_charge_status {
/* Magic number to write to ARM_SHIP_MODE register */
#define LTC4162L_ARM_SHIP_MODE_MAGIC 21325
+struct ltc4162l_info;
+
+struct ltc4162l_chip_info {
+ const char *name;
+ int (*get_vbat)(struct ltc4162l_info *info, unsigned int reg,
+ union power_supply_propval *val);
+ int (*get_vcharge)(struct ltc4162l_info *info, unsigned int reg,
+ union power_supply_propval *val);
+ int (*set_vcharge)(struct ltc4162l_info *info, unsigned int reg,
+ unsigned int value);
+ int (*get_die_temp)(struct ltc4162l_info *info,
+ union power_supply_propval *val);
+ unsigned int ibat_resolution_pv;
+ unsigned int vin_resolution_uv;
+ u8 telemetry_mask;
+};
+
struct ltc4162l_info {
struct i2c_client *client;
struct regmap *regmap;
struct power_supply *charger;
+ const struct ltc4162l_chip_info *chip_info;
u32 rsnsb; /* Series resistor that sets charge current, microOhm */
u32 rsnsi; /* Series resistor to measure input current, microOhm */
u8 cell_count; /* Number of connected cells, 0 while unknown */
@@ -108,6 +145,18 @@ static u8 ltc4162l_get_cell_count(struct ltc4162l_info *info)
return val;
};
+static u8 ltc4162l_get_chem_type(struct ltc4162l_info *info)
+{
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(info->regmap, LTC4162L_CHEM_CELLS_REG, &val);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(LTC4162L_CHEM_MASK, val);
+};
+
/* Convert enum value to POWER_SUPPLY_STATUS value */
static int ltc4162l_state_decode(enum ltc4162l_state value)
{
@@ -223,25 +272,83 @@ static int ltc4162l_get_vbat(struct ltc4162l_info *info,
unsigned int reg,
union power_supply_propval *val)
{
- unsigned int regval;
+ unsigned int regval, chem_type;
int ret;
ret = regmap_read(info->regmap, reg, &regval);
if (ret)
return ret;
- /* cell_count × 192.4μV/LSB */
- regval *= 1924;
- regval *= ltc4162l_get_cell_count(info);
- regval /= 10;
- val->intval = regval;
+ /*
+ * cell_count × scaling factor
+ * For ltc4162-s, it uses a cell_count value of 2 for each group of 3
+ * physical (2V) cells, thus will return 2, 4, 6, 8 for 6V, 12V, 18V,
+ * and 24V respectively, and has to divide by 2 to multiply the scale
+ * factor by 1, 2, 3, or 4 to represent a 6V, 12V, 18V, or 24V battery
+ * respectively.
+ */
+ chem_type = ltc4162l_get_chem_type(info);
+ switch (chem_type) {
+ case ltc4162_lad ... ltc4162_fst:
+ regval *= 1924;
+ regval *= ltc4162l_get_cell_count(info);
+ regval /= 10;
+ val->intval = regval;
- return 0;
+ return 0;
+ case ltc4162_sst ... ltc4162_sad:
+ regval *= 3848;
+ regval *= ltc4162l_get_cell_count(info) / 2;
+ regval /= 10;
+ val->intval = regval;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ltc4015_get_vbat(struct ltc4162l_info *info,
+ unsigned int reg,
+ union power_supply_propval *val)
+{
+ unsigned int regval, chem_type;
+ int ret;
+
+ ret = regmap_read(info->regmap, reg, &regval);
+ if (ret)
+ return ret;
+
+ /*
+ * cell count x scaling factor
+ * ltc4015 lead-acid fixed and lead-acid programmable corresponds to
+ * 0x7 and 0x8 chem respectively
+ */
+ chem_type = ltc4162l_get_chem_type(info);
+ switch (chem_type) {
+ case ltc4162_lad ... ltc4162_fst:
+ regval *= 192264;
+ regval *= ltc4162l_get_cell_count(info);
+ regval /= 1000;
+ val->intval = regval;
+
+ return 0;
+ case ltc4162_sst - 1 ... ltc4162_sad - 1:
+ regval *= 128176;
+ regval *= ltc4162l_get_cell_count(info);
+ regval /= 1000;
+ val->intval = regval;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
}
static int ltc4162l_get_ibat(struct ltc4162l_info *info,
union power_supply_propval *val)
{
+ const struct ltc4162l_chip_info *chip_info = info->chip_info;
unsigned int regval;
int ret;
@@ -249,9 +356,8 @@ static int ltc4162l_get_ibat(struct ltc4162l_info *info,
if (ret)
return ret;
- /* Signed 16-bit number, 1.466μV / RSNSB amperes/LSB. */
ret = (s16)(regval & 0xFFFF);
- val->intval = 100 * mult_frac(ret, 14660, (int)info->rsnsb);
+ val->intval = mult_frac(ret, chip_info->ibat_resolution_pv, info->rsnsb);
return 0;
}
@@ -260,6 +366,7 @@ static int ltc4162l_get_ibat(struct ltc4162l_info *info,
static int ltc4162l_get_input_voltage(struct ltc4162l_info *info,
union power_supply_propval *val)
{
+ const struct ltc4162l_chip_info *chip_info = info->chip_info;
unsigned int regval;
int ret;
@@ -267,8 +374,7 @@ static int ltc4162l_get_input_voltage(struct ltc4162l_info *info,
if (ret)
return ret;
- /* 1.649mV/LSB */
- val->intval = regval * 1694;
+ val->intval = regval * chip_info->vin_resolution_uv;
return 0;
}
@@ -276,6 +382,7 @@ static int ltc4162l_get_input_voltage(struct ltc4162l_info *info,
static int ltc4162l_get_input_current(struct ltc4162l_info *info,
union power_supply_propval *val)
{
+ const struct ltc4162l_chip_info *chip_info = info->chip_info;
unsigned int regval;
int ret;
@@ -283,11 +390,9 @@ static int ltc4162l_get_input_current(struct ltc4162l_info *info,
if (ret)
return ret;
- /* Signed 16-bit number, 1.466μV / RSNSI amperes/LSB. */
ret = (s16)(regval & 0xFFFF);
- ret *= 14660;
+ ret *= chip_info->ibat_resolution_pv;
ret /= info->rsnsi;
- ret *= 100;
val->intval = ret;
@@ -305,7 +410,7 @@ static int ltc4162l_get_icharge(struct ltc4162l_info *info,
if (ret)
return ret;
- regval &= BIT(6) - 1; /* Only the lower 5 bits */
+ regval &= GENMASK(5, 0);
/* The charge current servo level: (icharge_dac + 1) × 1mV/RSNSB */
++regval;
@@ -336,7 +441,7 @@ static int ltc4162l_get_vcharge(struct ltc4162l_info *info,
unsigned int reg,
union power_supply_propval *val)
{
- unsigned int regval;
+ unsigned int regval, chem_type;
int ret;
u32 voltage;
@@ -344,41 +449,181 @@ static int ltc4162l_get_vcharge(struct ltc4162l_info *info,
if (ret)
return ret;
- regval &= BIT(6) - 1; /* Only the lower 5 bits */
+ regval &= GENMASK(5, 0);
/*
* charge voltage setting can be computed from
- * cell_count × (vcharge_setting × 12.5mV + 3.8125V)
- * where vcharge_setting ranges from 0 to 31 (4.2V max).
+ * cell_count × (vcharge_setting × a + b)
+ * where vcharge_setting ranges from 0 to c (d).
+ * for ltc4162l: a = 12.5mV , b = 3.8125V, c = 31, d = 4.2Vmax
+ * for ltc4162f: a = 12.5mV , b = 3.4125V, c = 31, d = 3.8Vmax
+ *
+ * for ltc4162s, the charge voltage setting can be computed from
+ * N x (vcharge_setting x 28.571mV + 6.0V)
+ * where N is 1, 2, 3, or 4 for 6V, 12V, 18V, or 24V battery respectively,
+ * and vcharge_setting ranges from 0 to 31
*/
- voltage = 3812500 + (regval * 12500);
- voltage *= ltc4162l_get_cell_count(info);
- val->intval = voltage;
+ chem_type = ltc4162l_get_chem_type(info);
+ switch (chem_type) {
+ case ltc4162_lad ... ltc4162_l40:
+ voltage = 3812500 + (regval * 12500);
+ voltage *= ltc4162l_get_cell_count(info);
+ val->intval = voltage;
- return 0;
+ return 0;
+ case ltc4162_fad ... ltc4162_fst:
+ voltage = 3412500 + (regval * 12500);
+ voltage *= ltc4162l_get_cell_count(info);
+ val->intval = voltage;
+
+ return 0;
+ case ltc4162_sst ... ltc4162_sad:
+ voltage = 6000000 + (regval * 28571);
+ voltage *= ltc4162l_get_cell_count(info) / 2;
+ val->intval = voltage;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
}
-static int ltc4162l_set_vcharge(struct ltc4162l_info *info,
- unsigned int reg,
- unsigned int value)
+static int ltc4015_get_vcharge(struct ltc4162l_info *info,
+ unsigned int reg,
+ union power_supply_propval *val)
{
- u8 cell_count = ltc4162l_get_cell_count(info);
+ unsigned int regval, chem_type;
+ int ret;
+ u32 voltage;
+
+ ret = regmap_read(info->regmap, reg, &regval);
+ if (ret)
+ return ret;
- if (!cell_count)
- return -EBUSY; /* Not available yet, try again later */
+ regval &= GENMASK(5, 0);
+ /*
+ * charge voltage setting can be computed from:
+ * cell_count × (vcharge_setting × a + b)
+ * where vcharge_setting ranges from 0 to c (d).
+ * Li-Ion: a = 1/80V, b = 3.8125V, c = 31, d = 4.2Vmax
+ * LiFePO4: a = 1/80V, b = 3.4125V, c = 31, d = 3.8Vmax
+ * Lead Acid: a = 1/105V, b = 2V, c = 35, d = 2.6Vmax
+ */
+ chem_type = ltc4162l_get_chem_type(info);
+ switch (chem_type) {
+ case ltc4162_lad ... ltc4162_l40:
+ voltage = 3812500 + (regval * 12500);
+ voltage *= ltc4162l_get_cell_count(info);
+ val->intval = voltage;
+
+ return 0;
+ case ltc4162_fad ... ltc4162_fst:
+ voltage = 3412500 + (regval * 12500);
+ voltage *= ltc4162l_get_cell_count(info);
+ val->intval = voltage;
+
+ return 0;
+ case ltc4162_sst - 1 ... ltc4162_sad - 1:
+ voltage = 2000000 + mult_frac(regval, 1000000, 105);
+ voltage *= ltc4162l_get_cell_count(info);
+ val->intval = voltage;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ltc4162l_vcharge(unsigned int base_voltage,
+ unsigned int scale_factor,
+ unsigned int range,
+ unsigned int value,
+ u8 cell_count)
+{
value /= cell_count;
- if (value < 3812500)
+ if (value < base_voltage)
return -EINVAL;
- value -= 3812500;
- value /= 12500;
+ value -= base_voltage;
+ value /= scale_factor;
- if (value > 31)
+ if (value > range)
return -EINVAL;
- return regmap_write(info->regmap, reg, value);
+ return value;
+}
+
+static int ltc4162l_set_vcharge(struct ltc4162l_info *info,
+ unsigned int reg,
+ unsigned int value)
+{
+ unsigned int chem_type;
+ u8 cell_count;
+
+ chem_type = ltc4162l_get_chem_type(info);
+ switch (chem_type) {
+ case ltc4162_lad ... ltc4162_l40:
+ cell_count = ltc4162l_get_cell_count(info);
+ if (!cell_count)
+ return -EBUSY;
+
+ value = ltc4162l_vcharge(3812500, 12500, 31, value, cell_count);
+ return regmap_write(info->regmap, reg, value);
+ case ltc4162_fad ... ltc4162_fst:
+ cell_count = ltc4162l_get_cell_count(info);
+ if (!cell_count)
+ return -EBUSY;
+
+ value = ltc4162l_vcharge(3412500, 12500, 31, value, cell_count);
+ return regmap_write(info->regmap, reg, value);
+ case ltc4162_sst ... ltc4162_sad:
+ cell_count = ltc4162l_get_cell_count(info) / 2;
+ if (!cell_count)
+ return -EBUSY;
+
+ value = ltc4162l_vcharge(6000000, 28571, 31, value, cell_count);
+ return regmap_write(info->regmap, reg, value);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ltc4015_set_vcharge(struct ltc4162l_info *info,
+ unsigned int reg,
+ unsigned int value)
+{
+ unsigned int chem_type;
+ u8 cell_count;
+
+ chem_type = ltc4162l_get_chem_type(info);
+ switch (chem_type) {
+ case ltc4162_lad ... ltc4162_l40:
+ cell_count = ltc4162l_get_cell_count(info);
+ if (!cell_count)
+ return -EBUSY;
+
+ value = ltc4162l_vcharge(3812500, 12500, 31, value, cell_count);
+ return regmap_write(info->regmap, reg, value);
+ case ltc4162_fad ... ltc4162_fst:
+ cell_count = ltc4162l_get_cell_count(info);
+ if (!cell_count)
+ return -EBUSY;
+
+ value = ltc4162l_vcharge(3412500, 12500, 31, value, cell_count);
+ return regmap_write(info->regmap, reg, value);
+ case ltc4162_sst - 1 ... ltc4162_sad - 1:
+ cell_count = ltc4162l_get_cell_count(info);
+ if (!cell_count)
+ return -EBUSY;
+
+ value = ltc4162l_vcharge(2000000, 1000000 / 105, 35,
+ value, cell_count);
+ return regmap_write(info->regmap, reg, value);
+ default:
+ return -EINVAL;
+ }
}
static int ltc4162l_get_iin_limit_dac(struct ltc4162l_info *info,
@@ -391,7 +636,7 @@ static int ltc4162l_get_iin_limit_dac(struct ltc4162l_info *info,
if (ret)
return ret;
- regval &= BIT(6) - 1; /* Only 6 bits */
+ regval &= GENMASK(5, 0);
/* (iin_limit_dac + 1) × 500μV / RSNSI */
++regval;
@@ -437,9 +682,30 @@ static int ltc4162l_get_die_temp(struct ltc4162l_info *info,
return 0;
}
+static int ltc4015_get_die_temp(struct ltc4162l_info *info,
+ union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, LTC4162L_DIE_TEMPERATURE, &regval);
+ if (ret)
+ return ret;
+
+ /* (die_temp - 12010) / 45.6°C */
+ ret = (s16)(regval & 0xFFFF);
+ ret -= 12010;
+ ret *= 1000;
+ ret /= 456;
+ val->intval = ret;
+
+ return 0;
+}
+
static int ltc4162l_get_term_current(struct ltc4162l_info *info,
union power_supply_propval *val)
{
+ const struct ltc4162l_chip_info *chip_info = info->chip_info;
unsigned int regval;
int ret;
@@ -457,10 +723,9 @@ static int ltc4162l_get_term_current(struct ltc4162l_info *info,
if (ret)
return ret;
- /* 1.466μV / RSNSB amperes/LSB */
- regval *= 14660u;
+ regval *= chip_info->ibat_resolution_pv;
regval /= info->rsnsb;
- val->intval = 100 * regval;
+ val->intval = regval;
return 0;
}
@@ -534,10 +799,11 @@ static ssize_t vbat_show(struct device *dev,
{
struct power_supply *psy = to_power_supply(dev);
struct ltc4162l_info *info = power_supply_get_drvdata(psy);
+ const struct ltc4162l_chip_info *chip_info = info->chip_info;
union power_supply_propval val;
int ret;
- ret = ltc4162l_get_vbat(info, LTC4162L_VBAT, &val);
+ ret = chip_info->get_vbat(info, LTC4162L_VBAT, &val);
if (ret)
return ret;
@@ -550,10 +816,11 @@ static ssize_t vbat_avg_show(struct device *dev,
{
struct power_supply *psy = to_power_supply(dev);
struct ltc4162l_info *info = power_supply_get_drvdata(psy);
+ const struct ltc4162l_chip_info *chip_info = info->chip_info;
union power_supply_propval val;
int ret;
- ret = ltc4162l_get_vbat(info, LTC4162L_VBAT_FILT, &val);
+ ret = chip_info->get_vbat(info, LTC4162L_VBAT_FILT, &val);
if (ret)
return ret;
@@ -589,7 +856,8 @@ static ssize_t force_telemetry_show(struct device *dev,
if (ret)
return ret;
- return sysfs_emit(buf, "%u\n", regval & BIT(2) ? 1 : 0);
+ return sysfs_emit(buf, "%u\n", regval &
+ info->chip_info->telemetry_mask ? 1 : 0);
}
static ssize_t force_telemetry_store(struct device *dev,
@@ -607,7 +875,8 @@ static ssize_t force_telemetry_store(struct device *dev,
return ret;
ret = regmap_update_bits(info->regmap, LTC4162L_CONFIG_BITS_REG,
- BIT(2), value ? BIT(2) : 0);
+ info->chip_info->telemetry_mask,
+ value ? info->chip_info->telemetry_mask : 0);
if (ret < 0)
return ret;
@@ -681,6 +950,7 @@ static int ltc4162l_get_property(struct power_supply *psy,
union power_supply_propval *val)
{
struct ltc4162l_info *info = power_supply_get_drvdata(psy);
+ const struct ltc4162l_chip_info *chip_info = info->chip_info;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
@@ -702,15 +972,13 @@ static int ltc4162l_get_property(struct power_supply *psy,
return ltc4162l_get_icharge(info,
LTC4162L_CHARGE_CURRENT_SETTING, val);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
- return ltc4162l_get_vcharge(info,
- LTC4162L_VCHARGE_DAC, val);
+ return chip_info->get_vcharge(info, LTC4162L_VCHARGE_DAC, val);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
- return ltc4162l_get_vcharge(info,
- LTC4162L_VCHARGE_SETTING, val);
+ return chip_info->get_vcharge(info, LTC4162L_VCHARGE_SETTING, val);
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return ltc4162l_get_iin_limit_dac(info, val);
case POWER_SUPPLY_PROP_TEMP:
- return ltc4162l_get_die_temp(info, val);
+ return chip_info->get_die_temp(info, val);
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
return ltc4162l_get_term_current(info, val);
default:
@@ -772,7 +1040,6 @@ static enum power_supply_property ltc4162l_properties[] = {
};
static const struct power_supply_desc ltc4162l_desc = {
- .name = "ltc4162-l",
.type = POWER_SUPPLY_TYPE_MAINS,
.properties = ltc4162l_properties,
.num_properties = ARRAY_SIZE(ltc4162l_properties),
@@ -781,6 +1048,50 @@ static const struct power_supply_desc ltc4162l_desc = {
.property_is_writeable = ltc4162l_property_is_writeable,
};
+static const struct ltc4162l_chip_info ltc4162l_chip_info = {
+ .name = "ltc4162-l",
+ .get_vbat = ltc4162l_get_vbat,
+ .get_vcharge = ltc4162l_get_vcharge,
+ .set_vcharge = ltc4162l_set_vcharge,
+ .get_die_temp = ltc4162l_get_die_temp,
+ .ibat_resolution_pv = 1466000,
+ .vin_resolution_uv = 1649,
+ .telemetry_mask = BIT(2),
+};
+
+static const struct ltc4162l_chip_info ltc4162f_chip_info = {
+ .name = "ltc4162-f",
+ .get_vbat = ltc4162l_get_vbat,
+ .get_vcharge = ltc4162l_get_vcharge,
+ .set_vcharge = ltc4162l_set_vcharge,
+ .get_die_temp = ltc4162l_get_die_temp,
+ .ibat_resolution_pv = 1466000,
+ .vin_resolution_uv = 1649,
+ .telemetry_mask = BIT(2),
+};
+
+static const struct ltc4162l_chip_info ltc4162s_chip_info = {
+ .name = "ltc4162-s",
+ .get_vbat = ltc4162l_get_vbat,
+ .get_vcharge = ltc4162l_get_vcharge,
+ .set_vcharge = ltc4162l_set_vcharge,
+ .get_die_temp = ltc4162l_get_die_temp,
+ .ibat_resolution_pv = 1466000,
+ .vin_resolution_uv = 1649,
+ .telemetry_mask = BIT(2),
+};
+
+static const struct ltc4162l_chip_info ltc4015_chip_info = {
+ .name = "ltc4015",
+ .get_vbat = ltc4015_get_vbat,
+ .get_vcharge = ltc4015_get_vcharge,
+ .set_vcharge = ltc4015_set_vcharge,
+ .get_die_temp = ltc4015_get_die_temp,
+ .ibat_resolution_pv = 1464870,
+ .vin_resolution_uv = 1648,
+ .telemetry_mask = BIT(4),
+};
+
static bool ltc4162l_is_writeable_reg(struct device *dev, unsigned int reg)
{
/* all registers up to this one are writeable */
@@ -808,7 +1119,7 @@ static const struct regmap_config ltc4162l_regmap_config = {
.writeable_reg = ltc4162l_is_writeable_reg,
.volatile_reg = ltc4162l_is_volatile_reg,
.max_register = LTC4162L_INPUT_UNDERVOLTAGE_DAC,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static void ltc4162l_clear_interrupts(struct ltc4162l_info *info)
@@ -825,6 +1136,8 @@ static int ltc4162l_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct ltc4162l_info *info;
struct power_supply_config ltc4162l_config = {};
+ struct power_supply_desc *desc;
+ const struct ltc4162l_chip_info *chip_info;
u32 value;
int ret;
@@ -839,6 +1152,12 @@ static int ltc4162l_probe(struct i2c_client *client)
info->client = client;
i2c_set_clientdata(client, info);
+ chip_info = i2c_get_match_data(client);
+ if (!chip_info)
+ return -ENODEV;
+
+ info->chip_info = chip_info;
+
info->regmap = devm_regmap_init_i2c(client, &ltc4162l_regmap_config);
if (IS_ERR(info->regmap)) {
dev_err(dev, "Failed to initialize register map\n");
@@ -866,12 +1185,19 @@ static int ltc4162l_probe(struct i2c_client *client)
if (!device_property_read_u32(dev, "lltc,cell-count", &value))
info->cell_count = value;
- ltc4162l_config.of_node = dev->of_node;
+ ltc4162l_config.fwnode = dev_fwnode(dev);
ltc4162l_config.drv_data = info;
ltc4162l_config.attr_grp = ltc4162l_attr_groups;
- info->charger = devm_power_supply_register(dev, &ltc4162l_desc,
- &ltc4162l_config);
+ /* Duplicate the default descriptor to set name based on chip_info. */
+ desc = devm_kmemdup(dev, &ltc4162l_desc,
+ sizeof(struct power_supply_desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->name = chip_info->name;
+
+ info->charger = devm_power_supply_register(dev, desc, &ltc4162l_config);
if (IS_ERR(info->charger)) {
dev_err(dev, "Failed to register charger\n");
return PTR_ERR(info->charger);
@@ -903,14 +1229,20 @@ static void ltc4162l_alert(struct i2c_client *client,
}
static const struct i2c_device_id ltc4162l_i2c_id_table[] = {
- { "ltc4162-l" },
+ { "ltc4015", (kernel_ulong_t)&ltc4015_chip_info },
+ { "ltc4162-f", (kernel_ulong_t)&ltc4162f_chip_info },
+ { "ltc4162-l", (kernel_ulong_t)&ltc4162l_chip_info },
+ { "ltc4162-s", (kernel_ulong_t)&ltc4162s_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc4162l_i2c_id_table);
static const struct of_device_id ltc4162l_of_match[] __maybe_unused = {
- { .compatible = "lltc,ltc4162-l", },
- { },
+ { .compatible = "lltc,ltc4015", .data = &ltc4015_chip_info },
+ { .compatible = "lltc,ltc4162-f", .data = &ltc4162f_chip_info },
+ { .compatible = "lltc,ltc4162-l", .data = &ltc4162l_chip_info },
+ { .compatible = "lltc,ltc4162-s", .data = &ltc4162s_chip_info },
+ { }
};
MODULE_DEVICE_TABLE(of, ltc4162l_of_match);
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 51310f6e4803..c1640bc6accd 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -410,8 +410,9 @@ static int max17040_get_property(struct power_supply *psy,
if (!chip->channel_temp)
return -ENODATA;
- iio_read_channel_processed_scale(chip->channel_temp,
- &val->intval, 10);
+ iio_read_channel_processed(chip->channel_temp, &val->intval);
+ val->intval /= 100; /* Convert from milli- to deci-degree */
+
break;
default:
return -EINVAL;
diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index 496c3e1f2ee6..acea176101fa 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -16,6 +16,7 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/mod_devicetable.h>
#include <linux/power_supply.h>
@@ -52,13 +53,14 @@
#define MAX17042_VMAX_TOLERANCE 50 /* 50 mV */
struct max17042_chip {
- struct i2c_client *client;
+ struct device *dev;
struct regmap *regmap;
struct power_supply *battery;
enum max170xx_chip_type chip_type;
struct max17042_platform_data *pdata;
struct work_struct work;
int init_complete;
+ int irq;
};
static enum power_supply_property max17042_battery_props[] = {
@@ -573,11 +575,11 @@ static inline int max17042_model_data_compare(struct max17042_chip *chip,
int i;
if (memcmp(data1, data2, size)) {
- dev_err(&chip->client->dev, "%s compare failed\n", __func__);
+ dev_err(chip->dev, "%s compare failed\n", __func__);
for (i = 0; i < size; i++)
- dev_info(&chip->client->dev, "0x%x, 0x%x",
+ dev_info(chip->dev, "0x%x, 0x%x",
data1[i], data2[i]);
- dev_info(&chip->client->dev, "\n");
+ dev_info(chip->dev, "\n");
return -EINVAL;
}
return 0;
@@ -812,14 +814,14 @@ static int max17042_init_chip(struct max17042_chip *chip)
/* write cell characterization data */
ret = max17042_init_model(chip);
if (ret) {
- dev_err(&chip->client->dev, "%s init failed\n",
+ dev_err(chip->dev, "%s init failed\n",
__func__);
return -EIO;
}
ret = max17042_verify_model_lock(chip);
if (ret) {
- dev_err(&chip->client->dev, "%s lock verify failed\n",
+ dev_err(chip->dev, "%s lock verify failed\n",
__func__);
return -EIO;
}
@@ -875,7 +877,7 @@ static irqreturn_t max17042_thread_handler(int id, void *dev)
return IRQ_HANDLED;
if ((val & STATUS_SMN_BIT) || (val & STATUS_SMX_BIT)) {
- dev_dbg(&chip->client->dev, "SOC threshold INTR\n");
+ dev_dbg(chip->dev, "SOC threshold INTR\n");
max17042_set_soc_threshold(chip, 1);
}
@@ -907,7 +909,7 @@ static void max17042_init_worker(struct work_struct *work)
static struct max17042_platform_data *
max17042_get_of_pdata(struct max17042_chip *chip)
{
- struct device *dev = &chip->client->dev;
+ struct device *dev = chip->dev;
struct device_node *np = dev->of_node;
u32 prop;
struct max17042_platform_data *pdata;
@@ -949,7 +951,7 @@ static struct max17042_reg_data max17047_default_pdata_init_regs[] = {
static struct max17042_platform_data *
max17042_get_default_pdata(struct max17042_chip *chip)
{
- struct device *dev = &chip->client->dev;
+ struct device *dev = chip->dev;
struct max17042_platform_data *pdata;
int ret, misc_cfg;
@@ -990,7 +992,7 @@ max17042_get_default_pdata(struct max17042_chip *chip)
static struct max17042_platform_data *
max17042_get_pdata(struct max17042_chip *chip)
{
- struct device *dev = &chip->client->dev;
+ struct device *dev = chip->dev;
#ifdef CONFIG_OF
if (dev->of_node)
@@ -1003,6 +1005,7 @@ max17042_get_pdata(struct max17042_chip *chip)
}
static const struct regmap_config max17042_regmap_config = {
+ .name = "max17042",
.reg_bits = 8,
.val_bits = 16,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
@@ -1029,14 +1032,12 @@ static const struct power_supply_desc max17042_no_current_sense_psy_desc = {
.num_properties = ARRAY_SIZE(max17042_battery_props) - 2,
};
-static int max17042_probe(struct i2c_client *client)
+static int max17042_probe(struct i2c_client *client, struct device *dev, int irq,
+ enum max170xx_chip_type chip_type)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct i2c_adapter *adapter = client->adapter;
const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
struct power_supply_config psy_cfg = {};
- const struct acpi_device_id *acpi_id = NULL;
- struct device *dev = &client->dev;
struct max17042_chip *chip;
int ret;
int i;
@@ -1045,35 +1046,27 @@ static int max17042_probe(struct i2c_client *client)
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EIO;
- chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
- chip->client = client;
- 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->dev = dev;
+ chip->chip_type = chip_type;
chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config);
if (IS_ERR(chip->regmap)) {
- dev_err(&client->dev, "Failed to initialize regmap\n");
+ dev_err(dev, "Failed to initialize regmap\n");
return -EINVAL;
}
chip->pdata = max17042_get_pdata(chip);
if (!chip->pdata) {
- dev_err(&client->dev, "no platform data provided\n");
+ dev_err(dev, "no platform data provided\n");
return -EINVAL;
}
- i2c_set_clientdata(client, chip);
+ dev_set_drvdata(dev, chip);
psy_cfg.drv_data = chip;
- psy_cfg.of_node = dev->of_node;
+ psy_cfg.fwnode = dev_fwnode(dev);
/* When current is not measured,
* CURRENT_NOW and CURRENT_AVG properties should be invisible. */
@@ -1095,24 +1088,17 @@ static int max17042_probe(struct i2c_client *client)
regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007);
}
- chip->battery = devm_power_supply_register(&client->dev, max17042_desc,
+ chip->battery = devm_power_supply_register(dev, max17042_desc,
&psy_cfg);
if (IS_ERR(chip->battery)) {
- dev_err(&client->dev, "failed: power supply register\n");
+ dev_err(dev, "failed: power supply register\n");
return PTR_ERR(chip->battery);
}
- if (client->irq) {
- unsigned int flags = 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;
+ if (irq) {
+ unsigned int flags = IRQF_ONESHOT | IRQF_SHARED | IRQF_PROBE_SHARED;
- ret = devm_request_threaded_irq(&client->dev, client->irq,
+ ret = devm_request_threaded_irq(dev, irq,
NULL,
max17042_thread_handler, flags,
chip->battery->desc->name,
@@ -1123,18 +1109,20 @@ static int max17042_probe(struct i2c_client *client)
CFG_ALRT_BIT_ENBL);
max17042_set_soc_threshold(chip, 1);
} else {
- client->irq = 0;
+ irq = 0;
if (ret != -EBUSY)
- dev_err(&client->dev, "Failed to get IRQ\n");
+ dev_err(dev, "Failed to get IRQ\n");
}
}
/* Not able to update the charge threshold when exceeded? -> disable */
- if (!client->irq)
+ if (!irq)
regmap_write(chip->regmap, MAX17042_SALRT_Th, 0xff00);
+ chip->irq = irq;
+
regmap_read(chip->regmap, MAX17042_STATUS, &val);
if (val & STATUS_POR_BIT) {
- ret = devm_work_autocancel(&client->dev, &chip->work,
+ ret = devm_work_autocancel(dev, &chip->work,
max17042_init_worker);
if (ret)
return ret;
@@ -1146,6 +1134,44 @@ static int max17042_probe(struct i2c_client *client)
return 0;
}
+static int max17042_i2c_probe(struct i2c_client *client)
+{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ const struct acpi_device_id *acpi_id = NULL;
+ struct device *dev = &client->dev;
+ enum max170xx_chip_type chip_type;
+
+ if (id) {
+ chip_type = id->driver_data;
+ } else {
+ acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!acpi_id)
+ return -ENODEV;
+
+ chip_type = acpi_id->driver_data;
+ }
+
+ return max17042_probe(client, dev, client->irq, chip_type);
+}
+
+static int max17042_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct i2c_client *i2c;
+ const struct platform_device_id *id;
+ int irq;
+
+ i2c = to_i2c_client(pdev->dev.parent);
+ if (!i2c)
+ return -EINVAL;
+
+ dev->of_node = dev->parent->of_node;
+ id = platform_get_device_id(pdev);
+ irq = platform_get_irq(pdev, 0);
+
+ return max17042_probe(i2c, dev, irq, id->driver_data);
+}
+
#ifdef CONFIG_PM_SLEEP
static int max17042_suspend(struct device *dev)
{
@@ -1155,9 +1181,9 @@ static int max17042_suspend(struct device *dev)
* disable the irq and enable irq_wake
* capability to the interrupt line.
*/
- if (chip->client->irq) {
- disable_irq(chip->client->irq);
- enable_irq_wake(chip->client->irq);
+ if (chip->irq) {
+ disable_irq(chip->irq);
+ enable_irq_wake(chip->irq);
}
return 0;
@@ -1167,9 +1193,9 @@ static int max17042_resume(struct device *dev)
{
struct max17042_chip *chip = dev_get_drvdata(dev);
- if (chip->client->irq) {
- disable_irq_wake(chip->client->irq);
- enable_irq(chip->client->irq);
+ if (chip->irq) {
+ disable_irq_wake(chip->irq);
+ enable_irq(chip->irq);
/* re-program the SOC thresholds to 1% change */
max17042_set_soc_threshold(chip, 1);
}
@@ -1190,12 +1216,28 @@ MODULE_DEVICE_TABLE(acpi, max17042_acpi_match);
#endif
#ifdef CONFIG_OF
-static const struct of_device_id max17042_dt_match[] = {
- { .compatible = "maxim,max17042" },
- { .compatible = "maxim,max17047" },
- { .compatible = "maxim,max17050" },
- { .compatible = "maxim,max17055" },
- { .compatible = "maxim,max77849-battery" },
+/*
+ * Device may be instantiated through parent MFD device and device matching is done
+ * through platform_device_id.
+ *
+ * However if device's DT node contains proper clock compatible and driver is
+ * built as a module, then the *module* matching will be done trough DT aliases.
+ * This requires of_device_id table. In the same time this will not change the
+ * actual *device* matching so do not add .of_match_table.
+ */
+static const struct of_device_id max17042_dt_match[] __used = {
+ { .compatible = "maxim,max17042",
+ .data = (void *) MAXIM_DEVICE_TYPE_MAX17042 },
+ { .compatible = "maxim,max17047",
+ .data = (void *) MAXIM_DEVICE_TYPE_MAX17047 },
+ { .compatible = "maxim,max17050",
+ .data = (void *) MAXIM_DEVICE_TYPE_MAX17050 },
+ { .compatible = "maxim,max17055",
+ .data = (void *) MAXIM_DEVICE_TYPE_MAX17055 },
+ { .compatible = "maxim,max77705-battery",
+ .data = (void *) MAXIM_DEVICE_TYPE_MAX17047 },
+ { .compatible = "maxim,max77849-battery",
+ .data = (void *) MAXIM_DEVICE_TYPE_MAX17047 },
{ },
};
MODULE_DEVICE_TABLE(of, max17042_dt_match);
@@ -1211,6 +1253,17 @@ static const struct i2c_device_id max17042_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max17042_id);
+static const struct platform_device_id max17042_platform_id[] = {
+ { "max17042", MAXIM_DEVICE_TYPE_MAX17042 },
+ { "max17047", MAXIM_DEVICE_TYPE_MAX17047 },
+ { "max17050", MAXIM_DEVICE_TYPE_MAX17050 },
+ { "max17055", MAXIM_DEVICE_TYPE_MAX17055 },
+ { "max77705-battery", MAXIM_DEVICE_TYPE_MAX17047 },
+ { "max77849-battery", MAXIM_DEVICE_TYPE_MAX17047 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, max17042_platform_id);
+
static struct i2c_driver max17042_i2c_driver = {
.driver = {
.name = "max17042",
@@ -1218,10 +1271,44 @@ static struct i2c_driver max17042_i2c_driver = {
.of_match_table = of_match_ptr(max17042_dt_match),
.pm = &max17042_pm_ops,
},
- .probe = max17042_probe,
+ .probe = max17042_i2c_probe,
.id_table = max17042_id,
};
-module_i2c_driver(max17042_i2c_driver);
+
+static struct platform_driver max17042_platform_driver = {
+ .driver = {
+ .name = "max17042",
+ .acpi_match_table = ACPI_PTR(max17042_acpi_match),
+ .pm = &max17042_pm_ops,
+ },
+ .probe = max17042_platform_probe,
+ .id_table = max17042_platform_id,
+};
+
+static int __init max17042_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&max17042_platform_driver);
+ if (ret)
+ return ret;
+
+ ret = i2c_add_driver(&max17042_i2c_driver);
+ if (ret) {
+ platform_driver_unregister(&max17042_platform_driver);
+ return ret;
+ }
+
+ return 0;
+}
+module_init(max17042_init);
+
+static void __exit max17042_exit(void)
+{
+ i2c_del_driver(&max17042_i2c_driver);
+ platform_driver_unregister(&max17042_platform_driver);
+}
+module_exit(max17042_exit);
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
diff --git a/drivers/power/supply/max1720x_battery.c b/drivers/power/supply/max1720x_battery.c
index 33105419e242..ea3912fd1de8 100644
--- a/drivers/power/supply/max1720x_battery.c
+++ b/drivers/power/supply/max1720x_battery.c
@@ -16,6 +16,11 @@
#include <linux/unaligned.h>
+/* SBS compliant registers */
+#define MAX172XX_TEMP1 0x34
+#define MAX172XX_INT_TEMP 0x35
+#define MAX172XX_TEMP2 0x3B
+
/* Nonvolatile registers */
#define MAX1720X_NXTABLE0 0x80
#define MAX1720X_NRSENSE 0xCF /* RSense in 10^-5 Ohm */
@@ -24,11 +29,17 @@
/* ModelGauge m5 */
#define MAX172XX_STATUS 0x00 /* Status */
#define MAX172XX_STATUS_BAT_ABSENT BIT(3) /* Battery absent */
+#define MAX172XX_STATUS_IMX BIT(6) /* Maximum Current Alert Threshold Exceeded */
+#define MAX172XX_STATUS_VMN BIT(8) /* Minimum Voltage Alert Threshold Exceeded */
+#define MAX172XX_STATUS_TMN BIT(9) /* Minimum Temperature Alert Threshold Exceeded */
+#define MAX172XX_STATUS_VMX BIT(12) /* Maximum Voltage Alert Threshold Exceeded */
+#define MAX172XX_STATUS_TMX BIT(13) /* Maximum Temperature Alert Threshold Exceeded */
#define MAX172XX_REPCAP 0x05 /* Average capacity */
#define MAX172XX_REPSOC 0x06 /* Percentage of charge */
#define MAX172XX_TEMP 0x08 /* Temperature */
#define MAX172XX_CURRENT 0x0A /* Actual current */
#define MAX172XX_AVG_CURRENT 0x0B /* Average current */
+#define MAX172XX_FULL_CAP 0x10 /* Calculated full capacity */
#define MAX172XX_TTE 0x11 /* Time to empty */
#define MAX172XX_AVG_TA 0x16 /* Average temperature */
#define MAX172XX_CYCLES 0x17
@@ -108,15 +119,19 @@ static const struct regmap_config max1720x_regmap_cfg = {
.val_format_endian = REGMAP_ENDIAN_LITTLE,
.rd_table = &max1720x_readable_regs,
.volatile_table = &max1720x_volatile_regs,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static const struct regmap_range max1720x_nvmem_allow[] = {
+ regmap_reg_range(MAX172XX_TEMP1, MAX172XX_INT_TEMP),
+ regmap_reg_range(MAX172XX_TEMP2, MAX172XX_TEMP2),
regmap_reg_range(MAX1720X_NXTABLE0, MAX1720X_NDEVICE_NAME4),
};
static const struct regmap_range max1720x_nvmem_deny[] = {
- regmap_reg_range(0x00, 0x7F),
+ regmap_reg_range(0x00, 0x33),
+ regmap_reg_range(0x36, 0x3A),
+ regmap_reg_range(0x3C, 0x7F),
regmap_reg_range(0xE0, 0xFF),
};
@@ -240,6 +255,7 @@ static const struct nvmem_cell_info max1720x_nvmem_cells[] = {
};
static const enum power_supply_property max1720x_battery_props[] = {
+ POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
@@ -250,6 +266,7 @@ static const enum power_supply_property max1720x_battery_props[] = {
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
};
@@ -291,7 +308,7 @@ static int max172xx_temperature_to_ps(unsigned int reg)
/*
* Calculating current registers resolution:
*
- * RSense stored in 10^-5 Ohm, so mesaurment voltage must be
+ * RSense stored in 10^-5 Ohm, so measurement 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
@@ -303,6 +320,43 @@ static int max172xx_current_to_voltage(unsigned int reg)
return val * 156252;
}
+static int max172xx_battery_health(struct max1720x_device_info *info,
+ unsigned int *health)
+{
+ unsigned int status;
+ int ret;
+
+ ret = regmap_read(info->regmap, MAX172XX_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ if (status & MAX172XX_STATUS_VMN)
+ *health = POWER_SUPPLY_HEALTH_DEAD;
+ else if (status & MAX172XX_STATUS_VMX)
+ *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ else if (status & MAX172XX_STATUS_TMN)
+ *health = POWER_SUPPLY_HEALTH_COLD;
+ else if (status & MAX172XX_STATUS_TMX)
+ *health = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else if (status & MAX172XX_STATUS_IMX)
+ *health = POWER_SUPPLY_HEALTH_OVERCURRENT;
+ else
+ *health = POWER_SUPPLY_HEALTH_GOOD;
+
+ /* Clear events which are not self-clearing to detect next events */
+ if (status > 0 && status != MAX172XX_STATUS_IMX) {
+ ret = regmap_set_bits(info->regmap, MAX172XX_STATUS,
+ MAX172XX_STATUS_VMN |
+ MAX172XX_STATUS_VMX |
+ MAX172XX_STATUS_TMN |
+ MAX172XX_STATUS_TMX);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int max1720x_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -312,6 +366,10 @@ static int max1720x_battery_get_property(struct power_supply *psy,
int ret = 0;
switch (psp) {
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = max172xx_battery_health(info, &reg_val);
+ val->intval = reg_val;
+ break;
case POWER_SUPPLY_PROP_PRESENT:
/*
* POWER_SUPPLY_PROP_PRESENT will always readable via
@@ -362,6 +420,10 @@ static int max1720x_battery_get_property(struct power_supply *psy,
ret = regmap_read(info->regmap, MAX172XX_AVG_CURRENT, &reg_val);
val->intval = max172xx_current_to_voltage(reg_val) / info->rsense;
break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ ret = regmap_read(info->regmap, MAX172XX_FULL_CAP, &reg_val);
+ val->intval = max172xx_capacity_to_ps(reg_val);
+ break;
case POWER_SUPPLY_PROP_MODEL_NAME:
ret = regmap_read(info->regmap, MAX172XX_DEV_NAME, &reg_val);
reg_val = FIELD_GET(MAX172XX_DEV_NAME_TYPE_MASK, reg_val);
@@ -382,6 +444,54 @@ static int max1720x_battery_get_property(struct power_supply *psy,
return ret;
}
+static int max1720x_read_temp(struct device *dev, u8 reg, char *buf)
+{
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct max1720x_device_info *info = power_supply_get_drvdata(psy);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(info->regmap_nv, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Temperature in degrees Celsius starting at absolute zero, -273C or
+ * 0K with an LSb of 0.1C
+ */
+ return sysfs_emit(buf, "%d\n", val - 2730);
+}
+
+static ssize_t temp_ain1_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return max1720x_read_temp(dev, MAX172XX_TEMP1, buf);
+}
+
+static ssize_t temp_ain2_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return max1720x_read_temp(dev, MAX172XX_TEMP2, buf);
+}
+
+static ssize_t temp_int_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return max1720x_read_temp(dev, MAX172XX_INT_TEMP, buf);
+}
+
+static DEVICE_ATTR_RO(temp_ain1);
+static DEVICE_ATTR_RO(temp_ain2);
+static DEVICE_ATTR_RO(temp_int);
+
+static struct attribute *max1720x_attrs[] = {
+ &dev_attr_temp_ain1.attr,
+ &dev_attr_temp_ain2.attr,
+ &dev_attr_temp_int.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(max1720x);
+
static
int max1720x_nvmem_reg_read(void *priv, unsigned int off, void *val, size_t len)
{
@@ -482,6 +592,7 @@ static int max1720x_probe(struct i2c_client *client)
psy_cfg.drv_data = info;
psy_cfg.fwnode = dev_fwnode(dev);
+ psy_cfg.attr_grp = max1720x_groups;
i2c_set_clientdata(client, info);
info->regmap = devm_regmap_init_i2c(client, &max1720x_regmap_cfg);
if (IS_ERR(info->regmap))
diff --git a/drivers/power/supply/max77650-charger.c b/drivers/power/supply/max77650-charger.c
index 5f58c0c24b4d..4ae43668992e 100644
--- a/drivers/power/supply/max77650-charger.c
+++ b/drivers/power/supply/max77650-charger.c
@@ -298,7 +298,7 @@ static int max77650_charger_probe(struct platform_device *pdev)
chg->dev = dev;
- pscfg.of_node = dev->of_node;
+ pscfg.fwnode = dev_fwnode(dev);
pscfg.drv_data = chg;
chg_irq = platform_get_irq_byname(pdev, "CHG");
diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c
index cdea35c0d1de..027d6a539b65 100644
--- a/drivers/power/supply/max77693_charger.c
+++ b/drivers/power/supply/max77693_charger.c
@@ -608,7 +608,7 @@ static int max77693_set_charge_input_threshold_volt(struct max77693_charger *chg
case 4700000:
case 4800000:
case 4900000:
- data = (uvolt - 4700000) / 100000;
+ data = ((uvolt - 4700000) / 100000) + 1;
break;
default:
dev_err(chg->dev, "Wrong value for charge input voltage regulation threshold\n");
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
new file mode 100644
index 000000000000..329b430d0e50
--- /dev/null
+++ b/drivers/power/supply/max77705_charger.c
@@ -0,0 +1,589 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Based on max77650-charger.c
+ *
+ * Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.org>
+ *
+ * Battery charger driver for MAXIM 77705 charger/power-supply.
+ */
+
+#include <linux/devm-helpers.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max77693-common.h>
+#include <linux/mfd/max77705-private.h>
+#include <linux/power/max77705_charger.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+
+static const char *max77705_charger_model = "max77705";
+static const char *max77705_charger_manufacturer = "Maxim Integrated";
+
+static const struct regmap_config max77705_chg_regmap_config = {
+ .reg_base = MAX77705_CHG_REG_BASE,
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX77705_CHG_REG_SAFEOUT_CTRL,
+};
+
+static enum power_supply_property max77705_charger_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+};
+
+static int max77705_chgin_irq(void *irq_drv_data)
+{
+ struct max77705_charger_data *charger = irq_drv_data;
+
+ queue_work(charger->wqueue, &charger->chgin_work);
+
+ return 0;
+}
+
+static const struct regmap_irq max77705_charger_irqs[] = {
+ { .mask = MAX77705_BYP_IM, },
+ { .mask = MAX77705_INP_LIMIT_IM, },
+ { .mask = MAX77705_BATP_IM, },
+ { .mask = MAX77705_BAT_IM, },
+ { .mask = MAX77705_CHG_IM, },
+ { .mask = MAX77705_WCIN_IM, },
+ { .mask = MAX77705_CHGIN_IM, },
+ { .mask = MAX77705_AICL_IM, },
+};
+
+static struct regmap_irq_chip max77705_charger_irq_chip = {
+ .name = "max77705-charger",
+ .status_base = MAX77705_CHG_REG_INT,
+ .mask_base = MAX77705_CHG_REG_INT_MASK,
+ .handle_post_irq = max77705_chgin_irq,
+ .num_regs = 1,
+ .irqs = max77705_charger_irqs,
+ .num_irqs = ARRAY_SIZE(max77705_charger_irqs),
+};
+
+static int max77705_charger_enable(struct max77705_charger_data *chg)
+{
+ int rv;
+
+ rv = regmap_update_bits(chg->regmap, MAX77705_CHG_REG_CNFG_09,
+ MAX77705_CHG_EN_MASK, MAX77705_CHG_EN_MASK);
+ if (rv)
+ dev_err(chg->dev, "unable to enable the charger: %d\n", rv);
+
+ return rv;
+}
+
+static void max77705_charger_disable(void *data)
+{
+ struct max77705_charger_data *chg = data;
+ int rv;
+
+ rv = regmap_update_bits(chg->regmap,
+ MAX77705_CHG_REG_CNFG_09,
+ MAX77705_CHG_EN_MASK,
+ MAX77705_CHG_DISABLE);
+ if (rv)
+ dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
+}
+
+static int max77705_get_online(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, MAX77705_CHG_REG_INT_OK, &data);
+ if (ret < 0)
+ return ret;
+
+ *val = !!(data & MAX77705_CHGIN_OK);
+
+ return 0;
+}
+
+static int max77705_check_battery(struct max77705_charger_data *charger, int *val)
+{
+ unsigned int reg_data;
+ unsigned int reg_data2;
+ struct regmap *regmap = charger->regmap;
+
+ regmap_read(regmap, MAX77705_CHG_REG_INT_OK, &reg_data);
+
+ dev_dbg(charger->dev, "CHG_INT_OK(0x%x)\n", reg_data);
+
+ regmap_read(regmap, MAX77705_CHG_REG_DETAILS_00, &reg_data2);
+
+ dev_dbg(charger->dev, "CHG_DETAILS00(0x%x)\n", reg_data2);
+
+ if ((reg_data & MAX77705_BATP_OK) || !(reg_data2 & MAX77705_BATP_DTLS))
+ *val = true;
+ else
+ *val = false;
+
+ return 0;
+}
+
+static int max77705_get_charge_type(struct max77705_charger_data *charger, int *val)
+{
+ struct regmap *regmap = charger->regmap;
+ unsigned int reg_data;
+
+ regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, &reg_data);
+ if (!MAX77705_CHARGER_CHG_CHARGING(reg_data)) {
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ return 0;
+ }
+
+ regmap_read(regmap, MAX77705_CHG_REG_DETAILS_01, &reg_data);
+ reg_data &= MAX77705_CHG_DTLS;
+
+ switch (reg_data) {
+ case 0x0:
+ case MAX77705_CHARGER_CONSTANT_CURRENT:
+ case MAX77705_CHARGER_CONSTANT_VOLTAGE:
+ *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ return 0;
+ default:
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ return 0;
+ }
+
+ return 0;
+}
+
+static int max77705_get_status(struct max77705_charger_data *charger, int *val)
+{
+ struct regmap *regmap = charger->regmap;
+ unsigned int reg_data;
+
+ regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, &reg_data);
+ if (!MAX77705_CHARGER_CHG_CHARGING(reg_data)) {
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ return 0;
+ }
+
+ regmap_read(regmap, MAX77705_CHG_REG_DETAILS_01, &reg_data);
+ reg_data &= MAX77705_CHG_DTLS;
+
+ switch (reg_data) {
+ case 0x0:
+ case MAX77705_CHARGER_CONSTANT_CURRENT:
+ case MAX77705_CHARGER_CONSTANT_VOLTAGE:
+ *val = POWER_SUPPLY_STATUS_CHARGING;
+ return 0;
+ case MAX77705_CHARGER_END_OF_CHARGE:
+ case MAX77705_CHARGER_DONE:
+ *val = POWER_SUPPLY_STATUS_FULL;
+ return 0;
+ /* those values hard coded as in vendor kernel, because of */
+ /* failure to determine it's actual meaning. */
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ return 0;
+ case 0x08:
+ case 0xA:
+ case 0xB:
+ *val = POWER_SUPPLY_STATUS_DISCHARGING;
+ return 0;
+ default:
+ *val = POWER_SUPPLY_STATUS_UNKNOWN;
+ return 0;
+ }
+
+ return 0;
+}
+
+static int max77705_get_vbus_state(struct regmap *regmap, int *value)
+{
+ int ret;
+ unsigned int charge_dtls;
+
+ ret = regmap_read(regmap, MAX77705_CHG_REG_DETAILS_00, &charge_dtls);
+ if (ret)
+ return ret;
+
+ charge_dtls = ((charge_dtls & MAX77705_CHGIN_DTLS) >>
+ MAX77705_CHGIN_DTLS_SHIFT);
+
+ switch (charge_dtls) {
+ case 0x00:
+ *value = POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
+ break;
+ case 0x01:
+ *value = POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
+ break;
+ case 0x02:
+ *value = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ break;
+ case 0x03:
+ *value = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static int max77705_get_battery_health(struct max77705_charger_data *charger,
+ int *value)
+{
+ struct regmap *regmap = charger->regmap;
+ unsigned int bat_dtls;
+
+ regmap_read(regmap, MAX77705_CHG_REG_DETAILS_01, &bat_dtls);
+ bat_dtls = ((bat_dtls & MAX77705_BAT_DTLS) >> MAX77705_BAT_DTLS_SHIFT);
+
+ switch (bat_dtls) {
+ case MAX77705_BATTERY_NOBAT:
+ dev_dbg(charger->dev, "%s: No battery and the charger is suspended\n",
+ __func__);
+ *value = POWER_SUPPLY_HEALTH_NO_BATTERY;
+ break;
+ case MAX77705_BATTERY_PREQUALIFICATION:
+ dev_dbg(charger->dev, "%s: battery is okay but its voltage is low(~VPQLB)\n",
+ __func__);
+ break;
+ case MAX77705_BATTERY_DEAD:
+ dev_dbg(charger->dev, "%s: battery dead\n", __func__);
+ *value = POWER_SUPPLY_HEALTH_DEAD;
+ break;
+ case MAX77705_BATTERY_GOOD:
+ case MAX77705_BATTERY_LOWVOLTAGE:
+ *value = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case MAX77705_BATTERY_OVERVOLTAGE:
+ dev_dbg(charger->dev, "%s: battery ovp\n", __func__);
+ *value = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ break;
+ default:
+ dev_dbg(charger->dev, "%s: battery unknown\n", __func__);
+ *value = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ break;
+ }
+
+ return 0;
+}
+
+static int max77705_get_health(struct max77705_charger_data *charger, int *val)
+{
+ struct regmap *regmap = charger->regmap;
+ int ret, is_online = 0;
+
+ ret = max77705_get_online(regmap, &is_online);
+ if (ret)
+ return ret;
+ if (is_online) {
+ ret = max77705_get_vbus_state(regmap, val);
+ if (ret || (*val != POWER_SUPPLY_HEALTH_GOOD))
+ return ret;
+ }
+ return max77705_get_battery_health(charger, val);
+}
+
+static int max77705_get_input_current(struct max77705_charger_data *charger,
+ int *val)
+{
+ unsigned int reg_data;
+ int get_current = 0;
+ struct regmap *regmap = charger->regmap;
+
+ regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, &reg_data);
+
+ reg_data &= MAX77705_CHG_CHGIN_LIM_MASK;
+
+ if (reg_data <= 3)
+ get_current = MAX77705_CURRENT_CHGIN_MIN;
+ else if (reg_data >= MAX77705_CHG_CHGIN_LIM_MASK)
+ get_current = MAX77705_CURRENT_CHGIN_MAX;
+ else
+ get_current = (reg_data + 1) * MAX77705_CURRENT_CHGIN_STEP;
+
+ *val = get_current;
+
+ return 0;
+}
+
+static int max77705_get_charge_current(struct max77705_charger_data *charger,
+ int *val)
+{
+ unsigned int reg_data;
+ struct regmap *regmap = charger->regmap;
+
+ regmap_read(regmap, MAX77705_CHG_REG_CNFG_02, &reg_data);
+ reg_data &= MAX77705_CHG_CC;
+
+ *val = reg_data <= 0x2 ? MAX77705_CURRENT_CHGIN_MIN : reg_data * MAX77705_CURRENT_CHG_STEP;
+
+ return 0;
+}
+
+static int max77705_set_float_voltage(struct max77705_charger_data *charger,
+ int float_voltage)
+{
+ int float_voltage_mv;
+ unsigned int reg_data = 0;
+ struct regmap *regmap = charger->regmap;
+
+ float_voltage_mv = float_voltage / 1000;
+ reg_data = float_voltage_mv <= 4000 ? 0x0 :
+ float_voltage_mv >= 4500 ? 0x23 :
+ (float_voltage_mv <= 4200) ? (float_voltage_mv - 4000) / 50 :
+ (((float_voltage_mv - 4200) / 10) + 0x04);
+
+ return regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_04,
+ MAX77705_CHG_CV_PRM_MASK,
+ (reg_data << MAX77705_CHG_CV_PRM_SHIFT));
+}
+
+static int max77705_get_float_voltage(struct max77705_charger_data *charger,
+ int *val)
+{
+ unsigned int reg_data = 0;
+ int voltage_mv;
+ struct regmap *regmap = charger->regmap;
+
+ regmap_read(regmap, MAX77705_CHG_REG_CNFG_04, &reg_data);
+ reg_data &= MAX77705_CHG_PRM_MASK;
+ voltage_mv = reg_data <= 0x04 ? reg_data * 50 + 4000 :
+ (reg_data - 4) * 10 + 4200;
+ *val = voltage_mv * 1000;
+
+ return 0;
+}
+
+static int max77705_chg_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max77705_charger_data *charger = power_supply_get_drvdata(psy);
+ struct regmap *regmap = charger->regmap;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ return max77705_get_online(regmap, &val->intval);
+ case POWER_SUPPLY_PROP_PRESENT:
+ return max77705_check_battery(charger, &val->intval);
+ case POWER_SUPPLY_PROP_STATUS:
+ return max77705_get_status(charger, &val->intval);
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ return max77705_get_charge_type(charger, &val->intval);
+ case POWER_SUPPLY_PROP_HEALTH:
+ return max77705_get_health(charger, &val->intval);
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return max77705_get_input_current(charger, &val->intval);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return max77705_get_charge_current(charger, &val->intval);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ return max77705_get_float_voltage(charger, &val->intval);
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = charger->bat_info->voltage_max_design_uv;
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = max77705_charger_model;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = max77705_charger_manufacturer;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct power_supply_desc max77705_charger_psy_desc = {
+ .name = "max77705-charger",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = max77705_charger_props,
+ .num_properties = ARRAY_SIZE(max77705_charger_props),
+ .get_property = max77705_chg_get_property,
+};
+
+static void max77705_chgin_isr_work(struct work_struct *work)
+{
+ struct max77705_charger_data *charger =
+ container_of(work, struct max77705_charger_data, chgin_work);
+
+ power_supply_changed(charger->psy_chg);
+}
+
+static void max77705_charger_initialize(struct max77705_charger_data *chg)
+{
+ u8 reg_data;
+ struct power_supply_battery_info *info;
+ struct regmap *regmap = chg->regmap;
+
+ if (power_supply_get_battery_info(chg->psy_chg, &info) < 0)
+ return;
+
+ chg->bat_info = info;
+
+ /* unlock charger setting protect */
+ /* slowest LX slope */
+ reg_data = MAX77705_CHGPROT_MASK | MAX77705_SLOWEST_LX_SLOPE;
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_06, reg_data,
+ reg_data);
+
+ /* fast charge timer disable */
+ /* restart threshold disable */
+ /* pre-qual charge disable */
+ reg_data = (MAX77705_FCHGTIME_DISABLE << MAX77705_FCHGTIME_SHIFT) |
+ (MAX77705_CHG_RSTRT_DISABLE << MAX77705_CHG_RSTRT_SHIFT) |
+ (MAX77705_CHG_PQEN_DISABLE << MAX77705_PQEN_SHIFT);
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_01,
+ (MAX77705_FCHGTIME_MASK |
+ MAX77705_CHG_RSTRT_MASK |
+ MAX77705_PQEN_MASK),
+ reg_data);
+
+ /* OTG off(UNO on), boost off */
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_00,
+ MAX77705_OTG_CTRL, 0);
+
+ /* charge current 450mA(default) */
+ /* otg current limit 900mA */
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_02,
+ MAX77705_OTG_ILIM_MASK,
+ MAX77705_OTG_ILIM_900 << MAX77705_OTG_ILIM_SHIFT);
+
+ /* BAT to SYS OCP 4.80A */
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_05,
+ MAX77705_REG_B2SOVRC_MASK,
+ MAX77705_B2SOVRC_4_8A << MAX77705_REG_B2SOVRC_SHIFT);
+ /* top off current 150mA */
+ /* top off timer 30min */
+ reg_data = (MAX77705_TO_ITH_150MA << MAX77705_TO_ITH_SHIFT) |
+ (MAX77705_TO_TIME_30M << MAX77705_TO_TIME_SHIFT) |
+ (MAX77705_SYS_TRACK_DISABLE << MAX77705_SYS_TRACK_DIS_SHIFT);
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_03,
+ (MAX77705_TO_ITH_MASK |
+ MAX77705_TO_TIME_MASK |
+ MAX77705_SYS_TRACK_DIS_MASK), reg_data);
+
+ /* cv voltage 4.2V or 4.35V */
+ /* MINVSYS 3.6V(default) */
+ if (info->voltage_max_design_uv < 0) {
+ dev_warn(chg->dev, "missing battery:voltage-max-design-microvolt\n");
+ max77705_set_float_voltage(chg, 4200000);
+ } else {
+ max77705_set_float_voltage(chg, info->voltage_max_design_uv);
+ }
+
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_12,
+ MAX77705_VCHGIN_REG_MASK, MAX77705_VCHGIN_4_5);
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_12,
+ MAX77705_WCIN_REG_MASK, MAX77705_WCIN_4_5);
+
+ /* Watchdog timer */
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_00,
+ MAX77705_WDTEN_MASK, 0);
+
+ /* Active Discharge Enable */
+ regmap_update_bits(regmap, MAX77705_PMIC_REG_MAINCTRL1, 1, 1);
+
+ /* VBYPSET=5.0V */
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_11, MAX77705_VBYPSET_MASK, 0);
+
+ /* Switching Frequency : 1.5MHz */
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_08, MAX77705_REG_FSW_MASK,
+ (MAX77705_CHG_FSW_1_5MHz << MAX77705_REG_FSW_SHIFT));
+
+ /* Auto skip mode */
+ regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_12, MAX77705_REG_DISKIP_MASK,
+ (MAX77705_AUTO_SKIP << MAX77705_REG_DISKIP_SHIFT));
+}
+
+static int max77705_charger_probe(struct i2c_client *i2c)
+{
+ struct power_supply_config pscfg = {};
+ struct max77705_charger_data *chg;
+ struct device *dev;
+ struct regmap_irq_chip_data *irq_data;
+ int ret;
+
+ dev = &i2c->dev;
+
+ chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
+ if (!chg)
+ return -ENOMEM;
+
+ chg->dev = dev;
+ i2c_set_clientdata(i2c, chg);
+
+ chg->regmap = devm_regmap_init_i2c(i2c, &max77705_chg_regmap_config);
+ if (IS_ERR(chg->regmap))
+ return PTR_ERR(chg->regmap);
+
+ ret = regmap_update_bits(chg->regmap,
+ MAX77705_CHG_REG_INT_MASK,
+ MAX77705_CHGIN_IM, 0);
+ if (ret)
+ return ret;
+
+ pscfg.fwnode = dev_fwnode(dev);
+ pscfg.drv_data = chg;
+
+ chg->psy_chg = devm_power_supply_register(dev, &max77705_charger_psy_desc, &pscfg);
+ if (IS_ERR(chg->psy_chg))
+ return PTR_ERR(chg->psy_chg);
+
+ max77705_charger_irq_chip.irq_drv_data = chg;
+ ret = devm_regmap_add_irq_chip(chg->dev, chg->regmap, i2c->irq,
+ IRQF_ONESHOT | IRQF_SHARED, 0,
+ &max77705_charger_irq_chip,
+ &irq_data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add irq chip\n");
+
+ chg->wqueue = create_singlethread_workqueue(dev_name(dev));
+ if (!chg->wqueue)
+ return dev_err_probe(dev, -ENOMEM, "failed to create workqueue\n");
+
+ ret = devm_work_autocancel(dev, &chg->chgin_work, max77705_chgin_isr_work);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to initialize interrupt work\n");
+ goto destroy_wq;
+ }
+
+ max77705_charger_initialize(chg);
+
+ ret = max77705_charger_enable(chg);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to enable charge\n");
+ goto destroy_wq;
+ }
+
+ return devm_add_action_or_reset(dev, max77705_charger_disable, chg);
+
+destroy_wq:
+ destroy_workqueue(chg->wqueue);
+ return ret;
+}
+
+static const struct of_device_id max77705_charger_of_match[] = {
+ { .compatible = "maxim,max77705-charger" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max77705_charger_of_match);
+
+static struct i2c_driver max77705_charger_driver = {
+ .driver = {
+ .name = "max77705-charger",
+ .of_match_table = max77705_charger_of_match,
+ },
+ .probe = max77705_charger_probe,
+};
+module_i2c_driver(max77705_charger_driver);
+
+MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>");
+MODULE_DESCRIPTION("Maxim MAX77705 charger driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/max8903_charger.c b/drivers/power/supply/max8903_charger.c
index e65d0141f260..45fbaad6c647 100644
--- a/drivers/power/supply/max8903_charger.c
+++ b/drivers/power/supply/max8903_charger.c
@@ -349,7 +349,7 @@ static int max8903_probe(struct platform_device *pdev)
data->psy_desc.properties = max8903_charger_props;
data->psy_desc.num_properties = ARRAY_SIZE(max8903_charger_props);
- psy_cfg.of_node = dev->of_node;
+ psy_cfg.fwnode = dev_fwnode(dev);
psy_cfg.drv_data = data;
data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg);
diff --git a/drivers/power/supply/mm8013.c b/drivers/power/supply/mm8013.c
index 5bcfaeeda3db..93c50cff31bc 100644
--- a/drivers/power/supply/mm8013.c
+++ b/drivers/power/supply/mm8013.c
@@ -90,7 +90,7 @@ static int mm8013_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
- struct mm8013_chip *chip = psy->drv_data;
+ struct mm8013_chip *chip = power_supply_get_drvdata(psy);
int ret = 0;
u32 regval;
@@ -274,7 +274,7 @@ static int mm8013_probe(struct i2c_client *client)
return dev_err_probe(dev, ret, "MM8013 not found\n");
psy_cfg.drv_data = chip;
- psy_cfg.of_node = dev->of_node;
+ psy_cfg.fwnode = dev_fwnode(dev);
psy = devm_power_supply_register(dev, &mm8013_desc, &psy_cfg);
if (IS_ERR(psy))
diff --git a/drivers/power/supply/mt6360_charger.c b/drivers/power/supply/mt6360_charger.c
index e99e55148976..77747eb51667 100644
--- a/drivers/power/supply/mt6360_charger.c
+++ b/drivers/power/supply/mt6360_charger.c
@@ -810,7 +810,7 @@ static int mt6360_charger_probe(struct platform_device *pdev)
memcpy(&mci->psy_desc, &mt6360_charger_desc, sizeof(mci->psy_desc));
mci->psy_desc.name = dev_name(&pdev->dev);
charger_cfg.drv_data = mci;
- charger_cfg.of_node = pdev->dev.of_node;
+ charger_cfg.fwnode = dev_fwnode(&pdev->dev);
mci->psy = devm_power_supply_register(&pdev->dev,
&mci->psy_desc, &charger_cfg);
if (IS_ERR(mci->psy))
diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c
index ad8793bf997e..98579998b300 100644
--- a/drivers/power/supply/mt6370-charger.c
+++ b/drivers/power/supply/mt6370-charger.c
@@ -752,7 +752,7 @@ static int mt6370_chg_init_psy(struct mt6370_priv *priv)
{
struct power_supply_config cfg = {
.drv_data = priv,
- .of_node = dev_of_node(priv->dev),
+ .fwnode = dev_fwnode(priv->dev),
};
priv->psy = devm_power_supply_register(priv->dev, &mt6370_chg_psy_desc,
@@ -772,7 +772,6 @@ static void mt6370_chg_destroy_wq(void *data)
{
struct workqueue_struct *wq = data;
- flush_workqueue(wq);
destroy_workqueue(wq);
}
diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c
index 9f60094a5599..b9b607822676 100644
--- a/drivers/power/supply/olpc_battery.c
+++ b/drivers/power/supply/olpc_battery.c
@@ -527,7 +527,7 @@ static enum power_supply_property olpc_xo15_bat_props[] = {
#define EEPROM_SIZE (EEPROM_END - EEPROM_START)
static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t off, size_t count)
+ const struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{
uint8_t ec_byte;
int ret;
@@ -547,13 +547,13 @@ 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,
},
.size = EEPROM_SIZE,
- .read = olpc_bat_eeprom_read,
+ .read_new = olpc_bat_eeprom_read,
};
/* Allow userspace to see the specific error value pulled from the EC */
@@ -584,15 +584,14 @@ static struct attribute *olpc_bat_sysfs_attrs[] = {
NULL
};
-static struct bin_attribute *olpc_bat_sysfs_bin_attrs[] = {
+static const struct bin_attribute *const olpc_bat_sysfs_bin_attrs[] = {
&olpc_bat_eeprom,
NULL
};
static const struct attribute_group olpc_bat_sysfs_group = {
.attrs = olpc_bat_sysfs_attrs,
- .bin_attrs = olpc_bat_sysfs_bin_attrs,
-
+ .bin_attrs_new = olpc_bat_sysfs_bin_attrs,
};
static const struct attribute_group *olpc_bat_sysfs_groups[] = {
@@ -675,7 +674,7 @@ static int olpc_battery_probe(struct platform_device *pdev)
/* Ignore the status. It doesn't actually matter */
- ac_psy_cfg.of_node = pdev->dev.of_node;
+ ac_psy_cfg.fwnode = dev_fwnode(&pdev->dev);
ac_psy_cfg.drv_data = data;
data->olpc_ac = devm_power_supply_register(&pdev->dev, &olpc_ac_desc,
@@ -693,7 +692,7 @@ static int olpc_battery_probe(struct platform_device *pdev)
olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
}
- bat_psy_cfg.of_node = pdev->dev.of_node;
+ bat_psy_cfg.fwnode = dev_fwnode(&pdev->dev);
bat_psy_cfg.drv_data = data;
bat_psy_cfg.attr_grp = olpc_bat_sysfs_groups;
diff --git a/drivers/power/supply/pcf50633-charger.c b/drivers/power/supply/pcf50633-charger.c
deleted file mode 100644
index 0136bc87b105..000000000000
--- a/drivers/power/supply/pcf50633-charger.c
+++ /dev/null
@@ -1,466 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* NXP PCF50633 Main Battery Charger Driver
- *
- * (C) 2006-2008 by Openmoko, Inc.
- * Author: Balaji Rao <balajirrao@openmoko.org>
- * All rights reserved.
- *
- * Broken down from monstrous PCF50633 driver mainly by
- * Harald Welte, Andy Green and Werner Almesberger
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/sysfs.h>
-#include <linux/platform_device.h>
-#include <linux/power_supply.h>
-
-#include <linux/mfd/pcf50633/core.h>
-#include <linux/mfd/pcf50633/mbc.h>
-
-struct pcf50633_mbc {
- struct pcf50633 *pcf;
-
- int adapter_online;
- int usb_online;
-
- struct power_supply *usb;
- struct power_supply *adapter;
- struct power_supply *ac;
-};
-
-int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
-{
- struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
- int ret = 0;
- u8 bits;
- u8 mbcs2, chgmod;
- unsigned int mbcc5;
-
- if (ma >= 1000) {
- bits = PCF50633_MBCC7_USB_1000mA;
- ma = 1000;
- } else if (ma >= 500) {
- bits = PCF50633_MBCC7_USB_500mA;
- ma = 500;
- } else if (ma >= 100) {
- bits = PCF50633_MBCC7_USB_100mA;
- ma = 100;
- } else {
- bits = PCF50633_MBCC7_USB_SUSPEND;
- ma = 0;
- }
-
- ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
- PCF50633_MBCC7_USB_MASK, bits);
- if (ret)
- dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma);
- else
- dev_info(pcf->dev, "usb curlim to %d mA\n", ma);
-
- /*
- * We limit the charging current to be the USB current limit.
- * The reason is that on pcf50633, when it enters PMU Standby mode,
- * which it does when the device goes "off", the USB current limit
- * reverts to the variant default. In at least one common case, that
- * default is 500mA. By setting the charging current to be the same
- * as the USB limit we set here before PMU standby, we enforce it only
- * using the correct amount of current even when the USB current limit
- * gets reset to the wrong thing
- */
-
- if (mbc->pcf->pdata->charger_reference_current_ma) {
- mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
- if (mbcc5 > 255)
- mbcc5 = 255;
- pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
- }
-
- mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
- chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
-
- /* If chgmod == BATFULL, setting chgena has no effect.
- * Datasheet says we need to set resume instead but when autoresume is
- * used resume doesn't work. Clear and set chgena instead.
- */
- if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
- pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
- PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
- else {
- pcf50633_reg_clear_bits(pcf, PCF50633_REG_MBCC1,
- PCF50633_MBCC1_CHGENA);
- pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
- PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
- }
-
- power_supply_changed(mbc->usb);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(pcf50633_mbc_usb_curlim_set);
-
-int pcf50633_mbc_get_status(struct pcf50633 *pcf)
-{
- struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
- int status = 0;
- u8 chgmod;
-
- if (!mbc)
- return 0;
-
- chgmod = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2)
- & PCF50633_MBCS2_MBC_MASK;
-
- if (mbc->usb_online)
- status |= PCF50633_MBC_USB_ONLINE;
- if (chgmod == PCF50633_MBCS2_MBC_USB_PRE ||
- chgmod == PCF50633_MBCS2_MBC_USB_PRE_WAIT ||
- chgmod == PCF50633_MBCS2_MBC_USB_FAST ||
- chgmod == PCF50633_MBCS2_MBC_USB_FAST_WAIT)
- status |= PCF50633_MBC_USB_ACTIVE;
- if (mbc->adapter_online)
- status |= PCF50633_MBC_ADAPTER_ONLINE;
- if (chgmod == PCF50633_MBCS2_MBC_ADP_PRE ||
- chgmod == PCF50633_MBCS2_MBC_ADP_PRE_WAIT ||
- chgmod == PCF50633_MBCS2_MBC_ADP_FAST ||
- chgmod == PCF50633_MBCS2_MBC_ADP_FAST_WAIT)
- status |= PCF50633_MBC_ADAPTER_ACTIVE;
-
- return status;
-}
-EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status);
-
-int pcf50633_mbc_get_usb_online_status(struct pcf50633 *pcf)
-{
- struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
-
- if (!mbc)
- return 0;
-
- return mbc->usb_online;
-}
-EXPORT_SYMBOL_GPL(pcf50633_mbc_get_usb_online_status);
-
-static ssize_t
-show_chgmode(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
-
- u8 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
- u8 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
-
- return sysfs_emit(buf, "%d\n", chgmod);
-}
-static DEVICE_ATTR(chgmode, S_IRUGO, show_chgmode, NULL);
-
-static ssize_t
-show_usblim(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
- u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
- PCF50633_MBCC7_USB_MASK;
- unsigned int ma;
-
- if (usblim == PCF50633_MBCC7_USB_1000mA)
- ma = 1000;
- else if (usblim == PCF50633_MBCC7_USB_500mA)
- ma = 500;
- else if (usblim == PCF50633_MBCC7_USB_100mA)
- ma = 100;
- else
- ma = 0;
-
- return sysfs_emit(buf, "%u\n", ma);
-}
-
-static ssize_t set_usblim(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
- unsigned long ma;
- int ret;
-
- ret = kstrtoul(buf, 10, &ma);
- if (ret)
- return ret;
-
- pcf50633_mbc_usb_curlim_set(mbc->pcf, ma);
-
- return count;
-}
-
-static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, set_usblim);
-
-static ssize_t
-show_chglim(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
- u8 mbcc5 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC5);
- unsigned int ma;
-
- if (!mbc->pcf->pdata->charger_reference_current_ma)
- return -ENODEV;
-
- ma = (mbc->pcf->pdata->charger_reference_current_ma * mbcc5) >> 8;
-
- return sysfs_emit(buf, "%u\n", ma);
-}
-
-static ssize_t set_chglim(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
- unsigned long ma;
- unsigned int mbcc5;
- int ret;
-
- if (!mbc->pcf->pdata->charger_reference_current_ma)
- return -ENODEV;
-
- ret = kstrtoul(buf, 10, &ma);
- if (ret)
- return ret;
-
- mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
- if (mbcc5 > 255)
- mbcc5 = 255;
- pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
-
- return count;
-}
-
-/*
- * This attribute allows to change MBC charging limit on the fly
- * independently of usb current limit. It also gets set automatically every
- * time usb current limit is changed.
- */
-static DEVICE_ATTR(chg_curlim, S_IRUGO | S_IWUSR, show_chglim, set_chglim);
-
-static struct attribute *pcf50633_mbc_sysfs_attrs[] = {
- &dev_attr_chgmode.attr,
- &dev_attr_usb_curlim.attr,
- &dev_attr_chg_curlim.attr,
- NULL,
-};
-
-ATTRIBUTE_GROUPS(pcf50633_mbc_sysfs);
-
-static void
-pcf50633_mbc_irq_handler(int irq, void *data)
-{
- struct pcf50633_mbc *mbc = data;
-
- /* USB */
- if (irq == PCF50633_IRQ_USBINS) {
- mbc->usb_online = 1;
- } else if (irq == PCF50633_IRQ_USBREM) {
- mbc->usb_online = 0;
- pcf50633_mbc_usb_curlim_set(mbc->pcf, 0);
- }
-
- /* Adapter */
- if (irq == PCF50633_IRQ_ADPINS)
- mbc->adapter_online = 1;
- else if (irq == PCF50633_IRQ_ADPREM)
- mbc->adapter_online = 0;
-
- power_supply_changed(mbc->ac);
- power_supply_changed(mbc->usb);
- power_supply_changed(mbc->adapter);
-
- if (mbc->pcf->pdata->mbc_event_callback)
- mbc->pcf->pdata->mbc_event_callback(mbc->pcf, irq);
-}
-
-static int adapter_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
- int ret = 0;
-
- switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = mbc->adapter_online;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int usb_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
- int ret = 0;
- u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
- PCF50633_MBCC7_USB_MASK;
-
- switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = mbc->usb_online &&
- (usblim <= PCF50633_MBCC7_USB_500mA);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int ac_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
- int ret = 0;
- u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
- PCF50633_MBCC7_USB_MASK;
-
- switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = mbc->usb_online &&
- (usblim == PCF50633_MBCC7_USB_1000mA);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static enum power_supply_property power_props[] = {
- POWER_SUPPLY_PROP_ONLINE,
-};
-
-static const u8 mbc_irq_handlers[] = {
- PCF50633_IRQ_ADPINS,
- PCF50633_IRQ_ADPREM,
- PCF50633_IRQ_USBINS,
- PCF50633_IRQ_USBREM,
- PCF50633_IRQ_BATFULL,
- PCF50633_IRQ_CHGHALT,
- PCF50633_IRQ_THLIMON,
- PCF50633_IRQ_THLIMOFF,
- PCF50633_IRQ_USBLIMON,
- PCF50633_IRQ_USBLIMOFF,
- PCF50633_IRQ_LOWSYS,
- PCF50633_IRQ_LOWBAT,
-};
-
-static const struct power_supply_desc pcf50633_mbc_adapter_desc = {
- .name = "adapter",
- .type = POWER_SUPPLY_TYPE_MAINS,
- .properties = power_props,
- .num_properties = ARRAY_SIZE(power_props),
- .get_property = &adapter_get_property,
-};
-
-static const struct power_supply_desc pcf50633_mbc_usb_desc = {
- .name = "usb",
- .type = POWER_SUPPLY_TYPE_USB,
- .properties = power_props,
- .num_properties = ARRAY_SIZE(power_props),
- .get_property = usb_get_property,
-};
-
-static const struct power_supply_desc pcf50633_mbc_ac_desc = {
- .name = "ac",
- .type = POWER_SUPPLY_TYPE_MAINS,
- .properties = power_props,
- .num_properties = ARRAY_SIZE(power_props),
- .get_property = ac_get_property,
-};
-
-static int pcf50633_mbc_probe(struct platform_device *pdev)
-{
- struct power_supply_config psy_cfg = {};
- struct power_supply_config usb_psy_cfg;
- struct pcf50633_mbc *mbc;
- int i;
- u8 mbcs1;
-
- mbc = devm_kzalloc(&pdev->dev, sizeof(*mbc), GFP_KERNEL);
- if (!mbc)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, mbc);
- mbc->pcf = dev_to_pcf50633(pdev->dev.parent);
-
- /* Set up IRQ handlers */
- for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
- pcf50633_register_irq(mbc->pcf, mbc_irq_handlers[i],
- pcf50633_mbc_irq_handler, mbc);
-
- psy_cfg.supplied_to = mbc->pcf->pdata->batteries;
- psy_cfg.num_supplicants = mbc->pcf->pdata->num_batteries;
- psy_cfg.drv_data = mbc;
-
- /* Create power supplies */
- mbc->adapter = devm_power_supply_register(&pdev->dev,
- &pcf50633_mbc_adapter_desc,
- &psy_cfg);
- if (IS_ERR(mbc->adapter)) {
- dev_err(mbc->pcf->dev, "failed to register adapter\n");
- return PTR_ERR(mbc->adapter);
- }
-
- usb_psy_cfg = psy_cfg;
- usb_psy_cfg.attr_grp = pcf50633_mbc_sysfs_groups;
-
- mbc->usb = devm_power_supply_register(&pdev->dev,
- &pcf50633_mbc_usb_desc,
- &usb_psy_cfg);
- if (IS_ERR(mbc->usb)) {
- dev_err(mbc->pcf->dev, "failed to register usb\n");
- return PTR_ERR(mbc->usb);
- }
-
- mbc->ac = devm_power_supply_register(&pdev->dev,
- &pcf50633_mbc_ac_desc,
- &psy_cfg);
- if (IS_ERR(mbc->ac)) {
- dev_err(mbc->pcf->dev, "failed to register ac\n");
- return PTR_ERR(mbc->ac);
- }
-
- mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1);
- if (mbcs1 & PCF50633_MBCS1_USBPRES)
- pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc);
- if (mbcs1 & PCF50633_MBCS1_ADAPTPRES)
- pcf50633_mbc_irq_handler(PCF50633_IRQ_ADPINS, mbc);
-
- return 0;
-}
-
-static void pcf50633_mbc_remove(struct platform_device *pdev)
-{
- struct pcf50633_mbc *mbc = platform_get_drvdata(pdev);
- int i;
-
- /* Remove IRQ handlers */
- for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
- pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]);
-}
-
-static struct platform_driver pcf50633_mbc_driver = {
- .driver = {
- .name = "pcf50633-mbc",
- },
- .probe = pcf50633_mbc_probe,
- .remove = pcf50633_mbc_remove,
-};
-
-module_platform_driver(pcf50633_mbc_driver);
-
-MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
-MODULE_DESCRIPTION("PCF50633 mbc driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pcf50633-mbc");
diff --git a/drivers/power/supply/pm8916_bms_vm.c b/drivers/power/supply/pm8916_bms_vm.c
index 5d0dd842509c..5120be086e6f 100644
--- a/drivers/power/supply/pm8916_bms_vm.c
+++ b/drivers/power/supply/pm8916_bms_vm.c
@@ -210,7 +210,7 @@ static int pm8916_bms_vm_battery_probe(struct platform_device *pdev)
bat->vbat_now = bat->last_ocv;
psy_cfg.drv_data = bat;
- psy_cfg.of_node = dev->of_node;
+ psy_cfg.fwnode = dev_fwnode(dev);
bat->battery = devm_power_supply_register(dev, &pm8916_bms_vm_battery_psy_desc, &psy_cfg);
if (IS_ERR(bat->battery))
diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
index 6d92e98cbecc..c74b75b1b267 100644
--- a/drivers/power/supply/pm8916_lbc.c
+++ b/drivers/power/supply/pm8916_lbc.c
@@ -322,7 +322,7 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
dev_err_probe(dev, ret, "Error while parsing device tree\n");
psy_cfg.drv_data = chg;
- psy_cfg.of_node = dev->of_node;
+ psy_cfg.fwnode = dev_fwnode(dev);
chg->charger = devm_power_supply_register(dev, &pm8916_lbc_charger_psy_desc, &psy_cfg);
if (IS_ERR(chg->charger))
diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h
index 7434a6f24775..8f6a2d44b996 100644
--- a/drivers/power/supply/power_supply.h
+++ b/drivers/power/supply/power_supply.h
@@ -9,24 +9,55 @@
* Modified: 2004, Oct Szabolcs Gyurko
*/
+#include <linux/lockdep.h>
+
struct device;
struct device_type;
struct power_supply;
extern int power_supply_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp);
+extern bool power_supply_has_property(struct power_supply *psy,
+ enum power_supply_property psp);
+extern bool power_supply_ext_has_property(const struct power_supply_ext *ext,
+ enum power_supply_property psp);
+
+struct power_supply_ext_registration {
+ struct list_head list_head;
+ const struct power_supply_ext *ext;
+ struct device *dev;
+ void *data;
+};
+
+/* Make sure that the macro is a single expression */
+#define power_supply_for_each_extension(pos, psy) \
+ if ( ({ lockdep_assert_held(&(psy)->extensions_sem); 0; }) ) \
+ ; \
+ else \
+ list_for_each_entry(pos, &(psy)->extensions, list_head) \
#ifdef CONFIG_SYSFS
extern void __init power_supply_init_attrs(void);
extern int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env);
extern const struct attribute_group *power_supply_attr_groups[];
+extern int power_supply_sysfs_add_extension(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ struct device *dev);
+extern void power_supply_sysfs_remove_extension(struct power_supply *psy,
+ const struct power_supply_ext *ext);
#else
static inline void power_supply_init_attrs(void) {}
#define power_supply_attr_groups NULL
#define power_supply_uevent NULL
+static inline int power_supply_sysfs_add_extension(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ struct device *dev)
+{ return 0; }
+static inline void power_supply_sysfs_remove_extension(struct power_supply *psy,
+ const struct power_supply_ext *ext) {}
#endif /* CONFIG_SYSFS */
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 16085eff0084..33a5bfce4604 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -66,21 +66,19 @@ static bool __power_supply_is_supplied_by(struct power_supply *supplier,
return false;
}
-static int __power_supply_changed_work(struct device *dev, void *data)
+static int __power_supply_changed_work(struct power_supply *pst, void *data)
{
struct power_supply *psy = data;
- struct power_supply *pst = dev_get_drvdata(dev);
- if (__power_supply_is_supplied_by(psy, pst)) {
- if (pst->desc->external_power_changed)
- pst->desc->external_power_changed(pst);
- }
+ if (__power_supply_is_supplied_by(psy, pst))
+ power_supply_external_power_changed(pst);
return 0;
}
static void power_supply_changed_work(struct work_struct *work)
{
+ int ret;
unsigned long flags;
struct power_supply *psy = container_of(work, struct power_supply,
changed_work);
@@ -88,6 +86,16 @@ static void power_supply_changed_work(struct work_struct *work)
dev_dbg(&psy->dev, "%s\n", __func__);
spin_lock_irqsave(&psy->changed_lock, flags);
+
+ if (unlikely(psy->update_groups)) {
+ psy->update_groups = false;
+ spin_unlock_irqrestore(&psy->changed_lock, flags);
+ ret = sysfs_update_groups(&psy->dev.kobj, power_supply_dev_type.groups);
+ if (ret)
+ dev_warn(&psy->dev, "failed to update sysfs groups: %pe\n", ERR_PTR(ret));
+ spin_lock_irqsave(&psy->changed_lock, flags);
+ }
+
/*
* Check 'changed' here to avoid issues due to race between
* power_supply_changed() and this routine. In worst case
@@ -98,7 +106,7 @@ static void power_supply_changed_work(struct work_struct *work)
if (likely(psy->changed)) {
psy->changed = false;
spin_unlock_irqrestore(&psy->changed_lock, flags);
- power_supply_for_each_device(psy, __power_supply_changed_work);
+ power_supply_for_each_psy(psy, __power_supply_changed_work);
power_supply_update_leds(psy);
blocking_notifier_call_chain(&power_supply_notifier,
PSY_EVENT_PROP_CHANGED, psy);
@@ -116,11 +124,29 @@ static void power_supply_changed_work(struct work_struct *work)
spin_unlock_irqrestore(&psy->changed_lock, flags);
}
-int power_supply_for_each_device(void *data, int (*fn)(struct device *dev, void *data))
+struct psy_for_each_psy_cb_data {
+ int (*fn)(struct power_supply *psy, void *data);
+ void *data;
+};
+
+static int psy_for_each_psy_cb(struct device *dev, void *data)
+{
+ struct psy_for_each_psy_cb_data *cb_data = data;
+ struct power_supply *psy = dev_to_psy(dev);
+
+ return cb_data->fn(psy, cb_data->data);
+}
+
+int power_supply_for_each_psy(void *data, int (*fn)(struct power_supply *psy, void *data))
{
- return class_for_each_device(&power_supply_class, NULL, data, fn);
+ struct psy_for_each_psy_cb_data cb_data = {
+ .fn = fn,
+ .data = data,
+ };
+
+ return class_for_each_device(&power_supply_class, NULL, &cb_data, psy_for_each_psy_cb);
}
-EXPORT_SYMBOL_GPL(power_supply_for_each_device);
+EXPORT_SYMBOL_GPL(power_supply_for_each_psy);
void power_supply_changed(struct power_supply *psy)
{
@@ -166,20 +192,19 @@ static void power_supply_deferred_register_work(struct work_struct *work)
}
#ifdef CONFIG_OF
-static int __power_supply_populate_supplied_from(struct device *dev,
+static int __power_supply_populate_supplied_from(struct power_supply *epsy,
void *data)
{
struct power_supply *psy = data;
- struct power_supply *epsy = dev_get_drvdata(dev);
struct device_node *np;
int i = 0;
do {
- np = of_parse_phandle(psy->of_node, "power-supplies", i++);
+ np = of_parse_phandle(psy->dev.of_node, "power-supplies", i++);
if (!np)
break;
- if (np == epsy->of_node) {
+ if (np == epsy->dev.of_node) {
dev_dbg(&psy->dev, "%s: Found supply : %s\n",
psy->desc->name, epsy->desc->name);
psy->supplied_from[i-1] = (char *)epsy->desc->name;
@@ -197,21 +222,20 @@ static int power_supply_populate_supplied_from(struct power_supply *psy)
{
int error;
- error = power_supply_for_each_device(psy, __power_supply_populate_supplied_from);
+ error = power_supply_for_each_psy(psy, __power_supply_populate_supplied_from);
dev_dbg(&psy->dev, "%s %d\n", __func__, error);
return error;
}
-static int __power_supply_find_supply_from_node(struct device *dev,
+static int __power_supply_find_supply_from_node(struct power_supply *epsy,
void *data)
{
struct device_node *np = data;
- struct power_supply *epsy = dev_get_drvdata(dev);
- /* returning non-zero breaks out of power_supply_for_each_device loop */
- if (epsy->of_node == np)
+ /* returning non-zero breaks out of power_supply_for_each_psy loop */
+ if (epsy->dev.of_node == np)
return 1;
return 0;
@@ -222,16 +246,16 @@ static int power_supply_find_supply_from_node(struct device_node *supply_node)
int error;
/*
- * power_supply_for_each_device() either returns its own errors or values
+ * power_supply_for_each_psy() either returns its own errors or values
* returned by __power_supply_find_supply_from_node().
*
* __power_supply_find_supply_from_node() will return 0 (no match)
* or 1 (match).
*
- * We return 0 if power_supply_for_each_device() returned 1, -EPROBE_DEFER if
+ * We return 0 if power_supply_for_each_psy() returned 1, -EPROBE_DEFER if
* it returned 0, or error as returned by it.
*/
- error = power_supply_for_each_device(supply_node, __power_supply_find_supply_from_node);
+ error = power_supply_for_each_psy(supply_node, __power_supply_find_supply_from_node);
return error ? (error == 1 ? 0 : error) : -EPROBE_DEFER;
}
@@ -246,13 +270,13 @@ static int power_supply_check_supplies(struct power_supply *psy)
return 0;
/* No device node found, nothing to do */
- if (!psy->of_node)
+ if (!psy->dev.of_node)
return 0;
do {
int ret;
- np = of_parse_phandle(psy->of_node, "power-supplies", cnt++);
+ np = of_parse_phandle(psy->dev.of_node, "power-supplies", cnt++);
if (!np)
break;
@@ -316,10 +340,9 @@ struct psy_am_i_supplied_data {
unsigned int count;
};
-static int __power_supply_am_i_supplied(struct device *dev, void *_data)
+static int __power_supply_am_i_supplied(struct power_supply *epsy, void *_data)
{
union power_supply_propval ret = {0,};
- struct power_supply *epsy = dev_get_drvdata(dev);
struct psy_am_i_supplied_data *data = _data;
if (__power_supply_is_supplied_by(epsy, data->psy)) {
@@ -337,7 +360,7 @@ int power_supply_am_i_supplied(struct power_supply *psy)
struct psy_am_i_supplied_data data = { psy, 0 };
int error;
- error = power_supply_for_each_device(&data, __power_supply_am_i_supplied);
+ error = power_supply_for_each_psy(&data, __power_supply_am_i_supplied);
dev_dbg(&psy->dev, "%s count %u err %d\n", __func__, data.count, error);
@@ -348,10 +371,9 @@ int power_supply_am_i_supplied(struct power_supply *psy)
}
EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
-static int __power_supply_is_system_supplied(struct device *dev, void *data)
+static int __power_supply_is_system_supplied(struct power_supply *psy, void *data)
{
union power_supply_propval ret = {0,};
- struct power_supply *psy = dev_get_drvdata(dev);
unsigned int *count = data;
if (!psy->desc->get_property(psy, POWER_SUPPLY_PROP_SCOPE, &ret))
@@ -372,7 +394,7 @@ int power_supply_is_system_supplied(void)
int error;
unsigned int count = 0;
- error = power_supply_for_each_device(&count, __power_supply_is_system_supplied);
+ error = power_supply_for_each_psy(&count, __power_supply_is_system_supplied);
/*
* If no system scope power class device was found at all, most probably we
@@ -391,9 +413,8 @@ struct psy_get_supplier_prop_data {
union power_supply_propval *val;
};
-static int __power_supply_get_supplier_property(struct device *dev, void *_data)
+static int __power_supply_get_supplier_property(struct power_supply *epsy, void *_data)
{
- struct power_supply *epsy = dev_get_drvdata(dev);
struct psy_get_supplier_prop_data *data = _data;
if (__power_supply_is_supplied_by(epsy, data->psy))
@@ -418,7 +439,7 @@ int power_supply_get_property_from_supplier(struct power_supply *psy,
* This function is not intended for use with a supply with multiple
* suppliers, we simply pick the first supply to report the psp.
*/
- ret = power_supply_for_each_device(&data, __power_supply_get_supplier_property);
+ ret = power_supply_for_each_psy(&data, __power_supply_get_supplier_property);
if (ret < 0)
return ret;
if (ret == 0)
@@ -428,23 +449,10 @@ int power_supply_get_property_from_supplier(struct power_supply *psy,
}
EXPORT_SYMBOL_GPL(power_supply_get_property_from_supplier);
-int power_supply_set_battery_charged(struct power_supply *psy)
-{
- if (atomic_read(&psy->use_cnt) >= 0 &&
- psy->desc->type == POWER_SUPPLY_TYPE_BATTERY &&
- psy->desc->set_charged) {
- psy->desc->set_charged(psy);
- return 0;
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(power_supply_set_battery_charged);
-
static int power_supply_match_device_by_name(struct device *dev, const void *data)
{
const char *name = data;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
return strcmp(psy->desc->name, name) == 0;
}
@@ -467,7 +475,7 @@ struct power_supply *power_supply_get_by_name(const char *name)
power_supply_match_device_by_name);
if (dev) {
- psy = dev_get_drvdata(dev);
+ psy = dev_to_psy(dev);
atomic_inc(&psy->use_cnt);
}
@@ -524,7 +532,7 @@ struct power_supply *power_supply_get_by_phandle(struct device_node *np,
of_node_put(power_supply_np);
if (dev) {
- psy = dev_get_drvdata(dev);
+ psy = dev_to_psy(dev);
atomic_inc(&psy->use_cnt);
}
@@ -585,8 +593,8 @@ int power_supply_get_battery_info(struct power_supply *psy,
const __be32 *list;
u32 min_max[2];
- if (psy->of_node) {
- battery_np = of_parse_phandle(psy->of_node, "monitored-battery", 0);
+ if (psy->dev.of_node) {
+ battery_np = of_parse_phandle(psy->dev.of_node, "monitored-battery", 0);
if (!battery_np)
return -ENODEV;
@@ -1180,8 +1188,8 @@ bool power_supply_battery_bti_in_range(struct power_supply_battery_info *info,
}
EXPORT_SYMBOL_GPL(power_supply_battery_bti_in_range);
-static bool psy_has_property(const struct power_supply_desc *psy_desc,
- enum power_supply_property psp)
+static bool psy_desc_has_property(const struct power_supply_desc *psy_desc,
+ enum power_supply_property psp)
{
bool found = false;
int i;
@@ -1196,17 +1204,57 @@ static bool psy_has_property(const struct power_supply_desc *psy_desc,
return found;
}
+bool power_supply_ext_has_property(const struct power_supply_ext *psy_ext,
+ enum power_supply_property psp)
+{
+ int i;
+
+ for (i = 0; i < psy_ext->num_properties; i++)
+ if (psy_ext->properties[i] == psp)
+ return true;
+
+ return false;
+}
+
+bool power_supply_has_property(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ struct power_supply_ext_registration *reg;
+
+ if (psy_desc_has_property(psy->desc, psp))
+ return true;
+
+ if (power_supply_battery_info_has_prop(psy->battery_info, psp))
+ return true;
+
+ power_supply_for_each_extension(reg, psy) {
+ if (power_supply_ext_has_property(reg->ext, psp))
+ return true;
+ }
+
+ return false;
+}
+
int power_supply_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
+ struct power_supply_ext_registration *reg;
+
if (atomic_read(&psy->use_cnt) <= 0) {
if (!psy->initialized)
return -EAGAIN;
return -ENODEV;
}
- if (psy_has_property(psy->desc, psp))
+ scoped_guard(rwsem_read, &psy->extensions_sem) {
+ power_supply_for_each_extension(reg, psy) {
+ if (power_supply_ext_has_property(reg->ext, psp))
+ return reg->ext->get_property(psy, reg->ext, reg->data, psp, val);
+ }
+ }
+
+ if (psy_desc_has_property(psy->desc, psp))
return psy->desc->get_property(psy, psp, val);
else if (power_supply_battery_info_has_prop(psy->battery_info, psp))
return power_supply_battery_info_get_prop(psy->battery_info, psp, val);
@@ -1219,7 +1267,24 @@ int power_supply_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
- if (atomic_read(&psy->use_cnt) <= 0 || !psy->desc->set_property)
+ struct power_supply_ext_registration *reg;
+
+ if (atomic_read(&psy->use_cnt) <= 0)
+ return -ENODEV;
+
+ scoped_guard(rwsem_read, &psy->extensions_sem) {
+ power_supply_for_each_extension(reg, psy) {
+ if (power_supply_ext_has_property(reg->ext, psp)) {
+ if (reg->ext->set_property)
+ return reg->ext->set_property(psy, reg->ext, reg->data,
+ psp, val);
+ else
+ return -ENODEV;
+ }
+ }
+ }
+
+ if (!psy->desc->set_property)
return -ENODEV;
return psy->desc->set_property(psy, psp, val);
@@ -1229,7 +1294,22 @@ EXPORT_SYMBOL_GPL(power_supply_set_property);
int power_supply_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
- return psy->desc->property_is_writeable && psy->desc->property_is_writeable(psy, psp);
+ struct power_supply_ext_registration *reg;
+
+ power_supply_for_each_extension(reg, psy) {
+ if (power_supply_ext_has_property(reg->ext, psp)) {
+ if (reg->ext->property_is_writeable)
+ return reg->ext->property_is_writeable(psy, reg->ext,
+ reg->data, psp);
+ else
+ return 0;
+ }
+ }
+
+ if (!psy->desc->property_is_writeable)
+ return 0;
+
+ return psy->desc->property_is_writeable(psy, psp);
}
void power_supply_external_power_changed(struct power_supply *psy)
@@ -1248,6 +1328,88 @@ int power_supply_powers(struct power_supply *psy, struct device *dev)
}
EXPORT_SYMBOL_GPL(power_supply_powers);
+static int power_supply_update_sysfs_and_hwmon(struct power_supply *psy)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&psy->changed_lock, flags);
+ psy->update_groups = true;
+ spin_unlock_irqrestore(&psy->changed_lock, flags);
+
+ power_supply_changed(psy);
+
+ power_supply_remove_hwmon_sysfs(psy);
+ return power_supply_add_hwmon_sysfs(psy);
+}
+
+int power_supply_register_extension(struct power_supply *psy, const struct power_supply_ext *ext,
+ struct device *dev, void *data)
+{
+ struct power_supply_ext_registration *reg;
+ size_t i;
+ int ret;
+
+ if (!psy || !dev || !ext || !ext->name || !ext->properties || !ext->num_properties)
+ return -EINVAL;
+
+ guard(rwsem_write)(&psy->extensions_sem);
+
+ power_supply_for_each_extension(reg, psy)
+ if (strcmp(ext->name, reg->ext->name) == 0)
+ return -EEXIST;
+
+ for (i = 0; i < ext->num_properties; i++)
+ if (power_supply_has_property(psy, ext->properties[i]))
+ return -EEXIST;
+
+ reg = kmalloc(sizeof(*reg), GFP_KERNEL);
+ if (!reg)
+ return -ENOMEM;
+
+ reg->ext = ext;
+ reg->dev = dev;
+ reg->data = data;
+ list_add(&reg->list_head, &psy->extensions);
+
+ ret = power_supply_sysfs_add_extension(psy, ext, dev);
+ if (ret)
+ goto sysfs_add_failed;
+
+ ret = power_supply_update_sysfs_and_hwmon(psy);
+ if (ret)
+ goto sysfs_hwmon_failed;
+
+ return 0;
+
+sysfs_hwmon_failed:
+ power_supply_sysfs_remove_extension(psy, ext);
+sysfs_add_failed:
+ list_del(&reg->list_head);
+ kfree(reg);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(power_supply_register_extension);
+
+void power_supply_unregister_extension(struct power_supply *psy, const struct power_supply_ext *ext)
+{
+ struct power_supply_ext_registration *reg;
+
+ guard(rwsem_write)(&psy->extensions_sem);
+
+ power_supply_for_each_extension(reg, psy) {
+ if (reg->ext == ext) {
+ list_del(&reg->list_head);
+ power_supply_sysfs_remove_extension(psy, ext);
+ kfree(reg);
+ power_supply_update_sysfs_and_hwmon(psy);
+ return;
+ }
+ }
+
+ dev_warn(&psy->dev, "Trying to unregister invalid extension");
+}
+EXPORT_SYMBOL_GPL(power_supply_unregister_extension);
+
static void power_supply_dev_release(struct device *dev)
{
struct power_supply *psy = to_power_supply(dev);
@@ -1300,7 +1462,7 @@ static int psy_register_thermal(struct power_supply *psy)
return 0;
/* Register battery zone device psy reports temperature */
- if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
+ if (psy_desc_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
/* Prefer our hwmon device and avoid duplicates */
struct thermal_zone_params tzp = {
.no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
@@ -1369,9 +1531,8 @@ __power_supply_register(struct device *parent,
if (cfg) {
dev->groups = cfg->attr_grp;
psy->drv_data = cfg->drv_data;
- psy->of_node =
+ dev->of_node =
cfg->fwnode ? to_of_node(cfg->fwnode) : cfg->of_node;
- dev->of_node = psy->of_node;
psy->supplied_to = cfg->supplied_to;
psy->num_supplicants = cfg->num_supplicants;
}
@@ -1402,6 +1563,9 @@ __power_supply_register(struct device *parent,
}
spin_lock_init(&psy->changed_lock);
+ init_rwsem(&psy->extensions_sem);
+ INIT_LIST_HEAD(&psy->extensions);
+
rc = device_add(dev);
if (rc)
goto device_add_failed;
@@ -1418,9 +1582,11 @@ __power_supply_register(struct device *parent,
if (rc)
goto create_triggers_failed;
- rc = power_supply_add_hwmon_sysfs(psy);
- if (rc)
- goto add_hwmon_sysfs_failed;
+ scoped_guard(rwsem_read, &psy->extensions_sem) {
+ rc = power_supply_add_hwmon_sysfs(psy);
+ if (rc)
+ goto add_hwmon_sysfs_failed;
+ }
/*
* Update use_cnt after any uevents (most notably from device_add()).
diff --git a/drivers/power/supply/power_supply_hwmon.c b/drivers/power/supply/power_supply_hwmon.c
index 01be04903d7d..95245e6a6baa 100644
--- a/drivers/power/supply/power_supply_hwmon.c
+++ b/drivers/power/supply/power_supply_hwmon.c
@@ -349,9 +349,28 @@ static const struct hwmon_chip_info power_supply_hwmon_chip_info = {
.info = power_supply_hwmon_info,
};
+static const enum power_supply_property power_supply_hwmon_props[] = {
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_POWER_AVG,
+ POWER_SUPPLY_PROP_POWER_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TEMP_MAX,
+ POWER_SUPPLY_PROP_TEMP_MIN,
+ POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
+ POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
int power_supply_add_hwmon_sysfs(struct power_supply *psy)
{
- const struct power_supply_desc *desc = psy->desc;
struct power_supply_hwmon *psyhw;
struct device *dev = &psy->dev;
struct device *hwmon;
@@ -377,32 +396,11 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy)
goto error;
}
- for (i = 0; i < desc->num_properties; i++) {
- const enum power_supply_property prop = desc->properties[i];
-
- switch (prop) {
- case POWER_SUPPLY_PROP_CURRENT_AVG:
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- case POWER_SUPPLY_PROP_CURRENT_NOW:
- case POWER_SUPPLY_PROP_POWER_AVG:
- case POWER_SUPPLY_PROP_POWER_NOW:
- case POWER_SUPPLY_PROP_TEMP:
- case POWER_SUPPLY_PROP_TEMP_MAX:
- case POWER_SUPPLY_PROP_TEMP_MIN:
- case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
- case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
- case POWER_SUPPLY_PROP_TEMP_AMBIENT:
- case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN:
- case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX:
- case POWER_SUPPLY_PROP_VOLTAGE_AVG:
- case POWER_SUPPLY_PROP_VOLTAGE_MIN:
- case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ for (i = 0; i < ARRAY_SIZE(power_supply_hwmon_props); i++) {
+ const enum power_supply_property prop = power_supply_hwmon_props[i];
+
+ if (power_supply_has_property(psy, prop))
set_bit(prop, psyhw->props);
- break;
- default:
- break;
- }
}
name = psy->desc->name;
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 571de43fcca9..439dd0bf8644 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -33,7 +33,7 @@ struct power_supply_attr {
[POWER_SUPPLY_PROP_ ## _name] = \
{ \
.prop_name = #_name, \
- .attr_name = #_name "\0", \
+ .attr_name = #_name, \
.text_values = _text, \
.text_values_len = _len, \
}
@@ -99,6 +99,7 @@ static const char * const POWER_SUPPLY_HEALTH_TEXT[] = {
[POWER_SUPPLY_HEALTH_OVERHEAT] = "Overheat",
[POWER_SUPPLY_HEALTH_DEAD] = "Dead",
[POWER_SUPPLY_HEALTH_OVERVOLTAGE] = "Over voltage",
+ [POWER_SUPPLY_HEALTH_UNDERVOLTAGE] = "Under voltage",
[POWER_SUPPLY_HEALTH_UNSPEC_FAILURE] = "Unspecified failure",
[POWER_SUPPLY_HEALTH_COLD] = "Cold",
[POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE] = "Watchdog timer expire",
@@ -182,6 +183,8 @@ static struct power_supply_attr power_supply_attrs[] __ro_after_init = {
POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
POWER_SUPPLY_ATTR(CHARGE_CONTROL_END_THRESHOLD),
POWER_SUPPLY_ENUM_ATTR(CHARGE_BEHAVIOUR),
+ /* Same enum value texts as "charge_type" without the 's' at the end */
+ _POWER_SUPPLY_ENUM_ATTR(CHARGE_TYPES, POWER_SUPPLY_CHARGE_TYPE_TEXT),
POWER_SUPPLY_ATTR(INPUT_CURRENT_LIMIT),
POWER_SUPPLY_ATTR(INPUT_VOLTAGE_LIMIT),
POWER_SUPPLY_ATTR(INPUT_POWER_LIMIT),
@@ -237,23 +240,52 @@ static enum power_supply_property dev_attr_psp(struct device_attribute *attr)
return to_ps_attr(attr) - power_supply_attrs;
}
+static void power_supply_escape_spaces(const char *str, char *buf, size_t bufsize)
+{
+ strscpy(buf, str, bufsize);
+ strreplace(buf, ' ', '_');
+}
+
+static int power_supply_match_string(const char * const *array, size_t n, const char *s)
+{
+ int ret;
+
+ /* First try an exact match */
+ ret = __sysfs_match_string(array, n, s);
+ if (ret >= 0)
+ return ret;
+
+ /* Second round, try matching with spaces replaced by '_' */
+ for (size_t i = 0; i < n; i++) {
+ char buf[32];
+
+ power_supply_escape_spaces(array[i], buf, sizeof(buf));
+ if (sysfs_streq(buf, s))
+ return i;
+ }
+
+ return -EINVAL;
+}
+
static ssize_t power_supply_show_enum_with_available(
struct device *dev, const char * const labels[], int label_count,
unsigned int available_values, int value, char *buf)
{
bool match = false, available, active;
+ char escaped_label[32];
ssize_t count = 0;
int i;
for (i = 0; i < label_count; i++) {
available = available_values & BIT(i);
active = i == value;
+ power_supply_escape_spaces(labels[i], escaped_label, sizeof(escaped_label));
if (available && active) {
- count += sysfs_emit_at(buf, count, "[%s] ", labels[i]);
+ count += sysfs_emit_at(buf, count, "[%s] ", escaped_label);
match = true;
} else if (available) {
- count += sysfs_emit_at(buf, count, "%s ", labels[i]);
+ count += sysfs_emit_at(buf, count, "%s ", escaped_label);
}
}
@@ -268,11 +300,34 @@ static ssize_t power_supply_show_enum_with_available(
return count;
}
-static ssize_t power_supply_show_property(struct device *dev,
- struct device_attribute *attr,
- char *buf) {
+static ssize_t power_supply_show_charge_behaviour(struct device *dev,
+ struct power_supply *psy,
+ union power_supply_propval *value,
+ char *buf)
+{
+ struct power_supply_ext_registration *reg;
+
+ scoped_guard(rwsem_read, &psy->extensions_sem) {
+ power_supply_for_each_extension(reg, psy) {
+ if (power_supply_ext_has_property(reg->ext,
+ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR))
+ return power_supply_charge_behaviour_show(dev,
+ reg->ext->charge_behaviours,
+ value->intval, buf);
+ }
+ }
+
+ return power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours,
+ value->intval, buf);
+}
+
+static ssize_t power_supply_format_property(struct device *dev,
+ bool uevent,
+ struct device_attribute *attr,
+ char *buf)
+{
ssize_t ret;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
const struct power_supply_attr *ps_attr = to_ps_attr(attr);
enum power_supply_property psp = dev_attr_psp(attr);
union power_supply_propval value;
@@ -287,7 +342,7 @@ static ssize_t power_supply_show_property(struct device *dev,
dev_dbg_ratelimited(dev,
"driver has no data for `%s' property\n",
attr->attr.name);
- else if (ret != -ENODEV && ret != -EAGAIN)
+ else if (ret != -ENODEV && ret != -EAGAIN && ret != -EINVAL)
dev_err_ratelimited(dev,
"driver failed to report `%s' property: %zd\n",
attr->attr.name, ret);
@@ -303,13 +358,21 @@ static ssize_t power_supply_show_property(struct device *dev,
psy->desc->usb_types, value.intval, buf);
break;
case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
- ret = power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours,
- value.intval, buf);
+ if (uevent) /* no possible values in uevents */
+ goto default_format;
+ ret = power_supply_show_charge_behaviour(dev, psy, &value, buf);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPES:
+ if (uevent) /* no possible values in uevents */
+ goto default_format;
+ ret = power_supply_charge_types_show(dev, psy->desc->charge_types,
+ value.intval, buf);
break;
case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
ret = sysfs_emit(buf, "%s\n", value.strval);
break;
default:
+default_format:
if (ps_attr->text_values_len > 0 &&
value.intval < ps_attr->text_values_len && value.intval >= 0) {
ret = sysfs_emit(buf, "%s\n", ps_attr->text_values[value.intval]);
@@ -321,19 +384,26 @@ static ssize_t power_supply_show_property(struct device *dev,
return ret;
}
+static ssize_t power_supply_show_property(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return power_supply_format_property(dev, false, attr, buf);
+}
+
static ssize_t power_supply_store_property(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count) {
ssize_t ret;
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
const struct power_supply_attr *ps_attr = to_ps_attr(attr);
enum power_supply_property psp = dev_attr_psp(attr);
union power_supply_propval value;
ret = -EINVAL;
if (ps_attr->text_values_len > 0) {
- ret = __sysfs_match_string(ps_attr->text_values,
- ps_attr->text_values_len, buf);
+ ret = power_supply_match_string(ps_attr->text_values,
+ ps_attr->text_values_len, buf);
}
/*
@@ -364,9 +434,8 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
int attrno)
{
struct device *dev = kobj_to_dev(kobj);
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
- int i;
if (!power_supply_attrs[attrno].prop_name)
return 0;
@@ -374,19 +443,13 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
if (attrno == POWER_SUPPLY_PROP_TYPE)
return mode;
- for (i = 0; i < psy->desc->num_properties; i++) {
- int property = psy->desc->properties[i];
-
- if (property == attrno) {
- if (power_supply_property_is_writeable(psy, property) > 0)
- mode |= S_IWUSR;
+ guard(rwsem_read)(&psy->extensions_sem);
- return mode;
- }
- }
-
- if (power_supply_battery_info_has_prop(psy->battery_info, attrno))
+ if (power_supply_has_property(psy, attrno)) {
+ if (power_supply_property_is_writeable(psy, attrno) > 0)
+ mode |= S_IWUSR;
return mode;
+ }
return 0;
}
@@ -396,8 +459,18 @@ static const struct attribute_group power_supply_attr_group = {
.is_visible = power_supply_attr_is_visible,
};
+static struct attribute *power_supply_extension_attrs[] = {
+ NULL
+};
+
+static const struct attribute_group power_supply_extension_group = {
+ .name = "extensions",
+ .attrs = power_supply_extension_attrs,
+};
+
const struct attribute_group *power_supply_attr_groups[] = {
&power_supply_attr_group,
+ &power_supply_extension_group,
NULL
};
@@ -437,8 +510,8 @@ static int add_prop_uevent(const struct device *dev, struct kobj_uevent_env *env
pwr_attr = &power_supply_attrs[prop];
dev_attr = &pwr_attr->dev_attr;
- ret = power_supply_show_property((struct device *)dev, dev_attr, prop_buf);
- if (ret == -ENODEV || ret == -ENODATA) {
+ ret = power_supply_format_property((struct device *)dev, true, dev_attr, prop_buf);
+ if (ret == -ENODEV || ret == -ENODATA || ret == -EINVAL) {
/*
* When a battery is absent, we expect -ENODEV. Don't abort;
* send the uevent with at least the PRESENT=0 property
@@ -459,11 +532,7 @@ static int add_prop_uevent(const struct device *dev, struct kobj_uevent_env *env
int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- const struct power_supply *psy = dev_get_drvdata(dev);
- const enum power_supply_property *battery_props =
- power_supply_battery_info_properties;
- unsigned long psy_drv_properties[POWER_SUPPLY_ATTR_CNT /
- sizeof(unsigned long) + 1] = {0};
+ const struct power_supply *psy = dev_to_psy(dev);
int ret = 0, j;
char *prop_buf;
@@ -491,22 +560,8 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
if (ret)
goto out;
- for (j = 0; j < psy->desc->num_properties; j++) {
- set_bit(psy->desc->properties[j], psy_drv_properties);
- ret = add_prop_uevent(dev, env, psy->desc->properties[j],
- prop_buf);
- if (ret)
- goto out;
- }
-
- for (j = 0; j < power_supply_battery_info_properties_size; j++) {
- if (test_bit(battery_props[j], psy_drv_properties))
- continue;
- if (!power_supply_battery_info_has_prop(psy->battery_info,
- battery_props[j]))
- continue;
- ret = add_prop_uevent(dev, env, battery_props[j],
- prop_buf);
+ for (j = 0; j < POWER_SUPPLY_ATTR_CNT; j++) {
+ ret = add_prop_uevent(dev, env, j, prop_buf);
if (ret)
goto out;
}
@@ -542,3 +597,44 @@ int power_supply_charge_behaviour_parse(unsigned int available_behaviours, const
return -EINVAL;
}
EXPORT_SYMBOL_GPL(power_supply_charge_behaviour_parse);
+
+ssize_t power_supply_charge_types_show(struct device *dev,
+ unsigned int available_types,
+ enum power_supply_charge_type current_type,
+ char *buf)
+{
+ return power_supply_show_enum_with_available(
+ dev, POWER_SUPPLY_CHARGE_TYPE_TEXT,
+ ARRAY_SIZE(POWER_SUPPLY_CHARGE_TYPE_TEXT),
+ available_types, current_type, buf);
+}
+EXPORT_SYMBOL_GPL(power_supply_charge_types_show);
+
+int power_supply_charge_types_parse(unsigned int available_types, const char *buf)
+{
+ int i = power_supply_match_string(POWER_SUPPLY_CHARGE_TYPE_TEXT,
+ ARRAY_SIZE(POWER_SUPPLY_CHARGE_TYPE_TEXT),
+ buf);
+
+ if (i < 0)
+ return i;
+
+ if (available_types & BIT(i))
+ return i;
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(power_supply_charge_types_parse);
+
+int power_supply_sysfs_add_extension(struct power_supply *psy, const struct power_supply_ext *ext,
+ struct device *dev)
+{
+ return sysfs_add_link_to_group(&psy->dev.kobj, power_supply_extension_group.name,
+ &dev->kobj, ext->name);
+}
+
+void power_supply_sysfs_remove_extension(struct power_supply *psy,
+ const struct power_supply_ext *ext)
+{
+ sysfs_remove_link_from_group(&psy->dev.kobj, power_supply_extension_group.name, ext->name);
+}
diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c
index 47d29271ddf4..fe27676fbc7c 100644
--- a/drivers/power/supply/qcom_battmgr.c
+++ b/drivers/power/supply/qcom_battmgr.c
@@ -8,6 +8,7 @@
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/power_supply.h>
+#include <linux/property.h>
#include <linux/soc/qcom/pdr.h>
#include <linux/soc/qcom/pmic_glink.h>
#include <linux/math.h>
@@ -1336,10 +1337,10 @@ static int qcom_battmgr_probe(struct auxiliary_device *adev,
battmgr->dev = dev;
psy_cfg.drv_data = battmgr;
- psy_cfg.of_node = adev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&adev->dev);
psy_cfg_supply.drv_data = battmgr;
- psy_cfg_supply.of_node = adev->dev.of_node;
+ psy_cfg_supply.fwnode = dev_fwnode(&adev->dev);
psy_cfg_supply.supplied_to = qcom_battmgr_battery;
psy_cfg_supply.num_supplicants = 1;
diff --git a/drivers/power/supply/qcom_pmi8998_charger.c b/drivers/power/supply/qcom_pmi8998_charger.c
index 3b4132376649..74a8d8ed8d9f 100644
--- a/drivers/power/supply/qcom_pmi8998_charger.c
+++ b/drivers/power/supply/qcom_pmi8998_charger.c
@@ -964,7 +964,7 @@ static int smb2_probe(struct platform_device *pdev)
return rc;
supply_config.drv_data = chip;
- supply_config.of_node = pdev->dev.of_node;
+ supply_config.fwnode = dev_fwnode(&pdev->dev);
desc = devm_kzalloc(chip->dev, sizeof(smb2_psy_desc), GFP_KERNEL);
if (!desc)
diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c
index a79563f6ff7a..28afe758a2da 100644
--- a/drivers/power/supply/qcom_smbb.c
+++ b/drivers/power/supply/qcom_smbb.c
@@ -880,7 +880,7 @@ static int smbb_charger_probe(struct platform_device *pdev)
}
bat_cfg.drv_data = chg;
- bat_cfg.of_node = pdev->dev.of_node;
+ bat_cfg.fwnode = dev_fwnode(&pdev->dev);
chg->bat_psy = devm_power_supply_register(&pdev->dev,
&bat_psy_desc,
&bat_cfg);
diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c
index e5f35d083c23..945c7720c4ae 100644
--- a/drivers/power/supply/rk817_charger.c
+++ b/drivers/power/supply/rk817_charger.c
@@ -1088,7 +1088,7 @@ static int rk817_charger_probe(struct platform_device *pdev)
rk817_bat_calib_vol(charger);
pscfg.drv_data = charger;
- pscfg.of_node = node;
+ pscfg.fwnode = node ? &node->fwnode : NULL;
/*
* Get sample resistor value. Note only values of 10000 or 20000
diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c
index 7a27b262fb84..b2674adfa30b 100644
--- a/drivers/power/supply/rt5033_battery.c
+++ b/drivers/power/supply/rt5033_battery.c
@@ -160,7 +160,7 @@ static int rt5033_battery_probe(struct i2c_client *client)
}
i2c_set_clientdata(client, battery);
- psy_cfg.of_node = client->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&client->dev);
psy_cfg.drv_data = battery;
battery->psy = devm_power_supply_register(&client->dev,
diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c
index d19c7e80a92a..2fdc58439707 100644
--- a/drivers/power/supply/rt5033_charger.c
+++ b/drivers/power/supply/rt5033_charger.c
@@ -16,6 +16,7 @@
#include <linux/power_supply.h>
#include <linux/regmap.h>
#include <linux/mfd/rt5033-private.h>
+#include <linux/property.h>
struct rt5033_charger_data {
unsigned int pre_uamp;
@@ -675,7 +676,7 @@ static int rt5033_charger_probe(struct platform_device *pdev)
charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
mutex_init(&charger->lock);
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = charger;
charger->psy = devm_power_supply_register(charger->dev,
diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c
index 64a23e3d7bb0..1ffe7f02932f 100644
--- a/drivers/power/supply/rt9455_charger.c
+++ b/drivers/power/supply/rt9455_charger.c
@@ -1579,7 +1579,7 @@ static const struct regmap_config rt9455_regmap_config = {
.writeable_reg = rt9455_is_writeable_reg,
.volatile_reg = rt9455_is_volatile_reg,
.max_register = RT9455_REG_MASK3,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int rt9455_probe(struct i2c_client *client)
@@ -1658,7 +1658,7 @@ static int rt9455_probe(struct i2c_client *client)
INIT_DEFERRABLE_WORK(&info->batt_presence_work,
rt9455_batt_presence_work_callback);
- rt9455_charger_config.of_node = dev->of_node;
+ rt9455_charger_config.fwnode = dev_fwnode(dev);
rt9455_charger_config.drv_data = info;
rt9455_charger_config.supplied_to = rt9455_charger_supplied_to;
rt9455_charger_config.num_supplicants =
diff --git a/drivers/power/supply/rt9467-charger.c b/drivers/power/supply/rt9467-charger.c
index 235169c85c5d..e9aba9ad393c 100644
--- a/drivers/power/supply/rt9467-charger.c
+++ b/drivers/power/supply/rt9467-charger.c
@@ -826,7 +826,7 @@ static int rt9467_register_psy(struct rt9467_chg_data *data)
{
struct power_supply_config cfg = {
.drv_data = data,
- .of_node = dev_of_node(data->dev),
+ .fwnode = dev_fwnode(data->dev),
.attr_grp = rt9467_sysfs_groups,
};
diff --git a/drivers/power/supply/rt9471.c b/drivers/power/supply/rt9471.c
index 67b86ac91a21..bd966abb4df5 100644
--- a/drivers/power/supply/rt9471.c
+++ b/drivers/power/supply/rt9471.c
@@ -723,7 +723,7 @@ static int rt9471_register_psy(struct rt9471_chip *chip)
char *psy_name;
cfg.drv_data = chip;
- cfg.of_node = dev->of_node;
+ cfg.fwnode = dev_fwnode(dev);
cfg.attr_grp = rt9471_sysfs_groups;
psy_name = devm_kasprintf(dev, GFP_KERNEL, "rt9471-%s", dev_name(dev));
diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index a6c204c08232..943c82ee978f 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -21,6 +21,7 @@
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/string_choices.h>
enum {
REG_MANUFACTURER_DATA,
@@ -320,8 +321,8 @@ static int sbs_update_presence(struct sbs_info *chip, bool is_present)
client->flags &= ~I2C_CLIENT_PEC;
}
- dev_dbg(&client->dev, "PEC: %s\n", (client->flags & I2C_CLIENT_PEC) ?
- "enabled" : "disabled");
+ dev_dbg(&client->dev, "PEC: %s\n",
+ str_enabled_disabled(client->flags & I2C_CLIENT_PEC));
if (!chip->is_present && is_present && !chip->charger_broadcasts)
sbs_disable_charger_broadcasts(chip);
@@ -1137,7 +1138,7 @@ static int sbs_probe(struct i2c_client *client)
chip->flags = (uintptr_t)i2c_get_match_data(client);
chip->client = client;
- psy_cfg.of_node = client->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&client->dev);
psy_cfg.drv_data = chip;
chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
sbs_invalidate_cached_props(chip);
diff --git a/drivers/power/supply/sbs-charger.c b/drivers/power/supply/sbs-charger.c
index ab3f095d90ea..27764123b929 100644
--- a/drivers/power/supply/sbs-charger.c
+++ b/drivers/power/supply/sbs-charger.c
@@ -173,7 +173,7 @@ static int sbs_probe(struct i2c_client *client)
return -ENOMEM;
chip->client = client;
- psy_cfg.of_node = client->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&client->dev);
psy_cfg.drv_data = chip;
i2c_set_clientdata(client, chip);
diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c
index 7d2f39f19acb..869729dfcd66 100644
--- a/drivers/power/supply/sbs-manager.c
+++ b/drivers/power/supply/sbs-manager.c
@@ -379,7 +379,7 @@ static int sbsm_probe(struct i2c_client *client)
return ret;
psy_cfg.drv_data = data;
- psy_cfg.of_node = dev->of_node;
+ psy_cfg.fwnode = dev_fwnode(dev);
data->psy = devm_power_supply_register(dev, psy_desc, &psy_cfg);
if (IS_ERR(data->psy))
return dev_err_probe(dev, PTR_ERR(data->psy),
diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c
index 50d5157af927..58b86fd78771 100644
--- a/drivers/power/supply/sc2731_charger.c
+++ b/drivers/power/supply/sc2731_charger.c
@@ -480,7 +480,7 @@ static int sc2731_charger_probe(struct platform_device *pdev)
}
charger_cfg.drv_data = info;
- charger_cfg.of_node = np;
+ charger_cfg.fwnode = dev_fwnode(&pdev->dev);
info->psy_usb = devm_power_supply_register(&pdev->dev,
&sc2731_charger_desc,
&charger_cfg);
diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c
index f36edc2ba708..a7ed9de8a289 100644
--- a/drivers/power/supply/sc27xx_fuel_gauge.c
+++ b/drivers/power/supply/sc27xx_fuel_gauge.c
@@ -1014,9 +1014,8 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data)
if (!table)
return -EINVAL;
- data->cap_table = devm_kmemdup(data->dev, table,
- data->table_len * sizeof(*table),
- GFP_KERNEL);
+ data->cap_table = devm_kmemdup_array(data->dev, table, data->table_len,
+ sizeof(*table), GFP_KERNEL);
if (!data->cap_table) {
power_supply_put_battery_info(data->battery, info);
return -ENOMEM;
@@ -1141,7 +1140,6 @@ disable_fgu:
static int sc27xx_fgu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
struct power_supply_config fgu_cfg = { };
struct sc27xx_fgu_data *data;
int ret, irq;
@@ -1205,7 +1203,7 @@ static int sc27xx_fgu_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
fgu_cfg.drv_data = data;
- fgu_cfg.of_node = np;
+ fgu_cfg.fwnode = dev_fwnode(dev);
data->battery = devm_power_supply_register(dev, &sc27xx_fgu_desc,
&fgu_cfg);
if (IS_ERR(data->battery)) {
diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c
index c8392933ee28..8b95f7e8712f 100644
--- a/drivers/power/supply/smb347-charger.c
+++ b/drivers/power/supply/smb347-charger.c
@@ -1488,7 +1488,7 @@ static const struct regmap_config smb347_regmap = {
.max_register = SMB347_MAX_REGISTER,
.volatile_reg = smb347_volatile_reg,
.readable_reg = smb347_readable_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static const struct regulator_ops smb347_usb_vbus_regulator_ops = {
@@ -1553,7 +1553,7 @@ static int smb347_probe(struct i2c_client *client)
return PTR_ERR(smb->regmap);
mains_usb_cfg.drv_data = smb;
- mains_usb_cfg.of_node = dev->of_node;
+ mains_usb_cfg.fwnode = dev_fwnode(dev);
if (smb->use_mains) {
smb->mains = devm_power_supply_register(dev, &smb347_mains_desc,
&mains_usb_cfg);
diff --git a/drivers/power/supply/stc3117_fuel_gauge.c b/drivers/power/supply/stc3117_fuel_gauge.c
new file mode 100644
index 000000000000..a1bc5970370a
--- /dev/null
+++ b/drivers/power/supply/stc3117_fuel_gauge.c
@@ -0,0 +1,612 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * stc3117_fuel_gauge.c - STMicroelectronics STC3117 Fuel Gauge Driver
+ *
+ * Copyright (c) 2024 Silicon Signals Pvt Ltd.
+ * Author: Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>
+ * Bhavin Sharma <bhavin.sharma@siliconsignals.io>
+ */
+
+#include <linux/crc8.h>
+#include <linux/devm-helpers.h>
+#include <linux/i2c.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+
+#define STC3117_ADDR_MODE 0x00
+#define STC3117_ADDR_CTRL 0x01
+#define STC3117_ADDR_SOC_L 0x02
+#define STC3117_ADDR_SOC_H 0x03
+#define STC3117_ADDR_COUNTER_L 0x04
+#define STC3117_ADDR_COUNTER_H 0x05
+#define STC3117_ADDR_CURRENT_L 0x06
+#define STC3117_ADDR_CURRENT_H 0x07
+#define STC3117_ADDR_VOLTAGE_L 0x08
+#define STC3117_ADDR_VOLTAGE_H 0x09
+#define STC3117_ADDR_TEMPERATURE 0x0A
+#define STC3117_ADDR_AVG_CURRENT_L 0x0B
+#define STC3117_ADDR_AVG_CURRENT_H 0x0C
+#define STC3117_ADDR_OCV_L 0x0D
+#define STC3117_ADDR_OCV_H 0x0E
+#define STC3117_ADDR_CC_CNF_L 0x0F
+#define STC3117_ADDR_CC_CNF_H 0x10
+#define STC3117_ADDR_VM_CNF_L 0x11
+#define STC3117_ADDR_VM_CNF_H 0x12
+#define STC3117_ADDR_ALARM_soc 0x13
+#define STC3117_ADDR_ALARM_VOLTAGE 0x14
+#define STC3117_ADDR_ID 0x18
+#define STC3117_ADDR_CC_ADJ_L 0x1B
+#define STC3117_ADDR_CC_ADJ_H 0x1C
+#define STC3117_ADDR_VM_ADJ_L 0x1D
+#define STC3117_ADDR_VM_ADJ_H 0x1E
+#define STC3117_ADDR_RAM 0x20
+#define STC3117_ADDR_OCV_TABLE 0x30
+#define STC3117_ADDR_SOC_TABLE 0x30
+
+/* Bit mask definition */
+#define STC3117_ID 0x16
+#define STC3117_MIXED_MODE 0x00
+#define STC3117_VMODE BIT(0)
+#define STC3117_GG_RUN BIT(4)
+#define STC3117_CC_MODE BIT(5)
+#define STC3117_BATFAIL BIT(3)
+#define STC3117_PORDET BIT(4)
+#define STC3117_RAM_SIZE 16
+#define STC3117_OCV_TABLE_SIZE 16
+#define STC3117_RAM_TESTWORD 0x53A9
+#define STC3117_SOFT_RESET 0x11
+#define STC3117_NOMINAL_CAPACITY 2600
+
+#define VOLTAGE_LSB_VALUE 9011
+#define CURRENT_LSB_VALUE 24084
+#define APP_CUTOFF_VOLTAGE 2500
+#define MAX_HRSOC 51200
+#define MAX_SOC 1000
+#define CHG_MIN_CURRENT 200
+#define CHG_END_CURRENT 20
+#define APP_MIN_CURRENT (-5)
+#define BATTERY_FULL 95
+#define CRC8_POLYNOMIAL 0x07
+#define CRC8_INIT 0x00
+
+DECLARE_CRC8_TABLE(stc3117_crc_table);
+
+enum stc3117_state {
+ STC3117_INIT,
+ STC3117_RUNNING,
+ STC3117_POWERDN,
+};
+
+/* Default ocv curve Li-ion battery */
+static const int ocv_value[16] = {
+ 3400, 3582, 3669, 3676, 3699, 3737, 3757, 3774,
+ 3804, 3844, 3936, 3984, 4028, 4131, 4246, 4320
+};
+
+union stc3117_internal_ram {
+ u8 ram_bytes[STC3117_RAM_SIZE];
+ struct {
+ u16 testword; /* 0-1 Bytes */
+ u16 hrsoc; /* 2-3 Bytes */
+ u16 cc_cnf; /* 4-5 Bytes */
+ u16 vm_cnf; /* 6-7 Bytes */
+ u8 soc; /* 8 Byte */
+ u8 state; /* 9 Byte */
+ u8 unused[5]; /* 10-14 Bytes */
+ u8 crc; /* 15 Byte */
+ } reg;
+};
+
+struct stc3117_battery_info {
+ int voltage_min_mv;
+ int voltage_max_mv;
+ int battery_capacity_mah;
+ int sense_resistor;
+};
+
+struct stc3117_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct delayed_work update_work;
+ struct power_supply *battery;
+ union stc3117_internal_ram ram_data;
+ struct stc3117_battery_info battery_info;
+
+ u8 soc_tab[16];
+ int cc_cnf;
+ int vm_cnf;
+ int cc_adj;
+ int vm_adj;
+ int avg_current;
+ int avg_voltage;
+ int batt_current;
+ int voltage;
+ int temp;
+ int soc;
+ int ocv;
+ int hrsoc;
+ int presence;
+};
+
+static int stc3117_convert(int value, int factor)
+{
+ value = (value * factor) / 4096;
+ return value * 1000;
+}
+
+static int stc3117_get_battery_data(struct stc3117_data *data)
+{
+ u8 reg_list[16];
+ u8 data_adjust[4];
+ int value, mode;
+
+ regmap_bulk_read(data->regmap, STC3117_ADDR_MODE,
+ reg_list, sizeof(reg_list));
+
+ /* soc */
+ value = (reg_list[3] << 8) + reg_list[2];
+ data->hrsoc = value;
+ data->soc = (value * 10 + 256) / 512;
+
+ /* current in uA*/
+ value = (reg_list[7] << 8) + reg_list[6];
+ data->batt_current = stc3117_convert(value,
+ CURRENT_LSB_VALUE / data->battery_info.sense_resistor);
+
+ /* voltage in uV */
+ value = (reg_list[9] << 8) + reg_list[8];
+ data->voltage = stc3117_convert(value, VOLTAGE_LSB_VALUE);
+
+ /* temp in 1/10 °C */
+ data->temp = reg_list[10] * 10;
+
+ /* Avg current in uA */
+ value = (reg_list[12] << 8) + reg_list[11];
+ regmap_read(data->regmap, STC3117_ADDR_MODE, &mode);
+ if (!(mode & STC3117_VMODE)) {
+ value = stc3117_convert(value,
+ CURRENT_LSB_VALUE / data->battery_info.sense_resistor);
+ value = value / 4;
+ } else {
+ value = stc3117_convert(value, 36 * STC3117_NOMINAL_CAPACITY);
+ }
+ data->avg_current = value;
+
+ /* ocv in uV */
+ value = (reg_list[14] << 8) + reg_list[13];
+ value = stc3117_convert(value, VOLTAGE_LSB_VALUE);
+ value = (value + 2) / 4;
+ data->ocv = value;
+
+ /* CC & VM adjustment counters */
+ regmap_bulk_read(data->regmap, STC3117_ADDR_CC_ADJ_L,
+ data_adjust, sizeof(data_adjust));
+ value = (data_adjust[1] << 8) + data_adjust[0];
+ data->cc_adj = value;
+
+ value = (data_adjust[3] << 8) + data_adjust[2];
+ data->vm_adj = value;
+
+ return 0;
+}
+
+static int ram_write(struct stc3117_data *data)
+{
+ int ret;
+
+ ret = regmap_bulk_write(data->regmap, STC3117_ADDR_RAM,
+ data->ram_data.ram_bytes, STC3117_RAM_SIZE);
+ if (ret)
+ return ret;
+
+ return 0;
+};
+
+static int ram_read(struct stc3117_data *data)
+{
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, STC3117_ADDR_RAM,
+ data->ram_data.ram_bytes, STC3117_RAM_SIZE);
+ if (ret)
+ return ret;
+
+ return 0;
+};
+
+static int stc3117_set_para(struct stc3117_data *data)
+{
+ int ret;
+
+ ret = regmap_write(data->regmap, STC3117_ADDR_MODE, STC3117_VMODE);
+
+ for (int i = 0; i < STC3117_OCV_TABLE_SIZE; i++)
+ ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_TABLE + i,
+ ocv_value[i] * 100 / 55);
+ if (data->soc_tab[1] != 0)
+ ret |= regmap_bulk_write(data->regmap, STC3117_ADDR_SOC_TABLE,
+ data->soc_tab, STC3117_OCV_TABLE_SIZE);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_CC_CNF_H,
+ (data->ram_data.reg.cc_cnf >> 8) & 0xFF);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_CC_CNF_L,
+ data->ram_data.reg.cc_cnf & 0xFF);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_VM_CNF_H,
+ (data->ram_data.reg.vm_cnf >> 8) & 0xFF);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_VM_CNF_L,
+ data->ram_data.reg.vm_cnf & 0xFF);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_CTRL, 0x03);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_MODE,
+ STC3117_MIXED_MODE | STC3117_GG_RUN);
+
+ return ret;
+};
+
+static int stc3117_init(struct stc3117_data *data)
+{
+ int id, ret;
+ int ctrl;
+ int ocv_m, ocv_l;
+
+ regmap_read(data->regmap, STC3117_ADDR_ID, &id);
+ if (id != STC3117_ID)
+ return -EINVAL;
+
+ data->cc_cnf = (data->battery_info.battery_capacity_mah *
+ data->battery_info.sense_resistor * 250 + 6194) / 12389;
+ data->vm_cnf = (data->battery_info.battery_capacity_mah
+ * 200 * 50 + 24444) / 48889;
+
+ /* Battery has not been removed */
+ data->presence = 1;
+
+ /* Read RAM data */
+ ret = ram_read(data);
+ if (ret)
+ return ret;
+
+ if (data->ram_data.reg.testword != STC3117_RAM_TESTWORD ||
+ (crc8(stc3117_crc_table, data->ram_data.ram_bytes,
+ STC3117_RAM_SIZE, CRC8_INIT)) != 0) {
+ data->ram_data.reg.testword = STC3117_RAM_TESTWORD;
+ data->ram_data.reg.cc_cnf = data->cc_cnf;
+ data->ram_data.reg.vm_cnf = data->vm_cnf;
+ data->ram_data.reg.crc = crc8(stc3117_crc_table,
+ data->ram_data.ram_bytes,
+ STC3117_RAM_SIZE - 1, CRC8_INIT);
+
+ ret = regmap_read(data->regmap, STC3117_ADDR_OCV_H, &ocv_m);
+
+ ret |= regmap_read(data->regmap, STC3117_ADDR_OCV_L, &ocv_l);
+
+ ret |= stc3117_set_para(data);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_H, ocv_m);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_L, ocv_l);
+ if (ret)
+ return ret;
+ } else {
+ ret = regmap_read(data->regmap, STC3117_ADDR_CTRL, &ctrl);
+ if (ret)
+ return ret;
+
+ if ((ctrl & STC3117_BATFAIL) != 0 ||
+ (ctrl & STC3117_PORDET) != 0) {
+ ret = regmap_read(data->regmap,
+ STC3117_ADDR_OCV_H, &ocv_m);
+
+ ret |= regmap_read(data->regmap,
+ STC3117_ADDR_OCV_L, &ocv_l);
+
+ ret |= stc3117_set_para(data);
+
+ ret |= regmap_write(data->regmap,
+ STC3117_ADDR_OCV_H, ocv_m);
+
+ ret |= regmap_write(data->regmap,
+ STC3117_ADDR_OCV_L, ocv_l);
+ if (ret)
+ return ret;
+ } else {
+ ret = stc3117_set_para(data);
+ ret |= regmap_write(data->regmap, STC3117_ADDR_SOC_H,
+ (data->ram_data.reg.hrsoc >> 8 & 0xFF));
+ ret |= regmap_write(data->regmap, STC3117_ADDR_SOC_L,
+ (data->ram_data.reg.hrsoc & 0xFF));
+ if (ret)
+ return ret;
+ }
+ }
+
+ data->ram_data.reg.state = STC3117_INIT;
+ data->ram_data.reg.crc = crc8(stc3117_crc_table,
+ data->ram_data.ram_bytes,
+ STC3117_RAM_SIZE - 1, CRC8_INIT);
+ ret = ram_write(data);
+ if (ret)
+ return ret;
+
+ return 0;
+};
+
+static int stc3117_task(struct stc3117_data *data)
+{
+ int id, mode, ret;
+ int count_l, count_m;
+ int ocv_l, ocv_m;
+
+ regmap_read(data->regmap, STC3117_ADDR_ID, &id);
+ if (id != STC3117_ID) {
+ data->presence = 0;
+ return -EINVAL;
+ }
+
+ stc3117_get_battery_data(data);
+
+ /* Read RAM data */
+ ret = ram_read(data);
+ if (ret)
+ return ret;
+
+ if (data->ram_data.reg.testword != STC3117_RAM_TESTWORD ||
+ (crc8(stc3117_crc_table, data->ram_data.ram_bytes,
+ STC3117_RAM_SIZE, CRC8_INIT) != 0)) {
+ data->ram_data.reg.testword = STC3117_RAM_TESTWORD;
+ data->ram_data.reg.cc_cnf = data->cc_cnf;
+ data->ram_data.reg.vm_cnf = data->vm_cnf;
+ data->ram_data.reg.crc = crc8(stc3117_crc_table,
+ data->ram_data.ram_bytes,
+ STC3117_RAM_SIZE - 1, CRC8_INIT);
+ data->ram_data.reg.state = STC3117_INIT;
+ }
+
+ /* check battery presence status */
+ ret = regmap_read(data->regmap, STC3117_ADDR_CTRL, &mode);
+ if ((mode & STC3117_BATFAIL) != 0) {
+ data->presence = 0;
+ data->ram_data.reg.testword = 0;
+ data->ram_data.reg.state = STC3117_INIT;
+ ret = ram_write(data);
+ ret |= regmap_write(data->regmap, STC3117_ADDR_CTRL, STC3117_PORDET);
+ if (ret)
+ return ret;
+ }
+
+ data->presence = 1;
+
+ ret = regmap_read(data->regmap, STC3117_ADDR_MODE, &mode);
+ if (ret)
+ return ret;
+ if ((mode & STC3117_GG_RUN) == 0) {
+ if (data->ram_data.reg.state > STC3117_INIT) {
+ ret = stc3117_set_para(data);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_SOC_H,
+ (data->ram_data.reg.hrsoc >> 8 & 0xFF));
+ ret |= regmap_write(data->regmap, STC3117_ADDR_SOC_L,
+ (data->ram_data.reg.hrsoc & 0xFF));
+ if (ret)
+ return ret;
+ } else {
+ ret = regmap_read(data->regmap, STC3117_ADDR_OCV_H, &ocv_m);
+
+ ret |= regmap_read(data->regmap, STC3117_ADDR_OCV_L, &ocv_l);
+
+ ret |= stc3117_set_para(data);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_H, ocv_m);
+
+ ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_L, ocv_l);
+ if (ret)
+ return ret;
+ }
+ data->ram_data.reg.state = STC3117_INIT;
+ }
+
+ regmap_read(data->regmap, STC3117_ADDR_COUNTER_L, &count_l);
+ regmap_read(data->regmap, STC3117_ADDR_COUNTER_H, &count_m);
+
+ count_m = (count_m << 8) + count_l;
+
+ /* INIT state, wait for batt_current & temperature value available: */
+ if (data->ram_data.reg.state == STC3117_INIT && count_m > 4) {
+ data->avg_voltage = data->voltage;
+ data->avg_current = data->batt_current;
+ data->ram_data.reg.state = STC3117_RUNNING;
+ }
+
+ if (data->ram_data.reg.state != STC3117_RUNNING) {
+ data->batt_current = -ENODATA;
+ data->temp = -ENODATA;
+ } else {
+ if (data->voltage < APP_CUTOFF_VOLTAGE)
+ data->soc = -ENODATA;
+
+ if (mode & STC3117_VMODE) {
+ data->avg_current = -ENODATA;
+ data->batt_current = -ENODATA;
+ }
+ }
+
+ data->ram_data.reg.hrsoc = data->hrsoc;
+ data->ram_data.reg.soc = (data->soc + 5) / 10;
+ data->ram_data.reg.crc = crc8(stc3117_crc_table,
+ data->ram_data.ram_bytes,
+ STC3117_RAM_SIZE - 1, CRC8_INIT);
+
+ ret = ram_write(data);
+ if (ret)
+ return ret;
+ return 0;
+};
+
+static void fuel_gauge_update_work(struct work_struct *work)
+{
+ struct stc3117_data *data =
+ container_of(work, struct stc3117_data, update_work.work);
+
+ stc3117_task(data);
+
+ /* Schedule the work to run again in 2 seconds */
+ schedule_delayed_work(&data->update_work, msecs_to_jiffies(2000));
+}
+
+static int stc3117_get_property(struct power_supply *psy,
+ enum power_supply_property psp, union power_supply_propval *val)
+{
+ struct stc3117_data *data = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ if (data->soc > BATTERY_FULL)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else if (data->batt_current < 0)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else if (data->batt_current > 0)
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = data->voltage;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = data->batt_current;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+ val->intval = data->ocv;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ val->intval = data->avg_current;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = data->soc;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = data->temp;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = data->presence;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static enum power_supply_property stc3117_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_OCV,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_PRESENT,
+};
+
+static const struct power_supply_desc stc3117_battery_desc = {
+ .name = "stc3117-battery",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .get_property = stc3117_get_property,
+ .properties = stc3117_battery_props,
+ .num_properties = ARRAY_SIZE(stc3117_battery_props),
+};
+
+static const struct regmap_config stc3117_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int stc3117_probe(struct i2c_client *client)
+{
+ struct stc3117_data *data;
+ struct power_supply_config psy_cfg = {};
+ struct power_supply_battery_info *info;
+ int ret;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->client = client;
+ data->regmap = devm_regmap_init_i2c(client, &stc3117_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
+ psy_cfg.drv_data = data;
+ psy_cfg.fwnode = dev_fwnode(&client->dev);
+
+ crc8_populate_msb(stc3117_crc_table, CRC8_POLYNOMIAL);
+
+ data->battery = devm_power_supply_register(&client->dev,
+ &stc3117_battery_desc, &psy_cfg);
+ if (IS_ERR(data->battery))
+ return dev_err_probe(&client->dev, PTR_ERR(data->battery),
+ "failed to register battery\n");
+
+ ret = device_property_read_u32(&client->dev, "shunt-resistor-micro-ohms",
+ &data->battery_info.sense_resistor);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "failed to get shunt-resistor-micro-ohms\n");
+ data->battery_info.sense_resistor = data->battery_info.sense_resistor / 1000;
+
+ ret = power_supply_get_battery_info(data->battery, &info);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "failed to get battery information\n");
+
+ data->battery_info.battery_capacity_mah = info->charge_full_design_uah / 1000;
+ data->battery_info.voltage_min_mv = info->voltage_min_design_uv / 1000;
+ data->battery_info.voltage_max_mv = info->voltage_max_design_uv / 1000;
+
+ ret = stc3117_init(data);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "failed to initialize of stc3117\n");
+
+ ret = devm_delayed_work_autocancel(&client->dev, &data->update_work,
+ fuel_gauge_update_work);
+ if (ret)
+ return ret;
+
+ schedule_delayed_work(&data->update_work, 0);
+
+ return 0;
+}
+
+static const struct i2c_device_id stc3117_id[] = {
+ { "stc3117", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, stc3117_id);
+
+static const struct of_device_id stc3117_of_match[] = {
+ { .compatible = "st,stc3117" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, stc3117_of_match);
+
+static struct i2c_driver stc3117_i2c_driver = {
+ .driver = {
+ .name = "stc3117_i2c_driver",
+ .of_match_table = stc3117_of_match,
+ },
+ .probe = stc3117_probe,
+ .id_table = stc3117_id,
+};
+
+module_i2c_driver(stc3117_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>");
+MODULE_AUTHOR("Bhavin Sharma <bhavin.sharma@siliconsignals.io>");
+MODULE_DESCRIPTION("STC3117 Fuel Gauge Driver");
diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c
index ebd1edde28f1..c759add4df49 100644
--- a/drivers/power/supply/surface_battery.c
+++ b/drivers/power/supply/surface_battery.c
@@ -667,7 +667,7 @@ out:
static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
int status;
@@ -681,7 +681,7 @@ static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, cha
static ssize_t alarm_store(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
- struct power_supply *psy = dev_get_drvdata(dev);
+ struct power_supply *psy = dev_to_psy(dev);
struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
unsigned long value;
int status;
diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_power.c
index 442ceb7795e1..2a975a110f48 100644
--- a/drivers/power/supply/test_power.c
+++ b/drivers/power/supply/test_power.c
@@ -37,6 +37,7 @@ static int battery_charge_counter = -1000;
static int battery_current = -1600;
static enum power_supply_charge_behaviour battery_charge_behaviour =
POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
+static bool battery_extension;
static bool module_initialized;
@@ -238,6 +239,87 @@ static const struct power_supply_config test_power_configs[] = {
},
};
+static int test_power_battery_extmanufacture_year = 1234;
+static int test_power_battery_exttemp_max = 1000;
+static const enum power_supply_property test_power_battery_extprops[] = {
+ POWER_SUPPLY_PROP_MANUFACTURE_YEAR,
+ POWER_SUPPLY_PROP_TEMP_MAX,
+};
+
+static int test_power_battery_extget_property(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
+ val->intval = test_power_battery_extmanufacture_year;
+ break;
+ case POWER_SUPPLY_PROP_TEMP_MAX:
+ val->intval = test_power_battery_exttemp_max;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int test_power_battery_extset_property(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
+ test_power_battery_extmanufacture_year = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_TEMP_MAX:
+ test_power_battery_exttemp_max = val->intval;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int test_power_battery_extproperty_is_writeable(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *ext_data,
+ enum power_supply_property psp)
+{
+ return true;
+}
+
+static const struct power_supply_ext test_power_battery_ext = {
+ .name = "test_power",
+ .properties = test_power_battery_extprops,
+ .num_properties = ARRAY_SIZE(test_power_battery_extprops),
+ .get_property = test_power_battery_extget_property,
+ .set_property = test_power_battery_extset_property,
+ .property_is_writeable = test_power_battery_extproperty_is_writeable,
+};
+
+static void test_power_configure_battery_extension(bool enable)
+{
+ struct power_supply *psy;
+
+ psy = test_power_supplies[TEST_BATTERY];
+
+ if (enable) {
+ if (power_supply_register_extension(psy, &test_power_battery_ext, &psy->dev,
+ NULL)) {
+ pr_err("registering battery extension failed\n");
+ return;
+ }
+ } else {
+ power_supply_unregister_extension(psy, &test_power_battery_ext);
+ }
+
+ battery_extension = enable;
+}
+
static int __init test_power_init(void)
{
int i;
@@ -258,6 +340,8 @@ static int __init test_power_init(void)
}
}
+ test_power_configure_battery_extension(true);
+
module_initialized = true;
return 0;
failed:
@@ -524,6 +608,26 @@ static int param_set_battery_current(const char *key,
#define param_get_battery_current param_get_int
+static int param_set_battery_extension(const char *key,
+ const struct kernel_param *kp)
+{
+ bool prev_battery_extension;
+ int ret;
+
+ prev_battery_extension = battery_extension;
+
+ ret = param_set_bool(key, kp);
+ if (ret)
+ return ret;
+
+ if (prev_battery_extension != battery_extension)
+ test_power_configure_battery_extension(battery_extension);
+
+ return 0;
+}
+
+#define param_get_battery_extension param_get_bool
+
static const struct kernel_param_ops param_ops_ac_online = {
.set = param_set_ac_online,
.get = param_get_ac_online,
@@ -574,6 +678,11 @@ static const struct kernel_param_ops param_ops_battery_current = {
.get = param_get_battery_current,
};
+static const struct kernel_param_ops param_ops_battery_extension = {
+ .set = param_set_battery_extension,
+ .get = param_get_battery_extension,
+};
+
#define param_check_ac_online(name, p) __param_check(name, p, void);
#define param_check_usb_online(name, p) __param_check(name, p, void);
#define param_check_battery_status(name, p) __param_check(name, p, void);
@@ -584,6 +693,7 @@ static const struct kernel_param_ops param_ops_battery_current = {
#define param_check_battery_voltage(name, p) __param_check(name, p, void);
#define param_check_battery_charge_counter(name, p) __param_check(name, p, void);
#define param_check_battery_current(name, p) __param_check(name, p, void);
+#define param_check_battery_extension(name, p) __param_check(name, p, void);
module_param(ac_online, ac_online, 0644);
@@ -621,6 +731,9 @@ MODULE_PARM_DESC(battery_charge_counter,
module_param(battery_current, battery_current, 0644);
MODULE_PARM_DESC(battery_current, "battery current (milliampere)");
+module_param(battery_extension, battery_extension, 0644);
+MODULE_PARM_DESC(battery_extension, "battery extension");
+
MODULE_DESCRIPTION("Power supply driver for testing");
MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/tps65090-charger.c b/drivers/power/supply/tps65090-charger.c
index d65193e410a6..d010f013af8c 100644
--- a/drivers/power/supply/tps65090-charger.c
+++ b/drivers/power/supply/tps65090-charger.c
@@ -259,7 +259,7 @@ static int tps65090_charger_probe(struct platform_device *pdev)
psy_cfg.supplied_to = pdata->supplied_to;
psy_cfg.num_supplicants = pdata->num_supplicants;
- psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.fwnode = dev_fwnode(&pdev->dev);
psy_cfg.drv_data = cdata;
cdata->ac = devm_power_supply_register(&pdev->dev, &tps65090_charger_desc,
diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c
index 6fff44e1ecac..6af17ce0b204 100644
--- a/drivers/power/supply/tps65217_charger.c
+++ b/drivers/power/supply/tps65217_charger.c
@@ -198,7 +198,7 @@ static int tps65217_charger_probe(struct platform_device *pdev)
charger->tps = tps;
charger->dev = &pdev->dev;
- cfg.of_node = pdev->dev.of_node;
+ cfg.fwnode = dev_fwnode(&pdev->dev);
cfg.drv_data = charger;
charger->psy = devm_power_supply_register(&pdev->dev,
diff --git a/drivers/power/supply/ucs1002_power.c b/drivers/power/supply/ucs1002_power.c
index 7382bec6a43c..d32a7633f9e7 100644
--- a/drivers/power/supply/ucs1002_power.c
+++ b/drivers/power/supply/ucs1002_power.c
@@ -560,7 +560,7 @@ static int ucs1002_probe(struct i2c_client *client)
irq_a_det = of_irq_get_byname(dev->of_node, "a_det");
irq_alert = of_irq_get_byname(dev->of_node, "alert");
- charger_config.of_node = dev->of_node;
+ charger_config.fwnode = dev_fwnode(dev);
charger_config.drv_data = info;
ret = regmap_read(info->regmap, UCS1002_REG_PRODUCT_ID, &regval);
diff --git a/drivers/power/supply/ug3105_battery.c b/drivers/power/supply/ug3105_battery.c
index ccc5c4d2e230..38e23bdd4603 100644
--- a/drivers/power/supply/ug3105_battery.c
+++ b/drivers/power/supply/ug3105_battery.c
@@ -287,7 +287,6 @@ out:
static enum power_supply_property ug3105_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
- POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_OCV,
@@ -316,9 +315,6 @@ static int ug3105_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 1;
break;
- case POWER_SUPPLY_PROP_TECHNOLOGY:
- val->intval = chip->info->technology;
- break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
break;