summaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 17:39:57 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 17:39:57 +0000
commitdc50eab76b709d68175a358d6e23a5a3890764d3 (patch)
treec754d0390db060af0213ff994f0ac310e4cfd6e9 /drivers/power
parentAdding debian version 6.6.15-2. (diff)
downloadlinux-dc50eab76b709d68175a358d6e23a5a3890764d3.tar.xz
linux-dc50eab76b709d68175a358d6e23a5a3890764d3.zip
Merging upstream version 6.7.7.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/reset/Kconfig2
-rw-r--r--drivers/power/reset/axxia-reset.c7
-rw-r--r--drivers/power/reset/gpio-poweroff.c82
-rw-r--r--drivers/power/reset/msm-poweroff.c7
-rw-r--r--drivers/power/reset/nvmem-reboot-mode.c4
-rw-r--r--drivers/power/reset/st-poweroff.c7
-rw-r--r--drivers/power/reset/syscon-poweroff.c29
-rw-r--r--drivers/power/reset/vexpress-poweroff.c11
-rw-r--r--drivers/power/reset/xgene-reboot.c7
-rw-r--r--drivers/power/supply/88pm860x_battery.c8
-rw-r--r--drivers/power/supply/Kconfig34
-rw-r--r--drivers/power/supply/Makefile3
-rw-r--r--drivers/power/supply/ab8500_btemp.c6
-rw-r--r--drivers/power/supply/ab8500_chargalg.c6
-rw-r--r--drivers/power/supply/ab8500_charger.c6
-rw-r--r--drivers/power/supply/ab8500_fg.c6
-rw-r--r--drivers/power/supply/acer_a500_battery.c6
-rw-r--r--drivers/power/supply/act8945a_charger.c6
-rw-r--r--drivers/power/supply/axp20x_ac_power.c2
-rw-r--r--drivers/power/supply/axp20x_usb_power.c2
-rw-r--r--drivers/power/supply/bq24190_charger.c2
-rw-r--r--drivers/power/supply/bq24257_charger.c76
-rw-r--r--drivers/power/supply/bq2515x_charger.c67
-rw-r--r--drivers/power/supply/bq256xx_charger.c52
-rw-r--r--drivers/power/supply/bq25980_charger.c2
-rw-r--r--drivers/power/supply/charger-manager.c12
-rw-r--r--drivers/power/supply/cpcap-battery.c6
-rw-r--r--drivers/power/supply/cpcap-charger.c19
-rw-r--r--drivers/power/supply/da9030_battery.c6
-rw-r--r--drivers/power/supply/da9052-battery.c6
-rw-r--r--drivers/power/supply/da9150-charger.c6
-rw-r--r--drivers/power/supply/goldfish_battery.c5
-rw-r--r--drivers/power/supply/ipaq_micro_battery.c6
-rw-r--r--drivers/power/supply/isp1704_charger.c6
-rw-r--r--drivers/power/supply/lp8788-charger.c6
-rw-r--r--drivers/power/supply/max14577_charger.c6
-rw-r--r--drivers/power/supply/max17040_battery.c27
-rw-r--r--drivers/power/supply/max17042_battery.c6
-rw-r--r--drivers/power/supply/max77650-charger.c6
-rw-r--r--drivers/power/supply/max77693_charger.c6
-rw-r--r--drivers/power/supply/max8925_power.c5
-rw-r--r--drivers/power/supply/mm8013.c317
-rw-r--r--drivers/power/supply/mt6370-charger.c4
-rw-r--r--drivers/power/supply/pcf50633-charger.c6
-rw-r--r--drivers/power/supply/pm8916_bms_vm.c305
-rw-r--r--drivers/power/supply/pm8916_lbc.c381
-rw-r--r--drivers/power/supply/power_supply_core.c4
-rw-r--r--drivers/power/supply/power_supply_sysfs.c12
-rw-r--r--drivers/power/supply/qcom_pmi8998_charger.c3
-rw-r--r--drivers/power/supply/qcom_smbb.c6
-rw-r--r--drivers/power/supply/rk817_charger.c13
-rw-r--r--drivers/power/supply/rt5033_charger.c320
-rw-r--r--drivers/power/supply/rx51_battery.c6
-rw-r--r--drivers/power/supply/sbs-battery.c8
-rw-r--r--drivers/power/supply/sc2731_charger.c6
-rw-r--r--drivers/power/supply/surface_battery.c2
-rw-r--r--drivers/power/supply/surface_charger.c2
-rw-r--r--drivers/power/supply/tps65090-charger.c6
-rw-r--r--drivers/power/supply/tps65217_charger.c8
-rw-r--r--drivers/power/supply/twl4030_charger.c6
-rw-r--r--drivers/power/supply/twl4030_madc_battery.c6
-rw-r--r--drivers/power/supply/wm831x_backup.c6
-rw-r--r--drivers/power/supply/wm831x_power.c5
-rw-r--r--drivers/power/supply/wm8350_power.c5
-rw-r--r--drivers/power/supply/wm97xx_battery.c5
65 files changed, 1638 insertions, 378 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 411e00b25..fece990af 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -66,7 +66,7 @@ config POWER_RESET_BRCMKONA
config POWER_RESET_BRCMSTB
bool "Broadcom STB reset driver"
- depends on ARM || ARM64 || MIPS || COMPILE_TEST
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
depends on MFD_SYSCON
default ARCH_BRCMSTB || BMIPS_GENERIC
help
diff --git a/drivers/power/reset/axxia-reset.c b/drivers/power/reset/axxia-reset.c
index f7b40be5d..249467667 100644
--- a/drivers/power/reset/axxia-reset.c
+++ b/drivers/power/reset/axxia-reset.c
@@ -80,9 +80,4 @@ static struct platform_driver axxia_reset_driver = {
.of_match_table = of_match_ptr(of_axxia_reset_match),
},
};
-
-static int __init axxia_reset_init(void)
-{
- return platform_driver_register(&axxia_reset_driver);
-}
-device_initcall(axxia_reset_init);
+builtin_platform_driver(axxia_reset_driver);
diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c
index b28f24da1..52cfeee2c 100644
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -15,50 +15,51 @@
#include <linux/gpio/consumer.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/reboot.h>
#define DEFAULT_TIMEOUT_MS 3000
-/*
- * Hold configuration here, cannot be more than one instance of the driver
- * since pm_power_off itself is global.
- */
-static struct gpio_desc *reset_gpio;
-static u32 timeout = DEFAULT_TIMEOUT_MS;
-static u32 active_delay = 100;
-static u32 inactive_delay = 100;
-static void gpio_poweroff_do_poweroff(void)
+struct gpio_poweroff {
+ struct gpio_desc *reset_gpio;
+ u32 timeout_ms;
+ u32 active_delay_ms;
+ u32 inactive_delay_ms;
+};
+
+static int gpio_poweroff_do_poweroff(struct sys_off_data *data)
{
- BUG_ON(!reset_gpio);
+ struct gpio_poweroff *gpio_poweroff = data->cb_data;
/* drive it active, also inactive->active edge */
- gpiod_direction_output(reset_gpio, 1);
- mdelay(active_delay);
+ gpiod_direction_output(gpio_poweroff->reset_gpio, 1);
+ mdelay(gpio_poweroff->active_delay_ms);
/* drive inactive, also active->inactive edge */
- gpiod_set_value_cansleep(reset_gpio, 0);
- mdelay(inactive_delay);
+ gpiod_set_value_cansleep(gpio_poweroff->reset_gpio, 0);
+ mdelay(gpio_poweroff->inactive_delay_ms);
/* drive it active, also inactive->active edge */
- gpiod_set_value_cansleep(reset_gpio, 1);
+ gpiod_set_value_cansleep(gpio_poweroff->reset_gpio, 1);
/* give it some time */
- mdelay(timeout);
+ mdelay(gpio_poweroff->timeout_ms);
WARN_ON(1);
+
+ return NOTIFY_DONE;
}
static int gpio_poweroff_probe(struct platform_device *pdev)
{
+ struct gpio_poweroff *gpio_poweroff;
bool input = false;
enum gpiod_flags flags;
+ int priority = SYS_OFF_PRIO_DEFAULT;
+ int ret;
- /* If a pm_power_off function has already been added, leave it alone */
- if (pm_power_off != NULL) {
- dev_err(&pdev->dev,
- "%s: pm_power_off function already registered\n",
- __func__);
- return -EBUSY;
- }
+ gpio_poweroff = devm_kzalloc(&pdev->dev, sizeof(*gpio_poweroff), GFP_KERNEL);
+ if (!gpio_poweroff)
+ return -ENOMEM;
input = device_property_read_bool(&pdev->dev, "input");
if (input)
@@ -66,23 +67,29 @@ static int gpio_poweroff_probe(struct platform_device *pdev)
else
flags = GPIOD_OUT_LOW;
- device_property_read_u32(&pdev->dev, "active-delay-ms", &active_delay);
- device_property_read_u32(&pdev->dev, "inactive-delay-ms",
- &inactive_delay);
- device_property_read_u32(&pdev->dev, "timeout-ms", &timeout);
- reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);
- if (IS_ERR(reset_gpio))
- return PTR_ERR(reset_gpio);
+ gpio_poweroff->active_delay_ms = 100;
+ gpio_poweroff->inactive_delay_ms = 100;
+ gpio_poweroff->timeout_ms = DEFAULT_TIMEOUT_MS;
- pm_power_off = &gpio_poweroff_do_poweroff;
- return 0;
-}
+ device_property_read_u32(&pdev->dev, "active-delay-ms", &gpio_poweroff->active_delay_ms);
+ device_property_read_u32(&pdev->dev, "inactive-delay-ms",
+ &gpio_poweroff->inactive_delay_ms);
+ device_property_read_u32(&pdev->dev, "timeout-ms", &gpio_poweroff->timeout_ms);
+ device_property_read_u32(&pdev->dev, "priority", &priority);
+ if (priority > 255) {
+ dev_err(&pdev->dev, "Invalid priority property: %u\n", priority);
+ return -EINVAL;
+ }
-static int gpio_poweroff_remove(struct platform_device *pdev)
-{
- if (pm_power_off == &gpio_poweroff_do_poweroff)
- pm_power_off = NULL;
+ gpio_poweroff->reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);
+ if (IS_ERR(gpio_poweroff->reset_gpio))
+ return PTR_ERR(gpio_poweroff->reset_gpio);
+
+ ret = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_POWER_OFF,
+ priority, gpio_poweroff_do_poweroff, gpio_poweroff);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Cannot register poweroff handler\n");
return 0;
}
@@ -95,7 +102,6 @@ MODULE_DEVICE_TABLE(of, of_gpio_poweroff_match);
static struct platform_driver gpio_poweroff_driver = {
.probe = gpio_poweroff_probe,
- .remove = gpio_poweroff_remove,
.driver = {
.name = "poweroff-gpio",
.of_match_table = of_gpio_poweroff_match,
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index b9a401bd2..d96d248a6 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -59,9 +59,4 @@ static struct platform_driver msm_restart_driver = {
.of_match_table = of_match_ptr(of_msm_restart_match),
},
};
-
-static int __init msm_restart_init(void)
-{
- return platform_driver_register(&msm_restart_driver);
-}
-device_initcall(msm_restart_init);
+builtin_platform_driver(msm_restart_driver);
diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c
index e229308d4..41530b70c 100644
--- a/drivers/power/reset/nvmem-reboot-mode.c
+++ b/drivers/power/reset/nvmem-reboot-mode.c
@@ -45,8 +45,8 @@ static int nvmem_reboot_mode_probe(struct platform_device *pdev)
nvmem_rbm->cell = devm_nvmem_cell_get(&pdev->dev, "reboot-mode");
if (IS_ERR(nvmem_rbm->cell)) {
- dev_err(&pdev->dev, "failed to get the nvmem cell reboot-mode\n");
- return PTR_ERR(nvmem_rbm->cell);
+ return dev_err_probe(&pdev->dev, PTR_ERR(nvmem_rbm->cell),
+ "failed to get the nvmem cell reboot-mode\n");
}
ret = devm_reboot_mode_register(&pdev->dev, &nvmem_rbm->reboot);
diff --git a/drivers/power/reset/st-poweroff.c b/drivers/power/reset/st-poweroff.c
index 56ba21873..85175066b 100644
--- a/drivers/power/reset/st-poweroff.c
+++ b/drivers/power/reset/st-poweroff.c
@@ -100,12 +100,7 @@ static struct platform_driver st_reset_driver = {
},
};
-static int __init st_reset_init(void)
-{
- return platform_driver_register(&st_reset_driver);
-}
-
-device_initcall(st_reset_init);
+builtin_platform_driver(st_reset_driver);
MODULE_AUTHOR("Christophe Kerello <christophe.kerello@st.com>");
MODULE_DESCRIPTION("STMicroelectronics Power off Restart driver");
diff --git a/drivers/power/reset/syscon-poweroff.c b/drivers/power/reset/syscon-poweroff.c
index 430d440d5..c3aab7f59 100644
--- a/drivers/power/reset/syscon-poweroff.c
+++ b/drivers/power/reset/syscon-poweroff.c
@@ -32,23 +32,27 @@ static void syscon_poweroff(void)
static int syscon_poweroff_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
int mask_err, value_err;
- map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap");
+ map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap");
if (IS_ERR(map)) {
- dev_err(&pdev->dev, "unable to get syscon");
- return PTR_ERR(map);
+ map = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(map)) {
+ dev_err(dev, "unable to get syscon");
+ return PTR_ERR(map);
+ }
}
- if (of_property_read_u32(pdev->dev.of_node, "offset", &offset)) {
- dev_err(&pdev->dev, "unable to read 'offset'");
+ if (of_property_read_u32(dev->of_node, "offset", &offset)) {
+ dev_err(dev, "unable to read 'offset'");
return -EINVAL;
}
- value_err = of_property_read_u32(pdev->dev.of_node, "value", &value);
- mask_err = of_property_read_u32(pdev->dev.of_node, "mask", &mask);
+ value_err = of_property_read_u32(dev->of_node, "value", &value);
+ mask_err = of_property_read_u32(dev->of_node, "mask", &mask);
if (value_err && mask_err) {
- dev_err(&pdev->dev, "unable to read 'value' and 'mask'");
+ dev_err(dev, "unable to read 'value' and 'mask'");
return -EINVAL;
}
@@ -62,7 +66,7 @@ static int syscon_poweroff_probe(struct platform_device *pdev)
}
if (pm_power_off) {
- dev_err(&pdev->dev, "pm_power_off already claimed for %ps",
+ dev_err(dev, "pm_power_off already claimed for %ps",
pm_power_off);
return -EBUSY;
}
@@ -93,9 +97,4 @@ static struct platform_driver syscon_poweroff_driver = {
.of_match_table = syscon_poweroff_of_match,
},
};
-
-static int __init syscon_poweroff_register(void)
-{
- return platform_driver_register(&syscon_poweroff_driver);
-}
-device_initcall(syscon_poweroff_register);
+builtin_platform_driver(syscon_poweroff_driver);
diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c
index 17064d7b1..bb22b2db5 100644
--- a/drivers/power/reset/vexpress-poweroff.c
+++ b/drivers/power/reset/vexpress-poweroff.c
@@ -7,8 +7,8 @@
#include <linux/delay.h>
#include <linux/notifier.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/reboot.h>
#include <linux/stat.h>
#include <linux/vexpress.h>
@@ -108,20 +108,17 @@ static int _vexpress_register_restart_handler(struct device *dev)
static int vexpress_reset_probe(struct platform_device *pdev)
{
- const struct of_device_id *match =
- of_match_device(vexpress_reset_of_match, &pdev->dev);
+ enum vexpress_reset_func func;
struct regmap *regmap;
int ret = 0;
- if (!match)
- return -EINVAL;
-
regmap = devm_regmap_init_vexpress_config(&pdev->dev);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
dev_set_drvdata(&pdev->dev, regmap);
- switch ((uintptr_t)match->data) {
+ func = (uintptr_t)device_get_match_data(&pdev->dev);
+ switch (func) {
case FUNC_SHUTDOWN:
vexpress_power_off_device = &pdev->dev;
pm_power_off = vexpress_power_off;
diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c
index 3260bd931..c2e5a9994 100644
--- a/drivers/power/reset/xgene-reboot.c
+++ b/drivers/power/reset/xgene-reboot.c
@@ -87,9 +87,4 @@ static struct platform_driver xgene_reboot_driver = {
.of_match_table = xgene_reboot_of_match,
},
};
-
-static int __init xgene_reboot_init(void)
-{
- return platform_driver_register(&xgene_reboot_driver);
-}
-device_initcall(xgene_reboot_init);
+builtin_platform_driver(xgene_reboot_driver);
diff --git a/drivers/power/supply/88pm860x_battery.c b/drivers/power/supply/88pm860x_battery.c
index f3f3f8cd1..34619c4d4 100644
--- a/drivers/power/supply/88pm860x_battery.c
+++ b/drivers/power/supply/88pm860x_battery.c
@@ -921,12 +921,12 @@ static int pm860x_battery_probe(struct platform_device *pdev)
return -ENOMEM;
info->irq_cc = platform_get_irq(pdev, 0);
- if (info->irq_cc <= 0)
- return -EINVAL;
+ if (info->irq_cc < 0)
+ return info->irq_cc;
info->irq_batt = platform_get_irq(pdev, 1);
- if (info->irq_batt <= 0)
- return -EINVAL;
+ if (info->irq_batt < 0)
+ return info->irq_batt;
info->chip = chip;
info->i2c =
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index a61bb1283..f21cb0581 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -374,7 +374,7 @@ config AXP288_FUEL_GAUGE
config BATTERY_MAX17040
tristate "Maxim MAX17040/17041/17043 family Fuel Gauge"
- depends on I2C
+ depends on I2C && IIO
select REGMAP_I2C
help
Driver supports Maxim fuel-gauge systems for lithium-ion (Li+)
@@ -629,6 +629,29 @@ config CHARGER_QCOM_SMBB
documentation for more detail. The base name for this driver is
'pm8941_charger'.
+config BATTERY_PM8916_BMS_VM
+ tristate "Qualcomm PM8916 BMS-VM support"
+ depends on MFD_SPMI_PMIC || COMPILE_TEST
+ help
+ Say Y to add support for Voltage Mode BMS block found in some
+ Qualcomm PMICs such as PM8916. This hardware block provides
+ battery voltage monitoring for the system.
+
+ To compile this driver as module, choose M here: the
+ module will be called pm8916_bms_vm.
+
+config CHARGER_PM8916_LBC
+ tristate "Qualcomm PM8916 Linear Battery Charger support"
+ depends on MFD_SPMI_PMIC || COMPILE_TEST
+ depends on EXTCON || !EXTCON
+ help
+ Say Y here to add support for Linear Battery Charger block
+ found in some Qualcomm PMICs such as PM8916. This hardware
+ blokc provides simple CC/CV battery charger.
+
+ To compile this driver as module, choose M here: the
+ module will be called pm8916_lbc.
+
config CHARGER_BQ2415X
tristate "TI BQ2415x battery charger driver"
depends on I2C
@@ -952,4 +975,13 @@ config CHARGER_QCOM_SMB2
adds support for the SMB2 switch mode battery charger found
in PMI8998 and related PMICs.
+config FUEL_GAUGE_MM8013
+ tristate "Mitsumi MM8013 fuel gauge driver"
+ depends on I2C
+ help
+ Say Y here to enable the Mitsumi MM8013 fuel gauge driver.
+ It enables the monitoring of many battery parameters, including
+ the state of charge, temperature, cycle count, actual and design
+ capacity, etc.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index a8a9fa6de..58b567278 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -84,6 +84,8 @@ obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o
obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o
obj-$(CONFIG_CHARGER_MT6370) += mt6370-charger.o
obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o
+obj-$(CONFIG_BATTERY_PM8916_BMS_VM) += pm8916_bms_vm.o
+obj-$(CONFIG_CHARGER_PM8916_LBC) += pm8916_lbc.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o
@@ -111,3 +113,4 @@ obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o
obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o
obj-$(CONFIG_BATTERY_UG3105) += ug3105_battery.o
obj-$(CONFIG_CHARGER_QCOM_SMB2) += qcom_pmi8998_charger.o
+obj-$(CONFIG_FUEL_GAUGE_MM8013) += mm8013.o
diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c
index ce36d6ca3..7905eba93 100644
--- a/drivers/power/supply/ab8500_btemp.c
+++ b/drivers/power/supply/ab8500_btemp.c
@@ -804,11 +804,9 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
return component_add(dev, &ab8500_btemp_component_ops);
}
-static int ab8500_btemp_remove(struct platform_device *pdev)
+static void ab8500_btemp_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &ab8500_btemp_component_ops);
-
- return 0;
}
static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume);
@@ -821,7 +819,7 @@ MODULE_DEVICE_TABLE(of, ab8500_btemp_match);
struct platform_driver ab8500_btemp_driver = {
.probe = ab8500_btemp_probe,
- .remove = ab8500_btemp_remove,
+ .remove_new = ab8500_btemp_remove,
.driver = {
.name = "ab8500-btemp",
.of_match_table = ab8500_btemp_match,
diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c
index 2205ea083..de912658f 100644
--- a/drivers/power/supply/ab8500_chargalg.c
+++ b/drivers/power/supply/ab8500_chargalg.c
@@ -1824,11 +1824,9 @@ static int ab8500_chargalg_probe(struct platform_device *pdev)
return component_add(dev, &ab8500_chargalg_component_ops);
}
-static int ab8500_chargalg_remove(struct platform_device *pdev)
+static void ab8500_chargalg_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &ab8500_chargalg_component_ops);
-
- return 0;
}
static SIMPLE_DEV_PM_OPS(ab8500_chargalg_pm_ops, ab8500_chargalg_suspend, ab8500_chargalg_resume);
@@ -1840,7 +1838,7 @@ static const struct of_device_id ab8500_chargalg_match[] = {
struct platform_driver ab8500_chargalg_driver = {
.probe = ab8500_chargalg_probe,
- .remove = ab8500_chargalg_remove,
+ .remove_new = ab8500_chargalg_remove,
.driver = {
.name = "ab8500_chargalg",
.of_match_table = ab8500_chargalg_match,
diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c
index 308e68545..d72f32c66 100644
--- a/drivers/power/supply/ab8500_charger.c
+++ b/drivers/power/supply/ab8500_charger.c
@@ -3679,7 +3679,7 @@ remove_ab8500_bm:
return ret;
}
-static int ab8500_charger_remove(struct platform_device *pdev)
+static void ab8500_charger_remove(struct platform_device *pdev)
{
struct ab8500_charger *di = platform_get_drvdata(pdev);
@@ -3688,8 +3688,6 @@ static int ab8500_charger_remove(struct platform_device *pdev)
usb_unregister_notifier(di->usb_phy, &di->nb);
ab8500_bm_of_remove(di->usb_chg.psy, di->bm);
usb_put_phy(di->usb_phy);
-
- return 0;
}
static SIMPLE_DEV_PM_OPS(ab8500_charger_pm_ops, ab8500_charger_suspend, ab8500_charger_resume);
@@ -3702,7 +3700,7 @@ MODULE_DEVICE_TABLE(of, ab8500_charger_match);
static struct platform_driver ab8500_charger_driver = {
.probe = ab8500_charger_probe,
- .remove = ab8500_charger_remove,
+ .remove_new = ab8500_charger_remove,
.driver = {
.name = "ab8500-charger",
.of_match_table = ab8500_charger_match,
diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c
index 53560fbb6..8c593fbdd 100644
--- a/drivers/power/supply/ab8500_fg.c
+++ b/drivers/power/supply/ab8500_fg.c
@@ -3227,7 +3227,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
return component_add(dev, &ab8500_fg_component_ops);
}
-static int ab8500_fg_remove(struct platform_device *pdev)
+static void ab8500_fg_remove(struct platform_device *pdev)
{
struct ab8500_fg *di = platform_get_drvdata(pdev);
@@ -3236,8 +3236,6 @@ static int ab8500_fg_remove(struct platform_device *pdev)
list_del(&di->node);
ab8500_fg_sysfs_exit(di);
ab8500_fg_sysfs_psy_remove_attrs(di);
-
- return 0;
}
static SIMPLE_DEV_PM_OPS(ab8500_fg_pm_ops, ab8500_fg_suspend, ab8500_fg_resume);
@@ -3250,7 +3248,7 @@ MODULE_DEVICE_TABLE(of, ab8500_fg_match);
struct platform_driver ab8500_fg_driver = {
.probe = ab8500_fg_probe,
- .remove = ab8500_fg_remove,
+ .remove_new = ab8500_fg_remove,
.driver = {
.name = "ab8500-fg",
.of_match_table = ab8500_fg_match,
diff --git a/drivers/power/supply/acer_a500_battery.c b/drivers/power/supply/acer_a500_battery.c
index 32a0bfcac..ef5c419b1 100644
--- a/drivers/power/supply/acer_a500_battery.c
+++ b/drivers/power/supply/acer_a500_battery.c
@@ -251,13 +251,11 @@ static int a500_battery_probe(struct platform_device *pdev)
return 0;
}
-static int a500_battery_remove(struct platform_device *pdev)
+static void a500_battery_remove(struct platform_device *pdev)
{
struct a500_battery *bat = dev_get_drvdata(&pdev->dev);
cancel_delayed_work_sync(&bat->poll_work);
-
- return 0;
}
static int __maybe_unused a500_battery_suspend(struct device *dev)
@@ -287,7 +285,7 @@ static struct platform_driver a500_battery_driver = {
.pm = &a500_battery_pm_ops,
},
.probe = a500_battery_probe,
- .remove = a500_battery_remove,
+ .remove_new = a500_battery_remove,
};
module_platform_driver(a500_battery_driver);
diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c
index e9b5f4283..51122bfbf 100644
--- a/drivers/power/supply/act8945a_charger.c
+++ b/drivers/power/supply/act8945a_charger.c
@@ -638,14 +638,12 @@ static int act8945a_charger_probe(struct platform_device *pdev)
return 0;
}
-static int act8945a_charger_remove(struct platform_device *pdev)
+static void act8945a_charger_remove(struct platform_device *pdev)
{
struct act8945a_charger *charger = platform_get_drvdata(pdev);
charger->init_done = false;
cancel_work_sync(&charger->work);
-
- return 0;
}
static struct platform_driver act8945a_charger_driver = {
@@ -653,7 +651,7 @@ static struct platform_driver act8945a_charger_driver = {
.name = "act8945a-charger",
},
.probe = act8945a_charger_probe,
- .remove = act8945a_charger_remove,
+ .remove_new = act8945a_charger_remove,
};
module_platform_driver(act8945a_charger_driver);
diff --git a/drivers/power/supply/axp20x_ac_power.c b/drivers/power/supply/axp20x_ac_power.c
index 19a118633..e5733cb9e 100644
--- a/drivers/power/supply/axp20x_ac_power.c
+++ b/drivers/power/supply/axp20x_ac_power.c
@@ -45,7 +45,7 @@ struct axp20x_ac_power {
struct iio_channel *acin_i;
bool has_acin_path_sel;
unsigned int num_irqs;
- unsigned int irqs[];
+ unsigned int irqs[] __counted_by(num_irqs);
};
static irqreturn_t axp20x_ac_power_irq(int irq, void *devid)
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index bde17406c..e23308ad4 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -73,7 +73,7 @@ struct axp20x_usb_power {
unsigned int old_status;
unsigned int online;
unsigned int num_irqs;
- unsigned int irqs[];
+ unsigned int irqs[] __counted_by(num_irqs);
};
static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power)
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 3f99cb959..1db290ee2 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -1803,7 +1803,7 @@ static int bq24190_probe(struct i2c_client *client)
bdi->client = client;
bdi->dev = dev;
- strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
+ strscpy(bdi->model_name, id->name, sizeof(bdi->model_name));
mutex_init(&bdi->f_reg_lock);
bdi->charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
bdi->f_reg = 0;
diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c
index 2852860ab..801d0d2c5 100644
--- a/drivers/power/supply/bq24257_charger.c
+++ b/drivers/power/supply/bq24257_charger.c
@@ -35,20 +35,15 @@
#define BQ24257_ILIM_SET_DELAY 1000 /* msec */
-/*
- * When adding support for new devices make sure that enum bq2425x_chip and
- * bq2425x_chip_name[] always stay in sync!
- */
enum bq2425x_chip {
BQ24250,
BQ24251,
BQ24257,
};
-static const char *const bq2425x_chip_name[] = {
- "bq24250",
- "bq24251",
- "bq24257",
+struct bq2425x_chip_info {
+ const char *const name;
+ enum bq2425x_chip chip;
};
enum bq24257_fields {
@@ -84,7 +79,7 @@ struct bq24257_device {
struct device *dev;
struct power_supply *charger;
- enum bq2425x_chip chip;
+ const struct bq2425x_chip_info *info;
struct regmap *rmap;
struct regmap_field *rmap_fields[F_MAX_FIELDS];
@@ -329,7 +324,7 @@ static int bq24257_power_supply_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
- val->strval = bq2425x_chip_name[bq->chip];
+ val->strval = bq->info->name;
break;
case POWER_SUPPLY_PROP_ONLINE:
@@ -947,10 +942,8 @@ static int bq24257_fw_probe(struct bq24257_device *bq)
static int bq24257_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
- const struct acpi_device_id *acpi_id;
struct bq24257_device *bq;
int ret;
int i;
@@ -967,17 +960,9 @@ static int bq24257_probe(struct i2c_client *client)
bq->client = client;
bq->dev = dev;
- if (ACPI_HANDLE(dev)) {
- acpi_id = acpi_match_device(dev->driver->acpi_match_table,
- &client->dev);
- if (!acpi_id) {
- dev_err(dev, "Failed to match ACPI device\n");
- return -ENODEV;
- }
- bq->chip = (enum bq2425x_chip)acpi_id->driver_data;
- } else {
- bq->chip = (enum bq2425x_chip)id->driver_data;
- }
+ bq->info = i2c_get_match_data(client);
+ if (!bq->info)
+ return dev_err_probe(dev, -ENODEV, "Failed to match device\n");
mutex_init(&bq->lock);
@@ -1015,7 +1000,7 @@ static int bq24257_probe(struct i2c_client *client)
* used for the automatic setting of the input current limit setting so
* explicitly disable that feature.
*/
- if (bq->chip == BQ24250)
+ if (bq->info->chip == BQ24250)
bq->iilimit_autoset_enable = false;
if (bq->iilimit_autoset_enable)
@@ -1028,7 +1013,7 @@ static int bq24257_probe(struct i2c_client *client)
* the PG state. We also use a SW-based approach for all other devices
* if the PG pin is either not defined or can't be probed.
*/
- if (bq->chip != BQ24250)
+ if (bq->info->chip != BQ24250)
bq24257_pg_gpio_probe(bq);
if (PTR_ERR(bq->pg) == -EPROBE_DEFER)
@@ -1066,7 +1051,7 @@ static int bq24257_probe(struct i2c_client *client)
bq24257_irq_handler_thread,
IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- bq2425x_chip_name[bq->chip], bq);
+ bq->info->name, bq);
if (ret) {
dev_err(dev, "Failed to request IRQ #%d\n", client->irq);
return ret;
@@ -1132,28 +1117,43 @@ static const struct dev_pm_ops bq24257_pm = {
SET_SYSTEM_SLEEP_PM_OPS(bq24257_suspend, bq24257_resume)
};
+static const struct bq2425x_chip_info bq24250_info = {
+ .name = "bq24250",
+ .chip = BQ24250,
+};
+
+static const struct bq2425x_chip_info bq24251_info = {
+ .name = "bq24251",
+ .chip = BQ24251,
+};
+
+static const struct bq2425x_chip_info bq24257_info = {
+ .name = "bq24257",
+ .chip = BQ24257,
+};
+
static const struct i2c_device_id bq24257_i2c_ids[] = {
- { "bq24250", BQ24250 },
- { "bq24251", BQ24251 },
- { "bq24257", BQ24257 },
- {},
+ { "bq24250", (kernel_ulong_t)&bq24250_info },
+ { "bq24251", (kernel_ulong_t)&bq24251_info },
+ { "bq24257", (kernel_ulong_t)&bq24257_info },
+ {}
};
MODULE_DEVICE_TABLE(i2c, bq24257_i2c_ids);
static const struct of_device_id bq24257_of_match[] __maybe_unused = {
- { .compatible = "ti,bq24250", },
- { .compatible = "ti,bq24251", },
- { .compatible = "ti,bq24257", },
- { },
+ { .compatible = "ti,bq24250", &bq24250_info },
+ { .compatible = "ti,bq24251", &bq24251_info },
+ { .compatible = "ti,bq24257", &bq24257_info },
+ {}
};
MODULE_DEVICE_TABLE(of, bq24257_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id bq24257_acpi_match[] = {
- { "BQ242500", BQ24250 },
- { "BQ242510", BQ24251 },
- { "BQ242570", BQ24257 },
- {},
+ { "BQ242500", (kernel_ulong_t)&bq24250_info },
+ { "BQ242510", (kernel_ulong_t)&bq24251_info },
+ { "BQ242570", (kernel_ulong_t)&bq24257_info },
+ {}
};
MODULE_DEVICE_TABLE(acpi, bq24257_acpi_match);
#endif
diff --git a/drivers/power/supply/bq2515x_charger.c b/drivers/power/supply/bq2515x_charger.c
index 1dbacc9b0..a3424f67f 100644
--- a/drivers/power/supply/bq2515x_charger.c
+++ b/drivers/power/supply/bq2515x_charger.c
@@ -147,9 +147,14 @@ struct bq2515x_init_data {
int iprechg;
};
-enum bq2515x_id {
- BQ25150,
- BQ25155,
+/**
+ * struct bq2515x_info -
+ * @regmap_config: register map config
+ * @ilim: input current limit
+ */
+struct bq2515x_info {
+ const struct regmap_config *regmap_config;
+ int ilim;
};
/**
@@ -164,8 +169,8 @@ enum bq2515x_id {
* @ac_detect_gpio: power good (PG) pin
* @ce_gpio: charge enable (CE) pin
*
+ * @info: device info
* @model_name: string value describing device model
- * @device_id: value of device_id
* @mains_online: boolean value indicating power supply online
*
* @init_data: charger initialization data structure
@@ -181,8 +186,8 @@ struct bq2515x_device {
struct gpio_desc *ac_detect_gpio;
struct gpio_desc *ce_gpio;
+ const struct bq2515x_info *info;
char model_name[I2C_NAME_SIZE];
- int device_id;
bool mains_online;
struct bq2515x_init_data init_data;
@@ -998,16 +1003,8 @@ static int bq2515x_read_properties(struct bq2515x_device *bq2515x)
ret = device_property_read_u32(bq2515x->dev,
"input-current-limit-microamp",
&bq2515x->init_data.ilim);
- if (ret) {
- switch (bq2515x->device_id) {
- case BQ25150:
- bq2515x->init_data.ilim = BQ25150_DEFAULT_ILIM_UA;
- break;
- case BQ25155:
- bq2515x->init_data.ilim = BQ25155_DEFAULT_ILIM_UA;
- break;
- }
- }
+ if (ret)
+ bq2515x->init_data.ilim = bq2515x->info->ilim;
bq2515x->ac_detect_gpio = devm_gpiod_get_optional(bq2515x->dev,
"ac-detect", GPIOD_IN);
@@ -1092,21 +1089,11 @@ static int bq2515x_probe(struct i2c_client *client)
bq2515x->dev = dev;
- strncpy(bq2515x->model_name, id->name, I2C_NAME_SIZE);
-
- bq2515x->device_id = id->driver_data;
-
- switch (bq2515x->device_id) {
- case BQ25150:
- bq2515x->regmap = devm_regmap_init_i2c(client,
- &bq25150_regmap_config);
- break;
- case BQ25155:
- bq2515x->regmap = devm_regmap_init_i2c(client,
- &bq25155_regmap_config);
- break;
- }
+ strscpy(bq2515x->model_name, id->name, sizeof(bq2515x->model_name));
+ bq2515x->info = i2c_get_match_data(client);
+ bq2515x->regmap = devm_regmap_init_i2c(client,
+ bq2515x->info->regmap_config);
if (IS_ERR(bq2515x->regmap)) {
dev_err(dev, "failed to allocate register map\n");
return PTR_ERR(bq2515x->regmap);
@@ -1139,17 +1126,27 @@ static int bq2515x_probe(struct i2c_client *client)
return 0;
}
+static const struct bq2515x_info bq25150 = {
+ .regmap_config = &bq25150_regmap_config,
+ .ilim = BQ25150_DEFAULT_ILIM_UA,
+};
+
+static const struct bq2515x_info bq25155 = {
+ .regmap_config = &bq25155_regmap_config,
+ .ilim = BQ25155_DEFAULT_ILIM_UA,
+};
+
static const struct i2c_device_id bq2515x_i2c_ids[] = {
- { "bq25150", BQ25150, },
- { "bq25155", BQ25155, },
- {},
+ { "bq25150", (kernel_ulong_t)&bq25150 },
+ { "bq25155", (kernel_ulong_t)&bq25155 },
+ {}
};
MODULE_DEVICE_TABLE(i2c, bq2515x_i2c_ids);
static const struct of_device_id bq2515x_of_match[] = {
- { .compatible = "ti,bq25150", },
- { .compatible = "ti,bq25155", },
- { },
+ { .compatible = "ti,bq25150", .data = &bq25150 },
+ { .compatible = "ti,bq25155", .data = &bq25155 },
+ {}
};
MODULE_DEVICE_TABLE(of, bq2515x_of_match);
diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c
index c8368dae6..1a935bc88 100644
--- a/drivers/power/supply/bq256xx_charger.c
+++ b/drivers/power/supply/bq256xx_charger.c
@@ -1705,11 +1705,11 @@ static int bq256xx_probe(struct i2c_client *client)
bq->client = client;
bq->dev = dev;
- bq->chip_info = &bq256xx_chip_info_tbl[id->driver_data];
+ bq->chip_info = i2c_get_match_data(client);
mutex_init(&bq->lock);
- strncpy(bq->model_name, id->name, I2C_NAME_SIZE);
+ strscpy(bq->model_name, id->name, sizeof(bq->model_name));
bq->regmap = devm_regmap_init_i2c(client,
bq->chip_info->bq256xx_regmap_config);
@@ -1774,38 +1774,38 @@ static int bq256xx_probe(struct i2c_client *client)
}
static const struct i2c_device_id bq256xx_i2c_ids[] = {
- { "bq25600", BQ25600 },
- { "bq25600d", BQ25600D },
- { "bq25601", BQ25601 },
- { "bq25601d", BQ25601D },
- { "bq25611d", BQ25611D },
- { "bq25618", BQ25618 },
- { "bq25619", BQ25619 },
- {},
+ { "bq25600", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25600] },
+ { "bq25600d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25600D] },
+ { "bq25601", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25601] },
+ { "bq25601d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25601D] },
+ { "bq25611d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25611D] },
+ { "bq25618", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25618] },
+ { "bq25619", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25619] },
+ {}
};
MODULE_DEVICE_TABLE(i2c, bq256xx_i2c_ids);
static const struct of_device_id bq256xx_of_match[] = {
- { .compatible = "ti,bq25600", .data = (void *)BQ25600 },
- { .compatible = "ti,bq25600d", .data = (void *)BQ25600D },
- { .compatible = "ti,bq25601", .data = (void *)BQ25601 },
- { .compatible = "ti,bq25601d", .data = (void *)BQ25601D },
- { .compatible = "ti,bq25611d", .data = (void *)BQ25611D },
- { .compatible = "ti,bq25618", .data = (void *)BQ25618 },
- { .compatible = "ti,bq25619", .data = (void *)BQ25619 },
- { },
+ { .compatible = "ti,bq25600", .data = &bq256xx_chip_info_tbl[BQ25600] },
+ { .compatible = "ti,bq25600d", .data = &bq256xx_chip_info_tbl[BQ25600D] },
+ { .compatible = "ti,bq25601", .data = &bq256xx_chip_info_tbl[BQ25601] },
+ { .compatible = "ti,bq25601d", .data = &bq256xx_chip_info_tbl[BQ25601D] },
+ { .compatible = "ti,bq25611d", .data = &bq256xx_chip_info_tbl[BQ25611D] },
+ { .compatible = "ti,bq25618", .data = &bq256xx_chip_info_tbl[BQ25618] },
+ { .compatible = "ti,bq25619", .data = &bq256xx_chip_info_tbl[BQ25619] },
+ {}
};
MODULE_DEVICE_TABLE(of, bq256xx_of_match);
static const struct acpi_device_id bq256xx_acpi_match[] = {
- { "bq25600", BQ25600 },
- { "bq25600d", BQ25600D },
- { "bq25601", BQ25601 },
- { "bq25601d", BQ25601D },
- { "bq25611d", BQ25611D },
- { "bq25618", BQ25618 },
- { "bq25619", BQ25619 },
- {},
+ { "bq25600", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25600] },
+ { "bq25600d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25600D] },
+ { "bq25601", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25601] },
+ { "bq25601d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25601D] },
+ { "bq25611d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25611D] },
+ { "bq25618", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25618] },
+ { "bq25619", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25619] },
+ {}
};
MODULE_DEVICE_TABLE(acpi, bq256xx_acpi_match);
diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c
index d84117222..0c5e2938b 100644
--- a/drivers/power/supply/bq25980_charger.c
+++ b/drivers/power/supply/bq25980_charger.c
@@ -1223,7 +1223,7 @@ static int bq25980_probe(struct i2c_client *client)
mutex_init(&bq->lock);
- strncpy(bq->model_name, id->name, I2C_NAME_SIZE);
+ strscpy(bq->model_name, id->name, sizeof(bq->model_name));
bq->chip_info = &bq25980_chip_info_tbl[id->driver_data];
bq->regmap = devm_regmap_init_i2c(client,
diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c
index 5fa6ba7f4..96f0a7fbf 100644
--- a/drivers/power/supply/charger-manager.c
+++ b/drivers/power/supply/charger-manager.c
@@ -1516,9 +1516,11 @@ static int charger_manager_probe(struct platform_device *pdev)
memcpy(&cm->charger_psy_desc, &psy_default, sizeof(psy_default));
if (!desc->psy_name)
- strncpy(cm->psy_name_buf, psy_default.name, PSY_NAME_MAX);
+ strscpy(cm->psy_name_buf, psy_default.name,
+ sizeof(cm->psy_name_buf));
else
- strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX);
+ strscpy(cm->psy_name_buf, desc->psy_name,
+ sizeof(cm->psy_name_buf));
cm->charger_psy_desc.name = cm->psy_name_buf;
/* Allocate for psy properties because they may vary */
@@ -1628,7 +1630,7 @@ err_reg_extcon:
return ret;
}
-static int charger_manager_remove(struct platform_device *pdev)
+static void charger_manager_remove(struct platform_device *pdev)
{
struct charger_manager *cm = platform_get_drvdata(pdev);
struct charger_desc *desc = cm->desc;
@@ -1648,8 +1650,6 @@ static int charger_manager_remove(struct platform_device *pdev)
power_supply_unregister(cm->charger_psy);
try_charger_enable(cm, false);
-
- return 0;
}
static const struct platform_device_id charger_manager_id[] = {
@@ -1740,7 +1740,7 @@ static struct platform_driver charger_manager_driver = {
.of_match_table = charger_manager_match,
},
.probe = charger_manager_probe,
- .remove = charger_manager_remove,
+ .remove_new = charger_manager_remove,
.id_table = charger_manager_id,
};
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c
index 5dd76c0ac..30ec76cdf 100644
--- a/drivers/power/supply/cpcap-battery.c
+++ b/drivers/power/supply/cpcap-battery.c
@@ -1151,7 +1151,7 @@ static int cpcap_battery_probe(struct platform_device *pdev)
return 0;
}
-static int cpcap_battery_remove(struct platform_device *pdev)
+static void cpcap_battery_remove(struct platform_device *pdev)
{
struct cpcap_battery_ddata *ddata = platform_get_drvdata(pdev);
int error;
@@ -1161,8 +1161,6 @@ static int cpcap_battery_remove(struct platform_device *pdev)
0xffff, 0);
if (error)
dev_err(&pdev->dev, "could not disable: %i\n", error);
-
- return 0;
}
static struct platform_driver cpcap_battery_driver = {
@@ -1171,7 +1169,7 @@ static struct platform_driver cpcap_battery_driver = {
.of_match_table = of_match_ptr(cpcap_battery_id_table),
},
.probe = cpcap_battery_probe,
- .remove = cpcap_battery_remove,
+ .remove_new = cpcap_battery_remove,
};
module_platform_driver(cpcap_battery_driver);
diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c
index be9764541..cebca34ff 100644
--- a/drivers/power/supply/cpcap-charger.c
+++ b/drivers/power/supply/cpcap-charger.c
@@ -17,8 +17,7 @@
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
@@ -865,7 +864,6 @@ static const struct power_supply_desc cpcap_charger_usb_desc = {
.property_is_writeable = cpcap_charger_property_is_writeable,
};
-#ifdef CONFIG_OF
static const struct of_device_id cpcap_charger_id_table[] = {
{
.compatible = "motorola,mapphone-cpcap-charger",
@@ -873,20 +871,13 @@ static const struct of_device_id cpcap_charger_id_table[] = {
{},
};
MODULE_DEVICE_TABLE(of, cpcap_charger_id_table);
-#endif
static int cpcap_charger_probe(struct platform_device *pdev)
{
struct cpcap_charger_ddata *ddata;
- const struct of_device_id *of_id;
struct power_supply_config psy_cfg = {};
int error;
- of_id = of_match_device(of_match_ptr(cpcap_charger_id_table),
- &pdev->dev);
- if (!of_id)
- return -EINVAL;
-
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
@@ -966,21 +957,19 @@ static void cpcap_charger_shutdown(struct platform_device *pdev)
cancel_delayed_work_sync(&ddata->detect_work);
}
-static int cpcap_charger_remove(struct platform_device *pdev)
+static void cpcap_charger_remove(struct platform_device *pdev)
{
cpcap_charger_shutdown(pdev);
-
- return 0;
}
static struct platform_driver cpcap_charger_driver = {
.probe = cpcap_charger_probe,
.driver = {
.name = "cpcap-charger",
- .of_match_table = of_match_ptr(cpcap_charger_id_table),
+ .of_match_table = cpcap_charger_id_table,
},
.shutdown = cpcap_charger_shutdown,
- .remove = cpcap_charger_remove,
+ .remove_new = cpcap_charger_remove,
};
module_platform_driver(cpcap_charger_driver);
diff --git a/drivers/power/supply/da9030_battery.c b/drivers/power/supply/da9030_battery.c
index 0deba48d2..581cf956d 100644
--- a/drivers/power/supply/da9030_battery.c
+++ b/drivers/power/supply/da9030_battery.c
@@ -552,7 +552,7 @@ err_charger_init:
return ret;
}
-static int da9030_battery_remove(struct platform_device *dev)
+static void da9030_battery_remove(struct platform_device *dev)
{
struct da9030_charger *charger = platform_get_drvdata(dev);
@@ -564,8 +564,6 @@ static int da9030_battery_remove(struct platform_device *dev)
cancel_delayed_work_sync(&charger->work);
da9030_set_charge(charger, 0);
power_supply_unregister(charger->psy);
-
- return 0;
}
static struct platform_driver da903x_battery_driver = {
@@ -573,7 +571,7 @@ static struct platform_driver da903x_battery_driver = {
.name = "da903x-battery",
},
.probe = da9030_battery_probe,
- .remove = da9030_battery_remove,
+ .remove_new = da9030_battery_remove,
};
module_platform_driver(da903x_battery_driver);
diff --git a/drivers/power/supply/da9052-battery.c b/drivers/power/supply/da9052-battery.c
index d87bdecc9..6f7c58a41 100644
--- a/drivers/power/supply/da9052-battery.c
+++ b/drivers/power/supply/da9052-battery.c
@@ -637,7 +637,7 @@ err:
return ret;
}
-static int da9052_bat_remove(struct platform_device *pdev)
+static void da9052_bat_remove(struct platform_device *pdev)
{
int i;
struct da9052_battery *bat = platform_get_drvdata(pdev);
@@ -646,13 +646,11 @@ static int da9052_bat_remove(struct platform_device *pdev)
da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat);
power_supply_unregister(bat->psy);
-
- return 0;
}
static struct platform_driver da9052_bat_driver = {
.probe = da9052_bat_probe,
- .remove = da9052_bat_remove,
+ .remove_new = da9052_bat_remove,
.driver = {
.name = "da9052-bat",
},
diff --git a/drivers/power/supply/da9150-charger.c b/drivers/power/supply/da9150-charger.c
index 27f897067..37db9e4ed 100644
--- a/drivers/power/supply/da9150-charger.c
+++ b/drivers/power/supply/da9150-charger.c
@@ -635,7 +635,7 @@ ibus_chan_fail:
return ret;
}
-static int da9150_charger_remove(struct platform_device *pdev)
+static void da9150_charger_remove(struct platform_device *pdev)
{
struct da9150_charger *charger = platform_get_drvdata(pdev);
int irq;
@@ -665,8 +665,6 @@ static int da9150_charger_remove(struct platform_device *pdev)
iio_channel_release(charger->vbus_chan);
iio_channel_release(charger->tjunc_chan);
iio_channel_release(charger->vbat_chan);
-
- return 0;
}
static struct platform_driver da9150_charger_driver = {
@@ -674,7 +672,7 @@ static struct platform_driver da9150_charger_driver = {
.name = "da9150-charger",
},
.probe = da9150_charger_probe,
- .remove = da9150_charger_remove,
+ .remove_new = da9150_charger_remove,
};
module_platform_driver(da9150_charger_driver);
diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c
index a58d713d7..8bb645ad1 100644
--- a/drivers/power/supply/goldfish_battery.c
+++ b/drivers/power/supply/goldfish_battery.c
@@ -249,13 +249,12 @@ static int goldfish_battery_probe(struct platform_device *pdev)
return 0;
}
-static int goldfish_battery_remove(struct platform_device *pdev)
+static void goldfish_battery_remove(struct platform_device *pdev)
{
struct goldfish_battery_data *data = platform_get_drvdata(pdev);
power_supply_unregister(data->battery);
power_supply_unregister(data->ac);
- return 0;
}
static const struct of_device_id goldfish_battery_of_match[] = {
@@ -274,7 +273,7 @@ MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match);
static struct platform_driver goldfish_battery_device = {
.probe = goldfish_battery_probe,
- .remove = goldfish_battery_remove,
+ .remove_new = goldfish_battery_remove,
.driver = {
.name = "goldfish-battery",
.of_match_table = goldfish_battery_of_match,
diff --git a/drivers/power/supply/ipaq_micro_battery.c b/drivers/power/supply/ipaq_micro_battery.c
index 192d9db0f..66cc649f7 100644
--- a/drivers/power/supply/ipaq_micro_battery.c
+++ b/drivers/power/supply/ipaq_micro_battery.c
@@ -265,7 +265,7 @@ batt_err:
return ret;
}
-static int micro_batt_remove(struct platform_device *pdev)
+static void micro_batt_remove(struct platform_device *pdev)
{
struct micro_battery *mb = platform_get_drvdata(pdev);
@@ -274,8 +274,6 @@ static int micro_batt_remove(struct platform_device *pdev)
power_supply_unregister(micro_batt_power);
cancel_delayed_work_sync(&mb->update);
destroy_workqueue(mb->wq);
-
- return 0;
}
static int __maybe_unused micro_batt_suspend(struct device *dev)
@@ -304,7 +302,7 @@ static struct platform_driver micro_batt_device_driver = {
.pm = &micro_batt_dev_pm_ops,
},
.probe = micro_batt_probe,
- .remove = micro_batt_remove,
+ .remove_new = micro_batt_remove,
};
module_platform_driver(micro_batt_device_driver);
diff --git a/drivers/power/supply/isp1704_charger.c b/drivers/power/supply/isp1704_charger.c
index b6efc454e..860d8614c 100644
--- a/drivers/power/supply/isp1704_charger.c
+++ b/drivers/power/supply/isp1704_charger.c
@@ -477,15 +477,13 @@ fail0:
return ret;
}
-static int isp1704_charger_remove(struct platform_device *pdev)
+static void isp1704_charger_remove(struct platform_device *pdev)
{
struct isp1704_charger *isp = platform_get_drvdata(pdev);
usb_unregister_notifier(isp->phy, &isp->nb);
power_supply_unregister(isp->psy);
isp1704_charger_set_power(isp, 0);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -503,7 +501,7 @@ static struct platform_driver isp1704_charger_driver = {
.of_match_table = of_match_ptr(omap_isp1704_of_match),
},
.probe = isp1704_charger_probe,
- .remove = isp1704_charger_remove,
+ .remove_new = isp1704_charger_remove,
};
module_platform_driver(isp1704_charger_driver);
diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c
index 755b6a437..2c81be82a 100644
--- a/drivers/power/supply/lp8788-charger.c
+++ b/drivers/power/supply/lp8788-charger.c
@@ -714,20 +714,18 @@ static int lp8788_charger_probe(struct platform_device *pdev)
return 0;
}
-static int lp8788_charger_remove(struct platform_device *pdev)
+static void lp8788_charger_remove(struct platform_device *pdev)
{
struct lp8788_charger *pchg = platform_get_drvdata(pdev);
flush_work(&pchg->charger_work);
lp8788_irq_unregister(pdev, pchg);
lp8788_psy_unregister(pchg);
-
- return 0;
}
static struct platform_driver lp8788_charger_driver = {
.probe = lp8788_charger_probe,
- .remove = lp8788_charger_remove,
+ .remove_new = lp8788_charger_remove,
.driver = {
.name = LP8788_DEV_CHARGER,
},
diff --git a/drivers/power/supply/max14577_charger.c b/drivers/power/supply/max14577_charger.c
index 96f9de775..7c23fa89e 100644
--- a/drivers/power/supply/max14577_charger.c
+++ b/drivers/power/supply/max14577_charger.c
@@ -606,14 +606,12 @@ err:
return ret;
}
-static int max14577_charger_remove(struct platform_device *pdev)
+static void max14577_charger_remove(struct platform_device *pdev)
{
struct max14577_charger *chg = platform_get_drvdata(pdev);
device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);
power_supply_unregister(chg->charger);
-
- return 0;
}
static const struct platform_device_id max14577_charger_id[] = {
@@ -638,7 +636,7 @@ static struct platform_driver max14577_charger_driver = {
.of_match_table = of_max14577_charger_dt_match,
},
.probe = max14577_charger_probe,
- .remove = max14577_charger_remove,
+ .remove_new = max14577_charger_remove,
.id_table = max14577_charger_id,
};
module_platform_driver(max14577_charger_driver);
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index ff42db672..51310f6e4 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/iio/consumer.h>
#define MAX17040_VCELL 0x02
#define MAX17040_SOC 0x04
@@ -142,6 +143,7 @@ struct max17040_chip {
struct delayed_work work;
struct power_supply *battery;
struct chip_data data;
+ struct iio_channel *channel_temp;
/* battery capacity */
int soc;
@@ -389,6 +391,7 @@ static int max17040_get_property(struct power_supply *psy,
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
+ case POWER_SUPPLY_PROP_PRESENT:
val->intval = max17040_get_online(chip);
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
@@ -400,6 +403,16 @@ static int max17040_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
val->intval = chip->low_soc_alert;
break;
+ case POWER_SUPPLY_PROP_STATUS:
+ power_supply_get_property_from_supplier(psy, psp, val);
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ if (!chip->channel_temp)
+ return -ENODATA;
+
+ iio_read_channel_processed_scale(chip->channel_temp,
+ &val->intval, 10);
+ break;
default:
return -EINVAL;
}
@@ -415,9 +428,12 @@ static const struct regmap_config max17040_regmap = {
static enum power_supply_property max17040_battery_props[] = {
POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_TEMP,
};
static const struct power_supply_desc max17040_battery_desc = {
@@ -463,6 +479,17 @@ static int max17040_probe(struct i2c_client *client)
i2c_set_clientdata(client, chip);
psy_cfg.drv_data = chip;
+ /* Switch to devm_iio_channel_get_optional when available */
+ chip->channel_temp = devm_iio_channel_get(&client->dev, "temp");
+ if (IS_ERR(chip->channel_temp)) {
+ ret = PTR_ERR(chip->channel_temp);
+ if (ret != -ENODEV)
+ return dev_err_probe(&client->dev, PTR_ERR(chip->channel_temp),
+ "failed to get temp\n");
+ else
+ chip->channel_temp = NULL;
+ }
+
chip->battery = devm_power_supply_register(&client->dev,
&max17040_battery_desc, &psy_cfg);
if (IS_ERR(chip->battery)) {
diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index 17ac2ab78..e7d37e422 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -36,7 +36,7 @@
#define STATUS_BR_BIT (1 << 15)
/* Interrupt mask bits */
-#define CONFIG_ALRT_BIT_ENBL (1 << 2)
+#define CFG_ALRT_BIT_ENBL (1 << 2)
#define VFSOC0_LOCK 0x0000
#define VFSOC0_UNLOCK 0x0080
@@ -1116,8 +1116,8 @@ static int max17042_probe(struct i2c_client *client)
chip);
if (!ret) {
regmap_update_bits(chip->regmap, MAX17042_CONFIG,
- CONFIG_ALRT_BIT_ENBL,
- CONFIG_ALRT_BIT_ENBL);
+ CFG_ALRT_BIT_ENBL,
+ CFG_ALRT_BIT_ENBL);
max17042_set_soc_threshold(chip, 1);
} else {
client->irq = 0;
diff --git a/drivers/power/supply/max77650-charger.c b/drivers/power/supply/max77650-charger.c
index e8c25da40..818e13c61 100644
--- a/drivers/power/supply/max77650-charger.c
+++ b/drivers/power/supply/max77650-charger.c
@@ -345,13 +345,11 @@ static int max77650_charger_probe(struct platform_device *pdev)
return max77650_charger_enable(chg);
}
-static int max77650_charger_remove(struct platform_device *pdev)
+static void max77650_charger_remove(struct platform_device *pdev)
{
struct max77650_charger_data *chg = platform_get_drvdata(pdev);
max77650_charger_disable(chg);
-
- return 0;
}
static const struct of_device_id max77650_charger_of_match[] = {
@@ -366,7 +364,7 @@ static struct platform_driver max77650_charger_driver = {
.of_match_table = max77650_charger_of_match,
},
.probe = max77650_charger_probe,
- .remove = max77650_charger_remove,
+ .remove_new = max77650_charger_remove,
};
module_platform_driver(max77650_charger_driver);
diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c
index 794c8c054..d0157e63b 100644
--- a/drivers/power/supply/max77693_charger.c
+++ b/drivers/power/supply/max77693_charger.c
@@ -728,7 +728,7 @@ err:
return ret;
}
-static int max77693_charger_remove(struct platform_device *pdev)
+static void max77693_charger_remove(struct platform_device *pdev)
{
struct max77693_charger *chg = platform_get_drvdata(pdev);
@@ -737,8 +737,6 @@ static int max77693_charger_remove(struct platform_device *pdev)
device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);
power_supply_unregister(chg->charger);
-
- return 0;
}
static const struct platform_device_id max77693_charger_id[] = {
@@ -752,7 +750,7 @@ static struct platform_driver max77693_charger_driver = {
.name = "max77693-charger",
},
.probe = max77693_charger_probe,
- .remove = max77693_charger_remove,
+ .remove_new = max77693_charger_remove,
.id_table = max77693_charger_id,
};
module_platform_driver(max77693_charger_driver);
diff --git a/drivers/power/supply/max8925_power.c b/drivers/power/supply/max8925_power.c
index 8878f9131..4a2d6894f 100644
--- a/drivers/power/supply/max8925_power.c
+++ b/drivers/power/supply/max8925_power.c
@@ -566,7 +566,7 @@ out:
return ret;
}
-static int max8925_power_remove(struct platform_device *pdev)
+static void max8925_power_remove(struct platform_device *pdev)
{
struct max8925_power_info *info = platform_get_drvdata(pdev);
@@ -576,12 +576,11 @@ static int max8925_power_remove(struct platform_device *pdev)
power_supply_unregister(info->battery);
max8925_deinit_charger(info);
}
- return 0;
}
static struct platform_driver max8925_power_driver = {
.probe = max8925_power_probe,
- .remove = max8925_power_remove,
+ .remove_new = max8925_power_remove,
.driver = {
.name = "max8925-power",
},
diff --git a/drivers/power/supply/mm8013.c b/drivers/power/supply/mm8013.c
new file mode 100644
index 000000000..caa272b03
--- /dev/null
+++ b/drivers/power/supply/mm8013.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+
+#define REG_BATID 0x00 /* This one is very unclear */
+ #define BATID_101 0x0101 /* 107kOhm */
+ #define BATID_102 0x0102 /* 10kOhm */
+#define REG_TEMPERATURE 0x06
+#define REG_VOLTAGE 0x08
+#define REG_FLAGS 0x0a
+ #define MM8013_FLAG_OTC BIT(15)
+ #define MM8013_FLAG_OTD BIT(14)
+ #define MM8013_FLAG_BATHI BIT(13)
+ #define MM8013_FLAG_BATLOW BIT(12)
+ #define MM8013_FLAG_CHG_INH BIT(11)
+ #define MM8013_FLAG_FC BIT(9)
+ #define MM8013_FLAG_CHG BIT(8)
+ #define MM8013_FLAG_OCC BIT(6)
+ #define MM8013_FLAG_ODC BIT(5)
+ #define MM8013_FLAG_OT BIT(4)
+ #define MM8013_FLAG_UT BIT(3)
+ #define MM8013_FLAG_DSG BIT(0)
+#define REG_FULL_CHARGE_CAPACITY 0x0e
+#define REG_NOMINAL_CHARGE_CAPACITY 0x0c
+#define REG_AVERAGE_CURRENT 0x14
+#define REG_AVERAGE_TIME_TO_EMPTY 0x16
+#define REG_AVERAGE_TIME_TO_FULL 0x18
+#define REG_MAX_LOAD_CURRENT 0x1e
+#define REG_CYCLE_COUNT 0x2a
+#define REG_STATE_OF_CHARGE 0x2c
+#define REG_DESIGN_CAPACITY 0x3c
+/* TODO: 0x62-0x68 seem to contain 'MM8013C' in a length-prefixed, non-terminated string */
+
+#define DECIKELVIN_TO_DECIDEGC(t) (t - 2731)
+
+struct mm8013_chip {
+ struct i2c_client *client;
+ struct regmap *regmap;
+};
+
+static int mm8013_checkdevice(struct mm8013_chip *chip)
+{
+ int battery_id, ret;
+ u32 val;
+
+ ret = regmap_write(chip->regmap, REG_BATID, 0x0008);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(chip->regmap, REG_BATID, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val == BATID_102)
+ battery_id = 2;
+ else if (val == BATID_101)
+ battery_id = 1;
+ else
+ return -EINVAL;
+
+ dev_dbg(&chip->client->dev, "battery_id: %d\n", battery_id);
+
+ return 0;
+}
+
+static enum power_supply_property mm8013_battery_props[] = {
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CYCLE_COUNT,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+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;
+ int ret = 0;
+ u32 regval;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CAPACITY:
+ ret = regmap_read(chip->regmap, REG_STATE_OF_CHARGE, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = regval;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ ret = regmap_read(chip->regmap, REG_FLAGS, &regval);
+ if (ret < 0)
+ return ret;
+
+ if (regval & MM8013_FLAG_CHG_INH)
+ val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
+ else
+ val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ ret = regmap_read(chip->regmap, REG_FULL_CHARGE_CAPACITY, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = 1000 * regval;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ ret = regmap_read(chip->regmap, REG_DESIGN_CAPACITY, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = 1000 * regval;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ ret = regmap_read(chip->regmap, REG_NOMINAL_CHARGE_CAPACITY, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = 1000 * regval;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ ret = regmap_read(chip->regmap, REG_MAX_LOAD_CURRENT, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = -1000 * (s16)regval;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ ret = regmap_read(chip->regmap, REG_AVERAGE_CURRENT, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = -1000 * (s16)regval;
+ break;
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ ret = regmap_read(chip->regmap, REG_CYCLE_COUNT, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = regval;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = regmap_read(chip->regmap, REG_FLAGS, &regval);
+ if (ret < 0)
+ return ret;
+
+ if (regval & MM8013_FLAG_UT)
+ val->intval = POWER_SUPPLY_HEALTH_COLD;
+ else if (regval & (MM8013_FLAG_ODC | MM8013_FLAG_OCC))
+ val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT;
+ else if (regval & (MM8013_FLAG_BATLOW))
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ else if (regval & MM8013_FLAG_BATHI)
+ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ else if (regval & (MM8013_FLAG_OT | MM8013_FLAG_OTD | MM8013_FLAG_OTC))
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ ret = regmap_read(chip->regmap, REG_TEMPERATURE, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = ((s16)regval > 0);
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = regmap_read(chip->regmap, REG_FLAGS, &regval);
+ if (ret < 0)
+ return ret;
+
+ if (regval & MM8013_FLAG_DSG)
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (regval & MM8013_FLAG_CHG)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else if (regval & MM8013_FLAG_FC)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ ret = regmap_read(chip->regmap, REG_TEMPERATURE, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = DECIKELVIN_TO_DECIDEGC(regval);
+ break;
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+ ret = regmap_read(chip->regmap, REG_AVERAGE_TIME_TO_EMPTY, &regval);
+ if (ret < 0)
+ return ret;
+
+ /* The estimation is not yet ready */
+ if (regval == U16_MAX)
+ return -ENODATA;
+
+ val->intval = regval;
+ break;
+ case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+ ret = regmap_read(chip->regmap, REG_AVERAGE_TIME_TO_FULL, &regval);
+ if (ret < 0)
+ return ret;
+
+ /* The estimation is not yet ready */
+ if (regval == U16_MAX)
+ return -ENODATA;
+
+ val->intval = regval;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ ret = regmap_read(chip->regmap, REG_VOLTAGE, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = 1000 * regval;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct power_supply_desc mm8013_desc = {
+ .name = "mm8013",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = mm8013_battery_props,
+ .num_properties = ARRAY_SIZE(mm8013_battery_props),
+ .get_property = mm8013_get_property,
+};
+
+static const struct regmap_config mm8013_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = 0x68,
+ .use_single_read = true,
+ .use_single_write = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static int mm8013_probe(struct i2c_client *client)
+{
+ struct power_supply_config psy_cfg = {};
+ struct device *dev = &client->dev;
+ struct power_supply *psy;
+ struct mm8013_chip *chip;
+ int ret = 0;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return dev_err_probe(dev, -EIO,
+ "I2C_FUNC_SMBUS_WORD_DATA not supported\n");
+
+ chip = devm_kzalloc(dev, sizeof(struct mm8013_chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->client = client;
+
+ chip->regmap = devm_regmap_init_i2c(client, &mm8013_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ ret = PTR_ERR(chip->regmap);
+ return dev_err_probe(dev, ret, "Couldn't initialize regmap\n");
+ }
+
+ ret = mm8013_checkdevice(chip);
+ if (ret)
+ return dev_err_probe(dev, ret, "MM8013 not found\n");
+
+ psy_cfg.drv_data = chip;
+ psy_cfg.of_node = dev->of_node;
+
+ psy = devm_power_supply_register(dev, &mm8013_desc, &psy_cfg);
+ if (IS_ERR(psy))
+ return PTR_ERR(psy);
+
+ return 0;
+}
+
+static const struct i2c_device_id mm8013_id_table[] = {
+ { "mm8013", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mm8013_id_table);
+
+static const struct of_device_id mm8013_match_table[] = {
+ { .compatible = "mitsumi,mm8013" },
+ {}
+};
+
+static struct i2c_driver mm8013_i2c_driver = {
+ .probe = mm8013_probe,
+ .id_table = mm8013_id_table,
+ .driver = {
+ .name = "mm8013",
+ .of_match_table = mm8013_match_table,
+ },
+};
+module_i2c_driver(mm8013_i2c_driver);
+
+MODULE_DESCRIPTION("MM8013 fuel gauge driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c
index a9641bd3d..e24fce087 100644
--- a/drivers/power/supply/mt6370-charger.c
+++ b/drivers/power/supply/mt6370-charger.c
@@ -849,9 +849,7 @@ static int mt6370_chg_init_irq(struct mt6370_priv *priv)
ret = platform_get_irq_byname(to_platform_device(priv->dev),
mt6370_chg_irqs[i].name);
if (ret < 0)
- return dev_err_probe(priv->dev, ret,
- "Failed to get irq %s\n",
- mt6370_chg_irqs[i].name);
+ return ret;
priv->irq_nums[i] = ret;
ret = devm_request_threaded_irq(priv->dev, ret, NULL,
diff --git a/drivers/power/supply/pcf50633-charger.c b/drivers/power/supply/pcf50633-charger.c
index fd44cb8ac..950e30917 100644
--- a/drivers/power/supply/pcf50633-charger.c
+++ b/drivers/power/supply/pcf50633-charger.c
@@ -441,7 +441,7 @@ static int pcf50633_mbc_probe(struct platform_device *pdev)
return 0;
}
-static int pcf50633_mbc_remove(struct platform_device *pdev)
+static void pcf50633_mbc_remove(struct platform_device *pdev)
{
struct pcf50633_mbc *mbc = platform_get_drvdata(pdev);
int i;
@@ -453,8 +453,6 @@ static int pcf50633_mbc_remove(struct platform_device *pdev)
power_supply_unregister(mbc->usb);
power_supply_unregister(mbc->adapter);
power_supply_unregister(mbc->ac);
-
- return 0;
}
static struct platform_driver pcf50633_mbc_driver = {
@@ -462,7 +460,7 @@ static struct platform_driver pcf50633_mbc_driver = {
.name = "pcf50633-mbc",
},
.probe = pcf50633_mbc_probe,
- .remove = pcf50633_mbc_remove,
+ .remove_new = pcf50633_mbc_remove,
};
module_platform_driver(pcf50633_mbc_driver);
diff --git a/drivers/power/supply/pm8916_bms_vm.c b/drivers/power/supply/pm8916_bms_vm.c
new file mode 100644
index 000000000..5d0dd8425
--- /dev/null
+++ b/drivers/power/supply/pm8916_bms_vm.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, Nikita Travkin <nikita@trvn.ru>
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/timekeeping.h>
+#include <linux/mod_devicetable.h>
+
+#define PM8916_PERPH_TYPE 0x04
+#define PM8916_BMS_VM_TYPE 0x020D
+
+#define PM8916_SEC_ACCESS 0xD0
+#define PM8916_SEC_MAGIC 0xA5
+
+#define PM8916_BMS_VM_STATUS1 0x08
+#define PM8916_BMS_VM_FSM_STATE(x) (((x) & 0b00111000) >> 3)
+#define PM8916_BMS_VM_FSM_STATE_S2 0x2
+
+#define PM8916_BMS_VM_MODE_CTL 0x40
+#define PM8916_BMS_VM_MODE_FORCE_S3 (BIT(0) | BIT(1))
+#define PM8916_BMS_VM_MODE_NORMAL (BIT(1) | BIT(3))
+
+#define PM8916_BMS_VM_EN_CTL 0x46
+#define PM8916_BMS_ENABLED BIT(7)
+
+#define PM8916_BMS_VM_FIFO_LENGTH_CTL 0x47
+#define PM8916_BMS_VM_S1_SAMPLE_INTERVAL_CTL 0x55
+#define PM8916_BMS_VM_S2_SAMPLE_INTERVAL_CTL 0x56
+#define PM8916_BMS_VM_S3_S7_OCV_DATA0 0x6A
+#define PM8916_BMS_VM_BMS_FIFO_REG_0_LSB 0xC0
+
+/* Using only 1 fifo is broken in hardware */
+#define PM8916_BMS_VM_FIFO_COUNT 2 /* 2 .. 8 */
+
+#define PM8916_BMS_VM_S1_SAMPLE_INTERVAL 10
+#define PM8916_BMS_VM_S2_SAMPLE_INTERVAL 10
+
+struct pm8916_bms_vm_battery {
+ struct device *dev;
+ struct power_supply *battery;
+ struct power_supply_battery_info *info;
+ struct regmap *regmap;
+ unsigned int reg;
+ unsigned int last_ocv;
+ time64_t last_ocv_time;
+ unsigned int vbat_now;
+};
+
+static int pm8916_bms_vm_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pm8916_bms_vm_battery *bat = power_supply_get_drvdata(psy);
+ struct power_supply_battery_info *info = bat->info;
+ int supplied;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ supplied = power_supply_am_i_supplied(psy);
+
+ if (supplied < 0 && supplied != -ENODEV)
+ return supplied;
+ else if (supplied && supplied != -ENODEV)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ return 0;
+
+ case POWER_SUPPLY_PROP_HEALTH:
+ if (bat->vbat_now < info->voltage_min_design_uv)
+ val->intval = POWER_SUPPLY_HEALTH_DEAD;
+ else if (bat->vbat_now > info->voltage_max_design_uv)
+ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ else
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ return 0;
+
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = bat->vbat_now;
+ return 0;
+
+ case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+ /*
+ * Hardware only reliably measures OCV when the system is off or suspended.
+ * We expose the last known OCV value on boot, invalidating it after 180 seconds.
+ */
+ if (ktime_get_seconds() - bat->last_ocv_time > 180)
+ return -ENODATA;
+
+ val->intval = bat->last_ocv;
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static enum power_supply_property pm8916_bms_vm_battery_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_OCV,
+ POWER_SUPPLY_PROP_HEALTH,
+};
+
+static irqreturn_t pm8916_bms_vm_fifo_update_done_irq(int irq, void *data)
+{
+ struct pm8916_bms_vm_battery *bat = data;
+ u16 vbat_data[PM8916_BMS_VM_FIFO_COUNT];
+ int ret;
+
+ ret = regmap_bulk_read(bat->regmap, bat->reg + PM8916_BMS_VM_BMS_FIFO_REG_0_LSB,
+ &vbat_data, PM8916_BMS_VM_FIFO_COUNT * 2);
+ if (ret)
+ return IRQ_HANDLED;
+
+ /*
+ * The VM-BMS hardware only collects voltage data and the software
+ * has to process it to calculate the OCV and SoC. Hardware provides
+ * up to 8 averaged measurements for software to take in account.
+ *
+ * Just use the last measured value for now to report the current
+ * battery voltage.
+ */
+ bat->vbat_now = vbat_data[PM8916_BMS_VM_FIFO_COUNT - 1] * 300;
+
+ power_supply_changed(bat->battery);
+
+ return IRQ_HANDLED;
+}
+
+static const struct power_supply_desc pm8916_bms_vm_battery_psy_desc = {
+ .name = "pm8916-bms-vm",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = pm8916_bms_vm_battery_properties,
+ .num_properties = ARRAY_SIZE(pm8916_bms_vm_battery_properties),
+ .get_property = pm8916_bms_vm_battery_get_property,
+};
+
+static int pm8916_bms_vm_battery_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pm8916_bms_vm_battery *bat;
+ struct power_supply_config psy_cfg = {};
+ int ret, irq;
+ unsigned int tmp;
+
+ bat = devm_kzalloc(dev, sizeof(*bat), GFP_KERNEL);
+ if (!bat)
+ return -ENOMEM;
+
+ bat->dev = dev;
+
+ bat->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!bat->regmap)
+ return -ENODEV;
+
+ ret = device_property_read_u32(dev, "reg", &bat->reg);
+ if (ret < 0)
+ return -EINVAL;
+
+ irq = platform_get_irq_byname(pdev, "fifo");
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_bms_vm_fifo_update_done_irq,
+ IRQF_ONESHOT, "pm8916_vm_bms", bat);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(bat->regmap, bat->reg + PM8916_PERPH_TYPE, &tmp, 2);
+ if (ret)
+ goto comm_error;
+
+ if (tmp != PM8916_BMS_VM_TYPE)
+ return dev_err_probe(dev, -ENODEV, "Device reported wrong type: 0x%X\n", tmp);
+
+ ret = regmap_write(bat->regmap, bat->reg + PM8916_BMS_VM_S1_SAMPLE_INTERVAL_CTL,
+ PM8916_BMS_VM_S1_SAMPLE_INTERVAL);
+ if (ret)
+ goto comm_error;
+ ret = regmap_write(bat->regmap, bat->reg + PM8916_BMS_VM_S2_SAMPLE_INTERVAL_CTL,
+ PM8916_BMS_VM_S2_SAMPLE_INTERVAL);
+ if (ret)
+ goto comm_error;
+ ret = regmap_write(bat->regmap, bat->reg + PM8916_BMS_VM_FIFO_LENGTH_CTL,
+ PM8916_BMS_VM_FIFO_COUNT << 4 | PM8916_BMS_VM_FIFO_COUNT);
+ if (ret)
+ goto comm_error;
+ ret = regmap_write(bat->regmap,
+ bat->reg + PM8916_BMS_VM_EN_CTL, PM8916_BMS_ENABLED);
+ if (ret)
+ goto comm_error;
+
+ ret = regmap_bulk_read(bat->regmap,
+ bat->reg + PM8916_BMS_VM_S3_S7_OCV_DATA0, &tmp, 2);
+ if (ret)
+ goto comm_error;
+
+ bat->last_ocv_time = ktime_get_seconds();
+ bat->last_ocv = tmp * 300;
+ bat->vbat_now = bat->last_ocv;
+
+ psy_cfg.drv_data = bat;
+ psy_cfg.of_node = dev->of_node;
+
+ bat->battery = devm_power_supply_register(dev, &pm8916_bms_vm_battery_psy_desc, &psy_cfg);
+ if (IS_ERR(bat->battery))
+ return dev_err_probe(dev, PTR_ERR(bat->battery), "Unable to register battery\n");
+
+ ret = power_supply_get_battery_info(bat->battery, &bat->info);
+ if (ret)
+ return dev_err_probe(dev, ret, "Unable to get battery info\n");
+
+ platform_set_drvdata(pdev, bat);
+
+ return 0;
+
+comm_error:
+ return dev_err_probe(dev, ret, "Unable to communicate with device\n");
+}
+
+static int pm8916_bms_vm_battery_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct pm8916_bms_vm_battery *bat = platform_get_drvdata(pdev);
+ int ret;
+
+ /*
+ * Due to a hardware quirk the FSM doesn't switch states normally.
+ * Instead we unlock the debug registers and force S3 (Measure OCV/Sleep)
+ * mode every time we suspend.
+ */
+
+ ret = regmap_write(bat->regmap,
+ bat->reg + PM8916_SEC_ACCESS, PM8916_SEC_MAGIC);
+ if (ret)
+ goto error;
+ ret = regmap_write(bat->regmap,
+ bat->reg + PM8916_BMS_VM_MODE_CTL, PM8916_BMS_VM_MODE_FORCE_S3);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ dev_err(bat->dev, "Failed to force S3 mode: %pe\n", ERR_PTR(ret));
+ return ret;
+}
+
+static int pm8916_bms_vm_battery_resume(struct platform_device *pdev)
+{
+ struct pm8916_bms_vm_battery *bat = platform_get_drvdata(pdev);
+ int ret;
+ unsigned int tmp;
+
+ ret = regmap_bulk_read(bat->regmap,
+ bat->reg + PM8916_BMS_VM_S3_S7_OCV_DATA0, &tmp, 2);
+
+ bat->last_ocv_time = ktime_get_seconds();
+ bat->last_ocv = tmp * 300;
+
+ ret = regmap_write(bat->regmap,
+ bat->reg + PM8916_SEC_ACCESS, PM8916_SEC_MAGIC);
+ if (ret)
+ goto error;
+ ret = regmap_write(bat->regmap,
+ bat->reg + PM8916_BMS_VM_MODE_CTL, PM8916_BMS_VM_MODE_NORMAL);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ dev_err(bat->dev, "Failed to return normal mode: %pe\n", ERR_PTR(ret));
+ return ret;
+}
+
+static const struct of_device_id pm8916_bms_vm_battery_of_match[] = {
+ { .compatible = "qcom,pm8916-bms-vm", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pm8916_bms_vm_battery_of_match);
+
+static struct platform_driver pm8916_bms_vm_battery_driver = {
+ .driver = {
+ .name = "pm8916-bms-vm",
+ .of_match_table = pm8916_bms_vm_battery_of_match,
+ },
+ .probe = pm8916_bms_vm_battery_probe,
+ .suspend = pm8916_bms_vm_battery_suspend,
+ .resume = pm8916_bms_vm_battery_resume,
+};
+module_platform_driver(pm8916_bms_vm_battery_driver);
+
+MODULE_DESCRIPTION("pm8916 BMS-VM driver");
+MODULE_AUTHOR("Nikita Travkin <nikita@trvn.ru>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
new file mode 100644
index 000000000..6d92e98cb
--- /dev/null
+++ b/drivers/power/supply/pm8916_lbc.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, Nikita Travkin <nikita@trvn.ru>
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/extcon-provider.h>
+#include <linux/mod_devicetable.h>
+
+/* Two bytes: type + subtype */
+#define PM8916_PERPH_TYPE 0x04
+#define PM8916_LBC_CHGR_TYPE 0x1502
+#define PM8916_LBC_BAT_IF_TYPE 0x1602
+#define PM8916_LBC_USB_TYPE 0x1702
+#define PM8916_LBC_MISC_TYPE 0x1802
+
+#define PM8916_LBC_CHGR_CHG_OPTION 0x08
+#define PM8916_LBC_CHGR_PMIC_CHARGER BIT(7)
+
+#define PM8916_LBC_CHGR_CHG_STATUS 0x09
+
+#define PM8916_INT_RT_STS 0x10
+
+#define PM8916_LBC_USB_USBIN_VALID BIT(1)
+
+#define PM8916_LBC_CHGR_VDD_MAX 0x40
+#define PM8916_LBC_CHGR_VDD_SAFE 0x41
+#define PM8916_LBC_CHGR_IBAT_MAX 0x44
+#define PM8916_LBC_CHGR_IBAT_SAFE 0x45
+
+#define PM8916_LBC_CHGR_TCHG_MAX_EN 0x60
+#define PM8916_LBC_CHGR_TCHG_MAX_ENABLED BIT(7)
+#define PM8916_LBC_CHGR_TCHG_MAX 0x61
+
+#define PM8916_LBC_CHGR_CHG_CTRL 0x49
+#define PM8916_LBC_CHGR_CHG_EN BIT(7)
+#define PM8916_LBC_CHGR_PSTG_EN BIT(5)
+
+#define PM8916_LBC_CHGR_MIN_CURRENT 90000
+#define PM8916_LBC_CHGR_MAX_CURRENT 1440000
+
+#define PM8916_LBC_CHGR_MIN_VOLTAGE 4000000
+#define PM8916_LBC_CHGR_MAX_VOLTAGE 4775000
+#define PM8916_LBC_CHGR_VOLTAGE_STEP 25000
+
+#define PM8916_LBC_CHGR_MIN_TIME 4
+#define PM8916_LBC_CHGR_MAX_TIME 256
+
+struct pm8916_lbc_charger {
+ struct device *dev;
+ struct extcon_dev *edev;
+ struct power_supply *charger;
+ struct power_supply_battery_info *info;
+ struct regmap *regmap;
+ unsigned int reg[4];
+ bool online;
+ unsigned int charge_voltage_max;
+ unsigned int charge_voltage_safe;
+ unsigned int charge_current_max;
+ unsigned int charge_current_safe;
+};
+
+static const unsigned int pm8916_lbc_charger_cable[] = {
+ EXTCON_USB,
+ EXTCON_NONE,
+};
+
+enum {
+ LBC_CHGR = 0,
+ LBC_BAT_IF,
+ LBC_USB,
+ LBC_MISC,
+};
+
+static int pm8916_lbc_charger_configure(struct pm8916_lbc_charger *chg)
+{
+ int ret = 0;
+ unsigned int tmp;
+
+ chg->charge_voltage_max = clamp_t(u32, chg->charge_voltage_max,
+ PM8916_LBC_CHGR_MIN_VOLTAGE, chg->charge_voltage_safe);
+
+ tmp = chg->charge_voltage_max - PM8916_LBC_CHGR_MIN_VOLTAGE;
+ tmp /= PM8916_LBC_CHGR_VOLTAGE_STEP;
+ chg->charge_voltage_max = PM8916_LBC_CHGR_MIN_VOLTAGE + tmp * PM8916_LBC_CHGR_VOLTAGE_STEP;
+
+ ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_VDD_MAX, tmp);
+ if (ret)
+ goto error;
+
+ chg->charge_current_max = min(chg->charge_current_max, chg->charge_current_safe);
+
+ tmp = clamp_t(u32, chg->charge_current_max,
+ PM8916_LBC_CHGR_MIN_CURRENT, PM8916_LBC_CHGR_MAX_CURRENT);
+
+ tmp = chg->charge_current_max / PM8916_LBC_CHGR_MIN_CURRENT - 1;
+ chg->charge_current_max = (tmp + 1) * PM8916_LBC_CHGR_MIN_CURRENT;
+
+ ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_IBAT_MAX, tmp);
+ if (ret)
+ goto error;
+
+ ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_CHG_CTRL,
+ PM8916_LBC_CHGR_CHG_EN | PM8916_LBC_CHGR_PSTG_EN);
+ if (ret)
+ goto error;
+
+ return ret;
+
+error:
+ dev_err(chg->dev, "Failed to configure charging: %pe\n", ERR_PTR(ret));
+ return ret;
+}
+
+static int pm8916_lbc_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pm8916_lbc_charger *chg = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = chg->online;
+ return 0;
+
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+ val->intval = chg->charge_voltage_max;
+ return 0;
+
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ val->intval = chg->charge_current_max;
+ return 0;
+
+ default:
+ return -EINVAL;
+ };
+}
+
+static int pm8916_lbc_charger_set_property(struct power_supply *psy,
+ enum power_supply_property prop,
+ const union power_supply_propval *val)
+{
+ struct pm8916_lbc_charger *chg = power_supply_get_drvdata(psy);
+
+ switch (prop) {
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ chg->charge_current_max = val->intval;
+ return pm8916_lbc_charger_configure(chg);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int pm8916_lbc_charger_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static enum power_supply_property pm8916_lbc_charger_properties[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+};
+
+static irqreturn_t pm8916_lbc_charger_state_changed_irq(int irq, void *data)
+{
+ struct pm8916_lbc_charger *chg = data;
+ unsigned int tmp;
+ int ret;
+
+ ret = regmap_read(chg->regmap, chg->reg[LBC_USB] + PM8916_INT_RT_STS, &tmp);
+ if (ret)
+ return IRQ_HANDLED;
+
+ chg->online = !!(tmp & PM8916_LBC_USB_USBIN_VALID);
+ extcon_set_state_sync(chg->edev, EXTCON_USB, chg->online);
+
+ power_supply_changed(chg->charger);
+
+ return IRQ_HANDLED;
+}
+
+static int pm8916_lbc_charger_probe_dt(struct pm8916_lbc_charger *chg)
+{
+ struct device *dev = chg->dev;
+ int ret = 0;
+ unsigned int tmp;
+
+ ret = device_property_read_u32(dev, "qcom,fast-charge-safe-voltage", &chg->charge_voltage_safe);
+ if (ret)
+ return ret;
+ if (chg->charge_voltage_safe < PM8916_LBC_CHGR_MIN_VOLTAGE)
+ return -EINVAL;
+
+ chg->charge_voltage_safe = clamp_t(u32, chg->charge_voltage_safe,
+ PM8916_LBC_CHGR_MIN_VOLTAGE, PM8916_LBC_CHGR_MAX_VOLTAGE);
+
+ tmp = chg->charge_voltage_safe - PM8916_LBC_CHGR_MIN_VOLTAGE;
+ tmp /= PM8916_LBC_CHGR_VOLTAGE_STEP;
+ ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_VDD_SAFE, tmp);
+ if (ret)
+ return ret;
+
+ ret = device_property_read_u32(dev, "qcom,fast-charge-safe-current", &chg->charge_current_safe);
+ if (ret)
+ return ret;
+ if (chg->charge_current_safe < PM8916_LBC_CHGR_MIN_CURRENT)
+ return -EINVAL;
+
+ chg->charge_current_safe = clamp_t(u32, chg->charge_current_safe,
+ PM8916_LBC_CHGR_MIN_CURRENT, PM8916_LBC_CHGR_MAX_CURRENT);
+
+ chg->charge_current_max = chg->charge_current_safe;
+
+ tmp = chg->charge_current_safe / PM8916_LBC_CHGR_MIN_CURRENT - 1;
+ ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_IBAT_SAFE, tmp);
+ if (ret)
+ return ret;
+
+ /* Disable charger timeout. */
+ ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_TCHG_MAX_EN, 0x00);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static const struct power_supply_desc pm8916_lbc_charger_psy_desc = {
+ .name = "pm8916-lbc-chgr",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = pm8916_lbc_charger_properties,
+ .num_properties = ARRAY_SIZE(pm8916_lbc_charger_properties),
+ .get_property = pm8916_lbc_charger_get_property,
+ .set_property = pm8916_lbc_charger_set_property,
+ .property_is_writeable = pm8916_lbc_charger_property_is_writeable,
+};
+
+static int pm8916_lbc_charger_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pm8916_lbc_charger *chg;
+ struct power_supply_config psy_cfg = {};
+ int ret, len, irq;
+ unsigned int tmp;
+
+ chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
+ if (!chg)
+ return -ENOMEM;
+
+ chg->dev = dev;
+
+ chg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!chg->regmap)
+ return -ENODEV;
+
+ len = device_property_count_u32(dev, "reg");
+ if (len < 0)
+ return len;
+ if (len != 4)
+ return dev_err_probe(dev, -EINVAL,
+ "Wrong amount of reg values: %d (4 expected)\n", len);
+
+ irq = platform_get_irq_byname(pdev, "usb_vbus");
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
+ IRQF_ONESHOT, "pm8916_lbc", chg);
+ if (ret)
+ return ret;
+
+ ret = device_property_read_u32_array(dev, "reg", chg->reg, len);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_CHGR] + PM8916_PERPH_TYPE, &tmp, 2);
+ if (ret)
+ goto comm_error;
+ if (tmp != PM8916_LBC_CHGR_TYPE)
+ goto type_error;
+
+ ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_BAT_IF] + PM8916_PERPH_TYPE, &tmp, 2);
+ if (ret)
+ goto comm_error;
+ if (tmp != PM8916_LBC_BAT_IF_TYPE)
+ goto type_error;
+
+ ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_USB] + PM8916_PERPH_TYPE, &tmp, 2);
+ if (ret)
+ goto comm_error;
+ if (tmp != PM8916_LBC_USB_TYPE)
+ goto type_error;
+
+ ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_MISC] + PM8916_PERPH_TYPE, &tmp, 2);
+ if (ret)
+ goto comm_error;
+ if (tmp != PM8916_LBC_MISC_TYPE)
+ goto type_error;
+
+ ret = regmap_read(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_CHG_OPTION, &tmp);
+ if (ret)
+ goto comm_error;
+ if (tmp != PM8916_LBC_CHGR_PMIC_CHARGER)
+ dev_err_probe(dev, -ENODEV, "The system is using an external charger\n");
+
+ ret = pm8916_lbc_charger_probe_dt(chg);
+ if (ret)
+ dev_err_probe(dev, ret, "Error while parsing device tree\n");
+
+ psy_cfg.drv_data = chg;
+ psy_cfg.of_node = dev->of_node;
+
+ chg->charger = devm_power_supply_register(dev, &pm8916_lbc_charger_psy_desc, &psy_cfg);
+ if (IS_ERR(chg->charger))
+ return dev_err_probe(dev, PTR_ERR(chg->charger), "Unable to register charger\n");
+
+ ret = power_supply_get_battery_info(chg->charger, &chg->info);
+ if (ret)
+ return dev_err_probe(dev, ret, "Unable to get battery info\n");
+
+ chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable);
+ if (IS_ERR(chg->edev))
+ return PTR_ERR(chg->edev);
+
+ ret = devm_extcon_dev_register(dev, chg->edev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to register extcon device\n");
+
+ ret = regmap_read(chg->regmap, chg->reg[LBC_USB] + PM8916_INT_RT_STS, &tmp);
+ if (ret)
+ goto comm_error;
+
+ chg->online = !!(tmp & PM8916_LBC_USB_USBIN_VALID);
+ extcon_set_state_sync(chg->edev, EXTCON_USB, chg->online);
+
+ chg->charge_voltage_max = chg->info->voltage_max_design_uv;
+ ret = pm8916_lbc_charger_configure(chg);
+ if (ret)
+ return ret;
+
+ return 0;
+
+comm_error:
+ return dev_err_probe(dev, ret, "Unable to communicate with device\n");
+
+type_error:
+ return dev_err_probe(dev, -ENODEV, "Device reported wrong type: 0x%X\n", tmp);
+}
+
+static const struct of_device_id pm8916_lbc_charger_of_match[] = {
+ { .compatible = "qcom,pm8916-lbc", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pm8916_lbc_charger_of_match);
+
+static struct platform_driver pm8916_lbc_charger_driver = {
+ .driver = {
+ .name = "pm8916-lbc",
+ .of_match_table = pm8916_lbc_charger_of_match,
+ },
+ .probe = pm8916_lbc_charger_probe,
+};
+module_platform_driver(pm8916_lbc_charger_driver);
+
+MODULE_DESCRIPTION("pm8916 LBC driver");
+MODULE_AUTHOR("Nikita Travkin <nikita@trvn.ru>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 416409e2f..73265001d 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -29,8 +29,7 @@
struct class *power_supply_class;
EXPORT_SYMBOL_GPL(power_supply_class);
-BLOCKING_NOTIFIER_HEAD(power_supply_notifier);
-EXPORT_SYMBOL_GPL(power_supply_notifier);
+static BLOCKING_NOTIFIER_HEAD(power_supply_notifier);
static struct device_type power_supply_dev_type;
@@ -1380,6 +1379,7 @@ __power_supply_register(struct device *parent,
psy->drv_data = cfg->drv_data;
psy->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;
}
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index d483a8156..977611e16 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -15,6 +15,7 @@
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/string_helpers.h>
#include "power_supply.h"
@@ -398,14 +399,6 @@ static const struct attribute_group *power_supply_attr_groups[] = {
NULL,
};
-static void str_to_lower(char *str)
-{
- while (*str) {
- *str = tolower(*str);
- str++;
- }
-}
-
void power_supply_init_attrs(struct device_type *dev_type)
{
int i;
@@ -420,7 +413,8 @@ void power_supply_init_attrs(struct device_type *dev_type)
__func__, i);
sprintf(power_supply_attrs[i].attr_name, "_err_%d", i);
} else {
- str_to_lower(power_supply_attrs[i].attr_name);
+ string_lower(power_supply_attrs[i].attr_name,
+ power_supply_attrs[i].attr_name);
}
attr = &power_supply_attrs[i].dev_attr;
diff --git a/drivers/power/supply/qcom_pmi8998_charger.c b/drivers/power/supply/qcom_pmi8998_charger.c
index 22c7c0e7c..9bb777406 100644
--- a/drivers/power/supply/qcom_pmi8998_charger.c
+++ b/drivers/power/supply/qcom_pmi8998_charger.c
@@ -915,8 +915,7 @@ static int smb2_init_irq(struct smb2_chip *chip, int *irq, const char *name,
irqnum = platform_get_irq_byname(to_platform_device(chip->dev), name);
if (irqnum < 0)
- return dev_err_probe(chip->dev, irqnum,
- "Couldn't get irq %s byname\n", name);
+ return irqnum;
rc = devm_request_threaded_irq(chip->dev, irqnum, NULL, handler,
IRQF_ONESHOT, name, chip);
diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c
index bd50124ee..4e57762e2 100644
--- a/drivers/power/supply/qcom_smbb.c
+++ b/drivers/power/supply/qcom_smbb.c
@@ -1000,15 +1000,13 @@ static int smbb_charger_probe(struct platform_device *pdev)
return 0;
}
-static int smbb_charger_remove(struct platform_device *pdev)
+static void smbb_charger_remove(struct platform_device *pdev)
{
struct smbb_charger *chg;
chg = platform_get_drvdata(pdev);
regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0);
-
- return 0;
}
static const struct of_device_id smbb_charger_id_table[] = {
@@ -1020,7 +1018,7 @@ MODULE_DEVICE_TABLE(of, smbb_charger_id_table);
static struct platform_driver smbb_charger_driver = {
.probe = smbb_charger_probe,
- .remove = smbb_charger_remove,
+ .remove_new = smbb_charger_remove,
.driver = {
.name = "qcom-smbb",
.of_match_table = smbb_charger_id_table,
diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c
index f64daf5a4..7ca91739c 100644
--- a/drivers/power/supply/rk817_charger.c
+++ b/drivers/power/supply/rk817_charger.c
@@ -1207,11 +1207,24 @@ static int rk817_charger_probe(struct platform_device *pdev)
return 0;
}
+static int __maybe_unused rk817_resume(struct device *dev)
+{
+
+ struct rk817_charger *charger = dev_get_drvdata(dev);
+
+ /* force an immediate update */
+ mod_delayed_work(system_wq, &charger->work, 0);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rk817_charger_pm, NULL, rk817_resume);
static struct platform_driver rk817_charger_driver = {
.probe = rk817_charger_probe,
.driver = {
.name = "rk817-charger",
+ .pm = &rk817_charger_pm,
},
};
module_platform_driver(rk817_charger_driver);
diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c
index c0c516f22..d19c7e80a 100644
--- a/drivers/power/supply/rt5033_charger.c
+++ b/drivers/power/supply/rt5033_charger.c
@@ -6,8 +6,12 @@
* Author: Beomho Seo <beomho.seo@samsung.com>
*/
+#include <linux/devm-helpers.h>
+#include <linux/extcon.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
@@ -25,7 +29,15 @@ struct rt5033_charger {
struct device *dev;
struct regmap *regmap;
struct power_supply *psy;
- struct rt5033_charger_data *chg;
+ struct rt5033_charger_data chg;
+ struct extcon_dev *edev;
+ struct notifier_block extcon_nb;
+ struct work_struct extcon_work;
+ struct mutex lock;
+ bool online;
+ bool otg;
+ bool mivr_enabled;
+ u8 cv_regval;
};
static int rt5033_get_charger_state(struct rt5033_charger *charger)
@@ -56,6 +68,10 @@ static int rt5033_get_charger_state(struct rt5033_charger *charger)
state = POWER_SUPPLY_STATUS_UNKNOWN;
}
+ /* For OTG mode, RT5033 would still report "charging" */
+ if (charger->otg)
+ state = POWER_SUPPLY_STATUS_DISCHARGING;
+
return state;
}
@@ -115,7 +131,7 @@ static int rt5033_get_charger_const_voltage(struct rt5033_charger *charger)
static inline int rt5033_init_const_charge(struct rt5033_charger *charger)
{
- struct rt5033_charger_data *chg = charger->chg;
+ struct rt5033_charger_data *chg = &charger->chg;
int ret;
unsigned int val;
u8 reg_data;
@@ -147,6 +163,9 @@ static inline int rt5033_init_const_charge(struct rt5033_charger *charger)
return -EINVAL;
}
+ /* Store that value for later usage */
+ charger->cv_regval = reg_data;
+
/* Set end of charge current */
if (chg->eoc_uamp < RT5033_CHARGER_EOC_MIN ||
chg->eoc_uamp > RT5033_CHARGER_EOC_MAX) {
@@ -186,7 +205,7 @@ static inline int rt5033_init_const_charge(struct rt5033_charger *charger)
static inline int rt5033_init_fast_charge(struct rt5033_charger *charger)
{
- struct rt5033_charger_data *chg = charger->chg;
+ struct rt5033_charger_data *chg = &charger->chg;
int ret;
unsigned int val;
u8 reg_data;
@@ -231,7 +250,7 @@ static inline int rt5033_init_fast_charge(struct rt5033_charger *charger)
static inline int rt5033_init_pre_charge(struct rt5033_charger *charger)
{
- struct rt5033_charger_data *chg = charger->chg;
+ struct rt5033_charger_data *chg = &charger->chg;
int ret;
unsigned int val;
u8 reg_data;
@@ -330,6 +349,162 @@ static int rt5033_charger_reg_init(struct rt5033_charger *charger)
return 0;
}
+static int rt5033_charger_set_otg(struct rt5033_charger *charger)
+{
+ int ret;
+
+ mutex_lock(&charger->lock);
+
+ /* Set OTG boost v_out to 5 volts */
+ ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2,
+ RT5033_CHGCTRL2_CV_MASK,
+ 0x37 << RT5033_CHGCTRL2_CV_SHIFT);
+ if (ret) {
+ dev_err(charger->dev, "Failed set OTG boost v_out\n");
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ /* Set operation mode to OTG */
+ ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1,
+ RT5033_CHGCTRL1_MODE_MASK, RT5033_BOOST_MODE);
+ if (ret) {
+ dev_err(charger->dev, "Failed to update OTG mode.\n");
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ /* In case someone switched from charging to OTG directly */
+ if (charger->online)
+ charger->online = false;
+
+ charger->otg = true;
+
+out_unlock:
+ mutex_unlock(&charger->lock);
+
+ return ret;
+}
+
+static int rt5033_charger_unset_otg(struct rt5033_charger *charger)
+{
+ int ret;
+ u8 data;
+
+ /* Restore constant voltage for charging */
+ data = charger->cv_regval;
+ ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2,
+ RT5033_CHGCTRL2_CV_MASK,
+ data << RT5033_CHGCTRL2_CV_SHIFT);
+ if (ret) {
+ dev_err(charger->dev, "Failed to restore constant voltage\n");
+ return -EINVAL;
+ }
+
+ /* Set operation mode to charging */
+ ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1,
+ RT5033_CHGCTRL1_MODE_MASK, RT5033_CHARGER_MODE);
+ if (ret) {
+ dev_err(charger->dev, "Failed to update charger mode.\n");
+ return -EINVAL;
+ }
+
+ charger->otg = false;
+
+ return 0;
+}
+
+static int rt5033_charger_set_charging(struct rt5033_charger *charger)
+{
+ int ret;
+
+ mutex_lock(&charger->lock);
+
+ /* In case someone switched from OTG to charging directly */
+ if (charger->otg) {
+ ret = rt5033_charger_unset_otg(charger);
+ if (ret) {
+ mutex_unlock(&charger->lock);
+ return -EINVAL;
+ }
+ }
+
+ charger->online = true;
+
+ mutex_unlock(&charger->lock);
+
+ return 0;
+}
+
+static int rt5033_charger_set_mivr(struct rt5033_charger *charger)
+{
+ int ret;
+
+ mutex_lock(&charger->lock);
+
+ /*
+ * When connected via USB connector type SDP (Standard Downstream Port),
+ * the minimum input voltage regulation (MIVR) should be enabled. It
+ * prevents an input voltage drop due to insufficient current provided
+ * by the adapter or USB input. As a downside, it may reduces the
+ * charging current and thus slows the charging.
+ */
+ ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4,
+ RT5033_CHGCTRL4_MIVR_MASK, RT5033_CHARGER_MIVR_4600MV);
+ if (ret) {
+ dev_err(charger->dev, "Failed to set MIVR level.\n");
+ mutex_unlock(&charger->lock);
+ return -EINVAL;
+ }
+
+ charger->mivr_enabled = true;
+
+ mutex_unlock(&charger->lock);
+
+ /* Beyond this, do the same steps like setting charging */
+ rt5033_charger_set_charging(charger);
+
+ return 0;
+}
+
+static int rt5033_charger_set_disconnect(struct rt5033_charger *charger)
+{
+ int ret = 0;
+
+ mutex_lock(&charger->lock);
+
+ /* Disable MIVR if enabled */
+ if (charger->mivr_enabled) {
+ ret = regmap_update_bits(charger->regmap,
+ RT5033_REG_CHG_CTRL4,
+ RT5033_CHGCTRL4_MIVR_MASK,
+ RT5033_CHARGER_MIVR_DISABLE);
+ if (ret) {
+ dev_err(charger->dev, "Failed to disable MIVR.\n");
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ charger->mivr_enabled = false;
+ }
+
+ if (charger->otg) {
+ ret = rt5033_charger_unset_otg(charger);
+ if (ret) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+ }
+
+ if (charger->online)
+ charger->online = false;
+
+out_unlock:
+ mutex_unlock(&charger->lock);
+
+ return ret;
+}
+
static enum power_supply_property rt5033_charger_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
@@ -366,8 +541,7 @@ static int rt5033_charger_get_property(struct power_supply *psy,
val->strval = RT5033_MANUFACTURER;
break;
case POWER_SUPPLY_PROP_ONLINE:
- val->intval = (rt5033_get_charger_state(charger) ==
- POWER_SUPPLY_STATUS_CHARGING);
+ val->intval = charger->online;
break;
default:
return -EINVAL;
@@ -376,21 +550,16 @@ static int rt5033_charger_get_property(struct power_supply *psy,
return 0;
}
-static struct rt5033_charger_data *rt5033_charger_dt_init(
- struct rt5033_charger *charger)
+static int rt5033_charger_dt_init(struct rt5033_charger *charger)
{
- struct rt5033_charger_data *chg;
+ struct rt5033_charger_data *chg = &charger->chg;
struct power_supply_battery_info *info;
int ret;
- chg = devm_kzalloc(charger->dev, sizeof(*chg), GFP_KERNEL);
- if (!chg)
- return ERR_PTR(-ENOMEM);
-
ret = power_supply_get_battery_info(charger->psy, &info);
if (ret)
- return ERR_PTR(dev_err_probe(charger->dev, -EINVAL,
- "missing battery info\n"));
+ return dev_err_probe(charger->dev, -EINVAL,
+ "missing battery info\n");
/* Assign data. Validity will be checked in the init functions. */
chg->pre_uamp = info->precharge_current_ua;
@@ -399,7 +568,87 @@ static struct rt5033_charger_data *rt5033_charger_dt_init(
chg->pre_uvolt = info->precharge_voltage_max_uv;
chg->const_uvolt = info->constant_charge_voltage_max_uv;
- return chg;
+ return 0;
+}
+
+static void rt5033_charger_extcon_work(struct work_struct *work)
+{
+ struct rt5033_charger *charger =
+ container_of(work, struct rt5033_charger, extcon_work);
+ struct extcon_dev *edev = charger->edev;
+ int connector, state;
+ int ret;
+
+ for (connector = EXTCON_USB_HOST; connector <= EXTCON_CHG_USB_PD;
+ connector++) {
+ state = extcon_get_state(edev, connector);
+ if (state == 1)
+ break;
+ }
+
+ /*
+ * Adding a delay between extcon notification and extcon action. This
+ * makes extcon action execution more reliable. Without the delay the
+ * execution sometimes fails, possibly because the chip is busy or not
+ * ready.
+ */
+ msleep(100);
+
+ switch (connector) {
+ case EXTCON_CHG_USB_SDP:
+ ret = rt5033_charger_set_mivr(charger);
+ if (ret) {
+ dev_err(charger->dev, "failed to set USB mode\n");
+ break;
+ }
+ dev_info(charger->dev, "USB mode. connector type: %d\n",
+ connector);
+ break;
+ case EXTCON_CHG_USB_DCP:
+ case EXTCON_CHG_USB_CDP:
+ case EXTCON_CHG_USB_ACA:
+ case EXTCON_CHG_USB_FAST:
+ case EXTCON_CHG_USB_SLOW:
+ case EXTCON_CHG_WPT:
+ case EXTCON_CHG_USB_PD:
+ ret = rt5033_charger_set_charging(charger);
+ if (ret) {
+ dev_err(charger->dev, "failed to set charging\n");
+ break;
+ }
+ dev_info(charger->dev, "charging. connector type: %d\n",
+ connector);
+ break;
+ case EXTCON_USB_HOST:
+ ret = rt5033_charger_set_otg(charger);
+ if (ret) {
+ dev_err(charger->dev, "failed to set OTG\n");
+ break;
+ }
+ dev_info(charger->dev, "OTG enabled\n");
+ break;
+ default:
+ ret = rt5033_charger_set_disconnect(charger);
+ if (ret) {
+ dev_err(charger->dev, "failed to set disconnect\n");
+ break;
+ }
+ dev_info(charger->dev, "disconnected\n");
+ break;
+ }
+
+ power_supply_changed(charger->psy);
+}
+
+static int rt5033_charger_extcon_notifier(struct notifier_block *nb,
+ unsigned long event, void *param)
+{
+ struct rt5033_charger *charger =
+ container_of(nb, struct rt5033_charger, extcon_nb);
+
+ schedule_work(&charger->extcon_work);
+
+ return NOTIFY_OK;
}
static const struct power_supply_desc rt5033_charger_desc = {
@@ -414,6 +663,7 @@ static int rt5033_charger_probe(struct platform_device *pdev)
{
struct rt5033_charger *charger;
struct power_supply_config psy_cfg = {};
+ struct device_node *np_conn, *np_edev;
int ret;
charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
@@ -423,25 +673,53 @@ static int rt5033_charger_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, charger);
charger->dev = &pdev->dev;
charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ mutex_init(&charger->lock);
psy_cfg.of_node = pdev->dev.of_node;
psy_cfg.drv_data = charger;
- charger->psy = devm_power_supply_register(&pdev->dev,
+ charger->psy = devm_power_supply_register(charger->dev,
&rt5033_charger_desc,
&psy_cfg);
if (IS_ERR(charger->psy))
- return dev_err_probe(&pdev->dev, PTR_ERR(charger->psy),
+ return dev_err_probe(charger->dev, PTR_ERR(charger->psy),
"Failed to register power supply\n");
- charger->chg = rt5033_charger_dt_init(charger);
- if (IS_ERR_OR_NULL(charger->chg))
- return PTR_ERR(charger->chg);
+ ret = rt5033_charger_dt_init(charger);
+ if (ret)
+ return ret;
ret = rt5033_charger_reg_init(charger);
if (ret)
return ret;
+ /*
+ * Extcon support is not vital for the charger to work. If no extcon
+ * is available, just emit a warning and leave the probe function.
+ */
+ np_conn = of_parse_phandle(pdev->dev.of_node, "richtek,usb-connector", 0);
+ np_edev = of_get_parent(np_conn);
+ charger->edev = extcon_find_edev_by_node(np_edev);
+ if (IS_ERR(charger->edev)) {
+ dev_warn(charger->dev, "no extcon device found in device-tree\n");
+ goto out;
+ }
+
+ ret = devm_work_autocancel(charger->dev, &charger->extcon_work,
+ rt5033_charger_extcon_work);
+ if (ret) {
+ dev_err(charger->dev, "failed to initialize extcon work\n");
+ return ret;
+ }
+
+ charger->extcon_nb.notifier_call = rt5033_charger_extcon_notifier;
+ ret = devm_extcon_register_notifier_all(charger->dev, charger->edev,
+ &charger->extcon_nb);
+ if (ret) {
+ dev_err(charger->dev, "failed to register extcon notifier\n");
+ return ret;
+ }
+out:
return 0;
}
diff --git a/drivers/power/supply/rx51_battery.c b/drivers/power/supply/rx51_battery.c
index 6e488ecf4..e2bfc81f0 100644
--- a/drivers/power/supply/rx51_battery.c
+++ b/drivers/power/supply/rx51_battery.c
@@ -246,7 +246,7 @@ error:
return ret;
}
-static int rx51_battery_remove(struct platform_device *pdev)
+static void rx51_battery_remove(struct platform_device *pdev)
{
struct rx51_device_info *di = platform_get_drvdata(pdev);
@@ -255,8 +255,6 @@ static int rx51_battery_remove(struct platform_device *pdev)
iio_channel_release(di->channel_vbat);
iio_channel_release(di->channel_bsi);
iio_channel_release(di->channel_temp);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -269,7 +267,7 @@ MODULE_DEVICE_TABLE(of, n900_battery_of_match);
static struct platform_driver rx51_battery_driver = {
.probe = rx51_battery_probe,
- .remove = rx51_battery_remove,
+ .remove_new = rx51_battery_remove,
.driver = {
.name = "rx51-battery",
.of_match_table = of_match_ptr(n900_battery_of_match),
diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index cdfc8466d..a6c204c08 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -1135,7 +1135,7 @@ static int sbs_probe(struct i2c_client *client)
if (!chip)
return -ENOMEM;
- chip->flags = (u32)(uintptr_t)device_get_match_data(&client->dev);
+ chip->flags = (uintptr_t)i2c_get_match_data(client);
chip->client = client;
psy_cfg.of_node = client->dev.of_node;
psy_cfg.drv_data = chip;
@@ -1253,9 +1253,9 @@ static SIMPLE_DEV_PM_OPS(sbs_pm_ops, sbs_suspend, NULL);
#endif
static const struct i2c_device_id sbs_id[] = {
- { "bq20z65", 0 },
- { "bq20z75", 0 },
- { "sbs-battery", 1 },
+ { "bq20z65", SBS_FLAGS_TI_BQ20ZX5 },
+ { "bq20z75", SBS_FLAGS_TI_BQ20ZX5 },
+ { "sbs-battery", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, sbs_id);
diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c
index 9ac17cf7a..b3d8b1ca9 100644
--- a/drivers/power/supply/sc2731_charger.c
+++ b/drivers/power/supply/sc2731_charger.c
@@ -511,13 +511,11 @@ static int sc2731_charger_probe(struct platform_device *pdev)
return 0;
}
-static int sc2731_charger_remove(struct platform_device *pdev)
+static void sc2731_charger_remove(struct platform_device *pdev)
{
struct sc2731_charger_info *info = platform_get_drvdata(pdev);
usb_unregister_notifier(info->usb_phy, &info->usb_notify);
-
- return 0;
}
static const struct of_device_id sc2731_charger_of_match[] = {
@@ -532,7 +530,7 @@ static struct platform_driver sc2731_charger_driver = {
.of_match_table = sc2731_charger_of_match,
},
.probe = sc2731_charger_probe,
- .remove = sc2731_charger_remove,
+ .remove_new = sc2731_charger_remove,
};
module_platform_driver(sc2731_charger_driver);
diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c
index 19d2f8834..196d290dc 100644
--- a/drivers/power/supply/surface_battery.c
+++ b/drivers/power/supply/surface_battery.c
@@ -722,7 +722,7 @@ static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_devic
struct ssam_event_registry registry, const char *name)
{
mutex_init(&bat->lock);
- strncpy(bat->name, name, ARRAY_SIZE(bat->name) - 1);
+ strscpy(bat->name, name, sizeof(bat->name));
bat->sdev = sdev;
diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c
index cabdd8da1..7a6c62d6f 100644
--- a/drivers/power/supply/surface_charger.c
+++ b/drivers/power/supply/surface_charger.c
@@ -175,7 +175,7 @@ static void spwr_ac_init(struct spwr_ac_device *ac, struct ssam_device *sdev,
struct ssam_event_registry registry, const char *name)
{
mutex_init(&ac->lock);
- strncpy(ac->name, name, ARRAY_SIZE(ac->name) - 1);
+ strscpy(ac->name, name, sizeof(ac->name));
ac->sdev = sdev;
diff --git a/drivers/power/supply/tps65090-charger.c b/drivers/power/supply/tps65090-charger.c
index f96c705e0..c59197d2a 100644
--- a/drivers/power/supply/tps65090-charger.c
+++ b/drivers/power/supply/tps65090-charger.c
@@ -328,15 +328,13 @@ fail_unregister_supply:
return ret;
}
-static int tps65090_charger_remove(struct platform_device *pdev)
+static void tps65090_charger_remove(struct platform_device *pdev)
{
struct tps65090_charger *cdata = platform_get_drvdata(pdev);
if (cdata->irq == -ENXIO)
kthread_stop(cdata->poll_task);
power_supply_unregister(cdata->ac);
-
- return 0;
}
static const struct of_device_id of_tps65090_charger_match[] = {
@@ -351,7 +349,7 @@ static struct platform_driver tps65090_charger_driver = {
.of_match_table = of_tps65090_charger_match,
},
.probe = tps65090_charger_probe,
- .remove = tps65090_charger_remove,
+ .remove_new = tps65090_charger_remove,
};
module_platform_driver(tps65090_charger_driver);
diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c
index 96341cbde..2382749a2 100644
--- a/drivers/power/supply/tps65217_charger.c
+++ b/drivers/power/supply/tps65217_charger.c
@@ -237,7 +237,7 @@ static int tps65217_charger_probe(struct platform_device *pdev)
for (i = 0; i < NUM_CHARGER_IRQS; i++) {
ret = devm_request_threaded_irq(&pdev->dev, irq[i], NULL,
tps65217_charger_irq,
- IRQF_ONESHOT, "tps65217-charger",
+ IRQF_SHARED, "tps65217-charger",
charger);
if (ret) {
dev_err(charger->dev,
@@ -253,14 +253,12 @@ static int tps65217_charger_probe(struct platform_device *pdev)
return 0;
}
-static int tps65217_charger_remove(struct platform_device *pdev)
+static void tps65217_charger_remove(struct platform_device *pdev)
{
struct tps65217_charger *charger = platform_get_drvdata(pdev);
if (charger->poll_task)
kthread_stop(charger->poll_task);
-
- return 0;
}
static const struct of_device_id tps65217_charger_match_table[] = {
@@ -271,7 +269,7 @@ MODULE_DEVICE_TABLE(of, tps65217_charger_match_table);
static struct platform_driver tps65217_charger_driver = {
.probe = tps65217_charger_probe,
- .remove = tps65217_charger_remove,
+ .remove_new = tps65217_charger_remove,
.driver = {
.name = "tps65217-charger",
.of_match_table = of_match_ptr(tps65217_charger_match_table),
diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c
index e78d061d8..7b9b0b3e1 100644
--- a/drivers/power/supply/twl4030_charger.c
+++ b/drivers/power/supply/twl4030_charger.c
@@ -1108,7 +1108,7 @@ static int twl4030_bci_probe(struct platform_device *pdev)
return 0;
}
-static int twl4030_bci_remove(struct platform_device *pdev)
+static void twl4030_bci_remove(struct platform_device *pdev)
{
struct twl4030_bci *bci = platform_get_drvdata(pdev);
@@ -1123,8 +1123,6 @@ static int twl4030_bci_remove(struct platform_device *pdev)
TWL4030_INTERRUPTS_BCIIMR1A);
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
TWL4030_INTERRUPTS_BCIIMR2A);
-
- return 0;
}
static const struct of_device_id twl_bci_of_match[] __maybe_unused = {
@@ -1135,7 +1133,7 @@ MODULE_DEVICE_TABLE(of, twl_bci_of_match);
static struct platform_driver twl4030_bci_driver = {
.probe = twl4030_bci_probe,
- .remove = twl4030_bci_remove,
+ .remove_new = twl4030_bci_remove,
.driver = {
.name = "twl4030_bci",
.of_match_table = of_match_ptr(twl_bci_of_match),
diff --git a/drivers/power/supply/twl4030_madc_battery.c b/drivers/power/supply/twl4030_madc_battery.c
index 7fe029673..33106476b 100644
--- a/drivers/power/supply/twl4030_madc_battery.c
+++ b/drivers/power/supply/twl4030_madc_battery.c
@@ -244,7 +244,7 @@ err:
return ret;
}
-static int twl4030_madc_battery_remove(struct platform_device *pdev)
+static void twl4030_madc_battery_remove(struct platform_device *pdev)
{
struct twl4030_madc_battery *bat = platform_get_drvdata(pdev);
@@ -253,8 +253,6 @@ static int twl4030_madc_battery_remove(struct platform_device *pdev)
iio_channel_release(bat->channel_vbat);
iio_channel_release(bat->channel_ichg);
iio_channel_release(bat->channel_temp);
-
- return 0;
}
static struct platform_driver twl4030_madc_battery_driver = {
@@ -262,7 +260,7 @@ static struct platform_driver twl4030_madc_battery_driver = {
.name = "twl4030_madc_battery",
},
.probe = twl4030_madc_battery_probe,
- .remove = twl4030_madc_battery_remove,
+ .remove_new = twl4030_madc_battery_remove,
};
module_platform_driver(twl4030_madc_battery_driver);
diff --git a/drivers/power/supply/wm831x_backup.c b/drivers/power/supply/wm831x_backup.c
index ffb265b85..1a7265660 100644
--- a/drivers/power/supply/wm831x_backup.c
+++ b/drivers/power/supply/wm831x_backup.c
@@ -197,18 +197,16 @@ static int wm831x_backup_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(devdata->backup);
}
-static int wm831x_backup_remove(struct platform_device *pdev)
+static void wm831x_backup_remove(struct platform_device *pdev)
{
struct wm831x_backup *devdata = platform_get_drvdata(pdev);
power_supply_unregister(devdata->backup);
-
- return 0;
}
static struct platform_driver wm831x_backup_driver = {
.probe = wm831x_backup_probe,
- .remove = wm831x_backup_remove,
+ .remove_new = wm831x_backup_remove,
.driver = {
.name = "wm831x-backup",
},
diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c
index 82e31066c..e49b01ee5 100644
--- a/drivers/power/supply/wm831x_power.c
+++ b/drivers/power/supply/wm831x_power.c
@@ -694,7 +694,7 @@ err:
return ret;
}
-static int wm831x_power_remove(struct platform_device *pdev)
+static void wm831x_power_remove(struct platform_device *pdev)
{
struct wm831x_power *wm831x_power = platform_get_drvdata(pdev);
struct wm831x *wm831x = wm831x_power->wm831x;
@@ -722,12 +722,11 @@ static int wm831x_power_remove(struct platform_device *pdev)
power_supply_unregister(wm831x_power->battery);
power_supply_unregister(wm831x_power->wall);
power_supply_unregister(wm831x_power->usb);
- return 0;
}
static struct platform_driver wm831x_power_driver = {
.probe = wm831x_power_probe,
- .remove = wm831x_power_remove,
+ .remove_new = wm831x_power_remove,
.driver = {
.name = "wm831x-power",
},
diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c
index f27867612..f23b4f534 100644
--- a/drivers/power/supply/wm8350_power.c
+++ b/drivers/power/supply/wm8350_power.c
@@ -579,7 +579,7 @@ battery_failed:
return ret;
}
-static int wm8350_power_remove(struct platform_device *pdev)
+static void wm8350_power_remove(struct platform_device *pdev)
{
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
struct wm8350_power *power = &wm8350->power;
@@ -589,12 +589,11 @@ static int wm8350_power_remove(struct platform_device *pdev)
power_supply_unregister(power->battery);
power_supply_unregister(power->ac);
power_supply_unregister(power->usb);
- return 0;
}
static struct platform_driver wm8350_power_driver = {
.probe = wm8350_power_probe,
- .remove = wm8350_power_remove,
+ .remove_new = wm8350_power_remove,
.driver = {
.name = "wm8350-power",
},
diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c
index f4b190adb..1cc38d143 100644
--- a/drivers/power/supply/wm97xx_battery.c
+++ b/drivers/power/supply/wm97xx_battery.c
@@ -248,14 +248,13 @@ err3:
return ret;
}
-static int wm97xx_bat_remove(struct platform_device *dev)
+static void wm97xx_bat_remove(struct platform_device *dev)
{
if (charge_gpiod)
free_irq(gpiod_to_irq(charge_gpiod), dev);
cancel_work_sync(&bat_work);
power_supply_unregister(bat_psy);
kfree(prop);
- return 0;
}
static struct platform_driver wm97xx_bat_driver = {
@@ -266,7 +265,7 @@ static struct platform_driver wm97xx_bat_driver = {
#endif
},
.probe = wm97xx_bat_probe,
- .remove = wm97xx_bat_remove,
+ .remove_new = wm97xx_bat_remove,
};
module_platform_driver(wm97xx_bat_driver);