From a1c7c1a40478db4edef8ad0a0c6975c8921088b7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Jul 2022 13:41:31 +0200 Subject: [PATCH 01/22] power: supply: Explain maintenance charging In order for everyone to understand clearly why we want to use maintenance charging for batteries, expand the description with two diagrams and some text. Signed-off-by: Linus Walleij Reviewed-by: Matti Vaittinen Signed-off-by: Sebastian Reichel --- include/linux/power_supply.h | 48 +++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index cb380c1d9459..aa2c4a7c4826 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -374,9 +374,37 @@ struct power_supply_vbat_ri_table { * These timers should be chosen to align with the typical discharge curve * for the battery. * - * When the main CC/CV charging is complete the battery can optionally be - * maintenance charged at the voltages from this table: a table of settings is - * traversed using a slightly lower current and voltage than what is used for + * Ordinary CC/CV charging will stop charging when the charge current goes + * below charge_term_current_ua, and then restart it (if the device is still + * plugged into the charger) at charge_restart_voltage_uv. This happens in most + * consumer products because the power usage while connected to a charger is + * not zero, and devices are not manufactured to draw power directly from the + * charger: instead they will at all times dissipate the battery a little, like + * the power used in standby mode. This will over time give a charge graph + * such as this: + * + * Energy + * ^ ... ... ... ... ... ... ... + * | . . . . . . . . . . . . . + * | .. . .. . .. . .. . .. . .. . .. + * |. .. .. .. .. .. .. + * +-------------------------------------------------------------------> t + * + * Practically this means that the Li-ions are wandering back and forth in the + * battery and this causes degeneration of the battery anode and cathode. + * To prolong the life of the battery, maintenance charging is applied after + * reaching charge_term_current_ua to hold up the charge in the battery while + * consuming power, thus lowering the wear on the battery: + * + * Energy + * ^ ....................................... + * | . ...................... + * | .. + * |. + * +-------------------------------------------------------------------> t + * + * Maintenance charging uses the voltages from this table: a table of settings + * is traversed using a slightly lower current and voltage than what is used for * CC/CV charging. The maintenance charging will for safety reasons not go on * indefinately: we lower the current and voltage with successive maintenance * settings, then disable charging completely after we reach the last one, @@ -385,14 +413,22 @@ struct power_supply_vbat_ri_table { * ordinary CC/CV charging from there. * * As an example, a Samsung EB425161LA Lithium-Ion battery is CC/CV charged - * at 900mA to 4340mV, then maintenance charged at 600mA and 4150mV for - * 60 hours, then maintenance charged at 600mA and 4100mV for 200 hours. + * at 900mA to 4340mV, then maintenance charged at 600mA and 4150mV for up to + * 60 hours, then maintenance charged at 600mA and 4100mV for up to 200 hours. * After this the charge cycle is restarted waiting for * charge_restart_voltage_uv. * * For most mobile electronics this type of maintenance charging is enough for * the user to disconnect the device and make use of it before both maintenance - * charging cycles are complete. + * charging cycles are complete, if the current and voltage has been chosen + * appropriately. These need to be determined from battery discharge curves + * and expected standby current. + * + * If the voltage anyway drops to charge_restart_voltage_uv during maintenance + * charging, ordinary CC/CV charging is restarted. This can happen if the + * device is e.g. actively used during charging, so more current is drawn than + * the expected stand-by current. Also overvoltage protection will be applied + * as usual. */ struct power_supply_maintenance_charge_table { int charge_current_max_ua; From da7dc6a7a95ef00ff38e7c1873efa79bfec93de4 Mon Sep 17 00:00:00 2001 From: wangjianli Date: Sun, 21 Aug 2022 22:49:42 +0800 Subject: [PATCH 02/22] power: supply: cpcap-charger: fix repeated words in comments Delete the redundant word 'on'. Signed-off-by: wangjianli Signed-off-by: Sebastian Reichel --- drivers/power/supply/cpcap-charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index 60e0ce105a29..be9764541d52 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -5,7 +5,7 @@ * Copyright (C) 2017 Tony Lindgren * * Rewritten for Linux power framework with some parts based on - * on earlier driver found in the Motorola Linux kernel: + * earlier driver found in the Motorola Linux kernel: * * Copyright (C) 2009-2010 Motorola, Inc. */ From 0cb172a4918e0b180400c3e1b2894641703eab6d Mon Sep 17 00:00:00 2001 From: Zheyu Ma Date: Sun, 17 Jul 2022 10:58:20 +0800 Subject: [PATCH 03/22] power: supply: cw2015: Use device managed API to simplify the code Use devm_delayed_work_autocancel() instead of the INIT_DELAYED_WORK() to remove the cw_bat_remove() function. And power_supply_put_battery_info() can also be removed because the power_supply_get_battery_info() uses device managed memory allocation. Signed-off-by: Zheyu Ma Signed-off-by: Sebastian Reichel --- drivers/power/supply/cw2015_battery.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/power/supply/cw2015_battery.c b/drivers/power/supply/cw2015_battery.c index 728e2a6cc9c3..6d52641151d9 100644 --- a/drivers/power/supply/cw2015_battery.c +++ b/drivers/power/supply/cw2015_battery.c @@ -21,6 +21,7 @@ #include #include #include +#include #define CW2015_SIZE_BATINFO 64 @@ -698,7 +699,8 @@ static int cw_bat_probe(struct i2c_client *client) } cw_bat->battery_workqueue = create_singlethread_workqueue("rk_battery"); - INIT_DELAYED_WORK(&cw_bat->battery_delay_work, cw_bat_work); + devm_delayed_work_autocancel(&client->dev, + &cw_bat->battery_delay_work, cw_bat_work); queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->battery_delay_work, msecs_to_jiffies(10)); return 0; @@ -725,15 +727,6 @@ static int __maybe_unused cw_bat_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(cw_bat_pm_ops, cw_bat_suspend, cw_bat_resume); -static int cw_bat_remove(struct i2c_client *client) -{ - struct cw_battery *cw_bat = i2c_get_clientdata(client); - - cancel_delayed_work_sync(&cw_bat->battery_delay_work); - power_supply_put_battery_info(cw_bat->rk_bat, cw_bat->battery); - return 0; -} - static const struct i2c_device_id cw_bat_id_table[] = { { "cw2015", 0 }, { } @@ -752,7 +745,6 @@ static struct i2c_driver cw_bat_driver = { .pm = &cw_bat_pm_ops, }, .probe_new = cw_bat_probe, - .remove = cw_bat_remove, .id_table = cw_bat_id_table, }; From 03fccdc76dce9674d100797387d73b7af6d5e64f Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 9 Sep 2022 13:42:09 -0700 Subject: [PATCH 04/22] dt-bindings: power: reset: qcom-pon: Add new compatible "qcom,pmk8350-pon" Add a new compatible string "qcom,pmk8350-pon" for GEN3 PMIC PON peripherals and update "reg" property. Also, Add an optional "reg-names" property to differentiate between GEN1/GEN2 and GEN3 peripherals. GEN1/GEN2 peripherals only need one register address to be specified (e.g. "pon") whereas GEN3 peripherals can have two register addresses specified ("hlos", "pbs"). Signed-off-by: David Collins Signed-off-by: Anjelique Melendez Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- .../bindings/power/reset/qcom,pon.yaml | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml index e7b436d2e757..d96170eecbd2 100644 --- a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml +++ b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml @@ -15,18 +15,27 @@ description: | This DT node has pwrkey and resin as sub nodes. -allOf: - - $ref: reboot-mode.yaml# - properties: compatible: enum: - qcom,pm8916-pon - qcom,pms405-pon - qcom,pm8998-pon + - qcom,pmk8350-pon reg: - maxItems: 1 + description: | + Specifies the SPMI base address for the PON (power-on) peripheral. For + PMICs that have the PON peripheral (GEN3) split into PON_HLOS and PON_PBS + (e.g. PMK8350), this can hold addresses of both PON_HLOS and PON_PBS + peripherals. In that case, the PON_PBS address needs to be specified to + facilitate software debouncing on some PMIC. + minItems: 1 + maxItems: 2 + + reg-names: + minItems: 1 + maxItems: 2 pwrkey: type: object @@ -46,6 +55,39 @@ required: unevaluatedProperties: false +allOf: + - $ref: reboot-mode.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8916-pon + - qcom,pms405-pon + - qcom,pm8998-pon + then: + properties: + reg: + maxItems: 1 + reg-names: + items: + - const: pon + - if: + properties: + compatible: + contains: + const: qcom,pmk8350-pon + then: + properties: + reg: + minItems: 1 + maxItems: 2 + reg-names: + minItems: 1 + items: + - const: hlos + - const: pbs + examples: - | #include From 955d095a72f0ff55f6e74c8b42fa64611b0ac6cd Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Fri, 9 Sep 2022 13:42:10 -0700 Subject: [PATCH 05/22] power: reset: qcom-pon: add support for qcom,pmk8350-pon compatible string Add support for the new "qcom,pmk8350-pon" comptaible string. Signed-off-by: Anjelique Melendez Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/reset/qcom-pon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c index 4a688741a88a..16bc01738be9 100644 --- a/drivers/power/reset/qcom-pon.c +++ b/drivers/power/reset/qcom-pon.c @@ -82,6 +82,7 @@ static const struct of_device_id pm8916_pon_id_table[] = { { .compatible = "qcom,pm8916-pon", .data = (void *)GEN1_REASON_SHIFT }, { .compatible = "qcom,pms405-pon", .data = (void *)GEN1_REASON_SHIFT }, { .compatible = "qcom,pm8998-pon", .data = (void *)GEN2_REASON_SHIFT }, + { .compatible = "qcom,pmk8350-pon", .data = (void *)GEN2_REASON_SHIFT }, { } }; MODULE_DEVICE_TABLE(of, pm8916_pon_id_table); From 3eb7508d0bad13c2c4272fe30adfb02190294290 Mon Sep 17 00:00:00 2001 From: Shaomin Deng Date: Wed, 31 Aug 2022 11:49:05 -0400 Subject: [PATCH 06/22] power: supply: tps65217: Fix comments typo Delete the unneeded word "the" in comments. Signed-off-by: Shaomin Deng Signed-off-by: Sebastian Reichel --- drivers/power/supply/tps65217_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c index ba33d1617e0b..a4bc9f2a10bc 100644 --- a/drivers/power/supply/tps65217_charger.c +++ b/drivers/power/supply/tps65217_charger.c @@ -50,7 +50,7 @@ static int tps65217_config_charger(struct tps65217_charger *charger) * tps65217 rev. G, p. 31 (see p. 32 for NTC schematic) * * The device can be configured to support a 100k NTC (B = 3960) by - * setting the the NTC_TYPE bit in register CHGCONFIG1 to 1. However it + * setting the NTC_TYPE bit in register CHGCONFIG1 to 1. However it * is not recommended to do so. In sleep mode, the charger continues * charging the battery, but all register values are reset to default * values. Therefore, the charger would get the wrong temperature From 9d47e01b9d807808224347935562f7043a358054 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 27 Aug 2022 07:32:23 +0000 Subject: [PATCH 07/22] power: supply: adp5061: fix out-of-bounds read in adp5061_get_chg_type() ADP5061_CHG_STATUS_1_CHG_STATUS is masked with 0x07, which means a length of 8, but adp5061_chg_type array size is 4, may end up reading 4 elements beyond the end of the adp5061_chg_type[] array. Signed-off-by: Wei Yongjun Acked-by: Michael Hennerich Signed-off-by: Sebastian Reichel --- drivers/power/supply/adp5061.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/adp5061.c b/drivers/power/supply/adp5061.c index 003557043ab3..daee1161c305 100644 --- a/drivers/power/supply/adp5061.c +++ b/drivers/power/supply/adp5061.c @@ -427,11 +427,11 @@ static int adp5061_get_chg_type(struct adp5061_state *st, if (ret < 0) return ret; - chg_type = adp5061_chg_type[ADP5061_CHG_STATUS_1_CHG_STATUS(status1)]; - if (chg_type > ADP5061_CHG_FAST_CV) + chg_type = ADP5061_CHG_STATUS_1_CHG_STATUS(status1); + if (chg_type >= ARRAY_SIZE(adp5061_chg_type)) val->intval = POWER_SUPPLY_STATUS_UNKNOWN; else - val->intval = chg_type; + val->intval = adp5061_chg_type[chg_type]; return ret; } From e568252d722d70bcb3e903477e46f5024138f8ca Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 27 Aug 2022 07:32:24 +0000 Subject: [PATCH 08/22] power: supply: adp5061: show unknown capacity_level as text adp5061_get_battery_status() only defined show chg_status <= 4, others will be show as '-1731902199' from /sys/class/power_supply/xx/capacity_level. switch to show them as 'Unknown'. Signed-off-by: Wei Yongjun Acked-by: Michael Hennerich Signed-off-by: Sebastian Reichel --- drivers/power/supply/adp5061.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/power/supply/adp5061.c b/drivers/power/supply/adp5061.c index daee1161c305..fcf8ff0bc974 100644 --- a/drivers/power/supply/adp5061.c +++ b/drivers/power/supply/adp5061.c @@ -493,6 +493,9 @@ static int adp5061_get_battery_status(struct adp5061_state *st, case 0x4: /* VBAT_SNS > VWEAK */ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; break; + default: + val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; + break; } return ret; From 5ae6134ef380e4cbb50ab8d606a10b880a61c5c5 Mon Sep 17 00:00:00 2001 From: Jules Maselbas Date: Fri, 26 Aug 2022 12:00:45 +0200 Subject: [PATCH 09/22] power: supply: Fix repeated word in comments Remove redundant word `the`. Signed-off-by: Jules Maselbas Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 4239591e1522..5369abaceb5c 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -442,7 +442,7 @@ static int add_prop_uevent(struct device *dev, struct kobj_uevent_env *env, if (ret == -ENODEV || ret == -ENODATA) { /* * When a battery is absent, we expect -ENODEV. Don't abort; - * send the uevent with at least the the PRESENT=0 property + * send the uevent with at least the PRESENT=0 property */ return 0; } From 04f7c7df96de7a2e9a72e53e8082754b13495813 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 31 Jul 2022 12:02:28 +0200 Subject: [PATCH 10/22] power: supply: bq25890: Disable PUMPX_EN on errors When bq25890_pump_express_work encounters an errors disable the PUMPX_EN flag, just like the work does on a successful exit. Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 852a6fec4339..056260b2cb76 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -946,6 +946,7 @@ static void bq25890_pump_express_work(struct work_struct *data) return; error_print: + bq25890_field_write(bq, F_PUMPX_EN, 0); dev_err(bq->dev, "Failed to request hi-voltage charging\n"); } From 4a4748f28b0b2547de745ed929e929a9b45563f1 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 1 Aug 2022 04:57:27 +0200 Subject: [PATCH 11/22] power: supply: bq25890: Add support for setting IINLIM Let user set input current limit via sysfs. This is useful in case there are multiple chargers connected to the device, each of which with its own arbitrary maximum current which it can provide, some of which may provide more than the default 500mA. In that case, userspace can listen for plug events generated by each charger and adjust the current limit accordingly, e.g. to permit battery to charge faster. Note that the IINLIM is reset every time the bq25890 is disconnected from a charger, so the userspace must adjust the limit repeatly on every plug event. Signed-off-by: Marek Vasut Reviewed-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 056260b2cb76..f5368be32843 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -613,6 +613,33 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, return 0; } +static int bq25890_power_supply_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct bq25890_device *bq = power_supply_get_drvdata(psy); + u8 lval; + + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + lval = bq25890_find_idx(val->intval, F_IINLIM); + return bq25890_field_write(bq, F_IINLIM, lval); + default: + return -EINVAL; + } +} + +static int bq25890_power_supply_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return true; + default: + return false; + } +} + /* On the BQ25892 try to get charger-type info from our supplier */ static void bq25890_charger_external_power_changed(struct power_supply *psy) { @@ -874,6 +901,8 @@ static const struct power_supply_desc bq25890_power_supply_desc = { .properties = bq25890_power_supply_props, .num_properties = ARRAY_SIZE(bq25890_power_supply_props), .get_property = bq25890_power_supply_get_property, + .set_property = bq25890_power_supply_set_property, + .property_is_writeable = bq25890_power_supply_property_is_writeable, .external_power_changed = bq25890_charger_external_power_changed, }; From 569581a21ff57f43dbe900b2f578c0ec3b0018ba Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 21 Jul 2022 22:07:35 +0100 Subject: [PATCH 12/22] power: supply: bq27xxx: fix __be16 warnings The bq27xxx_dm_reg_ptr() should return a __be16 as the result is being passed to be16_to_cpup() to convert to the proper cpu endian value. Move to using __be16 as appropriate to fix the following sparse warnings: drivers/power/supply/bq27xxx_battery.c:1293:26: warning: incorrect type in argument 1 (different base types) drivers/power/supply/bq27xxx_battery.c:1293:26: expected restricted __be16 const [usertype] *p drivers/power/supply/bq27xxx_battery.c:1293:26: got unsigned short [usertype] *prev drivers/power/supply/bq27xxx_battery.c:1304:17: warning: incorrect type in argument 1 (different base types) drivers/power/supply/bq27xxx_battery.c:1304:17: expected restricted __be16 const [usertype] *p drivers/power/supply/bq27xxx_battery.c:1304:17: got unsigned short [usertype] *prev drivers/power/supply/bq27xxx_battery.c:1316:15: warning: incorrect type in assignment (different base types) drivers/power/supply/bq27xxx_battery.c:1316:15: expected unsigned short [usertype] drivers/power/supply/bq27xxx_battery.c:1316:15: got restricted __be16 [usertype] Signed-off-by: Ben Dooks Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 35e6a394c0df..9870552adfd9 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1044,12 +1044,12 @@ struct bq27xxx_dm_buf { .block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \ } -static inline u16 *bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf, +static inline __be16 *bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf, struct bq27xxx_dm_reg *reg) { if (buf->class == reg->subclass_id && buf->block == reg->offset / BQ27XXX_DM_SZ) - return (u16 *) (buf->data + reg->offset % BQ27XXX_DM_SZ); + return (__be16 *) (buf->data + reg->offset % BQ27XXX_DM_SZ); return NULL; } @@ -1275,7 +1275,7 @@ static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di, { struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id]; const char *str = bq27xxx_dm_reg_name[reg_id]; - u16 *prev = bq27xxx_dm_reg_ptr(buf, reg); + __be16 *prev = bq27xxx_dm_reg_ptr(buf, reg); if (prev == NULL) { dev_warn(di->dev, "buffer does not match %s dm spec\n", str); From f52c4d5f0bb486bc515b5f8a56130aea69fb29db Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 21 Jul 2022 22:01:20 +0100 Subject: [PATCH 13/22] power: supply: bq27xxx: fix NULL vs 0 warnings The driver has a lot of sparse warnings for using 0 as a NULL pointer when NULL would be appropriate. Change the 0 values to NULL to fix the warnings, some of which are shown here: drivers/power/supply/bq27xxx_battery.c:984:23: warning: Using plain integer as NULL pointer drivers/power/supply/bq27xxx_battery.c:985:23: warning: Using plain integer as NULL pointer drivers/power/supply/bq27xxx_battery.c:986:23: warning: Using plain integer as NULL pointer drivers/power/supply/bq27xxx_battery.c:987:23: warning: Using plain integer as NULL pointer drivers/power/supply/bq27xxx_battery.c:988:23: warning: Using plain integer as NULL pointer Signed-off-by: Ben Dooks Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 54 +++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 9870552adfd9..8bf048fbd36a 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -868,11 +868,11 @@ enum bq27xxx_dm_reg_id { BQ27XXX_DM_TERMINATE_VOLTAGE, }; -#define bq27000_dm_regs 0 -#define bq27010_dm_regs 0 -#define bq2750x_dm_regs 0 -#define bq2751x_dm_regs 0 -#define bq2752x_dm_regs 0 +#define bq27000_dm_regs NULL +#define bq27010_dm_regs NULL +#define bq2750x_dm_regs NULL +#define bq2751x_dm_regs NULL +#define bq2752x_dm_regs NULL #if 0 /* not yet tested */ static struct bq27xxx_dm_reg bq27500_dm_regs[] = { @@ -881,24 +881,24 @@ static struct bq27xxx_dm_reg bq27500_dm_regs[] = { [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 }, }; #else -#define bq27500_dm_regs 0 +#define bq27500_dm_regs NULL #endif /* todo create data memory definitions from datasheets and test on chips */ -#define bq27510g1_dm_regs 0 -#define bq27510g2_dm_regs 0 -#define bq27510g3_dm_regs 0 -#define bq27520g1_dm_regs 0 -#define bq27520g2_dm_regs 0 -#define bq27520g3_dm_regs 0 -#define bq27520g4_dm_regs 0 -#define bq27521_dm_regs 0 -#define bq27530_dm_regs 0 -#define bq27531_dm_regs 0 -#define bq27541_dm_regs 0 -#define bq27542_dm_regs 0 -#define bq27546_dm_regs 0 -#define bq27742_dm_regs 0 +#define bq27510g1_dm_regs NULL +#define bq27510g2_dm_regs NULL +#define bq27510g3_dm_regs NULL +#define bq27520g1_dm_regs NULL +#define bq27520g2_dm_regs NULL +#define bq27520g3_dm_regs NULL +#define bq27520g4_dm_regs NULL +#define bq27521_dm_regs NULL +#define bq27530_dm_regs NULL +#define bq27531_dm_regs NULL +#define bq27541_dm_regs NULL +#define bq27542_dm_regs NULL +#define bq27546_dm_regs NULL +#define bq27742_dm_regs NULL #if 0 /* not yet tested */ static struct bq27xxx_dm_reg bq27545_dm_regs[] = { @@ -907,7 +907,7 @@ static struct bq27xxx_dm_reg bq27545_dm_regs[] = { [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800, 3700 }, }; #else -#define bq27545_dm_regs 0 +#define bq27545_dm_regs NULL #endif static struct bq27xxx_dm_reg bq27411_dm_regs[] = { @@ -937,7 +937,7 @@ static struct bq27xxx_dm_reg bq27426_dm_regs[] = { #if 0 /* not yet tested */ #define bq27441_dm_regs bq27421_dm_regs #else -#define bq27441_dm_regs 0 +#define bq27441_dm_regs NULL #endif #if 0 /* not yet tested */ @@ -947,13 +947,13 @@ static struct bq27xxx_dm_reg bq27621_dm_regs[] = { [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500, 3700 }, }; #else -#define bq27621_dm_regs 0 +#define bq27621_dm_regs NULL #endif -#define bq27z561_dm_regs 0 -#define bq28z610_dm_regs 0 -#define bq34z100_dm_regs 0 -#define bq78z100_dm_regs 0 +#define bq27z561_dm_regs NULL +#define bq28z610_dm_regs NULL +#define bq34z100_dm_regs NULL +#define bq78z100_dm_regs NULL #define BQ27XXX_O_ZERO BIT(0) #define BQ27XXX_O_OTDC BIT(1) /* has OTC/OTD overtemperature flags */ From 55cafd4ba42cf495268f955dd38e277fc4b4381e Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 12 Sep 2022 07:15:53 -0700 Subject: [PATCH 14/22] power: supply: bq25890: Fix enum conversion in bq25890_power_supply_set_property() Clang warns: drivers/power/supply/bq25890_charger.c:625:40: error: implicit conversion from enumeration type 'enum bq25890_fields' to different enumeration type 'enum bq25890_table_ids' [-Werror,-Wenum-conversion] lval = bq25890_find_idx(val->intval, F_IINLIM); ~~~~~~~~~~~~~~~~ ^~~~~~~~ 1 error generated. Use the proper value from the right enumerated type, TBL_IINLIM, so there is no more implcit conversion. The numerical values of F_IINLIM and TBL_IINLIM happen to be the same so there is no change in behavior. Fixes: 4a4748f28b0b ("power: supply: bq25890: Add support for setting IINLIM") Link: https://github.com/ClangBuiltLinux/linux/issues/1707 Signed-off-by: Nathan Chancellor Reviewed-by: Marek Vasut Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index f5368be32843..e6bd60fef0f6 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -622,7 +622,7 @@ static int bq25890_power_supply_set_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: - lval = bq25890_find_idx(val->intval, F_IINLIM); + lval = bq25890_find_idx(val->intval, TBL_IINLIM); return bq25890_field_write(bq, F_IINLIM, lval); default: return -EINVAL; From c2f2e2c3aecdbabf822272a4b6e7d91537633cd9 Mon Sep 17 00:00:00 2001 From: ChiaEn Wu Date: Thu, 15 Sep 2022 17:47:32 +0800 Subject: [PATCH 15/22] lib: add linear range index macro Add linear_range_idx macro for declaring the linear_range struct simply. Reviewed-by: Matti Vaittinen Signed-off-by: ChiaEn Wu Signed-off-by: Sebastian Reichel --- include/linux/linear_range.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/linear_range.h b/include/linux/linear_range.h index fd3d0b358f22..2e4f4c3539c0 100644 --- a/include/linux/linear_range.h +++ b/include/linux/linear_range.h @@ -26,6 +26,17 @@ struct linear_range { unsigned int step; }; +#define LINEAR_RANGE(_min, _min_sel, _max_sel, _step) \ + { \ + .min = _min, \ + .min_sel = _min_sel, \ + .max_sel = _max_sel, \ + .step = _step, \ + } + +#define LINEAR_RANGE_IDX(_idx, _min, _min_sel, _max_sel, _step) \ + [_idx] = LINEAR_RANGE(_min, _min_sel, _max_sel, _step) + unsigned int linear_range_values_in_range(const struct linear_range *r); unsigned int linear_range_values_in_range_array(const struct linear_range *r, int ranges); From 689af5da8543d4378aed8f74696bad59a15d5a78 Mon Sep 17 00:00:00 2001 From: ChiaEn Wu Date: Thu, 15 Sep 2022 17:47:29 +0800 Subject: [PATCH 16/22] dt-bindings: power: supply: Add MediaTek MT6370 Charger Add MediaTek MT6370 Charger binding documentation. Reviewed-by: Krzysztof Kozlowski Signed-off-by: ChiaEn Wu Signed-off-by: Sebastian Reichel --- .../power/supply/mediatek,mt6370-charger.yaml | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml diff --git a/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml new file mode 100644 index 000000000000..fd491c598a00 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/mediatek,mt6370-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT6370 Battery Charger + +maintainers: + - ChiaEn Wu + +description: | + This module is part of the MT6370 MFD device. + Provides Battery Charger, Boost for OTG devices and BC1.2 detection. + +properties: + compatible: + const: mediatek,mt6370-charger + + interrupts: + description: | + Specify what irqs are needed to be handled by MT6370 Charger driver. + We need to use the IRQ "MT6370_IRQ_OVPCTRL_UVP_D" to know when USB + is plugged in, and then the driver will enable BC1.2 detection. + After the hardware of MT6370 completes the BC1.2 detection, + IRQ "MT6370_IRQ_ATTACH" will be triggered, and the driver will know + the result of BC1.2 detection. + When the IRQ "MT6370_IRQ_CHG_MIVR" is triggered, it means that the + hardware enters the "Minimum Input Voltage Regulation loop" and + a workaround needs to be applied at this time. + In summary, "MT6370_IRQ_OVPCTRL_UVP_D", "MT6370_IRQ_ATTACH" and + "MT6370_IRQ_CHG_MIVR" are required in this charger driver. + items: + - description: irq of "USB is plugged in" + - description: irq of "BC1.2 is done" + - description: irq of "Minimum Input Voltage Regulation loop is active" + + interrupt-names: + items: + - const: uvp_d_evt + - const: attach_i + - const: mivr + + io-channels: + description: | + Use ADC channel to read VBUS, IBUS, IBAT, etc., info. + minItems: 1 + items: + - description: | + VBUS voltage with lower accuracy (+-75mV) but higher measure + range (1~22V) + - description: | + VBUS voltage with higher accuracy (+-30mV) but lower measure + range (1~9.76V) + - description: the main system input voltage + - description: battery voltage + - description: battery temperature-sense input voltage + - description: IBUS current (required) + - description: battery current + - description: | + regulated output voltage to supply for the PWM low-side gate driver + and the bootstrap capacitor + - description: IC junction temperature + + io-channel-names: + minItems: 1 + items: + - const: vbusdiv5 + - const: vbusdiv2 + - const: vsys + - const: vbat + - const: ts_bat + - const: ibus + - const: ibat + - const: chg_vddp + - const: temp_jc + + usb-otg-vbus-regulator: + type: object + description: OTG boost regulator. + unevaluatedProperties: false + $ref: /schemas/regulator/regulator.yaml# + + properties: + enable-gpios: + maxItems: 1 + +required: + - compatible + - interrupts + - interrupt-names + - io-channels + +additionalProperties: false + +... From 233cb8a47d65715643f7608e7130b417df115d9f Mon Sep 17 00:00:00 2001 From: ChiaEn Wu Date: Thu, 15 Sep 2022 17:47:35 +0800 Subject: [PATCH 17/22] power: supply: mt6370: Add MediaTek MT6370 charger driver MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight driver, display bias voltage supply, one general purpose LDO, and the USB Type-C & PD controller complies with the latest USB Type-C and PD standards. Add support for the MediaTek MT6370 Charger driver. The charger module of MT6370 supports High-Accuracy Voltage/Current Regulation, Average Input Current Regulation, Battery Temperature Sensing, Over-Temperature Protection, DPDM Detection for BC1.2. Reviewed-by: Andy Shevchenko Signed-off-by: ChiaEn Wu Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 14 + drivers/power/supply/Makefile | 1 + drivers/power/supply/mt6370-charger.c | 961 ++++++++++++++++++++++++++ 3 files changed, 976 insertions(+) create mode 100644 drivers/power/supply/mt6370-charger.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 1aa8323ad9f6..591deb82e2c6 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -619,6 +619,20 @@ config CHARGER_MT6360 Average Input Current Regulation, Battery Temperature Sensing, Over-Temperature Protection, DPDM Detection for BC1.2. +config CHARGER_MT6370 + tristate "MediaTek MT6370 Charger Driver" + depends on MFD_MT6370 + depends on REGULATOR + select LINEAR_RANGES + help + Say Y here to enable MT6370 Charger Part. + The device supports High-Accuracy Voltage/Current Regulation, + Average Input Current Regulation, Battery Temperature Sensing, + Over-Temperature Protection, DPDM Detection for BC1.2. + + This driver can also be built as a module. If so, the module + will be called "mt6370-charger". + config CHARGER_QCOM_SMBB tristate "Qualcomm Switch-Mode Battery Charger and Boost" depends on MFD_SPMI_PMIC || COMPILE_TEST diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 7f02f36aea55..8c9527643c86 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o 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_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c new file mode 100644 index 000000000000..716cba259a7a --- /dev/null +++ b/drivers/power/supply/mt6370-charger.c @@ -0,0 +1,961 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiaEn Wu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6370_REG_CHG_CTRL1 0x111 +#define MT6370_REG_CHG_CTRL2 0x112 +#define MT6370_REG_CHG_CTRL3 0x113 +#define MT6370_REG_CHG_CTRL4 0x114 +#define MT6370_REG_CHG_CTRL5 0x115 +#define MT6370_REG_CHG_CTRL6 0x116 +#define MT6370_REG_CHG_CTRL7 0x117 +#define MT6370_REG_CHG_CTRL8 0x118 +#define MT6370_REG_CHG_CTRL9 0x119 +#define MT6370_REG_CHG_CTRL10 0x11A +#define MT6370_REG_DEVICE_TYPE 0x122 +#define MT6370_REG_USB_STATUS1 0x127 +#define MT6370_REG_CHG_STAT 0x14A +#define MT6370_REG_FLED_EN 0x17E +#define MT6370_REG_CHG_STAT1 0X1D0 +#define MT6370_REG_OVPCTRL_STAT 0x1D8 + +#define MT6370_VOBST_MASK GENMASK(7, 2) +#define MT6370_OTG_PIN_EN_MASK BIT(1) +#define MT6370_OPA_MODE_MASK BIT(0) +#define MT6370_OTG_OC_MASK GENMASK(2, 0) + +#define MT6370_MIVR_IBUS_TH_100_mA 100000 +#define MT6370_ADC_CHAN_IBUS 5 +#define MT6370_ADC_CHAN_MAX 9 + +enum mt6370_chg_reg_field { + /* MT6370_REG_CHG_CTRL2 */ + F_IINLMTSEL, F_CFO_EN, F_CHG_EN, + /* MT6370_REG_CHG_CTRL3 */ + F_IAICR, F_AICR_EN, F_ILIM_EN, + /* MT6370_REG_CHG_CTRL4 */ + F_VOREG, + /* MT6370_REG_CHG_CTRL6 */ + F_VMIVR, + /* MT6370_REG_CHG_CTRL7 */ + F_ICHG, + /* MT6370_REG_CHG_CTRL8 */ + F_IPREC, + /* MT6370_REG_CHG_CTRL9 */ + F_IEOC, + /* MT6370_REG_DEVICE_TYPE */ + F_USBCHGEN, + /* MT6370_REG_USB_STATUS1 */ + F_USB_STAT, F_CHGDET, + /* MT6370_REG_CHG_STAT */ + F_CHG_STAT, F_BOOST_STAT, F_VBAT_LVL, + /* MT6370_REG_FLED_EN */ + F_FL_STROBE, + /* MT6370_REG_CHG_STAT1 */ + F_CHG_MIVR_STAT, + /* MT6370_REG_OVPCTRL_STAT */ + F_UVP_D_STAT, + F_MAX +}; + +enum mt6370_irq { + MT6370_IRQ_ATTACH_I = 0, + MT6370_IRQ_UVP_D_EVT, + MT6370_IRQ_MIVR, + MT6370_IRQ_MAX +}; + +struct mt6370_priv { + struct device *dev; + struct iio_channel *iio_adcs; + struct mutex attach_lock; + struct power_supply *psy; + struct regmap *regmap; + struct regmap_field *rmap_fields[F_MAX]; + struct regulator_dev *rdev; + struct workqueue_struct *wq; + struct work_struct bc12_work; + struct delayed_work mivr_dwork; + unsigned int irq_nums[MT6370_IRQ_MAX]; + int attach; + int psy_usb_type; + bool pwr_rdy; +}; + +enum mt6370_usb_status { + MT6370_USB_STAT_NO_VBUS = 0, + MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING, + MT6370_USB_STAT_SDP, + MT6370_USB_STAT_SDP_NSTD, + MT6370_USB_STAT_DCP, + MT6370_USB_STAT_CDP, + MT6370_USB_STAT_MAX +}; + +struct mt6370_chg_field { + const char *name; + const struct linear_range *range; + struct reg_field field; +}; + +enum { + MT6370_RANGE_F_IAICR = 0, + MT6370_RANGE_F_VOREG, + MT6370_RANGE_F_VMIVR, + MT6370_RANGE_F_ICHG, + MT6370_RANGE_F_IPREC, + MT6370_RANGE_F_IEOC, + MT6370_RANGE_F_MAX +}; + +static const struct linear_range mt6370_chg_ranges[MT6370_RANGE_F_MAX] = { + LINEAR_RANGE_IDX(MT6370_RANGE_F_IAICR, 100000, 0x0, 0x3F, 50000), + LINEAR_RANGE_IDX(MT6370_RANGE_F_VOREG, 3900000, 0x0, 0x51, 10000), + LINEAR_RANGE_IDX(MT6370_RANGE_F_VMIVR, 3900000, 0x0, 0x5F, 100000), + LINEAR_RANGE_IDX(MT6370_RANGE_F_ICHG, 900000, 0x08, 0x31, 100000), + LINEAR_RANGE_IDX(MT6370_RANGE_F_IPREC, 100000, 0x0, 0x0F, 50000), + LINEAR_RANGE_IDX(MT6370_RANGE_F_IEOC, 100000, 0x0, 0x0F, 50000), +}; + +#define MT6370_CHG_FIELD(_fd, _reg, _lsb, _msb) \ +[_fd] = { \ + .name = #_fd, \ + .range = NULL, \ + .field = REG_FIELD(_reg, _lsb, _msb), \ +} + +#define MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb) \ +[_fd] = { \ + .name = #_fd, \ + .range = &mt6370_chg_ranges[MT6370_RANGE_##_fd], \ + .field = REG_FIELD(_reg, _lsb, _msb), \ +} + +static const struct mt6370_chg_field mt6370_chg_fields[F_MAX] = { + MT6370_CHG_FIELD(F_IINLMTSEL, MT6370_REG_CHG_CTRL2, 2, 3), + MT6370_CHG_FIELD(F_CFO_EN, MT6370_REG_CHG_CTRL2, 1, 1), + MT6370_CHG_FIELD(F_CHG_EN, MT6370_REG_CHG_CTRL2, 0, 0), + MT6370_CHG_FIELD_RANGE(F_IAICR, MT6370_REG_CHG_CTRL3, 2, 7), + MT6370_CHG_FIELD(F_AICR_EN, MT6370_REG_CHG_CTRL3, 1, 1), + MT6370_CHG_FIELD(F_ILIM_EN, MT6370_REG_CHG_CTRL3, 0, 0), + MT6370_CHG_FIELD_RANGE(F_VOREG, MT6370_REG_CHG_CTRL4, 1, 7), + MT6370_CHG_FIELD_RANGE(F_VMIVR, MT6370_REG_CHG_CTRL6, 1, 7), + MT6370_CHG_FIELD_RANGE(F_ICHG, MT6370_REG_CHG_CTRL7, 2, 7), + MT6370_CHG_FIELD_RANGE(F_IPREC, MT6370_REG_CHG_CTRL8, 0, 3), + MT6370_CHG_FIELD_RANGE(F_IEOC, MT6370_REG_CHG_CTRL9, 4, 7), + MT6370_CHG_FIELD(F_USBCHGEN, MT6370_REG_DEVICE_TYPE, 7, 7), + MT6370_CHG_FIELD(F_USB_STAT, MT6370_REG_USB_STATUS1, 4, 6), + MT6370_CHG_FIELD(F_CHGDET, MT6370_REG_USB_STATUS1, 3, 3), + MT6370_CHG_FIELD(F_CHG_STAT, MT6370_REG_CHG_STAT, 6, 7), + MT6370_CHG_FIELD(F_BOOST_STAT, MT6370_REG_CHG_STAT, 3, 3), + MT6370_CHG_FIELD(F_VBAT_LVL, MT6370_REG_CHG_STAT, 5, 5), + MT6370_CHG_FIELD(F_FL_STROBE, MT6370_REG_FLED_EN, 2, 2), + MT6370_CHG_FIELD(F_CHG_MIVR_STAT, MT6370_REG_CHG_STAT1, 6, 6), + MT6370_CHG_FIELD(F_UVP_D_STAT, MT6370_REG_OVPCTRL_STAT, 4, 4), +}; + +static inline int mt6370_chg_field_get(struct mt6370_priv *priv, + enum mt6370_chg_reg_field fd, + unsigned int *val) +{ + int ret; + unsigned int reg_val; + + ret = regmap_field_read(priv->rmap_fields[fd], ®_val); + if (ret) + return ret; + + if (mt6370_chg_fields[fd].range) + return linear_range_get_value(mt6370_chg_fields[fd].range, + reg_val, val); + + *val = reg_val; + return 0; +} + +static inline int mt6370_chg_field_set(struct mt6370_priv *priv, + enum mt6370_chg_reg_field fd, + unsigned int val) +{ + int ret; + bool f; + const struct linear_range *r; + + if (mt6370_chg_fields[fd].range) { + r = mt6370_chg_fields[fd].range; + + if (fd == F_VMIVR) { + ret = linear_range_get_selector_high(r, val, &val, &f); + if (ret) + val = r->max_sel; + } else { + linear_range_get_selector_within(r, val, &val); + } + } + + return regmap_field_write(priv->rmap_fields[fd], val); +} + +enum { + MT6370_CHG_STAT_READY = 0, + MT6370_CHG_STAT_CHARGE_IN_PROGRESS, + MT6370_CHG_STAT_DONE, + MT6370_CHG_STAT_FAULT, + MT6370_CHG_STAT_MAX +}; + +enum { + MT6370_ATTACH_STAT_DETACH = 0, + MT6370_ATTACH_STAT_ATTACH_WAIT_FOR_BC12, + MT6370_ATTACH_STAT_ATTACH_BC12_DONE, + MT6370_ATTACH_STAT_ATTACH_MAX +}; + +static int mt6370_chg_otg_of_parse_cb(struct device_node *of, + const struct regulator_desc *rdesc, + struct regulator_config *rcfg) +{ + struct mt6370_priv *priv = rcfg->driver_data; + + rcfg->ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(of), + "enable", 0, GPIOD_OUT_LOW | + GPIOD_FLAGS_BIT_NONEXCLUSIVE, + rdesc->name); + if (IS_ERR(rcfg->ena_gpiod)) { + rcfg->ena_gpiod = NULL; + return 0; + } + + return regmap_update_bits(priv->regmap, MT6370_REG_CHG_CTRL1, + MT6370_OTG_PIN_EN_MASK, + MT6370_OTG_PIN_EN_MASK); +} + +static void mt6370_chg_bc12_work_func(struct work_struct *work) +{ + struct mt6370_priv *priv = container_of(work, struct mt6370_priv, + bc12_work); + int ret; + bool rpt_psy = false; + unsigned int attach, usb_stat; + + mutex_lock(&priv->attach_lock); + attach = priv->attach; + + switch (attach) { + case MT6370_ATTACH_STAT_DETACH: + usb_stat = 0; + break; + case MT6370_ATTACH_STAT_ATTACH_WAIT_FOR_BC12: + ret = mt6370_chg_field_set(priv, F_USBCHGEN, attach); + if (ret) + dev_err(priv->dev, "Failed to enable USB CHG EN\n"); + goto bc12_work_func_out; + case MT6370_ATTACH_STAT_ATTACH_BC12_DONE: + ret = mt6370_chg_field_get(priv, F_USB_STAT, &usb_stat); + if (ret) { + dev_err(priv->dev, "Failed to get USB status\n"); + goto bc12_work_func_out; + } + break; + default: + dev_err(priv->dev, "Invalid attach state\n"); + goto bc12_work_func_out; + } + + rpt_psy = true; + + switch (usb_stat) { + case MT6370_USB_STAT_SDP: + case MT6370_USB_STAT_SDP_NSTD: + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; + break; + case MT6370_USB_STAT_DCP: + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; + break; + case MT6370_USB_STAT_CDP: + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP; + break; + case MT6370_USB_STAT_NO_VBUS: + case MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING: + default: + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; + break; + } + +bc12_work_func_out: + mutex_unlock(&priv->attach_lock); + + if (rpt_psy) + power_supply_changed(priv->psy); +} + +static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv) +{ + int ret; + unsigned int fl_strobe; + + /* check if flash led in strobe mode */ + ret = mt6370_chg_field_get(priv, F_FL_STROBE, &fl_strobe); + if (ret) { + dev_err(priv->dev, "Failed to get FL_STROBE_EN\n"); + return ret; + } + + if (fl_strobe) { + dev_err(priv->dev, "Flash led is still in strobe mode\n"); + return ret; + } + + /* cfo off */ + ret = mt6370_chg_field_set(priv, F_CFO_EN, 0); + if (ret) { + dev_err(priv->dev, "Failed to disable CFO_EN\n"); + return ret; + } + + /* cfo on */ + ret = mt6370_chg_field_set(priv, F_CFO_EN, 1); + if (ret) + dev_err(priv->dev, "Failed to enable CFO_EN\n"); + + return ret; +} + +static int mt6370_chg_read_adc_chan(struct mt6370_priv *priv, unsigned int chan, + int *val) +{ + int ret; + + if (chan >= MT6370_ADC_CHAN_MAX) + return -EINVAL; + + ret = iio_read_channel_processed(&priv->iio_adcs[chan], val); + if (ret) + dev_err(priv->dev, "Failed to read ADC\n"); + + return ret; +} + +static void mt6370_chg_mivr_dwork_func(struct work_struct *work) +{ + struct mt6370_priv *priv = container_of(work, struct mt6370_priv, + mivr_dwork.work); + int ret; + unsigned int mivr_stat, ibus; + + ret = mt6370_chg_field_get(priv, F_CHG_MIVR_STAT, &mivr_stat); + if (ret) { + dev_err(priv->dev, "Failed to get mivr state\n"); + goto mivr_handler_out; + } + + if (!mivr_stat) + goto mivr_handler_out; + + ret = mt6370_chg_read_adc_chan(priv, MT6370_ADC_CHAN_IBUS, &ibus); + if (ret) { + dev_err(priv->dev, "Failed to get ibus\n"); + goto mivr_handler_out; + } + + if (ibus < MT6370_MIVR_IBUS_TH_100_mA) { + ret = mt6370_chg_toggle_cfo(priv); + if (ret) + dev_err(priv->dev, "Failed to toggle cfo\n"); + } + +mivr_handler_out: + enable_irq(priv->irq_nums[MT6370_IRQ_MIVR]); + pm_relax(priv->dev); +} + +static void mt6370_chg_pwr_rdy_check(struct mt6370_priv *priv) +{ + int ret; + unsigned int opposite_pwr_rdy, otg_en; + union power_supply_propval val; + + /* Check in OTG mode or not */ + ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en); + if (ret) { + dev_err(priv->dev, "Failed to get OTG state\n"); + return; + } + + if (otg_en) + return; + + ret = mt6370_chg_field_get(priv, F_UVP_D_STAT, &opposite_pwr_rdy); + if (ret) { + dev_err(priv->dev, "Failed to get opposite power ready state\n"); + return; + } + + val.intval = opposite_pwr_rdy ? + MT6370_ATTACH_STAT_DETACH : + MT6370_ATTACH_STAT_ATTACH_WAIT_FOR_BC12; + + ret = power_supply_set_property(priv->psy, POWER_SUPPLY_PROP_ONLINE, + &val); + if (ret) + dev_err(priv->dev, "Failed to start attach/detach flow\n"); +} + +static int mt6370_chg_get_online(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + mutex_lock(&priv->attach_lock); + val->intval = !!priv->attach; + mutex_unlock(&priv->attach_lock); + + return 0; +} + +static int mt6370_chg_get_status(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + int ret; + unsigned int chg_stat; + union power_supply_propval online; + + ret = power_supply_get_property(priv->psy, POWER_SUPPLY_PROP_ONLINE, + &online); + if (ret) { + dev_err(priv->dev, "Failed to get online status\n"); + return ret; + } + + if (!online.intval) { + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + return 0; + } + + ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat); + if (ret) + return ret; + + switch (chg_stat) { + case MT6370_CHG_STAT_READY: + case MT6370_CHG_STAT_FAULT: + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + return ret; + case MT6370_CHG_STAT_CHARGE_IN_PROGRESS: + val->intval = POWER_SUPPLY_STATUS_CHARGING; + return ret; + case MT6370_CHG_STAT_DONE: + val->intval = POWER_SUPPLY_STATUS_FULL; + return ret; + default: + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + return ret; + } +} + +static int mt6370_chg_get_charge_type(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + int type, ret; + unsigned int chg_stat, vbat_lvl; + + ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat); + if (ret) + return ret; + + ret = mt6370_chg_field_get(priv, F_VBAT_LVL, &vbat_lvl); + if (ret) + return ret; + + switch (chg_stat) { + case MT6370_CHG_STAT_CHARGE_IN_PROGRESS: + if (vbat_lvl) + type = POWER_SUPPLY_CHARGE_TYPE_FAST; + else + type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case MT6370_CHG_STAT_READY: + case MT6370_CHG_STAT_DONE: + case MT6370_CHG_STAT_FAULT: + default: + type = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + } + + val->intval = type; + + return 0; +} + +static int mt6370_chg_set_online(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + bool pwr_rdy = !!val->intval; + + mutex_lock(&priv->attach_lock); + if (pwr_rdy == !!priv->attach) { + dev_err(priv->dev, "pwr_rdy is same(%d)\n", pwr_rdy); + mutex_unlock(&priv->attach_lock); + return 0; + } + + priv->attach = pwr_rdy; + mutex_unlock(&priv->attach_lock); + + if (!queue_work(priv->wq, &priv->bc12_work)) + dev_err(priv->dev, "bc12 work has already queued\n"); + + return 0; +} + +static int mt6370_chg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct mt6370_priv *priv = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + return mt6370_chg_get_online(priv, val); + case POWER_SUPPLY_PROP_STATUS: + return mt6370_chg_get_status(priv, val); + case POWER_SUPPLY_PROP_CHARGE_TYPE: + return mt6370_chg_get_charge_type(priv, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + return mt6370_chg_field_get(priv, F_ICHG, &val->intval); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_ICHG]); + return 0; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + return mt6370_chg_field_get(priv, F_VOREG, &val->intval); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_VOREG]); + return 0; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return mt6370_chg_field_get(priv, F_IAICR, &val->intval); + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + return mt6370_chg_field_get(priv, F_VMIVR, &val->intval); + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + return mt6370_chg_field_get(priv, F_IPREC, &val->intval); + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return mt6370_chg_field_get(priv, F_IEOC, &val->intval); + case POWER_SUPPLY_PROP_USB_TYPE: + val->intval = priv->psy_usb_type; + return 0; + default: + return -EINVAL; + } +} + +static int mt6370_chg_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct mt6370_priv *priv = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + return mt6370_chg_set_online(priv, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + return mt6370_chg_field_set(priv, F_ICHG, val->intval); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + return mt6370_chg_field_set(priv, F_VOREG, val->intval); + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return mt6370_chg_field_set(priv, F_IAICR, val->intval); + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + return mt6370_chg_field_set(priv, F_VMIVR, val->intval); + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + return mt6370_chg_field_set(priv, F_IPREC, val->intval); + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return mt6370_chg_field_set(priv, F_IEOC, val->intval); + default: + return -EINVAL; + } +} + +static int mt6370_chg_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return 1; + default: + return 0; + } +} + +static enum power_supply_property mt6370_chg_properties[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, + POWER_SUPPLY_PROP_USB_TYPE, +}; + +static enum power_supply_usb_type mt6370_chg_usb_types[] = { + POWER_SUPPLY_USB_TYPE_UNKNOWN, + POWER_SUPPLY_USB_TYPE_SDP, + POWER_SUPPLY_USB_TYPE_CDP, + POWER_SUPPLY_USB_TYPE_DCP, +}; + +static const struct power_supply_desc mt6370_chg_psy_desc = { + .name = "mt6370-charger", + .type = POWER_SUPPLY_TYPE_USB, + .properties = mt6370_chg_properties, + .num_properties = ARRAY_SIZE(mt6370_chg_properties), + .get_property = mt6370_chg_get_property, + .set_property = mt6370_chg_set_property, + .property_is_writeable = mt6370_chg_property_is_writeable, + .usb_types = mt6370_chg_usb_types, + .num_usb_types = ARRAY_SIZE(mt6370_chg_usb_types), +}; + +static const struct regulator_ops mt6370_chg_otg_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, +}; + +static const u32 mt6370_chg_otg_oc_ma[] = { + 500000, 700000, 1100000, 1300000, 1800000, 2100000, 2400000, +}; + +static const struct regulator_desc mt6370_chg_otg_rdesc = { + .of_match = "usb-otg-vbus-regulator", + .of_parse_cb = mt6370_chg_otg_of_parse_cb, + .name = "mt6370-usb-otg-vbus", + .ops = &mt6370_chg_otg_ops, + .owner = THIS_MODULE, + .type = REGULATOR_VOLTAGE, + .min_uV = 4425000, + .uV_step = 25000, + .n_voltages = 57, + .vsel_reg = MT6370_REG_CHG_CTRL5, + .vsel_mask = MT6370_VOBST_MASK, + .enable_reg = MT6370_REG_CHG_CTRL1, + .enable_mask = MT6370_OPA_MODE_MASK, + .curr_table = mt6370_chg_otg_oc_ma, + .n_current_limits = ARRAY_SIZE(mt6370_chg_otg_oc_ma), + .csel_reg = MT6370_REG_CHG_CTRL10, + .csel_mask = MT6370_OTG_OC_MASK, +}; + +static int mt6370_chg_init_rmap_fields(struct mt6370_priv *priv) +{ + int i; + const struct mt6370_chg_field *fds = mt6370_chg_fields; + + for (i = 0; i < F_MAX; i++) { + priv->rmap_fields[i] = devm_regmap_field_alloc(priv->dev, + priv->regmap, + fds[i].field); + if (IS_ERR(priv->rmap_fields[i])) + return dev_err_probe(priv->dev, + PTR_ERR(priv->rmap_fields[i]), + "Failed to allocate regmapfield[%s]\n", + fds[i].name); + } + + return 0; +} + +static int mt6370_chg_init_setting(struct mt6370_priv *priv) +{ + int ret; + + /* Disable usb_chg_en */ + ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0); + if (ret) { + dev_err(priv->dev, "Failed to disable usb_chg_en\n"); + return ret; + } + + /* Disable input current limit */ + ret = mt6370_chg_field_set(priv, F_ILIM_EN, 0); + if (ret) { + dev_err(priv->dev, "Failed to disable input current limit\n"); + return ret; + } + + /* ICHG/IEOC Workaround, ICHG can not be set less than 900mA */ + ret = mt6370_chg_field_set(priv, F_ICHG, 900000); + if (ret) { + dev_err(priv->dev, "Failed to set ICHG to 900mA"); + return ret; + } + + /* Change input current limit selection to using IAICR results */ + ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 2); + if (ret) { + dev_err(priv->dev, "Failed to set IINLMTSEL\n"); + return ret; + } + + return 0; +} + +#define MT6370_CHG_DT_PROP_DECL(_name, _type, _field) \ +{ \ + .name = "mediatek,chg-" #_name, \ + .type = MT6370_PARSE_TYPE_##_type, \ + .fd = _field, \ +} + +static int mt6370_chg_init_otg_regulator(struct mt6370_priv *priv) +{ + struct regulator_config rcfg = { + .dev = priv->dev, + .regmap = priv->regmap, + .driver_data = priv, + }; + + priv->rdev = devm_regulator_register(priv->dev, &mt6370_chg_otg_rdesc, + &rcfg); + + return PTR_ERR_OR_ZERO(priv->rdev); +} + +static int mt6370_chg_init_psy(struct mt6370_priv *priv) +{ + struct power_supply_config cfg = { + .drv_data = priv, + .of_node = dev_of_node(priv->dev), + }; + + priv->psy = devm_power_supply_register(priv->dev, &mt6370_chg_psy_desc, + &cfg); + + return PTR_ERR_OR_ZERO(priv->psy); +} + +static void mt6370_chg_destroy_attach_lock(void *data) +{ + struct mutex *attach_lock = data; + + mutex_destroy(attach_lock); +} + +static void mt6370_chg_destroy_wq(void *data) +{ + struct workqueue_struct *wq = data; + + flush_workqueue(wq); + destroy_workqueue(wq); +} + +static irqreturn_t mt6370_attach_i_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + unsigned int otg_en; + int ret; + + /* Check in OTG mode or not */ + ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en); + if (ret) { + dev_err(priv->dev, "Failed to get OTG state\n"); + return IRQ_NONE; + } + + if (otg_en) + return IRQ_HANDLED; + + mutex_lock(&priv->attach_lock); + priv->attach = MT6370_ATTACH_STAT_ATTACH_BC12_DONE; + mutex_unlock(&priv->attach_lock); + + if (!queue_work(priv->wq, &priv->bc12_work)) + dev_err(priv->dev, "bc12 work has already queued\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t mt6370_uvp_d_evt_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + + mt6370_chg_pwr_rdy_check(priv); + + return IRQ_HANDLED; +} + +static irqreturn_t mt6370_mivr_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + + pm_stay_awake(priv->dev); + disable_irq_nosync(priv->irq_nums[MT6370_IRQ_MIVR]); + schedule_delayed_work(&priv->mivr_dwork, msecs_to_jiffies(200)); + + return IRQ_HANDLED; +} + +#define MT6370_CHG_IRQ(_name) \ +{ \ + .name = #_name, \ + .handler = mt6370_##_name##_handler, \ +} + +static int mt6370_chg_init_irq(struct mt6370_priv *priv) +{ + int i, ret; + const struct { + char *name; + irq_handler_t handler; + } mt6370_chg_irqs[] = { + MT6370_CHG_IRQ(attach_i), + MT6370_CHG_IRQ(uvp_d_evt), + MT6370_CHG_IRQ(mivr), + }; + + for (i = 0; i < ARRAY_SIZE(mt6370_chg_irqs); i++) { + 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); + + priv->irq_nums[i] = ret; + ret = devm_request_threaded_irq(priv->dev, ret, NULL, + mt6370_chg_irqs[i].handler, + IRQF_TRIGGER_FALLING, + dev_name(priv->dev), priv); + if (ret) + return dev_err_probe(priv->dev, ret, + "Failed to request irq %s\n", + mt6370_chg_irqs[i].name); + } + + return 0; +} + +static int mt6370_chg_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mt6370_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) + return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n"); + + ret = mt6370_chg_init_rmap_fields(priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to init regmap fields\n"); + + platform_set_drvdata(pdev, priv); + + priv->iio_adcs = devm_iio_channel_get_all(priv->dev); + if (IS_ERR(priv->iio_adcs)) + return dev_err_probe(dev, PTR_ERR(priv->iio_adcs), + "Failed to get iio adc\n"); + + ret = mt6370_chg_init_otg_regulator(priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to init OTG regulator\n"); + + ret = mt6370_chg_init_psy(priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to init psy\n"); + + mutex_init(&priv->attach_lock); + ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_attach_lock, + &priv->attach_lock); + if (ret) + return dev_err_probe(dev, ret, "Failed to init attach lock\n"); + + priv->attach = MT6370_ATTACH_STAT_DETACH; + + priv->wq = create_singlethread_workqueue(dev_name(priv->dev)); + if (IS_ERR(priv->wq)) + return dev_err_probe(dev, PTR_ERR(priv->wq), + "Failed to create workqueue\n"); + + ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_wq, priv->wq); + if (ret) + return dev_err_probe(dev, ret, "Failed to init wq\n"); + + ret = devm_work_autocancel(dev, &priv->bc12_work, mt6370_chg_bc12_work_func); + if (ret) + return dev_err_probe(dev, ret, "Failed to init bc12 work\n"); + + ret = devm_delayed_work_autocancel(dev, &priv->mivr_dwork, mt6370_chg_mivr_dwork_func); + if (ret) + return dev_err_probe(dev, ret, "Failed to init mivr delayed work\n"); + + ret = mt6370_chg_init_setting(priv); + if (ret) + return dev_err_probe(dev, ret, + "Failed to init mt6370 charger setting\n"); + + ret = mt6370_chg_init_irq(priv); + if (ret) + return ret; + + mt6370_chg_pwr_rdy_check(priv); + + return 0; +} + +static const struct of_device_id mt6370_chg_of_match[] = { + { .compatible = "mediatek,mt6370-charger", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_chg_of_match); + +static struct platform_driver mt6370_chg_driver = { + .probe = mt6370_chg_probe, + .driver = { + .name = "mt6370-charger", + .of_match_table = mt6370_chg_of_match, + }, +}; +module_platform_driver(mt6370_chg_driver); + +MODULE_AUTHOR("ChiaEn Wu "); +MODULE_DESCRIPTION("MediaTek MT6370 Charger Driver"); +MODULE_LICENSE("GPL v2"); From 8bc800062221adb40eb24c4b4fd5c572a637114c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 28 Sep 2022 22:19:26 +0100 Subject: [PATCH 18/22] power: supply: max1721x: Fix spelling mistake "Gauage" -> "Gauge" There is a spelling mistake in the module description. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Sebastian Reichel --- drivers/power/supply/max1721x_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/max1721x_battery.c b/drivers/power/supply/max1721x_battery.c index 473e53cd2801..d8d52e09da7b 100644 --- a/drivers/power/supply/max1721x_battery.c +++ b/drivers/power/supply/max1721x_battery.c @@ -444,5 +444,5 @@ module_w1_family(w1_max1721x_family); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alex A. Mihaylov "); -MODULE_DESCRIPTION("Maxim MAX17211/MAX17215 Fuel Gauage IC driver"); +MODULE_DESCRIPTION("Maxim MAX17211/MAX17215 Fuel Gauge IC driver"); MODULE_ALIAS("w1-family-" __stringify(W1_MAX1721X_FAMILY_ID)); From d8be4fe92433ad905eedc7d877099685eb2eaaa1 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 28 Sep 2022 23:29:40 -0700 Subject: [PATCH 19/22] power: supply: mt6370: uses IIO interfaces, depends on IIO The mt6370-charger driver uses IIO interfaces and produces build errors when CONFIG_IIO is not set, so it should depend on IIO. ERROR: modpost: "iio_read_channel_processed" [drivers/power/supply/mt6370-charger.ko] undefined! ERROR: modpost: "devm_iio_channel_get_all" [drivers/power/supply/mt6370-charger.ko] undefined! Fixes: 233cb8a47d65 ("power: supply: mt6370: Add MediaTek MT6370 charger driver") Signed-off-by: Randy Dunlap Cc: ChiaEn Wu Cc: Sebastian Reichel Cc: linux-pm@vger.kernel.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 591deb82e2c6..62111f4bb093 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -623,6 +623,7 @@ config CHARGER_MT6370 tristate "MediaTek MT6370 Charger Driver" depends on MFD_MT6370 depends on REGULATOR + depends on IIO select LINEAR_RANGES help Say Y here to enable MT6370 Charger Part. From fe259a2155b43dff59be1e1e3c59ac72cfeab630 Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Tue, 27 Sep 2022 13:37:58 +0000 Subject: [PATCH 20/22] power: supply: ab8500: Remove unused struct ab8500_chargalg_sysfs_entry After commit 75ee3f6f0c1a("power: supply: ab8500_chargalg: Drop enable/disable sysfs"), no one use struct ab8500_chargalg_sysfs_entry, so remove it. Signed-off-by: Yuan Can Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_chargalg.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index ae4be553f424..40210d484be0 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -252,12 +252,6 @@ static enum power_supply_property ab8500_chargalg_props[] = { POWER_SUPPLY_PROP_HEALTH, }; -struct ab8500_chargalg_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct ab8500_chargalg *di, char *buf); - ssize_t (*store)(struct ab8500_chargalg *di, const char *buf, size_t length); -}; - /** * ab8500_chargalg_safety_timer_expired() - Expiration of the safety timer * @timer: pointer to the hrtimer structure From 5738d49fa47e0046050f5e62e4921d667b7ee3c3 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 23:29:15 +0800 Subject: [PATCH 21/22] power: supply: mt6370: Fix return value check in mt6370_chg_probe() If create_singlethread_workqueue() fails, it returns a null pointer, replace IS_ERR() check with NULL pointer check. Fixes: 233cb8a47d65 ("power: supply: mt6370: Add MediaTek MT6370 charger driver") Signed-off-by: Yang Yingliang Reviewed-by: ChiaEn Wu Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Sebastian Reichel --- drivers/power/supply/mt6370-charger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c index 716cba259a7a..f27dae5043f5 100644 --- a/drivers/power/supply/mt6370-charger.c +++ b/drivers/power/supply/mt6370-charger.c @@ -911,8 +911,8 @@ static int mt6370_chg_probe(struct platform_device *pdev) priv->attach = MT6370_ATTACH_STAT_DETACH; priv->wq = create_singlethread_workqueue(dev_name(priv->dev)); - if (IS_ERR(priv->wq)) - return dev_err_probe(dev, PTR_ERR(priv->wq), + if (!priv->wq) + return dev_err_probe(dev, -ENOMEM, "Failed to create workqueue\n"); ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_wq, priv->wq); From 189a2aaef9cbee4cd7c3d1bd142f790cc14c598e Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Mon, 18 Jul 2022 22:27:43 -0400 Subject: [PATCH 22/22] power: supply: ab8500: remove unused static local variable cpp_check reports [drivers/power/supply/ab8500_chargalg.c:493]: (style) Variable 'ab8500_chargalg_ex_ac_enable_toggle' is assigned a value that is never used. From inspection, this variable is never used. So remove it. Fixes: 6c50a08d9dd3 ("power: supply: ab8500: Drop external charger leftovers") Signed-off-by: Tom Rix Reviewed-by: Linus Walleij Reviewed-by: Chen Lifu Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_chargalg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 40210d484be0..ea4ad61d4c7e 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -484,8 +484,6 @@ static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di) static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, int vset_uv, int iset_ua) { - static int ab8500_chargalg_ex_ac_enable_toggle; - if (!di->ac_chg || !di->ac_chg->ops.enable) return -ENXIO;