diff options
author | Pavel <pavel@ucw.cz> | 2018-10-28 13:48:08 +0100 |
---|---|---|
committer | Pavel <pavel@ucw.cz> | 2019-01-07 11:22:50 +0100 |
commit | d4e3fa17e2e5c9a6a37f7cc01a3e3d8842f6dc41 (patch) | |
tree | f21782784c4b4e638a9e11eaf3c7ce27ed6d6158 | |
parent | af18736b64236dea75eae27987c82b3141a30670 (diff) | |
download | linux-k-d4e3fa17e2e5c9a6a37f7cc01a3e3d8842f6dc41.tar.gz |
d4: power: remove synthetic values, add control for charge current/voltage.
-rw-r--r-- | drivers/power/supply/cpcap-battery.c | 20 | ||||
-rw-r--r-- | drivers/power/supply/cpcap-charger.c | 132 |
2 files changed, 127 insertions, 25 deletions
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c index 08d5037fd05215..8eedfc50e63559 100644 --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -3,7 +3,7 @@ * * Copyright (C) 2017 Tony Lindgren <tony@atomide.com> * - * Some parts of the code based on earlie Motorola mapphone Linux kernel + * Some parts of the code based on earlier Motorola mapphone Linux kernel * drivers: * * Copyright (C) 2009-2010 Motorola, Inc. @@ -490,24 +490,6 @@ static int cpcap_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER: val->intval = latest->counter_uah; break; - case POWER_SUPPLY_PROP_POWER_NOW: - tmp = (latest->voltage / 10000) * latest->current_ua; - val->intval = div64_s64(tmp, 100); - break; - case POWER_SUPPLY_PROP_POWER_AVG: - if (cached) { - tmp = cpcap_battery_cc_get_avg_current(ddata); - tmp *= (latest->voltage / 10000); - val->intval = div64_s64(tmp, 100); - break; - } - sample = latest->cc.sample - previous->cc.sample; - accumulator = latest->cc.accumulator - previous->cc.accumulator; - tmp = cpcap_battery_cc_to_ua(ddata, sample, accumulator, - latest->cc.offset); - tmp *= ((latest->voltage + previous->voltage) / 20000); - val->intval = div64_s64(tmp, 100); - break; case POWER_SUPPLY_PROP_CAPACITY_LEVEL: if (cpcap_battery_full(ddata)) val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index c843eaff8ad055..0477b972735181 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -93,6 +93,17 @@ #define CPCAP_REG_CRM_VCHRG_4V42 CPCAP_REG_CRM_VCHRG(0xe) #define CPCAP_REG_CRM_VCHRG_4V44 CPCAP_REG_CRM_VCHRG(0xf) +static int voltage_to_register(int microvolt) +{ + switch (microvolt/1000) { + case 3800: return CPCAP_REG_CRM_VCHRG_3V80; + case 4100: return CPCAP_REG_CRM_VCHRG_4V10; + case 4200: return CPCAP_REG_CRM_VCHRG_4V20; + case 4350: return CPCAP_REG_CRM_VCHRG_4V35; + default: return -EINVAL; + } +} + /* * CPCAP_REG_CRM charge currents. These seem to match MC13783UG.pdf * values in "Table 8-3. Charge Path Regulator Current Limit @@ -116,6 +127,18 @@ #define CPCAP_REG_CRM_ICHRG_1A596 CPCAP_REG_CRM_ICHRG(0xe) #define CPCAP_REG_CRM_ICHRG_NO_LIMIT CPCAP_REG_CRM_ICHRG(0xf) +static int current_to_register(int microamp) +{ + switch (microamp/1000) { + case 0: return CPCAP_REG_CRM_ICHRG_0A000; + case 70: return CPCAP_REG_CRM_ICHRG_0A070; + case 177: return CPCAP_REG_CRM_ICHRG_0A177; + case 532: return CPCAP_REG_CRM_ICHRG_0A532; + case 1596: return CPCAP_REG_CRM_ICHRG_1A596; + default: return -EINVAL; + } +} + enum { CPCAP_CHARGER_IIO_BATTDET, CPCAP_CHARGER_IIO_VOLTAGE, @@ -142,6 +165,10 @@ struct cpcap_charger_ddata { atomic_t active; int status; + + int led_enabled; + int limit_current; + int limit_voltage; }; struct cpcap_interrupt_desc { @@ -163,11 +190,17 @@ struct cpcap_charger_ints_state { bool battdetb; }; +#define POWER_SUPPLY_PROP_INDICATION POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT + static enum power_supply_property cpcap_charger_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, + + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_INDICATION, }; static bool cpcap_charger_battery_found(struct cpcap_charger_ddata *ddata) @@ -229,6 +262,7 @@ static int cpcap_charger_get_property(struct power_supply *psy, val->intval = ddata->status; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: + /* FIXME? Display voltage even when not charging? */ if (ddata->status == POWER_SUPPLY_STATUS_CHARGING) val->intval = cpcap_charger_get_charge_voltage(ddata) * 1000; @@ -245,6 +279,50 @@ static int cpcap_charger_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_ONLINE: val->intval = ddata->status == POWER_SUPPLY_STATUS_CHARGING; break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + // -> charger -- current limit + val->intval = ddata->limit_current; + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + val->intval = ddata->limit_voltage; + break; + case POWER_SUPPLY_PROP_INDICATION: + val->intval = ddata->led_enabled; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cpcap_charger_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct cpcap_charger_ddata *ddata = dev_get_drvdata(psy->dev.parent); + + switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + printk("charge current: %d\n", val->intval); + if (current_to_register(val->intval) < 0) + return -EINVAL; + ddata->limit_current = val->intval; + schedule_delayed_work(&ddata->detect_work, 0); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + printk("charge voltage: %d\n", val->intval); + if (voltage_to_register(val->intval) < 0) + return -EINVAL; + ddata->limit_voltage = val->intval; + schedule_delayed_work(&ddata->detect_work, 0); + break; + case POWER_SUPPLY_PROP_INDICATION: + printk("hack indication: %d\n", val->intval); + ddata->led_enabled = !!val->intval; + schedule_delayed_work(&ddata->detect_work, 0); + break; default: return -EINVAL; } @@ -296,7 +374,7 @@ static int cpcap_charger_set_state(struct cpcap_charger_ddata *ddata, } error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, 0x3fff, - CPCAP_REG_CRM_CHRG_LED_EN | + ddata->led_enabled * CPCAP_REG_CRM_CHRG_LED_EN | trickle_current | CPCAP_REG_CRM_FET_OVRD | CPCAP_REG_CRM_FET_CTRL | @@ -440,16 +518,39 @@ static void cpcap_usb_detect(struct work_struct *work) return; if (cpcap_charger_vbus_valid(ddata) && s.chrgcurr1) { - int max_current; + int m_voltage, m_current; + int reg_current, reg_voltage; if (cpcap_charger_battery_found(ddata)) - max_current = CPCAP_REG_CRM_ICHRG_1A596; + m_current = 1596000; else - max_current = CPCAP_REG_CRM_ICHRG_0A532; + m_current = 532000; + + if (m_current > ddata->limit_current) + m_current = ddata->limit_current; + + m_voltage = 4350000; + if (m_voltage > ddata->limit_voltage) + m_voltage = ddata->limit_voltage; + + if (printk_ratelimit()) + printk("Charging, %d uV, %d uA\n", m_voltage, m_current); + + reg_voltage = voltage_to_register(m_voltage); + if (reg_voltage < 0) { + dev_err(ddata->dev, "%s impossible voltage\n", __func__); + return; + } + + reg_current = current_to_register(m_current); + if (reg_current < 0) { + dev_err(ddata->dev, "%s impossible current\n", __func__); + return; + } error = cpcap_charger_set_state(ddata, - CPCAP_REG_CRM_VCHRG_4V35, - max_current, 0); + reg_voltage, + reg_current, 0); if (error) goto out_err; } else { @@ -579,12 +680,27 @@ out_err: return error; } +static int cpcap_charger_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + case POWER_SUPPLY_PROP_INDICATION: + return 1; + default: + return 0; + } +} + static const struct power_supply_desc cpcap_charger_usb_desc = { .name = "usb", .type = POWER_SUPPLY_TYPE_USB, .properties = cpcap_charger_props, .num_properties = ARRAY_SIZE(cpcap_charger_props), .get_property = cpcap_charger_get_property, + .set_property = cpcap_charger_set_property, + .property_is_writeable = cpcap_charger_property_is_writeable, }; #ifdef CONFIG_OF @@ -619,6 +735,10 @@ static int cpcap_charger_probe(struct platform_device *pdev) if (!ddata->reg) return -ENODEV; + ddata->limit_current = 1596000; + ddata->limit_voltage = 4350000; + ddata->led_enabled = 1; + INIT_LIST_HEAD(&ddata->irq_list); INIT_DELAYED_WORK(&ddata->detect_work, cpcap_usb_detect); INIT_DELAYED_WORK(&ddata->vbus_work, cpcap_charger_vbus_work); |