123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * ADP5061 I2C Programmable Linear Battery Charger
- *
- * Copyright 2018 Analog Devices Inc.
- */
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/i2c.h>
- #include <linux/delay.h>
- #include <linux/pm.h>
- #include <linux/mod_devicetable.h>
- #include <linux/power_supply.h>
- #include <linux/platform_device.h>
- #include <linux/of.h>
- #include <linux/regmap.h>
- /* ADP5061 registers definition */
- #define ADP5061_ID 0x00
- #define ADP5061_REV 0x01
- #define ADP5061_VINX_SET 0x02
- #define ADP5061_TERM_SET 0x03
- #define ADP5061_CHG_CURR 0x04
- #define ADP5061_VOLTAGE_TH 0x05
- #define ADP5061_TIMER_SET 0x06
- #define ADP5061_FUNC_SET_1 0x07
- #define ADP5061_FUNC_SET_2 0x08
- #define ADP5061_INT_EN 0x09
- #define ADP5061_INT_ACT 0x0A
- #define ADP5061_CHG_STATUS_1 0x0B
- #define ADP5061_CHG_STATUS_2 0x0C
- #define ADP5061_FAULT 0x0D
- #define ADP5061_BATTERY_SHORT 0x10
- #define ADP5061_IEND 0x11
- /* ADP5061_VINX_SET */
- #define ADP5061_VINX_SET_ILIM_MSK GENMASK(3, 0)
- #define ADP5061_VINX_SET_ILIM_MODE(x) (((x) & 0x0F) << 0)
- /* ADP5061_TERM_SET */
- #define ADP5061_TERM_SET_VTRM_MSK GENMASK(7, 2)
- #define ADP5061_TERM_SET_VTRM_MODE(x) (((x) & 0x3F) << 2)
- #define ADP5061_TERM_SET_CHG_VLIM_MSK GENMASK(1, 0)
- #define ADP5061_TERM_SET_CHG_VLIM_MODE(x) (((x) & 0x03) << 0)
- /* ADP5061_CHG_CURR */
- #define ADP5061_CHG_CURR_ICHG_MSK GENMASK(6, 2)
- #define ADP5061_CHG_CURR_ICHG_MODE(x) (((x) & 0x1F) << 2)
- #define ADP5061_CHG_CURR_ITRK_DEAD_MSK GENMASK(1, 0)
- #define ADP5061_CHG_CURR_ITRK_DEAD_MODE(x) (((x) & 0x03) << 0)
- /* ADP5061_VOLTAGE_TH */
- #define ADP5061_VOLTAGE_TH_DIS_RCH_MSK BIT(7)
- #define ADP5061_VOLTAGE_TH_DIS_RCH_MODE(x) (((x) & 0x01) << 7)
- #define ADP5061_VOLTAGE_TH_VRCH_MSK GENMASK(6, 5)
- #define ADP5061_VOLTAGE_TH_VRCH_MODE(x) (((x) & 0x03) << 5)
- #define ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK GENMASK(4, 3)
- #define ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(x) (((x) & 0x03) << 3)
- #define ADP5061_VOLTAGE_TH_VWEAK_MSK GENMASK(2, 0)
- #define ADP5061_VOLTAGE_TH_VWEAK_MODE(x) (((x) & 0x07) << 0)
- /* ADP5061_CHG_STATUS_1 */
- #define ADP5061_CHG_STATUS_1_VIN_OV(x) (((x) >> 7) & 0x1)
- #define ADP5061_CHG_STATUS_1_VIN_OK(x) (((x) >> 6) & 0x1)
- #define ADP5061_CHG_STATUS_1_VIN_ILIM(x) (((x) >> 5) & 0x1)
- #define ADP5061_CHG_STATUS_1_THERM_LIM(x) (((x) >> 4) & 0x1)
- #define ADP5061_CHG_STATUS_1_CHDONE(x) (((x) >> 3) & 0x1)
- #define ADP5061_CHG_STATUS_1_CHG_STATUS(x) (((x) >> 0) & 0x7)
- /* ADP5061_CHG_STATUS_2 */
- #define ADP5061_CHG_STATUS_2_THR_STATUS(x) (((x) >> 5) & 0x7)
- #define ADP5061_CHG_STATUS_2_RCH_LIM_INFO(x) (((x) >> 3) & 0x1)
- #define ADP5061_CHG_STATUS_2_BAT_STATUS(x) (((x) >> 0) & 0x7)
- /* ADP5061_IEND */
- #define ADP5061_IEND_IEND_MSK GENMASK(7, 5)
- #define ADP5061_IEND_IEND_MODE(x) (((x) & 0x07) << 5)
- #define ADP5061_NO_BATTERY 0x01
- #define ADP5061_ICHG_MAX 1300 // mA
- enum adp5061_chg_status {
- ADP5061_CHG_OFF,
- ADP5061_CHG_TRICKLE,
- ADP5061_CHG_FAST_CC,
- ADP5061_CHG_FAST_CV,
- ADP5061_CHG_COMPLETE,
- ADP5061_CHG_LDO_MODE,
- ADP5061_CHG_TIMER_EXP,
- ADP5061_CHG_BAT_DET,
- };
- static const int adp5061_chg_type[4] = {
- [ADP5061_CHG_OFF] = POWER_SUPPLY_CHARGE_TYPE_NONE,
- [ADP5061_CHG_TRICKLE] = POWER_SUPPLY_CHARGE_TYPE_TRICKLE,
- [ADP5061_CHG_FAST_CC] = POWER_SUPPLY_CHARGE_TYPE_FAST,
- [ADP5061_CHG_FAST_CV] = POWER_SUPPLY_CHARGE_TYPE_FAST,
- };
- static const int adp5061_vweak_th[8] = {
- 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400,
- };
- static const int adp5061_prechg_current[4] = {
- 5, 10, 20, 80,
- };
- static const int adp5061_vmin[4] = {
- 2000, 2500, 2600, 2900,
- };
- static const int adp5061_const_chg_vmax[4] = {
- 3200, 3400, 3700, 3800,
- };
- static const int adp5061_const_ichg[24] = {
- 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650,
- 700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1200, 1300,
- };
- static const int adp5061_vmax[36] = {
- 3800, 3820, 3840, 3860, 3880, 3900, 3920, 3940, 3960, 3980,
- 4000, 4020, 4040, 4060, 4080, 4100, 4120, 4140, 4160, 4180,
- 4200, 4220, 4240, 4260, 4280, 4300, 4320, 4340, 4360, 4380,
- 4400, 4420, 4440, 4460, 4480, 4500,
- };
- static const int adp5061_in_current_lim[16] = {
- 100, 150, 200, 250, 300, 400, 500, 600, 700,
- 800, 900, 1000, 1200, 1500, 1800, 2100,
- };
- static const int adp5061_iend[8] = {
- 12500, 32500, 52500, 72500, 92500, 117500, 142500, 170000,
- };
- struct adp5061_state {
- struct i2c_client *client;
- struct regmap *regmap;
- struct power_supply *psy;
- };
- static int adp5061_get_array_index(const int *array, u8 size, int val)
- {
- int i;
- for (i = 1; i < size; i++) {
- if (val < array[i])
- break;
- }
- return i-1;
- }
- static int adp5061_get_status(struct adp5061_state *st,
- u8 *status1, u8 *status2)
- {
- u8 buf[2];
- int ret;
- /* CHG_STATUS1 and CHG_STATUS2 are adjacent regs */
- ret = regmap_bulk_read(st->regmap, ADP5061_CHG_STATUS_1,
- &buf[0], 2);
- if (ret < 0)
- return ret;
- *status1 = buf[0];
- *status2 = buf[1];
- return ret;
- }
- static int adp5061_get_input_current_limit(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- unsigned int regval;
- int mode, ret;
- ret = regmap_read(st->regmap, ADP5061_VINX_SET, ®val);
- if (ret < 0)
- return ret;
- mode = ADP5061_VINX_SET_ILIM_MODE(regval);
- val->intval = adp5061_in_current_lim[mode] * 1000;
- return ret;
- }
- static int adp5061_set_input_current_limit(struct adp5061_state *st, int val)
- {
- int index;
- /* Convert from uA to mA */
- val /= 1000;
- index = adp5061_get_array_index(adp5061_in_current_lim,
- ARRAY_SIZE(adp5061_in_current_lim),
- val);
- if (index < 0)
- return index;
- return regmap_update_bits(st->regmap, ADP5061_VINX_SET,
- ADP5061_VINX_SET_ILIM_MSK,
- ADP5061_VINX_SET_ILIM_MODE(index));
- }
- static int adp5061_set_min_voltage(struct adp5061_state *st, int val)
- {
- int index;
- /* Convert from uV to mV */
- val /= 1000;
- index = adp5061_get_array_index(adp5061_vmin,
- ARRAY_SIZE(adp5061_vmin),
- val);
- if (index < 0)
- return index;
- return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH,
- ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK,
- ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(index));
- }
- static int adp5061_get_min_voltage(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- unsigned int regval;
- int ret;
- ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val);
- if (ret < 0)
- return ret;
- regval = ((regval & ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK) >> 3);
- val->intval = adp5061_vmin[regval] * 1000;
- return ret;
- }
- static int adp5061_get_chg_volt_lim(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- unsigned int regval;
- int mode, ret;
- ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val);
- if (ret < 0)
- return ret;
- mode = ADP5061_TERM_SET_CHG_VLIM_MODE(regval);
- val->intval = adp5061_const_chg_vmax[mode] * 1000;
- return ret;
- }
- static int adp5061_get_max_voltage(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- unsigned int regval;
- int ret;
- ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val);
- if (ret < 0)
- return ret;
- regval = ((regval & ADP5061_TERM_SET_VTRM_MSK) >> 2) - 0x0F;
- if (regval >= ARRAY_SIZE(adp5061_vmax))
- regval = ARRAY_SIZE(adp5061_vmax) - 1;
- val->intval = adp5061_vmax[regval] * 1000;
- return ret;
- }
- static int adp5061_set_max_voltage(struct adp5061_state *st, int val)
- {
- int vmax_index;
- /* Convert from uV to mV */
- val /= 1000;
- if (val > 4500)
- val = 4500;
- vmax_index = adp5061_get_array_index(adp5061_vmax,
- ARRAY_SIZE(adp5061_vmax), val);
- if (vmax_index < 0)
- return vmax_index;
- vmax_index += 0x0F;
- return regmap_update_bits(st->regmap, ADP5061_TERM_SET,
- ADP5061_TERM_SET_VTRM_MSK,
- ADP5061_TERM_SET_VTRM_MODE(vmax_index));
- }
- static int adp5061_set_const_chg_vmax(struct adp5061_state *st, int val)
- {
- int index;
- /* Convert from uV to mV */
- val /= 1000;
- index = adp5061_get_array_index(adp5061_const_chg_vmax,
- ARRAY_SIZE(adp5061_const_chg_vmax),
- val);
- if (index < 0)
- return index;
- return regmap_update_bits(st->regmap, ADP5061_TERM_SET,
- ADP5061_TERM_SET_CHG_VLIM_MSK,
- ADP5061_TERM_SET_CHG_VLIM_MODE(index));
- }
- static int adp5061_set_const_chg_current(struct adp5061_state *st, int val)
- {
- int index;
- /* Convert from uA to mA */
- val /= 1000;
- if (val > ADP5061_ICHG_MAX)
- val = ADP5061_ICHG_MAX;
- index = adp5061_get_array_index(adp5061_const_ichg,
- ARRAY_SIZE(adp5061_const_ichg),
- val);
- if (index < 0)
- return index;
- return regmap_update_bits(st->regmap, ADP5061_CHG_CURR,
- ADP5061_CHG_CURR_ICHG_MSK,
- ADP5061_CHG_CURR_ICHG_MODE(index));
- }
- static int adp5061_get_const_chg_current(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- unsigned int regval;
- int ret;
- ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val);
- if (ret < 0)
- return ret;
- regval = ((regval & ADP5061_CHG_CURR_ICHG_MSK) >> 2);
- if (regval >= ARRAY_SIZE(adp5061_const_ichg))
- regval = ARRAY_SIZE(adp5061_const_ichg) - 1;
- val->intval = adp5061_const_ichg[regval] * 1000;
- return ret;
- }
- static int adp5061_get_prechg_current(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- unsigned int regval;
- int ret;
- ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val);
- if (ret < 0)
- return ret;
- regval &= ADP5061_CHG_CURR_ITRK_DEAD_MSK;
- val->intval = adp5061_prechg_current[regval] * 1000;
- return ret;
- }
- static int adp5061_set_prechg_current(struct adp5061_state *st, int val)
- {
- int index;
- /* Convert from uA to mA */
- val /= 1000;
- index = adp5061_get_array_index(adp5061_prechg_current,
- ARRAY_SIZE(adp5061_prechg_current),
- val);
- if (index < 0)
- return index;
- return regmap_update_bits(st->regmap, ADP5061_CHG_CURR,
- ADP5061_CHG_CURR_ITRK_DEAD_MSK,
- ADP5061_CHG_CURR_ITRK_DEAD_MODE(index));
- }
- static int adp5061_get_vweak_th(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- unsigned int regval;
- int ret;
- ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val);
- if (ret < 0)
- return ret;
- regval &= ADP5061_VOLTAGE_TH_VWEAK_MSK;
- val->intval = adp5061_vweak_th[regval] * 1000;
- return ret;
- }
- static int adp5061_set_vweak_th(struct adp5061_state *st, int val)
- {
- int index;
- /* Convert from uV to mV */
- val /= 1000;
- index = adp5061_get_array_index(adp5061_vweak_th,
- ARRAY_SIZE(adp5061_vweak_th),
- val);
- if (index < 0)
- return index;
- return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH,
- ADP5061_VOLTAGE_TH_VWEAK_MSK,
- ADP5061_VOLTAGE_TH_VWEAK_MODE(index));
- }
- static int adp5061_get_chg_type(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- u8 status1, status2;
- int chg_type, ret;
- ret = adp5061_get_status(st, &status1, &status2);
- if (ret < 0)
- return ret;
- 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 = adp5061_chg_type[chg_type];
- return ret;
- }
- static int adp5061_get_charger_status(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- u8 status1, status2;
- int ret;
- ret = adp5061_get_status(st, &status1, &status2);
- if (ret < 0)
- return ret;
- switch (ADP5061_CHG_STATUS_1_CHG_STATUS(status1)) {
- case ADP5061_CHG_OFF:
- val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
- break;
- case ADP5061_CHG_TRICKLE:
- case ADP5061_CHG_FAST_CC:
- case ADP5061_CHG_FAST_CV:
- val->intval = POWER_SUPPLY_STATUS_CHARGING;
- break;
- case ADP5061_CHG_COMPLETE:
- val->intval = POWER_SUPPLY_STATUS_FULL;
- break;
- case ADP5061_CHG_TIMER_EXP:
- /* The battery must be discharging if there is a charge fault */
- val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
- break;
- default:
- val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
- }
- return ret;
- }
- static int adp5061_get_battery_status(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- u8 status1, status2;
- int ret;
- ret = adp5061_get_status(st, &status1, &status2);
- if (ret < 0)
- return ret;
- switch (ADP5061_CHG_STATUS_2_BAT_STATUS(status2)) {
- case 0x0: /* Battery monitor off */
- case 0x1: /* No battery */
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
- break;
- case 0x2: /* VBAT < VTRK */
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
- break;
- case 0x3: /* VTRK < VBAT_SNS < VWEAK */
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
- break;
- case 0x4: /* VBAT_SNS > VWEAK */
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
- break;
- default:
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
- break;
- }
- return ret;
- }
- static int adp5061_get_termination_current(struct adp5061_state *st,
- union power_supply_propval *val)
- {
- unsigned int regval;
- int ret;
- ret = regmap_read(st->regmap, ADP5061_IEND, ®val);
- if (ret < 0)
- return ret;
- regval = (regval & ADP5061_IEND_IEND_MSK) >> 5;
- val->intval = adp5061_iend[regval];
- return ret;
- }
- static int adp5061_set_termination_current(struct adp5061_state *st, int val)
- {
- int index;
- index = adp5061_get_array_index(adp5061_iend,
- ARRAY_SIZE(adp5061_iend),
- val);
- if (index < 0)
- return index;
- return regmap_update_bits(st->regmap, ADP5061_IEND,
- ADP5061_IEND_IEND_MSK,
- ADP5061_IEND_IEND_MODE(index));
- }
- static int adp5061_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
- {
- struct adp5061_state *st = power_supply_get_drvdata(psy);
- u8 status1, status2;
- int mode, ret;
- switch (psp) {
- case POWER_SUPPLY_PROP_PRESENT:
- ret = adp5061_get_status(st, &status1, &status2);
- if (ret < 0)
- return ret;
- mode = ADP5061_CHG_STATUS_2_BAT_STATUS(status2);
- if (mode == ADP5061_NO_BATTERY)
- val->intval = 0;
- else
- val->intval = 1;
- break;
- case POWER_SUPPLY_PROP_CHARGE_TYPE:
- return adp5061_get_chg_type(st, val);
- case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
- /* This property is used to indicate the input current
- * limit into VINx (ILIM)
- */
- return adp5061_get_input_current_limit(st, val);
- case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- /* This property is used to indicate the termination
- * voltage (VTRM)
- */
- return adp5061_get_max_voltage(st, val);
- case POWER_SUPPLY_PROP_VOLTAGE_MIN:
- /*
- * This property is used to indicate the trickle to fast
- * charge threshold (VTRK_DEAD)
- */
- return adp5061_get_min_voltage(st, val);
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
- /* This property is used to indicate the charging
- * voltage limit (CHG_VLIM)
- */
- return adp5061_get_chg_volt_lim(st, val);
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
- /*
- * This property is used to indicate the value of the constant
- * current charge (ICHG)
- */
- return adp5061_get_const_chg_current(st, val);
- case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
- /*
- * This property is used to indicate the value of the trickle
- * and weak charge currents (ITRK_DEAD)
- */
- return adp5061_get_prechg_current(st, val);
- case POWER_SUPPLY_PROP_VOLTAGE_AVG:
- /*
- * This property is used to set the VWEAK threshold
- * bellow this value, weak charge mode is entered
- * above this value, fast chargerge mode is entered
- */
- return adp5061_get_vweak_th(st, val);
- case POWER_SUPPLY_PROP_STATUS:
- /*
- * Indicate the charger status in relation to power
- * supply status property
- */
- return adp5061_get_charger_status(st, val);
- case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
- /*
- * Indicate the battery status in relation to power
- * supply capacity level property
- */
- return adp5061_get_battery_status(st, val);
- case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
- /* Indicate the values of the termination current */
- return adp5061_get_termination_current(st, val);
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int adp5061_set_property(struct power_supply *psy,
- enum power_supply_property psp,
- const union power_supply_propval *val)
- {
- struct adp5061_state *st = power_supply_get_drvdata(psy);
- switch (psp) {
- case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
- return adp5061_set_input_current_limit(st, val->intval);
- case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- return adp5061_set_max_voltage(st, val->intval);
- case POWER_SUPPLY_PROP_VOLTAGE_MIN:
- return adp5061_set_min_voltage(st, val->intval);
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
- return adp5061_set_const_chg_vmax(st, val->intval);
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
- return adp5061_set_const_chg_current(st, val->intval);
- case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
- return adp5061_set_prechg_current(st, val->intval);
- case POWER_SUPPLY_PROP_VOLTAGE_AVG:
- return adp5061_set_vweak_th(st, val->intval);
- case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
- return adp5061_set_termination_current(st, val->intval);
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int adp5061_prop_writeable(struct power_supply *psy,
- enum power_supply_property psp)
- {
- switch (psp) {
- case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
- case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- case POWER_SUPPLY_PROP_VOLTAGE_MIN:
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
- case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
- case POWER_SUPPLY_PROP_VOLTAGE_AVG:
- case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
- return 1;
- default:
- return 0;
- }
- }
- static enum power_supply_property adp5061_props[] = {
- POWER_SUPPLY_PROP_PRESENT,
- POWER_SUPPLY_PROP_CHARGE_TYPE,
- POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
- POWER_SUPPLY_PROP_VOLTAGE_MAX,
- POWER_SUPPLY_PROP_VOLTAGE_MIN,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
- POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
- POWER_SUPPLY_PROP_VOLTAGE_AVG,
- POWER_SUPPLY_PROP_STATUS,
- POWER_SUPPLY_PROP_CAPACITY_LEVEL,
- POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
- };
- static const struct regmap_config adp5061_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- };
- static const struct power_supply_desc adp5061_desc = {
- .name = "adp5061",
- .type = POWER_SUPPLY_TYPE_USB,
- .get_property = adp5061_get_property,
- .set_property = adp5061_set_property,
- .property_is_writeable = adp5061_prop_writeable,
- .properties = adp5061_props,
- .num_properties = ARRAY_SIZE(adp5061_props),
- };
- static int adp5061_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- struct power_supply_config psy_cfg = {};
- struct adp5061_state *st;
- st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL);
- if (!st)
- return -ENOMEM;
- st->client = client;
- st->regmap = devm_regmap_init_i2c(client,
- &adp5061_regmap_config);
- if (IS_ERR(st->regmap)) {
- dev_err(&client->dev, "Failed to initialize register map\n");
- return -EINVAL;
- }
- i2c_set_clientdata(client, st);
- psy_cfg.drv_data = st;
- st->psy = devm_power_supply_register(&client->dev,
- &adp5061_desc,
- &psy_cfg);
- if (IS_ERR(st->psy)) {
- dev_err(&client->dev, "Failed to register power supply\n");
- return PTR_ERR(st->psy);
- }
- return 0;
- }
- static const struct i2c_device_id adp5061_id[] = {
- { "adp5061", 0},
- { }
- };
- MODULE_DEVICE_TABLE(i2c, adp5061_id);
- static struct i2c_driver adp5061_driver = {
- .driver = {
- .name = KBUILD_MODNAME,
- },
- .probe = adp5061_probe,
- .id_table = adp5061_id,
- };
- module_i2c_driver(adp5061_driver);
- MODULE_DESCRIPTION("Analog Devices adp5061 battery charger driver");
- MODULE_AUTHOR("Stefan Popa <[email protected]>");
- MODULE_LICENSE("GPL v2");
|