18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TI BQ24257 charger driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Intel Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Datasheets: 88c2ecf20Sopenharmony_ci * https://www.ti.com/product/bq24250 98c2ecf20Sopenharmony_ci * https://www.ti.com/product/bq24251 108c2ecf20Sopenharmony_ci * https://www.ti.com/product/bq24257 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/i2c.h> 158c2ecf20Sopenharmony_ci#include <linux/power_supply.h> 168c2ecf20Sopenharmony_ci#include <linux/regmap.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/delay.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/acpi.h> 238c2ecf20Sopenharmony_ci#include <linux/of.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define BQ24257_REG_1 0x00 268c2ecf20Sopenharmony_ci#define BQ24257_REG_2 0x01 278c2ecf20Sopenharmony_ci#define BQ24257_REG_3 0x02 288c2ecf20Sopenharmony_ci#define BQ24257_REG_4 0x03 298c2ecf20Sopenharmony_ci#define BQ24257_REG_5 0x04 308c2ecf20Sopenharmony_ci#define BQ24257_REG_6 0x05 318c2ecf20Sopenharmony_ci#define BQ24257_REG_7 0x06 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define BQ24257_MANUFACTURER "Texas Instruments" 348c2ecf20Sopenharmony_ci#define BQ24257_PG_GPIO "pg" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define BQ24257_ILIM_SET_DELAY 1000 /* msec */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * When adding support for new devices make sure that enum bq2425x_chip and 408c2ecf20Sopenharmony_ci * bq2425x_chip_name[] always stay in sync! 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cienum bq2425x_chip { 438c2ecf20Sopenharmony_ci BQ24250, 448c2ecf20Sopenharmony_ci BQ24251, 458c2ecf20Sopenharmony_ci BQ24257, 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic const char *const bq2425x_chip_name[] = { 498c2ecf20Sopenharmony_ci "bq24250", 508c2ecf20Sopenharmony_ci "bq24251", 518c2ecf20Sopenharmony_ci "bq24257", 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cienum bq24257_fields { 558c2ecf20Sopenharmony_ci F_WD_FAULT, F_WD_EN, F_STAT, F_FAULT, /* REG 1 */ 568c2ecf20Sopenharmony_ci F_RESET, F_IILIMIT, F_EN_STAT, F_EN_TERM, F_CE, F_HZ_MODE, /* REG 2 */ 578c2ecf20Sopenharmony_ci F_VBAT, F_USB_DET, /* REG 3 */ 588c2ecf20Sopenharmony_ci F_ICHG, F_ITERM, /* REG 4 */ 598c2ecf20Sopenharmony_ci F_LOOP_STATUS, F_LOW_CHG, F_DPDM_EN, F_CE_STATUS, F_VINDPM, /* REG 5 */ 608c2ecf20Sopenharmony_ci F_X2_TMR_EN, F_TMR, F_SYSOFF, F_TS_EN, F_TS_STAT, /* REG 6 */ 618c2ecf20Sopenharmony_ci F_VOVP, F_CLR_VDP, F_FORCE_BATDET, F_FORCE_PTM, /* REG 7 */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci F_MAX_FIELDS 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* initial field values, converted from uV/uA */ 678c2ecf20Sopenharmony_cistruct bq24257_init_data { 688c2ecf20Sopenharmony_ci u8 ichg; /* charge current */ 698c2ecf20Sopenharmony_ci u8 vbat; /* regulation voltage */ 708c2ecf20Sopenharmony_ci u8 iterm; /* termination current */ 718c2ecf20Sopenharmony_ci u8 iilimit; /* input current limit */ 728c2ecf20Sopenharmony_ci u8 vovp; /* over voltage protection voltage */ 738c2ecf20Sopenharmony_ci u8 vindpm; /* VDMP input threshold voltage */ 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistruct bq24257_state { 778c2ecf20Sopenharmony_ci u8 status; 788c2ecf20Sopenharmony_ci u8 fault; 798c2ecf20Sopenharmony_ci bool power_good; 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistruct bq24257_device { 838c2ecf20Sopenharmony_ci struct i2c_client *client; 848c2ecf20Sopenharmony_ci struct device *dev; 858c2ecf20Sopenharmony_ci struct power_supply *charger; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci enum bq2425x_chip chip; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci struct regmap *rmap; 908c2ecf20Sopenharmony_ci struct regmap_field *rmap_fields[F_MAX_FIELDS]; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci struct gpio_desc *pg; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci struct delayed_work iilimit_setup_work; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci struct bq24257_init_data init_data; 978c2ecf20Sopenharmony_ci struct bq24257_state state; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci struct mutex lock; /* protect state data */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci bool iilimit_autoset_enable; 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic bool bq24257_is_volatile_reg(struct device *dev, unsigned int reg) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci switch (reg) { 1078c2ecf20Sopenharmony_ci case BQ24257_REG_2: 1088c2ecf20Sopenharmony_ci case BQ24257_REG_4: 1098c2ecf20Sopenharmony_ci return false; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci default: 1128c2ecf20Sopenharmony_ci return true; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic const struct regmap_config bq24257_regmap_config = { 1178c2ecf20Sopenharmony_ci .reg_bits = 8, 1188c2ecf20Sopenharmony_ci .val_bits = 8, 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci .max_register = BQ24257_REG_7, 1218c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci .volatile_reg = bq24257_is_volatile_reg, 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic const struct reg_field bq24257_reg_fields[] = { 1278c2ecf20Sopenharmony_ci /* REG 1 */ 1288c2ecf20Sopenharmony_ci [F_WD_FAULT] = REG_FIELD(BQ24257_REG_1, 7, 7), 1298c2ecf20Sopenharmony_ci [F_WD_EN] = REG_FIELD(BQ24257_REG_1, 6, 6), 1308c2ecf20Sopenharmony_ci [F_STAT] = REG_FIELD(BQ24257_REG_1, 4, 5), 1318c2ecf20Sopenharmony_ci [F_FAULT] = REG_FIELD(BQ24257_REG_1, 0, 3), 1328c2ecf20Sopenharmony_ci /* REG 2 */ 1338c2ecf20Sopenharmony_ci [F_RESET] = REG_FIELD(BQ24257_REG_2, 7, 7), 1348c2ecf20Sopenharmony_ci [F_IILIMIT] = REG_FIELD(BQ24257_REG_2, 4, 6), 1358c2ecf20Sopenharmony_ci [F_EN_STAT] = REG_FIELD(BQ24257_REG_2, 3, 3), 1368c2ecf20Sopenharmony_ci [F_EN_TERM] = REG_FIELD(BQ24257_REG_2, 2, 2), 1378c2ecf20Sopenharmony_ci [F_CE] = REG_FIELD(BQ24257_REG_2, 1, 1), 1388c2ecf20Sopenharmony_ci [F_HZ_MODE] = REG_FIELD(BQ24257_REG_2, 0, 0), 1398c2ecf20Sopenharmony_ci /* REG 3 */ 1408c2ecf20Sopenharmony_ci [F_VBAT] = REG_FIELD(BQ24257_REG_3, 2, 7), 1418c2ecf20Sopenharmony_ci [F_USB_DET] = REG_FIELD(BQ24257_REG_3, 0, 1), 1428c2ecf20Sopenharmony_ci /* REG 4 */ 1438c2ecf20Sopenharmony_ci [F_ICHG] = REG_FIELD(BQ24257_REG_4, 3, 7), 1448c2ecf20Sopenharmony_ci [F_ITERM] = REG_FIELD(BQ24257_REG_4, 0, 2), 1458c2ecf20Sopenharmony_ci /* REG 5 */ 1468c2ecf20Sopenharmony_ci [F_LOOP_STATUS] = REG_FIELD(BQ24257_REG_5, 6, 7), 1478c2ecf20Sopenharmony_ci [F_LOW_CHG] = REG_FIELD(BQ24257_REG_5, 5, 5), 1488c2ecf20Sopenharmony_ci [F_DPDM_EN] = REG_FIELD(BQ24257_REG_5, 4, 4), 1498c2ecf20Sopenharmony_ci [F_CE_STATUS] = REG_FIELD(BQ24257_REG_5, 3, 3), 1508c2ecf20Sopenharmony_ci [F_VINDPM] = REG_FIELD(BQ24257_REG_5, 0, 2), 1518c2ecf20Sopenharmony_ci /* REG 6 */ 1528c2ecf20Sopenharmony_ci [F_X2_TMR_EN] = REG_FIELD(BQ24257_REG_6, 7, 7), 1538c2ecf20Sopenharmony_ci [F_TMR] = REG_FIELD(BQ24257_REG_6, 5, 6), 1548c2ecf20Sopenharmony_ci [F_SYSOFF] = REG_FIELD(BQ24257_REG_6, 4, 4), 1558c2ecf20Sopenharmony_ci [F_TS_EN] = REG_FIELD(BQ24257_REG_6, 3, 3), 1568c2ecf20Sopenharmony_ci [F_TS_STAT] = REG_FIELD(BQ24257_REG_6, 0, 2), 1578c2ecf20Sopenharmony_ci /* REG 7 */ 1588c2ecf20Sopenharmony_ci [F_VOVP] = REG_FIELD(BQ24257_REG_7, 5, 7), 1598c2ecf20Sopenharmony_ci [F_CLR_VDP] = REG_FIELD(BQ24257_REG_7, 4, 4), 1608c2ecf20Sopenharmony_ci [F_FORCE_BATDET] = REG_FIELD(BQ24257_REG_7, 3, 3), 1618c2ecf20Sopenharmony_ci [F_FORCE_PTM] = REG_FIELD(BQ24257_REG_7, 2, 2) 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic const u32 bq24257_vbat_map[] = { 1658c2ecf20Sopenharmony_ci 3500000, 3520000, 3540000, 3560000, 3580000, 3600000, 3620000, 3640000, 1668c2ecf20Sopenharmony_ci 3660000, 3680000, 3700000, 3720000, 3740000, 3760000, 3780000, 3800000, 1678c2ecf20Sopenharmony_ci 3820000, 3840000, 3860000, 3880000, 3900000, 3920000, 3940000, 3960000, 1688c2ecf20Sopenharmony_ci 3980000, 4000000, 4020000, 4040000, 4060000, 4080000, 4100000, 4120000, 1698c2ecf20Sopenharmony_ci 4140000, 4160000, 4180000, 4200000, 4220000, 4240000, 4260000, 4280000, 1708c2ecf20Sopenharmony_ci 4300000, 4320000, 4340000, 4360000, 4380000, 4400000, 4420000, 4440000 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#define BQ24257_VBAT_MAP_SIZE ARRAY_SIZE(bq24257_vbat_map) 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic const u32 bq24257_ichg_map[] = { 1768c2ecf20Sopenharmony_ci 500000, 550000, 600000, 650000, 700000, 750000, 800000, 850000, 900000, 1778c2ecf20Sopenharmony_ci 950000, 1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1788c2ecf20Sopenharmony_ci 1350000, 1400000, 1450000, 1500000, 1550000, 1600000, 1650000, 1700000, 1798c2ecf20Sopenharmony_ci 1750000, 1800000, 1850000, 1900000, 1950000, 2000000 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define BQ24257_ICHG_MAP_SIZE ARRAY_SIZE(bq24257_ichg_map) 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic const u32 bq24257_iterm_map[] = { 1858c2ecf20Sopenharmony_ci 50000, 75000, 100000, 125000, 150000, 175000, 200000, 225000 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define BQ24257_ITERM_MAP_SIZE ARRAY_SIZE(bq24257_iterm_map) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic const u32 bq24257_iilimit_map[] = { 1918c2ecf20Sopenharmony_ci 100000, 150000, 500000, 900000, 1500000, 2000000 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#define BQ24257_IILIMIT_MAP_SIZE ARRAY_SIZE(bq24257_iilimit_map) 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic const u32 bq24257_vovp_map[] = { 1978c2ecf20Sopenharmony_ci 6000000, 6500000, 7000000, 8000000, 9000000, 9500000, 10000000, 1988c2ecf20Sopenharmony_ci 10500000 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#define BQ24257_VOVP_MAP_SIZE ARRAY_SIZE(bq24257_vovp_map) 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic const u32 bq24257_vindpm_map[] = { 2048c2ecf20Sopenharmony_ci 4200000, 4280000, 4360000, 4440000, 4520000, 4600000, 4680000, 2058c2ecf20Sopenharmony_ci 4760000 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci#define BQ24257_VINDPM_MAP_SIZE ARRAY_SIZE(bq24257_vindpm_map) 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int bq24257_field_read(struct bq24257_device *bq, 2118c2ecf20Sopenharmony_ci enum bq24257_fields field_id) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci int ret; 2148c2ecf20Sopenharmony_ci int val; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci ret = regmap_field_read(bq->rmap_fields[field_id], &val); 2178c2ecf20Sopenharmony_ci if (ret < 0) 2188c2ecf20Sopenharmony_ci return ret; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return val; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int bq24257_field_write(struct bq24257_device *bq, 2248c2ecf20Sopenharmony_ci enum bq24257_fields field_id, u8 val) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci return regmap_field_write(bq->rmap_fields[field_id], val); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic u8 bq24257_find_idx(u32 value, const u32 *map, u8 map_size) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci u8 idx; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci for (idx = 1; idx < map_size; idx++) 2348c2ecf20Sopenharmony_ci if (value < map[idx]) 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return idx - 1; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cienum bq24257_status { 2418c2ecf20Sopenharmony_ci STATUS_READY, 2428c2ecf20Sopenharmony_ci STATUS_CHARGE_IN_PROGRESS, 2438c2ecf20Sopenharmony_ci STATUS_CHARGE_DONE, 2448c2ecf20Sopenharmony_ci STATUS_FAULT, 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cienum bq24257_fault { 2488c2ecf20Sopenharmony_ci FAULT_NORMAL, 2498c2ecf20Sopenharmony_ci FAULT_INPUT_OVP, 2508c2ecf20Sopenharmony_ci FAULT_INPUT_UVLO, 2518c2ecf20Sopenharmony_ci FAULT_SLEEP, 2528c2ecf20Sopenharmony_ci FAULT_BAT_TS, 2538c2ecf20Sopenharmony_ci FAULT_BAT_OVP, 2548c2ecf20Sopenharmony_ci FAULT_TS, 2558c2ecf20Sopenharmony_ci FAULT_TIMER, 2568c2ecf20Sopenharmony_ci FAULT_NO_BAT, 2578c2ecf20Sopenharmony_ci FAULT_ISET, 2588c2ecf20Sopenharmony_ci FAULT_INPUT_LDO_LOW, 2598c2ecf20Sopenharmony_ci}; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int bq24257_get_input_current_limit(struct bq24257_device *bq, 2628c2ecf20Sopenharmony_ci union power_supply_propval *val) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci int ret; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ret = bq24257_field_read(bq, F_IILIMIT); 2678c2ecf20Sopenharmony_ci if (ret < 0) 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* 2718c2ecf20Sopenharmony_ci * The "External ILIM" and "Production & Test" modes are not exposed 2728c2ecf20Sopenharmony_ci * through this driver and not being covered by the lookup table. 2738c2ecf20Sopenharmony_ci * Should such a mode have become active let's return an error rather 2748c2ecf20Sopenharmony_ci * than exceeding the bounds of the lookup table and returning 2758c2ecf20Sopenharmony_ci * garbage. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci if (ret >= BQ24257_IILIMIT_MAP_SIZE) 2788c2ecf20Sopenharmony_ci return -ENODATA; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci val->intval = bq24257_iilimit_map[ret]; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int bq24257_set_input_current_limit(struct bq24257_device *bq, 2868c2ecf20Sopenharmony_ci const union power_supply_propval *val) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci /* 2898c2ecf20Sopenharmony_ci * Address the case where the user manually sets an input current limit 2908c2ecf20Sopenharmony_ci * while the charger auto-detection mechanism is is active. In this 2918c2ecf20Sopenharmony_ci * case we want to abort and go straight to the user-specified value. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci if (bq->iilimit_autoset_enable) 2948c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&bq->iilimit_setup_work); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return bq24257_field_write(bq, F_IILIMIT, 2978c2ecf20Sopenharmony_ci bq24257_find_idx(val->intval, 2988c2ecf20Sopenharmony_ci bq24257_iilimit_map, 2998c2ecf20Sopenharmony_ci BQ24257_IILIMIT_MAP_SIZE)); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int bq24257_power_supply_get_property(struct power_supply *psy, 3038c2ecf20Sopenharmony_ci enum power_supply_property psp, 3048c2ecf20Sopenharmony_ci union power_supply_propval *val) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct bq24257_device *bq = power_supply_get_drvdata(psy); 3078c2ecf20Sopenharmony_ci struct bq24257_state state; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci mutex_lock(&bq->lock); 3108c2ecf20Sopenharmony_ci state = bq->state; 3118c2ecf20Sopenharmony_ci mutex_unlock(&bq->lock); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci switch (psp) { 3148c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 3158c2ecf20Sopenharmony_ci if (!state.power_good) 3168c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 3178c2ecf20Sopenharmony_ci else if (state.status == STATUS_READY) 3188c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 3198c2ecf20Sopenharmony_ci else if (state.status == STATUS_CHARGE_IN_PROGRESS) 3208c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_CHARGING; 3218c2ecf20Sopenharmony_ci else if (state.status == STATUS_CHARGE_DONE) 3228c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_FULL; 3238c2ecf20Sopenharmony_ci else 3248c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_MANUFACTURER: 3288c2ecf20Sopenharmony_ci val->strval = BQ24257_MANUFACTURER; 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_MODEL_NAME: 3328c2ecf20Sopenharmony_ci val->strval = bq2425x_chip_name[bq->chip]; 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 3368c2ecf20Sopenharmony_ci val->intval = state.power_good; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_HEALTH: 3408c2ecf20Sopenharmony_ci switch (state.fault) { 3418c2ecf20Sopenharmony_ci case FAULT_NORMAL: 3428c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_HEALTH_GOOD; 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci case FAULT_INPUT_OVP: 3468c2ecf20Sopenharmony_ci case FAULT_BAT_OVP: 3478c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci case FAULT_TS: 3518c2ecf20Sopenharmony_ci case FAULT_BAT_TS: 3528c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci case FAULT_TIMER: 3568c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci default: 3608c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 3678c2ecf20Sopenharmony_ci val->intval = bq24257_ichg_map[bq->init_data.ichg]; 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 3718c2ecf20Sopenharmony_ci val->intval = bq24257_ichg_map[BQ24257_ICHG_MAP_SIZE - 1]; 3728c2ecf20Sopenharmony_ci break; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 3758c2ecf20Sopenharmony_ci val->intval = bq24257_vbat_map[bq->init_data.vbat]; 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 3798c2ecf20Sopenharmony_ci val->intval = bq24257_vbat_map[BQ24257_VBAT_MAP_SIZE - 1]; 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 3838c2ecf20Sopenharmony_ci val->intval = bq24257_iterm_map[bq->init_data.iterm]; 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 3878c2ecf20Sopenharmony_ci return bq24257_get_input_current_limit(bq, val); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci default: 3908c2ecf20Sopenharmony_ci return -EINVAL; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int bq24257_power_supply_set_property(struct power_supply *psy, 3978c2ecf20Sopenharmony_ci enum power_supply_property prop, 3988c2ecf20Sopenharmony_ci const union power_supply_propval *val) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct bq24257_device *bq = power_supply_get_drvdata(psy); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci switch (prop) { 4038c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 4048c2ecf20Sopenharmony_ci return bq24257_set_input_current_limit(bq, val); 4058c2ecf20Sopenharmony_ci default: 4068c2ecf20Sopenharmony_ci return -EINVAL; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int bq24257_power_supply_property_is_writeable(struct power_supply *psy, 4118c2ecf20Sopenharmony_ci enum power_supply_property psp) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci switch (psp) { 4148c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 4158c2ecf20Sopenharmony_ci return true; 4168c2ecf20Sopenharmony_ci default: 4178c2ecf20Sopenharmony_ci return false; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int bq24257_get_chip_state(struct bq24257_device *bq, 4228c2ecf20Sopenharmony_ci struct bq24257_state *state) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci int ret; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci ret = bq24257_field_read(bq, F_STAT); 4278c2ecf20Sopenharmony_ci if (ret < 0) 4288c2ecf20Sopenharmony_ci return ret; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci state->status = ret; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci ret = bq24257_field_read(bq, F_FAULT); 4338c2ecf20Sopenharmony_ci if (ret < 0) 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci state->fault = ret; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (bq->pg) 4398c2ecf20Sopenharmony_ci state->power_good = !gpiod_get_value_cansleep(bq->pg); 4408c2ecf20Sopenharmony_ci else 4418c2ecf20Sopenharmony_ci /* 4428c2ecf20Sopenharmony_ci * If we have a chip without a dedicated power-good GPIO or 4438c2ecf20Sopenharmony_ci * some other explicit bit that would provide this information 4448c2ecf20Sopenharmony_ci * assume the power is good if there is no supply related 4458c2ecf20Sopenharmony_ci * fault - and not good otherwise. There is a possibility for 4468c2ecf20Sopenharmony_ci * other errors to mask that power in fact is not good but this 4478c2ecf20Sopenharmony_ci * is probably the best we can do here. 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci switch (state->fault) { 4508c2ecf20Sopenharmony_ci case FAULT_INPUT_OVP: 4518c2ecf20Sopenharmony_ci case FAULT_INPUT_UVLO: 4528c2ecf20Sopenharmony_ci case FAULT_INPUT_LDO_LOW: 4538c2ecf20Sopenharmony_ci state->power_good = false; 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci default: 4568c2ecf20Sopenharmony_ci state->power_good = true; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return 0; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic bool bq24257_state_changed(struct bq24257_device *bq, 4638c2ecf20Sopenharmony_ci struct bq24257_state *new_state) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci int ret; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci mutex_lock(&bq->lock); 4688c2ecf20Sopenharmony_ci ret = (bq->state.status != new_state->status || 4698c2ecf20Sopenharmony_ci bq->state.fault != new_state->fault || 4708c2ecf20Sopenharmony_ci bq->state.power_good != new_state->power_good); 4718c2ecf20Sopenharmony_ci mutex_unlock(&bq->lock); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return ret; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cienum bq24257_loop_status { 4778c2ecf20Sopenharmony_ci LOOP_STATUS_NONE, 4788c2ecf20Sopenharmony_ci LOOP_STATUS_IN_DPM, 4798c2ecf20Sopenharmony_ci LOOP_STATUS_IN_CURRENT_LIMIT, 4808c2ecf20Sopenharmony_ci LOOP_STATUS_THERMAL, 4818c2ecf20Sopenharmony_ci}; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cienum bq24257_in_ilimit { 4848c2ecf20Sopenharmony_ci IILIMIT_100, 4858c2ecf20Sopenharmony_ci IILIMIT_150, 4868c2ecf20Sopenharmony_ci IILIMIT_500, 4878c2ecf20Sopenharmony_ci IILIMIT_900, 4888c2ecf20Sopenharmony_ci IILIMIT_1500, 4898c2ecf20Sopenharmony_ci IILIMIT_2000, 4908c2ecf20Sopenharmony_ci IILIMIT_EXT, 4918c2ecf20Sopenharmony_ci IILIMIT_NONE, 4928c2ecf20Sopenharmony_ci}; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cienum bq24257_vovp { 4958c2ecf20Sopenharmony_ci VOVP_6000, 4968c2ecf20Sopenharmony_ci VOVP_6500, 4978c2ecf20Sopenharmony_ci VOVP_7000, 4988c2ecf20Sopenharmony_ci VOVP_8000, 4998c2ecf20Sopenharmony_ci VOVP_9000, 5008c2ecf20Sopenharmony_ci VOVP_9500, 5018c2ecf20Sopenharmony_ci VOVP_10000, 5028c2ecf20Sopenharmony_ci VOVP_10500 5038c2ecf20Sopenharmony_ci}; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cienum bq24257_vindpm { 5068c2ecf20Sopenharmony_ci VINDPM_4200, 5078c2ecf20Sopenharmony_ci VINDPM_4280, 5088c2ecf20Sopenharmony_ci VINDPM_4360, 5098c2ecf20Sopenharmony_ci VINDPM_4440, 5108c2ecf20Sopenharmony_ci VINDPM_4520, 5118c2ecf20Sopenharmony_ci VINDPM_4600, 5128c2ecf20Sopenharmony_ci VINDPM_4680, 5138c2ecf20Sopenharmony_ci VINDPM_4760 5148c2ecf20Sopenharmony_ci}; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cienum bq24257_port_type { 5178c2ecf20Sopenharmony_ci PORT_TYPE_DCP, /* Dedicated Charging Port */ 5188c2ecf20Sopenharmony_ci PORT_TYPE_CDP, /* Charging Downstream Port */ 5198c2ecf20Sopenharmony_ci PORT_TYPE_SDP, /* Standard Downstream Port */ 5208c2ecf20Sopenharmony_ci PORT_TYPE_NON_STANDARD, 5218c2ecf20Sopenharmony_ci}; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cienum bq24257_safety_timer { 5248c2ecf20Sopenharmony_ci SAFETY_TIMER_45, 5258c2ecf20Sopenharmony_ci SAFETY_TIMER_360, 5268c2ecf20Sopenharmony_ci SAFETY_TIMER_540, 5278c2ecf20Sopenharmony_ci SAFETY_TIMER_NONE, 5288c2ecf20Sopenharmony_ci}; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int bq24257_iilimit_autoset(struct bq24257_device *bq) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci int loop_status; 5338c2ecf20Sopenharmony_ci int iilimit; 5348c2ecf20Sopenharmony_ci int port_type; 5358c2ecf20Sopenharmony_ci int ret; 5368c2ecf20Sopenharmony_ci const u8 new_iilimit[] = { 5378c2ecf20Sopenharmony_ci [PORT_TYPE_DCP] = IILIMIT_2000, 5388c2ecf20Sopenharmony_ci [PORT_TYPE_CDP] = IILIMIT_2000, 5398c2ecf20Sopenharmony_ci [PORT_TYPE_SDP] = IILIMIT_500, 5408c2ecf20Sopenharmony_ci [PORT_TYPE_NON_STANDARD] = IILIMIT_500 5418c2ecf20Sopenharmony_ci }; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci ret = bq24257_field_read(bq, F_LOOP_STATUS); 5448c2ecf20Sopenharmony_ci if (ret < 0) 5458c2ecf20Sopenharmony_ci goto error; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci loop_status = ret; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci ret = bq24257_field_read(bq, F_IILIMIT); 5508c2ecf20Sopenharmony_ci if (ret < 0) 5518c2ecf20Sopenharmony_ci goto error; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci iilimit = ret; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* 5568c2ecf20Sopenharmony_ci * All USB ports should be able to handle 500mA. If not, DPM will lower 5578c2ecf20Sopenharmony_ci * the charging current to accommodate the power source. No need to set 5588c2ecf20Sopenharmony_ci * a lower IILIMIT value. 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci if (loop_status == LOOP_STATUS_IN_DPM && iilimit == IILIMIT_500) 5618c2ecf20Sopenharmony_ci return 0; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci ret = bq24257_field_read(bq, F_USB_DET); 5648c2ecf20Sopenharmony_ci if (ret < 0) 5658c2ecf20Sopenharmony_ci goto error; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci port_type = ret; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_IILIMIT, new_iilimit[port_type]); 5708c2ecf20Sopenharmony_ci if (ret < 0) 5718c2ecf20Sopenharmony_ci goto error; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_TMR, SAFETY_TIMER_360); 5748c2ecf20Sopenharmony_ci if (ret < 0) 5758c2ecf20Sopenharmony_ci goto error; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_CLR_VDP, 1); 5788c2ecf20Sopenharmony_ci if (ret < 0) 5798c2ecf20Sopenharmony_ci goto error; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci dev_dbg(bq->dev, "port/loop = %d/%d -> iilimit = %d\n", 5828c2ecf20Sopenharmony_ci port_type, loop_status, new_iilimit[port_type]); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cierror: 5878c2ecf20Sopenharmony_ci dev_err(bq->dev, "%s: Error communicating with the chip.\n", __func__); 5888c2ecf20Sopenharmony_ci return ret; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic void bq24257_iilimit_setup_work(struct work_struct *work) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct bq24257_device *bq = container_of(work, struct bq24257_device, 5948c2ecf20Sopenharmony_ci iilimit_setup_work.work); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci bq24257_iilimit_autoset(bq); 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void bq24257_handle_state_change(struct bq24257_device *bq, 6008c2ecf20Sopenharmony_ci struct bq24257_state *new_state) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci int ret; 6038c2ecf20Sopenharmony_ci struct bq24257_state old_state; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci mutex_lock(&bq->lock); 6068c2ecf20Sopenharmony_ci old_state = bq->state; 6078c2ecf20Sopenharmony_ci mutex_unlock(&bq->lock); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* 6108c2ecf20Sopenharmony_ci * Handle BQ2425x state changes observing whether the D+/D- based input 6118c2ecf20Sopenharmony_ci * current limit autoset functionality is enabled. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_ci if (!new_state->power_good) { 6148c2ecf20Sopenharmony_ci dev_dbg(bq->dev, "Power removed\n"); 6158c2ecf20Sopenharmony_ci if (bq->iilimit_autoset_enable) { 6168c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&bq->iilimit_setup_work); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* activate D+/D- port detection algorithm */ 6198c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_DPDM_EN, 1); 6208c2ecf20Sopenharmony_ci if (ret < 0) 6218c2ecf20Sopenharmony_ci goto error; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * When power is removed always return to the default input 6258c2ecf20Sopenharmony_ci * current limit as configured during probe. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_IILIMIT, bq->init_data.iilimit); 6288c2ecf20Sopenharmony_ci if (ret < 0) 6298c2ecf20Sopenharmony_ci goto error; 6308c2ecf20Sopenharmony_ci } else if (!old_state.power_good) { 6318c2ecf20Sopenharmony_ci dev_dbg(bq->dev, "Power inserted\n"); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (bq->iilimit_autoset_enable) 6348c2ecf20Sopenharmony_ci /* configure input current limit */ 6358c2ecf20Sopenharmony_ci schedule_delayed_work(&bq->iilimit_setup_work, 6368c2ecf20Sopenharmony_ci msecs_to_jiffies(BQ24257_ILIM_SET_DELAY)); 6378c2ecf20Sopenharmony_ci } else if (new_state->fault == FAULT_NO_BAT) { 6388c2ecf20Sopenharmony_ci dev_warn(bq->dev, "Battery removed\n"); 6398c2ecf20Sopenharmony_ci } else if (new_state->fault == FAULT_TIMER) { 6408c2ecf20Sopenharmony_ci dev_err(bq->dev, "Safety timer expired! Battery dead?\n"); 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cierror: 6468c2ecf20Sopenharmony_ci dev_err(bq->dev, "%s: Error communicating with the chip.\n", __func__); 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic irqreturn_t bq24257_irq_handler_thread(int irq, void *private) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci int ret; 6528c2ecf20Sopenharmony_ci struct bq24257_device *bq = private; 6538c2ecf20Sopenharmony_ci struct bq24257_state state; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci ret = bq24257_get_chip_state(bq, &state); 6568c2ecf20Sopenharmony_ci if (ret < 0) 6578c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (!bq24257_state_changed(bq, &state)) 6608c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci dev_dbg(bq->dev, "irq(state changed): status/fault/pg = %d/%d/%d\n", 6638c2ecf20Sopenharmony_ci state.status, state.fault, state.power_good); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci bq24257_handle_state_change(bq, &state); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci mutex_lock(&bq->lock); 6688c2ecf20Sopenharmony_ci bq->state = state; 6698c2ecf20Sopenharmony_ci mutex_unlock(&bq->lock); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci power_supply_changed(bq->charger); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic int bq24257_hw_init(struct bq24257_device *bq) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci int ret; 6798c2ecf20Sopenharmony_ci int i; 6808c2ecf20Sopenharmony_ci struct bq24257_state state; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci const struct { 6838c2ecf20Sopenharmony_ci int field; 6848c2ecf20Sopenharmony_ci u32 value; 6858c2ecf20Sopenharmony_ci } init_data[] = { 6868c2ecf20Sopenharmony_ci {F_ICHG, bq->init_data.ichg}, 6878c2ecf20Sopenharmony_ci {F_VBAT, bq->init_data.vbat}, 6888c2ecf20Sopenharmony_ci {F_ITERM, bq->init_data.iterm}, 6898c2ecf20Sopenharmony_ci {F_VOVP, bq->init_data.vovp}, 6908c2ecf20Sopenharmony_ci {F_VINDPM, bq->init_data.vindpm}, 6918c2ecf20Sopenharmony_ci }; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* 6948c2ecf20Sopenharmony_ci * Disable the watchdog timer to prevent the IC from going back to 6958c2ecf20Sopenharmony_ci * default settings after 50 seconds of I2C inactivity. 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_WD_EN, 0); 6988c2ecf20Sopenharmony_ci if (ret < 0) 6998c2ecf20Sopenharmony_ci return ret; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* configure the charge currents and voltages */ 7028c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_data); i++) { 7038c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, init_data[i].field, 7048c2ecf20Sopenharmony_ci init_data[i].value); 7058c2ecf20Sopenharmony_ci if (ret < 0) 7068c2ecf20Sopenharmony_ci return ret; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci ret = bq24257_get_chip_state(bq, &state); 7108c2ecf20Sopenharmony_ci if (ret < 0) 7118c2ecf20Sopenharmony_ci return ret; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci mutex_lock(&bq->lock); 7148c2ecf20Sopenharmony_ci bq->state = state; 7158c2ecf20Sopenharmony_ci mutex_unlock(&bq->lock); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (!bq->iilimit_autoset_enable) { 7188c2ecf20Sopenharmony_ci dev_dbg(bq->dev, "manually setting iilimit = %u\n", 7198c2ecf20Sopenharmony_ci bq->init_data.iilimit); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* program fixed input current limit */ 7228c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_IILIMIT, 7238c2ecf20Sopenharmony_ci bq->init_data.iilimit); 7248c2ecf20Sopenharmony_ci if (ret < 0) 7258c2ecf20Sopenharmony_ci return ret; 7268c2ecf20Sopenharmony_ci } else if (!state.power_good) 7278c2ecf20Sopenharmony_ci /* activate D+/D- detection algorithm */ 7288c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_DPDM_EN, 1); 7298c2ecf20Sopenharmony_ci else if (state.fault != FAULT_NO_BAT) 7308c2ecf20Sopenharmony_ci ret = bq24257_iilimit_autoset(bq); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci return ret; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic enum power_supply_property bq24257_power_supply_props[] = { 7368c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_MANUFACTURER, 7378c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_MODEL_NAME, 7388c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 7398c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_ONLINE, 7408c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_HEALTH, 7418c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 7428c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 7438c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 7448c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 7458c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 7468c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 7478c2ecf20Sopenharmony_ci}; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic char *bq24257_charger_supplied_to[] = { 7508c2ecf20Sopenharmony_ci "main-battery", 7518c2ecf20Sopenharmony_ci}; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic const struct power_supply_desc bq24257_power_supply_desc = { 7548c2ecf20Sopenharmony_ci .name = "bq24257-charger", 7558c2ecf20Sopenharmony_ci .type = POWER_SUPPLY_TYPE_USB, 7568c2ecf20Sopenharmony_ci .properties = bq24257_power_supply_props, 7578c2ecf20Sopenharmony_ci .num_properties = ARRAY_SIZE(bq24257_power_supply_props), 7588c2ecf20Sopenharmony_ci .get_property = bq24257_power_supply_get_property, 7598c2ecf20Sopenharmony_ci .set_property = bq24257_power_supply_set_property, 7608c2ecf20Sopenharmony_ci .property_is_writeable = bq24257_power_supply_property_is_writeable, 7618c2ecf20Sopenharmony_ci}; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic ssize_t bq24257_show_ovp_voltage(struct device *dev, 7648c2ecf20Sopenharmony_ci struct device_attribute *attr, 7658c2ecf20Sopenharmony_ci char *buf) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct power_supply *psy = dev_get_drvdata(dev); 7688c2ecf20Sopenharmony_ci struct bq24257_device *bq = power_supply_get_drvdata(psy); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", 7718c2ecf20Sopenharmony_ci bq24257_vovp_map[bq->init_data.vovp]); 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic ssize_t bq24257_show_in_dpm_voltage(struct device *dev, 7758c2ecf20Sopenharmony_ci struct device_attribute *attr, 7768c2ecf20Sopenharmony_ci char *buf) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct power_supply *psy = dev_get_drvdata(dev); 7798c2ecf20Sopenharmony_ci struct bq24257_device *bq = power_supply_get_drvdata(psy); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", 7828c2ecf20Sopenharmony_ci bq24257_vindpm_map[bq->init_data.vindpm]); 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic ssize_t bq24257_sysfs_show_enable(struct device *dev, 7868c2ecf20Sopenharmony_ci struct device_attribute *attr, 7878c2ecf20Sopenharmony_ci char *buf) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct power_supply *psy = dev_get_drvdata(dev); 7908c2ecf20Sopenharmony_ci struct bq24257_device *bq = power_supply_get_drvdata(psy); 7918c2ecf20Sopenharmony_ci int ret; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (strcmp(attr->attr.name, "high_impedance_enable") == 0) 7948c2ecf20Sopenharmony_ci ret = bq24257_field_read(bq, F_HZ_MODE); 7958c2ecf20Sopenharmony_ci else if (strcmp(attr->attr.name, "sysoff_enable") == 0) 7968c2ecf20Sopenharmony_ci ret = bq24257_field_read(bq, F_SYSOFF); 7978c2ecf20Sopenharmony_ci else 7988c2ecf20Sopenharmony_ci return -EINVAL; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (ret < 0) 8018c2ecf20Sopenharmony_ci return ret; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", ret); 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic ssize_t bq24257_sysfs_set_enable(struct device *dev, 8078c2ecf20Sopenharmony_ci struct device_attribute *attr, 8088c2ecf20Sopenharmony_ci const char *buf, 8098c2ecf20Sopenharmony_ci size_t count) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct power_supply *psy = dev_get_drvdata(dev); 8128c2ecf20Sopenharmony_ci struct bq24257_device *bq = power_supply_get_drvdata(psy); 8138c2ecf20Sopenharmony_ci long val; 8148c2ecf20Sopenharmony_ci int ret; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0) 8178c2ecf20Sopenharmony_ci return -EINVAL; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (strcmp(attr->attr.name, "high_impedance_enable") == 0) 8208c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_HZ_MODE, (bool)val); 8218c2ecf20Sopenharmony_ci else if (strcmp(attr->attr.name, "sysoff_enable") == 0) 8228c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_SYSOFF, (bool)val); 8238c2ecf20Sopenharmony_ci else 8248c2ecf20Sopenharmony_ci return -EINVAL; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (ret < 0) 8278c2ecf20Sopenharmony_ci return ret; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci return count; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ovp_voltage, S_IRUGO, bq24257_show_ovp_voltage, NULL); 8338c2ecf20Sopenharmony_cistatic DEVICE_ATTR(in_dpm_voltage, S_IRUGO, bq24257_show_in_dpm_voltage, NULL); 8348c2ecf20Sopenharmony_cistatic DEVICE_ATTR(high_impedance_enable, S_IWUSR | S_IRUGO, 8358c2ecf20Sopenharmony_ci bq24257_sysfs_show_enable, bq24257_sysfs_set_enable); 8368c2ecf20Sopenharmony_cistatic DEVICE_ATTR(sysoff_enable, S_IWUSR | S_IRUGO, 8378c2ecf20Sopenharmony_ci bq24257_sysfs_show_enable, bq24257_sysfs_set_enable); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic struct attribute *bq24257_charger_sysfs_attrs[] = { 8408c2ecf20Sopenharmony_ci &dev_attr_ovp_voltage.attr, 8418c2ecf20Sopenharmony_ci &dev_attr_in_dpm_voltage.attr, 8428c2ecf20Sopenharmony_ci &dev_attr_high_impedance_enable.attr, 8438c2ecf20Sopenharmony_ci &dev_attr_sysoff_enable.attr, 8448c2ecf20Sopenharmony_ci NULL, 8458c2ecf20Sopenharmony_ci}; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(bq24257_charger_sysfs); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic int bq24257_power_supply_init(struct bq24257_device *bq) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct power_supply_config psy_cfg = { .drv_data = bq, }; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci psy_cfg.attr_grp = bq24257_charger_sysfs_groups; 8548c2ecf20Sopenharmony_ci psy_cfg.supplied_to = bq24257_charger_supplied_to; 8558c2ecf20Sopenharmony_ci psy_cfg.num_supplicants = ARRAY_SIZE(bq24257_charger_supplied_to); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci bq->charger = devm_power_supply_register(bq->dev, 8588c2ecf20Sopenharmony_ci &bq24257_power_supply_desc, 8598c2ecf20Sopenharmony_ci &psy_cfg); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(bq->charger); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic void bq24257_pg_gpio_probe(struct bq24257_device *bq) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci bq->pg = devm_gpiod_get_optional(bq->dev, BQ24257_PG_GPIO, GPIOD_IN); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (PTR_ERR(bq->pg) == -EPROBE_DEFER) { 8698c2ecf20Sopenharmony_ci dev_info(bq->dev, "probe retry requested for PG pin\n"); 8708c2ecf20Sopenharmony_ci return; 8718c2ecf20Sopenharmony_ci } else if (IS_ERR(bq->pg)) { 8728c2ecf20Sopenharmony_ci dev_err(bq->dev, "error probing PG pin\n"); 8738c2ecf20Sopenharmony_ci bq->pg = NULL; 8748c2ecf20Sopenharmony_ci return; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (bq->pg) 8788c2ecf20Sopenharmony_ci dev_dbg(bq->dev, "probed PG pin = %d\n", desc_to_gpio(bq->pg)); 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int bq24257_fw_probe(struct bq24257_device *bq) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci int ret; 8848c2ecf20Sopenharmony_ci u32 property; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* Required properties */ 8878c2ecf20Sopenharmony_ci ret = device_property_read_u32(bq->dev, "ti,charge-current", &property); 8888c2ecf20Sopenharmony_ci if (ret < 0) 8898c2ecf20Sopenharmony_ci return ret; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci bq->init_data.ichg = bq24257_find_idx(property, bq24257_ichg_map, 8928c2ecf20Sopenharmony_ci BQ24257_ICHG_MAP_SIZE); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci ret = device_property_read_u32(bq->dev, "ti,battery-regulation-voltage", 8958c2ecf20Sopenharmony_ci &property); 8968c2ecf20Sopenharmony_ci if (ret < 0) 8978c2ecf20Sopenharmony_ci return ret; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci bq->init_data.vbat = bq24257_find_idx(property, bq24257_vbat_map, 9008c2ecf20Sopenharmony_ci BQ24257_VBAT_MAP_SIZE); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci ret = device_property_read_u32(bq->dev, "ti,termination-current", 9038c2ecf20Sopenharmony_ci &property); 9048c2ecf20Sopenharmony_ci if (ret < 0) 9058c2ecf20Sopenharmony_ci return ret; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci bq->init_data.iterm = bq24257_find_idx(property, bq24257_iterm_map, 9088c2ecf20Sopenharmony_ci BQ24257_ITERM_MAP_SIZE); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* Optional properties. If not provided use reasonable default. */ 9118c2ecf20Sopenharmony_ci ret = device_property_read_u32(bq->dev, "ti,current-limit", 9128c2ecf20Sopenharmony_ci &property); 9138c2ecf20Sopenharmony_ci if (ret < 0) { 9148c2ecf20Sopenharmony_ci bq->iilimit_autoset_enable = true; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* 9178c2ecf20Sopenharmony_ci * Explicitly set a default value which will be needed for 9188c2ecf20Sopenharmony_ci * devices that don't support the automatic setting of the input 9198c2ecf20Sopenharmony_ci * current limit through the charger type detection mechanism. 9208c2ecf20Sopenharmony_ci */ 9218c2ecf20Sopenharmony_ci bq->init_data.iilimit = IILIMIT_500; 9228c2ecf20Sopenharmony_ci } else 9238c2ecf20Sopenharmony_ci bq->init_data.iilimit = 9248c2ecf20Sopenharmony_ci bq24257_find_idx(property, 9258c2ecf20Sopenharmony_ci bq24257_iilimit_map, 9268c2ecf20Sopenharmony_ci BQ24257_IILIMIT_MAP_SIZE); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci ret = device_property_read_u32(bq->dev, "ti,ovp-voltage", 9298c2ecf20Sopenharmony_ci &property); 9308c2ecf20Sopenharmony_ci if (ret < 0) 9318c2ecf20Sopenharmony_ci bq->init_data.vovp = VOVP_6500; 9328c2ecf20Sopenharmony_ci else 9338c2ecf20Sopenharmony_ci bq->init_data.vovp = bq24257_find_idx(property, 9348c2ecf20Sopenharmony_ci bq24257_vovp_map, 9358c2ecf20Sopenharmony_ci BQ24257_VOVP_MAP_SIZE); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci ret = device_property_read_u32(bq->dev, "ti,in-dpm-voltage", 9388c2ecf20Sopenharmony_ci &property); 9398c2ecf20Sopenharmony_ci if (ret < 0) 9408c2ecf20Sopenharmony_ci bq->init_data.vindpm = VINDPM_4360; 9418c2ecf20Sopenharmony_ci else 9428c2ecf20Sopenharmony_ci bq->init_data.vindpm = 9438c2ecf20Sopenharmony_ci bq24257_find_idx(property, 9448c2ecf20Sopenharmony_ci bq24257_vindpm_map, 9458c2ecf20Sopenharmony_ci BQ24257_VINDPM_MAP_SIZE); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return 0; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic int bq24257_probe(struct i2c_client *client, 9518c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 9548c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 9558c2ecf20Sopenharmony_ci const struct acpi_device_id *acpi_id; 9568c2ecf20Sopenharmony_ci struct bq24257_device *bq; 9578c2ecf20Sopenharmony_ci int ret; 9588c2ecf20Sopenharmony_ci int i; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 9618c2ecf20Sopenharmony_ci dev_err(dev, "No support for SMBUS_BYTE_DATA\n"); 9628c2ecf20Sopenharmony_ci return -ENODEV; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); 9668c2ecf20Sopenharmony_ci if (!bq) 9678c2ecf20Sopenharmony_ci return -ENOMEM; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci bq->client = client; 9708c2ecf20Sopenharmony_ci bq->dev = dev; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (ACPI_HANDLE(dev)) { 9738c2ecf20Sopenharmony_ci acpi_id = acpi_match_device(dev->driver->acpi_match_table, 9748c2ecf20Sopenharmony_ci &client->dev); 9758c2ecf20Sopenharmony_ci if (!acpi_id) { 9768c2ecf20Sopenharmony_ci dev_err(dev, "Failed to match ACPI device\n"); 9778c2ecf20Sopenharmony_ci return -ENODEV; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci bq->chip = (enum bq2425x_chip)acpi_id->driver_data; 9808c2ecf20Sopenharmony_ci } else { 9818c2ecf20Sopenharmony_ci bq->chip = (enum bq2425x_chip)id->driver_data; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci mutex_init(&bq->lock); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci bq->rmap = devm_regmap_init_i2c(client, &bq24257_regmap_config); 9878c2ecf20Sopenharmony_ci if (IS_ERR(bq->rmap)) { 9888c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate register map\n"); 9898c2ecf20Sopenharmony_ci return PTR_ERR(bq->rmap); 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bq24257_reg_fields); i++) { 9938c2ecf20Sopenharmony_ci const struct reg_field *reg_fields = bq24257_reg_fields; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci bq->rmap_fields[i] = devm_regmap_field_alloc(dev, bq->rmap, 9968c2ecf20Sopenharmony_ci reg_fields[i]); 9978c2ecf20Sopenharmony_ci if (IS_ERR(bq->rmap_fields[i])) { 9988c2ecf20Sopenharmony_ci dev_err(dev, "cannot allocate regmap field\n"); 9998c2ecf20Sopenharmony_ci return PTR_ERR(bq->rmap_fields[i]); 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci i2c_set_clientdata(client, bq); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci if (!dev->platform_data) { 10068c2ecf20Sopenharmony_ci ret = bq24257_fw_probe(bq); 10078c2ecf20Sopenharmony_ci if (ret < 0) { 10088c2ecf20Sopenharmony_ci dev_err(dev, "Cannot read device properties.\n"); 10098c2ecf20Sopenharmony_ci return ret; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci } else { 10128c2ecf20Sopenharmony_ci return -ENODEV; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci /* 10168c2ecf20Sopenharmony_ci * The BQ24250 doesn't support the D+/D- based charger type detection 10178c2ecf20Sopenharmony_ci * used for the automatic setting of the input current limit setting so 10188c2ecf20Sopenharmony_ci * explicitly disable that feature. 10198c2ecf20Sopenharmony_ci */ 10208c2ecf20Sopenharmony_ci if (bq->chip == BQ24250) 10218c2ecf20Sopenharmony_ci bq->iilimit_autoset_enable = false; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (bq->iilimit_autoset_enable) 10248c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&bq->iilimit_setup_work, 10258c2ecf20Sopenharmony_ci bq24257_iilimit_setup_work); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* 10288c2ecf20Sopenharmony_ci * The BQ24250 doesn't have a dedicated Power Good (PG) pin so let's 10298c2ecf20Sopenharmony_ci * not probe for it and instead use a SW-based approach to determine 10308c2ecf20Sopenharmony_ci * the PG state. We also use a SW-based approach for all other devices 10318c2ecf20Sopenharmony_ci * if the PG pin is either not defined or can't be probed. 10328c2ecf20Sopenharmony_ci */ 10338c2ecf20Sopenharmony_ci if (bq->chip != BQ24250) 10348c2ecf20Sopenharmony_ci bq24257_pg_gpio_probe(bq); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (PTR_ERR(bq->pg) == -EPROBE_DEFER) 10378c2ecf20Sopenharmony_ci return PTR_ERR(bq->pg); 10388c2ecf20Sopenharmony_ci else if (!bq->pg) 10398c2ecf20Sopenharmony_ci dev_info(bq->dev, "using SW-based power-good detection\n"); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* reset all registers to defaults */ 10428c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_RESET, 1); 10438c2ecf20Sopenharmony_ci if (ret < 0) 10448c2ecf20Sopenharmony_ci return ret; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* 10478c2ecf20Sopenharmony_ci * Put the RESET bit back to 0, in cache. For some reason the HW always 10488c2ecf20Sopenharmony_ci * returns 1 on this bit, so this is the only way to avoid resetting the 10498c2ecf20Sopenharmony_ci * chip every time we update another field in this register. 10508c2ecf20Sopenharmony_ci */ 10518c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_RESET, 0); 10528c2ecf20Sopenharmony_ci if (ret < 0) 10538c2ecf20Sopenharmony_ci return ret; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci ret = bq24257_hw_init(bq); 10568c2ecf20Sopenharmony_ci if (ret < 0) { 10578c2ecf20Sopenharmony_ci dev_err(dev, "Cannot initialize the chip.\n"); 10588c2ecf20Sopenharmony_ci return ret; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci ret = bq24257_power_supply_init(bq); 10628c2ecf20Sopenharmony_ci if (ret < 0) { 10638c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register power supply\n"); 10648c2ecf20Sopenharmony_ci return ret; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(dev, client->irq, NULL, 10688c2ecf20Sopenharmony_ci bq24257_irq_handler_thread, 10698c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | 10708c2ecf20Sopenharmony_ci IRQF_TRIGGER_RISING | IRQF_ONESHOT, 10718c2ecf20Sopenharmony_ci bq2425x_chip_name[bq->chip], bq); 10728c2ecf20Sopenharmony_ci if (ret) { 10738c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request IRQ #%d\n", client->irq); 10748c2ecf20Sopenharmony_ci return ret; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return 0; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic int bq24257_remove(struct i2c_client *client) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci struct bq24257_device *bq = i2c_get_clientdata(client); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (bq->iilimit_autoset_enable) 10858c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&bq->iilimit_setup_work); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci bq24257_field_write(bq, F_RESET, 1); /* reset to defaults */ 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci return 0; 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 10938c2ecf20Sopenharmony_cistatic int bq24257_suspend(struct device *dev) 10948c2ecf20Sopenharmony_ci{ 10958c2ecf20Sopenharmony_ci struct bq24257_device *bq = dev_get_drvdata(dev); 10968c2ecf20Sopenharmony_ci int ret = 0; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (bq->iilimit_autoset_enable) 10998c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&bq->iilimit_setup_work); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* reset all registers to default (and activate standalone mode) */ 11028c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_RESET, 1); 11038c2ecf20Sopenharmony_ci if (ret < 0) 11048c2ecf20Sopenharmony_ci dev_err(bq->dev, "Cannot reset chip to standalone mode.\n"); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci return ret; 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic int bq24257_resume(struct device *dev) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci int ret; 11128c2ecf20Sopenharmony_ci struct bq24257_device *bq = dev_get_drvdata(dev); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci ret = regcache_drop_region(bq->rmap, BQ24257_REG_1, BQ24257_REG_7); 11158c2ecf20Sopenharmony_ci if (ret < 0) 11168c2ecf20Sopenharmony_ci return ret; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci ret = bq24257_field_write(bq, F_RESET, 0); 11198c2ecf20Sopenharmony_ci if (ret < 0) 11208c2ecf20Sopenharmony_ci return ret; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci ret = bq24257_hw_init(bq); 11238c2ecf20Sopenharmony_ci if (ret < 0) { 11248c2ecf20Sopenharmony_ci dev_err(bq->dev, "Cannot init chip after resume.\n"); 11258c2ecf20Sopenharmony_ci return ret; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* signal userspace, maybe state changed while suspended */ 11298c2ecf20Sopenharmony_ci power_supply_changed(bq->charger); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci return 0; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci#endif 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_cistatic const struct dev_pm_ops bq24257_pm = { 11368c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(bq24257_suspend, bq24257_resume) 11378c2ecf20Sopenharmony_ci}; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic const struct i2c_device_id bq24257_i2c_ids[] = { 11408c2ecf20Sopenharmony_ci { "bq24250", BQ24250 }, 11418c2ecf20Sopenharmony_ci { "bq24251", BQ24251 }, 11428c2ecf20Sopenharmony_ci { "bq24257", BQ24257 }, 11438c2ecf20Sopenharmony_ci {}, 11448c2ecf20Sopenharmony_ci}; 11458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, bq24257_i2c_ids); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cistatic const struct of_device_id bq24257_of_match[] = { 11488c2ecf20Sopenharmony_ci { .compatible = "ti,bq24250", }, 11498c2ecf20Sopenharmony_ci { .compatible = "ti,bq24251", }, 11508c2ecf20Sopenharmony_ci { .compatible = "ti,bq24257", }, 11518c2ecf20Sopenharmony_ci { }, 11528c2ecf20Sopenharmony_ci}; 11538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bq24257_of_match); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 11568c2ecf20Sopenharmony_cistatic const struct acpi_device_id bq24257_acpi_match[] = { 11578c2ecf20Sopenharmony_ci { "BQ242500", BQ24250 }, 11588c2ecf20Sopenharmony_ci { "BQ242510", BQ24251 }, 11598c2ecf20Sopenharmony_ci { "BQ242570", BQ24257 }, 11608c2ecf20Sopenharmony_ci {}, 11618c2ecf20Sopenharmony_ci}; 11628c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, bq24257_acpi_match); 11638c2ecf20Sopenharmony_ci#endif 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistatic struct i2c_driver bq24257_driver = { 11668c2ecf20Sopenharmony_ci .driver = { 11678c2ecf20Sopenharmony_ci .name = "bq24257-charger", 11688c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(bq24257_of_match), 11698c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(bq24257_acpi_match), 11708c2ecf20Sopenharmony_ci .pm = &bq24257_pm, 11718c2ecf20Sopenharmony_ci }, 11728c2ecf20Sopenharmony_ci .probe = bq24257_probe, 11738c2ecf20Sopenharmony_ci .remove = bq24257_remove, 11748c2ecf20Sopenharmony_ci .id_table = bq24257_i2c_ids, 11758c2ecf20Sopenharmony_ci}; 11768c2ecf20Sopenharmony_cimodule_i2c_driver(bq24257_driver); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ciMODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>"); 11798c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("bq24257 charger driver"); 11808c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1181