cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

adp5061.c (19240B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ADP5061 I2C Programmable Linear Battery Charger
      4 *
      5 * Copyright 2018 Analog Devices Inc.
      6 */
      7
      8#include <linux/init.h>
      9#include <linux/module.h>
     10#include <linux/slab.h>
     11#include <linux/i2c.h>
     12#include <linux/delay.h>
     13#include <linux/pm.h>
     14#include <linux/mod_devicetable.h>
     15#include <linux/power_supply.h>
     16#include <linux/platform_device.h>
     17#include <linux/of.h>
     18#include <linux/regmap.h>
     19
     20/* ADP5061 registers definition */
     21#define ADP5061_ID			0x00
     22#define ADP5061_REV			0x01
     23#define ADP5061_VINX_SET		0x02
     24#define ADP5061_TERM_SET		0x03
     25#define ADP5061_CHG_CURR		0x04
     26#define ADP5061_VOLTAGE_TH		0x05
     27#define ADP5061_TIMER_SET		0x06
     28#define ADP5061_FUNC_SET_1		0x07
     29#define ADP5061_FUNC_SET_2		0x08
     30#define ADP5061_INT_EN			0x09
     31#define ADP5061_INT_ACT			0x0A
     32#define ADP5061_CHG_STATUS_1		0x0B
     33#define ADP5061_CHG_STATUS_2		0x0C
     34#define ADP5061_FAULT			0x0D
     35#define ADP5061_BATTERY_SHORT		0x10
     36#define ADP5061_IEND			0x11
     37
     38/* ADP5061_VINX_SET */
     39#define ADP5061_VINX_SET_ILIM_MSK		GENMASK(3, 0)
     40#define ADP5061_VINX_SET_ILIM_MODE(x)		(((x) & 0x0F) << 0)
     41
     42/* ADP5061_TERM_SET */
     43#define ADP5061_TERM_SET_VTRM_MSK		GENMASK(7, 2)
     44#define ADP5061_TERM_SET_VTRM_MODE(x)		(((x) & 0x3F) << 2)
     45#define ADP5061_TERM_SET_CHG_VLIM_MSK		GENMASK(1, 0)
     46#define ADP5061_TERM_SET_CHG_VLIM_MODE(x)	(((x) & 0x03) << 0)
     47
     48/* ADP5061_CHG_CURR */
     49#define ADP5061_CHG_CURR_ICHG_MSK		GENMASK(6, 2)
     50#define ADP5061_CHG_CURR_ICHG_MODE(x)		(((x) & 0x1F) << 2)
     51#define ADP5061_CHG_CURR_ITRK_DEAD_MSK		GENMASK(1, 0)
     52#define ADP5061_CHG_CURR_ITRK_DEAD_MODE(x)	(((x) & 0x03) << 0)
     53
     54/* ADP5061_VOLTAGE_TH */
     55#define ADP5061_VOLTAGE_TH_DIS_RCH_MSK		BIT(7)
     56#define ADP5061_VOLTAGE_TH_DIS_RCH_MODE(x)	(((x) & 0x01) << 7)
     57#define ADP5061_VOLTAGE_TH_VRCH_MSK		GENMASK(6, 5)
     58#define ADP5061_VOLTAGE_TH_VRCH_MODE(x)		(((x) & 0x03) << 5)
     59#define ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK	GENMASK(4, 3)
     60#define ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(x)	(((x) & 0x03) << 3)
     61#define ADP5061_VOLTAGE_TH_VWEAK_MSK		GENMASK(2, 0)
     62#define ADP5061_VOLTAGE_TH_VWEAK_MODE(x)	(((x) & 0x07) << 0)
     63
     64/* ADP5061_CHG_STATUS_1 */
     65#define ADP5061_CHG_STATUS_1_VIN_OV(x)		(((x) >> 7) & 0x1)
     66#define ADP5061_CHG_STATUS_1_VIN_OK(x)		(((x) >> 6) & 0x1)
     67#define ADP5061_CHG_STATUS_1_VIN_ILIM(x)	(((x) >> 5) & 0x1)
     68#define ADP5061_CHG_STATUS_1_THERM_LIM(x)	(((x) >> 4) & 0x1)
     69#define ADP5061_CHG_STATUS_1_CHDONE(x)		(((x) >> 3) & 0x1)
     70#define ADP5061_CHG_STATUS_1_CHG_STATUS(x)	(((x) >> 0) & 0x7)
     71
     72/* ADP5061_CHG_STATUS_2 */
     73#define ADP5061_CHG_STATUS_2_THR_STATUS(x)	(((x) >> 5) & 0x7)
     74#define ADP5061_CHG_STATUS_2_RCH_LIM_INFO(x)	(((x) >> 3) & 0x1)
     75#define ADP5061_CHG_STATUS_2_BAT_STATUS(x)	(((x) >> 0) & 0x7)
     76
     77/* ADP5061_IEND */
     78#define ADP5061_IEND_IEND_MSK			GENMASK(7, 5)
     79#define ADP5061_IEND_IEND_MODE(x)		(((x) & 0x07) << 5)
     80
     81#define ADP5061_NO_BATTERY	0x01
     82#define ADP5061_ICHG_MAX	1300 // mA
     83
     84enum adp5061_chg_status {
     85	ADP5061_CHG_OFF,
     86	ADP5061_CHG_TRICKLE,
     87	ADP5061_CHG_FAST_CC,
     88	ADP5061_CHG_FAST_CV,
     89	ADP5061_CHG_COMPLETE,
     90	ADP5061_CHG_LDO_MODE,
     91	ADP5061_CHG_TIMER_EXP,
     92	ADP5061_CHG_BAT_DET,
     93};
     94
     95static const int adp5061_chg_type[4] = {
     96	[ADP5061_CHG_OFF] = POWER_SUPPLY_CHARGE_TYPE_NONE,
     97	[ADP5061_CHG_TRICKLE] = POWER_SUPPLY_CHARGE_TYPE_TRICKLE,
     98	[ADP5061_CHG_FAST_CC] = POWER_SUPPLY_CHARGE_TYPE_FAST,
     99	[ADP5061_CHG_FAST_CV] = POWER_SUPPLY_CHARGE_TYPE_FAST,
    100};
    101
    102static const int adp5061_vweak_th[8] = {
    103	2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400,
    104};
    105
    106static const int adp5061_prechg_current[4] = {
    107	5, 10, 20, 80,
    108};
    109
    110static const int adp5061_vmin[4] = {
    111	2000, 2500, 2600, 2900,
    112};
    113
    114static const int adp5061_const_chg_vmax[4] = {
    115	3200, 3400, 3700, 3800,
    116};
    117
    118static const int adp5061_const_ichg[24] = {
    119	50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650,
    120	700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1200, 1300,
    121};
    122
    123static const int adp5061_vmax[36] = {
    124	3800, 3820, 3840, 3860, 3880, 3900, 3920, 3940, 3960, 3980,
    125	4000, 4020, 4040, 4060, 4080, 4100, 4120, 4140, 4160, 4180,
    126	4200, 4220, 4240, 4260, 4280, 4300, 4320, 4340, 4360, 4380,
    127	4400, 4420, 4440, 4460, 4480, 4500,
    128};
    129
    130static const int adp5061_in_current_lim[16] = {
    131	100, 150, 200, 250, 300, 400, 500, 600, 700,
    132	800, 900, 1000, 1200, 1500, 1800, 2100,
    133};
    134
    135static const int adp5061_iend[8] = {
    136	12500, 32500, 52500, 72500, 92500, 117500, 142500, 170000,
    137};
    138
    139struct adp5061_state {
    140	struct i2c_client		*client;
    141	struct regmap			*regmap;
    142	struct power_supply		*psy;
    143};
    144
    145static int adp5061_get_array_index(const int *array, u8 size, int val)
    146{
    147	int i;
    148
    149	for (i = 1; i < size; i++) {
    150		if (val < array[i])
    151			break;
    152	}
    153
    154	return i-1;
    155}
    156
    157static int adp5061_get_status(struct adp5061_state *st,
    158			      u8 *status1, u8 *status2)
    159{
    160	u8 buf[2];
    161	int ret;
    162
    163	/* CHG_STATUS1 and CHG_STATUS2 are adjacent regs */
    164	ret = regmap_bulk_read(st->regmap, ADP5061_CHG_STATUS_1,
    165			       &buf[0], 2);
    166	if (ret < 0)
    167		return ret;
    168
    169	*status1 = buf[0];
    170	*status2 = buf[1];
    171
    172	return ret;
    173}
    174
    175static int adp5061_get_input_current_limit(struct adp5061_state *st,
    176		union power_supply_propval *val)
    177{
    178	unsigned int regval;
    179	int mode, ret;
    180
    181	ret = regmap_read(st->regmap, ADP5061_VINX_SET, &regval);
    182	if (ret < 0)
    183		return ret;
    184
    185	mode = ADP5061_VINX_SET_ILIM_MODE(regval);
    186	val->intval = adp5061_in_current_lim[mode] * 1000;
    187
    188	return ret;
    189}
    190
    191static int adp5061_set_input_current_limit(struct adp5061_state *st, int val)
    192{
    193	int index;
    194
    195	/* Convert from uA to mA */
    196	val /= 1000;
    197	index = adp5061_get_array_index(adp5061_in_current_lim,
    198					ARRAY_SIZE(adp5061_in_current_lim),
    199					val);
    200	if (index < 0)
    201		return index;
    202
    203	return regmap_update_bits(st->regmap, ADP5061_VINX_SET,
    204				  ADP5061_VINX_SET_ILIM_MSK,
    205				  ADP5061_VINX_SET_ILIM_MODE(index));
    206}
    207
    208static int adp5061_set_min_voltage(struct adp5061_state *st, int val)
    209{
    210	int index;
    211
    212	/* Convert from uV to mV */
    213	val /= 1000;
    214	index = adp5061_get_array_index(adp5061_vmin,
    215					ARRAY_SIZE(adp5061_vmin),
    216					val);
    217	if (index < 0)
    218		return index;
    219
    220	return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH,
    221				  ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK,
    222				  ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(index));
    223}
    224
    225static int adp5061_get_min_voltage(struct adp5061_state *st,
    226				   union power_supply_propval *val)
    227{
    228	unsigned int regval;
    229	int ret;
    230
    231	ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, &regval);
    232	if (ret < 0)
    233		return ret;
    234
    235	regval = ((regval & ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK) >> 3);
    236	val->intval = adp5061_vmin[regval] * 1000;
    237
    238	return ret;
    239}
    240
    241static int adp5061_get_chg_volt_lim(struct adp5061_state *st,
    242				    union power_supply_propval *val)
    243{
    244	unsigned int regval;
    245	int mode, ret;
    246
    247	ret = regmap_read(st->regmap, ADP5061_TERM_SET, &regval);
    248	if (ret < 0)
    249		return ret;
    250
    251	mode = ADP5061_TERM_SET_CHG_VLIM_MODE(regval);
    252	val->intval = adp5061_const_chg_vmax[mode] * 1000;
    253
    254	return ret;
    255}
    256
    257static int adp5061_get_max_voltage(struct adp5061_state *st,
    258				   union power_supply_propval *val)
    259{
    260	unsigned int regval;
    261	int ret;
    262
    263	ret = regmap_read(st->regmap, ADP5061_TERM_SET, &regval);
    264	if (ret < 0)
    265		return ret;
    266
    267	regval = ((regval & ADP5061_TERM_SET_VTRM_MSK) >> 2) - 0x0F;
    268	if (regval >= ARRAY_SIZE(adp5061_vmax))
    269		regval = ARRAY_SIZE(adp5061_vmax) - 1;
    270
    271	val->intval = adp5061_vmax[regval] * 1000;
    272
    273	return ret;
    274}
    275
    276static int adp5061_set_max_voltage(struct adp5061_state *st, int val)
    277{
    278	int vmax_index;
    279
    280	/* Convert from uV to mV */
    281	val /= 1000;
    282	if (val > 4500)
    283		val = 4500;
    284
    285	vmax_index = adp5061_get_array_index(adp5061_vmax,
    286					     ARRAY_SIZE(adp5061_vmax), val);
    287	if (vmax_index < 0)
    288		return vmax_index;
    289
    290	vmax_index += 0x0F;
    291
    292	return regmap_update_bits(st->regmap, ADP5061_TERM_SET,
    293				  ADP5061_TERM_SET_VTRM_MSK,
    294				  ADP5061_TERM_SET_VTRM_MODE(vmax_index));
    295}
    296
    297static int adp5061_set_const_chg_vmax(struct adp5061_state *st, int val)
    298{
    299	int index;
    300
    301	/* Convert from uV to mV */
    302	val /= 1000;
    303	index = adp5061_get_array_index(adp5061_const_chg_vmax,
    304					ARRAY_SIZE(adp5061_const_chg_vmax),
    305					val);
    306	if (index < 0)
    307		return index;
    308
    309	return regmap_update_bits(st->regmap, ADP5061_TERM_SET,
    310				  ADP5061_TERM_SET_CHG_VLIM_MSK,
    311				  ADP5061_TERM_SET_CHG_VLIM_MODE(index));
    312}
    313
    314static int adp5061_set_const_chg_current(struct adp5061_state *st, int val)
    315{
    316
    317	int index;
    318
    319	/* Convert from uA to mA */
    320	val /= 1000;
    321	if (val > ADP5061_ICHG_MAX)
    322		val = ADP5061_ICHG_MAX;
    323
    324	index = adp5061_get_array_index(adp5061_const_ichg,
    325					ARRAY_SIZE(adp5061_const_ichg),
    326					val);
    327	if (index < 0)
    328		return index;
    329
    330	return regmap_update_bits(st->regmap, ADP5061_CHG_CURR,
    331				  ADP5061_CHG_CURR_ICHG_MSK,
    332				  ADP5061_CHG_CURR_ICHG_MODE(index));
    333}
    334
    335static int adp5061_get_const_chg_current(struct adp5061_state *st,
    336		union power_supply_propval *val)
    337{
    338	unsigned int regval;
    339	int ret;
    340
    341	ret = regmap_read(st->regmap, ADP5061_CHG_CURR, &regval);
    342	if (ret < 0)
    343		return ret;
    344
    345	regval = ((regval & ADP5061_CHG_CURR_ICHG_MSK) >> 2);
    346	if (regval >= ARRAY_SIZE(adp5061_const_ichg))
    347		regval = ARRAY_SIZE(adp5061_const_ichg) - 1;
    348
    349	val->intval = adp5061_const_ichg[regval] * 1000;
    350
    351	return ret;
    352}
    353
    354static int adp5061_get_prechg_current(struct adp5061_state *st,
    355				      union power_supply_propval *val)
    356{
    357	unsigned int regval;
    358	int ret;
    359
    360	ret = regmap_read(st->regmap, ADP5061_CHG_CURR, &regval);
    361	if (ret < 0)
    362		return ret;
    363
    364	regval &= ADP5061_CHG_CURR_ITRK_DEAD_MSK;
    365	val->intval = adp5061_prechg_current[regval] * 1000;
    366
    367	return ret;
    368}
    369
    370static int adp5061_set_prechg_current(struct adp5061_state *st, int val)
    371{
    372	int index;
    373
    374	/* Convert from uA to mA */
    375	val /= 1000;
    376	index = adp5061_get_array_index(adp5061_prechg_current,
    377					ARRAY_SIZE(adp5061_prechg_current),
    378					val);
    379	if (index < 0)
    380		return index;
    381
    382	return regmap_update_bits(st->regmap, ADP5061_CHG_CURR,
    383				  ADP5061_CHG_CURR_ITRK_DEAD_MSK,
    384				  ADP5061_CHG_CURR_ITRK_DEAD_MODE(index));
    385}
    386
    387static int adp5061_get_vweak_th(struct adp5061_state *st,
    388				union power_supply_propval *val)
    389{
    390	unsigned int regval;
    391	int ret;
    392
    393	ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, &regval);
    394	if (ret < 0)
    395		return ret;
    396
    397	regval &= ADP5061_VOLTAGE_TH_VWEAK_MSK;
    398	val->intval = adp5061_vweak_th[regval] * 1000;
    399
    400	return ret;
    401}
    402
    403static int adp5061_set_vweak_th(struct adp5061_state *st, int val)
    404{
    405	int index;
    406
    407	/* Convert from uV to mV */
    408	val /= 1000;
    409	index = adp5061_get_array_index(adp5061_vweak_th,
    410					ARRAY_SIZE(adp5061_vweak_th),
    411					val);
    412	if (index < 0)
    413		return index;
    414
    415	return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH,
    416				  ADP5061_VOLTAGE_TH_VWEAK_MSK,
    417				  ADP5061_VOLTAGE_TH_VWEAK_MODE(index));
    418}
    419
    420static int adp5061_get_chg_type(struct adp5061_state *st,
    421				union power_supply_propval *val)
    422{
    423	u8 status1, status2;
    424	int chg_type, ret;
    425
    426	ret = adp5061_get_status(st, &status1, &status2);
    427	if (ret < 0)
    428		return ret;
    429
    430	chg_type = adp5061_chg_type[ADP5061_CHG_STATUS_1_CHG_STATUS(status1)];
    431	if (chg_type > ADP5061_CHG_FAST_CV)
    432		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
    433	else
    434		val->intval = chg_type;
    435
    436	return ret;
    437}
    438
    439static int adp5061_get_charger_status(struct adp5061_state *st,
    440				      union power_supply_propval *val)
    441{
    442	u8 status1, status2;
    443	int ret;
    444
    445	ret = adp5061_get_status(st, &status1, &status2);
    446	if (ret < 0)
    447		return ret;
    448
    449	switch (ADP5061_CHG_STATUS_1_CHG_STATUS(status1)) {
    450	case ADP5061_CHG_OFF:
    451		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
    452		break;
    453	case ADP5061_CHG_TRICKLE:
    454	case ADP5061_CHG_FAST_CC:
    455	case ADP5061_CHG_FAST_CV:
    456		val->intval = POWER_SUPPLY_STATUS_CHARGING;
    457		break;
    458	case ADP5061_CHG_COMPLETE:
    459		val->intval = POWER_SUPPLY_STATUS_FULL;
    460		break;
    461	case ADP5061_CHG_TIMER_EXP:
    462		/* The battery must be discharging if there is a charge fault */
    463		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
    464		break;
    465	default:
    466		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
    467	}
    468
    469	return ret;
    470}
    471
    472static int adp5061_get_battery_status(struct adp5061_state *st,
    473				      union power_supply_propval *val)
    474{
    475	u8 status1, status2;
    476	int ret;
    477
    478	ret = adp5061_get_status(st, &status1, &status2);
    479	if (ret < 0)
    480		return ret;
    481
    482	switch (ADP5061_CHG_STATUS_2_BAT_STATUS(status2)) {
    483	case 0x0: /* Battery monitor off */
    484	case 0x1: /* No battery */
    485		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
    486		break;
    487	case 0x2: /* VBAT < VTRK */
    488		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
    489		break;
    490	case 0x3: /* VTRK < VBAT_SNS < VWEAK */
    491		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
    492		break;
    493	case 0x4: /* VBAT_SNS > VWEAK */
    494		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
    495		break;
    496	}
    497
    498	return ret;
    499}
    500
    501static int adp5061_get_termination_current(struct adp5061_state *st,
    502					   union power_supply_propval *val)
    503{
    504	unsigned int regval;
    505	int ret;
    506
    507	ret = regmap_read(st->regmap, ADP5061_IEND, &regval);
    508	if (ret < 0)
    509		return ret;
    510
    511	regval = (regval & ADP5061_IEND_IEND_MSK) >> 5;
    512	val->intval = adp5061_iend[regval];
    513
    514	return ret;
    515}
    516
    517static int adp5061_set_termination_current(struct adp5061_state *st, int val)
    518{
    519	int index;
    520
    521	index = adp5061_get_array_index(adp5061_iend,
    522					ARRAY_SIZE(adp5061_iend),
    523					val);
    524	if (index < 0)
    525		return index;
    526
    527	return regmap_update_bits(st->regmap, ADP5061_IEND,
    528				  ADP5061_IEND_IEND_MSK,
    529				  ADP5061_IEND_IEND_MODE(index));
    530}
    531
    532static int adp5061_get_property(struct power_supply *psy,
    533				enum power_supply_property psp,
    534				union power_supply_propval *val)
    535{
    536	struct adp5061_state *st = power_supply_get_drvdata(psy);
    537	u8 status1, status2;
    538	int mode, ret;
    539
    540	switch (psp) {
    541	case POWER_SUPPLY_PROP_PRESENT:
    542		ret = adp5061_get_status(st, &status1, &status2);
    543		if (ret < 0)
    544			return ret;
    545
    546		mode = ADP5061_CHG_STATUS_2_BAT_STATUS(status2);
    547		if (mode == ADP5061_NO_BATTERY)
    548			val->intval = 0;
    549		else
    550			val->intval = 1;
    551		break;
    552	case POWER_SUPPLY_PROP_CHARGE_TYPE:
    553		return adp5061_get_chg_type(st, val);
    554	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
    555		/* This property is used to indicate the input current
    556		 * limit into VINx (ILIM)
    557		 */
    558		return adp5061_get_input_current_limit(st, val);
    559	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
    560		/* This property is used to indicate the termination
    561		 * voltage (VTRM)
    562		 */
    563		return adp5061_get_max_voltage(st, val);
    564	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
    565		/*
    566		 * This property is used to indicate the trickle to fast
    567		 * charge threshold (VTRK_DEAD)
    568		 */
    569		return adp5061_get_min_voltage(st, val);
    570	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
    571		/* This property is used to indicate the charging
    572		 * voltage limit (CHG_VLIM)
    573		 */
    574		return adp5061_get_chg_volt_lim(st, val);
    575	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
    576		/*
    577		 * This property is used to indicate the value of the constant
    578		 * current charge (ICHG)
    579		 */
    580		return adp5061_get_const_chg_current(st, val);
    581	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
    582		/*
    583		 * This property is used to indicate the value of the trickle
    584		 * and weak charge currents (ITRK_DEAD)
    585		 */
    586		return adp5061_get_prechg_current(st, val);
    587	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
    588		/*
    589		 * This property is used to set the VWEAK threshold
    590		 * bellow this value, weak charge mode is entered
    591		 * above this value, fast chargerge mode is entered
    592		 */
    593		return adp5061_get_vweak_th(st, val);
    594	case POWER_SUPPLY_PROP_STATUS:
    595		/*
    596		 * Indicate the charger status in relation to power
    597		 * supply status property
    598		 */
    599		return adp5061_get_charger_status(st, val);
    600	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
    601		/*
    602		 * Indicate the battery status in relation to power
    603		 * supply capacity level property
    604		 */
    605		return adp5061_get_battery_status(st, val);
    606	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
    607		/* Indicate the values of the termination current */
    608		return adp5061_get_termination_current(st, val);
    609	default:
    610		return -EINVAL;
    611	}
    612
    613	return 0;
    614}
    615
    616static int adp5061_set_property(struct power_supply *psy,
    617				enum power_supply_property psp,
    618				const union power_supply_propval *val)
    619{
    620	struct adp5061_state *st = power_supply_get_drvdata(psy);
    621
    622	switch (psp) {
    623	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
    624		return adp5061_set_input_current_limit(st, val->intval);
    625	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
    626		return adp5061_set_max_voltage(st, val->intval);
    627	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
    628		return adp5061_set_min_voltage(st, val->intval);
    629	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
    630		return adp5061_set_const_chg_vmax(st, val->intval);
    631	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
    632		return adp5061_set_const_chg_current(st, val->intval);
    633	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
    634		return adp5061_set_prechg_current(st, val->intval);
    635	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
    636		return adp5061_set_vweak_th(st, val->intval);
    637	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
    638		return adp5061_set_termination_current(st, val->intval);
    639	default:
    640		return -EINVAL;
    641	}
    642
    643	return 0;
    644}
    645
    646static int adp5061_prop_writeable(struct power_supply *psy,
    647				  enum power_supply_property psp)
    648{
    649	switch (psp) {
    650	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
    651	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
    652	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
    653	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
    654	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
    655	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
    656	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
    657	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
    658		return 1;
    659	default:
    660		return 0;
    661	}
    662}
    663
    664static enum power_supply_property adp5061_props[] = {
    665	POWER_SUPPLY_PROP_PRESENT,
    666	POWER_SUPPLY_PROP_CHARGE_TYPE,
    667	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
    668	POWER_SUPPLY_PROP_VOLTAGE_MAX,
    669	POWER_SUPPLY_PROP_VOLTAGE_MIN,
    670	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
    671	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
    672	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
    673	POWER_SUPPLY_PROP_VOLTAGE_AVG,
    674	POWER_SUPPLY_PROP_STATUS,
    675	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
    676	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
    677};
    678
    679static const struct regmap_config adp5061_regmap_config = {
    680	.reg_bits = 8,
    681	.val_bits = 8,
    682};
    683
    684static const struct power_supply_desc adp5061_desc = {
    685	.name			= "adp5061",
    686	.type			= POWER_SUPPLY_TYPE_USB,
    687	.get_property		= adp5061_get_property,
    688	.set_property		= adp5061_set_property,
    689	.property_is_writeable	= adp5061_prop_writeable,
    690	.properties		= adp5061_props,
    691	.num_properties		= ARRAY_SIZE(adp5061_props),
    692};
    693
    694static int adp5061_probe(struct i2c_client *client,
    695			 const struct i2c_device_id *id)
    696{
    697	struct power_supply_config psy_cfg = {};
    698	struct adp5061_state *st;
    699
    700	st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL);
    701	if (!st)
    702		return -ENOMEM;
    703
    704	st->client = client;
    705	st->regmap = devm_regmap_init_i2c(client,
    706					  &adp5061_regmap_config);
    707	if (IS_ERR(st->regmap)) {
    708		dev_err(&client->dev, "Failed to initialize register map\n");
    709		return -EINVAL;
    710	}
    711
    712	i2c_set_clientdata(client, st);
    713	psy_cfg.drv_data = st;
    714
    715	st->psy = devm_power_supply_register(&client->dev,
    716					     &adp5061_desc,
    717					     &psy_cfg);
    718
    719	if (IS_ERR(st->psy)) {
    720		dev_err(&client->dev, "Failed to register power supply\n");
    721		return PTR_ERR(st->psy);
    722	}
    723
    724	return 0;
    725}
    726
    727static const struct i2c_device_id adp5061_id[] = {
    728	{ "adp5061", 0},
    729	{ }
    730};
    731MODULE_DEVICE_TABLE(i2c, adp5061_id);
    732
    733static struct i2c_driver adp5061_driver = {
    734	.driver = {
    735		.name = KBUILD_MODNAME,
    736	},
    737	.probe = adp5061_probe,
    738	.id_table = adp5061_id,
    739};
    740module_i2c_driver(adp5061_driver);
    741
    742MODULE_DESCRIPTION("Analog Devices adp5061 battery charger driver");
    743MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
    744MODULE_LICENSE("GPL v2");