162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ADP5061 I2C Programmable Linear Battery Charger 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2018 Analog Devices Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/pm.h> 1462306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1562306a36Sopenharmony_ci#include <linux/power_supply.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/regmap.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* ADP5061 registers definition */ 2162306a36Sopenharmony_ci#define ADP5061_ID 0x00 2262306a36Sopenharmony_ci#define ADP5061_REV 0x01 2362306a36Sopenharmony_ci#define ADP5061_VINX_SET 0x02 2462306a36Sopenharmony_ci#define ADP5061_TERM_SET 0x03 2562306a36Sopenharmony_ci#define ADP5061_CHG_CURR 0x04 2662306a36Sopenharmony_ci#define ADP5061_VOLTAGE_TH 0x05 2762306a36Sopenharmony_ci#define ADP5061_TIMER_SET 0x06 2862306a36Sopenharmony_ci#define ADP5061_FUNC_SET_1 0x07 2962306a36Sopenharmony_ci#define ADP5061_FUNC_SET_2 0x08 3062306a36Sopenharmony_ci#define ADP5061_INT_EN 0x09 3162306a36Sopenharmony_ci#define ADP5061_INT_ACT 0x0A 3262306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_1 0x0B 3362306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_2 0x0C 3462306a36Sopenharmony_ci#define ADP5061_FAULT 0x0D 3562306a36Sopenharmony_ci#define ADP5061_BATTERY_SHORT 0x10 3662306a36Sopenharmony_ci#define ADP5061_IEND 0x11 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* ADP5061_VINX_SET */ 3962306a36Sopenharmony_ci#define ADP5061_VINX_SET_ILIM_MSK GENMASK(3, 0) 4062306a36Sopenharmony_ci#define ADP5061_VINX_SET_ILIM_MODE(x) (((x) & 0x0F) << 0) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* ADP5061_TERM_SET */ 4362306a36Sopenharmony_ci#define ADP5061_TERM_SET_VTRM_MSK GENMASK(7, 2) 4462306a36Sopenharmony_ci#define ADP5061_TERM_SET_VTRM_MODE(x) (((x) & 0x3F) << 2) 4562306a36Sopenharmony_ci#define ADP5061_TERM_SET_CHG_VLIM_MSK GENMASK(1, 0) 4662306a36Sopenharmony_ci#define ADP5061_TERM_SET_CHG_VLIM_MODE(x) (((x) & 0x03) << 0) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* ADP5061_CHG_CURR */ 4962306a36Sopenharmony_ci#define ADP5061_CHG_CURR_ICHG_MSK GENMASK(6, 2) 5062306a36Sopenharmony_ci#define ADP5061_CHG_CURR_ICHG_MODE(x) (((x) & 0x1F) << 2) 5162306a36Sopenharmony_ci#define ADP5061_CHG_CURR_ITRK_DEAD_MSK GENMASK(1, 0) 5262306a36Sopenharmony_ci#define ADP5061_CHG_CURR_ITRK_DEAD_MODE(x) (((x) & 0x03) << 0) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* ADP5061_VOLTAGE_TH */ 5562306a36Sopenharmony_ci#define ADP5061_VOLTAGE_TH_DIS_RCH_MSK BIT(7) 5662306a36Sopenharmony_ci#define ADP5061_VOLTAGE_TH_DIS_RCH_MODE(x) (((x) & 0x01) << 7) 5762306a36Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VRCH_MSK GENMASK(6, 5) 5862306a36Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VRCH_MODE(x) (((x) & 0x03) << 5) 5962306a36Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK GENMASK(4, 3) 6062306a36Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(x) (((x) & 0x03) << 3) 6162306a36Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VWEAK_MSK GENMASK(2, 0) 6262306a36Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VWEAK_MODE(x) (((x) & 0x07) << 0) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* ADP5061_CHG_STATUS_1 */ 6562306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_1_VIN_OV(x) (((x) >> 7) & 0x1) 6662306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_1_VIN_OK(x) (((x) >> 6) & 0x1) 6762306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_1_VIN_ILIM(x) (((x) >> 5) & 0x1) 6862306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_1_THERM_LIM(x) (((x) >> 4) & 0x1) 6962306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_1_CHDONE(x) (((x) >> 3) & 0x1) 7062306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_1_CHG_STATUS(x) (((x) >> 0) & 0x7) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* ADP5061_CHG_STATUS_2 */ 7362306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_2_THR_STATUS(x) (((x) >> 5) & 0x7) 7462306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_2_RCH_LIM_INFO(x) (((x) >> 3) & 0x1) 7562306a36Sopenharmony_ci#define ADP5061_CHG_STATUS_2_BAT_STATUS(x) (((x) >> 0) & 0x7) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* ADP5061_IEND */ 7862306a36Sopenharmony_ci#define ADP5061_IEND_IEND_MSK GENMASK(7, 5) 7962306a36Sopenharmony_ci#define ADP5061_IEND_IEND_MODE(x) (((x) & 0x07) << 5) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define ADP5061_NO_BATTERY 0x01 8262306a36Sopenharmony_ci#define ADP5061_ICHG_MAX 1300 // mA 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cienum adp5061_chg_status { 8562306a36Sopenharmony_ci ADP5061_CHG_OFF, 8662306a36Sopenharmony_ci ADP5061_CHG_TRICKLE, 8762306a36Sopenharmony_ci ADP5061_CHG_FAST_CC, 8862306a36Sopenharmony_ci ADP5061_CHG_FAST_CV, 8962306a36Sopenharmony_ci ADP5061_CHG_COMPLETE, 9062306a36Sopenharmony_ci ADP5061_CHG_LDO_MODE, 9162306a36Sopenharmony_ci ADP5061_CHG_TIMER_EXP, 9262306a36Sopenharmony_ci ADP5061_CHG_BAT_DET, 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic const int adp5061_chg_type[4] = { 9662306a36Sopenharmony_ci [ADP5061_CHG_OFF] = POWER_SUPPLY_CHARGE_TYPE_NONE, 9762306a36Sopenharmony_ci [ADP5061_CHG_TRICKLE] = POWER_SUPPLY_CHARGE_TYPE_TRICKLE, 9862306a36Sopenharmony_ci [ADP5061_CHG_FAST_CC] = POWER_SUPPLY_CHARGE_TYPE_FAST, 9962306a36Sopenharmony_ci [ADP5061_CHG_FAST_CV] = POWER_SUPPLY_CHARGE_TYPE_FAST, 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic const int adp5061_vweak_th[8] = { 10362306a36Sopenharmony_ci 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic const int adp5061_prechg_current[4] = { 10762306a36Sopenharmony_ci 5, 10, 20, 80, 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic const int adp5061_vmin[4] = { 11162306a36Sopenharmony_ci 2000, 2500, 2600, 2900, 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic const int adp5061_const_chg_vmax[4] = { 11562306a36Sopenharmony_ci 3200, 3400, 3700, 3800, 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic const int adp5061_const_ichg[24] = { 11962306a36Sopenharmony_ci 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 12062306a36Sopenharmony_ci 700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1200, 1300, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic const int adp5061_vmax[36] = { 12462306a36Sopenharmony_ci 3800, 3820, 3840, 3860, 3880, 3900, 3920, 3940, 3960, 3980, 12562306a36Sopenharmony_ci 4000, 4020, 4040, 4060, 4080, 4100, 4120, 4140, 4160, 4180, 12662306a36Sopenharmony_ci 4200, 4220, 4240, 4260, 4280, 4300, 4320, 4340, 4360, 4380, 12762306a36Sopenharmony_ci 4400, 4420, 4440, 4460, 4480, 4500, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic const int adp5061_in_current_lim[16] = { 13162306a36Sopenharmony_ci 100, 150, 200, 250, 300, 400, 500, 600, 700, 13262306a36Sopenharmony_ci 800, 900, 1000, 1200, 1500, 1800, 2100, 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic const int adp5061_iend[8] = { 13662306a36Sopenharmony_ci 12500, 32500, 52500, 72500, 92500, 117500, 142500, 170000, 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistruct adp5061_state { 14062306a36Sopenharmony_ci struct i2c_client *client; 14162306a36Sopenharmony_ci struct regmap *regmap; 14262306a36Sopenharmony_ci struct power_supply *psy; 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int adp5061_get_array_index(const int *array, u8 size, int val) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci int i; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci for (i = 1; i < size; i++) { 15062306a36Sopenharmony_ci if (val < array[i]) 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return i-1; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int adp5061_get_status(struct adp5061_state *st, 15862306a36Sopenharmony_ci u8 *status1, u8 *status2) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci u8 buf[2]; 16162306a36Sopenharmony_ci int ret; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* CHG_STATUS1 and CHG_STATUS2 are adjacent regs */ 16462306a36Sopenharmony_ci ret = regmap_bulk_read(st->regmap, ADP5061_CHG_STATUS_1, 16562306a36Sopenharmony_ci &buf[0], 2); 16662306a36Sopenharmony_ci if (ret < 0) 16762306a36Sopenharmony_ci return ret; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci *status1 = buf[0]; 17062306a36Sopenharmony_ci *status2 = buf[1]; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return ret; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int adp5061_get_input_current_limit(struct adp5061_state *st, 17662306a36Sopenharmony_ci union power_supply_propval *val) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci unsigned int regval; 17962306a36Sopenharmony_ci int mode, ret; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_VINX_SET, ®val); 18262306a36Sopenharmony_ci if (ret < 0) 18362306a36Sopenharmony_ci return ret; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci mode = ADP5061_VINX_SET_ILIM_MODE(regval); 18662306a36Sopenharmony_ci val->intval = adp5061_in_current_lim[mode] * 1000; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return ret; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int adp5061_set_input_current_limit(struct adp5061_state *st, int val) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci int index; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Convert from uA to mA */ 19662306a36Sopenharmony_ci val /= 1000; 19762306a36Sopenharmony_ci index = adp5061_get_array_index(adp5061_in_current_lim, 19862306a36Sopenharmony_ci ARRAY_SIZE(adp5061_in_current_lim), 19962306a36Sopenharmony_ci val); 20062306a36Sopenharmony_ci if (index < 0) 20162306a36Sopenharmony_ci return index; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_VINX_SET, 20462306a36Sopenharmony_ci ADP5061_VINX_SET_ILIM_MSK, 20562306a36Sopenharmony_ci ADP5061_VINX_SET_ILIM_MODE(index)); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic int adp5061_set_min_voltage(struct adp5061_state *st, int val) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci int index; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Convert from uV to mV */ 21362306a36Sopenharmony_ci val /= 1000; 21462306a36Sopenharmony_ci index = adp5061_get_array_index(adp5061_vmin, 21562306a36Sopenharmony_ci ARRAY_SIZE(adp5061_vmin), 21662306a36Sopenharmony_ci val); 21762306a36Sopenharmony_ci if (index < 0) 21862306a36Sopenharmony_ci return index; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH, 22162306a36Sopenharmony_ci ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK, 22262306a36Sopenharmony_ci ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(index)); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int adp5061_get_min_voltage(struct adp5061_state *st, 22662306a36Sopenharmony_ci union power_supply_propval *val) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci unsigned int regval; 22962306a36Sopenharmony_ci int ret; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val); 23262306a36Sopenharmony_ci if (ret < 0) 23362306a36Sopenharmony_ci return ret; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci regval = ((regval & ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK) >> 3); 23662306a36Sopenharmony_ci val->intval = adp5061_vmin[regval] * 1000; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return ret; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int adp5061_get_chg_volt_lim(struct adp5061_state *st, 24262306a36Sopenharmony_ci union power_supply_propval *val) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci unsigned int regval; 24562306a36Sopenharmony_ci int mode, ret; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val); 24862306a36Sopenharmony_ci if (ret < 0) 24962306a36Sopenharmony_ci return ret; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci mode = ADP5061_TERM_SET_CHG_VLIM_MODE(regval); 25262306a36Sopenharmony_ci val->intval = adp5061_const_chg_vmax[mode] * 1000; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return ret; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int adp5061_get_max_voltage(struct adp5061_state *st, 25862306a36Sopenharmony_ci union power_supply_propval *val) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci unsigned int regval; 26162306a36Sopenharmony_ci int ret; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val); 26462306a36Sopenharmony_ci if (ret < 0) 26562306a36Sopenharmony_ci return ret; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci regval = ((regval & ADP5061_TERM_SET_VTRM_MSK) >> 2) - 0x0F; 26862306a36Sopenharmony_ci if (regval >= ARRAY_SIZE(adp5061_vmax)) 26962306a36Sopenharmony_ci regval = ARRAY_SIZE(adp5061_vmax) - 1; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci val->intval = adp5061_vmax[regval] * 1000; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return ret; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int adp5061_set_max_voltage(struct adp5061_state *st, int val) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci int vmax_index; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* Convert from uV to mV */ 28162306a36Sopenharmony_ci val /= 1000; 28262306a36Sopenharmony_ci if (val > 4500) 28362306a36Sopenharmony_ci val = 4500; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci vmax_index = adp5061_get_array_index(adp5061_vmax, 28662306a36Sopenharmony_ci ARRAY_SIZE(adp5061_vmax), val); 28762306a36Sopenharmony_ci if (vmax_index < 0) 28862306a36Sopenharmony_ci return vmax_index; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci vmax_index += 0x0F; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_TERM_SET, 29362306a36Sopenharmony_ci ADP5061_TERM_SET_VTRM_MSK, 29462306a36Sopenharmony_ci ADP5061_TERM_SET_VTRM_MODE(vmax_index)); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int adp5061_set_const_chg_vmax(struct adp5061_state *st, int val) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci int index; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Convert from uV to mV */ 30262306a36Sopenharmony_ci val /= 1000; 30362306a36Sopenharmony_ci index = adp5061_get_array_index(adp5061_const_chg_vmax, 30462306a36Sopenharmony_ci ARRAY_SIZE(adp5061_const_chg_vmax), 30562306a36Sopenharmony_ci val); 30662306a36Sopenharmony_ci if (index < 0) 30762306a36Sopenharmony_ci return index; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_TERM_SET, 31062306a36Sopenharmony_ci ADP5061_TERM_SET_CHG_VLIM_MSK, 31162306a36Sopenharmony_ci ADP5061_TERM_SET_CHG_VLIM_MODE(index)); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int adp5061_set_const_chg_current(struct adp5061_state *st, int val) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci int index; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Convert from uA to mA */ 32062306a36Sopenharmony_ci val /= 1000; 32162306a36Sopenharmony_ci if (val > ADP5061_ICHG_MAX) 32262306a36Sopenharmony_ci val = ADP5061_ICHG_MAX; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci index = adp5061_get_array_index(adp5061_const_ichg, 32562306a36Sopenharmony_ci ARRAY_SIZE(adp5061_const_ichg), 32662306a36Sopenharmony_ci val); 32762306a36Sopenharmony_ci if (index < 0) 32862306a36Sopenharmony_ci return index; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_CHG_CURR, 33162306a36Sopenharmony_ci ADP5061_CHG_CURR_ICHG_MSK, 33262306a36Sopenharmony_ci ADP5061_CHG_CURR_ICHG_MODE(index)); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int adp5061_get_const_chg_current(struct adp5061_state *st, 33662306a36Sopenharmony_ci union power_supply_propval *val) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci unsigned int regval; 33962306a36Sopenharmony_ci int ret; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val); 34262306a36Sopenharmony_ci if (ret < 0) 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci regval = ((regval & ADP5061_CHG_CURR_ICHG_MSK) >> 2); 34662306a36Sopenharmony_ci if (regval >= ARRAY_SIZE(adp5061_const_ichg)) 34762306a36Sopenharmony_ci regval = ARRAY_SIZE(adp5061_const_ichg) - 1; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci val->intval = adp5061_const_ichg[regval] * 1000; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return ret; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int adp5061_get_prechg_current(struct adp5061_state *st, 35562306a36Sopenharmony_ci union power_supply_propval *val) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci unsigned int regval; 35862306a36Sopenharmony_ci int ret; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val); 36162306a36Sopenharmony_ci if (ret < 0) 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci regval &= ADP5061_CHG_CURR_ITRK_DEAD_MSK; 36562306a36Sopenharmony_ci val->intval = adp5061_prechg_current[regval] * 1000; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int adp5061_set_prechg_current(struct adp5061_state *st, int val) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci int index; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* Convert from uA to mA */ 37562306a36Sopenharmony_ci val /= 1000; 37662306a36Sopenharmony_ci index = adp5061_get_array_index(adp5061_prechg_current, 37762306a36Sopenharmony_ci ARRAY_SIZE(adp5061_prechg_current), 37862306a36Sopenharmony_ci val); 37962306a36Sopenharmony_ci if (index < 0) 38062306a36Sopenharmony_ci return index; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_CHG_CURR, 38362306a36Sopenharmony_ci ADP5061_CHG_CURR_ITRK_DEAD_MSK, 38462306a36Sopenharmony_ci ADP5061_CHG_CURR_ITRK_DEAD_MODE(index)); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int adp5061_get_vweak_th(struct adp5061_state *st, 38862306a36Sopenharmony_ci union power_supply_propval *val) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci unsigned int regval; 39162306a36Sopenharmony_ci int ret; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val); 39462306a36Sopenharmony_ci if (ret < 0) 39562306a36Sopenharmony_ci return ret; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci regval &= ADP5061_VOLTAGE_TH_VWEAK_MSK; 39862306a36Sopenharmony_ci val->intval = adp5061_vweak_th[regval] * 1000; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return ret; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int adp5061_set_vweak_th(struct adp5061_state *st, int val) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci int index; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Convert from uV to mV */ 40862306a36Sopenharmony_ci val /= 1000; 40962306a36Sopenharmony_ci index = adp5061_get_array_index(adp5061_vweak_th, 41062306a36Sopenharmony_ci ARRAY_SIZE(adp5061_vweak_th), 41162306a36Sopenharmony_ci val); 41262306a36Sopenharmony_ci if (index < 0) 41362306a36Sopenharmony_ci return index; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH, 41662306a36Sopenharmony_ci ADP5061_VOLTAGE_TH_VWEAK_MSK, 41762306a36Sopenharmony_ci ADP5061_VOLTAGE_TH_VWEAK_MODE(index)); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int adp5061_get_chg_type(struct adp5061_state *st, 42162306a36Sopenharmony_ci union power_supply_propval *val) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci u8 status1, status2; 42462306a36Sopenharmony_ci int chg_type, ret; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci ret = adp5061_get_status(st, &status1, &status2); 42762306a36Sopenharmony_ci if (ret < 0) 42862306a36Sopenharmony_ci return ret; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci chg_type = ADP5061_CHG_STATUS_1_CHG_STATUS(status1); 43162306a36Sopenharmony_ci if (chg_type >= ARRAY_SIZE(adp5061_chg_type)) 43262306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 43362306a36Sopenharmony_ci else 43462306a36Sopenharmony_ci val->intval = adp5061_chg_type[chg_type]; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return ret; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int adp5061_get_charger_status(struct adp5061_state *st, 44062306a36Sopenharmony_ci union power_supply_propval *val) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci u8 status1, status2; 44362306a36Sopenharmony_ci int ret; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci ret = adp5061_get_status(st, &status1, &status2); 44662306a36Sopenharmony_ci if (ret < 0) 44762306a36Sopenharmony_ci return ret; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci switch (ADP5061_CHG_STATUS_1_CHG_STATUS(status1)) { 45062306a36Sopenharmony_ci case ADP5061_CHG_OFF: 45162306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 45262306a36Sopenharmony_ci break; 45362306a36Sopenharmony_ci case ADP5061_CHG_TRICKLE: 45462306a36Sopenharmony_ci case ADP5061_CHG_FAST_CC: 45562306a36Sopenharmony_ci case ADP5061_CHG_FAST_CV: 45662306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_CHARGING; 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case ADP5061_CHG_COMPLETE: 45962306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_FULL; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case ADP5061_CHG_TIMER_EXP: 46262306a36Sopenharmony_ci /* The battery must be discharging if there is a charge fault */ 46362306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 46462306a36Sopenharmony_ci break; 46562306a36Sopenharmony_ci default: 46662306a36Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci return ret; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int adp5061_get_battery_status(struct adp5061_state *st, 47362306a36Sopenharmony_ci union power_supply_propval *val) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci u8 status1, status2; 47662306a36Sopenharmony_ci int ret; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci ret = adp5061_get_status(st, &status1, &status2); 47962306a36Sopenharmony_ci if (ret < 0) 48062306a36Sopenharmony_ci return ret; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci switch (ADP5061_CHG_STATUS_2_BAT_STATUS(status2)) { 48362306a36Sopenharmony_ci case 0x0: /* Battery monitor off */ 48462306a36Sopenharmony_ci case 0x1: /* No battery */ 48562306a36Sopenharmony_ci val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci case 0x2: /* VBAT < VTRK */ 48862306a36Sopenharmony_ci val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci case 0x3: /* VTRK < VBAT_SNS < VWEAK */ 49162306a36Sopenharmony_ci val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case 0x4: /* VBAT_SNS > VWEAK */ 49462306a36Sopenharmony_ci val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci default: 49762306a36Sopenharmony_ci val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return ret; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int adp5061_get_termination_current(struct adp5061_state *st, 50562306a36Sopenharmony_ci union power_supply_propval *val) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci unsigned int regval; 50862306a36Sopenharmony_ci int ret; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_IEND, ®val); 51162306a36Sopenharmony_ci if (ret < 0) 51262306a36Sopenharmony_ci return ret; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci regval = (regval & ADP5061_IEND_IEND_MSK) >> 5; 51562306a36Sopenharmony_ci val->intval = adp5061_iend[regval]; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return ret; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int adp5061_set_termination_current(struct adp5061_state *st, int val) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci int index; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci index = adp5061_get_array_index(adp5061_iend, 52562306a36Sopenharmony_ci ARRAY_SIZE(adp5061_iend), 52662306a36Sopenharmony_ci val); 52762306a36Sopenharmony_ci if (index < 0) 52862306a36Sopenharmony_ci return index; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_IEND, 53162306a36Sopenharmony_ci ADP5061_IEND_IEND_MSK, 53262306a36Sopenharmony_ci ADP5061_IEND_IEND_MODE(index)); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic int adp5061_get_property(struct power_supply *psy, 53662306a36Sopenharmony_ci enum power_supply_property psp, 53762306a36Sopenharmony_ci union power_supply_propval *val) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct adp5061_state *st = power_supply_get_drvdata(psy); 54062306a36Sopenharmony_ci u8 status1, status2; 54162306a36Sopenharmony_ci int mode, ret; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci switch (psp) { 54462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_PRESENT: 54562306a36Sopenharmony_ci ret = adp5061_get_status(st, &status1, &status2); 54662306a36Sopenharmony_ci if (ret < 0) 54762306a36Sopenharmony_ci return ret; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci mode = ADP5061_CHG_STATUS_2_BAT_STATUS(status2); 55062306a36Sopenharmony_ci if (mode == ADP5061_NO_BATTERY) 55162306a36Sopenharmony_ci val->intval = 0; 55262306a36Sopenharmony_ci else 55362306a36Sopenharmony_ci val->intval = 1; 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TYPE: 55662306a36Sopenharmony_ci return adp5061_get_chg_type(st, val); 55762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 55862306a36Sopenharmony_ci /* This property is used to indicate the input current 55962306a36Sopenharmony_ci * limit into VINx (ILIM) 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci return adp5061_get_input_current_limit(st, val); 56262306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MAX: 56362306a36Sopenharmony_ci /* This property is used to indicate the termination 56462306a36Sopenharmony_ci * voltage (VTRM) 56562306a36Sopenharmony_ci */ 56662306a36Sopenharmony_ci return adp5061_get_max_voltage(st, val); 56762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MIN: 56862306a36Sopenharmony_ci /* 56962306a36Sopenharmony_ci * This property is used to indicate the trickle to fast 57062306a36Sopenharmony_ci * charge threshold (VTRK_DEAD) 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci return adp5061_get_min_voltage(st, val); 57362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 57462306a36Sopenharmony_ci /* This property is used to indicate the charging 57562306a36Sopenharmony_ci * voltage limit (CHG_VLIM) 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ci return adp5061_get_chg_volt_lim(st, val); 57862306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 57962306a36Sopenharmony_ci /* 58062306a36Sopenharmony_ci * This property is used to indicate the value of the constant 58162306a36Sopenharmony_ci * current charge (ICHG) 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_ci return adp5061_get_const_chg_current(st, val); 58462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 58562306a36Sopenharmony_ci /* 58662306a36Sopenharmony_ci * This property is used to indicate the value of the trickle 58762306a36Sopenharmony_ci * and weak charge currents (ITRK_DEAD) 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_ci return adp5061_get_prechg_current(st, val); 59062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_AVG: 59162306a36Sopenharmony_ci /* 59262306a36Sopenharmony_ci * This property is used to set the VWEAK threshold 59362306a36Sopenharmony_ci * bellow this value, weak charge mode is entered 59462306a36Sopenharmony_ci * above this value, fast chargerge mode is entered 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_ci return adp5061_get_vweak_th(st, val); 59762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 59862306a36Sopenharmony_ci /* 59962306a36Sopenharmony_ci * Indicate the charger status in relation to power 60062306a36Sopenharmony_ci * supply status property 60162306a36Sopenharmony_ci */ 60262306a36Sopenharmony_ci return adp5061_get_charger_status(st, val); 60362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 60462306a36Sopenharmony_ci /* 60562306a36Sopenharmony_ci * Indicate the battery status in relation to power 60662306a36Sopenharmony_ci * supply capacity level property 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_ci return adp5061_get_battery_status(st, val); 60962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 61062306a36Sopenharmony_ci /* Indicate the values of the termination current */ 61162306a36Sopenharmony_ci return adp5061_get_termination_current(st, val); 61262306a36Sopenharmony_ci default: 61362306a36Sopenharmony_ci return -EINVAL; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return 0; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic int adp5061_set_property(struct power_supply *psy, 62062306a36Sopenharmony_ci enum power_supply_property psp, 62162306a36Sopenharmony_ci const union power_supply_propval *val) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct adp5061_state *st = power_supply_get_drvdata(psy); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci switch (psp) { 62662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 62762306a36Sopenharmony_ci return adp5061_set_input_current_limit(st, val->intval); 62862306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MAX: 62962306a36Sopenharmony_ci return adp5061_set_max_voltage(st, val->intval); 63062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MIN: 63162306a36Sopenharmony_ci return adp5061_set_min_voltage(st, val->intval); 63262306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 63362306a36Sopenharmony_ci return adp5061_set_const_chg_vmax(st, val->intval); 63462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 63562306a36Sopenharmony_ci return adp5061_set_const_chg_current(st, val->intval); 63662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 63762306a36Sopenharmony_ci return adp5061_set_prechg_current(st, val->intval); 63862306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_AVG: 63962306a36Sopenharmony_ci return adp5061_set_vweak_th(st, val->intval); 64062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 64162306a36Sopenharmony_ci return adp5061_set_termination_current(st, val->intval); 64262306a36Sopenharmony_ci default: 64362306a36Sopenharmony_ci return -EINVAL; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return 0; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int adp5061_prop_writeable(struct power_supply *psy, 65062306a36Sopenharmony_ci enum power_supply_property psp) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci switch (psp) { 65362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 65462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MAX: 65562306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MIN: 65662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 65762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 65862306a36Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 65962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_AVG: 66062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 66162306a36Sopenharmony_ci return 1; 66262306a36Sopenharmony_ci default: 66362306a36Sopenharmony_ci return 0; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic enum power_supply_property adp5061_props[] = { 66862306a36Sopenharmony_ci POWER_SUPPLY_PROP_PRESENT, 66962306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TYPE, 67062306a36Sopenharmony_ci POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 67162306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_MAX, 67262306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_MIN, 67362306a36Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 67462306a36Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 67562306a36Sopenharmony_ci POWER_SUPPLY_PROP_PRECHARGE_CURRENT, 67662306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_AVG, 67762306a36Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 67862306a36Sopenharmony_ci POWER_SUPPLY_PROP_CAPACITY_LEVEL, 67962306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 68062306a36Sopenharmony_ci}; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic const struct regmap_config adp5061_regmap_config = { 68362306a36Sopenharmony_ci .reg_bits = 8, 68462306a36Sopenharmony_ci .val_bits = 8, 68562306a36Sopenharmony_ci}; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic const struct power_supply_desc adp5061_desc = { 68862306a36Sopenharmony_ci .name = "adp5061", 68962306a36Sopenharmony_ci .type = POWER_SUPPLY_TYPE_USB, 69062306a36Sopenharmony_ci .get_property = adp5061_get_property, 69162306a36Sopenharmony_ci .set_property = adp5061_set_property, 69262306a36Sopenharmony_ci .property_is_writeable = adp5061_prop_writeable, 69362306a36Sopenharmony_ci .properties = adp5061_props, 69462306a36Sopenharmony_ci .num_properties = ARRAY_SIZE(adp5061_props), 69562306a36Sopenharmony_ci}; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic int adp5061_probe(struct i2c_client *client) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct power_supply_config psy_cfg = {}; 70062306a36Sopenharmony_ci struct adp5061_state *st; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL); 70362306a36Sopenharmony_ci if (!st) 70462306a36Sopenharmony_ci return -ENOMEM; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci st->client = client; 70762306a36Sopenharmony_ci st->regmap = devm_regmap_init_i2c(client, 70862306a36Sopenharmony_ci &adp5061_regmap_config); 70962306a36Sopenharmony_ci if (IS_ERR(st->regmap)) { 71062306a36Sopenharmony_ci dev_err(&client->dev, "Failed to initialize register map\n"); 71162306a36Sopenharmony_ci return -EINVAL; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci i2c_set_clientdata(client, st); 71562306a36Sopenharmony_ci psy_cfg.drv_data = st; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci st->psy = devm_power_supply_register(&client->dev, 71862306a36Sopenharmony_ci &adp5061_desc, 71962306a36Sopenharmony_ci &psy_cfg); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (IS_ERR(st->psy)) { 72262306a36Sopenharmony_ci dev_err(&client->dev, "Failed to register power supply\n"); 72362306a36Sopenharmony_ci return PTR_ERR(st->psy); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci return 0; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic const struct i2c_device_id adp5061_id[] = { 73062306a36Sopenharmony_ci { "adp5061", 0}, 73162306a36Sopenharmony_ci { } 73262306a36Sopenharmony_ci}; 73362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adp5061_id); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic struct i2c_driver adp5061_driver = { 73662306a36Sopenharmony_ci .driver = { 73762306a36Sopenharmony_ci .name = KBUILD_MODNAME, 73862306a36Sopenharmony_ci }, 73962306a36Sopenharmony_ci .probe = adp5061_probe, 74062306a36Sopenharmony_ci .id_table = adp5061_id, 74162306a36Sopenharmony_ci}; 74262306a36Sopenharmony_cimodule_i2c_driver(adp5061_driver); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices adp5061 battery charger driver"); 74562306a36Sopenharmony_ciMODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); 74662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 747