diff options
-rw-r--r-- | Documentation/devicetree/bindings/power/reset/qcom,pon.yaml | 50 | ||||
-rw-r--r-- | drivers/power/reset/qcom-pon.c | 1 | ||||
-rw-r--r-- | drivers/power/supply/adp5061.c | 9 | ||||
-rw-r--r-- | drivers/power/supply/bq25890_charger.c | 30 | ||||
-rw-r--r-- | drivers/power/supply/bq27xxx_battery.c | 60 | ||||
-rw-r--r-- | drivers/power/supply/cpcap-charger.c | 2 | ||||
-rw-r--r-- | drivers/power/supply/cw2015_battery.c | 14 | ||||
-rw-r--r-- | drivers/power/supply/power_supply_sysfs.c | 2 | ||||
-rw-r--r-- | drivers/power/supply/tps65217_charger.c | 2 | ||||
-rw-r--r-- | include/linux/power_supply.h | 48 |
10 files changed, 161 insertions, 57 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 <dt-bindings/interrupt-controller/irq.h> 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); diff --git a/drivers/power/supply/adp5061.c b/drivers/power/supply/adp5061.c index 003557043ab3..fcf8ff0bc974 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; } @@ -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; diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 852a6fec4339..e6bd60fef0f6 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, TBL_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, }; @@ -946,6 +975,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"); } diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 35e6a394c0df..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 */ @@ -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); 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 <[email protected]> * * 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. */ 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 <linux/regmap.h> #include <linux/time.h> #include <linux/workqueue.h> +#include <linux/devm-helpers.h> #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, }; 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; } 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 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; |