xref: /openbmc/linux/drivers/power/supply/bq25890_charger.c (revision c688e0c436cb5292285a193134346fcdaaa3a56d)
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;
98*c688e0c4SMarek 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;
1118c0984e5SSebastian Reichel 
1128c0984e5SSebastian Reichel 	struct usb_phy *usb_phy;
1138c0984e5SSebastian Reichel 	struct notifier_block usb_nb;
1148c0984e5SSebastian Reichel 	struct work_struct usb_work;
11548f45b09SYauhen Kharuzhy 	struct delayed_work pump_express_work;
1168c0984e5SSebastian Reichel 	unsigned long usb_event;
1178c0984e5SSebastian Reichel 
1188c0984e5SSebastian Reichel 	struct regmap *rmap;
1198c0984e5SSebastian Reichel 	struct regmap_field *rmap_fields[F_MAX_FIELDS];
1208c0984e5SSebastian Reichel 
1217e3b8e35SHans de Goede 	bool skip_reset;
12240428bd4SHans de Goede 	bool read_back_init_data;
123*c688e0c4SMarek Vasut 	bool force_hiz;
12448f45b09SYauhen Kharuzhy 	u32 pump_express_vbus_max;
125d20267c9SYauhen Kharuzhy 	enum bq25890_chip_version chip_version;
1268c0984e5SSebastian Reichel 	struct bq25890_init_data init_data;
1278c0984e5SSebastian Reichel 	struct bq25890_state state;
1288c0984e5SSebastian Reichel 
1298c0984e5SSebastian Reichel 	struct mutex lock; /* protect state data */
1308c0984e5SSebastian Reichel };
1318c0984e5SSebastian Reichel 
1328c0984e5SSebastian Reichel static const struct regmap_range bq25890_readonly_reg_ranges[] = {
1338c0984e5SSebastian Reichel 	regmap_reg_range(0x0b, 0x0c),
1348c0984e5SSebastian Reichel 	regmap_reg_range(0x0e, 0x13),
1358c0984e5SSebastian Reichel };
1368c0984e5SSebastian Reichel 
1378c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_writeable_regs = {
1388c0984e5SSebastian Reichel 	.no_ranges = bq25890_readonly_reg_ranges,
1398c0984e5SSebastian Reichel 	.n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges),
1408c0984e5SSebastian Reichel };
1418c0984e5SSebastian Reichel 
1428c0984e5SSebastian Reichel static const struct regmap_range bq25890_volatile_reg_ranges[] = {
1438c0984e5SSebastian Reichel 	regmap_reg_range(0x00, 0x00),
14421d90edaSMichał Mirosław 	regmap_reg_range(0x02, 0x02),
1458c0984e5SSebastian Reichel 	regmap_reg_range(0x09, 0x09),
146d20267c9SYauhen Kharuzhy 	regmap_reg_range(0x0b, 0x14),
1478c0984e5SSebastian Reichel };
1488c0984e5SSebastian Reichel 
1498c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_volatile_regs = {
1508c0984e5SSebastian Reichel 	.yes_ranges = bq25890_volatile_reg_ranges,
1518c0984e5SSebastian Reichel 	.n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges),
1528c0984e5SSebastian Reichel };
1538c0984e5SSebastian Reichel 
1548c0984e5SSebastian Reichel static const struct regmap_config bq25890_regmap_config = {
1558c0984e5SSebastian Reichel 	.reg_bits = 8,
1568c0984e5SSebastian Reichel 	.val_bits = 8,
1578c0984e5SSebastian Reichel 
1588c0984e5SSebastian Reichel 	.max_register = 0x14,
1598c0984e5SSebastian Reichel 	.cache_type = REGCACHE_RBTREE,
1608c0984e5SSebastian Reichel 
1618c0984e5SSebastian Reichel 	.wr_table = &bq25890_writeable_regs,
1628c0984e5SSebastian Reichel 	.volatile_table = &bq25890_volatile_regs,
1638c0984e5SSebastian Reichel };
1648c0984e5SSebastian Reichel 
1658c0984e5SSebastian Reichel static const struct reg_field bq25890_reg_fields[] = {
1668c0984e5SSebastian Reichel 	/* REG00 */
1678c0984e5SSebastian Reichel 	[F_EN_HIZ]		= REG_FIELD(0x00, 7, 7),
1688c0984e5SSebastian Reichel 	[F_EN_ILIM]		= REG_FIELD(0x00, 6, 6),
169766873c1SYauhen Kharuzhy 	[F_IINLIM]		= REG_FIELD(0x00, 0, 5),
1708c0984e5SSebastian Reichel 	/* REG01 */
1718c0984e5SSebastian Reichel 	[F_BHOT]		= REG_FIELD(0x01, 6, 7),
1728c0984e5SSebastian Reichel 	[F_BCOLD]		= REG_FIELD(0x01, 5, 5),
1738c0984e5SSebastian Reichel 	[F_VINDPM_OFS]		= REG_FIELD(0x01, 0, 4),
1748c0984e5SSebastian Reichel 	/* REG02 */
1758c0984e5SSebastian Reichel 	[F_CONV_START]		= REG_FIELD(0x02, 7, 7),
1768c0984e5SSebastian Reichel 	[F_CONV_RATE]		= REG_FIELD(0x02, 6, 6),
1778c0984e5SSebastian Reichel 	[F_BOOSTF]		= REG_FIELD(0x02, 5, 5),
1788c0984e5SSebastian Reichel 	[F_ICO_EN]		= REG_FIELD(0x02, 4, 4),
1792e1a2ddeSAngus Ainslie (Purism) 	[F_HVDCP_EN]		= REG_FIELD(0x02, 3, 3),  // reserved on BQ25896
1802e1a2ddeSAngus Ainslie (Purism) 	[F_MAXC_EN]		= REG_FIELD(0x02, 2, 2),  // reserved on BQ25896
1818c0984e5SSebastian Reichel 	[F_FORCE_DPM]		= REG_FIELD(0x02, 1, 1),
1828c0984e5SSebastian Reichel 	[F_AUTO_DPDM_EN]	= REG_FIELD(0x02, 0, 0),
1838c0984e5SSebastian Reichel 	/* REG03 */
1848c0984e5SSebastian Reichel 	[F_BAT_LOAD_EN]		= REG_FIELD(0x03, 7, 7),
1858c0984e5SSebastian Reichel 	[F_WD_RST]		= REG_FIELD(0x03, 6, 6),
1868c0984e5SSebastian Reichel 	[F_OTG_CFG]		= REG_FIELD(0x03, 5, 5),
1878c0984e5SSebastian Reichel 	[F_CHG_CFG]		= REG_FIELD(0x03, 4, 4),
1888c0984e5SSebastian Reichel 	[F_SYSVMIN]		= REG_FIELD(0x03, 1, 3),
189d20267c9SYauhen Kharuzhy 	[F_MIN_VBAT_SEL]	= REG_FIELD(0x03, 0, 0), // BQ25896 only
1908c0984e5SSebastian Reichel 	/* REG04 */
1918c0984e5SSebastian Reichel 	[F_PUMPX_EN]		= REG_FIELD(0x04, 7, 7),
1928c0984e5SSebastian Reichel 	[F_ICHG]		= REG_FIELD(0x04, 0, 6),
1938c0984e5SSebastian Reichel 	/* REG05 */
1948c0984e5SSebastian Reichel 	[F_IPRECHG]		= REG_FIELD(0x05, 4, 7),
1958c0984e5SSebastian Reichel 	[F_ITERM]		= REG_FIELD(0x05, 0, 3),
1968c0984e5SSebastian Reichel 	/* REG06 */
1978c0984e5SSebastian Reichel 	[F_VREG]		= REG_FIELD(0x06, 2, 7),
1988c0984e5SSebastian Reichel 	[F_BATLOWV]		= REG_FIELD(0x06, 1, 1),
1998c0984e5SSebastian Reichel 	[F_VRECHG]		= REG_FIELD(0x06, 0, 0),
2008c0984e5SSebastian Reichel 	/* REG07 */
2018c0984e5SSebastian Reichel 	[F_TERM_EN]		= REG_FIELD(0x07, 7, 7),
2028c0984e5SSebastian Reichel 	[F_STAT_DIS]		= REG_FIELD(0x07, 6, 6),
2038c0984e5SSebastian Reichel 	[F_WD]			= REG_FIELD(0x07, 4, 5),
2048c0984e5SSebastian Reichel 	[F_TMR_EN]		= REG_FIELD(0x07, 3, 3),
2058c0984e5SSebastian Reichel 	[F_CHG_TMR]		= REG_FIELD(0x07, 1, 2),
2065c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_ISET]		= REG_FIELD(0x07, 0, 0), // reserved on BQ25895
2078c0984e5SSebastian Reichel 	/* REG08 */
20895809139SMichał Mirosław 	[F_BATCMP]		= REG_FIELD(0x08, 5, 7),
2098c0984e5SSebastian Reichel 	[F_VCLAMP]		= REG_FIELD(0x08, 2, 4),
2108c0984e5SSebastian Reichel 	[F_TREG]		= REG_FIELD(0x08, 0, 1),
2118c0984e5SSebastian Reichel 	/* REG09 */
2128c0984e5SSebastian Reichel 	[F_FORCE_ICO]		= REG_FIELD(0x09, 7, 7),
2138c0984e5SSebastian Reichel 	[F_TMR2X_EN]		= REG_FIELD(0x09, 6, 6),
2148c0984e5SSebastian Reichel 	[F_BATFET_DIS]		= REG_FIELD(0x09, 5, 5),
2155c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_VSET]		= REG_FIELD(0x09, 4, 4), // reserved on BQ25895
2168c0984e5SSebastian Reichel 	[F_BATFET_DLY]		= REG_FIELD(0x09, 3, 3),
2178c0984e5SSebastian Reichel 	[F_BATFET_RST_EN]	= REG_FIELD(0x09, 2, 2),
2188c0984e5SSebastian Reichel 	[F_PUMPX_UP]		= REG_FIELD(0x09, 1, 1),
2198c0984e5SSebastian Reichel 	[F_PUMPX_DN]		= REG_FIELD(0x09, 0, 0),
2208c0984e5SSebastian Reichel 	/* REG0A */
2218c0984e5SSebastian Reichel 	[F_BOOSTV]		= REG_FIELD(0x0A, 4, 7),
2225c35ba9bSAngus Ainslie (Purism) 	[F_BOOSTI]		= REG_FIELD(0x0A, 0, 2), // reserved on BQ25895
223d20267c9SYauhen Kharuzhy 	[F_PFM_OTG_DIS]		= REG_FIELD(0x0A, 3, 3), // BQ25896 only
2248c0984e5SSebastian Reichel 	/* REG0B */
2258c0984e5SSebastian Reichel 	[F_VBUS_STAT]		= REG_FIELD(0x0B, 5, 7),
2268c0984e5SSebastian Reichel 	[F_CHG_STAT]		= REG_FIELD(0x0B, 3, 4),
2278c0984e5SSebastian Reichel 	[F_PG_STAT]		= REG_FIELD(0x0B, 2, 2),
2282e1a2ddeSAngus Ainslie (Purism) 	[F_SDP_STAT]		= REG_FIELD(0x0B, 1, 1), // reserved on BQ25896
2298c0984e5SSebastian Reichel 	[F_VSYS_STAT]		= REG_FIELD(0x0B, 0, 0),
2308c0984e5SSebastian Reichel 	/* REG0C */
2318c0984e5SSebastian Reichel 	[F_WD_FAULT]		= REG_FIELD(0x0C, 7, 7),
2328c0984e5SSebastian Reichel 	[F_BOOST_FAULT]		= REG_FIELD(0x0C, 6, 6),
2338c0984e5SSebastian Reichel 	[F_CHG_FAULT]		= REG_FIELD(0x0C, 4, 5),
2348c0984e5SSebastian Reichel 	[F_BAT_FAULT]		= REG_FIELD(0x0C, 3, 3),
2358c0984e5SSebastian Reichel 	[F_NTC_FAULT]		= REG_FIELD(0x0C, 0, 2),
2368c0984e5SSebastian Reichel 	/* REG0D */
2378c0984e5SSebastian Reichel 	[F_FORCE_VINDPM]	= REG_FIELD(0x0D, 7, 7),
2388c0984e5SSebastian Reichel 	[F_VINDPM]		= REG_FIELD(0x0D, 0, 6),
2398c0984e5SSebastian Reichel 	/* REG0E */
2408c0984e5SSebastian Reichel 	[F_THERM_STAT]		= REG_FIELD(0x0E, 7, 7),
2418c0984e5SSebastian Reichel 	[F_BATV]		= REG_FIELD(0x0E, 0, 6),
2428c0984e5SSebastian Reichel 	/* REG0F */
2438c0984e5SSebastian Reichel 	[F_SYSV]		= REG_FIELD(0x0F, 0, 6),
2448c0984e5SSebastian Reichel 	/* REG10 */
2458c0984e5SSebastian Reichel 	[F_TSPCT]		= REG_FIELD(0x10, 0, 6),
2468c0984e5SSebastian Reichel 	/* REG11 */
2478c0984e5SSebastian Reichel 	[F_VBUS_GD]		= REG_FIELD(0x11, 7, 7),
2488c0984e5SSebastian Reichel 	[F_VBUSV]		= REG_FIELD(0x11, 0, 6),
2498c0984e5SSebastian Reichel 	/* REG12 */
2508c0984e5SSebastian Reichel 	[F_ICHGR]		= REG_FIELD(0x12, 0, 6),
2518c0984e5SSebastian Reichel 	/* REG13 */
2528c0984e5SSebastian Reichel 	[F_VDPM_STAT]		= REG_FIELD(0x13, 7, 7),
2538c0984e5SSebastian Reichel 	[F_IDPM_STAT]		= REG_FIELD(0x13, 6, 6),
2548c0984e5SSebastian Reichel 	[F_IDPM_LIM]		= REG_FIELD(0x13, 0, 5),
2558c0984e5SSebastian Reichel 	/* REG14 */
2568c0984e5SSebastian Reichel 	[F_REG_RST]		= REG_FIELD(0x14, 7, 7),
2578c0984e5SSebastian Reichel 	[F_ICO_OPTIMIZED]	= REG_FIELD(0x14, 6, 6),
2588c0984e5SSebastian Reichel 	[F_PN]			= REG_FIELD(0x14, 3, 5),
2598c0984e5SSebastian Reichel 	[F_TS_PROFILE]		= REG_FIELD(0x14, 2, 2),
2608c0984e5SSebastian Reichel 	[F_DEV_REV]		= REG_FIELD(0x14, 0, 1)
2618c0984e5SSebastian Reichel };
2628c0984e5SSebastian Reichel 
2638c0984e5SSebastian Reichel /*
2648c0984e5SSebastian Reichel  * Most of the val -> idx conversions can be computed, given the minimum,
2658c0984e5SSebastian Reichel  * maximum and the step between values. For the rest of conversions, we use
2668c0984e5SSebastian Reichel  * lookup tables.
2678c0984e5SSebastian Reichel  */
2688c0984e5SSebastian Reichel enum bq25890_table_ids {
2698c0984e5SSebastian Reichel 	/* range tables */
2708c0984e5SSebastian Reichel 	TBL_ICHG,
2718c0984e5SSebastian Reichel 	TBL_ITERM,
272766873c1SYauhen Kharuzhy 	TBL_IINLIM,
2738c0984e5SSebastian Reichel 	TBL_VREG,
2748c0984e5SSebastian Reichel 	TBL_BOOSTV,
2758c0984e5SSebastian Reichel 	TBL_SYSVMIN,
27648f45b09SYauhen Kharuzhy 	TBL_VBUSV,
27772408329SMichał Mirosław 	TBL_VBATCOMP,
27872408329SMichał Mirosław 	TBL_RBATCOMP,
2798c0984e5SSebastian Reichel 
2808c0984e5SSebastian Reichel 	/* lookup tables */
2818c0984e5SSebastian Reichel 	TBL_TREG,
2828c0984e5SSebastian Reichel 	TBL_BOOSTI,
2839652c024SAngus Ainslie 	TBL_TSPCT,
2848c0984e5SSebastian Reichel };
2858c0984e5SSebastian Reichel 
2868c0984e5SSebastian Reichel /* Thermal Regulation Threshold lookup table, in degrees Celsius */
2878c0984e5SSebastian Reichel static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 };
2888c0984e5SSebastian Reichel 
2898c0984e5SSebastian Reichel #define BQ25890_TREG_TBL_SIZE		ARRAY_SIZE(bq25890_treg_tbl)
2908c0984e5SSebastian Reichel 
2918c0984e5SSebastian Reichel /* Boost mode current limit lookup table, in uA */
2928c0984e5SSebastian Reichel static const u32 bq25890_boosti_tbl[] = {
2938c0984e5SSebastian Reichel 	500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000
2948c0984e5SSebastian Reichel };
2958c0984e5SSebastian Reichel 
2968c0984e5SSebastian Reichel #define BQ25890_BOOSTI_TBL_SIZE		ARRAY_SIZE(bq25890_boosti_tbl)
2978c0984e5SSebastian Reichel 
2989652c024SAngus Ainslie /* NTC 10K temperature lookup table in tenths of a degree */
2999652c024SAngus Ainslie static const u32 bq25890_tspct_tbl[] = {
3009652c024SAngus Ainslie 	850, 840, 830, 820, 810, 800, 790, 780,
3019652c024SAngus Ainslie 	770, 760, 750, 740, 730, 720, 710, 700,
3029652c024SAngus Ainslie 	690, 685, 680, 675, 670, 660, 650, 645,
3039652c024SAngus Ainslie 	640, 630, 620, 615, 610, 600, 590, 585,
3049652c024SAngus Ainslie 	580, 570, 565, 560, 550, 540, 535, 530,
3059652c024SAngus Ainslie 	520, 515, 510, 500, 495, 490, 480, 475,
3069652c024SAngus Ainslie 	470, 460, 455, 450, 440, 435, 430, 425,
3079652c024SAngus Ainslie 	420, 410, 405, 400, 390, 385, 380, 370,
3089652c024SAngus Ainslie 	365, 360, 355, 350, 340, 335, 330, 320,
3099652c024SAngus Ainslie 	310, 305, 300, 290, 285, 280, 275, 270,
3109652c024SAngus Ainslie 	260, 250, 245, 240, 230, 225, 220, 210,
3119652c024SAngus Ainslie 	205, 200, 190, 180, 175, 170, 160, 150,
3129652c024SAngus Ainslie 	145, 140, 130, 120, 115, 110, 100, 90,
3139652c024SAngus Ainslie 	80, 70, 60, 50, 40, 30, 20, 10,
3149652c024SAngus Ainslie 	0, -10, -20, -30, -40, -60, -70, -80,
3159652c024SAngus Ainslie 	-90, -10, -120, -140, -150, -170, -190, -210,
3169652c024SAngus Ainslie };
3179652c024SAngus Ainslie 
3189652c024SAngus Ainslie #define BQ25890_TSPCT_TBL_SIZE		ARRAY_SIZE(bq25890_tspct_tbl)
3199652c024SAngus Ainslie 
3208c0984e5SSebastian Reichel struct bq25890_range {
3218c0984e5SSebastian Reichel 	u32 min;
3228c0984e5SSebastian Reichel 	u32 max;
3238c0984e5SSebastian Reichel 	u32 step;
3248c0984e5SSebastian Reichel };
3258c0984e5SSebastian Reichel 
3268c0984e5SSebastian Reichel struct bq25890_lookup {
3278c0984e5SSebastian Reichel 	const u32 *tbl;
3288c0984e5SSebastian Reichel 	u32 size;
3298c0984e5SSebastian Reichel };
3308c0984e5SSebastian Reichel 
3318c0984e5SSebastian Reichel static const union {
3328c0984e5SSebastian Reichel 	struct bq25890_range  rt;
3338c0984e5SSebastian Reichel 	struct bq25890_lookup lt;
3348c0984e5SSebastian Reichel } bq25890_tables[] = {
3358c0984e5SSebastian Reichel 	/* range tables */
336d20267c9SYauhen Kharuzhy 	/* TODO: BQ25896 has max ICHG 3008 mA */
3378c0984e5SSebastian Reichel 	[TBL_ICHG] =	 { .rt = {0,        5056000, 64000} },	 /* uA */
3388c0984e5SSebastian Reichel 	[TBL_ITERM] =	 { .rt = {64000,    1024000, 64000} },	 /* uA */
339766873c1SYauhen Kharuzhy 	[TBL_IINLIM] =   { .rt = {100000,   3250000, 50000} },	 /* uA */
3408c0984e5SSebastian Reichel 	[TBL_VREG] =	 { .rt = {3840000,  4608000, 16000} },	 /* uV */
3418c0984e5SSebastian Reichel 	[TBL_BOOSTV] =	 { .rt = {4550000,  5510000, 64000} },	 /* uV */
3428c0984e5SSebastian Reichel 	[TBL_SYSVMIN] =  { .rt = {3000000,  3700000, 100000} },	 /* uV */
34348f45b09SYauhen Kharuzhy 	[TBL_VBUSV] =	 { .rt = {2600000, 15300000, 100000} },	 /* uV */
34472408329SMichał Mirosław 	[TBL_VBATCOMP] = { .rt = {0,         224000, 32000} },	 /* uV */
34572408329SMichał Mirosław 	[TBL_RBATCOMP] = { .rt = {0,         140000, 20000} },	 /* uOhm */
3468c0984e5SSebastian Reichel 
3478c0984e5SSebastian Reichel 	/* lookup tables */
3488c0984e5SSebastian Reichel 	[TBL_TREG] =	{ .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} },
3499652c024SAngus Ainslie 	[TBL_BOOSTI] =	{ .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} },
3509652c024SAngus Ainslie 	[TBL_TSPCT] =	{ .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} }
3518c0984e5SSebastian Reichel };
3528c0984e5SSebastian Reichel 
3538c0984e5SSebastian Reichel static int bq25890_field_read(struct bq25890_device *bq,
3548c0984e5SSebastian Reichel 			      enum bq25890_fields field_id)
3558c0984e5SSebastian Reichel {
3568c0984e5SSebastian Reichel 	int ret;
3578c0984e5SSebastian Reichel 	int val;
3588c0984e5SSebastian Reichel 
3598c0984e5SSebastian Reichel 	ret = regmap_field_read(bq->rmap_fields[field_id], &val);
3608c0984e5SSebastian Reichel 	if (ret < 0)
3618c0984e5SSebastian Reichel 		return ret;
3628c0984e5SSebastian Reichel 
3638c0984e5SSebastian Reichel 	return val;
3648c0984e5SSebastian Reichel }
3658c0984e5SSebastian Reichel 
3668c0984e5SSebastian Reichel static int bq25890_field_write(struct bq25890_device *bq,
3678c0984e5SSebastian Reichel 			       enum bq25890_fields field_id, u8 val)
3688c0984e5SSebastian Reichel {
3698c0984e5SSebastian Reichel 	return regmap_field_write(bq->rmap_fields[field_id], val);
3708c0984e5SSebastian Reichel }
3718c0984e5SSebastian Reichel 
3728c0984e5SSebastian Reichel static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id)
3738c0984e5SSebastian Reichel {
3748c0984e5SSebastian Reichel 	u8 idx;
3758c0984e5SSebastian Reichel 
3768c0984e5SSebastian Reichel 	if (id >= TBL_TREG) {
3778c0984e5SSebastian Reichel 		const u32 *tbl = bq25890_tables[id].lt.tbl;
3788c0984e5SSebastian Reichel 		u32 tbl_size = bq25890_tables[id].lt.size;
3798c0984e5SSebastian Reichel 
3808c0984e5SSebastian Reichel 		for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++)
3818c0984e5SSebastian Reichel 			;
3828c0984e5SSebastian Reichel 	} else {
3838c0984e5SSebastian Reichel 		const struct bq25890_range *rtbl = &bq25890_tables[id].rt;
3848c0984e5SSebastian Reichel 		u8 rtbl_size;
3858c0984e5SSebastian Reichel 
3868c0984e5SSebastian Reichel 		rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1;
3878c0984e5SSebastian Reichel 
3888c0984e5SSebastian Reichel 		for (idx = 1;
3898c0984e5SSebastian Reichel 		     idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value);
3908c0984e5SSebastian Reichel 		     idx++)
3918c0984e5SSebastian Reichel 			;
3928c0984e5SSebastian Reichel 	}
3938c0984e5SSebastian Reichel 
3948c0984e5SSebastian Reichel 	return idx - 1;
3958c0984e5SSebastian Reichel }
3968c0984e5SSebastian Reichel 
3978c0984e5SSebastian Reichel static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id)
3988c0984e5SSebastian Reichel {
3998c0984e5SSebastian Reichel 	const struct bq25890_range *rtbl;
4008c0984e5SSebastian Reichel 
4018c0984e5SSebastian Reichel 	/* lookup table? */
4028c0984e5SSebastian Reichel 	if (id >= TBL_TREG)
4038c0984e5SSebastian Reichel 		return bq25890_tables[id].lt.tbl[idx];
4048c0984e5SSebastian Reichel 
4058c0984e5SSebastian Reichel 	/* range table */
4068c0984e5SSebastian Reichel 	rtbl = &bq25890_tables[id].rt;
4078c0984e5SSebastian Reichel 
4088c0984e5SSebastian Reichel 	return (rtbl->min + idx * rtbl->step);
4098c0984e5SSebastian Reichel }
4108c0984e5SSebastian Reichel 
4118c0984e5SSebastian Reichel enum bq25890_status {
4128c0984e5SSebastian Reichel 	STATUS_NOT_CHARGING,
4138c0984e5SSebastian Reichel 	STATUS_PRE_CHARGING,
4148c0984e5SSebastian Reichel 	STATUS_FAST_CHARGING,
4158c0984e5SSebastian Reichel 	STATUS_TERMINATION_DONE,
4168c0984e5SSebastian Reichel };
4178c0984e5SSebastian Reichel 
4188c0984e5SSebastian Reichel enum bq25890_chrg_fault {
4198c0984e5SSebastian Reichel 	CHRG_FAULT_NORMAL,
4208c0984e5SSebastian Reichel 	CHRG_FAULT_INPUT,
4218c0984e5SSebastian Reichel 	CHRG_FAULT_THERMAL_SHUTDOWN,
4228c0984e5SSebastian Reichel 	CHRG_FAULT_TIMER_EXPIRED,
4238c0984e5SSebastian Reichel };
4248c0984e5SSebastian Reichel 
425c562a43aSYauhen Kharuzhy enum bq25890_ntc_fault {
426c562a43aSYauhen Kharuzhy 	NTC_FAULT_NORMAL = 0,
427c562a43aSYauhen Kharuzhy 	NTC_FAULT_WARM = 2,
428c562a43aSYauhen Kharuzhy 	NTC_FAULT_COOL = 3,
429c562a43aSYauhen Kharuzhy 	NTC_FAULT_COLD = 5,
430c562a43aSYauhen Kharuzhy 	NTC_FAULT_HOT = 6,
431c562a43aSYauhen Kharuzhy };
432c562a43aSYauhen Kharuzhy 
43321d90edaSMichał Mirosław static bool bq25890_is_adc_property(enum power_supply_property psp)
43421d90edaSMichał Mirosław {
43521d90edaSMichał Mirosław 	switch (psp) {
43621d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
43721d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_CURRENT_NOW:
4389652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
43921d90edaSMichał Mirosław 		return true;
44021d90edaSMichał Mirosław 
44121d90edaSMichał Mirosław 	default:
44221d90edaSMichał Mirosław 		return false;
44321d90edaSMichał Mirosław 	}
44421d90edaSMichał Mirosław }
44521d90edaSMichał Mirosław 
4463b4df57bSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq);
4473b4df57bSMichał Mirosław 
44848f45b09SYauhen Kharuzhy static int bq25890_get_vbus_voltage(struct bq25890_device *bq)
44948f45b09SYauhen Kharuzhy {
45048f45b09SYauhen Kharuzhy 	int ret;
45148f45b09SYauhen Kharuzhy 
45248f45b09SYauhen Kharuzhy 	ret = bq25890_field_read(bq, F_VBUSV);
45348f45b09SYauhen Kharuzhy 	if (ret < 0)
45448f45b09SYauhen Kharuzhy 		return ret;
45548f45b09SYauhen Kharuzhy 
45648f45b09SYauhen Kharuzhy 	return bq25890_find_val(ret, TBL_VBUSV);
45748f45b09SYauhen Kharuzhy }
45848f45b09SYauhen Kharuzhy 
459d1b25092SMarek Vasut static void bq25890_update_state(struct bq25890_device *bq,
4608c0984e5SSebastian Reichel 				 enum power_supply_property psp,
461d1b25092SMarek Vasut 				 struct bq25890_state *state)
4628c0984e5SSebastian Reichel {
46321d90edaSMichał Mirosław 	bool do_adc_conv;
46421d90edaSMichał Mirosław 	int ret;
4658c0984e5SSebastian Reichel 
4668c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
4673b4df57bSMichał Mirosław 	/* update state in case we lost an interrupt */
4683b4df57bSMichał Mirosław 	__bq25890_handle_irq(bq);
469d1b25092SMarek Vasut 	*state = bq->state;
470d1b25092SMarek Vasut 	do_adc_conv = !state->online && bq25890_is_adc_property(psp);
47121d90edaSMichał Mirosław 	if (do_adc_conv)
47221d90edaSMichał Mirosław 		bq25890_field_write(bq, F_CONV_START, 1);
4738c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
4748c0984e5SSebastian Reichel 
47521d90edaSMichał Mirosław 	if (do_adc_conv)
47621d90edaSMichał Mirosław 		regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START],
47721d90edaSMichał Mirosław 			ret, !ret, 25000, 1000000);
478d1b25092SMarek Vasut }
479d1b25092SMarek Vasut 
480d1b25092SMarek Vasut static int bq25890_power_supply_get_property(struct power_supply *psy,
481d1b25092SMarek Vasut 					     enum power_supply_property psp,
482d1b25092SMarek Vasut 					     union power_supply_propval *val)
483d1b25092SMarek Vasut {
484d1b25092SMarek Vasut 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
485d1b25092SMarek Vasut 	struct bq25890_state state;
486d1b25092SMarek Vasut 	int ret;
487d1b25092SMarek Vasut 
488d1b25092SMarek Vasut 	bq25890_update_state(bq, psp, &state);
48921d90edaSMichał Mirosław 
4908c0984e5SSebastian Reichel 	switch (psp) {
4918c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_STATUS:
492*c688e0c4SMarek Vasut 		if (!state.online || state.hiz)
4938c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
4948c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_NOT_CHARGING)
4958c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
4968c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_PRE_CHARGING ||
4978c0984e5SSebastian Reichel 			 state.chrg_status == STATUS_FAST_CHARGING)
4988c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
4998c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_TERMINATION_DONE)
5008c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_FULL;
5018c0984e5SSebastian Reichel 		else
5028c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
5038c0984e5SSebastian Reichel 
5048c0984e5SSebastian Reichel 		break;
5058c0984e5SSebastian Reichel 
506b302a0aeSMichał Mirosław 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
507*c688e0c4SMarek Vasut 		if (!state.online || state.hiz ||
508*c688e0c4SMarek Vasut 		    state.chrg_status == STATUS_NOT_CHARGING ||
509b302a0aeSMichał Mirosław 		    state.chrg_status == STATUS_TERMINATION_DONE)
510b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
511b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_PRE_CHARGING)
512b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
513b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_FAST_CHARGING)
514b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
515b302a0aeSMichał Mirosław 		else /* unreachable */
516b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
517b302a0aeSMichał Mirosław 		break;
518b302a0aeSMichał Mirosław 
5198c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MANUFACTURER:
5208c0984e5SSebastian Reichel 		val->strval = BQ25890_MANUFACTURER;
5218c0984e5SSebastian Reichel 		break;
5228c0984e5SSebastian Reichel 
5232e1a2ddeSAngus Ainslie (Purism) 	case POWER_SUPPLY_PROP_MODEL_NAME:
5245956fca7SMichał Mirosław 		val->strval = bq25890_chip_name[bq->chip_version];
5252e1a2ddeSAngus Ainslie (Purism) 		break;
5262e1a2ddeSAngus Ainslie (Purism) 
5278c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
528*c688e0c4SMarek Vasut 		val->intval = state.online && !state.hiz;
5298c0984e5SSebastian Reichel 		break;
5308c0984e5SSebastian Reichel 
5318c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_HEALTH:
5328c0984e5SSebastian Reichel 		if (!state.chrg_fault && !state.bat_fault && !state.boost_fault)
5338c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_GOOD;
5348c0984e5SSebastian Reichel 		else if (state.bat_fault)
5358c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
5368c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED)
5378c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
5388c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN)
5398c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
5408c0984e5SSebastian Reichel 		else
5418c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
5428c0984e5SSebastian Reichel 		break;
5438c0984e5SSebastian Reichel 
544c942656dSMichał Mirosław 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
545c942656dSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM);
546c942656dSMichał Mirosław 		break;
547c942656dSMichał Mirosław 
5488c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
5498c0984e5SSebastian Reichel 		val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM);
5508c0984e5SSebastian Reichel 		break;
5518c0984e5SSebastian Reichel 
552478efc79SMichał Mirosław 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
553766873c1SYauhen Kharuzhy 		ret = bq25890_field_read(bq, F_IINLIM);
554478efc79SMichał Mirosław 		if (ret < 0)
555478efc79SMichał Mirosław 			return ret;
556478efc79SMichał Mirosław 
557766873c1SYauhen Kharuzhy 		val->intval = bq25890_find_val(ret, TBL_IINLIM);
558478efc79SMichał Mirosław 		break;
559478efc79SMichał Mirosław 
560ef1ca210SMarek Vasut 	case POWER_SUPPLY_PROP_CURRENT_NOW:	/* I_BAT now */
561ef1ca210SMarek Vasut 		/*
562ef1ca210SMarek Vasut 		 * This is ADC-sampled immediate charge current supplied
563ef1ca210SMarek Vasut 		 * from charger to battery. The property name is confusing,
564ef1ca210SMarek Vasut 		 * for clarification refer to:
565ef1ca210SMarek Vasut 		 * Documentation/ABI/testing/sysfs-class-power
566ef1ca210SMarek Vasut 		 * /sys/class/power_supply/<supply_name>/current_now
567ef1ca210SMarek Vasut 		 */
5681e4724d0SMichał Mirosław 		ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */
5691e4724d0SMichał Mirosław 		if (ret < 0)
5701e4724d0SMichał Mirosław 			return ret;
5711e4724d0SMichał Mirosław 
5721e4724d0SMichał Mirosław 		/* converted_val = ADC_val * 50mA (table 10.3.19) */
5731e4724d0SMichał Mirosław 		val->intval = ret * -50000;
5741e4724d0SMichał Mirosław 		break;
5751e4724d0SMichał Mirosław 
5768327a8abSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:	/* I_BAT user limit */
5778327a8abSMarek Vasut 		/*
5788327a8abSMarek Vasut 		 * This is user-configured constant charge current supplied
5798327a8abSMarek Vasut 		 * from charger to battery in first phase of charging, when
5808327a8abSMarek Vasut 		 * battery voltage is below constant charge voltage.
5818327a8abSMarek Vasut 		 *
5828327a8abSMarek Vasut 		 * This value reflects the current hardware setting.
5838327a8abSMarek Vasut 		 *
5848327a8abSMarek Vasut 		 * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX is the
5858327a8abSMarek Vasut 		 * maximum value of this property.
5868327a8abSMarek Vasut 		 */
5878327a8abSMarek Vasut 		ret = bq25890_field_read(bq, F_ICHG);
5888327a8abSMarek Vasut 		if (ret < 0)
5898327a8abSMarek Vasut 			return ret;
5908327a8abSMarek Vasut 		val->intval = bq25890_find_val(ret, TBL_ICHG);
5918327a8abSMarek Vasut 
5928327a8abSMarek Vasut 		/* When temperature is too low, charge current is decreased */
5938327a8abSMarek Vasut 		if (bq->state.ntc_fault == NTC_FAULT_COOL) {
5948327a8abSMarek Vasut 			ret = bq25890_field_read(bq, F_JEITA_ISET);
5958327a8abSMarek Vasut 			if (ret < 0)
5968327a8abSMarek Vasut 				return ret;
5978327a8abSMarek Vasut 
5988327a8abSMarek Vasut 			if (ret)
5998327a8abSMarek Vasut 				val->intval /= 5;
6008327a8abSMarek Vasut 			else
6018327a8abSMarek Vasut 				val->intval /= 2;
6028327a8abSMarek Vasut 		}
6038327a8abSMarek Vasut 		break;
6048327a8abSMarek Vasut 
6058327a8abSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:	/* I_BAT max */
6068327a8abSMarek Vasut 		/*
6078327a8abSMarek Vasut 		 * This is maximum allowed constant charge current supplied
6088327a8abSMarek Vasut 		 * from charger to battery in first phase of charging, when
6098327a8abSMarek Vasut 		 * battery voltage is below constant charge voltage.
6108327a8abSMarek Vasut 		 *
6118327a8abSMarek Vasut 		 * This value is constant for each battery and set from DT.
6128327a8abSMarek Vasut 		 */
6138327a8abSMarek Vasut 		val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
6148327a8abSMarek Vasut 		break;
6158327a8abSMarek Vasut 
6167c852375SMarek Vasut 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:	/* V_BAT now */
6177c852375SMarek Vasut 		/*
6187c852375SMarek Vasut 		 * This is ADC-sampled immediate charge voltage supplied
6197c852375SMarek Vasut 		 * from charger to battery. The property name is confusing,
6207c852375SMarek Vasut 		 * for clarification refer to:
6217c852375SMarek Vasut 		 * Documentation/ABI/testing/sysfs-class-power
6227c852375SMarek Vasut 		 * /sys/class/power_supply/<supply_name>/voltage_now
6237c852375SMarek Vasut 		 */
6247c852375SMarek Vasut 		ret = bq25890_field_read(bq, F_BATV); /* read measured value */
6257c852375SMarek Vasut 		if (ret < 0)
6267c852375SMarek Vasut 			return ret;
6277c852375SMarek Vasut 
6287c852375SMarek Vasut 		/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
6297c852375SMarek Vasut 		val->intval = 2304000 + ret * 20000;
6307c852375SMarek Vasut 		break;
6317c852375SMarek Vasut 
6327c852375SMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:	/* V_BAT user limit */
6337c852375SMarek Vasut 		/*
6347c852375SMarek Vasut 		 * This is user-configured constant charge voltage supplied
6357c852375SMarek Vasut 		 * from charger to battery in second phase of charging, when
6367c852375SMarek Vasut 		 * battery voltage reached constant charge voltage.
6377c852375SMarek Vasut 		 *
6387c852375SMarek Vasut 		 * This value reflects the current hardware setting.
6397c852375SMarek Vasut 		 *
6407c852375SMarek Vasut 		 * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX is the
6417c852375SMarek Vasut 		 * maximum value of this property.
6427c852375SMarek Vasut 		 */
6437c852375SMarek Vasut 		ret = bq25890_field_read(bq, F_VREG);
6447c852375SMarek Vasut 		if (ret < 0)
6457c852375SMarek Vasut 			return ret;
6467c852375SMarek Vasut 
6477c852375SMarek Vasut 		val->intval = bq25890_find_val(ret, TBL_VREG);
6487c852375SMarek Vasut 		break;
6497c852375SMarek Vasut 
6507c852375SMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:	/* V_BAT max */
6517c852375SMarek Vasut 		/*
6527c852375SMarek Vasut 		 * This is maximum allowed constant charge voltage supplied
6537c852375SMarek Vasut 		 * from charger to battery in second phase of charging, when
6547c852375SMarek Vasut 		 * battery voltage reached constant charge voltage.
6557c852375SMarek Vasut 		 *
6567c852375SMarek Vasut 		 * This value is constant for each battery and set from DT.
6577c852375SMarek Vasut 		 */
6587c852375SMarek Vasut 		val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
6597c852375SMarek Vasut 		break;
6607c852375SMarek Vasut 
6619652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
6629652c024SAngus Ainslie 		ret = bq25890_field_read(bq, F_TSPCT);
6639652c024SAngus Ainslie 		if (ret < 0)
6649652c024SAngus Ainslie 			return ret;
6659652c024SAngus Ainslie 
6669652c024SAngus Ainslie 		/* convert TS percentage into rough temperature */
6679652c024SAngus Ainslie 		val->intval = bq25890_find_val(ret, TBL_TSPCT);
6689652c024SAngus Ainslie 		break;
6699652c024SAngus Ainslie 
6708c0984e5SSebastian Reichel 	default:
6718c0984e5SSebastian Reichel 		return -EINVAL;
6728c0984e5SSebastian Reichel 	}
6738c0984e5SSebastian Reichel 
6748c0984e5SSebastian Reichel 	return 0;
6758c0984e5SSebastian Reichel }
6768c0984e5SSebastian Reichel 
6774a4748f2SMarek Vasut static int bq25890_power_supply_set_property(struct power_supply *psy,
6784a4748f2SMarek Vasut 					     enum power_supply_property psp,
6794a4748f2SMarek Vasut 					     const union power_supply_propval *val)
6804a4748f2SMarek Vasut {
6814a4748f2SMarek Vasut 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
682*c688e0c4SMarek Vasut 	struct bq25890_state state;
683*c688e0c4SMarek Vasut 	int maxval, ret;
6844a4748f2SMarek Vasut 	u8 lval;
6854a4748f2SMarek Vasut 
6864a4748f2SMarek Vasut 	switch (psp) {
687b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
688b63e60ebSMarek Vasut 		maxval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
689b63e60ebSMarek Vasut 		lval = bq25890_find_idx(min(val->intval, maxval), TBL_ICHG);
690b63e60ebSMarek Vasut 		return bq25890_field_write(bq, F_ICHG, lval);
691b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
692b63e60ebSMarek Vasut 		maxval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
693b63e60ebSMarek Vasut 		lval = bq25890_find_idx(min(val->intval, maxval), TBL_VREG);
694b63e60ebSMarek Vasut 		return bq25890_field_write(bq, F_VREG, lval);
6954a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
69655cafd4bSNathan Chancellor 		lval = bq25890_find_idx(val->intval, TBL_IINLIM);
6974a4748f2SMarek Vasut 		return bq25890_field_write(bq, F_IINLIM, lval);
698*c688e0c4SMarek Vasut 	case POWER_SUPPLY_PROP_ONLINE:
699*c688e0c4SMarek Vasut 		ret = bq25890_field_write(bq, F_EN_HIZ, !val->intval);
700*c688e0c4SMarek Vasut 		if (!ret)
701*c688e0c4SMarek Vasut 			bq->force_hiz = !val->intval;
702*c688e0c4SMarek Vasut 		bq25890_update_state(bq, psp, &state);
703*c688e0c4SMarek Vasut 		return ret;
7044a4748f2SMarek Vasut 	default:
7054a4748f2SMarek Vasut 		return -EINVAL;
7064a4748f2SMarek Vasut 	}
7074a4748f2SMarek Vasut }
7084a4748f2SMarek Vasut 
7094a4748f2SMarek Vasut static int bq25890_power_supply_property_is_writeable(struct power_supply *psy,
7104a4748f2SMarek Vasut 						      enum power_supply_property psp)
7114a4748f2SMarek Vasut {
7124a4748f2SMarek Vasut 	switch (psp) {
713b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
714b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
7154a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
716*c688e0c4SMarek Vasut 	case POWER_SUPPLY_PROP_ONLINE:
7174a4748f2SMarek Vasut 		return true;
7184a4748f2SMarek Vasut 	default:
7194a4748f2SMarek Vasut 		return false;
7204a4748f2SMarek Vasut 	}
7214a4748f2SMarek Vasut }
7224a4748f2SMarek Vasut 
723eab25b4fSHans de Goede /* On the BQ25892 try to get charger-type info from our supplier */
724eab25b4fSHans de Goede static void bq25890_charger_external_power_changed(struct power_supply *psy)
725eab25b4fSHans de Goede {
726eab25b4fSHans de Goede 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
727eab25b4fSHans de Goede 	union power_supply_propval val;
728eab25b4fSHans de Goede 	int input_current_limit, ret;
729eab25b4fSHans de Goede 
730eab25b4fSHans de Goede 	if (bq->chip_version != BQ25892)
731eab25b4fSHans de Goede 		return;
732eab25b4fSHans de Goede 
733eab25b4fSHans de Goede 	ret = power_supply_get_property_from_supplier(bq->charger,
734eab25b4fSHans de Goede 						      POWER_SUPPLY_PROP_USB_TYPE,
735eab25b4fSHans de Goede 						      &val);
736eab25b4fSHans de Goede 	if (ret)
737eab25b4fSHans de Goede 		return;
738eab25b4fSHans de Goede 
739eab25b4fSHans de Goede 	switch (val.intval) {
740eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_DCP:
741eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM);
74248f45b09SYauhen Kharuzhy 		if (bq->pump_express_vbus_max) {
74348f45b09SYauhen Kharuzhy 			queue_delayed_work(system_power_efficient_wq,
74448f45b09SYauhen Kharuzhy 					   &bq->pump_express_work,
74548f45b09SYauhen Kharuzhy 					   PUMP_EXPRESS_START_DELAY);
74648f45b09SYauhen Kharuzhy 		}
747eab25b4fSHans de Goede 		break;
748eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_CDP:
749eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_ACA:
750eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM);
751eab25b4fSHans de Goede 		break;
752eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_SDP:
753eab25b4fSHans de Goede 	default:
754eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(500000, TBL_IINLIM);
755eab25b4fSHans de Goede 	}
756eab25b4fSHans de Goede 
757eab25b4fSHans de Goede 	bq25890_field_write(bq, F_IINLIM, input_current_limit);
758eab25b4fSHans de Goede }
759eab25b4fSHans de Goede 
7608c0984e5SSebastian Reichel static int bq25890_get_chip_state(struct bq25890_device *bq,
7618c0984e5SSebastian Reichel 				  struct bq25890_state *state)
7628c0984e5SSebastian Reichel {
7638c0984e5SSebastian Reichel 	int i, ret;
7648c0984e5SSebastian Reichel 
7658c0984e5SSebastian Reichel 	struct {
7668c0984e5SSebastian Reichel 		enum bq25890_fields id;
7678c0984e5SSebastian Reichel 		u8 *data;
7688c0984e5SSebastian Reichel 	} state_fields[] = {
7698c0984e5SSebastian Reichel 		{F_CHG_STAT,	&state->chrg_status},
7708c0984e5SSebastian Reichel 		{F_PG_STAT,	&state->online},
771*c688e0c4SMarek Vasut 		{F_EN_HIZ,	&state->hiz},
7728c0984e5SSebastian Reichel 		{F_VSYS_STAT,	&state->vsys_status},
7738c0984e5SSebastian Reichel 		{F_BOOST_FAULT, &state->boost_fault},
7748c0984e5SSebastian Reichel 		{F_BAT_FAULT,	&state->bat_fault},
775c562a43aSYauhen Kharuzhy 		{F_CHG_FAULT,	&state->chrg_fault},
776c562a43aSYauhen Kharuzhy 		{F_NTC_FAULT,	&state->ntc_fault}
7778c0984e5SSebastian Reichel 	};
7788c0984e5SSebastian Reichel 
7798c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(state_fields); i++) {
7808c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, state_fields[i].id);
7818c0984e5SSebastian Reichel 		if (ret < 0)
7828c0984e5SSebastian Reichel 			return ret;
7838c0984e5SSebastian Reichel 
7848c0984e5SSebastian Reichel 		*state_fields[i].data = ret;
7858c0984e5SSebastian Reichel 	}
7868c0984e5SSebastian Reichel 
787*c688e0c4SMarek Vasut 	dev_dbg(bq->dev, "S:CHG/PG/HIZ/VSYS=%d/%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
788*c688e0c4SMarek Vasut 		state->chrg_status, state->online,
789*c688e0c4SMarek Vasut 		state->hiz, state->vsys_status,
790*c688e0c4SMarek Vasut 		state->chrg_fault, state->boost_fault,
791*c688e0c4SMarek Vasut 		state->bat_fault, state->ntc_fault);
7928c0984e5SSebastian Reichel 
7938c0984e5SSebastian Reichel 	return 0;
7948c0984e5SSebastian Reichel }
7958c0984e5SSebastian Reichel 
79672d9cd9cSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
7978c0984e5SSebastian Reichel {
79872d9cd9cSMichał Mirosław 	struct bq25890_state new_state;
7998c0984e5SSebastian Reichel 	int ret;
8008c0984e5SSebastian Reichel 
80172d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &new_state);
80272d9cd9cSMichał Mirosław 	if (ret < 0)
80372d9cd9cSMichał Mirosław 		return IRQ_NONE;
8048c0984e5SSebastian Reichel 
80572d9cd9cSMichał Mirosław 	if (!memcmp(&bq->state, &new_state, sizeof(new_state)))
80672d9cd9cSMichał Mirosław 		return IRQ_NONE;
80772d9cd9cSMichał Mirosław 
808*c688e0c4SMarek Vasut 	/* power removed or HiZ */
809*c688e0c4SMarek Vasut 	if ((!new_state.online || new_state.hiz) && bq->state.online) {
8108c0984e5SSebastian Reichel 		/* disable ADC */
81180211be1SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_CONV_RATE, 0);
8128c0984e5SSebastian Reichel 		if (ret < 0)
8138c0984e5SSebastian Reichel 			goto error;
814*c688e0c4SMarek Vasut 	} else if (new_state.online && !bq->state.online) {
815*c688e0c4SMarek Vasut 		/*
816*c688e0c4SMarek Vasut 		 * Restore HiZ bit in case it was set by user.
817*c688e0c4SMarek Vasut 		 * The chip does not retain this bit once the
818*c688e0c4SMarek Vasut 		 * cable is re-plugged, hence the bit must be
819*c688e0c4SMarek Vasut 		 * reset manually here.
820*c688e0c4SMarek Vasut 		 */
821*c688e0c4SMarek Vasut 		if (bq->force_hiz) {
822*c688e0c4SMarek Vasut 			ret = bq25890_field_write(bq, F_EN_HIZ, bq->force_hiz);
823*c688e0c4SMarek Vasut 			if (ret < 0)
824*c688e0c4SMarek Vasut 				goto error;
825*c688e0c4SMarek Vasut 			new_state.hiz = 1;
826*c688e0c4SMarek Vasut 		}
827*c688e0c4SMarek Vasut 
828*c688e0c4SMarek Vasut 		if (!new_state.hiz) {
829*c688e0c4SMarek Vasut 			/* power inserted and not HiZ */
8308c0984e5SSebastian Reichel 			/* enable ADC, to have control of charge current/voltage */
83180211be1SYauhen Kharuzhy 			ret = bq25890_field_write(bq, F_CONV_RATE, 1);
8328c0984e5SSebastian Reichel 			if (ret < 0)
8338c0984e5SSebastian Reichel 				goto error;
8348c0984e5SSebastian Reichel 		}
835*c688e0c4SMarek Vasut 	}
8368c0984e5SSebastian Reichel 
83772d9cd9cSMichał Mirosław 	bq->state = new_state;
83872d9cd9cSMichał Mirosław 	power_supply_changed(bq->charger);
8398c0984e5SSebastian Reichel 
84072d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
8418c0984e5SSebastian Reichel error:
84272d9cd9cSMichał Mirosław 	dev_err(bq->dev, "Error communicating with the chip: %pe\n",
84372d9cd9cSMichał Mirosław 		ERR_PTR(ret));
84472d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
8458c0984e5SSebastian Reichel }
8468c0984e5SSebastian Reichel 
8478c0984e5SSebastian Reichel static irqreturn_t bq25890_irq_handler_thread(int irq, void *private)
8488c0984e5SSebastian Reichel {
8498c0984e5SSebastian Reichel 	struct bq25890_device *bq = private;
85072d9cd9cSMichał Mirosław 	irqreturn_t ret;
8518c0984e5SSebastian Reichel 
8528c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
85372d9cd9cSMichał Mirosław 	ret = __bq25890_handle_irq(bq);
8548c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
8558c0984e5SSebastian Reichel 
85672d9cd9cSMichał Mirosław 	return ret;
8578c0984e5SSebastian Reichel }
8588c0984e5SSebastian Reichel 
8598c0984e5SSebastian Reichel static int bq25890_chip_reset(struct bq25890_device *bq)
8608c0984e5SSebastian Reichel {
8618c0984e5SSebastian Reichel 	int ret;
8628c0984e5SSebastian Reichel 	int rst_check_counter = 10;
8638c0984e5SSebastian Reichel 
8648c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_REG_RST, 1);
8658c0984e5SSebastian Reichel 	if (ret < 0)
8668c0984e5SSebastian Reichel 		return ret;
8678c0984e5SSebastian Reichel 
8688c0984e5SSebastian Reichel 	do {
8698c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, F_REG_RST);
8708c0984e5SSebastian Reichel 		if (ret < 0)
8718c0984e5SSebastian Reichel 			return ret;
8728c0984e5SSebastian Reichel 
8738c0984e5SSebastian Reichel 		usleep_range(5, 10);
8748c0984e5SSebastian Reichel 	} while (ret == 1 && --rst_check_counter);
8758c0984e5SSebastian Reichel 
8768c0984e5SSebastian Reichel 	if (!rst_check_counter)
8778c0984e5SSebastian Reichel 		return -ETIMEDOUT;
8788c0984e5SSebastian Reichel 
8798c0984e5SSebastian Reichel 	return 0;
8808c0984e5SSebastian Reichel }
8818c0984e5SSebastian Reichel 
8827b22a974SHans de Goede static int bq25890_rw_init_data(struct bq25890_device *bq)
8838c0984e5SSebastian Reichel {
88440428bd4SHans de Goede 	bool write = !bq->read_back_init_data;
8858c0984e5SSebastian Reichel 	int ret;
8868c0984e5SSebastian Reichel 	int i;
8878c0984e5SSebastian Reichel 
8888c0984e5SSebastian Reichel 	const struct {
8898c0984e5SSebastian Reichel 		enum bq25890_fields id;
8907b22a974SHans de Goede 		u8 *value;
8918c0984e5SSebastian Reichel 	} init_data[] = {
8927b22a974SHans de Goede 		{F_ICHG,	 &bq->init_data.ichg},
8937b22a974SHans de Goede 		{F_VREG,	 &bq->init_data.vreg},
8947b22a974SHans de Goede 		{F_ITERM,	 &bq->init_data.iterm},
8957b22a974SHans de Goede 		{F_IPRECHG,	 &bq->init_data.iprechg},
8967b22a974SHans de Goede 		{F_SYSVMIN,	 &bq->init_data.sysvmin},
8977b22a974SHans de Goede 		{F_BOOSTV,	 &bq->init_data.boostv},
8987b22a974SHans de Goede 		{F_BOOSTI,	 &bq->init_data.boosti},
8997b22a974SHans de Goede 		{F_BOOSTF,	 &bq->init_data.boostf},
9007b22a974SHans de Goede 		{F_EN_ILIM,	 &bq->init_data.ilim_en},
9017b22a974SHans de Goede 		{F_TREG,	 &bq->init_data.treg},
9027b22a974SHans de Goede 		{F_BATCMP,	 &bq->init_data.rbatcomp},
9037b22a974SHans de Goede 		{F_VCLAMP,	 &bq->init_data.vclamp},
9048c0984e5SSebastian Reichel 	};
9058c0984e5SSebastian Reichel 
9067b22a974SHans de Goede 	for (i = 0; i < ARRAY_SIZE(init_data); i++) {
9077b22a974SHans de Goede 		if (write) {
9087b22a974SHans de Goede 			ret = bq25890_field_write(bq, init_data[i].id,
9097b22a974SHans de Goede 						  *init_data[i].value);
9107b22a974SHans de Goede 		} else {
9117b22a974SHans de Goede 			ret = bq25890_field_read(bq, init_data[i].id);
9127b22a974SHans de Goede 			if (ret >= 0)
9137b22a974SHans de Goede 				*init_data[i].value = ret;
9147b22a974SHans de Goede 		}
9157b22a974SHans de Goede 		if (ret < 0) {
9167b22a974SHans de Goede 			dev_dbg(bq->dev, "Accessing init data failed %d\n", ret);
9177b22a974SHans de Goede 			return ret;
9187b22a974SHans de Goede 		}
9197b22a974SHans de Goede 	}
9207b22a974SHans de Goede 
9217b22a974SHans de Goede 	return 0;
9227b22a974SHans de Goede }
9237b22a974SHans de Goede 
9247b22a974SHans de Goede static int bq25890_hw_init(struct bq25890_device *bq)
9257b22a974SHans de Goede {
9267b22a974SHans de Goede 	int ret;
9277b22a974SHans de Goede 
9287e3b8e35SHans de Goede 	if (!bq->skip_reset) {
9298c0984e5SSebastian Reichel 		ret = bq25890_chip_reset(bq);
9309d9ae341SAngus Ainslie (Purism) 		if (ret < 0) {
9319d9ae341SAngus Ainslie (Purism) 			dev_dbg(bq->dev, "Reset failed %d\n", ret);
9328c0984e5SSebastian Reichel 			return ret;
933ad1570d9Skbuild test robot 		}
93406c75095SHans de Goede 	} else {
93506c75095SHans de Goede 		/*
93606c75095SHans de Goede 		 * Ensure charging is enabled, on some boards where the fw
93706c75095SHans de Goede 		 * takes care of initalizition F_CHG_CFG is set to 0 before
93806c75095SHans de Goede 		 * handing control over to the OS.
93906c75095SHans de Goede 		 */
94006c75095SHans de Goede 		ret = bq25890_field_write(bq, F_CHG_CFG, 1);
94106c75095SHans de Goede 		if (ret < 0) {
94206c75095SHans de Goede 			dev_dbg(bq->dev, "Enabling charging failed %d\n", ret);
94306c75095SHans de Goede 			return ret;
94406c75095SHans de Goede 		}
9457e3b8e35SHans de Goede 	}
9468c0984e5SSebastian Reichel 
9478c0984e5SSebastian Reichel 	/* disable watchdog */
9488c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_WD, 0);
9499d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
9509d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret);
9518c0984e5SSebastian Reichel 		return ret;
952ad1570d9Skbuild test robot 	}
9538c0984e5SSebastian Reichel 
9548c0984e5SSebastian Reichel 	/* initialize currents/voltages and other parameters */
9557b22a974SHans de Goede 	ret = bq25890_rw_init_data(bq);
9567b22a974SHans de Goede 	if (ret)
9578c0984e5SSebastian Reichel 		return ret;
9588c0984e5SSebastian Reichel 
95922ad4f99SHans de Goede 	ret = bq25890_get_chip_state(bq, &bq->state);
96022ad4f99SHans de Goede 	if (ret < 0) {
96122ad4f99SHans de Goede 		dev_dbg(bq->dev, "Get state failed %d\n", ret);
96222ad4f99SHans de Goede 		return ret;
96322ad4f99SHans de Goede 	}
96422ad4f99SHans de Goede 
96521d90edaSMichał Mirosław 	/* Configure ADC for continuous conversions when charging */
96621d90edaSMichał Mirosław 	ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
9679d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
9689d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
9698c0984e5SSebastian Reichel 		return ret;
970ad1570d9Skbuild test robot 	}
9718c0984e5SSebastian Reichel 
9728c0984e5SSebastian Reichel 	return 0;
9738c0984e5SSebastian Reichel }
9748c0984e5SSebastian Reichel 
975a6a48facSMichał Mirosław static const enum power_supply_property bq25890_power_supply_props[] = {
9768c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MANUFACTURER,
9772e1a2ddeSAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_MODEL_NAME,
9788c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
979b302a0aeSMichał Mirosław 	POWER_SUPPLY_PROP_CHARGE_TYPE,
9808c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
9818c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_HEALTH,
9828327a8abSMarek Vasut 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
9838c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
9848c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
9858c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
986c942656dSMichał Mirosław 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
9878c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
988478efc79SMichał Mirosław 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
989ae6fe7a3SAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
9901e4724d0SMichał Mirosław 	POWER_SUPPLY_PROP_CURRENT_NOW,
9919652c024SAngus Ainslie 	POWER_SUPPLY_PROP_TEMP,
9928c0984e5SSebastian Reichel };
9938c0984e5SSebastian Reichel 
9948c0984e5SSebastian Reichel static char *bq25890_charger_supplied_to[] = {
9958c0984e5SSebastian Reichel 	"main-battery",
9968c0984e5SSebastian Reichel };
9978c0984e5SSebastian Reichel 
9988c0984e5SSebastian Reichel static const struct power_supply_desc bq25890_power_supply_desc = {
9998c0984e5SSebastian Reichel 	.name = "bq25890-charger",
10008c0984e5SSebastian Reichel 	.type = POWER_SUPPLY_TYPE_USB,
10018c0984e5SSebastian Reichel 	.properties = bq25890_power_supply_props,
10028c0984e5SSebastian Reichel 	.num_properties = ARRAY_SIZE(bq25890_power_supply_props),
10038c0984e5SSebastian Reichel 	.get_property = bq25890_power_supply_get_property,
10044a4748f2SMarek Vasut 	.set_property = bq25890_power_supply_set_property,
10054a4748f2SMarek Vasut 	.property_is_writeable = bq25890_power_supply_property_is_writeable,
1006eab25b4fSHans de Goede 	.external_power_changed	= bq25890_charger_external_power_changed,
10078c0984e5SSebastian Reichel };
10088c0984e5SSebastian Reichel 
10098c0984e5SSebastian Reichel static int bq25890_power_supply_init(struct bq25890_device *bq)
10108c0984e5SSebastian Reichel {
10118c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = { .drv_data = bq, };
10128c0984e5SSebastian Reichel 
10138c0984e5SSebastian Reichel 	psy_cfg.supplied_to = bq25890_charger_supplied_to;
10148c0984e5SSebastian Reichel 	psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
10158c0984e5SSebastian Reichel 
1016d01363daSHans de Goede 	bq->charger = devm_power_supply_register(bq->dev,
1017d01363daSHans de Goede 						 &bq25890_power_supply_desc,
10188c0984e5SSebastian Reichel 						 &psy_cfg);
10198c0984e5SSebastian Reichel 
10208c0984e5SSebastian Reichel 	return PTR_ERR_OR_ZERO(bq->charger);
10218c0984e5SSebastian Reichel }
10228c0984e5SSebastian Reichel 
10235575802dSHans de Goede static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val)
10245575802dSHans de Goede {
10255575802dSHans de Goede 	int ret;
10265575802dSHans de Goede 
10275575802dSHans de Goede 	ret = bq25890_field_write(bq, F_OTG_CFG, val);
10285575802dSHans de Goede 	if (ret < 0)
10295575802dSHans de Goede 		dev_err(bq->dev, "Error switching to boost/charger mode: %d\n", ret);
10305575802dSHans de Goede 
10315575802dSHans de Goede 	return ret;
10325575802dSHans de Goede }
10335575802dSHans de Goede 
103448f45b09SYauhen Kharuzhy static void bq25890_pump_express_work(struct work_struct *data)
103548f45b09SYauhen Kharuzhy {
103648f45b09SYauhen Kharuzhy 	struct bq25890_device *bq =
103748f45b09SYauhen Kharuzhy 		container_of(data, struct bq25890_device, pump_express_work.work);
103848f45b09SYauhen Kharuzhy 	int voltage, i, ret;
103948f45b09SYauhen Kharuzhy 
104048f45b09SYauhen Kharuzhy 	dev_dbg(bq->dev, "Start to request input voltage increasing\n");
104148f45b09SYauhen Kharuzhy 
104248f45b09SYauhen Kharuzhy 	/* Enable current pulse voltage control protocol */
104348f45b09SYauhen Kharuzhy 	ret = bq25890_field_write(bq, F_PUMPX_EN, 1);
104448f45b09SYauhen Kharuzhy 	if (ret < 0)
104548f45b09SYauhen Kharuzhy 		goto error_print;
104648f45b09SYauhen Kharuzhy 
104748f45b09SYauhen Kharuzhy 	for (i = 0; i < PUMP_EXPRESS_MAX_TRIES; i++) {
104848f45b09SYauhen Kharuzhy 		voltage = bq25890_get_vbus_voltage(bq);
104948f45b09SYauhen Kharuzhy 		if (voltage < 0)
105048f45b09SYauhen Kharuzhy 			goto error_print;
105148f45b09SYauhen Kharuzhy 		dev_dbg(bq->dev, "input voltage = %d uV\n", voltage);
105248f45b09SYauhen Kharuzhy 
105348f45b09SYauhen Kharuzhy 		if ((voltage + PUMP_EXPRESS_VBUS_MARGIN_uV) >
105448f45b09SYauhen Kharuzhy 					bq->pump_express_vbus_max)
105548f45b09SYauhen Kharuzhy 			break;
105648f45b09SYauhen Kharuzhy 
105748f45b09SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_PUMPX_UP, 1);
105848f45b09SYauhen Kharuzhy 		if (ret < 0)
105948f45b09SYauhen Kharuzhy 			goto error_print;
106048f45b09SYauhen Kharuzhy 
106148f45b09SYauhen Kharuzhy 		/* Note a single PUMPX up pulse-sequence takes 2.1s */
106248f45b09SYauhen Kharuzhy 		ret = regmap_field_read_poll_timeout(bq->rmap_fields[F_PUMPX_UP],
106348f45b09SYauhen Kharuzhy 						     ret, !ret, 100000, 3000000);
106448f45b09SYauhen Kharuzhy 		if (ret < 0)
106548f45b09SYauhen Kharuzhy 			goto error_print;
106648f45b09SYauhen Kharuzhy 
106748f45b09SYauhen Kharuzhy 		/* Make sure ADC has sampled Vbus before checking again */
106848f45b09SYauhen Kharuzhy 		msleep(1000);
106948f45b09SYauhen Kharuzhy 	}
107048f45b09SYauhen Kharuzhy 
107148f45b09SYauhen Kharuzhy 	bq25890_field_write(bq, F_PUMPX_EN, 0);
107248f45b09SYauhen Kharuzhy 
107348f45b09SYauhen Kharuzhy 	dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n",
107448f45b09SYauhen Kharuzhy 		 voltage);
107548f45b09SYauhen Kharuzhy 
107648f45b09SYauhen Kharuzhy 	return;
107748f45b09SYauhen Kharuzhy error_print:
107804f7c7dfSHans de Goede 	bq25890_field_write(bq, F_PUMPX_EN, 0);
107948f45b09SYauhen Kharuzhy 	dev_err(bq->dev, "Failed to request hi-voltage charging\n");
108048f45b09SYauhen Kharuzhy }
108148f45b09SYauhen Kharuzhy 
10828c0984e5SSebastian Reichel static void bq25890_usb_work(struct work_struct *data)
10838c0984e5SSebastian Reichel {
10848c0984e5SSebastian Reichel 	int ret;
10858c0984e5SSebastian Reichel 	struct bq25890_device *bq =
10868c0984e5SSebastian Reichel 			container_of(data, struct bq25890_device, usb_work);
10878c0984e5SSebastian Reichel 
10888c0984e5SSebastian Reichel 	switch (bq->usb_event) {
10898c0984e5SSebastian Reichel 	case USB_EVENT_ID:
10908c0984e5SSebastian Reichel 		/* Enable boost mode */
10915575802dSHans de Goede 		bq25890_set_otg_cfg(bq, 1);
10928c0984e5SSebastian Reichel 		break;
10938c0984e5SSebastian Reichel 
10948c0984e5SSebastian Reichel 	case USB_EVENT_NONE:
10958c0984e5SSebastian Reichel 		/* Disable boost mode */
10965575802dSHans de Goede 		ret = bq25890_set_otg_cfg(bq, 0);
10975575802dSHans de Goede 		if (ret == 0)
10988c0984e5SSebastian Reichel 			power_supply_changed(bq->charger);
10998c0984e5SSebastian Reichel 		break;
11008c0984e5SSebastian Reichel 	}
11018c0984e5SSebastian Reichel }
11028c0984e5SSebastian Reichel 
11038c0984e5SSebastian Reichel static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val,
11048c0984e5SSebastian Reichel 				void *priv)
11058c0984e5SSebastian Reichel {
11068c0984e5SSebastian Reichel 	struct bq25890_device *bq =
11078c0984e5SSebastian Reichel 			container_of(nb, struct bq25890_device, usb_nb);
11088c0984e5SSebastian Reichel 
11098c0984e5SSebastian Reichel 	bq->usb_event = val;
11108c0984e5SSebastian Reichel 	queue_work(system_power_efficient_wq, &bq->usb_work);
11118c0984e5SSebastian Reichel 
11128c0984e5SSebastian Reichel 	return NOTIFY_OK;
11138c0984e5SSebastian Reichel }
11148c0984e5SSebastian Reichel 
111579d35365SHans de Goede #ifdef CONFIG_REGULATOR
111679d35365SHans de Goede static int bq25890_vbus_enable(struct regulator_dev *rdev)
111779d35365SHans de Goede {
111879d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
111979d35365SHans de Goede 
112079d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 1);
112179d35365SHans de Goede }
112279d35365SHans de Goede 
112379d35365SHans de Goede static int bq25890_vbus_disable(struct regulator_dev *rdev)
112479d35365SHans de Goede {
112579d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
112679d35365SHans de Goede 
112779d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 0);
112879d35365SHans de Goede }
112979d35365SHans de Goede 
113079d35365SHans de Goede static int bq25890_vbus_is_enabled(struct regulator_dev *rdev)
113179d35365SHans de Goede {
113279d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
113379d35365SHans de Goede 
113479d35365SHans de Goede 	return bq25890_field_read(bq, F_OTG_CFG);
113579d35365SHans de Goede }
113679d35365SHans de Goede 
113785052e90SMarek Vasut static int bq25890_vbus_get_voltage(struct regulator_dev *rdev)
113885052e90SMarek Vasut {
113985052e90SMarek Vasut 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
114085052e90SMarek Vasut 
114185052e90SMarek Vasut 	return bq25890_get_vbus_voltage(bq);
114285052e90SMarek Vasut }
114385052e90SMarek Vasut 
114414a3d159SMarek Vasut static int bq25890_vsys_get_voltage(struct regulator_dev *rdev)
114514a3d159SMarek Vasut {
114614a3d159SMarek Vasut 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
114714a3d159SMarek Vasut 	int ret;
114814a3d159SMarek Vasut 
114914a3d159SMarek Vasut 	/* Should be some output voltage ? */
115014a3d159SMarek Vasut 	ret = bq25890_field_read(bq, F_SYSV); /* read measured value */
115114a3d159SMarek Vasut 	if (ret < 0)
115214a3d159SMarek Vasut 		return ret;
115314a3d159SMarek Vasut 
115414a3d159SMarek Vasut 	/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
115514a3d159SMarek Vasut 	return 2304000 + ret * 20000;
115614a3d159SMarek Vasut }
115714a3d159SMarek Vasut 
115879d35365SHans de Goede static const struct regulator_ops bq25890_vbus_ops = {
115979d35365SHans de Goede 	.enable = bq25890_vbus_enable,
116079d35365SHans de Goede 	.disable = bq25890_vbus_disable,
116179d35365SHans de Goede 	.is_enabled = bq25890_vbus_is_enabled,
116285052e90SMarek Vasut 	.get_voltage = bq25890_vbus_get_voltage,
116379d35365SHans de Goede };
116479d35365SHans de Goede 
116579d35365SHans de Goede static const struct regulator_desc bq25890_vbus_desc = {
116679d35365SHans de Goede 	.name = "usb_otg_vbus",
116779d35365SHans de Goede 	.of_match = "usb-otg-vbus",
116879d35365SHans de Goede 	.type = REGULATOR_VOLTAGE,
116979d35365SHans de Goede 	.owner = THIS_MODULE,
117079d35365SHans de Goede 	.ops = &bq25890_vbus_ops,
117179d35365SHans de Goede };
11725f5c10ecSMarek Vasut 
117314a3d159SMarek Vasut static const struct regulator_ops bq25890_vsys_ops = {
117414a3d159SMarek Vasut 	.get_voltage = bq25890_vsys_get_voltage,
117514a3d159SMarek Vasut };
117614a3d159SMarek Vasut 
117714a3d159SMarek Vasut static const struct regulator_desc bq25890_vsys_desc = {
117814a3d159SMarek Vasut 	.name = "vsys",
117914a3d159SMarek Vasut 	.of_match = "vsys",
118014a3d159SMarek Vasut 	.type = REGULATOR_VOLTAGE,
118114a3d159SMarek Vasut 	.owner = THIS_MODULE,
118214a3d159SMarek Vasut 	.ops = &bq25890_vsys_ops,
118314a3d159SMarek Vasut };
118414a3d159SMarek Vasut 
11855f5c10ecSMarek Vasut static int bq25890_register_regulator(struct bq25890_device *bq)
11865f5c10ecSMarek Vasut {
11875f5c10ecSMarek Vasut 	struct bq25890_platform_data *pdata = dev_get_platdata(bq->dev);
11885f5c10ecSMarek Vasut 	struct regulator_config cfg = {
11895f5c10ecSMarek Vasut 		.dev = bq->dev,
11905f5c10ecSMarek Vasut 		.driver_data = bq,
11915f5c10ecSMarek Vasut 	};
11925f5c10ecSMarek Vasut 	struct regulator_dev *reg;
11935f5c10ecSMarek Vasut 
11945f5c10ecSMarek Vasut 	if (pdata)
11955f5c10ecSMarek Vasut 		cfg.init_data = pdata->regulator_init_data;
11965f5c10ecSMarek Vasut 
11975f5c10ecSMarek Vasut 	reg = devm_regulator_register(bq->dev, &bq25890_vbus_desc, &cfg);
11985f5c10ecSMarek Vasut 	if (IS_ERR(reg)) {
11995f5c10ecSMarek Vasut 		return dev_err_probe(bq->dev, PTR_ERR(reg),
12005f5c10ecSMarek Vasut 				     "registering vbus regulator");
12015f5c10ecSMarek Vasut 	}
12025f5c10ecSMarek Vasut 
1203571650b3SHans de Goede 	/* pdata->regulator_init_data is for vbus only */
1204571650b3SHans de Goede 	cfg.init_data = NULL;
120514a3d159SMarek Vasut 	reg = devm_regulator_register(bq->dev, &bq25890_vsys_desc, &cfg);
120614a3d159SMarek Vasut 	if (IS_ERR(reg)) {
120714a3d159SMarek Vasut 		return dev_err_probe(bq->dev, PTR_ERR(reg),
120814a3d159SMarek Vasut 				     "registering vsys regulator");
120914a3d159SMarek Vasut 	}
121014a3d159SMarek Vasut 
12115f5c10ecSMarek Vasut 	return 0;
12125f5c10ecSMarek Vasut }
12135f5c10ecSMarek Vasut #else
12145f5c10ecSMarek Vasut static inline int
12155f5c10ecSMarek Vasut bq25890_register_regulator(struct bq25890_device *bq)
12165f5c10ecSMarek Vasut {
12175f5c10ecSMarek Vasut 	return 0;
12185f5c10ecSMarek Vasut }
121979d35365SHans de Goede #endif
122079d35365SHans de Goede 
1221d20267c9SYauhen Kharuzhy static int bq25890_get_chip_version(struct bq25890_device *bq)
1222d20267c9SYauhen Kharuzhy {
1223d20267c9SYauhen Kharuzhy 	int id, rev;
1224d20267c9SYauhen Kharuzhy 
1225d20267c9SYauhen Kharuzhy 	id = bq25890_field_read(bq, F_PN);
1226d20267c9SYauhen Kharuzhy 	if (id < 0) {
1227172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip ID: %d\n", id);
1228d20267c9SYauhen Kharuzhy 		return id;
1229d20267c9SYauhen Kharuzhy 	}
1230d20267c9SYauhen Kharuzhy 
1231d20267c9SYauhen Kharuzhy 	rev = bq25890_field_read(bq, F_DEV_REV);
1232d20267c9SYauhen Kharuzhy 	if (rev < 0) {
1233172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip revision: %d\n", rev);
1234cb619e80SColin Ian King 		return rev;
1235d20267c9SYauhen Kharuzhy 	}
1236d20267c9SYauhen Kharuzhy 
1237d20267c9SYauhen Kharuzhy 	switch (id) {
1238d20267c9SYauhen Kharuzhy 	case BQ25890_ID:
1239d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25890;
1240d20267c9SYauhen Kharuzhy 		break;
1241d20267c9SYauhen Kharuzhy 
1242d20267c9SYauhen Kharuzhy 	/* BQ25892 and BQ25896 share same ID 0 */
1243d20267c9SYauhen Kharuzhy 	case BQ25896_ID:
1244d20267c9SYauhen Kharuzhy 		switch (rev) {
1245d20267c9SYauhen Kharuzhy 		case 2:
1246d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25896;
1247d20267c9SYauhen Kharuzhy 			break;
1248d20267c9SYauhen Kharuzhy 		case 1:
1249d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1250d20267c9SYauhen Kharuzhy 			break;
1251d20267c9SYauhen Kharuzhy 		default:
1252d20267c9SYauhen Kharuzhy 			dev_err(bq->dev,
1253d20267c9SYauhen Kharuzhy 				"Unknown device revision %d, assume BQ25892\n",
1254d20267c9SYauhen Kharuzhy 				rev);
1255d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1256d20267c9SYauhen Kharuzhy 		}
1257d20267c9SYauhen Kharuzhy 		break;
1258d20267c9SYauhen Kharuzhy 
1259d20267c9SYauhen Kharuzhy 	case BQ25895_ID:
1260d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25895;
1261d20267c9SYauhen Kharuzhy 		break;
1262d20267c9SYauhen Kharuzhy 
1263d20267c9SYauhen Kharuzhy 	default:
1264d20267c9SYauhen Kharuzhy 		dev_err(bq->dev, "Unknown chip ID %d\n", id);
1265d20267c9SYauhen Kharuzhy 		return -ENODEV;
1266d20267c9SYauhen Kharuzhy 	}
1267d20267c9SYauhen Kharuzhy 
1268d20267c9SYauhen Kharuzhy 	return 0;
1269d20267c9SYauhen Kharuzhy }
1270d20267c9SYauhen Kharuzhy 
12718c0984e5SSebastian Reichel static int bq25890_irq_probe(struct bq25890_device *bq)
12728c0984e5SSebastian Reichel {
12738c0984e5SSebastian Reichel 	struct gpio_desc *irq;
12748c0984e5SSebastian Reichel 
127586775879SAndy Shevchenko 	irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN);
1276172d0cceSMartin Kepplinger 	if (IS_ERR(irq))
1277172d0cceSMartin Kepplinger 		return dev_err_probe(bq->dev, PTR_ERR(irq),
1278172d0cceSMartin Kepplinger 				     "Could not probe irq pin.\n");
12798c0984e5SSebastian Reichel 
12808c0984e5SSebastian Reichel 	return gpiod_to_irq(irq);
12818c0984e5SSebastian Reichel }
12828c0984e5SSebastian Reichel 
12838c0984e5SSebastian Reichel static int bq25890_fw_read_u32_props(struct bq25890_device *bq)
12848c0984e5SSebastian Reichel {
12858c0984e5SSebastian Reichel 	int ret;
12868c0984e5SSebastian Reichel 	u32 property;
12878c0984e5SSebastian Reichel 	int i;
12888c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
12898c0984e5SSebastian Reichel 	struct {
12908c0984e5SSebastian Reichel 		char *name;
12918c0984e5SSebastian Reichel 		bool optional;
12928c0984e5SSebastian Reichel 		enum bq25890_table_ids tbl_id;
12938c0984e5SSebastian Reichel 		u8 *conv_data; /* holds converted value from given property */
12948c0984e5SSebastian Reichel 	} props[] = {
12958c0984e5SSebastian Reichel 		/* required properties */
12968c0984e5SSebastian Reichel 		{"ti,charge-current", false, TBL_ICHG, &init->ichg},
12978c0984e5SSebastian Reichel 		{"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg},
12988c0984e5SSebastian Reichel 		{"ti,termination-current", false, TBL_ITERM, &init->iterm},
12998c0984e5SSebastian Reichel 		{"ti,precharge-current", false, TBL_ITERM, &init->iprechg},
13008c0984e5SSebastian Reichel 		{"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin},
13018c0984e5SSebastian Reichel 		{"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv},
13028c0984e5SSebastian Reichel 		{"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti},
13038c0984e5SSebastian Reichel 
13048c0984e5SSebastian Reichel 		/* optional properties */
130572408329SMichał Mirosław 		{"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg},
130672408329SMichał Mirosław 		{"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp},
130772408329SMichał Mirosław 		{"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp},
13088c0984e5SSebastian Reichel 	};
13098c0984e5SSebastian Reichel 
13108c0984e5SSebastian Reichel 	/* initialize data for optional properties */
13118c0984e5SSebastian Reichel 	init->treg = 3; /* 120 degrees Celsius */
131272408329SMichał Mirosław 	init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */
13138c0984e5SSebastian Reichel 
13148c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(props); i++) {
13158c0984e5SSebastian Reichel 		ret = device_property_read_u32(bq->dev, props[i].name,
13168c0984e5SSebastian Reichel 					       &property);
13178c0984e5SSebastian Reichel 		if (ret < 0) {
13188c0984e5SSebastian Reichel 			if (props[i].optional)
13198c0984e5SSebastian Reichel 				continue;
13208c0984e5SSebastian Reichel 
13219d9ae341SAngus Ainslie (Purism) 			dev_err(bq->dev, "Unable to read property %d %s\n", ret,
13229d9ae341SAngus Ainslie (Purism) 				props[i].name);
13239d9ae341SAngus Ainslie (Purism) 
13248c0984e5SSebastian Reichel 			return ret;
13258c0984e5SSebastian Reichel 		}
13268c0984e5SSebastian Reichel 
13278c0984e5SSebastian Reichel 		*props[i].conv_data = bq25890_find_idx(property,
13288c0984e5SSebastian Reichel 						       props[i].tbl_id);
13298c0984e5SSebastian Reichel 	}
13308c0984e5SSebastian Reichel 
13318c0984e5SSebastian Reichel 	return 0;
13328c0984e5SSebastian Reichel }
13338c0984e5SSebastian Reichel 
13348c0984e5SSebastian Reichel static int bq25890_fw_probe(struct bq25890_device *bq)
13358c0984e5SSebastian Reichel {
13368c0984e5SSebastian Reichel 	int ret;
13378c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
13388c0984e5SSebastian Reichel 
133948f45b09SYauhen Kharuzhy 	/* Optional, left at 0 if property is not present */
134048f45b09SYauhen Kharuzhy 	device_property_read_u32(bq->dev, "linux,pump-express-vbus-max",
134148f45b09SYauhen Kharuzhy 				 &bq->pump_express_vbus_max);
134248f45b09SYauhen Kharuzhy 
13437e3b8e35SHans de Goede 	bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset");
134440428bd4SHans de Goede 	bq->read_back_init_data = device_property_read_bool(bq->dev,
134540428bd4SHans de Goede 						"linux,read-back-settings");
134640428bd4SHans de Goede 	if (bq->read_back_init_data)
134740428bd4SHans de Goede 		return 0;
13487e3b8e35SHans de Goede 
13498c0984e5SSebastian Reichel 	ret = bq25890_fw_read_u32_props(bq);
13508c0984e5SSebastian Reichel 	if (ret < 0)
13518c0984e5SSebastian Reichel 		return ret;
13528c0984e5SSebastian Reichel 
13538c0984e5SSebastian Reichel 	init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin");
13548c0984e5SSebastian Reichel 	init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq");
13558c0984e5SSebastian Reichel 
13568c0984e5SSebastian Reichel 	return 0;
13578c0984e5SSebastian Reichel }
13588c0984e5SSebastian Reichel 
1359a7aaa800SHans de Goede static void bq25890_non_devm_cleanup(void *data)
1360a7aaa800SHans de Goede {
1361a7aaa800SHans de Goede 	struct bq25890_device *bq = data;
1362a7aaa800SHans de Goede 
1363a7aaa800SHans de Goede 	cancel_delayed_work_sync(&bq->pump_express_work);
1364a7aaa800SHans de Goede }
1365a7aaa800SHans de Goede 
1366c5cddca2SUwe Kleine-König static int bq25890_probe(struct i2c_client *client)
13678c0984e5SSebastian Reichel {
13688c0984e5SSebastian Reichel 	struct device *dev = &client->dev;
13698c0984e5SSebastian Reichel 	struct bq25890_device *bq;
13708c0984e5SSebastian Reichel 	int ret;
13718c0984e5SSebastian Reichel 
13728c0984e5SSebastian Reichel 	bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL);
13738c0984e5SSebastian Reichel 	if (!bq)
13748c0984e5SSebastian Reichel 		return -ENOMEM;
13758c0984e5SSebastian Reichel 
13768c0984e5SSebastian Reichel 	bq->client = client;
13778c0984e5SSebastian Reichel 	bq->dev = dev;
13788c0984e5SSebastian Reichel 
13798c0984e5SSebastian Reichel 	mutex_init(&bq->lock);
138048f45b09SYauhen Kharuzhy 	INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work);
13818c0984e5SSebastian Reichel 
13828c0984e5SSebastian Reichel 	bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config);
1383172d0cceSMartin Kepplinger 	if (IS_ERR(bq->rmap))
1384172d0cceSMartin Kepplinger 		return dev_err_probe(dev, PTR_ERR(bq->rmap),
1385172d0cceSMartin Kepplinger 				     "failed to allocate register map\n");
13868c0984e5SSebastian Reichel 
1387c1ae3a4eSHans de Goede 	ret = devm_regmap_field_bulk_alloc(dev, bq->rmap, bq->rmap_fields,
1388c1ae3a4eSHans de Goede 					   bq25890_reg_fields, F_MAX_FIELDS);
1389c1ae3a4eSHans de Goede 	if (ret)
1390c1ae3a4eSHans de Goede 		return ret;
13918c0984e5SSebastian Reichel 
13928c0984e5SSebastian Reichel 	i2c_set_clientdata(client, bq);
13938c0984e5SSebastian Reichel 
1394d20267c9SYauhen Kharuzhy 	ret = bq25890_get_chip_version(bq);
1395d20267c9SYauhen Kharuzhy 	if (ret) {
1396172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret);
1397d20267c9SYauhen Kharuzhy 		return ret;
13988c0984e5SSebastian Reichel 	}
13998c0984e5SSebastian Reichel 
14008c0984e5SSebastian Reichel 	ret = bq25890_fw_probe(bq);
1401f481d5b8SHans de Goede 	if (ret < 0)
1402f481d5b8SHans de Goede 		return dev_err_probe(dev, ret, "reading device properties\n");
14038c0984e5SSebastian Reichel 
14048c0984e5SSebastian Reichel 	ret = bq25890_hw_init(bq);
14058c0984e5SSebastian Reichel 	if (ret < 0) {
1406172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot initialize the chip: %d\n", ret);
14078c0984e5SSebastian Reichel 		return ret;
14088c0984e5SSebastian Reichel 	}
14098c0984e5SSebastian Reichel 
14108c0984e5SSebastian Reichel 	if (client->irq <= 0)
14118c0984e5SSebastian Reichel 		client->irq = bq25890_irq_probe(bq);
14128c0984e5SSebastian Reichel 
14138c0984e5SSebastian Reichel 	if (client->irq < 0) {
14148c0984e5SSebastian Reichel 		dev_err(dev, "No irq resource found.\n");
14158c0984e5SSebastian Reichel 		return client->irq;
14168c0984e5SSebastian Reichel 	}
14178c0984e5SSebastian Reichel 
14188c0984e5SSebastian Reichel 	/* OTG reporting */
14198c0984e5SSebastian Reichel 	bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
14205f5c10ecSMarek Vasut 
1421a7aaa800SHans de Goede 	/*
1422a7aaa800SHans de Goede 	 * This must be before bq25890_power_supply_init(), so that it runs
1423a7aaa800SHans de Goede 	 * after devm unregisters the power_supply.
1424a7aaa800SHans de Goede 	 */
1425a7aaa800SHans de Goede 	ret = devm_add_action_or_reset(dev, bq25890_non_devm_cleanup, bq);
1426a7aaa800SHans de Goede 	if (ret)
1427a7aaa800SHans de Goede 		return ret;
1428a7aaa800SHans de Goede 
14295f5c10ecSMarek Vasut 	ret = bq25890_register_regulator(bq);
14305f5c10ecSMarek Vasut 	if (ret)
14315f5c10ecSMarek Vasut 		return ret;
14325f5c10ecSMarek Vasut 
1433d01363daSHans de Goede 	ret = bq25890_power_supply_init(bq);
14347e6fb678SHans de Goede 	if (ret < 0)
14357e6fb678SHans de Goede 		return dev_err_probe(dev, ret, "registering power supply\n");
1436d01363daSHans de Goede 
14378c0984e5SSebastian Reichel 	ret = devm_request_threaded_irq(dev, client->irq, NULL,
14388c0984e5SSebastian Reichel 					bq25890_irq_handler_thread,
14398c0984e5SSebastian Reichel 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
14408c0984e5SSebastian Reichel 					BQ25890_IRQ_PIN, bq);
14418c0984e5SSebastian Reichel 	if (ret)
14427e6fb678SHans de Goede 		return ret;
14437e6fb678SHans de Goede 
14447e6fb678SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
14457e6fb678SHans de Goede 		INIT_WORK(&bq->usb_work, bq25890_usb_work);
14467e6fb678SHans de Goede 		bq->usb_nb.notifier_call = bq25890_usb_notifier;
14477e6fb678SHans de Goede 		usb_register_notifier(bq->usb_phy, &bq->usb_nb);
14487e6fb678SHans de Goede 	}
14498c0984e5SSebastian Reichel 
14508c0984e5SSebastian Reichel 	return 0;
14518c0984e5SSebastian Reichel }
14528c0984e5SSebastian Reichel 
1453ed5c2f5fSUwe Kleine-König static void bq25890_remove(struct i2c_client *client)
14548c0984e5SSebastian Reichel {
14558c0984e5SSebastian Reichel 	struct bq25890_device *bq = i2c_get_clientdata(client);
14568c0984e5SSebastian Reichel 
14577e6fb678SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
14588c0984e5SSebastian Reichel 		usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
14597e6fb678SHans de Goede 		cancel_work_sync(&bq->usb_work);
14607e6fb678SHans de Goede 	}
14618c0984e5SSebastian Reichel 
14627e3b8e35SHans de Goede 	if (!bq->skip_reset) {
14638c0984e5SSebastian Reichel 		/* reset all registers to default values */
14648c0984e5SSebastian Reichel 		bq25890_chip_reset(bq);
14657e3b8e35SHans de Goede 	}
14668c0984e5SSebastian Reichel }
14678c0984e5SSebastian Reichel 
146879d35365SHans de Goede static void bq25890_shutdown(struct i2c_client *client)
146979d35365SHans de Goede {
147079d35365SHans de Goede 	struct bq25890_device *bq = i2c_get_clientdata(client);
147179d35365SHans de Goede 
147279d35365SHans de Goede 	/*
147379d35365SHans de Goede 	 * TODO this if + return should probably be removed, but that would
147479d35365SHans de Goede 	 * introduce a function change for boards using the usb-phy framework.
147579d35365SHans de Goede 	 * This needs to be tested on such a board before making this change.
147679d35365SHans de Goede 	 */
147779d35365SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy))
147879d35365SHans de Goede 		return;
147979d35365SHans de Goede 
148079d35365SHans de Goede 	/*
148179d35365SHans de Goede 	 * Turn off the 5v Boost regulator which outputs Vbus to the device's
148279d35365SHans de Goede 	 * Micro-USB or Type-C USB port. Leaving this on drains power and
148379d35365SHans de Goede 	 * this avoids the PMIC on some device-models seeing this as Vbus
148479d35365SHans de Goede 	 * getting inserted after shutdown, causing the device to immediately
148579d35365SHans de Goede 	 * power-up again.
148679d35365SHans de Goede 	 */
148779d35365SHans de Goede 	bq25890_set_otg_cfg(bq, 0);
148879d35365SHans de Goede }
148979d35365SHans de Goede 
14908c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
14918c0984e5SSebastian Reichel static int bq25890_suspend(struct device *dev)
14928c0984e5SSebastian Reichel {
14938c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
14948c0984e5SSebastian Reichel 
14958c0984e5SSebastian Reichel 	/*
14968c0984e5SSebastian Reichel 	 * If charger is removed, while in suspend, make sure ADC is diabled
14978c0984e5SSebastian Reichel 	 * since it consumes slightly more power.
14988c0984e5SSebastian Reichel 	 */
149921d90edaSMichał Mirosław 	return bq25890_field_write(bq, F_CONV_RATE, 0);
15008c0984e5SSebastian Reichel }
15018c0984e5SSebastian Reichel 
15028c0984e5SSebastian Reichel static int bq25890_resume(struct device *dev)
15038c0984e5SSebastian Reichel {
15048c0984e5SSebastian Reichel 	int ret;
15058c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
15068c0984e5SSebastian Reichel 
150772d9cd9cSMichał Mirosław 	mutex_lock(&bq->lock);
150872d9cd9cSMichał Mirosław 
150972d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &bq->state);
15108c0984e5SSebastian Reichel 	if (ret < 0)
1511cf5701bfSDan Carpenter 		goto unlock;
15128c0984e5SSebastian Reichel 
15138c0984e5SSebastian Reichel 	/* Re-enable ADC only if charger is plugged in. */
151472d9cd9cSMichał Mirosław 	if (bq->state.online) {
151521d90edaSMichał Mirosław 		ret = bq25890_field_write(bq, F_CONV_RATE, 1);
15168c0984e5SSebastian Reichel 		if (ret < 0)
1517cf5701bfSDan Carpenter 			goto unlock;
15188c0984e5SSebastian Reichel 	}
15198c0984e5SSebastian Reichel 
15208c0984e5SSebastian Reichel 	/* signal userspace, maybe state changed while suspended */
15218c0984e5SSebastian Reichel 	power_supply_changed(bq->charger);
15228c0984e5SSebastian Reichel 
1523cf5701bfSDan Carpenter unlock:
152472d9cd9cSMichał Mirosław 	mutex_unlock(&bq->lock);
152572d9cd9cSMichał Mirosław 
1526cf5701bfSDan Carpenter 	return ret;
15278c0984e5SSebastian Reichel }
15288c0984e5SSebastian Reichel #endif
15298c0984e5SSebastian Reichel 
15308c0984e5SSebastian Reichel static const struct dev_pm_ops bq25890_pm = {
15318c0984e5SSebastian Reichel 	SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume)
15328c0984e5SSebastian Reichel };
15338c0984e5SSebastian Reichel 
15348c0984e5SSebastian Reichel static const struct i2c_device_id bq25890_i2c_ids[] = {
15358c0984e5SSebastian Reichel 	{ "bq25890", 0 },
153646aa27e7SYauhen Kharuzhy 	{ "bq25892", 0 },
153746aa27e7SYauhen Kharuzhy 	{ "bq25895", 0 },
153846aa27e7SYauhen Kharuzhy 	{ "bq25896", 0 },
15398c0984e5SSebastian Reichel 	{},
15408c0984e5SSebastian Reichel };
15418c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids);
15428c0984e5SSebastian Reichel 
15438c0984e5SSebastian Reichel static const struct of_device_id bq25890_of_match[] = {
15448c0984e5SSebastian Reichel 	{ .compatible = "ti,bq25890", },
154546aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25892", },
154646aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25895", },
154746aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25896", },
15488c0984e5SSebastian Reichel 	{ },
15498c0984e5SSebastian Reichel };
15508c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, bq25890_of_match);
15518c0984e5SSebastian Reichel 
155202067dc9SKrzysztof Kozlowski #ifdef CONFIG_ACPI
15538c0984e5SSebastian Reichel static const struct acpi_device_id bq25890_acpi_match[] = {
15548c0984e5SSebastian Reichel 	{"BQ258900", 0},
15558c0984e5SSebastian Reichel 	{},
15568c0984e5SSebastian Reichel };
15578c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match);
155802067dc9SKrzysztof Kozlowski #endif
15598c0984e5SSebastian Reichel 
15608c0984e5SSebastian Reichel static struct i2c_driver bq25890_driver = {
15618c0984e5SSebastian Reichel 	.driver = {
15628c0984e5SSebastian Reichel 		.name = "bq25890-charger",
15638c0984e5SSebastian Reichel 		.of_match_table = of_match_ptr(bq25890_of_match),
15648c0984e5SSebastian Reichel 		.acpi_match_table = ACPI_PTR(bq25890_acpi_match),
15658c0984e5SSebastian Reichel 		.pm = &bq25890_pm,
15668c0984e5SSebastian Reichel 	},
1567c5cddca2SUwe Kleine-König 	.probe_new = bq25890_probe,
15688c0984e5SSebastian Reichel 	.remove = bq25890_remove,
156979d35365SHans de Goede 	.shutdown = bq25890_shutdown,
15708c0984e5SSebastian Reichel 	.id_table = bq25890_i2c_ids,
15718c0984e5SSebastian Reichel };
15728c0984e5SSebastian Reichel module_i2c_driver(bq25890_driver);
15738c0984e5SSebastian Reichel 
15748c0984e5SSebastian Reichel MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
15758c0984e5SSebastian Reichel MODULE_DESCRIPTION("bq25890 charger driver");
15768c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
1577