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