18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ADP5061 I2C Programmable Linear Battery Charger 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2018 Analog Devices Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/pm.h> 148c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 158c2ecf20Sopenharmony_ci#include <linux/power_supply.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* ADP5061 registers definition */ 218c2ecf20Sopenharmony_ci#define ADP5061_ID 0x00 228c2ecf20Sopenharmony_ci#define ADP5061_REV 0x01 238c2ecf20Sopenharmony_ci#define ADP5061_VINX_SET 0x02 248c2ecf20Sopenharmony_ci#define ADP5061_TERM_SET 0x03 258c2ecf20Sopenharmony_ci#define ADP5061_CHG_CURR 0x04 268c2ecf20Sopenharmony_ci#define ADP5061_VOLTAGE_TH 0x05 278c2ecf20Sopenharmony_ci#define ADP5061_TIMER_SET 0x06 288c2ecf20Sopenharmony_ci#define ADP5061_FUNC_SET_1 0x07 298c2ecf20Sopenharmony_ci#define ADP5061_FUNC_SET_2 0x08 308c2ecf20Sopenharmony_ci#define ADP5061_INT_EN 0x09 318c2ecf20Sopenharmony_ci#define ADP5061_INT_ACT 0x0A 328c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_1 0x0B 338c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_2 0x0C 348c2ecf20Sopenharmony_ci#define ADP5061_FAULT 0x0D 358c2ecf20Sopenharmony_ci#define ADP5061_BATTERY_SHORT 0x10 368c2ecf20Sopenharmony_ci#define ADP5061_IEND 0x11 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* ADP5061_VINX_SET */ 398c2ecf20Sopenharmony_ci#define ADP5061_VINX_SET_ILIM_MSK GENMASK(3, 0) 408c2ecf20Sopenharmony_ci#define ADP5061_VINX_SET_ILIM_MODE(x) (((x) & 0x0F) << 0) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* ADP5061_TERM_SET */ 438c2ecf20Sopenharmony_ci#define ADP5061_TERM_SET_VTRM_MSK GENMASK(7, 2) 448c2ecf20Sopenharmony_ci#define ADP5061_TERM_SET_VTRM_MODE(x) (((x) & 0x3F) << 2) 458c2ecf20Sopenharmony_ci#define ADP5061_TERM_SET_CHG_VLIM_MSK GENMASK(1, 0) 468c2ecf20Sopenharmony_ci#define ADP5061_TERM_SET_CHG_VLIM_MODE(x) (((x) & 0x03) << 0) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* ADP5061_CHG_CURR */ 498c2ecf20Sopenharmony_ci#define ADP5061_CHG_CURR_ICHG_MSK GENMASK(6, 2) 508c2ecf20Sopenharmony_ci#define ADP5061_CHG_CURR_ICHG_MODE(x) (((x) & 0x1F) << 2) 518c2ecf20Sopenharmony_ci#define ADP5061_CHG_CURR_ITRK_DEAD_MSK GENMASK(1, 0) 528c2ecf20Sopenharmony_ci#define ADP5061_CHG_CURR_ITRK_DEAD_MODE(x) (((x) & 0x03) << 0) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* ADP5061_VOLTAGE_TH */ 558c2ecf20Sopenharmony_ci#define ADP5061_VOLTAGE_TH_DIS_RCH_MSK BIT(7) 568c2ecf20Sopenharmony_ci#define ADP5061_VOLTAGE_TH_DIS_RCH_MODE(x) (((x) & 0x01) << 7) 578c2ecf20Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VRCH_MSK GENMASK(6, 5) 588c2ecf20Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VRCH_MODE(x) (((x) & 0x03) << 5) 598c2ecf20Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK GENMASK(4, 3) 608c2ecf20Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(x) (((x) & 0x03) << 3) 618c2ecf20Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VWEAK_MSK GENMASK(2, 0) 628c2ecf20Sopenharmony_ci#define ADP5061_VOLTAGE_TH_VWEAK_MODE(x) (((x) & 0x07) << 0) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* ADP5061_CHG_STATUS_1 */ 658c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_1_VIN_OV(x) (((x) >> 7) & 0x1) 668c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_1_VIN_OK(x) (((x) >> 6) & 0x1) 678c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_1_VIN_ILIM(x) (((x) >> 5) & 0x1) 688c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_1_THERM_LIM(x) (((x) >> 4) & 0x1) 698c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_1_CHDONE(x) (((x) >> 3) & 0x1) 708c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_1_CHG_STATUS(x) (((x) >> 0) & 0x7) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* ADP5061_CHG_STATUS_2 */ 738c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_2_THR_STATUS(x) (((x) >> 5) & 0x7) 748c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_2_RCH_LIM_INFO(x) (((x) >> 3) & 0x1) 758c2ecf20Sopenharmony_ci#define ADP5061_CHG_STATUS_2_BAT_STATUS(x) (((x) >> 0) & 0x7) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* ADP5061_IEND */ 788c2ecf20Sopenharmony_ci#define ADP5061_IEND_IEND_MSK GENMASK(7, 5) 798c2ecf20Sopenharmony_ci#define ADP5061_IEND_IEND_MODE(x) (((x) & 0x07) << 5) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define ADP5061_NO_BATTERY 0x01 828c2ecf20Sopenharmony_ci#define ADP5061_ICHG_MAX 1300 // mA 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cienum adp5061_chg_status { 858c2ecf20Sopenharmony_ci ADP5061_CHG_OFF, 868c2ecf20Sopenharmony_ci ADP5061_CHG_TRICKLE, 878c2ecf20Sopenharmony_ci ADP5061_CHG_FAST_CC, 888c2ecf20Sopenharmony_ci ADP5061_CHG_FAST_CV, 898c2ecf20Sopenharmony_ci ADP5061_CHG_COMPLETE, 908c2ecf20Sopenharmony_ci ADP5061_CHG_LDO_MODE, 918c2ecf20Sopenharmony_ci ADP5061_CHG_TIMER_EXP, 928c2ecf20Sopenharmony_ci ADP5061_CHG_BAT_DET, 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic const int adp5061_chg_type[4] = { 968c2ecf20Sopenharmony_ci [ADP5061_CHG_OFF] = POWER_SUPPLY_CHARGE_TYPE_NONE, 978c2ecf20Sopenharmony_ci [ADP5061_CHG_TRICKLE] = POWER_SUPPLY_CHARGE_TYPE_TRICKLE, 988c2ecf20Sopenharmony_ci [ADP5061_CHG_FAST_CC] = POWER_SUPPLY_CHARGE_TYPE_FAST, 998c2ecf20Sopenharmony_ci [ADP5061_CHG_FAST_CV] = POWER_SUPPLY_CHARGE_TYPE_FAST, 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic const int adp5061_vweak_th[8] = { 1038c2ecf20Sopenharmony_ci 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic const int adp5061_prechg_current[4] = { 1078c2ecf20Sopenharmony_ci 5, 10, 20, 80, 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic const int adp5061_vmin[4] = { 1118c2ecf20Sopenharmony_ci 2000, 2500, 2600, 2900, 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic const int adp5061_const_chg_vmax[4] = { 1158c2ecf20Sopenharmony_ci 3200, 3400, 3700, 3800, 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic const int adp5061_const_ichg[24] = { 1198c2ecf20Sopenharmony_ci 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 1208c2ecf20Sopenharmony_ci 700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1200, 1300, 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic const int adp5061_vmax[36] = { 1248c2ecf20Sopenharmony_ci 3800, 3820, 3840, 3860, 3880, 3900, 3920, 3940, 3960, 3980, 1258c2ecf20Sopenharmony_ci 4000, 4020, 4040, 4060, 4080, 4100, 4120, 4140, 4160, 4180, 1268c2ecf20Sopenharmony_ci 4200, 4220, 4240, 4260, 4280, 4300, 4320, 4340, 4360, 4380, 1278c2ecf20Sopenharmony_ci 4400, 4420, 4440, 4460, 4480, 4500, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic const int adp5061_in_current_lim[16] = { 1318c2ecf20Sopenharmony_ci 100, 150, 200, 250, 300, 400, 500, 600, 700, 1328c2ecf20Sopenharmony_ci 800, 900, 1000, 1200, 1500, 1800, 2100, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic const int adp5061_iend[8] = { 1368c2ecf20Sopenharmony_ci 12500, 32500, 52500, 72500, 92500, 117500, 142500, 170000, 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistruct adp5061_state { 1408c2ecf20Sopenharmony_ci struct i2c_client *client; 1418c2ecf20Sopenharmony_ci struct regmap *regmap; 1428c2ecf20Sopenharmony_ci struct power_supply *psy; 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int adp5061_get_array_index(const int *array, u8 size, int val) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int i; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci for (i = 1; i < size; i++) { 1508c2ecf20Sopenharmony_ci if (val < array[i]) 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return i-1; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int adp5061_get_status(struct adp5061_state *st, 1588c2ecf20Sopenharmony_ci u8 *status1, u8 *status2) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci u8 buf[2]; 1618c2ecf20Sopenharmony_ci int ret; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* CHG_STATUS1 and CHG_STATUS2 are adjacent regs */ 1648c2ecf20Sopenharmony_ci ret = regmap_bulk_read(st->regmap, ADP5061_CHG_STATUS_1, 1658c2ecf20Sopenharmony_ci &buf[0], 2); 1668c2ecf20Sopenharmony_ci if (ret < 0) 1678c2ecf20Sopenharmony_ci return ret; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci *status1 = buf[0]; 1708c2ecf20Sopenharmony_ci *status2 = buf[1]; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int adp5061_get_input_current_limit(struct adp5061_state *st, 1768c2ecf20Sopenharmony_ci union power_supply_propval *val) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci unsigned int regval; 1798c2ecf20Sopenharmony_ci int mode, ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_VINX_SET, ®val); 1828c2ecf20Sopenharmony_ci if (ret < 0) 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci mode = ADP5061_VINX_SET_ILIM_MODE(regval); 1868c2ecf20Sopenharmony_ci val->intval = adp5061_in_current_lim[mode] * 1000; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return ret; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int adp5061_set_input_current_limit(struct adp5061_state *st, int val) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci int index; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* Convert from uA to mA */ 1968c2ecf20Sopenharmony_ci val /= 1000; 1978c2ecf20Sopenharmony_ci index = adp5061_get_array_index(adp5061_in_current_lim, 1988c2ecf20Sopenharmony_ci ARRAY_SIZE(adp5061_in_current_lim), 1998c2ecf20Sopenharmony_ci val); 2008c2ecf20Sopenharmony_ci if (index < 0) 2018c2ecf20Sopenharmony_ci return index; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_VINX_SET, 2048c2ecf20Sopenharmony_ci ADP5061_VINX_SET_ILIM_MSK, 2058c2ecf20Sopenharmony_ci ADP5061_VINX_SET_ILIM_MODE(index)); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int adp5061_set_min_voltage(struct adp5061_state *st, int val) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int index; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* Convert from uV to mV */ 2138c2ecf20Sopenharmony_ci val /= 1000; 2148c2ecf20Sopenharmony_ci index = adp5061_get_array_index(adp5061_vmin, 2158c2ecf20Sopenharmony_ci ARRAY_SIZE(adp5061_vmin), 2168c2ecf20Sopenharmony_ci val); 2178c2ecf20Sopenharmony_ci if (index < 0) 2188c2ecf20Sopenharmony_ci return index; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH, 2218c2ecf20Sopenharmony_ci ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK, 2228c2ecf20Sopenharmony_ci ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(index)); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int adp5061_get_min_voltage(struct adp5061_state *st, 2268c2ecf20Sopenharmony_ci union power_supply_propval *val) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci unsigned int regval; 2298c2ecf20Sopenharmony_ci int ret; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val); 2328c2ecf20Sopenharmony_ci if (ret < 0) 2338c2ecf20Sopenharmony_ci return ret; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci regval = ((regval & ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK) >> 3); 2368c2ecf20Sopenharmony_ci val->intval = adp5061_vmin[regval] * 1000; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return ret; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int adp5061_get_chg_volt_lim(struct adp5061_state *st, 2428c2ecf20Sopenharmony_ci union power_supply_propval *val) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci unsigned int regval; 2458c2ecf20Sopenharmony_ci int mode, ret; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val); 2488c2ecf20Sopenharmony_ci if (ret < 0) 2498c2ecf20Sopenharmony_ci return ret; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci mode = ADP5061_TERM_SET_CHG_VLIM_MODE(regval); 2528c2ecf20Sopenharmony_ci val->intval = adp5061_const_chg_vmax[mode] * 1000; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic int adp5061_get_max_voltage(struct adp5061_state *st, 2588c2ecf20Sopenharmony_ci union power_supply_propval *val) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci unsigned int regval; 2618c2ecf20Sopenharmony_ci int ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val); 2648c2ecf20Sopenharmony_ci if (ret < 0) 2658c2ecf20Sopenharmony_ci return ret; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci regval = ((regval & ADP5061_TERM_SET_VTRM_MSK) >> 2) - 0x0F; 2688c2ecf20Sopenharmony_ci if (regval >= ARRAY_SIZE(adp5061_vmax)) 2698c2ecf20Sopenharmony_ci regval = ARRAY_SIZE(adp5061_vmax) - 1; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci val->intval = adp5061_vmax[regval] * 1000; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int adp5061_set_max_voltage(struct adp5061_state *st, int val) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci int vmax_index; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* Convert from uV to mV */ 2818c2ecf20Sopenharmony_ci val /= 1000; 2828c2ecf20Sopenharmony_ci if (val > 4500) 2838c2ecf20Sopenharmony_ci val = 4500; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci vmax_index = adp5061_get_array_index(adp5061_vmax, 2868c2ecf20Sopenharmony_ci ARRAY_SIZE(adp5061_vmax), val); 2878c2ecf20Sopenharmony_ci if (vmax_index < 0) 2888c2ecf20Sopenharmony_ci return vmax_index; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci vmax_index += 0x0F; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_TERM_SET, 2938c2ecf20Sopenharmony_ci ADP5061_TERM_SET_VTRM_MSK, 2948c2ecf20Sopenharmony_ci ADP5061_TERM_SET_VTRM_MODE(vmax_index)); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int adp5061_set_const_chg_vmax(struct adp5061_state *st, int val) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci int index; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Convert from uV to mV */ 3028c2ecf20Sopenharmony_ci val /= 1000; 3038c2ecf20Sopenharmony_ci index = adp5061_get_array_index(adp5061_const_chg_vmax, 3048c2ecf20Sopenharmony_ci ARRAY_SIZE(adp5061_const_chg_vmax), 3058c2ecf20Sopenharmony_ci val); 3068c2ecf20Sopenharmony_ci if (index < 0) 3078c2ecf20Sopenharmony_ci return index; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_TERM_SET, 3108c2ecf20Sopenharmony_ci ADP5061_TERM_SET_CHG_VLIM_MSK, 3118c2ecf20Sopenharmony_ci ADP5061_TERM_SET_CHG_VLIM_MODE(index)); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int adp5061_set_const_chg_current(struct adp5061_state *st, int val) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci int index; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Convert from uA to mA */ 3208c2ecf20Sopenharmony_ci val /= 1000; 3218c2ecf20Sopenharmony_ci if (val > ADP5061_ICHG_MAX) 3228c2ecf20Sopenharmony_ci val = ADP5061_ICHG_MAX; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci index = adp5061_get_array_index(adp5061_const_ichg, 3258c2ecf20Sopenharmony_ci ARRAY_SIZE(adp5061_const_ichg), 3268c2ecf20Sopenharmony_ci val); 3278c2ecf20Sopenharmony_ci if (index < 0) 3288c2ecf20Sopenharmony_ci return index; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_CHG_CURR, 3318c2ecf20Sopenharmony_ci ADP5061_CHG_CURR_ICHG_MSK, 3328c2ecf20Sopenharmony_ci ADP5061_CHG_CURR_ICHG_MODE(index)); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int adp5061_get_const_chg_current(struct adp5061_state *st, 3368c2ecf20Sopenharmony_ci union power_supply_propval *val) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci unsigned int regval; 3398c2ecf20Sopenharmony_ci int ret; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val); 3428c2ecf20Sopenharmony_ci if (ret < 0) 3438c2ecf20Sopenharmony_ci return ret; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci regval = ((regval & ADP5061_CHG_CURR_ICHG_MSK) >> 2); 3468c2ecf20Sopenharmony_ci if (regval >= ARRAY_SIZE(adp5061_const_ichg)) 3478c2ecf20Sopenharmony_ci regval = ARRAY_SIZE(adp5061_const_ichg) - 1; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci val->intval = adp5061_const_ichg[regval] * 1000; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int adp5061_get_prechg_current(struct adp5061_state *st, 3558c2ecf20Sopenharmony_ci union power_supply_propval *val) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci unsigned int regval; 3588c2ecf20Sopenharmony_ci int ret; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val); 3618c2ecf20Sopenharmony_ci if (ret < 0) 3628c2ecf20Sopenharmony_ci return ret; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci regval &= ADP5061_CHG_CURR_ITRK_DEAD_MSK; 3658c2ecf20Sopenharmony_ci val->intval = adp5061_prechg_current[regval] * 1000; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int adp5061_set_prechg_current(struct adp5061_state *st, int val) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci int index; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Convert from uA to mA */ 3758c2ecf20Sopenharmony_ci val /= 1000; 3768c2ecf20Sopenharmony_ci index = adp5061_get_array_index(adp5061_prechg_current, 3778c2ecf20Sopenharmony_ci ARRAY_SIZE(adp5061_prechg_current), 3788c2ecf20Sopenharmony_ci val); 3798c2ecf20Sopenharmony_ci if (index < 0) 3808c2ecf20Sopenharmony_ci return index; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_CHG_CURR, 3838c2ecf20Sopenharmony_ci ADP5061_CHG_CURR_ITRK_DEAD_MSK, 3848c2ecf20Sopenharmony_ci ADP5061_CHG_CURR_ITRK_DEAD_MODE(index)); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int adp5061_get_vweak_th(struct adp5061_state *st, 3888c2ecf20Sopenharmony_ci union power_supply_propval *val) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci unsigned int regval; 3918c2ecf20Sopenharmony_ci int ret; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val); 3948c2ecf20Sopenharmony_ci if (ret < 0) 3958c2ecf20Sopenharmony_ci return ret; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci regval &= ADP5061_VOLTAGE_TH_VWEAK_MSK; 3988c2ecf20Sopenharmony_ci val->intval = adp5061_vweak_th[regval] * 1000; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return ret; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int adp5061_set_vweak_th(struct adp5061_state *st, int val) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci int index; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Convert from uV to mV */ 4088c2ecf20Sopenharmony_ci val /= 1000; 4098c2ecf20Sopenharmony_ci index = adp5061_get_array_index(adp5061_vweak_th, 4108c2ecf20Sopenharmony_ci ARRAY_SIZE(adp5061_vweak_th), 4118c2ecf20Sopenharmony_ci val); 4128c2ecf20Sopenharmony_ci if (index < 0) 4138c2ecf20Sopenharmony_ci return index; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH, 4168c2ecf20Sopenharmony_ci ADP5061_VOLTAGE_TH_VWEAK_MSK, 4178c2ecf20Sopenharmony_ci ADP5061_VOLTAGE_TH_VWEAK_MODE(index)); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int adp5061_get_chg_type(struct adp5061_state *st, 4218c2ecf20Sopenharmony_ci union power_supply_propval *val) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci u8 status1, status2; 4248c2ecf20Sopenharmony_ci int chg_type, ret; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci ret = adp5061_get_status(st, &status1, &status2); 4278c2ecf20Sopenharmony_ci if (ret < 0) 4288c2ecf20Sopenharmony_ci return ret; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci chg_type = ADP5061_CHG_STATUS_1_CHG_STATUS(status1); 4318c2ecf20Sopenharmony_ci if (chg_type >= ARRAY_SIZE(adp5061_chg_type)) 4328c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 4338c2ecf20Sopenharmony_ci else 4348c2ecf20Sopenharmony_ci val->intval = adp5061_chg_type[chg_type]; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int adp5061_get_charger_status(struct adp5061_state *st, 4408c2ecf20Sopenharmony_ci union power_supply_propval *val) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci u8 status1, status2; 4438c2ecf20Sopenharmony_ci int ret; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci ret = adp5061_get_status(st, &status1, &status2); 4468c2ecf20Sopenharmony_ci if (ret < 0) 4478c2ecf20Sopenharmony_ci return ret; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci switch (ADP5061_CHG_STATUS_1_CHG_STATUS(status1)) { 4508c2ecf20Sopenharmony_ci case ADP5061_CHG_OFF: 4518c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 4528c2ecf20Sopenharmony_ci break; 4538c2ecf20Sopenharmony_ci case ADP5061_CHG_TRICKLE: 4548c2ecf20Sopenharmony_ci case ADP5061_CHG_FAST_CC: 4558c2ecf20Sopenharmony_ci case ADP5061_CHG_FAST_CV: 4568c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_CHARGING; 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci case ADP5061_CHG_COMPLETE: 4598c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_FULL; 4608c2ecf20Sopenharmony_ci break; 4618c2ecf20Sopenharmony_ci case ADP5061_CHG_TIMER_EXP: 4628c2ecf20Sopenharmony_ci /* The battery must be discharging if there is a charge fault */ 4638c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci default: 4668c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return ret; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int adp5061_get_battery_status(struct adp5061_state *st, 4738c2ecf20Sopenharmony_ci union power_supply_propval *val) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci u8 status1, status2; 4768c2ecf20Sopenharmony_ci int ret; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci ret = adp5061_get_status(st, &status1, &status2); 4798c2ecf20Sopenharmony_ci if (ret < 0) 4808c2ecf20Sopenharmony_ci return ret; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci switch (ADP5061_CHG_STATUS_2_BAT_STATUS(status2)) { 4838c2ecf20Sopenharmony_ci case 0x0: /* Battery monitor off */ 4848c2ecf20Sopenharmony_ci case 0x1: /* No battery */ 4858c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci case 0x2: /* VBAT < VTRK */ 4888c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 4898c2ecf20Sopenharmony_ci break; 4908c2ecf20Sopenharmony_ci case 0x3: /* VTRK < VBAT_SNS < VWEAK */ 4918c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case 0x4: /* VBAT_SNS > VWEAK */ 4948c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return ret; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int adp5061_get_termination_current(struct adp5061_state *st, 5028c2ecf20Sopenharmony_ci union power_supply_propval *val) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci unsigned int regval; 5058c2ecf20Sopenharmony_ci int ret; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci ret = regmap_read(st->regmap, ADP5061_IEND, ®val); 5088c2ecf20Sopenharmony_ci if (ret < 0) 5098c2ecf20Sopenharmony_ci return ret; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci regval = (regval & ADP5061_IEND_IEND_MSK) >> 5; 5128c2ecf20Sopenharmony_ci val->intval = adp5061_iend[regval]; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return ret; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int adp5061_set_termination_current(struct adp5061_state *st, int val) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci int index; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci index = adp5061_get_array_index(adp5061_iend, 5228c2ecf20Sopenharmony_ci ARRAY_SIZE(adp5061_iend), 5238c2ecf20Sopenharmony_ci val); 5248c2ecf20Sopenharmony_ci if (index < 0) 5258c2ecf20Sopenharmony_ci return index; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return regmap_update_bits(st->regmap, ADP5061_IEND, 5288c2ecf20Sopenharmony_ci ADP5061_IEND_IEND_MSK, 5298c2ecf20Sopenharmony_ci ADP5061_IEND_IEND_MODE(index)); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int adp5061_get_property(struct power_supply *psy, 5338c2ecf20Sopenharmony_ci enum power_supply_property psp, 5348c2ecf20Sopenharmony_ci union power_supply_propval *val) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct adp5061_state *st = power_supply_get_drvdata(psy); 5378c2ecf20Sopenharmony_ci u8 status1, status2; 5388c2ecf20Sopenharmony_ci int mode, ret; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci switch (psp) { 5418c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_PRESENT: 5428c2ecf20Sopenharmony_ci ret = adp5061_get_status(st, &status1, &status2); 5438c2ecf20Sopenharmony_ci if (ret < 0) 5448c2ecf20Sopenharmony_ci return ret; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci mode = ADP5061_CHG_STATUS_2_BAT_STATUS(status2); 5478c2ecf20Sopenharmony_ci if (mode == ADP5061_NO_BATTERY) 5488c2ecf20Sopenharmony_ci val->intval = 0; 5498c2ecf20Sopenharmony_ci else 5508c2ecf20Sopenharmony_ci val->intval = 1; 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TYPE: 5538c2ecf20Sopenharmony_ci return adp5061_get_chg_type(st, val); 5548c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 5558c2ecf20Sopenharmony_ci /* This property is used to indicate the input current 5568c2ecf20Sopenharmony_ci * limit into VINx (ILIM) 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ci return adp5061_get_input_current_limit(st, val); 5598c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MAX: 5608c2ecf20Sopenharmony_ci /* This property is used to indicate the termination 5618c2ecf20Sopenharmony_ci * voltage (VTRM) 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_ci return adp5061_get_max_voltage(st, val); 5648c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MIN: 5658c2ecf20Sopenharmony_ci /* 5668c2ecf20Sopenharmony_ci * This property is used to indicate the trickle to fast 5678c2ecf20Sopenharmony_ci * charge threshold (VTRK_DEAD) 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ci return adp5061_get_min_voltage(st, val); 5708c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 5718c2ecf20Sopenharmony_ci /* This property is used to indicate the charging 5728c2ecf20Sopenharmony_ci * voltage limit (CHG_VLIM) 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_ci return adp5061_get_chg_volt_lim(st, val); 5758c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 5768c2ecf20Sopenharmony_ci /* 5778c2ecf20Sopenharmony_ci * This property is used to indicate the value of the constant 5788c2ecf20Sopenharmony_ci * current charge (ICHG) 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_ci return adp5061_get_const_chg_current(st, val); 5818c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 5828c2ecf20Sopenharmony_ci /* 5838c2ecf20Sopenharmony_ci * This property is used to indicate the value of the trickle 5848c2ecf20Sopenharmony_ci * and weak charge currents (ITRK_DEAD) 5858c2ecf20Sopenharmony_ci */ 5868c2ecf20Sopenharmony_ci return adp5061_get_prechg_current(st, val); 5878c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_AVG: 5888c2ecf20Sopenharmony_ci /* 5898c2ecf20Sopenharmony_ci * This property is used to set the VWEAK threshold 5908c2ecf20Sopenharmony_ci * bellow this value, weak charge mode is entered 5918c2ecf20Sopenharmony_ci * above this value, fast chargerge mode is entered 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_ci return adp5061_get_vweak_th(st, val); 5948c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 5958c2ecf20Sopenharmony_ci /* 5968c2ecf20Sopenharmony_ci * Indicate the charger status in relation to power 5978c2ecf20Sopenharmony_ci * supply status property 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_ci return adp5061_get_charger_status(st, val); 6008c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 6018c2ecf20Sopenharmony_ci /* 6028c2ecf20Sopenharmony_ci * Indicate the battery status in relation to power 6038c2ecf20Sopenharmony_ci * supply capacity level property 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci return adp5061_get_battery_status(st, val); 6068c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 6078c2ecf20Sopenharmony_ci /* Indicate the values of the termination current */ 6088c2ecf20Sopenharmony_ci return adp5061_get_termination_current(st, val); 6098c2ecf20Sopenharmony_ci default: 6108c2ecf20Sopenharmony_ci return -EINVAL; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic int adp5061_set_property(struct power_supply *psy, 6178c2ecf20Sopenharmony_ci enum power_supply_property psp, 6188c2ecf20Sopenharmony_ci const union power_supply_propval *val) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci struct adp5061_state *st = power_supply_get_drvdata(psy); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci switch (psp) { 6238c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 6248c2ecf20Sopenharmony_ci return adp5061_set_input_current_limit(st, val->intval); 6258c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MAX: 6268c2ecf20Sopenharmony_ci return adp5061_set_max_voltage(st, val->intval); 6278c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MIN: 6288c2ecf20Sopenharmony_ci return adp5061_set_min_voltage(st, val->intval); 6298c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 6308c2ecf20Sopenharmony_ci return adp5061_set_const_chg_vmax(st, val->intval); 6318c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 6328c2ecf20Sopenharmony_ci return adp5061_set_const_chg_current(st, val->intval); 6338c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 6348c2ecf20Sopenharmony_ci return adp5061_set_prechg_current(st, val->intval); 6358c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_AVG: 6368c2ecf20Sopenharmony_ci return adp5061_set_vweak_th(st, val->intval); 6378c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 6388c2ecf20Sopenharmony_ci return adp5061_set_termination_current(st, val->intval); 6398c2ecf20Sopenharmony_ci default: 6408c2ecf20Sopenharmony_ci return -EINVAL; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return 0; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic int adp5061_prop_writeable(struct power_supply *psy, 6478c2ecf20Sopenharmony_ci enum power_supply_property psp) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci switch (psp) { 6508c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 6518c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MAX: 6528c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MIN: 6538c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 6548c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 6558c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 6568c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_AVG: 6578c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 6588c2ecf20Sopenharmony_ci return 1; 6598c2ecf20Sopenharmony_ci default: 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic enum power_supply_property adp5061_props[] = { 6658c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_PRESENT, 6668c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TYPE, 6678c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 6688c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_MAX, 6698c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_MIN, 6708c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 6718c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 6728c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_PRECHARGE_CURRENT, 6738c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_AVG, 6748c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 6758c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6768c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 6778c2ecf20Sopenharmony_ci}; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic const struct regmap_config adp5061_regmap_config = { 6808c2ecf20Sopenharmony_ci .reg_bits = 8, 6818c2ecf20Sopenharmony_ci .val_bits = 8, 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic const struct power_supply_desc adp5061_desc = { 6858c2ecf20Sopenharmony_ci .name = "adp5061", 6868c2ecf20Sopenharmony_ci .type = POWER_SUPPLY_TYPE_USB, 6878c2ecf20Sopenharmony_ci .get_property = adp5061_get_property, 6888c2ecf20Sopenharmony_ci .set_property = adp5061_set_property, 6898c2ecf20Sopenharmony_ci .property_is_writeable = adp5061_prop_writeable, 6908c2ecf20Sopenharmony_ci .properties = adp5061_props, 6918c2ecf20Sopenharmony_ci .num_properties = ARRAY_SIZE(adp5061_props), 6928c2ecf20Sopenharmony_ci}; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic int adp5061_probe(struct i2c_client *client, 6958c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci struct power_supply_config psy_cfg = {}; 6988c2ecf20Sopenharmony_ci struct adp5061_state *st; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL); 7018c2ecf20Sopenharmony_ci if (!st) 7028c2ecf20Sopenharmony_ci return -ENOMEM; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci st->client = client; 7058c2ecf20Sopenharmony_ci st->regmap = devm_regmap_init_i2c(client, 7068c2ecf20Sopenharmony_ci &adp5061_regmap_config); 7078c2ecf20Sopenharmony_ci if (IS_ERR(st->regmap)) { 7088c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to initialize register map\n"); 7098c2ecf20Sopenharmony_ci return -EINVAL; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci i2c_set_clientdata(client, st); 7138c2ecf20Sopenharmony_ci psy_cfg.drv_data = st; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci st->psy = devm_power_supply_register(&client->dev, 7168c2ecf20Sopenharmony_ci &adp5061_desc, 7178c2ecf20Sopenharmony_ci &psy_cfg); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (IS_ERR(st->psy)) { 7208c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to register power supply\n"); 7218c2ecf20Sopenharmony_ci return PTR_ERR(st->psy); 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci return 0; 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic const struct i2c_device_id adp5061_id[] = { 7288c2ecf20Sopenharmony_ci { "adp5061", 0}, 7298c2ecf20Sopenharmony_ci { } 7308c2ecf20Sopenharmony_ci}; 7318c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adp5061_id); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic struct i2c_driver adp5061_driver = { 7348c2ecf20Sopenharmony_ci .driver = { 7358c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 7368c2ecf20Sopenharmony_ci }, 7378c2ecf20Sopenharmony_ci .probe = adp5061_probe, 7388c2ecf20Sopenharmony_ci .id_table = adp5061_id, 7398c2ecf20Sopenharmony_ci}; 7408c2ecf20Sopenharmony_cimodule_i2c_driver(adp5061_driver); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices adp5061 battery charger driver"); 7438c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); 7448c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 745