18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the TI bq24190 battery charger. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Mark A. Greer <mgreer@animalcreek.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 128c2ecf20Sopenharmony_ci#include <linux/of_device.h> 138c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 148c2ecf20Sopenharmony_ci#include <linux/power_supply.h> 158c2ecf20Sopenharmony_ci#include <linux/power/bq24190_charger.h> 168c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 188c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 198c2ecf20Sopenharmony_ci#include <linux/gpio.h> 208c2ecf20Sopenharmony_ci#include <linux/i2c.h> 218c2ecf20Sopenharmony_ci#include <linux/extcon-provider.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define BQ24190_MANUFACTURER "Texas Instruments" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define BQ24190_REG_ISC 0x00 /* Input Source Control */ 268c2ecf20Sopenharmony_ci#define BQ24190_REG_ISC_EN_HIZ_MASK BIT(7) 278c2ecf20Sopenharmony_ci#define BQ24190_REG_ISC_EN_HIZ_SHIFT 7 288c2ecf20Sopenharmony_ci#define BQ24190_REG_ISC_VINDPM_MASK (BIT(6) | BIT(5) | BIT(4) | \ 298c2ecf20Sopenharmony_ci BIT(3)) 308c2ecf20Sopenharmony_ci#define BQ24190_REG_ISC_VINDPM_SHIFT 3 318c2ecf20Sopenharmony_ci#define BQ24190_REG_ISC_IINLIM_MASK (BIT(2) | BIT(1) | BIT(0)) 328c2ecf20Sopenharmony_ci#define BQ24190_REG_ISC_IINLIM_SHIFT 0 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define BQ24190_REG_POC 0x01 /* Power-On Configuration */ 358c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_RESET_MASK BIT(7) 368c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_RESET_SHIFT 7 378c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_WDT_RESET_MASK BIT(6) 388c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_WDT_RESET_SHIFT 6 398c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_CHG_CONFIG_MASK (BIT(5) | BIT(4)) 408c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_CHG_CONFIG_SHIFT 4 418c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_CHG_CONFIG_DISABLE 0x0 428c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_CHG_CONFIG_CHARGE 0x1 438c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_CHG_CONFIG_OTG 0x2 448c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_CHG_CONFIG_OTG_ALT 0x3 458c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_SYS_MIN_MASK (BIT(3) | BIT(2) | BIT(1)) 468c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_SYS_MIN_SHIFT 1 478c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_SYS_MIN_MIN 3000 488c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_SYS_MIN_MAX 3700 498c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_BOOST_LIM_MASK BIT(0) 508c2ecf20Sopenharmony_ci#define BQ24190_REG_POC_BOOST_LIM_SHIFT 0 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define BQ24190_REG_CCC 0x02 /* Charge Current Control */ 538c2ecf20Sopenharmony_ci#define BQ24190_REG_CCC_ICHG_MASK (BIT(7) | BIT(6) | BIT(5) | \ 548c2ecf20Sopenharmony_ci BIT(4) | BIT(3) | BIT(2)) 558c2ecf20Sopenharmony_ci#define BQ24190_REG_CCC_ICHG_SHIFT 2 568c2ecf20Sopenharmony_ci#define BQ24190_REG_CCC_FORCE_20PCT_MASK BIT(0) 578c2ecf20Sopenharmony_ci#define BQ24190_REG_CCC_FORCE_20PCT_SHIFT 0 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define BQ24190_REG_PCTCC 0x03 /* Pre-charge/Termination Current Cntl */ 608c2ecf20Sopenharmony_ci#define BQ24190_REG_PCTCC_IPRECHG_MASK (BIT(7) | BIT(6) | BIT(5) | \ 618c2ecf20Sopenharmony_ci BIT(4)) 628c2ecf20Sopenharmony_ci#define BQ24190_REG_PCTCC_IPRECHG_SHIFT 4 638c2ecf20Sopenharmony_ci#define BQ24190_REG_PCTCC_IPRECHG_MIN 128 648c2ecf20Sopenharmony_ci#define BQ24190_REG_PCTCC_IPRECHG_MAX 2048 658c2ecf20Sopenharmony_ci#define BQ24190_REG_PCTCC_ITERM_MASK (BIT(3) | BIT(2) | BIT(1) | \ 668c2ecf20Sopenharmony_ci BIT(0)) 678c2ecf20Sopenharmony_ci#define BQ24190_REG_PCTCC_ITERM_SHIFT 0 688c2ecf20Sopenharmony_ci#define BQ24190_REG_PCTCC_ITERM_MIN 128 698c2ecf20Sopenharmony_ci#define BQ24190_REG_PCTCC_ITERM_MAX 2048 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define BQ24190_REG_CVC 0x04 /* Charge Voltage Control */ 728c2ecf20Sopenharmony_ci#define BQ24190_REG_CVC_VREG_MASK (BIT(7) | BIT(6) | BIT(5) | \ 738c2ecf20Sopenharmony_ci BIT(4) | BIT(3) | BIT(2)) 748c2ecf20Sopenharmony_ci#define BQ24190_REG_CVC_VREG_SHIFT 2 758c2ecf20Sopenharmony_ci#define BQ24190_REG_CVC_BATLOWV_MASK BIT(1) 768c2ecf20Sopenharmony_ci#define BQ24190_REG_CVC_BATLOWV_SHIFT 1 778c2ecf20Sopenharmony_ci#define BQ24190_REG_CVC_VRECHG_MASK BIT(0) 788c2ecf20Sopenharmony_ci#define BQ24190_REG_CVC_VRECHG_SHIFT 0 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC 0x05 /* Charge Term/Timer Control */ 818c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_EN_TERM_MASK BIT(7) 828c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_EN_TERM_SHIFT 7 838c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_TERM_STAT_MASK BIT(6) 848c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_TERM_STAT_SHIFT 6 858c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_WATCHDOG_MASK (BIT(5) | BIT(4)) 868c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_WATCHDOG_SHIFT 4 878c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_EN_TIMER_MASK BIT(3) 888c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_EN_TIMER_SHIFT 3 898c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_CHG_TIMER_MASK (BIT(2) | BIT(1)) 908c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_CHG_TIMER_SHIFT 1 918c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_JEITA_ISET_MASK BIT(0) 928c2ecf20Sopenharmony_ci#define BQ24190_REG_CTTC_JEITA_ISET_SHIFT 0 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define BQ24190_REG_ICTRC 0x06 /* IR Comp/Thermal Regulation Control */ 958c2ecf20Sopenharmony_ci#define BQ24190_REG_ICTRC_BAT_COMP_MASK (BIT(7) | BIT(6) | BIT(5)) 968c2ecf20Sopenharmony_ci#define BQ24190_REG_ICTRC_BAT_COMP_SHIFT 5 978c2ecf20Sopenharmony_ci#define BQ24190_REG_ICTRC_VCLAMP_MASK (BIT(4) | BIT(3) | BIT(2)) 988c2ecf20Sopenharmony_ci#define BQ24190_REG_ICTRC_VCLAMP_SHIFT 2 998c2ecf20Sopenharmony_ci#define BQ24190_REG_ICTRC_TREG_MASK (BIT(1) | BIT(0)) 1008c2ecf20Sopenharmony_ci#define BQ24190_REG_ICTRC_TREG_SHIFT 0 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC 0x07 /* Misc. Operation Control */ 1038c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_DPDM_EN_MASK BIT(7) 1048c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_DPDM_EN_SHIFT 7 1058c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_TMR2X_EN_MASK BIT(6) 1068c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_TMR2X_EN_SHIFT 6 1078c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_BATFET_DISABLE_MASK BIT(5) 1088c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_BATFET_DISABLE_SHIFT 5 1098c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_JEITA_VSET_MASK BIT(4) 1108c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_JEITA_VSET_SHIFT 4 1118c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_INT_MASK_MASK (BIT(1) | BIT(0)) 1128c2ecf20Sopenharmony_ci#define BQ24190_REG_MOC_INT_MASK_SHIFT 0 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#define BQ24190_REG_SS 0x08 /* System Status */ 1158c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_VBUS_STAT_MASK (BIT(7) | BIT(6)) 1168c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_VBUS_STAT_SHIFT 6 1178c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_CHRG_STAT_MASK (BIT(5) | BIT(4)) 1188c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_CHRG_STAT_SHIFT 4 1198c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_DPM_STAT_MASK BIT(3) 1208c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_DPM_STAT_SHIFT 3 1218c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_PG_STAT_MASK BIT(2) 1228c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_PG_STAT_SHIFT 2 1238c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_THERM_STAT_MASK BIT(1) 1248c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_THERM_STAT_SHIFT 1 1258c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_VSYS_STAT_MASK BIT(0) 1268c2ecf20Sopenharmony_ci#define BQ24190_REG_SS_VSYS_STAT_SHIFT 0 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define BQ24190_REG_F 0x09 /* Fault */ 1298c2ecf20Sopenharmony_ci#define BQ24190_REG_F_WATCHDOG_FAULT_MASK BIT(7) 1308c2ecf20Sopenharmony_ci#define BQ24190_REG_F_WATCHDOG_FAULT_SHIFT 7 1318c2ecf20Sopenharmony_ci#define BQ24190_REG_F_BOOST_FAULT_MASK BIT(6) 1328c2ecf20Sopenharmony_ci#define BQ24190_REG_F_BOOST_FAULT_SHIFT 6 1338c2ecf20Sopenharmony_ci#define BQ24190_REG_F_CHRG_FAULT_MASK (BIT(5) | BIT(4)) 1348c2ecf20Sopenharmony_ci#define BQ24190_REG_F_CHRG_FAULT_SHIFT 4 1358c2ecf20Sopenharmony_ci#define BQ24190_REG_F_BAT_FAULT_MASK BIT(3) 1368c2ecf20Sopenharmony_ci#define BQ24190_REG_F_BAT_FAULT_SHIFT 3 1378c2ecf20Sopenharmony_ci#define BQ24190_REG_F_NTC_FAULT_MASK (BIT(2) | BIT(1) | BIT(0)) 1388c2ecf20Sopenharmony_ci#define BQ24190_REG_F_NTC_FAULT_SHIFT 0 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS 0x0A /* Vendor/Part/Revision Status */ 1418c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS_PN_MASK (BIT(5) | BIT(4) | BIT(3)) 1428c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS_PN_SHIFT 3 1438c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS_PN_24190 0x4 1448c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS_PN_24192 0x5 /* Also 24193, 24196 */ 1458c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS_PN_24192I 0x3 1468c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS_TS_PROFILE_MASK BIT(2) 1478c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS_TS_PROFILE_SHIFT 2 1488c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS_DEV_REG_MASK (BIT(1) | BIT(0)) 1498c2ecf20Sopenharmony_ci#define BQ24190_REG_VPRS_DEV_REG_SHIFT 0 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* 1528c2ecf20Sopenharmony_ci * The FAULT register is latched by the bq24190 (except for NTC_FAULT) 1538c2ecf20Sopenharmony_ci * so the first read after a fault returns the latched value and subsequent 1548c2ecf20Sopenharmony_ci * reads return the current value. In order to return the fault status 1558c2ecf20Sopenharmony_ci * to the user, have the interrupt handler save the reg's value and retrieve 1568c2ecf20Sopenharmony_ci * it in the appropriate health/status routine. 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistruct bq24190_dev_info { 1598c2ecf20Sopenharmony_ci struct i2c_client *client; 1608c2ecf20Sopenharmony_ci struct device *dev; 1618c2ecf20Sopenharmony_ci struct extcon_dev *edev; 1628c2ecf20Sopenharmony_ci struct power_supply *charger; 1638c2ecf20Sopenharmony_ci struct power_supply *battery; 1648c2ecf20Sopenharmony_ci struct delayed_work input_current_limit_work; 1658c2ecf20Sopenharmony_ci char model_name[I2C_NAME_SIZE]; 1668c2ecf20Sopenharmony_ci bool initialized; 1678c2ecf20Sopenharmony_ci bool irq_event; 1688c2ecf20Sopenharmony_ci u16 sys_min; 1698c2ecf20Sopenharmony_ci u16 iprechg; 1708c2ecf20Sopenharmony_ci u16 iterm; 1718c2ecf20Sopenharmony_ci struct mutex f_reg_lock; 1728c2ecf20Sopenharmony_ci u8 f_reg; 1738c2ecf20Sopenharmony_ci u8 ss_reg; 1748c2ecf20Sopenharmony_ci u8 watchdog; 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const unsigned int bq24190_usb_extcon_cable[] = { 1788c2ecf20Sopenharmony_ci EXTCON_USB, 1798c2ecf20Sopenharmony_ci EXTCON_NONE, 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * The tables below provide a 2-way mapping for the value that goes in 1848c2ecf20Sopenharmony_ci * the register field and the real-world value that it represents. 1858c2ecf20Sopenharmony_ci * The index of the array is the value that goes in the register; the 1868c2ecf20Sopenharmony_ci * number at that index in the array is the real-world value that it 1878c2ecf20Sopenharmony_ci * represents. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* REG00[2:0] (IINLIM) in uAh */ 1918c2ecf20Sopenharmony_cistatic const int bq24190_isc_iinlim_values[] = { 1928c2ecf20Sopenharmony_ci 100000, 150000, 500000, 900000, 1200000, 1500000, 2000000, 3000000 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* REG02[7:2] (ICHG) in uAh */ 1968c2ecf20Sopenharmony_cistatic const int bq24190_ccc_ichg_values[] = { 1978c2ecf20Sopenharmony_ci 512000, 576000, 640000, 704000, 768000, 832000, 896000, 960000, 1988c2ecf20Sopenharmony_ci 1024000, 1088000, 1152000, 1216000, 1280000, 1344000, 1408000, 1472000, 1998c2ecf20Sopenharmony_ci 1536000, 1600000, 1664000, 1728000, 1792000, 1856000, 1920000, 1984000, 2008c2ecf20Sopenharmony_ci 2048000, 2112000, 2176000, 2240000, 2304000, 2368000, 2432000, 2496000, 2018c2ecf20Sopenharmony_ci 2560000, 2624000, 2688000, 2752000, 2816000, 2880000, 2944000, 3008000, 2028c2ecf20Sopenharmony_ci 3072000, 3136000, 3200000, 3264000, 3328000, 3392000, 3456000, 3520000, 2038c2ecf20Sopenharmony_ci 3584000, 3648000, 3712000, 3776000, 3840000, 3904000, 3968000, 4032000, 2048c2ecf20Sopenharmony_ci 4096000, 4160000, 4224000, 4288000, 4352000, 4416000, 4480000, 4544000 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* REG04[7:2] (VREG) in uV */ 2088c2ecf20Sopenharmony_cistatic const int bq24190_cvc_vreg_values[] = { 2098c2ecf20Sopenharmony_ci 3504000, 3520000, 3536000, 3552000, 3568000, 3584000, 3600000, 3616000, 2108c2ecf20Sopenharmony_ci 3632000, 3648000, 3664000, 3680000, 3696000, 3712000, 3728000, 3744000, 2118c2ecf20Sopenharmony_ci 3760000, 3776000, 3792000, 3808000, 3824000, 3840000, 3856000, 3872000, 2128c2ecf20Sopenharmony_ci 3888000, 3904000, 3920000, 3936000, 3952000, 3968000, 3984000, 4000000, 2138c2ecf20Sopenharmony_ci 4016000, 4032000, 4048000, 4064000, 4080000, 4096000, 4112000, 4128000, 2148c2ecf20Sopenharmony_ci 4144000, 4160000, 4176000, 4192000, 4208000, 4224000, 4240000, 4256000, 2158c2ecf20Sopenharmony_ci 4272000, 4288000, 4304000, 4320000, 4336000, 4352000, 4368000, 4384000, 2168c2ecf20Sopenharmony_ci 4400000 2178c2ecf20Sopenharmony_ci}; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* REG06[1:0] (TREG) in tenths of degrees Celsius */ 2208c2ecf20Sopenharmony_cistatic const int bq24190_ictrc_treg_values[] = { 2218c2ecf20Sopenharmony_ci 600, 800, 1000, 1200 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* 2258c2ecf20Sopenharmony_ci * Return the index in 'tbl' of greatest value that is less than or equal to 2268c2ecf20Sopenharmony_ci * 'val'. The index range returned is 0 to 'tbl_size' - 1. Assumes that 2278c2ecf20Sopenharmony_ci * the values in 'tbl' are sorted from smallest to largest and 'tbl_size' 2288c2ecf20Sopenharmony_ci * is less than 2^8. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_cistatic u8 bq24190_find_idx(const int tbl[], int tbl_size, int v) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci int i; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci for (i = 1; i < tbl_size; i++) 2358c2ecf20Sopenharmony_ci if (v < tbl[i]) 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return i - 1; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* Basic driver I/O routines */ 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int bq24190_read(struct bq24190_dev_info *bdi, u8 reg, u8 *data) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int ret; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci ret = i2c_smbus_read_byte_data(bdi->client, reg); 2488c2ecf20Sopenharmony_ci if (ret < 0) 2498c2ecf20Sopenharmony_ci return ret; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci *data = ret; 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int bq24190_write(struct bq24190_dev_info *bdi, u8 reg, u8 data) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(bdi->client, reg, data); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int bq24190_read_mask(struct bq24190_dev_info *bdi, u8 reg, 2618c2ecf20Sopenharmony_ci u8 mask, u8 shift, u8 *data) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci u8 v; 2648c2ecf20Sopenharmony_ci int ret; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ret = bq24190_read(bdi, reg, &v); 2678c2ecf20Sopenharmony_ci if (ret < 0) 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci v &= mask; 2718c2ecf20Sopenharmony_ci v >>= shift; 2728c2ecf20Sopenharmony_ci *data = v; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int bq24190_write_mask(struct bq24190_dev_info *bdi, u8 reg, 2788c2ecf20Sopenharmony_ci u8 mask, u8 shift, u8 data) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci u8 v; 2818c2ecf20Sopenharmony_ci int ret; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci ret = bq24190_read(bdi, reg, &v); 2848c2ecf20Sopenharmony_ci if (ret < 0) 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci v &= ~mask; 2888c2ecf20Sopenharmony_ci v |= ((data << shift) & mask); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return bq24190_write(bdi, reg, v); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic int bq24190_get_field_val(struct bq24190_dev_info *bdi, 2948c2ecf20Sopenharmony_ci u8 reg, u8 mask, u8 shift, 2958c2ecf20Sopenharmony_ci const int tbl[], int tbl_size, 2968c2ecf20Sopenharmony_ci int *val) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci u8 v; 2998c2ecf20Sopenharmony_ci int ret; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, reg, mask, shift, &v); 3028c2ecf20Sopenharmony_ci if (ret < 0) 3038c2ecf20Sopenharmony_ci return ret; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci v = (v >= tbl_size) ? (tbl_size - 1) : v; 3068c2ecf20Sopenharmony_ci *val = tbl[v]; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return 0; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic int bq24190_set_field_val(struct bq24190_dev_info *bdi, 3128c2ecf20Sopenharmony_ci u8 reg, u8 mask, u8 shift, 3138c2ecf20Sopenharmony_ci const int tbl[], int tbl_size, 3148c2ecf20Sopenharmony_ci int val) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci u8 idx; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci idx = bq24190_find_idx(tbl, tbl_size, val); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return bq24190_write_mask(bdi, reg, mask, shift, idx); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSFS 3248c2ecf20Sopenharmony_ci/* 3258c2ecf20Sopenharmony_ci * There are a numerous options that are configurable on the bq24190 3268c2ecf20Sopenharmony_ci * that go well beyond what the power_supply properties provide access to. 3278c2ecf20Sopenharmony_ci * Provide sysfs access to them so they can be examined and possibly modified 3288c2ecf20Sopenharmony_ci * on the fly. They will be provided for the charger power_supply object only 3298c2ecf20Sopenharmony_ci * and will be prefixed by 'f_' to make them easier to recognize. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci#define BQ24190_SYSFS_FIELD(_name, r, f, m, store) \ 3338c2ecf20Sopenharmony_ci{ \ 3348c2ecf20Sopenharmony_ci .attr = __ATTR(f_##_name, m, bq24190_sysfs_show, store), \ 3358c2ecf20Sopenharmony_ci .reg = BQ24190_REG_##r, \ 3368c2ecf20Sopenharmony_ci .mask = BQ24190_REG_##r##_##f##_MASK, \ 3378c2ecf20Sopenharmony_ci .shift = BQ24190_REG_##r##_##f##_SHIFT, \ 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci#define BQ24190_SYSFS_FIELD_RW(_name, r, f) \ 3418c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD(_name, r, f, S_IWUSR | S_IRUGO, \ 3428c2ecf20Sopenharmony_ci bq24190_sysfs_store) 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci#define BQ24190_SYSFS_FIELD_RO(_name, r, f) \ 3458c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD(_name, r, f, S_IRUGO, NULL) 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic ssize_t bq24190_sysfs_show(struct device *dev, 3488c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf); 3498c2ecf20Sopenharmony_cistatic ssize_t bq24190_sysfs_store(struct device *dev, 3508c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistruct bq24190_sysfs_field_info { 3538c2ecf20Sopenharmony_ci struct device_attribute attr; 3548c2ecf20Sopenharmony_ci u8 reg; 3558c2ecf20Sopenharmony_ci u8 mask; 3568c2ecf20Sopenharmony_ci u8 shift; 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/* On i386 ptrace-abi.h defines SS that breaks the macro calls below. */ 3608c2ecf20Sopenharmony_ci#undef SS 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic struct bq24190_sysfs_field_info bq24190_sysfs_field_tbl[] = { 3638c2ecf20Sopenharmony_ci /* sysfs name reg field in reg */ 3648c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(en_hiz, ISC, EN_HIZ), 3658c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(vindpm, ISC, VINDPM), 3668c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(iinlim, ISC, IINLIM), 3678c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(chg_config, POC, CHG_CONFIG), 3688c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(sys_min, POC, SYS_MIN), 3698c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(boost_lim, POC, BOOST_LIM), 3708c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(ichg, CCC, ICHG), 3718c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(force_20_pct, CCC, FORCE_20PCT), 3728c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(iprechg, PCTCC, IPRECHG), 3738c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(iterm, PCTCC, ITERM), 3748c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(vreg, CVC, VREG), 3758c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(batlowv, CVC, BATLOWV), 3768c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(vrechg, CVC, VRECHG), 3778c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(en_term, CTTC, EN_TERM), 3788c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(term_stat, CTTC, TERM_STAT), 3798c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(watchdog, CTTC, WATCHDOG), 3808c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(en_timer, CTTC, EN_TIMER), 3818c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(chg_timer, CTTC, CHG_TIMER), 3828c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(jeta_iset, CTTC, JEITA_ISET), 3838c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(bat_comp, ICTRC, BAT_COMP), 3848c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(vclamp, ICTRC, VCLAMP), 3858c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(treg, ICTRC, TREG), 3868c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(dpdm_en, MOC, DPDM_EN), 3878c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(tmr2x_en, MOC, TMR2X_EN), 3888c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(batfet_disable, MOC, BATFET_DISABLE), 3898c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RW(jeita_vset, MOC, JEITA_VSET), 3908c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(int_mask, MOC, INT_MASK), 3918c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(vbus_stat, SS, VBUS_STAT), 3928c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(chrg_stat, SS, CHRG_STAT), 3938c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(dpm_stat, SS, DPM_STAT), 3948c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(pg_stat, SS, PG_STAT), 3958c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(therm_stat, SS, THERM_STAT), 3968c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(vsys_stat, SS, VSYS_STAT), 3978c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(watchdog_fault, F, WATCHDOG_FAULT), 3988c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(boost_fault, F, BOOST_FAULT), 3998c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(chrg_fault, F, CHRG_FAULT), 4008c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(bat_fault, F, BAT_FAULT), 4018c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(ntc_fault, F, NTC_FAULT), 4028c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(pn, VPRS, PN), 4038c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(ts_profile, VPRS, TS_PROFILE), 4048c2ecf20Sopenharmony_ci BQ24190_SYSFS_FIELD_RO(dev_reg, VPRS, DEV_REG), 4058c2ecf20Sopenharmony_ci}; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic struct attribute * 4088c2ecf20Sopenharmony_ci bq24190_sysfs_attrs[ARRAY_SIZE(bq24190_sysfs_field_tbl) + 1]; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(bq24190_sysfs); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic void bq24190_sysfs_init_attrs(void) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci for (i = 0; i < limit; i++) 4178c2ecf20Sopenharmony_ci bq24190_sysfs_attrs[i] = &bq24190_sysfs_field_tbl[i].attr.attr; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci bq24190_sysfs_attrs[limit] = NULL; /* Has additional entry for this */ 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic struct bq24190_sysfs_field_info *bq24190_sysfs_field_lookup( 4238c2ecf20Sopenharmony_ci const char *name) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci for (i = 0; i < limit; i++) 4288c2ecf20Sopenharmony_ci if (!strcmp(name, bq24190_sysfs_field_tbl[i].attr.attr.name)) 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (i >= limit) 4328c2ecf20Sopenharmony_ci return NULL; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return &bq24190_sysfs_field_tbl[i]; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic ssize_t bq24190_sysfs_show(struct device *dev, 4388c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct power_supply *psy = dev_get_drvdata(dev); 4418c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); 4428c2ecf20Sopenharmony_ci struct bq24190_sysfs_field_info *info; 4438c2ecf20Sopenharmony_ci ssize_t count; 4448c2ecf20Sopenharmony_ci int ret; 4458c2ecf20Sopenharmony_ci u8 v; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci info = bq24190_sysfs_field_lookup(attr->attr.name); 4488c2ecf20Sopenharmony_ci if (!info) 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(bdi->dev); 4528c2ecf20Sopenharmony_ci if (ret < 0) 4538c2ecf20Sopenharmony_ci return ret; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v); 4568c2ecf20Sopenharmony_ci if (ret) 4578c2ecf20Sopenharmony_ci count = ret; 4588c2ecf20Sopenharmony_ci else 4598c2ecf20Sopenharmony_ci count = scnprintf(buf, PAGE_SIZE, "%hhx\n", v); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 4628c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return count; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic ssize_t bq24190_sysfs_store(struct device *dev, 4688c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct power_supply *psy = dev_get_drvdata(dev); 4718c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); 4728c2ecf20Sopenharmony_ci struct bq24190_sysfs_field_info *info; 4738c2ecf20Sopenharmony_ci int ret; 4748c2ecf20Sopenharmony_ci u8 v; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci info = bq24190_sysfs_field_lookup(attr->attr.name); 4778c2ecf20Sopenharmony_ci if (!info) 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci ret = kstrtou8(buf, 0, &v); 4818c2ecf20Sopenharmony_ci if (ret < 0) 4828c2ecf20Sopenharmony_ci return ret; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(bdi->dev); 4858c2ecf20Sopenharmony_ci if (ret < 0) 4868c2ecf20Sopenharmony_ci return ret; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v); 4898c2ecf20Sopenharmony_ci if (ret) 4908c2ecf20Sopenharmony_ci count = ret; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 4938c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return count; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci#endif 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci#ifdef CONFIG_REGULATOR 5008c2ecf20Sopenharmony_cistatic int bq24190_set_charge_mode(struct regulator_dev *dev, u8 val) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = rdev_get_drvdata(dev); 5038c2ecf20Sopenharmony_ci int ret; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(bdi->dev); 5068c2ecf20Sopenharmony_ci if (ret < 0) { 5078c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", ret); 5088c2ecf20Sopenharmony_ci return ret; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci ret = bq24190_write_mask(bdi, BQ24190_REG_POC, 5128c2ecf20Sopenharmony_ci BQ24190_REG_POC_CHG_CONFIG_MASK, 5138c2ecf20Sopenharmony_ci BQ24190_REG_POC_CHG_CONFIG_SHIFT, val); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 5168c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return ret; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int bq24190_vbus_enable(struct regulator_dev *dev) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci return bq24190_set_charge_mode(dev, BQ24190_REG_POC_CHG_CONFIG_OTG); 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int bq24190_vbus_disable(struct regulator_dev *dev) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci return bq24190_set_charge_mode(dev, BQ24190_REG_POC_CHG_CONFIG_CHARGE); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int bq24190_vbus_is_enabled(struct regulator_dev *dev) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = rdev_get_drvdata(dev); 5348c2ecf20Sopenharmony_ci int ret; 5358c2ecf20Sopenharmony_ci u8 val; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(bdi->dev); 5388c2ecf20Sopenharmony_ci if (ret < 0) { 5398c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", ret); 5408c2ecf20Sopenharmony_ci return ret; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_POC, 5448c2ecf20Sopenharmony_ci BQ24190_REG_POC_CHG_CONFIG_MASK, 5458c2ecf20Sopenharmony_ci BQ24190_REG_POC_CHG_CONFIG_SHIFT, &val); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 5488c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (ret) 5518c2ecf20Sopenharmony_ci return ret; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return (val == BQ24190_REG_POC_CHG_CONFIG_OTG || 5548c2ecf20Sopenharmony_ci val == BQ24190_REG_POC_CHG_CONFIG_OTG_ALT); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic const struct regulator_ops bq24190_vbus_ops = { 5588c2ecf20Sopenharmony_ci .enable = bq24190_vbus_enable, 5598c2ecf20Sopenharmony_ci .disable = bq24190_vbus_disable, 5608c2ecf20Sopenharmony_ci .is_enabled = bq24190_vbus_is_enabled, 5618c2ecf20Sopenharmony_ci}; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic const struct regulator_desc bq24190_vbus_desc = { 5648c2ecf20Sopenharmony_ci .name = "usb_otg_vbus", 5658c2ecf20Sopenharmony_ci .of_match = "usb-otg-vbus", 5668c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 5678c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 5688c2ecf20Sopenharmony_ci .ops = &bq24190_vbus_ops, 5698c2ecf20Sopenharmony_ci .fixed_uV = 5000000, 5708c2ecf20Sopenharmony_ci .n_voltages = 1, 5718c2ecf20Sopenharmony_ci}; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic const struct regulator_init_data bq24190_vbus_init_data = { 5748c2ecf20Sopenharmony_ci .constraints = { 5758c2ecf20Sopenharmony_ci .valid_ops_mask = REGULATOR_CHANGE_STATUS, 5768c2ecf20Sopenharmony_ci }, 5778c2ecf20Sopenharmony_ci}; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic int bq24190_register_vbus_regulator(struct bq24190_dev_info *bdi) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct bq24190_platform_data *pdata = bdi->dev->platform_data; 5828c2ecf20Sopenharmony_ci struct regulator_config cfg = { }; 5838c2ecf20Sopenharmony_ci struct regulator_dev *reg; 5848c2ecf20Sopenharmony_ci int ret = 0; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci cfg.dev = bdi->dev; 5878c2ecf20Sopenharmony_ci if (pdata && pdata->regulator_init_data) 5888c2ecf20Sopenharmony_ci cfg.init_data = pdata->regulator_init_data; 5898c2ecf20Sopenharmony_ci else 5908c2ecf20Sopenharmony_ci cfg.init_data = &bq24190_vbus_init_data; 5918c2ecf20Sopenharmony_ci cfg.driver_data = bdi; 5928c2ecf20Sopenharmony_ci reg = devm_regulator_register(bdi->dev, &bq24190_vbus_desc, &cfg); 5938c2ecf20Sopenharmony_ci if (IS_ERR(reg)) { 5948c2ecf20Sopenharmony_ci ret = PTR_ERR(reg); 5958c2ecf20Sopenharmony_ci dev_err(bdi->dev, "Can't register regulator: %d\n", ret); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return ret; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci#else 6018c2ecf20Sopenharmony_cistatic int bq24190_register_vbus_regulator(struct bq24190_dev_info *bdi) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci#endif 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int bq24190_set_config(struct bq24190_dev_info *bdi) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci int ret; 6108c2ecf20Sopenharmony_ci u8 v; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci ret = bq24190_read(bdi, BQ24190_REG_CTTC, &v); 6138c2ecf20Sopenharmony_ci if (ret < 0) 6148c2ecf20Sopenharmony_ci return ret; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci bdi->watchdog = ((v & BQ24190_REG_CTTC_WATCHDOG_MASK) >> 6178c2ecf20Sopenharmony_ci BQ24190_REG_CTTC_WATCHDOG_SHIFT); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* 6208c2ecf20Sopenharmony_ci * According to the "Host Mode and default Mode" section of the 6218c2ecf20Sopenharmony_ci * manual, a write to any register causes the bq24190 to switch 6228c2ecf20Sopenharmony_ci * from default mode to host mode. It will switch back to default 6238c2ecf20Sopenharmony_ci * mode after a WDT timeout unless the WDT is turned off as well. 6248c2ecf20Sopenharmony_ci * So, by simply turning off the WDT, we accomplish both with the 6258c2ecf20Sopenharmony_ci * same write. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci v &= ~BQ24190_REG_CTTC_WATCHDOG_MASK; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci ret = bq24190_write(bdi, BQ24190_REG_CTTC, v); 6308c2ecf20Sopenharmony_ci if (ret < 0) 6318c2ecf20Sopenharmony_ci return ret; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (bdi->sys_min) { 6348c2ecf20Sopenharmony_ci v = bdi->sys_min / 100 - 30; // manual section 9.5.1.2, table 9 6358c2ecf20Sopenharmony_ci ret = bq24190_write_mask(bdi, BQ24190_REG_POC, 6368c2ecf20Sopenharmony_ci BQ24190_REG_POC_SYS_MIN_MASK, 6378c2ecf20Sopenharmony_ci BQ24190_REG_POC_SYS_MIN_SHIFT, 6388c2ecf20Sopenharmony_ci v); 6398c2ecf20Sopenharmony_ci if (ret < 0) 6408c2ecf20Sopenharmony_ci return ret; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (bdi->iprechg) { 6448c2ecf20Sopenharmony_ci v = bdi->iprechg / 128 - 1; // manual section 9.5.1.4, table 11 6458c2ecf20Sopenharmony_ci ret = bq24190_write_mask(bdi, BQ24190_REG_PCTCC, 6468c2ecf20Sopenharmony_ci BQ24190_REG_PCTCC_IPRECHG_MASK, 6478c2ecf20Sopenharmony_ci BQ24190_REG_PCTCC_IPRECHG_SHIFT, 6488c2ecf20Sopenharmony_ci v); 6498c2ecf20Sopenharmony_ci if (ret < 0) 6508c2ecf20Sopenharmony_ci return ret; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (bdi->iterm) { 6548c2ecf20Sopenharmony_ci v = bdi->iterm / 128 - 1; // manual section 9.5.1.4, table 11 6558c2ecf20Sopenharmony_ci ret = bq24190_write_mask(bdi, BQ24190_REG_PCTCC, 6568c2ecf20Sopenharmony_ci BQ24190_REG_PCTCC_ITERM_MASK, 6578c2ecf20Sopenharmony_ci BQ24190_REG_PCTCC_ITERM_SHIFT, 6588c2ecf20Sopenharmony_ci v); 6598c2ecf20Sopenharmony_ci if (ret < 0) 6608c2ecf20Sopenharmony_ci return ret; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci return 0; 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic int bq24190_register_reset(struct bq24190_dev_info *bdi) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci int ret, limit = 100; 6698c2ecf20Sopenharmony_ci u8 v; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* 6728c2ecf20Sopenharmony_ci * This prop. can be passed on device instantiation from platform code: 6738c2ecf20Sopenharmony_ci * struct property_entry pe[] = 6748c2ecf20Sopenharmony_ci * { PROPERTY_ENTRY_BOOL("disable-reset"), ... }; 6758c2ecf20Sopenharmony_ci * struct i2c_board_info bi = 6768c2ecf20Sopenharmony_ci * { .type = "bq24190", .addr = 0x6b, .properties = pe, .irq = irq }; 6778c2ecf20Sopenharmony_ci * struct i2c_adapter ad = { ... }; 6788c2ecf20Sopenharmony_ci * i2c_add_adapter(&ad); 6798c2ecf20Sopenharmony_ci * i2c_new_client_device(&ad, &bi); 6808c2ecf20Sopenharmony_ci */ 6818c2ecf20Sopenharmony_ci if (device_property_read_bool(bdi->dev, "disable-reset")) 6828c2ecf20Sopenharmony_ci return 0; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* Reset the registers */ 6858c2ecf20Sopenharmony_ci ret = bq24190_write_mask(bdi, BQ24190_REG_POC, 6868c2ecf20Sopenharmony_ci BQ24190_REG_POC_RESET_MASK, 6878c2ecf20Sopenharmony_ci BQ24190_REG_POC_RESET_SHIFT, 6888c2ecf20Sopenharmony_ci 0x1); 6898c2ecf20Sopenharmony_ci if (ret < 0) 6908c2ecf20Sopenharmony_ci return ret; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* Reset bit will be cleared by hardware so poll until it is */ 6938c2ecf20Sopenharmony_ci do { 6948c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_POC, 6958c2ecf20Sopenharmony_ci BQ24190_REG_POC_RESET_MASK, 6968c2ecf20Sopenharmony_ci BQ24190_REG_POC_RESET_SHIFT, 6978c2ecf20Sopenharmony_ci &v); 6988c2ecf20Sopenharmony_ci if (ret < 0) 6998c2ecf20Sopenharmony_ci return ret; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (v == 0) 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci usleep_range(100, 200); 7058c2ecf20Sopenharmony_ci } while (--limit); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci return -EIO; 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci/* Charger power supply property routines */ 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic int bq24190_charger_get_charge_type(struct bq24190_dev_info *bdi, 7138c2ecf20Sopenharmony_ci union power_supply_propval *val) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci u8 v; 7168c2ecf20Sopenharmony_ci int type, ret; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_POC, 7198c2ecf20Sopenharmony_ci BQ24190_REG_POC_CHG_CONFIG_MASK, 7208c2ecf20Sopenharmony_ci BQ24190_REG_POC_CHG_CONFIG_SHIFT, 7218c2ecf20Sopenharmony_ci &v); 7228c2ecf20Sopenharmony_ci if (ret < 0) 7238c2ecf20Sopenharmony_ci return ret; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* If POC[CHG_CONFIG] (REG01[5:4]) == 0, charge is disabled */ 7268c2ecf20Sopenharmony_ci if (!v) { 7278c2ecf20Sopenharmony_ci type = POWER_SUPPLY_CHARGE_TYPE_NONE; 7288c2ecf20Sopenharmony_ci } else { 7298c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_CCC, 7308c2ecf20Sopenharmony_ci BQ24190_REG_CCC_FORCE_20PCT_MASK, 7318c2ecf20Sopenharmony_ci BQ24190_REG_CCC_FORCE_20PCT_SHIFT, 7328c2ecf20Sopenharmony_ci &v); 7338c2ecf20Sopenharmony_ci if (ret < 0) 7348c2ecf20Sopenharmony_ci return ret; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci type = (v) ? POWER_SUPPLY_CHARGE_TYPE_TRICKLE : 7378c2ecf20Sopenharmony_ci POWER_SUPPLY_CHARGE_TYPE_FAST; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci val->intval = type; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci return 0; 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic int bq24190_charger_set_charge_type(struct bq24190_dev_info *bdi, 7468c2ecf20Sopenharmony_ci const union power_supply_propval *val) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci u8 chg_config, force_20pct, en_term; 7498c2ecf20Sopenharmony_ci int ret; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* 7528c2ecf20Sopenharmony_ci * According to the "Termination when REG02[0] = 1" section of 7538c2ecf20Sopenharmony_ci * the bq24190 manual, the trickle charge could be less than the 7548c2ecf20Sopenharmony_ci * termination current so it recommends turning off the termination 7558c2ecf20Sopenharmony_ci * function. 7568c2ecf20Sopenharmony_ci * 7578c2ecf20Sopenharmony_ci * Note: AFAICT from the datasheet, the user will have to manually 7588c2ecf20Sopenharmony_ci * turn off the charging when in 20% mode. If its not turned off, 7598c2ecf20Sopenharmony_ci * there could be battery damage. So, use this mode at your own risk. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci switch (val->intval) { 7628c2ecf20Sopenharmony_ci case POWER_SUPPLY_CHARGE_TYPE_NONE: 7638c2ecf20Sopenharmony_ci chg_config = 0x0; 7648c2ecf20Sopenharmony_ci break; 7658c2ecf20Sopenharmony_ci case POWER_SUPPLY_CHARGE_TYPE_TRICKLE: 7668c2ecf20Sopenharmony_ci chg_config = 0x1; 7678c2ecf20Sopenharmony_ci force_20pct = 0x1; 7688c2ecf20Sopenharmony_ci en_term = 0x0; 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci case POWER_SUPPLY_CHARGE_TYPE_FAST: 7718c2ecf20Sopenharmony_ci chg_config = 0x1; 7728c2ecf20Sopenharmony_ci force_20pct = 0x0; 7738c2ecf20Sopenharmony_ci en_term = 0x1; 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci default: 7768c2ecf20Sopenharmony_ci return -EINVAL; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (chg_config) { /* Enabling the charger */ 7808c2ecf20Sopenharmony_ci ret = bq24190_write_mask(bdi, BQ24190_REG_CCC, 7818c2ecf20Sopenharmony_ci BQ24190_REG_CCC_FORCE_20PCT_MASK, 7828c2ecf20Sopenharmony_ci BQ24190_REG_CCC_FORCE_20PCT_SHIFT, 7838c2ecf20Sopenharmony_ci force_20pct); 7848c2ecf20Sopenharmony_ci if (ret < 0) 7858c2ecf20Sopenharmony_ci return ret; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci ret = bq24190_write_mask(bdi, BQ24190_REG_CTTC, 7888c2ecf20Sopenharmony_ci BQ24190_REG_CTTC_EN_TERM_MASK, 7898c2ecf20Sopenharmony_ci BQ24190_REG_CTTC_EN_TERM_SHIFT, 7908c2ecf20Sopenharmony_ci en_term); 7918c2ecf20Sopenharmony_ci if (ret < 0) 7928c2ecf20Sopenharmony_ci return ret; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return bq24190_write_mask(bdi, BQ24190_REG_POC, 7968c2ecf20Sopenharmony_ci BQ24190_REG_POC_CHG_CONFIG_MASK, 7978c2ecf20Sopenharmony_ci BQ24190_REG_POC_CHG_CONFIG_SHIFT, chg_config); 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic int bq24190_charger_get_health(struct bq24190_dev_info *bdi, 8018c2ecf20Sopenharmony_ci union power_supply_propval *val) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci u8 v; 8048c2ecf20Sopenharmony_ci int health; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci mutex_lock(&bdi->f_reg_lock); 8078c2ecf20Sopenharmony_ci v = bdi->f_reg; 8088c2ecf20Sopenharmony_ci mutex_unlock(&bdi->f_reg_lock); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (v & BQ24190_REG_F_NTC_FAULT_MASK) { 8118c2ecf20Sopenharmony_ci switch (v >> BQ24190_REG_F_NTC_FAULT_SHIFT & 0x7) { 8128c2ecf20Sopenharmony_ci case 0x1: /* TS1 Cold */ 8138c2ecf20Sopenharmony_ci case 0x3: /* TS2 Cold */ 8148c2ecf20Sopenharmony_ci case 0x5: /* Both Cold */ 8158c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_COLD; 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci case 0x2: /* TS1 Hot */ 8188c2ecf20Sopenharmony_ci case 0x4: /* TS2 Hot */ 8198c2ecf20Sopenharmony_ci case 0x6: /* Both Hot */ 8208c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_OVERHEAT; 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci default: 8238c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_UNKNOWN; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci } else if (v & BQ24190_REG_F_BAT_FAULT_MASK) { 8268c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 8278c2ecf20Sopenharmony_ci } else if (v & BQ24190_REG_F_CHRG_FAULT_MASK) { 8288c2ecf20Sopenharmony_ci switch (v >> BQ24190_REG_F_CHRG_FAULT_SHIFT & 0x3) { 8298c2ecf20Sopenharmony_ci case 0x1: /* Input Fault (VBUS OVP or VBAT<VBUS<3.8V) */ 8308c2ecf20Sopenharmony_ci /* 8318c2ecf20Sopenharmony_ci * This could be over-voltage or under-voltage 8328c2ecf20Sopenharmony_ci * and there's no way to tell which. Instead 8338c2ecf20Sopenharmony_ci * of looking foolish and returning 'OVERVOLTAGE' 8348c2ecf20Sopenharmony_ci * when its really under-voltage, just return 8358c2ecf20Sopenharmony_ci * 'UNSPEC_FAILURE'. 8368c2ecf20Sopenharmony_ci */ 8378c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 8388c2ecf20Sopenharmony_ci break; 8398c2ecf20Sopenharmony_ci case 0x2: /* Thermal Shutdown */ 8408c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_OVERHEAT; 8418c2ecf20Sopenharmony_ci break; 8428c2ecf20Sopenharmony_ci case 0x3: /* Charge Safety Timer Expiration */ 8438c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci default: /* prevent compiler warning */ 8468c2ecf20Sopenharmony_ci health = -1; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci } else if (v & BQ24190_REG_F_BOOST_FAULT_MASK) { 8498c2ecf20Sopenharmony_ci /* 8508c2ecf20Sopenharmony_ci * This could be over-current or over-voltage but there's 8518c2ecf20Sopenharmony_ci * no way to tell which. Return 'OVERVOLTAGE' since there 8528c2ecf20Sopenharmony_ci * isn't an 'OVERCURRENT' value defined that we can return 8538c2ecf20Sopenharmony_ci * even if it was over-current. 8548c2ecf20Sopenharmony_ci */ 8558c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 8568c2ecf20Sopenharmony_ci } else { 8578c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_GOOD; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci val->intval = health; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci return 0; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int bq24190_charger_get_online(struct bq24190_dev_info *bdi, 8668c2ecf20Sopenharmony_ci union power_supply_propval *val) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci u8 pg_stat, batfet_disable; 8698c2ecf20Sopenharmony_ci int ret; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_SS, 8728c2ecf20Sopenharmony_ci BQ24190_REG_SS_PG_STAT_MASK, 8738c2ecf20Sopenharmony_ci BQ24190_REG_SS_PG_STAT_SHIFT, &pg_stat); 8748c2ecf20Sopenharmony_ci if (ret < 0) 8758c2ecf20Sopenharmony_ci return ret; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_MOC, 8788c2ecf20Sopenharmony_ci BQ24190_REG_MOC_BATFET_DISABLE_MASK, 8798c2ecf20Sopenharmony_ci BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable); 8808c2ecf20Sopenharmony_ci if (ret < 0) 8818c2ecf20Sopenharmony_ci return ret; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci val->intval = pg_stat && !batfet_disable; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci return 0; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic int bq24190_battery_set_online(struct bq24190_dev_info *bdi, 8898c2ecf20Sopenharmony_ci const union power_supply_propval *val); 8908c2ecf20Sopenharmony_cistatic int bq24190_battery_get_status(struct bq24190_dev_info *bdi, 8918c2ecf20Sopenharmony_ci union power_supply_propval *val); 8928c2ecf20Sopenharmony_cistatic int bq24190_battery_get_temp_alert_max(struct bq24190_dev_info *bdi, 8938c2ecf20Sopenharmony_ci union power_supply_propval *val); 8948c2ecf20Sopenharmony_cistatic int bq24190_battery_set_temp_alert_max(struct bq24190_dev_info *bdi, 8958c2ecf20Sopenharmony_ci const union power_supply_propval *val); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int bq24190_charger_set_online(struct bq24190_dev_info *bdi, 8988c2ecf20Sopenharmony_ci const union power_supply_propval *val) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci return bq24190_battery_set_online(bdi, val); 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic int bq24190_charger_get_status(struct bq24190_dev_info *bdi, 9048c2ecf20Sopenharmony_ci union power_supply_propval *val) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci return bq24190_battery_get_status(bdi, val); 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic int bq24190_charger_get_temp_alert_max(struct bq24190_dev_info *bdi, 9108c2ecf20Sopenharmony_ci union power_supply_propval *val) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci return bq24190_battery_get_temp_alert_max(bdi, val); 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_cistatic int bq24190_charger_set_temp_alert_max(struct bq24190_dev_info *bdi, 9168c2ecf20Sopenharmony_ci const union power_supply_propval *val) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci return bq24190_battery_set_temp_alert_max(bdi, val); 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic int bq24190_charger_get_precharge(struct bq24190_dev_info *bdi, 9228c2ecf20Sopenharmony_ci union power_supply_propval *val) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci u8 v; 9258c2ecf20Sopenharmony_ci int ret; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_PCTCC, 9288c2ecf20Sopenharmony_ci BQ24190_REG_PCTCC_IPRECHG_MASK, 9298c2ecf20Sopenharmony_ci BQ24190_REG_PCTCC_IPRECHG_SHIFT, &v); 9308c2ecf20Sopenharmony_ci if (ret < 0) 9318c2ecf20Sopenharmony_ci return ret; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci val->intval = ++v * 128 * 1000; 9348c2ecf20Sopenharmony_ci return 0; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic int bq24190_charger_get_charge_term(struct bq24190_dev_info *bdi, 9388c2ecf20Sopenharmony_ci union power_supply_propval *val) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci u8 v; 9418c2ecf20Sopenharmony_ci int ret; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_PCTCC, 9448c2ecf20Sopenharmony_ci BQ24190_REG_PCTCC_ITERM_MASK, 9458c2ecf20Sopenharmony_ci BQ24190_REG_PCTCC_ITERM_SHIFT, &v); 9468c2ecf20Sopenharmony_ci if (ret < 0) 9478c2ecf20Sopenharmony_ci return ret; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci val->intval = ++v * 128 * 1000; 9508c2ecf20Sopenharmony_ci return 0; 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic int bq24190_charger_get_current(struct bq24190_dev_info *bdi, 9548c2ecf20Sopenharmony_ci union power_supply_propval *val) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci u8 v; 9578c2ecf20Sopenharmony_ci int curr, ret; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci ret = bq24190_get_field_val(bdi, BQ24190_REG_CCC, 9608c2ecf20Sopenharmony_ci BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT, 9618c2ecf20Sopenharmony_ci bq24190_ccc_ichg_values, 9628c2ecf20Sopenharmony_ci ARRAY_SIZE(bq24190_ccc_ichg_values), &curr); 9638c2ecf20Sopenharmony_ci if (ret < 0) 9648c2ecf20Sopenharmony_ci return ret; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_CCC, 9678c2ecf20Sopenharmony_ci BQ24190_REG_CCC_FORCE_20PCT_MASK, 9688c2ecf20Sopenharmony_ci BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v); 9698c2ecf20Sopenharmony_ci if (ret < 0) 9708c2ecf20Sopenharmony_ci return ret; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* If FORCE_20PCT is enabled, then current is 20% of ICHG value */ 9738c2ecf20Sopenharmony_ci if (v) 9748c2ecf20Sopenharmony_ci curr /= 5; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci val->intval = curr; 9778c2ecf20Sopenharmony_ci return 0; 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic int bq24190_charger_get_current_max(struct bq24190_dev_info *bdi, 9818c2ecf20Sopenharmony_ci union power_supply_propval *val) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci int idx = ARRAY_SIZE(bq24190_ccc_ichg_values) - 1; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci val->intval = bq24190_ccc_ichg_values[idx]; 9868c2ecf20Sopenharmony_ci return 0; 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic int bq24190_charger_set_current(struct bq24190_dev_info *bdi, 9908c2ecf20Sopenharmony_ci const union power_supply_propval *val) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci u8 v; 9938c2ecf20Sopenharmony_ci int ret, curr = val->intval; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_CCC, 9968c2ecf20Sopenharmony_ci BQ24190_REG_CCC_FORCE_20PCT_MASK, 9978c2ecf20Sopenharmony_ci BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v); 9988c2ecf20Sopenharmony_ci if (ret < 0) 9998c2ecf20Sopenharmony_ci return ret; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* If FORCE_20PCT is enabled, have to multiply value passed in by 5 */ 10028c2ecf20Sopenharmony_ci if (v) 10038c2ecf20Sopenharmony_ci curr *= 5; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci return bq24190_set_field_val(bdi, BQ24190_REG_CCC, 10068c2ecf20Sopenharmony_ci BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT, 10078c2ecf20Sopenharmony_ci bq24190_ccc_ichg_values, 10088c2ecf20Sopenharmony_ci ARRAY_SIZE(bq24190_ccc_ichg_values), curr); 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic int bq24190_charger_get_voltage(struct bq24190_dev_info *bdi, 10128c2ecf20Sopenharmony_ci union power_supply_propval *val) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci int voltage, ret; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci ret = bq24190_get_field_val(bdi, BQ24190_REG_CVC, 10178c2ecf20Sopenharmony_ci BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT, 10188c2ecf20Sopenharmony_ci bq24190_cvc_vreg_values, 10198c2ecf20Sopenharmony_ci ARRAY_SIZE(bq24190_cvc_vreg_values), &voltage); 10208c2ecf20Sopenharmony_ci if (ret < 0) 10218c2ecf20Sopenharmony_ci return ret; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci val->intval = voltage; 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic int bq24190_charger_get_voltage_max(struct bq24190_dev_info *bdi, 10288c2ecf20Sopenharmony_ci union power_supply_propval *val) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci int idx = ARRAY_SIZE(bq24190_cvc_vreg_values) - 1; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci val->intval = bq24190_cvc_vreg_values[idx]; 10338c2ecf20Sopenharmony_ci return 0; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_cistatic int bq24190_charger_set_voltage(struct bq24190_dev_info *bdi, 10378c2ecf20Sopenharmony_ci const union power_supply_propval *val) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci return bq24190_set_field_val(bdi, BQ24190_REG_CVC, 10408c2ecf20Sopenharmony_ci BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT, 10418c2ecf20Sopenharmony_ci bq24190_cvc_vreg_values, 10428c2ecf20Sopenharmony_ci ARRAY_SIZE(bq24190_cvc_vreg_values), val->intval); 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic int bq24190_charger_get_iinlimit(struct bq24190_dev_info *bdi, 10468c2ecf20Sopenharmony_ci union power_supply_propval *val) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci int iinlimit, ret; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci ret = bq24190_get_field_val(bdi, BQ24190_REG_ISC, 10518c2ecf20Sopenharmony_ci BQ24190_REG_ISC_IINLIM_MASK, 10528c2ecf20Sopenharmony_ci BQ24190_REG_ISC_IINLIM_SHIFT, 10538c2ecf20Sopenharmony_ci bq24190_isc_iinlim_values, 10548c2ecf20Sopenharmony_ci ARRAY_SIZE(bq24190_isc_iinlim_values), &iinlimit); 10558c2ecf20Sopenharmony_ci if (ret < 0) 10568c2ecf20Sopenharmony_ci return ret; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci val->intval = iinlimit; 10598c2ecf20Sopenharmony_ci return 0; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic int bq24190_charger_set_iinlimit(struct bq24190_dev_info *bdi, 10638c2ecf20Sopenharmony_ci const union power_supply_propval *val) 10648c2ecf20Sopenharmony_ci{ 10658c2ecf20Sopenharmony_ci return bq24190_set_field_val(bdi, BQ24190_REG_ISC, 10668c2ecf20Sopenharmony_ci BQ24190_REG_ISC_IINLIM_MASK, 10678c2ecf20Sopenharmony_ci BQ24190_REG_ISC_IINLIM_SHIFT, 10688c2ecf20Sopenharmony_ci bq24190_isc_iinlim_values, 10698c2ecf20Sopenharmony_ci ARRAY_SIZE(bq24190_isc_iinlim_values), val->intval); 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic int bq24190_charger_get_property(struct power_supply *psy, 10738c2ecf20Sopenharmony_ci enum power_supply_property psp, union power_supply_propval *val) 10748c2ecf20Sopenharmony_ci{ 10758c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); 10768c2ecf20Sopenharmony_ci int ret; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci dev_dbg(bdi->dev, "prop: %d\n", psp); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(bdi->dev); 10818c2ecf20Sopenharmony_ci if (ret < 0) 10828c2ecf20Sopenharmony_ci return ret; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci switch (psp) { 10858c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TYPE: 10868c2ecf20Sopenharmony_ci ret = bq24190_charger_get_charge_type(bdi, val); 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_HEALTH: 10898c2ecf20Sopenharmony_ci ret = bq24190_charger_get_health(bdi, val); 10908c2ecf20Sopenharmony_ci break; 10918c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 10928c2ecf20Sopenharmony_ci ret = bq24190_charger_get_online(bdi, val); 10938c2ecf20Sopenharmony_ci break; 10948c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 10958c2ecf20Sopenharmony_ci ret = bq24190_charger_get_status(bdi, val); 10968c2ecf20Sopenharmony_ci break; 10978c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 10988c2ecf20Sopenharmony_ci ret = bq24190_charger_get_temp_alert_max(bdi, val); 10998c2ecf20Sopenharmony_ci break; 11008c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 11018c2ecf20Sopenharmony_ci ret = bq24190_charger_get_precharge(bdi, val); 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 11048c2ecf20Sopenharmony_ci ret = bq24190_charger_get_charge_term(bdi, val); 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 11078c2ecf20Sopenharmony_ci ret = bq24190_charger_get_current(bdi, val); 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 11108c2ecf20Sopenharmony_ci ret = bq24190_charger_get_current_max(bdi, val); 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 11138c2ecf20Sopenharmony_ci ret = bq24190_charger_get_voltage(bdi, val); 11148c2ecf20Sopenharmony_ci break; 11158c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 11168c2ecf20Sopenharmony_ci ret = bq24190_charger_get_voltage_max(bdi, val); 11178c2ecf20Sopenharmony_ci break; 11188c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 11198c2ecf20Sopenharmony_ci ret = bq24190_charger_get_iinlimit(bdi, val); 11208c2ecf20Sopenharmony_ci break; 11218c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_SCOPE: 11228c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_SCOPE_SYSTEM; 11238c2ecf20Sopenharmony_ci ret = 0; 11248c2ecf20Sopenharmony_ci break; 11258c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_MODEL_NAME: 11268c2ecf20Sopenharmony_ci val->strval = bdi->model_name; 11278c2ecf20Sopenharmony_ci ret = 0; 11288c2ecf20Sopenharmony_ci break; 11298c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_MANUFACTURER: 11308c2ecf20Sopenharmony_ci val->strval = BQ24190_MANUFACTURER; 11318c2ecf20Sopenharmony_ci ret = 0; 11328c2ecf20Sopenharmony_ci break; 11338c2ecf20Sopenharmony_ci default: 11348c2ecf20Sopenharmony_ci ret = -ENODATA; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 11388c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci return ret; 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic int bq24190_charger_set_property(struct power_supply *psy, 11448c2ecf20Sopenharmony_ci enum power_supply_property psp, 11458c2ecf20Sopenharmony_ci const union power_supply_propval *val) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); 11488c2ecf20Sopenharmony_ci int ret; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci dev_dbg(bdi->dev, "prop: %d\n", psp); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(bdi->dev); 11538c2ecf20Sopenharmony_ci if (ret < 0) 11548c2ecf20Sopenharmony_ci return ret; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci switch (psp) { 11578c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 11588c2ecf20Sopenharmony_ci ret = bq24190_charger_set_online(bdi, val); 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 11618c2ecf20Sopenharmony_ci ret = bq24190_charger_set_temp_alert_max(bdi, val); 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TYPE: 11648c2ecf20Sopenharmony_ci ret = bq24190_charger_set_charge_type(bdi, val); 11658c2ecf20Sopenharmony_ci break; 11668c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 11678c2ecf20Sopenharmony_ci ret = bq24190_charger_set_current(bdi, val); 11688c2ecf20Sopenharmony_ci break; 11698c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 11708c2ecf20Sopenharmony_ci ret = bq24190_charger_set_voltage(bdi, val); 11718c2ecf20Sopenharmony_ci break; 11728c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 11738c2ecf20Sopenharmony_ci ret = bq24190_charger_set_iinlimit(bdi, val); 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci default: 11768c2ecf20Sopenharmony_ci ret = -EINVAL; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 11808c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci return ret; 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_cistatic int bq24190_charger_property_is_writeable(struct power_supply *psy, 11868c2ecf20Sopenharmony_ci enum power_supply_property psp) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci switch (psp) { 11898c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 11908c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 11918c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TYPE: 11928c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 11938c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 11948c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 11958c2ecf20Sopenharmony_ci return 1; 11968c2ecf20Sopenharmony_ci default: 11978c2ecf20Sopenharmony_ci return 0; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic void bq24190_input_current_limit_work(struct work_struct *work) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = 12048c2ecf20Sopenharmony_ci container_of(work, struct bq24190_dev_info, 12058c2ecf20Sopenharmony_ci input_current_limit_work.work); 12068c2ecf20Sopenharmony_ci union power_supply_propval val; 12078c2ecf20Sopenharmony_ci int ret; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci ret = power_supply_get_property_from_supplier(bdi->charger, 12108c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CURRENT_MAX, 12118c2ecf20Sopenharmony_ci &val); 12128c2ecf20Sopenharmony_ci if (ret) 12138c2ecf20Sopenharmony_ci return; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci bq24190_charger_set_property(bdi->charger, 12168c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 12178c2ecf20Sopenharmony_ci &val); 12188c2ecf20Sopenharmony_ci power_supply_changed(bdi->charger); 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci/* Sync the input-current-limit with our parent supply (if we have one) */ 12228c2ecf20Sopenharmony_cistatic void bq24190_charger_external_power_changed(struct power_supply *psy) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* 12278c2ecf20Sopenharmony_ci * The Power-Good detection may take up to 220ms, sometimes 12288c2ecf20Sopenharmony_ci * the external charger detection is quicker, and the bq24190 will 12298c2ecf20Sopenharmony_ci * reset to iinlim based on its own charger detection (which is not 12308c2ecf20Sopenharmony_ci * hooked up when using external charger detection) resulting in a 12318c2ecf20Sopenharmony_ci * too low default 500mA iinlim. Delay setting the input-current-limit 12328c2ecf20Sopenharmony_ci * for 300ms to avoid this. 12338c2ecf20Sopenharmony_ci */ 12348c2ecf20Sopenharmony_ci queue_delayed_work(system_wq, &bdi->input_current_limit_work, 12358c2ecf20Sopenharmony_ci msecs_to_jiffies(300)); 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic enum power_supply_property bq24190_charger_properties[] = { 12398c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TYPE, 12408c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_HEALTH, 12418c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_ONLINE, 12428c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 12438c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_TEMP_ALERT_MAX, 12448c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_PRECHARGE_CURRENT, 12458c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 12468c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 12478c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 12488c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 12498c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 12508c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 12518c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_SCOPE, 12528c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_MODEL_NAME, 12538c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_MANUFACTURER, 12548c2ecf20Sopenharmony_ci}; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic char *bq24190_charger_supplied_to[] = { 12578c2ecf20Sopenharmony_ci "main-battery", 12588c2ecf20Sopenharmony_ci}; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic const struct power_supply_desc bq24190_charger_desc = { 12618c2ecf20Sopenharmony_ci .name = "bq24190-charger", 12628c2ecf20Sopenharmony_ci .type = POWER_SUPPLY_TYPE_USB, 12638c2ecf20Sopenharmony_ci .properties = bq24190_charger_properties, 12648c2ecf20Sopenharmony_ci .num_properties = ARRAY_SIZE(bq24190_charger_properties), 12658c2ecf20Sopenharmony_ci .get_property = bq24190_charger_get_property, 12668c2ecf20Sopenharmony_ci .set_property = bq24190_charger_set_property, 12678c2ecf20Sopenharmony_ci .property_is_writeable = bq24190_charger_property_is_writeable, 12688c2ecf20Sopenharmony_ci .external_power_changed = bq24190_charger_external_power_changed, 12698c2ecf20Sopenharmony_ci}; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci/* Battery power supply property routines */ 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic int bq24190_battery_get_status(struct bq24190_dev_info *bdi, 12748c2ecf20Sopenharmony_ci union power_supply_propval *val) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci u8 ss_reg, chrg_fault; 12778c2ecf20Sopenharmony_ci int status, ret; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci mutex_lock(&bdi->f_reg_lock); 12808c2ecf20Sopenharmony_ci chrg_fault = bdi->f_reg; 12818c2ecf20Sopenharmony_ci mutex_unlock(&bdi->f_reg_lock); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK; 12848c2ecf20Sopenharmony_ci chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg); 12878c2ecf20Sopenharmony_ci if (ret < 0) 12888c2ecf20Sopenharmony_ci return ret; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* 12918c2ecf20Sopenharmony_ci * The battery must be discharging when any of these are true: 12928c2ecf20Sopenharmony_ci * - there is no good power source; 12938c2ecf20Sopenharmony_ci * - there is a charge fault. 12948c2ecf20Sopenharmony_ci * Could also be discharging when in "supplement mode" but 12958c2ecf20Sopenharmony_ci * there is no way to tell when its in that mode. 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_ci if (!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK) || chrg_fault) { 12988c2ecf20Sopenharmony_ci status = POWER_SUPPLY_STATUS_DISCHARGING; 12998c2ecf20Sopenharmony_ci } else { 13008c2ecf20Sopenharmony_ci ss_reg &= BQ24190_REG_SS_CHRG_STAT_MASK; 13018c2ecf20Sopenharmony_ci ss_reg >>= BQ24190_REG_SS_CHRG_STAT_SHIFT; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci switch (ss_reg) { 13048c2ecf20Sopenharmony_ci case 0x0: /* Not Charging */ 13058c2ecf20Sopenharmony_ci status = POWER_SUPPLY_STATUS_NOT_CHARGING; 13068c2ecf20Sopenharmony_ci break; 13078c2ecf20Sopenharmony_ci case 0x1: /* Pre-charge */ 13088c2ecf20Sopenharmony_ci case 0x2: /* Fast Charging */ 13098c2ecf20Sopenharmony_ci status = POWER_SUPPLY_STATUS_CHARGING; 13108c2ecf20Sopenharmony_ci break; 13118c2ecf20Sopenharmony_ci case 0x3: /* Charge Termination Done */ 13128c2ecf20Sopenharmony_ci status = POWER_SUPPLY_STATUS_FULL; 13138c2ecf20Sopenharmony_ci break; 13148c2ecf20Sopenharmony_ci default: 13158c2ecf20Sopenharmony_ci ret = -EIO; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (!ret) 13208c2ecf20Sopenharmony_ci val->intval = status; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci return ret; 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic int bq24190_battery_get_health(struct bq24190_dev_info *bdi, 13268c2ecf20Sopenharmony_ci union power_supply_propval *val) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci u8 v; 13298c2ecf20Sopenharmony_ci int health; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci mutex_lock(&bdi->f_reg_lock); 13328c2ecf20Sopenharmony_ci v = bdi->f_reg; 13338c2ecf20Sopenharmony_ci mutex_unlock(&bdi->f_reg_lock); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci if (v & BQ24190_REG_F_BAT_FAULT_MASK) { 13368c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 13378c2ecf20Sopenharmony_ci } else { 13388c2ecf20Sopenharmony_ci v &= BQ24190_REG_F_NTC_FAULT_MASK; 13398c2ecf20Sopenharmony_ci v >>= BQ24190_REG_F_NTC_FAULT_SHIFT; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci switch (v) { 13428c2ecf20Sopenharmony_ci case 0x0: /* Normal */ 13438c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_GOOD; 13448c2ecf20Sopenharmony_ci break; 13458c2ecf20Sopenharmony_ci case 0x1: /* TS1 Cold */ 13468c2ecf20Sopenharmony_ci case 0x3: /* TS2 Cold */ 13478c2ecf20Sopenharmony_ci case 0x5: /* Both Cold */ 13488c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_COLD; 13498c2ecf20Sopenharmony_ci break; 13508c2ecf20Sopenharmony_ci case 0x2: /* TS1 Hot */ 13518c2ecf20Sopenharmony_ci case 0x4: /* TS2 Hot */ 13528c2ecf20Sopenharmony_ci case 0x6: /* Both Hot */ 13538c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_OVERHEAT; 13548c2ecf20Sopenharmony_ci break; 13558c2ecf20Sopenharmony_ci default: 13568c2ecf20Sopenharmony_ci health = POWER_SUPPLY_HEALTH_UNKNOWN; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci val->intval = health; 13618c2ecf20Sopenharmony_ci return 0; 13628c2ecf20Sopenharmony_ci} 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cistatic int bq24190_battery_get_online(struct bq24190_dev_info *bdi, 13658c2ecf20Sopenharmony_ci union power_supply_propval *val) 13668c2ecf20Sopenharmony_ci{ 13678c2ecf20Sopenharmony_ci u8 batfet_disable; 13688c2ecf20Sopenharmony_ci int ret; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_MOC, 13718c2ecf20Sopenharmony_ci BQ24190_REG_MOC_BATFET_DISABLE_MASK, 13728c2ecf20Sopenharmony_ci BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable); 13738c2ecf20Sopenharmony_ci if (ret < 0) 13748c2ecf20Sopenharmony_ci return ret; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci val->intval = !batfet_disable; 13778c2ecf20Sopenharmony_ci return 0; 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic int bq24190_battery_set_online(struct bq24190_dev_info *bdi, 13818c2ecf20Sopenharmony_ci const union power_supply_propval *val) 13828c2ecf20Sopenharmony_ci{ 13838c2ecf20Sopenharmony_ci return bq24190_write_mask(bdi, BQ24190_REG_MOC, 13848c2ecf20Sopenharmony_ci BQ24190_REG_MOC_BATFET_DISABLE_MASK, 13858c2ecf20Sopenharmony_ci BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, !val->intval); 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_cistatic int bq24190_battery_get_temp_alert_max(struct bq24190_dev_info *bdi, 13898c2ecf20Sopenharmony_ci union power_supply_propval *val) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci int temp, ret; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci ret = bq24190_get_field_val(bdi, BQ24190_REG_ICTRC, 13948c2ecf20Sopenharmony_ci BQ24190_REG_ICTRC_TREG_MASK, 13958c2ecf20Sopenharmony_ci BQ24190_REG_ICTRC_TREG_SHIFT, 13968c2ecf20Sopenharmony_ci bq24190_ictrc_treg_values, 13978c2ecf20Sopenharmony_ci ARRAY_SIZE(bq24190_ictrc_treg_values), &temp); 13988c2ecf20Sopenharmony_ci if (ret < 0) 13998c2ecf20Sopenharmony_ci return ret; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci val->intval = temp; 14028c2ecf20Sopenharmony_ci return 0; 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_cistatic int bq24190_battery_set_temp_alert_max(struct bq24190_dev_info *bdi, 14068c2ecf20Sopenharmony_ci const union power_supply_propval *val) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci return bq24190_set_field_val(bdi, BQ24190_REG_ICTRC, 14098c2ecf20Sopenharmony_ci BQ24190_REG_ICTRC_TREG_MASK, 14108c2ecf20Sopenharmony_ci BQ24190_REG_ICTRC_TREG_SHIFT, 14118c2ecf20Sopenharmony_ci bq24190_ictrc_treg_values, 14128c2ecf20Sopenharmony_ci ARRAY_SIZE(bq24190_ictrc_treg_values), val->intval); 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic int bq24190_battery_get_property(struct power_supply *psy, 14168c2ecf20Sopenharmony_ci enum power_supply_property psp, union power_supply_propval *val) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); 14198c2ecf20Sopenharmony_ci int ret; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n"); 14228c2ecf20Sopenharmony_ci dev_dbg(bdi->dev, "prop: %d\n", psp); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(bdi->dev); 14258c2ecf20Sopenharmony_ci if (ret < 0) 14268c2ecf20Sopenharmony_ci return ret; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci switch (psp) { 14298c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 14308c2ecf20Sopenharmony_ci ret = bq24190_battery_get_status(bdi, val); 14318c2ecf20Sopenharmony_ci break; 14328c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_HEALTH: 14338c2ecf20Sopenharmony_ci ret = bq24190_battery_get_health(bdi, val); 14348c2ecf20Sopenharmony_ci break; 14358c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 14368c2ecf20Sopenharmony_ci ret = bq24190_battery_get_online(bdi, val); 14378c2ecf20Sopenharmony_ci break; 14388c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_TECHNOLOGY: 14398c2ecf20Sopenharmony_ci /* Could be Li-on or Li-polymer but no way to tell which */ 14408c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; 14418c2ecf20Sopenharmony_ci ret = 0; 14428c2ecf20Sopenharmony_ci break; 14438c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 14448c2ecf20Sopenharmony_ci ret = bq24190_battery_get_temp_alert_max(bdi, val); 14458c2ecf20Sopenharmony_ci break; 14468c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_SCOPE: 14478c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_SCOPE_SYSTEM; 14488c2ecf20Sopenharmony_ci ret = 0; 14498c2ecf20Sopenharmony_ci break; 14508c2ecf20Sopenharmony_ci default: 14518c2ecf20Sopenharmony_ci ret = -ENODATA; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 14558c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci return ret; 14588c2ecf20Sopenharmony_ci} 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_cistatic int bq24190_battery_set_property(struct power_supply *psy, 14618c2ecf20Sopenharmony_ci enum power_supply_property psp, 14628c2ecf20Sopenharmony_ci const union power_supply_propval *val) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); 14658c2ecf20Sopenharmony_ci int ret; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n"); 14688c2ecf20Sopenharmony_ci dev_dbg(bdi->dev, "prop: %d\n", psp); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(bdi->dev); 14718c2ecf20Sopenharmony_ci if (ret < 0) 14728c2ecf20Sopenharmony_ci return ret; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci switch (psp) { 14758c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 14768c2ecf20Sopenharmony_ci ret = bq24190_battery_set_online(bdi, val); 14778c2ecf20Sopenharmony_ci break; 14788c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 14798c2ecf20Sopenharmony_ci ret = bq24190_battery_set_temp_alert_max(bdi, val); 14808c2ecf20Sopenharmony_ci break; 14818c2ecf20Sopenharmony_ci default: 14828c2ecf20Sopenharmony_ci ret = -EINVAL; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 14868c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci return ret; 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cistatic int bq24190_battery_property_is_writeable(struct power_supply *psy, 14928c2ecf20Sopenharmony_ci enum power_supply_property psp) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci int ret; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci switch (psp) { 14978c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 14988c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 14998c2ecf20Sopenharmony_ci ret = 1; 15008c2ecf20Sopenharmony_ci break; 15018c2ecf20Sopenharmony_ci default: 15028c2ecf20Sopenharmony_ci ret = 0; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci return ret; 15068c2ecf20Sopenharmony_ci} 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_cistatic enum power_supply_property bq24190_battery_properties[] = { 15098c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 15108c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_HEALTH, 15118c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_ONLINE, 15128c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_TECHNOLOGY, 15138c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_TEMP_ALERT_MAX, 15148c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_SCOPE, 15158c2ecf20Sopenharmony_ci}; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_cistatic const struct power_supply_desc bq24190_battery_desc = { 15188c2ecf20Sopenharmony_ci .name = "bq24190-battery", 15198c2ecf20Sopenharmony_ci .type = POWER_SUPPLY_TYPE_BATTERY, 15208c2ecf20Sopenharmony_ci .properties = bq24190_battery_properties, 15218c2ecf20Sopenharmony_ci .num_properties = ARRAY_SIZE(bq24190_battery_properties), 15228c2ecf20Sopenharmony_ci .get_property = bq24190_battery_get_property, 15238c2ecf20Sopenharmony_ci .set_property = bq24190_battery_set_property, 15248c2ecf20Sopenharmony_ci .property_is_writeable = bq24190_battery_property_is_writeable, 15258c2ecf20Sopenharmony_ci}; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_cistatic int bq24190_configure_usb_otg(struct bq24190_dev_info *bdi, u8 ss_reg) 15288c2ecf20Sopenharmony_ci{ 15298c2ecf20Sopenharmony_ci bool otg_enabled; 15308c2ecf20Sopenharmony_ci int ret; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci otg_enabled = !!(ss_reg & BQ24190_REG_SS_VBUS_STAT_MASK); 15338c2ecf20Sopenharmony_ci ret = extcon_set_state_sync(bdi->edev, EXTCON_USB, otg_enabled); 15348c2ecf20Sopenharmony_ci if (ret < 0) 15358c2ecf20Sopenharmony_ci dev_err(bdi->dev, "Can't set extcon state to %d: %d\n", 15368c2ecf20Sopenharmony_ci otg_enabled, ret); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci return ret; 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic void bq24190_check_status(struct bq24190_dev_info *bdi) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci const u8 battery_mask_ss = BQ24190_REG_SS_CHRG_STAT_MASK; 15448c2ecf20Sopenharmony_ci const u8 battery_mask_f = BQ24190_REG_F_BAT_FAULT_MASK 15458c2ecf20Sopenharmony_ci | BQ24190_REG_F_NTC_FAULT_MASK; 15468c2ecf20Sopenharmony_ci bool alert_charger = false, alert_battery = false; 15478c2ecf20Sopenharmony_ci u8 ss_reg = 0, f_reg = 0; 15488c2ecf20Sopenharmony_ci int i, ret; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg); 15518c2ecf20Sopenharmony_ci if (ret < 0) { 15528c2ecf20Sopenharmony_ci dev_err(bdi->dev, "Can't read SS reg: %d\n", ret); 15538c2ecf20Sopenharmony_ci return; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci i = 0; 15578c2ecf20Sopenharmony_ci do { 15588c2ecf20Sopenharmony_ci ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg); 15598c2ecf20Sopenharmony_ci if (ret < 0) { 15608c2ecf20Sopenharmony_ci dev_err(bdi->dev, "Can't read F reg: %d\n", ret); 15618c2ecf20Sopenharmony_ci return; 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci } while (f_reg && ++i < 2); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci /* ignore over/under voltage fault after disconnect */ 15668c2ecf20Sopenharmony_ci if (f_reg == (1 << BQ24190_REG_F_CHRG_FAULT_SHIFT) && 15678c2ecf20Sopenharmony_ci !(ss_reg & BQ24190_REG_SS_PG_STAT_MASK)) 15688c2ecf20Sopenharmony_ci f_reg = 0; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (f_reg != bdi->f_reg) { 15718c2ecf20Sopenharmony_ci dev_warn(bdi->dev, 15728c2ecf20Sopenharmony_ci "Fault: boost %d, charge %d, battery %d, ntc %d\n", 15738c2ecf20Sopenharmony_ci !!(f_reg & BQ24190_REG_F_BOOST_FAULT_MASK), 15748c2ecf20Sopenharmony_ci !!(f_reg & BQ24190_REG_F_CHRG_FAULT_MASK), 15758c2ecf20Sopenharmony_ci !!(f_reg & BQ24190_REG_F_BAT_FAULT_MASK), 15768c2ecf20Sopenharmony_ci !!(f_reg & BQ24190_REG_F_NTC_FAULT_MASK)); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci mutex_lock(&bdi->f_reg_lock); 15798c2ecf20Sopenharmony_ci if ((bdi->f_reg & battery_mask_f) != (f_reg & battery_mask_f)) 15808c2ecf20Sopenharmony_ci alert_battery = true; 15818c2ecf20Sopenharmony_ci if ((bdi->f_reg & ~battery_mask_f) != (f_reg & ~battery_mask_f)) 15828c2ecf20Sopenharmony_ci alert_charger = true; 15838c2ecf20Sopenharmony_ci bdi->f_reg = f_reg; 15848c2ecf20Sopenharmony_ci mutex_unlock(&bdi->f_reg_lock); 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (ss_reg != bdi->ss_reg) { 15888c2ecf20Sopenharmony_ci /* 15898c2ecf20Sopenharmony_ci * The device is in host mode so when PG_STAT goes from 1->0 15908c2ecf20Sopenharmony_ci * (i.e., power removed) HIZ needs to be disabled. 15918c2ecf20Sopenharmony_ci */ 15928c2ecf20Sopenharmony_ci if ((bdi->ss_reg & BQ24190_REG_SS_PG_STAT_MASK) && 15938c2ecf20Sopenharmony_ci !(ss_reg & BQ24190_REG_SS_PG_STAT_MASK)) { 15948c2ecf20Sopenharmony_ci ret = bq24190_write_mask(bdi, BQ24190_REG_ISC, 15958c2ecf20Sopenharmony_ci BQ24190_REG_ISC_EN_HIZ_MASK, 15968c2ecf20Sopenharmony_ci BQ24190_REG_ISC_EN_HIZ_SHIFT, 15978c2ecf20Sopenharmony_ci 0); 15988c2ecf20Sopenharmony_ci if (ret < 0) 15998c2ecf20Sopenharmony_ci dev_err(bdi->dev, "Can't access ISC reg: %d\n", 16008c2ecf20Sopenharmony_ci ret); 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if ((bdi->ss_reg & battery_mask_ss) != (ss_reg & battery_mask_ss)) 16048c2ecf20Sopenharmony_ci alert_battery = true; 16058c2ecf20Sopenharmony_ci if ((bdi->ss_reg & ~battery_mask_ss) != (ss_reg & ~battery_mask_ss)) 16068c2ecf20Sopenharmony_ci alert_charger = true; 16078c2ecf20Sopenharmony_ci bdi->ss_reg = ss_reg; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (alert_charger || alert_battery) { 16118c2ecf20Sopenharmony_ci power_supply_changed(bdi->charger); 16128c2ecf20Sopenharmony_ci bq24190_configure_usb_otg(bdi, ss_reg); 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci if (alert_battery && bdi->battery) 16158c2ecf20Sopenharmony_ci power_supply_changed(bdi->battery); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci dev_dbg(bdi->dev, "ss_reg: 0x%02x, f_reg: 0x%02x\n", ss_reg, f_reg); 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cistatic irqreturn_t bq24190_irq_handler_thread(int irq, void *data) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = data; 16238c2ecf20Sopenharmony_ci int error; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci bdi->irq_event = true; 16268c2ecf20Sopenharmony_ci error = pm_runtime_resume_and_get(bdi->dev); 16278c2ecf20Sopenharmony_ci if (error < 0) { 16288c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error); 16298c2ecf20Sopenharmony_ci return IRQ_NONE; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci bq24190_check_status(bdi); 16328c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 16338c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 16348c2ecf20Sopenharmony_ci bdi->irq_event = false; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci return IRQ_HANDLED; 16378c2ecf20Sopenharmony_ci} 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cistatic int bq24190_hw_init(struct bq24190_dev_info *bdi) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci u8 v; 16428c2ecf20Sopenharmony_ci int ret; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci /* First check that the device really is what its supposed to be */ 16458c2ecf20Sopenharmony_ci ret = bq24190_read_mask(bdi, BQ24190_REG_VPRS, 16468c2ecf20Sopenharmony_ci BQ24190_REG_VPRS_PN_MASK, 16478c2ecf20Sopenharmony_ci BQ24190_REG_VPRS_PN_SHIFT, 16488c2ecf20Sopenharmony_ci &v); 16498c2ecf20Sopenharmony_ci if (ret < 0) 16508c2ecf20Sopenharmony_ci return ret; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci switch (v) { 16538c2ecf20Sopenharmony_ci case BQ24190_REG_VPRS_PN_24190: 16548c2ecf20Sopenharmony_ci case BQ24190_REG_VPRS_PN_24192: 16558c2ecf20Sopenharmony_ci case BQ24190_REG_VPRS_PN_24192I: 16568c2ecf20Sopenharmony_ci break; 16578c2ecf20Sopenharmony_ci default: 16588c2ecf20Sopenharmony_ci dev_err(bdi->dev, "Error unknown model: 0x%02x\n", v); 16598c2ecf20Sopenharmony_ci return -ENODEV; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci ret = bq24190_register_reset(bdi); 16638c2ecf20Sopenharmony_ci if (ret < 0) 16648c2ecf20Sopenharmony_ci return ret; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci ret = bq24190_set_config(bdi); 16678c2ecf20Sopenharmony_ci if (ret < 0) 16688c2ecf20Sopenharmony_ci return ret; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci return bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg); 16718c2ecf20Sopenharmony_ci} 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_cistatic int bq24190_get_config(struct bq24190_dev_info *bdi) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci const char * const s = "ti,system-minimum-microvolt"; 16768c2ecf20Sopenharmony_ci struct power_supply_battery_info info = {}; 16778c2ecf20Sopenharmony_ci int v; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (device_property_read_u32(bdi->dev, s, &v) == 0) { 16808c2ecf20Sopenharmony_ci v /= 1000; 16818c2ecf20Sopenharmony_ci if (v >= BQ24190_REG_POC_SYS_MIN_MIN 16828c2ecf20Sopenharmony_ci && v <= BQ24190_REG_POC_SYS_MIN_MAX) 16838c2ecf20Sopenharmony_ci bdi->sys_min = v; 16848c2ecf20Sopenharmony_ci else 16858c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "invalid value for %s: %u\n", s, v); 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci if (bdi->dev->of_node && 16898c2ecf20Sopenharmony_ci !power_supply_get_battery_info(bdi->charger, &info)) { 16908c2ecf20Sopenharmony_ci v = info.precharge_current_ua / 1000; 16918c2ecf20Sopenharmony_ci if (v >= BQ24190_REG_PCTCC_IPRECHG_MIN 16928c2ecf20Sopenharmony_ci && v <= BQ24190_REG_PCTCC_IPRECHG_MAX) 16938c2ecf20Sopenharmony_ci bdi->iprechg = v; 16948c2ecf20Sopenharmony_ci else 16958c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "invalid value for battery:precharge-current-microamp: %d\n", 16968c2ecf20Sopenharmony_ci v); 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci v = info.charge_term_current_ua / 1000; 16998c2ecf20Sopenharmony_ci if (v >= BQ24190_REG_PCTCC_ITERM_MIN 17008c2ecf20Sopenharmony_ci && v <= BQ24190_REG_PCTCC_ITERM_MAX) 17018c2ecf20Sopenharmony_ci bdi->iterm = v; 17028c2ecf20Sopenharmony_ci else 17038c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "invalid value for battery:charge-term-current-microamp: %d\n", 17048c2ecf20Sopenharmony_ci v); 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci return 0; 17088c2ecf20Sopenharmony_ci} 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_cistatic int bq24190_probe(struct i2c_client *client, 17118c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 17128c2ecf20Sopenharmony_ci{ 17138c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 17148c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 17158c2ecf20Sopenharmony_ci struct power_supply_config charger_cfg = {}, battery_cfg = {}; 17168c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi; 17178c2ecf20Sopenharmony_ci int ret; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 17208c2ecf20Sopenharmony_ci dev_err(dev, "No support for SMBUS_BYTE_DATA\n"); 17218c2ecf20Sopenharmony_ci return -ENODEV; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL); 17258c2ecf20Sopenharmony_ci if (!bdi) { 17268c2ecf20Sopenharmony_ci dev_err(dev, "Can't alloc bdi struct\n"); 17278c2ecf20Sopenharmony_ci return -ENOMEM; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci bdi->client = client; 17318c2ecf20Sopenharmony_ci bdi->dev = dev; 17328c2ecf20Sopenharmony_ci strncpy(bdi->model_name, id->name, I2C_NAME_SIZE); 17338c2ecf20Sopenharmony_ci mutex_init(&bdi->f_reg_lock); 17348c2ecf20Sopenharmony_ci bdi->f_reg = 0; 17358c2ecf20Sopenharmony_ci bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */ 17368c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&bdi->input_current_limit_work, 17378c2ecf20Sopenharmony_ci bq24190_input_current_limit_work); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci i2c_set_clientdata(client, bdi); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci if (client->irq <= 0) { 17428c2ecf20Sopenharmony_ci dev_err(dev, "Can't get irq info\n"); 17438c2ecf20Sopenharmony_ci return -EINVAL; 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci bdi->edev = devm_extcon_dev_allocate(dev, bq24190_usb_extcon_cable); 17478c2ecf20Sopenharmony_ci if (IS_ERR(bdi->edev)) 17488c2ecf20Sopenharmony_ci return PTR_ERR(bdi->edev); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci ret = devm_extcon_dev_register(dev, bdi->edev); 17518c2ecf20Sopenharmony_ci if (ret < 0) 17528c2ecf20Sopenharmony_ci return ret; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 17558c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 17568c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 600); 17578c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 17588c2ecf20Sopenharmony_ci if (ret < 0) { 17598c2ecf20Sopenharmony_ci dev_err(dev, "pm_runtime_get failed: %i\n", ret); 17608c2ecf20Sopenharmony_ci goto out_pmrt; 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSFS 17648c2ecf20Sopenharmony_ci bq24190_sysfs_init_attrs(); 17658c2ecf20Sopenharmony_ci charger_cfg.attr_grp = bq24190_sysfs_groups; 17668c2ecf20Sopenharmony_ci#endif 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci charger_cfg.drv_data = bdi; 17698c2ecf20Sopenharmony_ci charger_cfg.of_node = dev->of_node; 17708c2ecf20Sopenharmony_ci charger_cfg.supplied_to = bq24190_charger_supplied_to; 17718c2ecf20Sopenharmony_ci charger_cfg.num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to), 17728c2ecf20Sopenharmony_ci bdi->charger = power_supply_register(dev, &bq24190_charger_desc, 17738c2ecf20Sopenharmony_ci &charger_cfg); 17748c2ecf20Sopenharmony_ci if (IS_ERR(bdi->charger)) { 17758c2ecf20Sopenharmony_ci dev_err(dev, "Can't register charger\n"); 17768c2ecf20Sopenharmony_ci ret = PTR_ERR(bdi->charger); 17778c2ecf20Sopenharmony_ci goto out_pmrt; 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci /* the battery class is deprecated and will be removed. */ 17818c2ecf20Sopenharmony_ci /* in the interim, this property hides it. */ 17828c2ecf20Sopenharmony_ci if (!device_property_read_bool(dev, "omit-battery-class")) { 17838c2ecf20Sopenharmony_ci battery_cfg.drv_data = bdi; 17848c2ecf20Sopenharmony_ci bdi->battery = power_supply_register(dev, &bq24190_battery_desc, 17858c2ecf20Sopenharmony_ci &battery_cfg); 17868c2ecf20Sopenharmony_ci if (IS_ERR(bdi->battery)) { 17878c2ecf20Sopenharmony_ci dev_err(dev, "Can't register battery\n"); 17888c2ecf20Sopenharmony_ci ret = PTR_ERR(bdi->battery); 17898c2ecf20Sopenharmony_ci goto out_charger; 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci ret = bq24190_get_config(bdi); 17948c2ecf20Sopenharmony_ci if (ret < 0) { 17958c2ecf20Sopenharmony_ci dev_err(dev, "Can't get devicetree config\n"); 17968c2ecf20Sopenharmony_ci goto out_charger; 17978c2ecf20Sopenharmony_ci } 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci ret = bq24190_hw_init(bdi); 18008c2ecf20Sopenharmony_ci if (ret < 0) { 18018c2ecf20Sopenharmony_ci dev_err(dev, "Hardware init failed\n"); 18028c2ecf20Sopenharmony_ci goto out_charger; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci ret = bq24190_configure_usb_otg(bdi, bdi->ss_reg); 18068c2ecf20Sopenharmony_ci if (ret < 0) 18078c2ecf20Sopenharmony_ci goto out_charger; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci bdi->initialized = true; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(dev, client->irq, NULL, 18128c2ecf20Sopenharmony_ci bq24190_irq_handler_thread, 18138c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 18148c2ecf20Sopenharmony_ci "bq24190-charger", bdi); 18158c2ecf20Sopenharmony_ci if (ret < 0) { 18168c2ecf20Sopenharmony_ci dev_err(dev, "Can't set up irq handler\n"); 18178c2ecf20Sopenharmony_ci goto out_charger; 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci ret = bq24190_register_vbus_regulator(bdi); 18218c2ecf20Sopenharmony_ci if (ret < 0) 18228c2ecf20Sopenharmony_ci goto out_charger; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci enable_irq_wake(client->irq); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 18278c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci return 0; 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ciout_charger: 18328c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(bdi->battery)) 18338c2ecf20Sopenharmony_ci power_supply_unregister(bdi->battery); 18348c2ecf20Sopenharmony_ci power_supply_unregister(bdi->charger); 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ciout_pmrt: 18378c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 18388c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 18398c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 18408c2ecf20Sopenharmony_ci return ret; 18418c2ecf20Sopenharmony_ci} 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_cistatic int bq24190_remove(struct i2c_client *client) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = i2c_get_clientdata(client); 18468c2ecf20Sopenharmony_ci int error; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&bdi->input_current_limit_work); 18498c2ecf20Sopenharmony_ci error = pm_runtime_resume_and_get(bdi->dev); 18508c2ecf20Sopenharmony_ci if (error < 0) 18518c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error); 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci bq24190_register_reset(bdi); 18548c2ecf20Sopenharmony_ci if (bdi->battery) 18558c2ecf20Sopenharmony_ci power_supply_unregister(bdi->battery); 18568c2ecf20Sopenharmony_ci power_supply_unregister(bdi->charger); 18578c2ecf20Sopenharmony_ci if (error >= 0) 18588c2ecf20Sopenharmony_ci pm_runtime_put_sync(bdi->dev); 18598c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(bdi->dev); 18608c2ecf20Sopenharmony_ci pm_runtime_disable(bdi->dev); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci return 0; 18638c2ecf20Sopenharmony_ci} 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_cistatic __maybe_unused int bq24190_runtime_suspend(struct device *dev) 18668c2ecf20Sopenharmony_ci{ 18678c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 18688c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = i2c_get_clientdata(client); 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (!bdi->initialized) 18718c2ecf20Sopenharmony_ci return 0; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci dev_dbg(bdi->dev, "%s\n", __func__); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci return 0; 18768c2ecf20Sopenharmony_ci} 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_cistatic __maybe_unused int bq24190_runtime_resume(struct device *dev) 18798c2ecf20Sopenharmony_ci{ 18808c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 18818c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = i2c_get_clientdata(client); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci if (!bdi->initialized) 18848c2ecf20Sopenharmony_ci return 0; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci if (!bdi->irq_event) { 18878c2ecf20Sopenharmony_ci dev_dbg(bdi->dev, "checking events on possible wakeirq\n"); 18888c2ecf20Sopenharmony_ci bq24190_check_status(bdi); 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci return 0; 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_cistatic __maybe_unused int bq24190_pm_suspend(struct device *dev) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 18978c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = i2c_get_clientdata(client); 18988c2ecf20Sopenharmony_ci int error; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci error = pm_runtime_resume_and_get(bdi->dev); 19018c2ecf20Sopenharmony_ci if (error < 0) 19028c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci bq24190_register_reset(bdi); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci if (error >= 0) { 19078c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 19088c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 19098c2ecf20Sopenharmony_ci } 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci return 0; 19128c2ecf20Sopenharmony_ci} 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_cistatic __maybe_unused int bq24190_pm_resume(struct device *dev) 19158c2ecf20Sopenharmony_ci{ 19168c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 19178c2ecf20Sopenharmony_ci struct bq24190_dev_info *bdi = i2c_get_clientdata(client); 19188c2ecf20Sopenharmony_ci int error; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci bdi->f_reg = 0; 19218c2ecf20Sopenharmony_ci bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */ 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci error = pm_runtime_resume_and_get(bdi->dev); 19248c2ecf20Sopenharmony_ci if (error < 0) 19258c2ecf20Sopenharmony_ci dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci bq24190_register_reset(bdi); 19288c2ecf20Sopenharmony_ci bq24190_set_config(bdi); 19298c2ecf20Sopenharmony_ci bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci if (error >= 0) { 19328c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdi->dev); 19338c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdi->dev); 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci /* Things may have changed while suspended so alert upper layer */ 19378c2ecf20Sopenharmony_ci power_supply_changed(bdi->charger); 19388c2ecf20Sopenharmony_ci if (bdi->battery) 19398c2ecf20Sopenharmony_ci power_supply_changed(bdi->battery); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci return 0; 19428c2ecf20Sopenharmony_ci} 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_cistatic const struct dev_pm_ops bq24190_pm_ops = { 19458c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(bq24190_runtime_suspend, bq24190_runtime_resume, 19468c2ecf20Sopenharmony_ci NULL) 19478c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(bq24190_pm_suspend, bq24190_pm_resume) 19488c2ecf20Sopenharmony_ci}; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_cistatic const struct i2c_device_id bq24190_i2c_ids[] = { 19518c2ecf20Sopenharmony_ci { "bq24190" }, 19528c2ecf20Sopenharmony_ci { "bq24192" }, 19538c2ecf20Sopenharmony_ci { "bq24192i" }, 19548c2ecf20Sopenharmony_ci { "bq24196" }, 19558c2ecf20Sopenharmony_ci { }, 19568c2ecf20Sopenharmony_ci}; 19578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 19608c2ecf20Sopenharmony_cistatic const struct of_device_id bq24190_of_match[] = { 19618c2ecf20Sopenharmony_ci { .compatible = "ti,bq24190", }, 19628c2ecf20Sopenharmony_ci { .compatible = "ti,bq24192", }, 19638c2ecf20Sopenharmony_ci { .compatible = "ti,bq24192i", }, 19648c2ecf20Sopenharmony_ci { .compatible = "ti,bq24196", }, 19658c2ecf20Sopenharmony_ci { }, 19668c2ecf20Sopenharmony_ci}; 19678c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bq24190_of_match); 19688c2ecf20Sopenharmony_ci#else 19698c2ecf20Sopenharmony_cistatic const struct of_device_id bq24190_of_match[] = { 19708c2ecf20Sopenharmony_ci { }, 19718c2ecf20Sopenharmony_ci}; 19728c2ecf20Sopenharmony_ci#endif 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_cistatic struct i2c_driver bq24190_driver = { 19758c2ecf20Sopenharmony_ci .probe = bq24190_probe, 19768c2ecf20Sopenharmony_ci .remove = bq24190_remove, 19778c2ecf20Sopenharmony_ci .id_table = bq24190_i2c_ids, 19788c2ecf20Sopenharmony_ci .driver = { 19798c2ecf20Sopenharmony_ci .name = "bq24190-charger", 19808c2ecf20Sopenharmony_ci .pm = &bq24190_pm_ops, 19818c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(bq24190_of_match), 19828c2ecf20Sopenharmony_ci }, 19838c2ecf20Sopenharmony_ci}; 19848c2ecf20Sopenharmony_cimodule_i2c_driver(bq24190_driver); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 19878c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>"); 19888c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI BQ24190 Charger Driver"); 1989