xref: /openbmc/linux/drivers/power/supply/bq25890_charger.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28c0984e5SSebastian Reichel /*
38c0984e5SSebastian Reichel  * TI BQ25890 charger driver
48c0984e5SSebastian Reichel  *
58c0984e5SSebastian Reichel  * Copyright (C) 2015 Intel Corporation
68c0984e5SSebastian Reichel  */
78c0984e5SSebastian Reichel 
88c0984e5SSebastian Reichel #include <linux/module.h>
98c0984e5SSebastian Reichel #include <linux/i2c.h>
108c0984e5SSebastian Reichel #include <linux/power_supply.h>
1179d35365SHans de Goede #include <linux/power/bq25890_charger.h>
128c0984e5SSebastian Reichel #include <linux/regmap.h>
1379d35365SHans de Goede #include <linux/regulator/driver.h>
148c0984e5SSebastian Reichel #include <linux/types.h>
158c0984e5SSebastian Reichel #include <linux/gpio/consumer.h>
168c0984e5SSebastian Reichel #include <linux/interrupt.h>
178c0984e5SSebastian Reichel #include <linux/delay.h>
188c0984e5SSebastian Reichel #include <linux/usb/phy.h>
198c0984e5SSebastian Reichel 
208c0984e5SSebastian Reichel #include <linux/acpi.h>
218c0984e5SSebastian Reichel #include <linux/of.h>
228c0984e5SSebastian Reichel 
238c0984e5SSebastian Reichel #define BQ25890_MANUFACTURER		"Texas Instruments"
248c0984e5SSebastian Reichel #define BQ25890_IRQ_PIN			"bq25890_irq"
258c0984e5SSebastian Reichel 
268c0984e5SSebastian Reichel #define BQ25890_ID			3
275c35ba9bSAngus Ainslie (Purism) #define BQ25895_ID			7
282e1a2ddeSAngus Ainslie (Purism) #define BQ25896_ID			0
298c0984e5SSebastian Reichel 
3048f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_START_DELAY	(5 * HZ)
3148f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_MAX_TRIES		6
3248f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_VBUS_MARGIN_uV	1000000
3348f45b09SYauhen Kharuzhy 
34d20267c9SYauhen Kharuzhy enum bq25890_chip_version {
35d20267c9SYauhen Kharuzhy 	BQ25890,
36d20267c9SYauhen Kharuzhy 	BQ25892,
37d20267c9SYauhen Kharuzhy 	BQ25895,
38d20267c9SYauhen Kharuzhy 	BQ25896,
39d20267c9SYauhen Kharuzhy };
40d20267c9SYauhen Kharuzhy 
415956fca7SMichał Mirosław static const char *const bq25890_chip_name[] = {
425956fca7SMichał Mirosław 	"BQ25890",
435956fca7SMichał Mirosław 	"BQ25892",
445956fca7SMichał Mirosław 	"BQ25895",
455956fca7SMichał Mirosław 	"BQ25896",
465956fca7SMichał Mirosław };
475956fca7SMichał Mirosław 
488c0984e5SSebastian Reichel enum bq25890_fields {
49766873c1SYauhen Kharuzhy 	F_EN_HIZ, F_EN_ILIM, F_IINLIM,				     /* Reg00 */
508c0984e5SSebastian Reichel 	F_BHOT, F_BCOLD, F_VINDPM_OFS,				     /* Reg01 */
518c0984e5SSebastian Reichel 	F_CONV_START, F_CONV_RATE, F_BOOSTF, F_ICO_EN,
528c0984e5SSebastian Reichel 	F_HVDCP_EN, F_MAXC_EN, F_FORCE_DPM, F_AUTO_DPDM_EN,	     /* Reg02 */
53d20267c9SYauhen Kharuzhy 	F_BAT_LOAD_EN, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_SYSVMIN,
54d20267c9SYauhen Kharuzhy 	F_MIN_VBAT_SEL,						     /* Reg03 */
558c0984e5SSebastian Reichel 	F_PUMPX_EN, F_ICHG,					     /* Reg04 */
568c0984e5SSebastian Reichel 	F_IPRECHG, F_ITERM,					     /* Reg05 */
578c0984e5SSebastian Reichel 	F_VREG, F_BATLOWV, F_VRECHG,				     /* Reg06 */
588c0984e5SSebastian Reichel 	F_TERM_EN, F_STAT_DIS, F_WD, F_TMR_EN, F_CHG_TMR,
598c0984e5SSebastian Reichel 	F_JEITA_ISET,						     /* Reg07 */
608c0984e5SSebastian Reichel 	F_BATCMP, F_VCLAMP, F_TREG,				     /* Reg08 */
618c0984e5SSebastian Reichel 	F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JEITA_VSET,
628c0984e5SSebastian Reichel 	F_BATFET_DLY, F_BATFET_RST_EN, F_PUMPX_UP, F_PUMPX_DN,	     /* Reg09 */
63d20267c9SYauhen Kharuzhy 	F_BOOSTV, F_PFM_OTG_DIS, F_BOOSTI,			     /* Reg0A */
64d20267c9SYauhen Kharuzhy 	F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_SDP_STAT, F_0B_RSVD,
65d20267c9SYauhen Kharuzhy 	F_VSYS_STAT,						     /* Reg0B */
668c0984e5SSebastian Reichel 	F_WD_FAULT, F_BOOST_FAULT, F_CHG_FAULT, F_BAT_FAULT,
678c0984e5SSebastian Reichel 	F_NTC_FAULT,						     /* Reg0C */
688c0984e5SSebastian Reichel 	F_FORCE_VINDPM, F_VINDPM,				     /* Reg0D */
698c0984e5SSebastian Reichel 	F_THERM_STAT, F_BATV,					     /* Reg0E */
708c0984e5SSebastian Reichel 	F_SYSV,							     /* Reg0F */
718c0984e5SSebastian Reichel 	F_TSPCT,						     /* Reg10 */
728c0984e5SSebastian Reichel 	F_VBUS_GD, F_VBUSV,					     /* Reg11 */
738c0984e5SSebastian Reichel 	F_ICHGR,						     /* Reg12 */
748c0984e5SSebastian Reichel 	F_VDPM_STAT, F_IDPM_STAT, F_IDPM_LIM,			     /* Reg13 */
758c0984e5SSebastian Reichel 	F_REG_RST, F_ICO_OPTIMIZED, F_PN, F_TS_PROFILE, F_DEV_REV,   /* Reg14 */
768c0984e5SSebastian Reichel 
778c0984e5SSebastian Reichel 	F_MAX_FIELDS
788c0984e5SSebastian Reichel };
798c0984e5SSebastian Reichel 
808c0984e5SSebastian Reichel /* initial field values, converted to register values */
818c0984e5SSebastian Reichel struct bq25890_init_data {
828c0984e5SSebastian Reichel 	u8 ichg;	/* charge current		*/
838c0984e5SSebastian Reichel 	u8 vreg;	/* regulation voltage		*/
848c0984e5SSebastian Reichel 	u8 iterm;	/* termination current		*/
858c0984e5SSebastian Reichel 	u8 iprechg;	/* precharge current		*/
868c0984e5SSebastian Reichel 	u8 sysvmin;	/* minimum system voltage limit */
878c0984e5SSebastian Reichel 	u8 boostv;	/* boost regulation voltage	*/
888c0984e5SSebastian Reichel 	u8 boosti;	/* boost current limit		*/
898c0984e5SSebastian Reichel 	u8 boostf;	/* boost frequency		*/
908c0984e5SSebastian Reichel 	u8 ilim_en;	/* enable ILIM pin		*/
918c0984e5SSebastian Reichel 	u8 treg;	/* thermal regulation threshold */
9272408329SMichał Mirosław 	u8 rbatcomp;	/* IBAT sense resistor value    */
9372408329SMichał Mirosław 	u8 vclamp;	/* IBAT compensation voltage limit */
948c0984e5SSebastian Reichel };
958c0984e5SSebastian Reichel 
968c0984e5SSebastian Reichel struct bq25890_state {
978c0984e5SSebastian Reichel 	u8 online;
98c688e0c4SMarek Vasut 	u8 hiz;
998c0984e5SSebastian Reichel 	u8 chrg_status;
1008c0984e5SSebastian Reichel 	u8 chrg_fault;
1018c0984e5SSebastian Reichel 	u8 vsys_status;
1028c0984e5SSebastian Reichel 	u8 boost_fault;
1038c0984e5SSebastian Reichel 	u8 bat_fault;
104c562a43aSYauhen Kharuzhy 	u8 ntc_fault;
1058c0984e5SSebastian Reichel };
1068c0984e5SSebastian Reichel 
1078c0984e5SSebastian Reichel struct bq25890_device {
1088c0984e5SSebastian Reichel 	struct i2c_client *client;
1098c0984e5SSebastian Reichel 	struct device *dev;
1108c0984e5SSebastian Reichel 	struct power_supply *charger;
111d54bf877SHans de Goede 	struct power_supply *secondary_chrg;
1124e9498b8SHans de Goede 	struct power_supply_desc desc;
1134e9498b8SHans de Goede 	char name[28]; /* "bq25890-charger-%d" */
1144e9498b8SHans de Goede 	int id;
1158c0984e5SSebastian Reichel 
1168c0984e5SSebastian Reichel 	struct usb_phy *usb_phy;
1178c0984e5SSebastian Reichel 	struct notifier_block usb_nb;
1188c0984e5SSebastian Reichel 	struct work_struct usb_work;
11948f45b09SYauhen Kharuzhy 	struct delayed_work pump_express_work;
1208c0984e5SSebastian Reichel 	unsigned long usb_event;
1218c0984e5SSebastian Reichel 
1228c0984e5SSebastian Reichel 	struct regmap *rmap;
1238c0984e5SSebastian Reichel 	struct regmap_field *rmap_fields[F_MAX_FIELDS];
1248c0984e5SSebastian Reichel 
1257e3b8e35SHans de Goede 	bool skip_reset;
12640428bd4SHans de Goede 	bool read_back_init_data;
127c688e0c4SMarek Vasut 	bool force_hiz;
12848f45b09SYauhen Kharuzhy 	u32 pump_express_vbus_max;
1296adaa9a4SHans de Goede 	u32 iinlim_percentage;
130d20267c9SYauhen Kharuzhy 	enum bq25890_chip_version chip_version;
1318c0984e5SSebastian Reichel 	struct bq25890_init_data init_data;
1328c0984e5SSebastian Reichel 	struct bq25890_state state;
1338c0984e5SSebastian Reichel 
1348c0984e5SSebastian Reichel 	struct mutex lock; /* protect state data */
1358c0984e5SSebastian Reichel };
1368c0984e5SSebastian Reichel 
1374e9498b8SHans de Goede static DEFINE_IDR(bq25890_id);
1384e9498b8SHans de Goede static DEFINE_MUTEX(bq25890_id_mutex);
1394e9498b8SHans de Goede 
1408c0984e5SSebastian Reichel static const struct regmap_range bq25890_readonly_reg_ranges[] = {
1418c0984e5SSebastian Reichel 	regmap_reg_range(0x0b, 0x0c),
1428c0984e5SSebastian Reichel 	regmap_reg_range(0x0e, 0x13),
1438c0984e5SSebastian Reichel };
1448c0984e5SSebastian Reichel 
1458c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_writeable_regs = {
1468c0984e5SSebastian Reichel 	.no_ranges = bq25890_readonly_reg_ranges,
1478c0984e5SSebastian Reichel 	.n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges),
1488c0984e5SSebastian Reichel };
1498c0984e5SSebastian Reichel 
1508c0984e5SSebastian Reichel static const struct regmap_range bq25890_volatile_reg_ranges[] = {
1518c0984e5SSebastian Reichel 	regmap_reg_range(0x00, 0x00),
15221d90edaSMichał Mirosław 	regmap_reg_range(0x02, 0x02),
1538c0984e5SSebastian Reichel 	regmap_reg_range(0x09, 0x09),
154d20267c9SYauhen Kharuzhy 	regmap_reg_range(0x0b, 0x14),
1558c0984e5SSebastian Reichel };
1568c0984e5SSebastian Reichel 
1578c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_volatile_regs = {
1588c0984e5SSebastian Reichel 	.yes_ranges = bq25890_volatile_reg_ranges,
1598c0984e5SSebastian Reichel 	.n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges),
1608c0984e5SSebastian Reichel };
1618c0984e5SSebastian Reichel 
1628c0984e5SSebastian Reichel static const struct regmap_config bq25890_regmap_config = {
1638c0984e5SSebastian Reichel 	.reg_bits = 8,
1648c0984e5SSebastian Reichel 	.val_bits = 8,
1658c0984e5SSebastian Reichel 
1668c0984e5SSebastian Reichel 	.max_register = 0x14,
1678c0984e5SSebastian Reichel 	.cache_type = REGCACHE_RBTREE,
1688c0984e5SSebastian Reichel 
1698c0984e5SSebastian Reichel 	.wr_table = &bq25890_writeable_regs,
1708c0984e5SSebastian Reichel 	.volatile_table = &bq25890_volatile_regs,
1718c0984e5SSebastian Reichel };
1728c0984e5SSebastian Reichel 
1738c0984e5SSebastian Reichel static const struct reg_field bq25890_reg_fields[] = {
1748c0984e5SSebastian Reichel 	/* REG00 */
1758c0984e5SSebastian Reichel 	[F_EN_HIZ]		= REG_FIELD(0x00, 7, 7),
1768c0984e5SSebastian Reichel 	[F_EN_ILIM]		= REG_FIELD(0x00, 6, 6),
177766873c1SYauhen Kharuzhy 	[F_IINLIM]		= REG_FIELD(0x00, 0, 5),
1788c0984e5SSebastian Reichel 	/* REG01 */
1798c0984e5SSebastian Reichel 	[F_BHOT]		= REG_FIELD(0x01, 6, 7),
1808c0984e5SSebastian Reichel 	[F_BCOLD]		= REG_FIELD(0x01, 5, 5),
1818c0984e5SSebastian Reichel 	[F_VINDPM_OFS]		= REG_FIELD(0x01, 0, 4),
1828c0984e5SSebastian Reichel 	/* REG02 */
1838c0984e5SSebastian Reichel 	[F_CONV_START]		= REG_FIELD(0x02, 7, 7),
1848c0984e5SSebastian Reichel 	[F_CONV_RATE]		= REG_FIELD(0x02, 6, 6),
1858c0984e5SSebastian Reichel 	[F_BOOSTF]		= REG_FIELD(0x02, 5, 5),
1868c0984e5SSebastian Reichel 	[F_ICO_EN]		= REG_FIELD(0x02, 4, 4),
1872e1a2ddeSAngus Ainslie (Purism) 	[F_HVDCP_EN]		= REG_FIELD(0x02, 3, 3),  // reserved on BQ25896
1882e1a2ddeSAngus Ainslie (Purism) 	[F_MAXC_EN]		= REG_FIELD(0x02, 2, 2),  // reserved on BQ25896
1898c0984e5SSebastian Reichel 	[F_FORCE_DPM]		= REG_FIELD(0x02, 1, 1),
1908c0984e5SSebastian Reichel 	[F_AUTO_DPDM_EN]	= REG_FIELD(0x02, 0, 0),
1918c0984e5SSebastian Reichel 	/* REG03 */
1928c0984e5SSebastian Reichel 	[F_BAT_LOAD_EN]		= REG_FIELD(0x03, 7, 7),
1938c0984e5SSebastian Reichel 	[F_WD_RST]		= REG_FIELD(0x03, 6, 6),
1948c0984e5SSebastian Reichel 	[F_OTG_CFG]		= REG_FIELD(0x03, 5, 5),
1958c0984e5SSebastian Reichel 	[F_CHG_CFG]		= REG_FIELD(0x03, 4, 4),
1968c0984e5SSebastian Reichel 	[F_SYSVMIN]		= REG_FIELD(0x03, 1, 3),
197d20267c9SYauhen Kharuzhy 	[F_MIN_VBAT_SEL]	= REG_FIELD(0x03, 0, 0), // BQ25896 only
1988c0984e5SSebastian Reichel 	/* REG04 */
1998c0984e5SSebastian Reichel 	[F_PUMPX_EN]		= REG_FIELD(0x04, 7, 7),
2008c0984e5SSebastian Reichel 	[F_ICHG]		= REG_FIELD(0x04, 0, 6),
2018c0984e5SSebastian Reichel 	/* REG05 */
2028c0984e5SSebastian Reichel 	[F_IPRECHG]		= REG_FIELD(0x05, 4, 7),
2038c0984e5SSebastian Reichel 	[F_ITERM]		= REG_FIELD(0x05, 0, 3),
2048c0984e5SSebastian Reichel 	/* REG06 */
2058c0984e5SSebastian Reichel 	[F_VREG]		= REG_FIELD(0x06, 2, 7),
2068c0984e5SSebastian Reichel 	[F_BATLOWV]		= REG_FIELD(0x06, 1, 1),
2078c0984e5SSebastian Reichel 	[F_VRECHG]		= REG_FIELD(0x06, 0, 0),
2088c0984e5SSebastian Reichel 	/* REG07 */
2098c0984e5SSebastian Reichel 	[F_TERM_EN]		= REG_FIELD(0x07, 7, 7),
2108c0984e5SSebastian Reichel 	[F_STAT_DIS]		= REG_FIELD(0x07, 6, 6),
2118c0984e5SSebastian Reichel 	[F_WD]			= REG_FIELD(0x07, 4, 5),
2128c0984e5SSebastian Reichel 	[F_TMR_EN]		= REG_FIELD(0x07, 3, 3),
2138c0984e5SSebastian Reichel 	[F_CHG_TMR]		= REG_FIELD(0x07, 1, 2),
2145c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_ISET]		= REG_FIELD(0x07, 0, 0), // reserved on BQ25895
2158c0984e5SSebastian Reichel 	/* REG08 */
21695809139SMichał Mirosław 	[F_BATCMP]		= REG_FIELD(0x08, 5, 7),
2178c0984e5SSebastian Reichel 	[F_VCLAMP]		= REG_FIELD(0x08, 2, 4),
2188c0984e5SSebastian Reichel 	[F_TREG]		= REG_FIELD(0x08, 0, 1),
2198c0984e5SSebastian Reichel 	/* REG09 */
2208c0984e5SSebastian Reichel 	[F_FORCE_ICO]		= REG_FIELD(0x09, 7, 7),
2218c0984e5SSebastian Reichel 	[F_TMR2X_EN]		= REG_FIELD(0x09, 6, 6),
2228c0984e5SSebastian Reichel 	[F_BATFET_DIS]		= REG_FIELD(0x09, 5, 5),
2235c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_VSET]		= REG_FIELD(0x09, 4, 4), // reserved on BQ25895
2248c0984e5SSebastian Reichel 	[F_BATFET_DLY]		= REG_FIELD(0x09, 3, 3),
2258c0984e5SSebastian Reichel 	[F_BATFET_RST_EN]	= REG_FIELD(0x09, 2, 2),
2268c0984e5SSebastian Reichel 	[F_PUMPX_UP]		= REG_FIELD(0x09, 1, 1),
2278c0984e5SSebastian Reichel 	[F_PUMPX_DN]		= REG_FIELD(0x09, 0, 0),
2288c0984e5SSebastian Reichel 	/* REG0A */
2298c0984e5SSebastian Reichel 	[F_BOOSTV]		= REG_FIELD(0x0A, 4, 7),
2305c35ba9bSAngus Ainslie (Purism) 	[F_BOOSTI]		= REG_FIELD(0x0A, 0, 2), // reserved on BQ25895
231d20267c9SYauhen Kharuzhy 	[F_PFM_OTG_DIS]		= REG_FIELD(0x0A, 3, 3), // BQ25896 only
2328c0984e5SSebastian Reichel 	/* REG0B */
2338c0984e5SSebastian Reichel 	[F_VBUS_STAT]		= REG_FIELD(0x0B, 5, 7),
2348c0984e5SSebastian Reichel 	[F_CHG_STAT]		= REG_FIELD(0x0B, 3, 4),
2358c0984e5SSebastian Reichel 	[F_PG_STAT]		= REG_FIELD(0x0B, 2, 2),
2362e1a2ddeSAngus Ainslie (Purism) 	[F_SDP_STAT]		= REG_FIELD(0x0B, 1, 1), // reserved on BQ25896
2378c0984e5SSebastian Reichel 	[F_VSYS_STAT]		= REG_FIELD(0x0B, 0, 0),
2388c0984e5SSebastian Reichel 	/* REG0C */
2398c0984e5SSebastian Reichel 	[F_WD_FAULT]		= REG_FIELD(0x0C, 7, 7),
2408c0984e5SSebastian Reichel 	[F_BOOST_FAULT]		= REG_FIELD(0x0C, 6, 6),
2418c0984e5SSebastian Reichel 	[F_CHG_FAULT]		= REG_FIELD(0x0C, 4, 5),
2428c0984e5SSebastian Reichel 	[F_BAT_FAULT]		= REG_FIELD(0x0C, 3, 3),
2438c0984e5SSebastian Reichel 	[F_NTC_FAULT]		= REG_FIELD(0x0C, 0, 2),
2448c0984e5SSebastian Reichel 	/* REG0D */
2458c0984e5SSebastian Reichel 	[F_FORCE_VINDPM]	= REG_FIELD(0x0D, 7, 7),
2468c0984e5SSebastian Reichel 	[F_VINDPM]		= REG_FIELD(0x0D, 0, 6),
2478c0984e5SSebastian Reichel 	/* REG0E */
2488c0984e5SSebastian Reichel 	[F_THERM_STAT]		= REG_FIELD(0x0E, 7, 7),
2498c0984e5SSebastian Reichel 	[F_BATV]		= REG_FIELD(0x0E, 0, 6),
2508c0984e5SSebastian Reichel 	/* REG0F */
2518c0984e5SSebastian Reichel 	[F_SYSV]		= REG_FIELD(0x0F, 0, 6),
2528c0984e5SSebastian Reichel 	/* REG10 */
2538c0984e5SSebastian Reichel 	[F_TSPCT]		= REG_FIELD(0x10, 0, 6),
2548c0984e5SSebastian Reichel 	/* REG11 */
2558c0984e5SSebastian Reichel 	[F_VBUS_GD]		= REG_FIELD(0x11, 7, 7),
2568c0984e5SSebastian Reichel 	[F_VBUSV]		= REG_FIELD(0x11, 0, 6),
2578c0984e5SSebastian Reichel 	/* REG12 */
2588c0984e5SSebastian Reichel 	[F_ICHGR]		= REG_FIELD(0x12, 0, 6),
2598c0984e5SSebastian Reichel 	/* REG13 */
2608c0984e5SSebastian Reichel 	[F_VDPM_STAT]		= REG_FIELD(0x13, 7, 7),
2618c0984e5SSebastian Reichel 	[F_IDPM_STAT]		= REG_FIELD(0x13, 6, 6),
2628c0984e5SSebastian Reichel 	[F_IDPM_LIM]		= REG_FIELD(0x13, 0, 5),
2638c0984e5SSebastian Reichel 	/* REG14 */
2648c0984e5SSebastian Reichel 	[F_REG_RST]		= REG_FIELD(0x14, 7, 7),
2658c0984e5SSebastian Reichel 	[F_ICO_OPTIMIZED]	= REG_FIELD(0x14, 6, 6),
2668c0984e5SSebastian Reichel 	[F_PN]			= REG_FIELD(0x14, 3, 5),
2678c0984e5SSebastian Reichel 	[F_TS_PROFILE]		= REG_FIELD(0x14, 2, 2),
2688c0984e5SSebastian Reichel 	[F_DEV_REV]		= REG_FIELD(0x14, 0, 1)
2698c0984e5SSebastian Reichel };
2708c0984e5SSebastian Reichel 
2718c0984e5SSebastian Reichel /*
2728c0984e5SSebastian Reichel  * Most of the val -> idx conversions can be computed, given the minimum,
2738c0984e5SSebastian Reichel  * maximum and the step between values. For the rest of conversions, we use
2748c0984e5SSebastian Reichel  * lookup tables.
2758c0984e5SSebastian Reichel  */
2768c0984e5SSebastian Reichel enum bq25890_table_ids {
2778c0984e5SSebastian Reichel 	/* range tables */
2788c0984e5SSebastian Reichel 	TBL_ICHG,
2798c0984e5SSebastian Reichel 	TBL_ITERM,
280766873c1SYauhen Kharuzhy 	TBL_IINLIM,
2818c0984e5SSebastian Reichel 	TBL_VREG,
2828c0984e5SSebastian Reichel 	TBL_BOOSTV,
2838c0984e5SSebastian Reichel 	TBL_SYSVMIN,
28448f45b09SYauhen Kharuzhy 	TBL_VBUSV,
28572408329SMichał Mirosław 	TBL_VBATCOMP,
28672408329SMichał Mirosław 	TBL_RBATCOMP,
2878c0984e5SSebastian Reichel 
2888c0984e5SSebastian Reichel 	/* lookup tables */
2898c0984e5SSebastian Reichel 	TBL_TREG,
2908c0984e5SSebastian Reichel 	TBL_BOOSTI,
2919652c024SAngus Ainslie 	TBL_TSPCT,
2928c0984e5SSebastian Reichel };
2938c0984e5SSebastian Reichel 
2948c0984e5SSebastian Reichel /* Thermal Regulation Threshold lookup table, in degrees Celsius */
2958c0984e5SSebastian Reichel static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 };
2968c0984e5SSebastian Reichel 
2978c0984e5SSebastian Reichel #define BQ25890_TREG_TBL_SIZE		ARRAY_SIZE(bq25890_treg_tbl)
2988c0984e5SSebastian Reichel 
2998c0984e5SSebastian Reichel /* Boost mode current limit lookup table, in uA */
3008c0984e5SSebastian Reichel static const u32 bq25890_boosti_tbl[] = {
3018c0984e5SSebastian Reichel 	500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000
3028c0984e5SSebastian Reichel };
3038c0984e5SSebastian Reichel 
3048c0984e5SSebastian Reichel #define BQ25890_BOOSTI_TBL_SIZE		ARRAY_SIZE(bq25890_boosti_tbl)
3058c0984e5SSebastian Reichel 
3069652c024SAngus Ainslie /* NTC 10K temperature lookup table in tenths of a degree */
3079652c024SAngus Ainslie static const u32 bq25890_tspct_tbl[] = {
3089652c024SAngus Ainslie 	850, 840, 830, 820, 810, 800, 790, 780,
3099652c024SAngus Ainslie 	770, 760, 750, 740, 730, 720, 710, 700,
3109652c024SAngus Ainslie 	690, 685, 680, 675, 670, 660, 650, 645,
3119652c024SAngus Ainslie 	640, 630, 620, 615, 610, 600, 590, 585,
3129652c024SAngus Ainslie 	580, 570, 565, 560, 550, 540, 535, 530,
3139652c024SAngus Ainslie 	520, 515, 510, 500, 495, 490, 480, 475,
3149652c024SAngus Ainslie 	470, 460, 455, 450, 440, 435, 430, 425,
3159652c024SAngus Ainslie 	420, 410, 405, 400, 390, 385, 380, 370,
3169652c024SAngus Ainslie 	365, 360, 355, 350, 340, 335, 330, 320,
3179652c024SAngus Ainslie 	310, 305, 300, 290, 285, 280, 275, 270,
3189652c024SAngus Ainslie 	260, 250, 245, 240, 230, 225, 220, 210,
3199652c024SAngus Ainslie 	205, 200, 190, 180, 175, 170, 160, 150,
3209652c024SAngus Ainslie 	145, 140, 130, 120, 115, 110, 100, 90,
3219652c024SAngus Ainslie 	80, 70, 60, 50, 40, 30, 20, 10,
3229652c024SAngus Ainslie 	0, -10, -20, -30, -40, -60, -70, -80,
3239652c024SAngus Ainslie 	-90, -10, -120, -140, -150, -170, -190, -210,
3249652c024SAngus Ainslie };
3259652c024SAngus Ainslie 
3269652c024SAngus Ainslie #define BQ25890_TSPCT_TBL_SIZE		ARRAY_SIZE(bq25890_tspct_tbl)
3279652c024SAngus Ainslie 
3288c0984e5SSebastian Reichel struct bq25890_range {
3298c0984e5SSebastian Reichel 	u32 min;
3308c0984e5SSebastian Reichel 	u32 max;
3318c0984e5SSebastian Reichel 	u32 step;
3328c0984e5SSebastian Reichel };
3338c0984e5SSebastian Reichel 
3348c0984e5SSebastian Reichel struct bq25890_lookup {
3358c0984e5SSebastian Reichel 	const u32 *tbl;
3368c0984e5SSebastian Reichel 	u32 size;
3378c0984e5SSebastian Reichel };
3388c0984e5SSebastian Reichel 
3398c0984e5SSebastian Reichel static const union {
3408c0984e5SSebastian Reichel 	struct bq25890_range  rt;
3418c0984e5SSebastian Reichel 	struct bq25890_lookup lt;
3428c0984e5SSebastian Reichel } bq25890_tables[] = {
3438c0984e5SSebastian Reichel 	/* range tables */
344d20267c9SYauhen Kharuzhy 	/* TODO: BQ25896 has max ICHG 3008 mA */
3458c0984e5SSebastian Reichel 	[TBL_ICHG] =	 { .rt = {0,        5056000, 64000} },	 /* uA */
3468c0984e5SSebastian Reichel 	[TBL_ITERM] =	 { .rt = {64000,    1024000, 64000} },	 /* uA */
347766873c1SYauhen Kharuzhy 	[TBL_IINLIM] =   { .rt = {100000,   3250000, 50000} },	 /* uA */
3488c0984e5SSebastian Reichel 	[TBL_VREG] =	 { .rt = {3840000,  4608000, 16000} },	 /* uV */
3498c0984e5SSebastian Reichel 	[TBL_BOOSTV] =	 { .rt = {4550000,  5510000, 64000} },	 /* uV */
3508c0984e5SSebastian Reichel 	[TBL_SYSVMIN] =  { .rt = {3000000,  3700000, 100000} },	 /* uV */
35148f45b09SYauhen Kharuzhy 	[TBL_VBUSV] =	 { .rt = {2600000, 15300000, 100000} },	 /* uV */
35272408329SMichał Mirosław 	[TBL_VBATCOMP] = { .rt = {0,         224000, 32000} },	 /* uV */
35372408329SMichał Mirosław 	[TBL_RBATCOMP] = { .rt = {0,         140000, 20000} },	 /* uOhm */
3548c0984e5SSebastian Reichel 
3558c0984e5SSebastian Reichel 	/* lookup tables */
3568c0984e5SSebastian Reichel 	[TBL_TREG] =	{ .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} },
3579652c024SAngus Ainslie 	[TBL_BOOSTI] =	{ .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} },
3589652c024SAngus Ainslie 	[TBL_TSPCT] =	{ .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} }
3598c0984e5SSebastian Reichel };
3608c0984e5SSebastian Reichel 
bq25890_field_read(struct bq25890_device * bq,enum bq25890_fields field_id)3618c0984e5SSebastian Reichel static int bq25890_field_read(struct bq25890_device *bq,
3628c0984e5SSebastian Reichel 			      enum bq25890_fields field_id)
3638c0984e5SSebastian Reichel {
3648c0984e5SSebastian Reichel 	int ret;
3658c0984e5SSebastian Reichel 	int val;
3668c0984e5SSebastian Reichel 
3678c0984e5SSebastian Reichel 	ret = regmap_field_read(bq->rmap_fields[field_id], &val);
3688c0984e5SSebastian Reichel 	if (ret < 0)
3698c0984e5SSebastian Reichel 		return ret;
3708c0984e5SSebastian Reichel 
3718c0984e5SSebastian Reichel 	return val;
3728c0984e5SSebastian Reichel }
3738c0984e5SSebastian Reichel 
bq25890_field_write(struct bq25890_device * bq,enum bq25890_fields field_id,u8 val)3748c0984e5SSebastian Reichel static int bq25890_field_write(struct bq25890_device *bq,
3758c0984e5SSebastian Reichel 			       enum bq25890_fields field_id, u8 val)
3768c0984e5SSebastian Reichel {
3778c0984e5SSebastian Reichel 	return regmap_field_write(bq->rmap_fields[field_id], val);
3788c0984e5SSebastian Reichel }
3798c0984e5SSebastian Reichel 
bq25890_find_idx(u32 value,enum bq25890_table_ids id)3808c0984e5SSebastian Reichel static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id)
3818c0984e5SSebastian Reichel {
3828c0984e5SSebastian Reichel 	u8 idx;
3838c0984e5SSebastian Reichel 
3848c0984e5SSebastian Reichel 	if (id >= TBL_TREG) {
3858c0984e5SSebastian Reichel 		const u32 *tbl = bq25890_tables[id].lt.tbl;
3868c0984e5SSebastian Reichel 		u32 tbl_size = bq25890_tables[id].lt.size;
3878c0984e5SSebastian Reichel 
3888c0984e5SSebastian Reichel 		for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++)
3898c0984e5SSebastian Reichel 			;
3908c0984e5SSebastian Reichel 	} else {
3918c0984e5SSebastian Reichel 		const struct bq25890_range *rtbl = &bq25890_tables[id].rt;
3928c0984e5SSebastian Reichel 		u8 rtbl_size;
3938c0984e5SSebastian Reichel 
3948c0984e5SSebastian Reichel 		rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1;
3958c0984e5SSebastian Reichel 
3968c0984e5SSebastian Reichel 		for (idx = 1;
3978c0984e5SSebastian Reichel 		     idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value);
3988c0984e5SSebastian Reichel 		     idx++)
3998c0984e5SSebastian Reichel 			;
4008c0984e5SSebastian Reichel 	}
4018c0984e5SSebastian Reichel 
4028c0984e5SSebastian Reichel 	return idx - 1;
4038c0984e5SSebastian Reichel }
4048c0984e5SSebastian Reichel 
bq25890_find_val(u8 idx,enum bq25890_table_ids id)4058c0984e5SSebastian Reichel static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id)
4068c0984e5SSebastian Reichel {
4078c0984e5SSebastian Reichel 	const struct bq25890_range *rtbl;
4088c0984e5SSebastian Reichel 
4098c0984e5SSebastian Reichel 	/* lookup table? */
4108c0984e5SSebastian Reichel 	if (id >= TBL_TREG)
4118c0984e5SSebastian Reichel 		return bq25890_tables[id].lt.tbl[idx];
4128c0984e5SSebastian Reichel 
4138c0984e5SSebastian Reichel 	/* range table */
4148c0984e5SSebastian Reichel 	rtbl = &bq25890_tables[id].rt;
4158c0984e5SSebastian Reichel 
4168c0984e5SSebastian Reichel 	return (rtbl->min + idx * rtbl->step);
4178c0984e5SSebastian Reichel }
4188c0984e5SSebastian Reichel 
4198c0984e5SSebastian Reichel enum bq25890_status {
4208c0984e5SSebastian Reichel 	STATUS_NOT_CHARGING,
4218c0984e5SSebastian Reichel 	STATUS_PRE_CHARGING,
4228c0984e5SSebastian Reichel 	STATUS_FAST_CHARGING,
4238c0984e5SSebastian Reichel 	STATUS_TERMINATION_DONE,
4248c0984e5SSebastian Reichel };
4258c0984e5SSebastian Reichel 
4268c0984e5SSebastian Reichel enum bq25890_chrg_fault {
4278c0984e5SSebastian Reichel 	CHRG_FAULT_NORMAL,
4288c0984e5SSebastian Reichel 	CHRG_FAULT_INPUT,
4298c0984e5SSebastian Reichel 	CHRG_FAULT_THERMAL_SHUTDOWN,
4308c0984e5SSebastian Reichel 	CHRG_FAULT_TIMER_EXPIRED,
4318c0984e5SSebastian Reichel };
4328c0984e5SSebastian Reichel 
433c562a43aSYauhen Kharuzhy enum bq25890_ntc_fault {
434c562a43aSYauhen Kharuzhy 	NTC_FAULT_NORMAL = 0,
435c562a43aSYauhen Kharuzhy 	NTC_FAULT_WARM = 2,
436c562a43aSYauhen Kharuzhy 	NTC_FAULT_COOL = 3,
437c562a43aSYauhen Kharuzhy 	NTC_FAULT_COLD = 5,
438c562a43aSYauhen Kharuzhy 	NTC_FAULT_HOT = 6,
439c562a43aSYauhen Kharuzhy };
440c562a43aSYauhen Kharuzhy 
bq25890_is_adc_property(enum power_supply_property psp)44121d90edaSMichał Mirosław static bool bq25890_is_adc_property(enum power_supply_property psp)
44221d90edaSMichał Mirosław {
44321d90edaSMichał Mirosław 	switch (psp) {
44421d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
44521d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_CURRENT_NOW:
4469652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
44721d90edaSMichał Mirosław 		return true;
44821d90edaSMichał Mirosław 
44921d90edaSMichał Mirosław 	default:
45021d90edaSMichał Mirosław 		return false;
45121d90edaSMichał Mirosław 	}
45221d90edaSMichał Mirosław }
45321d90edaSMichał Mirosław 
4543b4df57bSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq);
4553b4df57bSMichał Mirosław 
bq25890_get_vbus_voltage(struct bq25890_device * bq)45648f45b09SYauhen Kharuzhy static int bq25890_get_vbus_voltage(struct bq25890_device *bq)
45748f45b09SYauhen Kharuzhy {
45848f45b09SYauhen Kharuzhy 	int ret;
45948f45b09SYauhen Kharuzhy 
46048f45b09SYauhen Kharuzhy 	ret = bq25890_field_read(bq, F_VBUSV);
46148f45b09SYauhen Kharuzhy 	if (ret < 0)
46248f45b09SYauhen Kharuzhy 		return ret;
46348f45b09SYauhen Kharuzhy 
46448f45b09SYauhen Kharuzhy 	return bq25890_find_val(ret, TBL_VBUSV);
46548f45b09SYauhen Kharuzhy }
46648f45b09SYauhen Kharuzhy 
bq25890_update_state(struct bq25890_device * bq,enum power_supply_property psp,struct bq25890_state * state)467d1b25092SMarek Vasut static void bq25890_update_state(struct bq25890_device *bq,
4688c0984e5SSebastian Reichel 				 enum power_supply_property psp,
469d1b25092SMarek Vasut 				 struct bq25890_state *state)
4708c0984e5SSebastian Reichel {
47121d90edaSMichał Mirosław 	bool do_adc_conv;
47221d90edaSMichał Mirosław 	int ret;
4738c0984e5SSebastian Reichel 
4748c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
4753b4df57bSMichał Mirosław 	/* update state in case we lost an interrupt */
4763b4df57bSMichał Mirosław 	__bq25890_handle_irq(bq);
477d1b25092SMarek Vasut 	*state = bq->state;
478dee0df84SHans de Goede 	do_adc_conv = (!state->online || state->hiz) && bq25890_is_adc_property(psp);
47921d90edaSMichał Mirosław 	if (do_adc_conv)
48021d90edaSMichał Mirosław 		bq25890_field_write(bq, F_CONV_START, 1);
4818c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
4828c0984e5SSebastian Reichel 
48321d90edaSMichał Mirosław 	if (do_adc_conv)
48421d90edaSMichał Mirosław 		regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START],
48521d90edaSMichał Mirosław 			ret, !ret, 25000, 1000000);
486d1b25092SMarek Vasut }
487d1b25092SMarek Vasut 
bq25890_power_supply_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)488d1b25092SMarek Vasut static int bq25890_power_supply_get_property(struct power_supply *psy,
489d1b25092SMarek Vasut 					     enum power_supply_property psp,
490d1b25092SMarek Vasut 					     union power_supply_propval *val)
491d1b25092SMarek Vasut {
492d1b25092SMarek Vasut 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
493d1b25092SMarek Vasut 	struct bq25890_state state;
494d1b25092SMarek Vasut 	int ret;
495d1b25092SMarek Vasut 
496d1b25092SMarek Vasut 	bq25890_update_state(bq, psp, &state);
49721d90edaSMichał Mirosław 
4988c0984e5SSebastian Reichel 	switch (psp) {
4998c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_STATUS:
500c688e0c4SMarek Vasut 		if (!state.online || state.hiz)
5018c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
5028c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_NOT_CHARGING)
5038c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
5048c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_PRE_CHARGING ||
5058c0984e5SSebastian Reichel 			 state.chrg_status == STATUS_FAST_CHARGING)
5068c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
5078c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_TERMINATION_DONE)
5088c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_FULL;
5098c0984e5SSebastian Reichel 		else
5108c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
5118c0984e5SSebastian Reichel 
5128c0984e5SSebastian Reichel 		break;
5138c0984e5SSebastian Reichel 
514b302a0aeSMichał Mirosław 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
515c688e0c4SMarek Vasut 		if (!state.online || state.hiz ||
516c688e0c4SMarek Vasut 		    state.chrg_status == STATUS_NOT_CHARGING ||
517b302a0aeSMichał Mirosław 		    state.chrg_status == STATUS_TERMINATION_DONE)
518b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
519b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_PRE_CHARGING)
520b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
521b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_FAST_CHARGING)
522b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
523b302a0aeSMichał Mirosław 		else /* unreachable */
524b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
525b302a0aeSMichał Mirosław 		break;
526b302a0aeSMichał Mirosław 
5278c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MANUFACTURER:
5288c0984e5SSebastian Reichel 		val->strval = BQ25890_MANUFACTURER;
5298c0984e5SSebastian Reichel 		break;
5308c0984e5SSebastian Reichel 
5312e1a2ddeSAngus Ainslie (Purism) 	case POWER_SUPPLY_PROP_MODEL_NAME:
5325956fca7SMichał Mirosław 		val->strval = bq25890_chip_name[bq->chip_version];
5332e1a2ddeSAngus Ainslie (Purism) 		break;
5342e1a2ddeSAngus Ainslie (Purism) 
5358c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
536c688e0c4SMarek Vasut 		val->intval = state.online && !state.hiz;
5378c0984e5SSebastian Reichel 		break;
5388c0984e5SSebastian Reichel 
5398c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_HEALTH:
5408c0984e5SSebastian Reichel 		if (!state.chrg_fault && !state.bat_fault && !state.boost_fault)
5418c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_GOOD;
5428c0984e5SSebastian Reichel 		else if (state.bat_fault)
5438c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
5448c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED)
5458c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
5468c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN)
5478c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
5488c0984e5SSebastian Reichel 		else
5498c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
5508c0984e5SSebastian Reichel 		break;
5518c0984e5SSebastian Reichel 
552c942656dSMichał Mirosław 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
553c942656dSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM);
554c942656dSMichał Mirosław 		break;
555c942656dSMichał Mirosław 
5568c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
5578c0984e5SSebastian Reichel 		val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM);
5588c0984e5SSebastian Reichel 		break;
5598c0984e5SSebastian Reichel 
560478efc79SMichał Mirosław 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
561766873c1SYauhen Kharuzhy 		ret = bq25890_field_read(bq, F_IINLIM);
562478efc79SMichał Mirosław 		if (ret < 0)
563478efc79SMichał Mirosław 			return ret;
564478efc79SMichał Mirosław 
565766873c1SYauhen Kharuzhy 		val->intval = bq25890_find_val(ret, TBL_IINLIM);
566478efc79SMichał Mirosław 		break;
567478efc79SMichał Mirosław 
568ef1ca210SMarek Vasut 	case POWER_SUPPLY_PROP_CURRENT_NOW:	/* I_BAT now */
569ef1ca210SMarek Vasut 		/*
570ef1ca210SMarek Vasut 		 * This is ADC-sampled immediate charge current supplied
571ef1ca210SMarek Vasut 		 * from charger to battery. The property name is confusing,
572ef1ca210SMarek Vasut 		 * for clarification refer to:
573ef1ca210SMarek Vasut 		 * Documentation/ABI/testing/sysfs-class-power
574ef1ca210SMarek Vasut 		 * /sys/class/power_supply/<supply_name>/current_now
575ef1ca210SMarek Vasut 		 */
5761e4724d0SMichał Mirosław 		ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */
5771e4724d0SMichał Mirosław 		if (ret < 0)
5781e4724d0SMichał Mirosław 			return ret;
5791e4724d0SMichał Mirosław 
5801e4724d0SMichał Mirosław 		/* converted_val = ADC_val * 50mA (table 10.3.19) */
5811e4724d0SMichał Mirosław 		val->intval = ret * -50000;
5821e4724d0SMichał Mirosław 		break;
5831e4724d0SMichał Mirosław 
5848327a8abSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:	/* I_BAT user limit */
5858327a8abSMarek Vasut 		/*
5868327a8abSMarek Vasut 		 * This is user-configured constant charge current supplied
5878327a8abSMarek Vasut 		 * from charger to battery in first phase of charging, when
5888327a8abSMarek Vasut 		 * battery voltage is below constant charge voltage.
5898327a8abSMarek Vasut 		 *
5908327a8abSMarek Vasut 		 * This value reflects the current hardware setting.
5918327a8abSMarek Vasut 		 *
5928327a8abSMarek Vasut 		 * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX is the
5938327a8abSMarek Vasut 		 * maximum value of this property.
5948327a8abSMarek Vasut 		 */
5958327a8abSMarek Vasut 		ret = bq25890_field_read(bq, F_ICHG);
5968327a8abSMarek Vasut 		if (ret < 0)
5978327a8abSMarek Vasut 			return ret;
5988327a8abSMarek Vasut 		val->intval = bq25890_find_val(ret, TBL_ICHG);
5998327a8abSMarek Vasut 
6008327a8abSMarek Vasut 		/* When temperature is too low, charge current is decreased */
6018327a8abSMarek Vasut 		if (bq->state.ntc_fault == NTC_FAULT_COOL) {
6028327a8abSMarek Vasut 			ret = bq25890_field_read(bq, F_JEITA_ISET);
6038327a8abSMarek Vasut 			if (ret < 0)
6048327a8abSMarek Vasut 				return ret;
6058327a8abSMarek Vasut 
6068327a8abSMarek Vasut 			if (ret)
6078327a8abSMarek Vasut 				val->intval /= 5;
6088327a8abSMarek Vasut 			else
6098327a8abSMarek Vasut 				val->intval /= 2;
6108327a8abSMarek Vasut 		}
6118327a8abSMarek Vasut 		break;
6128327a8abSMarek Vasut 
6138327a8abSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:	/* I_BAT max */
6148327a8abSMarek Vasut 		/*
6158327a8abSMarek Vasut 		 * This is maximum allowed constant charge current supplied
6168327a8abSMarek Vasut 		 * from charger to battery in first phase of charging, when
6178327a8abSMarek Vasut 		 * battery voltage is below constant charge voltage.
6188327a8abSMarek Vasut 		 *
6198327a8abSMarek Vasut 		 * This value is constant for each battery and set from DT.
6208327a8abSMarek Vasut 		 */
6218327a8abSMarek Vasut 		val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
6228327a8abSMarek Vasut 		break;
6238327a8abSMarek Vasut 
6247c852375SMarek Vasut 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:	/* V_BAT now */
6257c852375SMarek Vasut 		/*
6267c852375SMarek Vasut 		 * This is ADC-sampled immediate charge voltage supplied
6277c852375SMarek Vasut 		 * from charger to battery. The property name is confusing,
6287c852375SMarek Vasut 		 * for clarification refer to:
6297c852375SMarek Vasut 		 * Documentation/ABI/testing/sysfs-class-power
6307c852375SMarek Vasut 		 * /sys/class/power_supply/<supply_name>/voltage_now
6317c852375SMarek Vasut 		 */
6327c852375SMarek Vasut 		ret = bq25890_field_read(bq, F_BATV); /* read measured value */
6337c852375SMarek Vasut 		if (ret < 0)
6347c852375SMarek Vasut 			return ret;
6357c852375SMarek Vasut 
6367c852375SMarek Vasut 		/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
6377c852375SMarek Vasut 		val->intval = 2304000 + ret * 20000;
6387c852375SMarek Vasut 		break;
6397c852375SMarek Vasut 
6407c852375SMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:	/* V_BAT user limit */
6417c852375SMarek Vasut 		/*
6427c852375SMarek Vasut 		 * This is user-configured constant charge voltage supplied
6437c852375SMarek Vasut 		 * from charger to battery in second phase of charging, when
6447c852375SMarek Vasut 		 * battery voltage reached constant charge voltage.
6457c852375SMarek Vasut 		 *
6467c852375SMarek Vasut 		 * This value reflects the current hardware setting.
6477c852375SMarek Vasut 		 *
6487c852375SMarek Vasut 		 * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX is the
6497c852375SMarek Vasut 		 * maximum value of this property.
6507c852375SMarek Vasut 		 */
6517c852375SMarek Vasut 		ret = bq25890_field_read(bq, F_VREG);
6527c852375SMarek Vasut 		if (ret < 0)
6537c852375SMarek Vasut 			return ret;
6547c852375SMarek Vasut 
6557c852375SMarek Vasut 		val->intval = bq25890_find_val(ret, TBL_VREG);
6567c852375SMarek Vasut 		break;
6577c852375SMarek Vasut 
6587c852375SMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:	/* V_BAT max */
6597c852375SMarek Vasut 		/*
6607c852375SMarek Vasut 		 * This is maximum allowed constant charge voltage supplied
6617c852375SMarek Vasut 		 * from charger to battery in second phase of charging, when
6627c852375SMarek Vasut 		 * battery voltage reached constant charge voltage.
6637c852375SMarek Vasut 		 *
6647c852375SMarek Vasut 		 * This value is constant for each battery and set from DT.
6657c852375SMarek Vasut 		 */
6667c852375SMarek Vasut 		val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
6677c852375SMarek Vasut 		break;
6687c852375SMarek Vasut 
6699652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
6709652c024SAngus Ainslie 		ret = bq25890_field_read(bq, F_TSPCT);
6719652c024SAngus Ainslie 		if (ret < 0)
6729652c024SAngus Ainslie 			return ret;
6739652c024SAngus Ainslie 
6749652c024SAngus Ainslie 		/* convert TS percentage into rough temperature */
6759652c024SAngus Ainslie 		val->intval = bq25890_find_val(ret, TBL_TSPCT);
6769652c024SAngus Ainslie 		break;
6779652c024SAngus Ainslie 
6788c0984e5SSebastian Reichel 	default:
6798c0984e5SSebastian Reichel 		return -EINVAL;
6808c0984e5SSebastian Reichel 	}
6818c0984e5SSebastian Reichel 
6828c0984e5SSebastian Reichel 	return 0;
6838c0984e5SSebastian Reichel }
6848c0984e5SSebastian Reichel 
bq25890_power_supply_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)6854a4748f2SMarek Vasut static int bq25890_power_supply_set_property(struct power_supply *psy,
6864a4748f2SMarek Vasut 					     enum power_supply_property psp,
6874a4748f2SMarek Vasut 					     const union power_supply_propval *val)
6884a4748f2SMarek Vasut {
6894a4748f2SMarek Vasut 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
690c688e0c4SMarek Vasut 	struct bq25890_state state;
691c688e0c4SMarek Vasut 	int maxval, ret;
6924a4748f2SMarek Vasut 	u8 lval;
6934a4748f2SMarek Vasut 
6944a4748f2SMarek Vasut 	switch (psp) {
695b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
696b63e60ebSMarek Vasut 		maxval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
697b63e60ebSMarek Vasut 		lval = bq25890_find_idx(min(val->intval, maxval), TBL_ICHG);
698b63e60ebSMarek Vasut 		return bq25890_field_write(bq, F_ICHG, lval);
699b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
700b63e60ebSMarek Vasut 		maxval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
701b63e60ebSMarek Vasut 		lval = bq25890_find_idx(min(val->intval, maxval), TBL_VREG);
702b63e60ebSMarek Vasut 		return bq25890_field_write(bq, F_VREG, lval);
7034a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
70455cafd4bSNathan Chancellor 		lval = bq25890_find_idx(val->intval, TBL_IINLIM);
7054a4748f2SMarek Vasut 		return bq25890_field_write(bq, F_IINLIM, lval);
706c688e0c4SMarek Vasut 	case POWER_SUPPLY_PROP_ONLINE:
707c688e0c4SMarek Vasut 		ret = bq25890_field_write(bq, F_EN_HIZ, !val->intval);
708c688e0c4SMarek Vasut 		if (!ret)
709c688e0c4SMarek Vasut 			bq->force_hiz = !val->intval;
710c688e0c4SMarek Vasut 		bq25890_update_state(bq, psp, &state);
711c688e0c4SMarek Vasut 		return ret;
7124a4748f2SMarek Vasut 	default:
7134a4748f2SMarek Vasut 		return -EINVAL;
7144a4748f2SMarek Vasut 	}
7154a4748f2SMarek Vasut }
7164a4748f2SMarek Vasut 
bq25890_power_supply_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)7174a4748f2SMarek Vasut static int bq25890_power_supply_property_is_writeable(struct power_supply *psy,
7184a4748f2SMarek Vasut 						      enum power_supply_property psp)
7194a4748f2SMarek Vasut {
7204a4748f2SMarek Vasut 	switch (psp) {
721b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
722b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
7234a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
724c688e0c4SMarek Vasut 	case POWER_SUPPLY_PROP_ONLINE:
7254a4748f2SMarek Vasut 		return true;
7264a4748f2SMarek Vasut 	default:
7274a4748f2SMarek Vasut 		return false;
7284a4748f2SMarek Vasut 	}
7294a4748f2SMarek Vasut }
7304a4748f2SMarek Vasut 
7316adaa9a4SHans de Goede /*
7326adaa9a4SHans de Goede  * If there are multiple chargers the maximum current the external power-supply
7336adaa9a4SHans de Goede  * can deliver needs to be divided over the chargers. This is done according
7346adaa9a4SHans de Goede  * to the bq->iinlim_percentage setting.
7356adaa9a4SHans de Goede  */
bq25890_charger_get_scaled_iinlim_regval(struct bq25890_device * bq,int iinlim_ua)7366adaa9a4SHans de Goede static int bq25890_charger_get_scaled_iinlim_regval(struct bq25890_device *bq,
7376adaa9a4SHans de Goede 						    int iinlim_ua)
7386adaa9a4SHans de Goede {
7396adaa9a4SHans de Goede 	iinlim_ua = iinlim_ua * bq->iinlim_percentage / 100;
7406adaa9a4SHans de Goede 	return bq25890_find_idx(iinlim_ua, TBL_IINLIM);
7416adaa9a4SHans de Goede }
7426adaa9a4SHans de Goede 
743eab25b4fSHans de Goede /* On the BQ25892 try to get charger-type info from our supplier */
bq25890_charger_external_power_changed(struct power_supply * psy)744eab25b4fSHans de Goede static void bq25890_charger_external_power_changed(struct power_supply *psy)
745eab25b4fSHans de Goede {
746eab25b4fSHans de Goede 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
747eab25b4fSHans de Goede 	union power_supply_propval val;
748eab25b4fSHans de Goede 	int input_current_limit, ret;
749eab25b4fSHans de Goede 
750eab25b4fSHans de Goede 	if (bq->chip_version != BQ25892)
751eab25b4fSHans de Goede 		return;
752eab25b4fSHans de Goede 
753029a443bSHans de Goede 	ret = power_supply_get_property_from_supplier(psy,
754eab25b4fSHans de Goede 						      POWER_SUPPLY_PROP_USB_TYPE,
755eab25b4fSHans de Goede 						      &val);
756eab25b4fSHans de Goede 	if (ret)
757eab25b4fSHans de Goede 		return;
758eab25b4fSHans de Goede 
759eab25b4fSHans de Goede 	switch (val.intval) {
760eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_DCP:
7616adaa9a4SHans de Goede 		input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, 2000000);
76248f45b09SYauhen Kharuzhy 		if (bq->pump_express_vbus_max) {
76348f45b09SYauhen Kharuzhy 			queue_delayed_work(system_power_efficient_wq,
76448f45b09SYauhen Kharuzhy 					   &bq->pump_express_work,
76548f45b09SYauhen Kharuzhy 					   PUMP_EXPRESS_START_DELAY);
76648f45b09SYauhen Kharuzhy 		}
767eab25b4fSHans de Goede 		break;
768eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_CDP:
769eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_ACA:
7706adaa9a4SHans de Goede 		input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, 1500000);
771eab25b4fSHans de Goede 		break;
772eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_SDP:
773eab25b4fSHans de Goede 	default:
7746adaa9a4SHans de Goede 		input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, 500000);
775eab25b4fSHans de Goede 	}
776eab25b4fSHans de Goede 
777eab25b4fSHans de Goede 	bq25890_field_write(bq, F_IINLIM, input_current_limit);
778*ad3d9c77SHans de Goede 	power_supply_changed(psy);
779eab25b4fSHans de Goede }
780eab25b4fSHans de Goede 
bq25890_get_chip_state(struct bq25890_device * bq,struct bq25890_state * state)7818c0984e5SSebastian Reichel static int bq25890_get_chip_state(struct bq25890_device *bq,
7828c0984e5SSebastian Reichel 				  struct bq25890_state *state)
7838c0984e5SSebastian Reichel {
7848c0984e5SSebastian Reichel 	int i, ret;
7858c0984e5SSebastian Reichel 
7868c0984e5SSebastian Reichel 	struct {
7878c0984e5SSebastian Reichel 		enum bq25890_fields id;
7888c0984e5SSebastian Reichel 		u8 *data;
7898c0984e5SSebastian Reichel 	} state_fields[] = {
7908c0984e5SSebastian Reichel 		{F_CHG_STAT,	&state->chrg_status},
7918c0984e5SSebastian Reichel 		{F_PG_STAT,	&state->online},
792c688e0c4SMarek Vasut 		{F_EN_HIZ,	&state->hiz},
7938c0984e5SSebastian Reichel 		{F_VSYS_STAT,	&state->vsys_status},
7948c0984e5SSebastian Reichel 		{F_BOOST_FAULT, &state->boost_fault},
7958c0984e5SSebastian Reichel 		{F_BAT_FAULT,	&state->bat_fault},
796c562a43aSYauhen Kharuzhy 		{F_CHG_FAULT,	&state->chrg_fault},
797c562a43aSYauhen Kharuzhy 		{F_NTC_FAULT,	&state->ntc_fault}
7988c0984e5SSebastian Reichel 	};
7998c0984e5SSebastian Reichel 
8008c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(state_fields); i++) {
8018c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, state_fields[i].id);
8028c0984e5SSebastian Reichel 		if (ret < 0)
8038c0984e5SSebastian Reichel 			return ret;
8048c0984e5SSebastian Reichel 
8058c0984e5SSebastian Reichel 		*state_fields[i].data = ret;
8068c0984e5SSebastian Reichel 	}
8078c0984e5SSebastian Reichel 
808c688e0c4SMarek Vasut 	dev_dbg(bq->dev, "S:CHG/PG/HIZ/VSYS=%d/%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
809c688e0c4SMarek Vasut 		state->chrg_status, state->online,
810c688e0c4SMarek Vasut 		state->hiz, state->vsys_status,
811c688e0c4SMarek Vasut 		state->chrg_fault, state->boost_fault,
812c688e0c4SMarek Vasut 		state->bat_fault, state->ntc_fault);
8138c0984e5SSebastian Reichel 
8148c0984e5SSebastian Reichel 	return 0;
8158c0984e5SSebastian Reichel }
8168c0984e5SSebastian Reichel 
__bq25890_handle_irq(struct bq25890_device * bq)81772d9cd9cSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
8188c0984e5SSebastian Reichel {
8194413f9e9SHans de Goede 	bool adc_conv_rate, new_adc_conv_rate;
82072d9cd9cSMichał Mirosław 	struct bq25890_state new_state;
8218c0984e5SSebastian Reichel 	int ret;
8228c0984e5SSebastian Reichel 
82372d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &new_state);
82472d9cd9cSMichał Mirosław 	if (ret < 0)
82572d9cd9cSMichał Mirosław 		return IRQ_NONE;
8268c0984e5SSebastian Reichel 
82772d9cd9cSMichał Mirosław 	if (!memcmp(&bq->state, &new_state, sizeof(new_state)))
82872d9cd9cSMichał Mirosław 		return IRQ_NONE;
82972d9cd9cSMichał Mirosław 
830c688e0c4SMarek Vasut 	/*
8314413f9e9SHans de Goede 	 * Restore HiZ bit in case it was set by user. The chip does not retain
8324413f9e9SHans de Goede 	 * this bit on cable replug, hence the bit must be reset manually here.
833c688e0c4SMarek Vasut 	 */
8344413f9e9SHans de Goede 	if (new_state.online && !bq->state.online && bq->force_hiz) {
835c688e0c4SMarek Vasut 		ret = bq25890_field_write(bq, F_EN_HIZ, bq->force_hiz);
836c688e0c4SMarek Vasut 		if (ret < 0)
837c688e0c4SMarek Vasut 			goto error;
838c688e0c4SMarek Vasut 		new_state.hiz = 1;
839c688e0c4SMarek Vasut 	}
840c688e0c4SMarek Vasut 
8414413f9e9SHans de Goede 	/* Should period ADC sampling be enabled? */
8424413f9e9SHans de Goede 	adc_conv_rate = bq->state.online && !bq->state.hiz;
8434413f9e9SHans de Goede 	new_adc_conv_rate = new_state.online && !new_state.hiz;
8444413f9e9SHans de Goede 
8454413f9e9SHans de Goede 	if (new_adc_conv_rate != adc_conv_rate) {
8464413f9e9SHans de Goede 		ret = bq25890_field_write(bq, F_CONV_RATE, new_adc_conv_rate);
8478c0984e5SSebastian Reichel 		if (ret < 0)
8488c0984e5SSebastian Reichel 			goto error;
8498c0984e5SSebastian Reichel 	}
8508c0984e5SSebastian Reichel 
85172d9cd9cSMichał Mirosław 	bq->state = new_state;
85272d9cd9cSMichał Mirosław 	power_supply_changed(bq->charger);
8538c0984e5SSebastian Reichel 
85472d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
8558c0984e5SSebastian Reichel error:
85672d9cd9cSMichał Mirosław 	dev_err(bq->dev, "Error communicating with the chip: %pe\n",
85772d9cd9cSMichał Mirosław 		ERR_PTR(ret));
85872d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
8598c0984e5SSebastian Reichel }
8608c0984e5SSebastian Reichel 
bq25890_irq_handler_thread(int irq,void * private)8618c0984e5SSebastian Reichel static irqreturn_t bq25890_irq_handler_thread(int irq, void *private)
8628c0984e5SSebastian Reichel {
8638c0984e5SSebastian Reichel 	struct bq25890_device *bq = private;
86472d9cd9cSMichał Mirosław 	irqreturn_t ret;
8658c0984e5SSebastian Reichel 
8668c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
86772d9cd9cSMichał Mirosław 	ret = __bq25890_handle_irq(bq);
8688c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
8698c0984e5SSebastian Reichel 
87072d9cd9cSMichał Mirosław 	return ret;
8718c0984e5SSebastian Reichel }
8728c0984e5SSebastian Reichel 
bq25890_chip_reset(struct bq25890_device * bq)8738c0984e5SSebastian Reichel static int bq25890_chip_reset(struct bq25890_device *bq)
8748c0984e5SSebastian Reichel {
8758c0984e5SSebastian Reichel 	int ret;
8768c0984e5SSebastian Reichel 	int rst_check_counter = 10;
8778c0984e5SSebastian Reichel 
8788c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_REG_RST, 1);
8798c0984e5SSebastian Reichel 	if (ret < 0)
8808c0984e5SSebastian Reichel 		return ret;
8818c0984e5SSebastian Reichel 
8828c0984e5SSebastian Reichel 	do {
8838c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, F_REG_RST);
8848c0984e5SSebastian Reichel 		if (ret < 0)
8858c0984e5SSebastian Reichel 			return ret;
8868c0984e5SSebastian Reichel 
8878c0984e5SSebastian Reichel 		usleep_range(5, 10);
8888c0984e5SSebastian Reichel 	} while (ret == 1 && --rst_check_counter);
8898c0984e5SSebastian Reichel 
8908c0984e5SSebastian Reichel 	if (!rst_check_counter)
8918c0984e5SSebastian Reichel 		return -ETIMEDOUT;
8928c0984e5SSebastian Reichel 
8938c0984e5SSebastian Reichel 	return 0;
8948c0984e5SSebastian Reichel }
8958c0984e5SSebastian Reichel 
bq25890_rw_init_data(struct bq25890_device * bq)8967b22a974SHans de Goede static int bq25890_rw_init_data(struct bq25890_device *bq)
8978c0984e5SSebastian Reichel {
89840428bd4SHans de Goede 	bool write = !bq->read_back_init_data;
8998c0984e5SSebastian Reichel 	int ret;
9008c0984e5SSebastian Reichel 	int i;
9018c0984e5SSebastian Reichel 
9028c0984e5SSebastian Reichel 	const struct {
9038c0984e5SSebastian Reichel 		enum bq25890_fields id;
9047b22a974SHans de Goede 		u8 *value;
9058c0984e5SSebastian Reichel 	} init_data[] = {
9067b22a974SHans de Goede 		{F_ICHG,	 &bq->init_data.ichg},
9077b22a974SHans de Goede 		{F_VREG,	 &bq->init_data.vreg},
9087b22a974SHans de Goede 		{F_ITERM,	 &bq->init_data.iterm},
9097b22a974SHans de Goede 		{F_IPRECHG,	 &bq->init_data.iprechg},
9107b22a974SHans de Goede 		{F_SYSVMIN,	 &bq->init_data.sysvmin},
9117b22a974SHans de Goede 		{F_BOOSTV,	 &bq->init_data.boostv},
9127b22a974SHans de Goede 		{F_BOOSTI,	 &bq->init_data.boosti},
9137b22a974SHans de Goede 		{F_BOOSTF,	 &bq->init_data.boostf},
9147b22a974SHans de Goede 		{F_EN_ILIM,	 &bq->init_data.ilim_en},
9157b22a974SHans de Goede 		{F_TREG,	 &bq->init_data.treg},
9167b22a974SHans de Goede 		{F_BATCMP,	 &bq->init_data.rbatcomp},
9177b22a974SHans de Goede 		{F_VCLAMP,	 &bq->init_data.vclamp},
9188c0984e5SSebastian Reichel 	};
9198c0984e5SSebastian Reichel 
9207b22a974SHans de Goede 	for (i = 0; i < ARRAY_SIZE(init_data); i++) {
9217b22a974SHans de Goede 		if (write) {
9227b22a974SHans de Goede 			ret = bq25890_field_write(bq, init_data[i].id,
9237b22a974SHans de Goede 						  *init_data[i].value);
9247b22a974SHans de Goede 		} else {
9257b22a974SHans de Goede 			ret = bq25890_field_read(bq, init_data[i].id);
9267b22a974SHans de Goede 			if (ret >= 0)
9277b22a974SHans de Goede 				*init_data[i].value = ret;
9287b22a974SHans de Goede 		}
9297b22a974SHans de Goede 		if (ret < 0) {
9307b22a974SHans de Goede 			dev_dbg(bq->dev, "Accessing init data failed %d\n", ret);
9317b22a974SHans de Goede 			return ret;
9327b22a974SHans de Goede 		}
9337b22a974SHans de Goede 	}
9347b22a974SHans de Goede 
9357b22a974SHans de Goede 	return 0;
9367b22a974SHans de Goede }
9377b22a974SHans de Goede 
bq25890_hw_init(struct bq25890_device * bq)9387b22a974SHans de Goede static int bq25890_hw_init(struct bq25890_device *bq)
9397b22a974SHans de Goede {
9407b22a974SHans de Goede 	int ret;
9417b22a974SHans de Goede 
9427e3b8e35SHans de Goede 	if (!bq->skip_reset) {
9438c0984e5SSebastian Reichel 		ret = bq25890_chip_reset(bq);
9449d9ae341SAngus Ainslie (Purism) 		if (ret < 0) {
9459d9ae341SAngus Ainslie (Purism) 			dev_dbg(bq->dev, "Reset failed %d\n", ret);
9468c0984e5SSebastian Reichel 			return ret;
947ad1570d9Skbuild test robot 		}
94806c75095SHans de Goede 	} else {
94906c75095SHans de Goede 		/*
95006c75095SHans de Goede 		 * Ensure charging is enabled, on some boards where the fw
95106c75095SHans de Goede 		 * takes care of initalizition F_CHG_CFG is set to 0 before
95206c75095SHans de Goede 		 * handing control over to the OS.
95306c75095SHans de Goede 		 */
95406c75095SHans de Goede 		ret = bq25890_field_write(bq, F_CHG_CFG, 1);
95506c75095SHans de Goede 		if (ret < 0) {
95606c75095SHans de Goede 			dev_dbg(bq->dev, "Enabling charging failed %d\n", ret);
95706c75095SHans de Goede 			return ret;
95806c75095SHans de Goede 		}
9597e3b8e35SHans de Goede 	}
9608c0984e5SSebastian Reichel 
9618c0984e5SSebastian Reichel 	/* disable watchdog */
9628c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_WD, 0);
9639d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
9649d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret);
9658c0984e5SSebastian Reichel 		return ret;
966ad1570d9Skbuild test robot 	}
9678c0984e5SSebastian Reichel 
9688c0984e5SSebastian Reichel 	/* initialize currents/voltages and other parameters */
9697b22a974SHans de Goede 	ret = bq25890_rw_init_data(bq);
9707b22a974SHans de Goede 	if (ret)
9718c0984e5SSebastian Reichel 		return ret;
9728c0984e5SSebastian Reichel 
97322ad4f99SHans de Goede 	ret = bq25890_get_chip_state(bq, &bq->state);
97422ad4f99SHans de Goede 	if (ret < 0) {
97522ad4f99SHans de Goede 		dev_dbg(bq->dev, "Get state failed %d\n", ret);
97622ad4f99SHans de Goede 		return ret;
97722ad4f99SHans de Goede 	}
97822ad4f99SHans de Goede 
97921d90edaSMichał Mirosław 	/* Configure ADC for continuous conversions when charging */
980dee0df84SHans de Goede 	ret = bq25890_field_write(bq, F_CONV_RATE, bq->state.online && !bq->state.hiz);
9819d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
9829d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
9838c0984e5SSebastian Reichel 		return ret;
984ad1570d9Skbuild test robot 	}
9858c0984e5SSebastian Reichel 
9868c0984e5SSebastian Reichel 	return 0;
9878c0984e5SSebastian Reichel }
9888c0984e5SSebastian Reichel 
989a6a48facSMichał Mirosław static const enum power_supply_property bq25890_power_supply_props[] = {
9908c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MANUFACTURER,
9912e1a2ddeSAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_MODEL_NAME,
9928c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
993b302a0aeSMichał Mirosław 	POWER_SUPPLY_PROP_CHARGE_TYPE,
9948c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
9958c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_HEALTH,
9968327a8abSMarek Vasut 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
9978c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
9988c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
9998c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
1000c942656dSMichał Mirosław 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
10018c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
1002478efc79SMichał Mirosław 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
1003ae6fe7a3SAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
10041e4724d0SMichał Mirosław 	POWER_SUPPLY_PROP_CURRENT_NOW,
10059652c024SAngus Ainslie 	POWER_SUPPLY_PROP_TEMP,
10068c0984e5SSebastian Reichel };
10078c0984e5SSebastian Reichel 
10088c0984e5SSebastian Reichel static char *bq25890_charger_supplied_to[] = {
10098c0984e5SSebastian Reichel 	"main-battery",
10108c0984e5SSebastian Reichel };
10118c0984e5SSebastian Reichel 
10128c0984e5SSebastian Reichel static const struct power_supply_desc bq25890_power_supply_desc = {
10138c0984e5SSebastian Reichel 	.type = POWER_SUPPLY_TYPE_USB,
10148c0984e5SSebastian Reichel 	.properties = bq25890_power_supply_props,
10158c0984e5SSebastian Reichel 	.num_properties = ARRAY_SIZE(bq25890_power_supply_props),
10168c0984e5SSebastian Reichel 	.get_property = bq25890_power_supply_get_property,
10174a4748f2SMarek Vasut 	.set_property = bq25890_power_supply_set_property,
10184a4748f2SMarek Vasut 	.property_is_writeable = bq25890_power_supply_property_is_writeable,
1019eab25b4fSHans de Goede 	.external_power_changed	= bq25890_charger_external_power_changed,
10208c0984e5SSebastian Reichel };
10218c0984e5SSebastian Reichel 
bq25890_power_supply_init(struct bq25890_device * bq)10228c0984e5SSebastian Reichel static int bq25890_power_supply_init(struct bq25890_device *bq)
10238c0984e5SSebastian Reichel {
10248c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = { .drv_data = bq, };
10258c0984e5SSebastian Reichel 
10264e9498b8SHans de Goede 	/* Get ID for the device */
10274e9498b8SHans de Goede 	mutex_lock(&bq25890_id_mutex);
10284e9498b8SHans de Goede 	bq->id = idr_alloc(&bq25890_id, bq, 0, 0, GFP_KERNEL);
10294e9498b8SHans de Goede 	mutex_unlock(&bq25890_id_mutex);
10304e9498b8SHans de Goede 	if (bq->id < 0)
10314e9498b8SHans de Goede 		return bq->id;
10324e9498b8SHans de Goede 
10334e9498b8SHans de Goede 	snprintf(bq->name, sizeof(bq->name), "bq25890-charger-%d", bq->id);
10344e9498b8SHans de Goede 	bq->desc = bq25890_power_supply_desc;
10354e9498b8SHans de Goede 	bq->desc.name = bq->name;
10364e9498b8SHans de Goede 
10378c0984e5SSebastian Reichel 	psy_cfg.supplied_to = bq25890_charger_supplied_to;
10388c0984e5SSebastian Reichel 	psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
10398c0984e5SSebastian Reichel 
10404e9498b8SHans de Goede 	bq->charger = devm_power_supply_register(bq->dev, &bq->desc, &psy_cfg);
10418c0984e5SSebastian Reichel 
10428c0984e5SSebastian Reichel 	return PTR_ERR_OR_ZERO(bq->charger);
10438c0984e5SSebastian Reichel }
10448c0984e5SSebastian Reichel 
bq25890_set_otg_cfg(struct bq25890_device * bq,u8 val)10455575802dSHans de Goede static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val)
10465575802dSHans de Goede {
10475575802dSHans de Goede 	int ret;
10485575802dSHans de Goede 
10495575802dSHans de Goede 	ret = bq25890_field_write(bq, F_OTG_CFG, val);
10505575802dSHans de Goede 	if (ret < 0)
10515575802dSHans de Goede 		dev_err(bq->dev, "Error switching to boost/charger mode: %d\n", ret);
10525575802dSHans de Goede 
10535575802dSHans de Goede 	return ret;
10545575802dSHans de Goede }
10555575802dSHans de Goede 
bq25890_pump_express_work(struct work_struct * data)105648f45b09SYauhen Kharuzhy static void bq25890_pump_express_work(struct work_struct *data)
105748f45b09SYauhen Kharuzhy {
105848f45b09SYauhen Kharuzhy 	struct bq25890_device *bq =
105948f45b09SYauhen Kharuzhy 		container_of(data, struct bq25890_device, pump_express_work.work);
1060d54bf877SHans de Goede 	union power_supply_propval value;
106148f45b09SYauhen Kharuzhy 	int voltage, i, ret;
106248f45b09SYauhen Kharuzhy 
106348f45b09SYauhen Kharuzhy 	dev_dbg(bq->dev, "Start to request input voltage increasing\n");
106448f45b09SYauhen Kharuzhy 
1065d54bf877SHans de Goede 	/* If there is a second charger put in Hi-Z mode */
1066d54bf877SHans de Goede 	if (bq->secondary_chrg) {
1067d54bf877SHans de Goede 		value.intval = 0;
1068d54bf877SHans de Goede 		power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value);
1069d54bf877SHans de Goede 	}
1070d54bf877SHans de Goede 
107148f45b09SYauhen Kharuzhy 	/* Enable current pulse voltage control protocol */
107248f45b09SYauhen Kharuzhy 	ret = bq25890_field_write(bq, F_PUMPX_EN, 1);
107348f45b09SYauhen Kharuzhy 	if (ret < 0)
107448f45b09SYauhen Kharuzhy 		goto error_print;
107548f45b09SYauhen Kharuzhy 
107648f45b09SYauhen Kharuzhy 	for (i = 0; i < PUMP_EXPRESS_MAX_TRIES; i++) {
107748f45b09SYauhen Kharuzhy 		voltage = bq25890_get_vbus_voltage(bq);
107848f45b09SYauhen Kharuzhy 		if (voltage < 0)
107948f45b09SYauhen Kharuzhy 			goto error_print;
108048f45b09SYauhen Kharuzhy 		dev_dbg(bq->dev, "input voltage = %d uV\n", voltage);
108148f45b09SYauhen Kharuzhy 
108248f45b09SYauhen Kharuzhy 		if ((voltage + PUMP_EXPRESS_VBUS_MARGIN_uV) >
108348f45b09SYauhen Kharuzhy 					bq->pump_express_vbus_max)
108448f45b09SYauhen Kharuzhy 			break;
108548f45b09SYauhen Kharuzhy 
108648f45b09SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_PUMPX_UP, 1);
108748f45b09SYauhen Kharuzhy 		if (ret < 0)
108848f45b09SYauhen Kharuzhy 			goto error_print;
108948f45b09SYauhen Kharuzhy 
109048f45b09SYauhen Kharuzhy 		/* Note a single PUMPX up pulse-sequence takes 2.1s */
109148f45b09SYauhen Kharuzhy 		ret = regmap_field_read_poll_timeout(bq->rmap_fields[F_PUMPX_UP],
109248f45b09SYauhen Kharuzhy 						     ret, !ret, 100000, 3000000);
109348f45b09SYauhen Kharuzhy 		if (ret < 0)
109448f45b09SYauhen Kharuzhy 			goto error_print;
109548f45b09SYauhen Kharuzhy 
109648f45b09SYauhen Kharuzhy 		/* Make sure ADC has sampled Vbus before checking again */
109748f45b09SYauhen Kharuzhy 		msleep(1000);
109848f45b09SYauhen Kharuzhy 	}
109948f45b09SYauhen Kharuzhy 
110048f45b09SYauhen Kharuzhy 	bq25890_field_write(bq, F_PUMPX_EN, 0);
110148f45b09SYauhen Kharuzhy 
1102d54bf877SHans de Goede 	if (bq->secondary_chrg) {
1103d54bf877SHans de Goede 		value.intval = 1;
1104d54bf877SHans de Goede 		power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value);
1105d54bf877SHans de Goede 	}
1106d54bf877SHans de Goede 
110748f45b09SYauhen Kharuzhy 	dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n",
110848f45b09SYauhen Kharuzhy 		 voltage);
110948f45b09SYauhen Kharuzhy 
1110*ad3d9c77SHans de Goede 	power_supply_changed(bq->charger);
1111*ad3d9c77SHans de Goede 
111248f45b09SYauhen Kharuzhy 	return;
111348f45b09SYauhen Kharuzhy error_print:
111404f7c7dfSHans de Goede 	bq25890_field_write(bq, F_PUMPX_EN, 0);
111548f45b09SYauhen Kharuzhy 	dev_err(bq->dev, "Failed to request hi-voltage charging\n");
111648f45b09SYauhen Kharuzhy }
111748f45b09SYauhen Kharuzhy 
bq25890_usb_work(struct work_struct * data)11188c0984e5SSebastian Reichel static void bq25890_usb_work(struct work_struct *data)
11198c0984e5SSebastian Reichel {
11208c0984e5SSebastian Reichel 	int ret;
11218c0984e5SSebastian Reichel 	struct bq25890_device *bq =
11228c0984e5SSebastian Reichel 			container_of(data, struct bq25890_device, usb_work);
11238c0984e5SSebastian Reichel 
11248c0984e5SSebastian Reichel 	switch (bq->usb_event) {
11258c0984e5SSebastian Reichel 	case USB_EVENT_ID:
11268c0984e5SSebastian Reichel 		/* Enable boost mode */
11275575802dSHans de Goede 		bq25890_set_otg_cfg(bq, 1);
11288c0984e5SSebastian Reichel 		break;
11298c0984e5SSebastian Reichel 
11308c0984e5SSebastian Reichel 	case USB_EVENT_NONE:
11318c0984e5SSebastian Reichel 		/* Disable boost mode */
11325575802dSHans de Goede 		ret = bq25890_set_otg_cfg(bq, 0);
11335575802dSHans de Goede 		if (ret == 0)
11348c0984e5SSebastian Reichel 			power_supply_changed(bq->charger);
11358c0984e5SSebastian Reichel 		break;
11368c0984e5SSebastian Reichel 	}
11378c0984e5SSebastian Reichel }
11388c0984e5SSebastian Reichel 
bq25890_usb_notifier(struct notifier_block * nb,unsigned long val,void * priv)11398c0984e5SSebastian Reichel static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val,
11408c0984e5SSebastian Reichel 				void *priv)
11418c0984e5SSebastian Reichel {
11428c0984e5SSebastian Reichel 	struct bq25890_device *bq =
11438c0984e5SSebastian Reichel 			container_of(nb, struct bq25890_device, usb_nb);
11448c0984e5SSebastian Reichel 
11458c0984e5SSebastian Reichel 	bq->usb_event = val;
11468c0984e5SSebastian Reichel 	queue_work(system_power_efficient_wq, &bq->usb_work);
11478c0984e5SSebastian Reichel 
11488c0984e5SSebastian Reichel 	return NOTIFY_OK;
11498c0984e5SSebastian Reichel }
11508c0984e5SSebastian Reichel 
115179d35365SHans de Goede #ifdef CONFIG_REGULATOR
bq25890_vbus_enable(struct regulator_dev * rdev)115279d35365SHans de Goede static int bq25890_vbus_enable(struct regulator_dev *rdev)
115379d35365SHans de Goede {
115479d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
1155d54bf877SHans de Goede 	union power_supply_propval val = {
1156d54bf877SHans de Goede 		.intval = 0,
1157d54bf877SHans de Goede 	};
1158d54bf877SHans de Goede 
1159d54bf877SHans de Goede 	/*
1160d54bf877SHans de Goede 	 * When enabling 5V boost / Vbus output, we need to put the secondary
1161d54bf877SHans de Goede 	 * charger in Hi-Z mode to avoid it trying to charge the secondary
1162d54bf877SHans de Goede 	 * battery from the 5V boost output.
1163d54bf877SHans de Goede 	 */
1164d54bf877SHans de Goede 	if (bq->secondary_chrg)
1165d54bf877SHans de Goede 		power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val);
116679d35365SHans de Goede 
116779d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 1);
116879d35365SHans de Goede }
116979d35365SHans de Goede 
bq25890_vbus_disable(struct regulator_dev * rdev)117079d35365SHans de Goede static int bq25890_vbus_disable(struct regulator_dev *rdev)
117179d35365SHans de Goede {
117279d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
1173d54bf877SHans de Goede 	union power_supply_propval val = {
1174d54bf877SHans de Goede 		.intval = 1,
1175d54bf877SHans de Goede 	};
1176d54bf877SHans de Goede 	int ret;
117779d35365SHans de Goede 
1178d54bf877SHans de Goede 	ret = bq25890_set_otg_cfg(bq, 0);
1179d54bf877SHans de Goede 	if (ret)
1180d54bf877SHans de Goede 		return ret;
1181d54bf877SHans de Goede 
1182d54bf877SHans de Goede 	if (bq->secondary_chrg)
1183d54bf877SHans de Goede 		power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val);
1184d54bf877SHans de Goede 
1185d54bf877SHans de Goede 	return 0;
118679d35365SHans de Goede }
118779d35365SHans de Goede 
bq25890_vbus_is_enabled(struct regulator_dev * rdev)118879d35365SHans de Goede static int bq25890_vbus_is_enabled(struct regulator_dev *rdev)
118979d35365SHans de Goede {
119079d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
119179d35365SHans de Goede 
119279d35365SHans de Goede 	return bq25890_field_read(bq, F_OTG_CFG);
119379d35365SHans de Goede }
119479d35365SHans de Goede 
bq25890_vbus_get_voltage(struct regulator_dev * rdev)119585052e90SMarek Vasut static int bq25890_vbus_get_voltage(struct regulator_dev *rdev)
119685052e90SMarek Vasut {
119785052e90SMarek Vasut 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
119885052e90SMarek Vasut 
119985052e90SMarek Vasut 	return bq25890_get_vbus_voltage(bq);
120085052e90SMarek Vasut }
120185052e90SMarek Vasut 
bq25890_vsys_get_voltage(struct regulator_dev * rdev)120214a3d159SMarek Vasut static int bq25890_vsys_get_voltage(struct regulator_dev *rdev)
120314a3d159SMarek Vasut {
120414a3d159SMarek Vasut 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
120514a3d159SMarek Vasut 	int ret;
120614a3d159SMarek Vasut 
120714a3d159SMarek Vasut 	/* Should be some output voltage ? */
120814a3d159SMarek Vasut 	ret = bq25890_field_read(bq, F_SYSV); /* read measured value */
120914a3d159SMarek Vasut 	if (ret < 0)
121014a3d159SMarek Vasut 		return ret;
121114a3d159SMarek Vasut 
121214a3d159SMarek Vasut 	/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
121314a3d159SMarek Vasut 	return 2304000 + ret * 20000;
121414a3d159SMarek Vasut }
121514a3d159SMarek Vasut 
121679d35365SHans de Goede static const struct regulator_ops bq25890_vbus_ops = {
121779d35365SHans de Goede 	.enable = bq25890_vbus_enable,
121879d35365SHans de Goede 	.disable = bq25890_vbus_disable,
121979d35365SHans de Goede 	.is_enabled = bq25890_vbus_is_enabled,
122085052e90SMarek Vasut 	.get_voltage = bq25890_vbus_get_voltage,
122179d35365SHans de Goede };
122279d35365SHans de Goede 
122379d35365SHans de Goede static const struct regulator_desc bq25890_vbus_desc = {
122479d35365SHans de Goede 	.name = "usb_otg_vbus",
122579d35365SHans de Goede 	.of_match = "usb-otg-vbus",
122679d35365SHans de Goede 	.type = REGULATOR_VOLTAGE,
122779d35365SHans de Goede 	.owner = THIS_MODULE,
122879d35365SHans de Goede 	.ops = &bq25890_vbus_ops,
122979d35365SHans de Goede };
12305f5c10ecSMarek Vasut 
123114a3d159SMarek Vasut static const struct regulator_ops bq25890_vsys_ops = {
123214a3d159SMarek Vasut 	.get_voltage = bq25890_vsys_get_voltage,
123314a3d159SMarek Vasut };
123414a3d159SMarek Vasut 
123514a3d159SMarek Vasut static const struct regulator_desc bq25890_vsys_desc = {
123614a3d159SMarek Vasut 	.name = "vsys",
123714a3d159SMarek Vasut 	.of_match = "vsys",
123814a3d159SMarek Vasut 	.type = REGULATOR_VOLTAGE,
123914a3d159SMarek Vasut 	.owner = THIS_MODULE,
124014a3d159SMarek Vasut 	.ops = &bq25890_vsys_ops,
124114a3d159SMarek Vasut };
124214a3d159SMarek Vasut 
bq25890_register_regulator(struct bq25890_device * bq)12435f5c10ecSMarek Vasut static int bq25890_register_regulator(struct bq25890_device *bq)
12445f5c10ecSMarek Vasut {
12455f5c10ecSMarek Vasut 	struct bq25890_platform_data *pdata = dev_get_platdata(bq->dev);
12465f5c10ecSMarek Vasut 	struct regulator_config cfg = {
12475f5c10ecSMarek Vasut 		.dev = bq->dev,
12485f5c10ecSMarek Vasut 		.driver_data = bq,
12495f5c10ecSMarek Vasut 	};
12505f5c10ecSMarek Vasut 	struct regulator_dev *reg;
12515f5c10ecSMarek Vasut 
12525f5c10ecSMarek Vasut 	if (pdata)
12535f5c10ecSMarek Vasut 		cfg.init_data = pdata->regulator_init_data;
12545f5c10ecSMarek Vasut 
12555f5c10ecSMarek Vasut 	reg = devm_regulator_register(bq->dev, &bq25890_vbus_desc, &cfg);
12565f5c10ecSMarek Vasut 	if (IS_ERR(reg)) {
12575f5c10ecSMarek Vasut 		return dev_err_probe(bq->dev, PTR_ERR(reg),
12585f5c10ecSMarek Vasut 				     "registering vbus regulator");
12595f5c10ecSMarek Vasut 	}
12605f5c10ecSMarek Vasut 
1261571650b3SHans de Goede 	/* pdata->regulator_init_data is for vbus only */
1262571650b3SHans de Goede 	cfg.init_data = NULL;
126314a3d159SMarek Vasut 	reg = devm_regulator_register(bq->dev, &bq25890_vsys_desc, &cfg);
126414a3d159SMarek Vasut 	if (IS_ERR(reg)) {
126514a3d159SMarek Vasut 		return dev_err_probe(bq->dev, PTR_ERR(reg),
126614a3d159SMarek Vasut 				     "registering vsys regulator");
126714a3d159SMarek Vasut 	}
126814a3d159SMarek Vasut 
12695f5c10ecSMarek Vasut 	return 0;
12705f5c10ecSMarek Vasut }
12715f5c10ecSMarek Vasut #else
12725f5c10ecSMarek Vasut static inline int
bq25890_register_regulator(struct bq25890_device * bq)12735f5c10ecSMarek Vasut bq25890_register_regulator(struct bq25890_device *bq)
12745f5c10ecSMarek Vasut {
12755f5c10ecSMarek Vasut 	return 0;
12765f5c10ecSMarek Vasut }
127779d35365SHans de Goede #endif
127879d35365SHans de Goede 
bq25890_get_chip_version(struct bq25890_device * bq)1279d20267c9SYauhen Kharuzhy static int bq25890_get_chip_version(struct bq25890_device *bq)
1280d20267c9SYauhen Kharuzhy {
1281d20267c9SYauhen Kharuzhy 	int id, rev;
1282d20267c9SYauhen Kharuzhy 
1283d20267c9SYauhen Kharuzhy 	id = bq25890_field_read(bq, F_PN);
1284d20267c9SYauhen Kharuzhy 	if (id < 0) {
1285172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip ID: %d\n", id);
1286d20267c9SYauhen Kharuzhy 		return id;
1287d20267c9SYauhen Kharuzhy 	}
1288d20267c9SYauhen Kharuzhy 
1289d20267c9SYauhen Kharuzhy 	rev = bq25890_field_read(bq, F_DEV_REV);
1290d20267c9SYauhen Kharuzhy 	if (rev < 0) {
1291172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip revision: %d\n", rev);
1292cb619e80SColin Ian King 		return rev;
1293d20267c9SYauhen Kharuzhy 	}
1294d20267c9SYauhen Kharuzhy 
1295d20267c9SYauhen Kharuzhy 	switch (id) {
1296d20267c9SYauhen Kharuzhy 	case BQ25890_ID:
1297d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25890;
1298d20267c9SYauhen Kharuzhy 		break;
1299d20267c9SYauhen Kharuzhy 
1300d20267c9SYauhen Kharuzhy 	/* BQ25892 and BQ25896 share same ID 0 */
1301d20267c9SYauhen Kharuzhy 	case BQ25896_ID:
1302d20267c9SYauhen Kharuzhy 		switch (rev) {
1303d20267c9SYauhen Kharuzhy 		case 2:
1304d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25896;
1305d20267c9SYauhen Kharuzhy 			break;
1306d20267c9SYauhen Kharuzhy 		case 1:
1307d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1308d20267c9SYauhen Kharuzhy 			break;
1309d20267c9SYauhen Kharuzhy 		default:
1310d20267c9SYauhen Kharuzhy 			dev_err(bq->dev,
1311d20267c9SYauhen Kharuzhy 				"Unknown device revision %d, assume BQ25892\n",
1312d20267c9SYauhen Kharuzhy 				rev);
1313d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1314d20267c9SYauhen Kharuzhy 		}
1315d20267c9SYauhen Kharuzhy 		break;
1316d20267c9SYauhen Kharuzhy 
1317d20267c9SYauhen Kharuzhy 	case BQ25895_ID:
1318d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25895;
1319d20267c9SYauhen Kharuzhy 		break;
1320d20267c9SYauhen Kharuzhy 
1321d20267c9SYauhen Kharuzhy 	default:
1322d20267c9SYauhen Kharuzhy 		dev_err(bq->dev, "Unknown chip ID %d\n", id);
1323d20267c9SYauhen Kharuzhy 		return -ENODEV;
1324d20267c9SYauhen Kharuzhy 	}
1325d20267c9SYauhen Kharuzhy 
1326d20267c9SYauhen Kharuzhy 	return 0;
1327d20267c9SYauhen Kharuzhy }
1328d20267c9SYauhen Kharuzhy 
bq25890_irq_probe(struct bq25890_device * bq)13298c0984e5SSebastian Reichel static int bq25890_irq_probe(struct bq25890_device *bq)
13308c0984e5SSebastian Reichel {
13318c0984e5SSebastian Reichel 	struct gpio_desc *irq;
13328c0984e5SSebastian Reichel 
133386775879SAndy Shevchenko 	irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN);
1334172d0cceSMartin Kepplinger 	if (IS_ERR(irq))
1335172d0cceSMartin Kepplinger 		return dev_err_probe(bq->dev, PTR_ERR(irq),
1336172d0cceSMartin Kepplinger 				     "Could not probe irq pin.\n");
13378c0984e5SSebastian Reichel 
13388c0984e5SSebastian Reichel 	return gpiod_to_irq(irq);
13398c0984e5SSebastian Reichel }
13408c0984e5SSebastian Reichel 
bq25890_fw_read_u32_props(struct bq25890_device * bq)13418c0984e5SSebastian Reichel static int bq25890_fw_read_u32_props(struct bq25890_device *bq)
13428c0984e5SSebastian Reichel {
13438c0984e5SSebastian Reichel 	int ret;
13448c0984e5SSebastian Reichel 	u32 property;
13458c0984e5SSebastian Reichel 	int i;
13468c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
13478c0984e5SSebastian Reichel 	struct {
13488c0984e5SSebastian Reichel 		char *name;
13498c0984e5SSebastian Reichel 		bool optional;
13508c0984e5SSebastian Reichel 		enum bq25890_table_ids tbl_id;
13518c0984e5SSebastian Reichel 		u8 *conv_data; /* holds converted value from given property */
13528c0984e5SSebastian Reichel 	} props[] = {
13538c0984e5SSebastian Reichel 		/* required properties */
13548c0984e5SSebastian Reichel 		{"ti,charge-current", false, TBL_ICHG, &init->ichg},
13558c0984e5SSebastian Reichel 		{"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg},
13568c0984e5SSebastian Reichel 		{"ti,termination-current", false, TBL_ITERM, &init->iterm},
13578c0984e5SSebastian Reichel 		{"ti,precharge-current", false, TBL_ITERM, &init->iprechg},
13588c0984e5SSebastian Reichel 		{"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin},
13598c0984e5SSebastian Reichel 		{"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv},
13608c0984e5SSebastian Reichel 		{"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti},
13618c0984e5SSebastian Reichel 
13628c0984e5SSebastian Reichel 		/* optional properties */
136372408329SMichał Mirosław 		{"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg},
136472408329SMichał Mirosław 		{"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp},
136572408329SMichał Mirosław 		{"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp},
13668c0984e5SSebastian Reichel 	};
13678c0984e5SSebastian Reichel 
13688c0984e5SSebastian Reichel 	/* initialize data for optional properties */
13698c0984e5SSebastian Reichel 	init->treg = 3; /* 120 degrees Celsius */
137072408329SMichał Mirosław 	init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */
13718c0984e5SSebastian Reichel 
13728c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(props); i++) {
13738c0984e5SSebastian Reichel 		ret = device_property_read_u32(bq->dev, props[i].name,
13748c0984e5SSebastian Reichel 					       &property);
13758c0984e5SSebastian Reichel 		if (ret < 0) {
13768c0984e5SSebastian Reichel 			if (props[i].optional)
13778c0984e5SSebastian Reichel 				continue;
13788c0984e5SSebastian Reichel 
13799d9ae341SAngus Ainslie (Purism) 			dev_err(bq->dev, "Unable to read property %d %s\n", ret,
13809d9ae341SAngus Ainslie (Purism) 				props[i].name);
13819d9ae341SAngus Ainslie (Purism) 
13828c0984e5SSebastian Reichel 			return ret;
13838c0984e5SSebastian Reichel 		}
13848c0984e5SSebastian Reichel 
13858c0984e5SSebastian Reichel 		*props[i].conv_data = bq25890_find_idx(property,
13868c0984e5SSebastian Reichel 						       props[i].tbl_id);
13878c0984e5SSebastian Reichel 	}
13888c0984e5SSebastian Reichel 
13898c0984e5SSebastian Reichel 	return 0;
13908c0984e5SSebastian Reichel }
13918c0984e5SSebastian Reichel 
bq25890_fw_probe(struct bq25890_device * bq)13928c0984e5SSebastian Reichel static int bq25890_fw_probe(struct bq25890_device *bq)
13938c0984e5SSebastian Reichel {
13948c0984e5SSebastian Reichel 	int ret;
13958c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
1396d54bf877SHans de Goede 	const char *str;
13976adaa9a4SHans de Goede 	u32 val;
1398d54bf877SHans de Goede 
1399d54bf877SHans de Goede 	ret = device_property_read_string(bq->dev, "linux,secondary-charger-name", &str);
1400d54bf877SHans de Goede 	if (ret == 0) {
1401d54bf877SHans de Goede 		bq->secondary_chrg = power_supply_get_by_name(str);
1402d54bf877SHans de Goede 		if (!bq->secondary_chrg)
1403d54bf877SHans de Goede 			return -EPROBE_DEFER;
1404d54bf877SHans de Goede 	}
14058c0984e5SSebastian Reichel 
140648f45b09SYauhen Kharuzhy 	/* Optional, left at 0 if property is not present */
140748f45b09SYauhen Kharuzhy 	device_property_read_u32(bq->dev, "linux,pump-express-vbus-max",
140848f45b09SYauhen Kharuzhy 				 &bq->pump_express_vbus_max);
140948f45b09SYauhen Kharuzhy 
14106adaa9a4SHans de Goede 	ret = device_property_read_u32(bq->dev, "linux,iinlim-percentage", &val);
14116adaa9a4SHans de Goede 	if (ret == 0) {
14126adaa9a4SHans de Goede 		if (val > 100) {
14136adaa9a4SHans de Goede 			dev_err(bq->dev, "Error linux,iinlim-percentage %u > 100\n", val);
14146adaa9a4SHans de Goede 			return -EINVAL;
14156adaa9a4SHans de Goede 		}
14166adaa9a4SHans de Goede 		bq->iinlim_percentage = val;
14176adaa9a4SHans de Goede 	} else {
14186adaa9a4SHans de Goede 		bq->iinlim_percentage = 100;
14196adaa9a4SHans de Goede 	}
14206adaa9a4SHans de Goede 
14217e3b8e35SHans de Goede 	bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset");
142240428bd4SHans de Goede 	bq->read_back_init_data = device_property_read_bool(bq->dev,
142340428bd4SHans de Goede 						"linux,read-back-settings");
142440428bd4SHans de Goede 	if (bq->read_back_init_data)
142540428bd4SHans de Goede 		return 0;
14267e3b8e35SHans de Goede 
14278c0984e5SSebastian Reichel 	ret = bq25890_fw_read_u32_props(bq);
14288c0984e5SSebastian Reichel 	if (ret < 0)
14298c0984e5SSebastian Reichel 		return ret;
14308c0984e5SSebastian Reichel 
14318c0984e5SSebastian Reichel 	init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin");
14328c0984e5SSebastian Reichel 	init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq");
14338c0984e5SSebastian Reichel 
14348c0984e5SSebastian Reichel 	return 0;
14358c0984e5SSebastian Reichel }
14368c0984e5SSebastian Reichel 
bq25890_non_devm_cleanup(void * data)1437a7aaa800SHans de Goede static void bq25890_non_devm_cleanup(void *data)
1438a7aaa800SHans de Goede {
1439a7aaa800SHans de Goede 	struct bq25890_device *bq = data;
1440a7aaa800SHans de Goede 
1441a7aaa800SHans de Goede 	cancel_delayed_work_sync(&bq->pump_express_work);
14424e9498b8SHans de Goede 
14434e9498b8SHans de Goede 	if (bq->id >= 0) {
14444e9498b8SHans de Goede 		mutex_lock(&bq25890_id_mutex);
14454e9498b8SHans de Goede 		idr_remove(&bq25890_id, bq->id);
14464e9498b8SHans de Goede 		mutex_unlock(&bq25890_id_mutex);
14474e9498b8SHans de Goede 	}
1448a7aaa800SHans de Goede }
1449a7aaa800SHans de Goede 
bq25890_probe(struct i2c_client * client)1450c5cddca2SUwe Kleine-König static int bq25890_probe(struct i2c_client *client)
14518c0984e5SSebastian Reichel {
14528c0984e5SSebastian Reichel 	struct device *dev = &client->dev;
14538c0984e5SSebastian Reichel 	struct bq25890_device *bq;
14548c0984e5SSebastian Reichel 	int ret;
14558c0984e5SSebastian Reichel 
14568c0984e5SSebastian Reichel 	bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL);
14578c0984e5SSebastian Reichel 	if (!bq)
14588c0984e5SSebastian Reichel 		return -ENOMEM;
14598c0984e5SSebastian Reichel 
14608c0984e5SSebastian Reichel 	bq->client = client;
14618c0984e5SSebastian Reichel 	bq->dev = dev;
14624e9498b8SHans de Goede 	bq->id = -1;
14638c0984e5SSebastian Reichel 
14648c0984e5SSebastian Reichel 	mutex_init(&bq->lock);
146548f45b09SYauhen Kharuzhy 	INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work);
14668c0984e5SSebastian Reichel 
14678c0984e5SSebastian Reichel 	bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config);
1468172d0cceSMartin Kepplinger 	if (IS_ERR(bq->rmap))
1469172d0cceSMartin Kepplinger 		return dev_err_probe(dev, PTR_ERR(bq->rmap),
1470172d0cceSMartin Kepplinger 				     "failed to allocate register map\n");
14718c0984e5SSebastian Reichel 
1472c1ae3a4eSHans de Goede 	ret = devm_regmap_field_bulk_alloc(dev, bq->rmap, bq->rmap_fields,
1473c1ae3a4eSHans de Goede 					   bq25890_reg_fields, F_MAX_FIELDS);
1474c1ae3a4eSHans de Goede 	if (ret)
1475c1ae3a4eSHans de Goede 		return ret;
14768c0984e5SSebastian Reichel 
14778c0984e5SSebastian Reichel 	i2c_set_clientdata(client, bq);
14788c0984e5SSebastian Reichel 
1479d20267c9SYauhen Kharuzhy 	ret = bq25890_get_chip_version(bq);
1480d20267c9SYauhen Kharuzhy 	if (ret) {
1481172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret);
1482d20267c9SYauhen Kharuzhy 		return ret;
14838c0984e5SSebastian Reichel 	}
14848c0984e5SSebastian Reichel 
14858c0984e5SSebastian Reichel 	ret = bq25890_fw_probe(bq);
1486f481d5b8SHans de Goede 	if (ret < 0)
1487f481d5b8SHans de Goede 		return dev_err_probe(dev, ret, "reading device properties\n");
14888c0984e5SSebastian Reichel 
14898c0984e5SSebastian Reichel 	ret = bq25890_hw_init(bq);
14908c0984e5SSebastian Reichel 	if (ret < 0) {
1491172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot initialize the chip: %d\n", ret);
14928c0984e5SSebastian Reichel 		return ret;
14938c0984e5SSebastian Reichel 	}
14948c0984e5SSebastian Reichel 
14958c0984e5SSebastian Reichel 	if (client->irq <= 0)
14968c0984e5SSebastian Reichel 		client->irq = bq25890_irq_probe(bq);
14978c0984e5SSebastian Reichel 
14988c0984e5SSebastian Reichel 	if (client->irq < 0) {
14998c0984e5SSebastian Reichel 		dev_err(dev, "No irq resource found.\n");
15008c0984e5SSebastian Reichel 		return client->irq;
15018c0984e5SSebastian Reichel 	}
15028c0984e5SSebastian Reichel 
15038c0984e5SSebastian Reichel 	/* OTG reporting */
15048c0984e5SSebastian Reichel 	bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
15055f5c10ecSMarek Vasut 
1506a7aaa800SHans de Goede 	/*
1507a7aaa800SHans de Goede 	 * This must be before bq25890_power_supply_init(), so that it runs
1508a7aaa800SHans de Goede 	 * after devm unregisters the power_supply.
1509a7aaa800SHans de Goede 	 */
1510a7aaa800SHans de Goede 	ret = devm_add_action_or_reset(dev, bq25890_non_devm_cleanup, bq);
1511a7aaa800SHans de Goede 	if (ret)
1512a7aaa800SHans de Goede 		return ret;
1513a7aaa800SHans de Goede 
15145f5c10ecSMarek Vasut 	ret = bq25890_register_regulator(bq);
15155f5c10ecSMarek Vasut 	if (ret)
15165f5c10ecSMarek Vasut 		return ret;
15175f5c10ecSMarek Vasut 
1518d01363daSHans de Goede 	ret = bq25890_power_supply_init(bq);
15197e6fb678SHans de Goede 	if (ret < 0)
15207e6fb678SHans de Goede 		return dev_err_probe(dev, ret, "registering power supply\n");
1521d01363daSHans de Goede 
15228c0984e5SSebastian Reichel 	ret = devm_request_threaded_irq(dev, client->irq, NULL,
15238c0984e5SSebastian Reichel 					bq25890_irq_handler_thread,
15248c0984e5SSebastian Reichel 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
15258c0984e5SSebastian Reichel 					BQ25890_IRQ_PIN, bq);
15268c0984e5SSebastian Reichel 	if (ret)
15277e6fb678SHans de Goede 		return ret;
15287e6fb678SHans de Goede 
15297e6fb678SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
15307e6fb678SHans de Goede 		INIT_WORK(&bq->usb_work, bq25890_usb_work);
15317e6fb678SHans de Goede 		bq->usb_nb.notifier_call = bq25890_usb_notifier;
15327e6fb678SHans de Goede 		usb_register_notifier(bq->usb_phy, &bq->usb_nb);
15337e6fb678SHans de Goede 	}
15348c0984e5SSebastian Reichel 
15358c0984e5SSebastian Reichel 	return 0;
15368c0984e5SSebastian Reichel }
15378c0984e5SSebastian Reichel 
bq25890_remove(struct i2c_client * client)1538ed5c2f5fSUwe Kleine-König static void bq25890_remove(struct i2c_client *client)
15398c0984e5SSebastian Reichel {
15408c0984e5SSebastian Reichel 	struct bq25890_device *bq = i2c_get_clientdata(client);
15418c0984e5SSebastian Reichel 
15427e6fb678SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
15438c0984e5SSebastian Reichel 		usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
15447e6fb678SHans de Goede 		cancel_work_sync(&bq->usb_work);
15457e6fb678SHans de Goede 	}
15468c0984e5SSebastian Reichel 
15477e3b8e35SHans de Goede 	if (!bq->skip_reset) {
15488c0984e5SSebastian Reichel 		/* reset all registers to default values */
15498c0984e5SSebastian Reichel 		bq25890_chip_reset(bq);
15507e3b8e35SHans de Goede 	}
15518c0984e5SSebastian Reichel }
15528c0984e5SSebastian Reichel 
bq25890_shutdown(struct i2c_client * client)155379d35365SHans de Goede static void bq25890_shutdown(struct i2c_client *client)
155479d35365SHans de Goede {
155579d35365SHans de Goede 	struct bq25890_device *bq = i2c_get_clientdata(client);
155679d35365SHans de Goede 
155779d35365SHans de Goede 	/*
155879d35365SHans de Goede 	 * TODO this if + return should probably be removed, but that would
155979d35365SHans de Goede 	 * introduce a function change for boards using the usb-phy framework.
156079d35365SHans de Goede 	 * This needs to be tested on such a board before making this change.
156179d35365SHans de Goede 	 */
156279d35365SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy))
156379d35365SHans de Goede 		return;
156479d35365SHans de Goede 
156579d35365SHans de Goede 	/*
156679d35365SHans de Goede 	 * Turn off the 5v Boost regulator which outputs Vbus to the device's
156779d35365SHans de Goede 	 * Micro-USB or Type-C USB port. Leaving this on drains power and
156879d35365SHans de Goede 	 * this avoids the PMIC on some device-models seeing this as Vbus
156979d35365SHans de Goede 	 * getting inserted after shutdown, causing the device to immediately
157079d35365SHans de Goede 	 * power-up again.
157179d35365SHans de Goede 	 */
157279d35365SHans de Goede 	bq25890_set_otg_cfg(bq, 0);
157379d35365SHans de Goede }
157479d35365SHans de Goede 
15758c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
bq25890_suspend(struct device * dev)15768c0984e5SSebastian Reichel static int bq25890_suspend(struct device *dev)
15778c0984e5SSebastian Reichel {
15788c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
15798c0984e5SSebastian Reichel 
15808c0984e5SSebastian Reichel 	/*
15818c0984e5SSebastian Reichel 	 * If charger is removed, while in suspend, make sure ADC is diabled
15828c0984e5SSebastian Reichel 	 * since it consumes slightly more power.
15838c0984e5SSebastian Reichel 	 */
158421d90edaSMichał Mirosław 	return bq25890_field_write(bq, F_CONV_RATE, 0);
15858c0984e5SSebastian Reichel }
15868c0984e5SSebastian Reichel 
bq25890_resume(struct device * dev)15878c0984e5SSebastian Reichel static int bq25890_resume(struct device *dev)
15888c0984e5SSebastian Reichel {
15898c0984e5SSebastian Reichel 	int ret;
15908c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
15918c0984e5SSebastian Reichel 
159272d9cd9cSMichał Mirosław 	mutex_lock(&bq->lock);
159372d9cd9cSMichał Mirosław 
159472d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &bq->state);
15958c0984e5SSebastian Reichel 	if (ret < 0)
1596cf5701bfSDan Carpenter 		goto unlock;
15978c0984e5SSebastian Reichel 
15988c0984e5SSebastian Reichel 	/* Re-enable ADC only if charger is plugged in. */
159972d9cd9cSMichał Mirosław 	if (bq->state.online) {
160021d90edaSMichał Mirosław 		ret = bq25890_field_write(bq, F_CONV_RATE, 1);
16018c0984e5SSebastian Reichel 		if (ret < 0)
1602cf5701bfSDan Carpenter 			goto unlock;
16038c0984e5SSebastian Reichel 	}
16048c0984e5SSebastian Reichel 
16058c0984e5SSebastian Reichel 	/* signal userspace, maybe state changed while suspended */
16068c0984e5SSebastian Reichel 	power_supply_changed(bq->charger);
16078c0984e5SSebastian Reichel 
1608cf5701bfSDan Carpenter unlock:
160972d9cd9cSMichał Mirosław 	mutex_unlock(&bq->lock);
161072d9cd9cSMichał Mirosław 
1611cf5701bfSDan Carpenter 	return ret;
16128c0984e5SSebastian Reichel }
16138c0984e5SSebastian Reichel #endif
16148c0984e5SSebastian Reichel 
16158c0984e5SSebastian Reichel static const struct dev_pm_ops bq25890_pm = {
16168c0984e5SSebastian Reichel 	SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume)
16178c0984e5SSebastian Reichel };
16188c0984e5SSebastian Reichel 
16198c0984e5SSebastian Reichel static const struct i2c_device_id bq25890_i2c_ids[] = {
16208c0984e5SSebastian Reichel 	{ "bq25890", 0 },
162146aa27e7SYauhen Kharuzhy 	{ "bq25892", 0 },
162246aa27e7SYauhen Kharuzhy 	{ "bq25895", 0 },
162346aa27e7SYauhen Kharuzhy 	{ "bq25896", 0 },
16248c0984e5SSebastian Reichel 	{},
16258c0984e5SSebastian Reichel };
16268c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids);
16278c0984e5SSebastian Reichel 
162865cc52f3SKrzysztof Kozlowski static const struct of_device_id bq25890_of_match[] __maybe_unused = {
16298c0984e5SSebastian Reichel 	{ .compatible = "ti,bq25890", },
163046aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25892", },
163146aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25895", },
163246aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25896", },
16338c0984e5SSebastian Reichel 	{ },
16348c0984e5SSebastian Reichel };
16358c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, bq25890_of_match);
16368c0984e5SSebastian Reichel 
163702067dc9SKrzysztof Kozlowski #ifdef CONFIG_ACPI
16388c0984e5SSebastian Reichel static const struct acpi_device_id bq25890_acpi_match[] = {
16398c0984e5SSebastian Reichel 	{"BQ258900", 0},
16408c0984e5SSebastian Reichel 	{},
16418c0984e5SSebastian Reichel };
16428c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match);
164302067dc9SKrzysztof Kozlowski #endif
16448c0984e5SSebastian Reichel 
16458c0984e5SSebastian Reichel static struct i2c_driver bq25890_driver = {
16468c0984e5SSebastian Reichel 	.driver = {
16478c0984e5SSebastian Reichel 		.name = "bq25890-charger",
16488c0984e5SSebastian Reichel 		.of_match_table = of_match_ptr(bq25890_of_match),
16498c0984e5SSebastian Reichel 		.acpi_match_table = ACPI_PTR(bq25890_acpi_match),
16508c0984e5SSebastian Reichel 		.pm = &bq25890_pm,
16518c0984e5SSebastian Reichel 	},
1652c5cddca2SUwe Kleine-König 	.probe = bq25890_probe,
16538c0984e5SSebastian Reichel 	.remove = bq25890_remove,
165479d35365SHans de Goede 	.shutdown = bq25890_shutdown,
16558c0984e5SSebastian Reichel 	.id_table = bq25890_i2c_ids,
16568c0984e5SSebastian Reichel };
16578c0984e5SSebastian Reichel module_i2c_driver(bq25890_driver);
16588c0984e5SSebastian Reichel 
16598c0984e5SSebastian Reichel MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
16608c0984e5SSebastian Reichel MODULE_DESCRIPTION("bq25890 charger driver");
16618c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
1662