xref: /openbmc/linux/drivers/power/supply/bq25890_charger.c (revision ef1ca2102e9c546a507ed43994f5dd022f7a80d3)
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;
988c0984e5SSebastian Reichel 	u8 chrg_status;
998c0984e5SSebastian Reichel 	u8 chrg_fault;
1008c0984e5SSebastian Reichel 	u8 vsys_status;
1018c0984e5SSebastian Reichel 	u8 boost_fault;
1028c0984e5SSebastian Reichel 	u8 bat_fault;
103c562a43aSYauhen Kharuzhy 	u8 ntc_fault;
1048c0984e5SSebastian Reichel };
1058c0984e5SSebastian Reichel 
1068c0984e5SSebastian Reichel struct bq25890_device {
1078c0984e5SSebastian Reichel 	struct i2c_client *client;
1088c0984e5SSebastian Reichel 	struct device *dev;
1098c0984e5SSebastian Reichel 	struct power_supply *charger;
1108c0984e5SSebastian Reichel 
1118c0984e5SSebastian Reichel 	struct usb_phy *usb_phy;
1128c0984e5SSebastian Reichel 	struct notifier_block usb_nb;
1138c0984e5SSebastian Reichel 	struct work_struct usb_work;
11448f45b09SYauhen Kharuzhy 	struct delayed_work pump_express_work;
1158c0984e5SSebastian Reichel 	unsigned long usb_event;
1168c0984e5SSebastian Reichel 
1178c0984e5SSebastian Reichel 	struct regmap *rmap;
1188c0984e5SSebastian Reichel 	struct regmap_field *rmap_fields[F_MAX_FIELDS];
1198c0984e5SSebastian Reichel 
1207e3b8e35SHans de Goede 	bool skip_reset;
12140428bd4SHans de Goede 	bool read_back_init_data;
12248f45b09SYauhen Kharuzhy 	u32 pump_express_vbus_max;
123d20267c9SYauhen Kharuzhy 	enum bq25890_chip_version chip_version;
1248c0984e5SSebastian Reichel 	struct bq25890_init_data init_data;
1258c0984e5SSebastian Reichel 	struct bq25890_state state;
1268c0984e5SSebastian Reichel 
1278c0984e5SSebastian Reichel 	struct mutex lock; /* protect state data */
1288c0984e5SSebastian Reichel };
1298c0984e5SSebastian Reichel 
1308c0984e5SSebastian Reichel static const struct regmap_range bq25890_readonly_reg_ranges[] = {
1318c0984e5SSebastian Reichel 	regmap_reg_range(0x0b, 0x0c),
1328c0984e5SSebastian Reichel 	regmap_reg_range(0x0e, 0x13),
1338c0984e5SSebastian Reichel };
1348c0984e5SSebastian Reichel 
1358c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_writeable_regs = {
1368c0984e5SSebastian Reichel 	.no_ranges = bq25890_readonly_reg_ranges,
1378c0984e5SSebastian Reichel 	.n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges),
1388c0984e5SSebastian Reichel };
1398c0984e5SSebastian Reichel 
1408c0984e5SSebastian Reichel static const struct regmap_range bq25890_volatile_reg_ranges[] = {
1418c0984e5SSebastian Reichel 	regmap_reg_range(0x00, 0x00),
14221d90edaSMichał Mirosław 	regmap_reg_range(0x02, 0x02),
1438c0984e5SSebastian Reichel 	regmap_reg_range(0x09, 0x09),
144d20267c9SYauhen Kharuzhy 	regmap_reg_range(0x0b, 0x14),
1458c0984e5SSebastian Reichel };
1468c0984e5SSebastian Reichel 
1478c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_volatile_regs = {
1488c0984e5SSebastian Reichel 	.yes_ranges = bq25890_volatile_reg_ranges,
1498c0984e5SSebastian Reichel 	.n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges),
1508c0984e5SSebastian Reichel };
1518c0984e5SSebastian Reichel 
1528c0984e5SSebastian Reichel static const struct regmap_config bq25890_regmap_config = {
1538c0984e5SSebastian Reichel 	.reg_bits = 8,
1548c0984e5SSebastian Reichel 	.val_bits = 8,
1558c0984e5SSebastian Reichel 
1568c0984e5SSebastian Reichel 	.max_register = 0x14,
1578c0984e5SSebastian Reichel 	.cache_type = REGCACHE_RBTREE,
1588c0984e5SSebastian Reichel 
1598c0984e5SSebastian Reichel 	.wr_table = &bq25890_writeable_regs,
1608c0984e5SSebastian Reichel 	.volatile_table = &bq25890_volatile_regs,
1618c0984e5SSebastian Reichel };
1628c0984e5SSebastian Reichel 
1638c0984e5SSebastian Reichel static const struct reg_field bq25890_reg_fields[] = {
1648c0984e5SSebastian Reichel 	/* REG00 */
1658c0984e5SSebastian Reichel 	[F_EN_HIZ]		= REG_FIELD(0x00, 7, 7),
1668c0984e5SSebastian Reichel 	[F_EN_ILIM]		= REG_FIELD(0x00, 6, 6),
167766873c1SYauhen Kharuzhy 	[F_IINLIM]		= REG_FIELD(0x00, 0, 5),
1688c0984e5SSebastian Reichel 	/* REG01 */
1698c0984e5SSebastian Reichel 	[F_BHOT]		= REG_FIELD(0x01, 6, 7),
1708c0984e5SSebastian Reichel 	[F_BCOLD]		= REG_FIELD(0x01, 5, 5),
1718c0984e5SSebastian Reichel 	[F_VINDPM_OFS]		= REG_FIELD(0x01, 0, 4),
1728c0984e5SSebastian Reichel 	/* REG02 */
1738c0984e5SSebastian Reichel 	[F_CONV_START]		= REG_FIELD(0x02, 7, 7),
1748c0984e5SSebastian Reichel 	[F_CONV_RATE]		= REG_FIELD(0x02, 6, 6),
1758c0984e5SSebastian Reichel 	[F_BOOSTF]		= REG_FIELD(0x02, 5, 5),
1768c0984e5SSebastian Reichel 	[F_ICO_EN]		= REG_FIELD(0x02, 4, 4),
1772e1a2ddeSAngus Ainslie (Purism) 	[F_HVDCP_EN]		= REG_FIELD(0x02, 3, 3),  // reserved on BQ25896
1782e1a2ddeSAngus Ainslie (Purism) 	[F_MAXC_EN]		= REG_FIELD(0x02, 2, 2),  // reserved on BQ25896
1798c0984e5SSebastian Reichel 	[F_FORCE_DPM]		= REG_FIELD(0x02, 1, 1),
1808c0984e5SSebastian Reichel 	[F_AUTO_DPDM_EN]	= REG_FIELD(0x02, 0, 0),
1818c0984e5SSebastian Reichel 	/* REG03 */
1828c0984e5SSebastian Reichel 	[F_BAT_LOAD_EN]		= REG_FIELD(0x03, 7, 7),
1838c0984e5SSebastian Reichel 	[F_WD_RST]		= REG_FIELD(0x03, 6, 6),
1848c0984e5SSebastian Reichel 	[F_OTG_CFG]		= REG_FIELD(0x03, 5, 5),
1858c0984e5SSebastian Reichel 	[F_CHG_CFG]		= REG_FIELD(0x03, 4, 4),
1868c0984e5SSebastian Reichel 	[F_SYSVMIN]		= REG_FIELD(0x03, 1, 3),
187d20267c9SYauhen Kharuzhy 	[F_MIN_VBAT_SEL]	= REG_FIELD(0x03, 0, 0), // BQ25896 only
1888c0984e5SSebastian Reichel 	/* REG04 */
1898c0984e5SSebastian Reichel 	[F_PUMPX_EN]		= REG_FIELD(0x04, 7, 7),
1908c0984e5SSebastian Reichel 	[F_ICHG]		= REG_FIELD(0x04, 0, 6),
1918c0984e5SSebastian Reichel 	/* REG05 */
1928c0984e5SSebastian Reichel 	[F_IPRECHG]		= REG_FIELD(0x05, 4, 7),
1938c0984e5SSebastian Reichel 	[F_ITERM]		= REG_FIELD(0x05, 0, 3),
1948c0984e5SSebastian Reichel 	/* REG06 */
1958c0984e5SSebastian Reichel 	[F_VREG]		= REG_FIELD(0x06, 2, 7),
1968c0984e5SSebastian Reichel 	[F_BATLOWV]		= REG_FIELD(0x06, 1, 1),
1978c0984e5SSebastian Reichel 	[F_VRECHG]		= REG_FIELD(0x06, 0, 0),
1988c0984e5SSebastian Reichel 	/* REG07 */
1998c0984e5SSebastian Reichel 	[F_TERM_EN]		= REG_FIELD(0x07, 7, 7),
2008c0984e5SSebastian Reichel 	[F_STAT_DIS]		= REG_FIELD(0x07, 6, 6),
2018c0984e5SSebastian Reichel 	[F_WD]			= REG_FIELD(0x07, 4, 5),
2028c0984e5SSebastian Reichel 	[F_TMR_EN]		= REG_FIELD(0x07, 3, 3),
2038c0984e5SSebastian Reichel 	[F_CHG_TMR]		= REG_FIELD(0x07, 1, 2),
2045c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_ISET]		= REG_FIELD(0x07, 0, 0), // reserved on BQ25895
2058c0984e5SSebastian Reichel 	/* REG08 */
20695809139SMichał Mirosław 	[F_BATCMP]		= REG_FIELD(0x08, 5, 7),
2078c0984e5SSebastian Reichel 	[F_VCLAMP]		= REG_FIELD(0x08, 2, 4),
2088c0984e5SSebastian Reichel 	[F_TREG]		= REG_FIELD(0x08, 0, 1),
2098c0984e5SSebastian Reichel 	/* REG09 */
2108c0984e5SSebastian Reichel 	[F_FORCE_ICO]		= REG_FIELD(0x09, 7, 7),
2118c0984e5SSebastian Reichel 	[F_TMR2X_EN]		= REG_FIELD(0x09, 6, 6),
2128c0984e5SSebastian Reichel 	[F_BATFET_DIS]		= REG_FIELD(0x09, 5, 5),
2135c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_VSET]		= REG_FIELD(0x09, 4, 4), // reserved on BQ25895
2148c0984e5SSebastian Reichel 	[F_BATFET_DLY]		= REG_FIELD(0x09, 3, 3),
2158c0984e5SSebastian Reichel 	[F_BATFET_RST_EN]	= REG_FIELD(0x09, 2, 2),
2168c0984e5SSebastian Reichel 	[F_PUMPX_UP]		= REG_FIELD(0x09, 1, 1),
2178c0984e5SSebastian Reichel 	[F_PUMPX_DN]		= REG_FIELD(0x09, 0, 0),
2188c0984e5SSebastian Reichel 	/* REG0A */
2198c0984e5SSebastian Reichel 	[F_BOOSTV]		= REG_FIELD(0x0A, 4, 7),
2205c35ba9bSAngus Ainslie (Purism) 	[F_BOOSTI]		= REG_FIELD(0x0A, 0, 2), // reserved on BQ25895
221d20267c9SYauhen Kharuzhy 	[F_PFM_OTG_DIS]		= REG_FIELD(0x0A, 3, 3), // BQ25896 only
2228c0984e5SSebastian Reichel 	/* REG0B */
2238c0984e5SSebastian Reichel 	[F_VBUS_STAT]		= REG_FIELD(0x0B, 5, 7),
2248c0984e5SSebastian Reichel 	[F_CHG_STAT]		= REG_FIELD(0x0B, 3, 4),
2258c0984e5SSebastian Reichel 	[F_PG_STAT]		= REG_FIELD(0x0B, 2, 2),
2262e1a2ddeSAngus Ainslie (Purism) 	[F_SDP_STAT]		= REG_FIELD(0x0B, 1, 1), // reserved on BQ25896
2278c0984e5SSebastian Reichel 	[F_VSYS_STAT]		= REG_FIELD(0x0B, 0, 0),
2288c0984e5SSebastian Reichel 	/* REG0C */
2298c0984e5SSebastian Reichel 	[F_WD_FAULT]		= REG_FIELD(0x0C, 7, 7),
2308c0984e5SSebastian Reichel 	[F_BOOST_FAULT]		= REG_FIELD(0x0C, 6, 6),
2318c0984e5SSebastian Reichel 	[F_CHG_FAULT]		= REG_FIELD(0x0C, 4, 5),
2328c0984e5SSebastian Reichel 	[F_BAT_FAULT]		= REG_FIELD(0x0C, 3, 3),
2338c0984e5SSebastian Reichel 	[F_NTC_FAULT]		= REG_FIELD(0x0C, 0, 2),
2348c0984e5SSebastian Reichel 	/* REG0D */
2358c0984e5SSebastian Reichel 	[F_FORCE_VINDPM]	= REG_FIELD(0x0D, 7, 7),
2368c0984e5SSebastian Reichel 	[F_VINDPM]		= REG_FIELD(0x0D, 0, 6),
2378c0984e5SSebastian Reichel 	/* REG0E */
2388c0984e5SSebastian Reichel 	[F_THERM_STAT]		= REG_FIELD(0x0E, 7, 7),
2398c0984e5SSebastian Reichel 	[F_BATV]		= REG_FIELD(0x0E, 0, 6),
2408c0984e5SSebastian Reichel 	/* REG0F */
2418c0984e5SSebastian Reichel 	[F_SYSV]		= REG_FIELD(0x0F, 0, 6),
2428c0984e5SSebastian Reichel 	/* REG10 */
2438c0984e5SSebastian Reichel 	[F_TSPCT]		= REG_FIELD(0x10, 0, 6),
2448c0984e5SSebastian Reichel 	/* REG11 */
2458c0984e5SSebastian Reichel 	[F_VBUS_GD]		= REG_FIELD(0x11, 7, 7),
2468c0984e5SSebastian Reichel 	[F_VBUSV]		= REG_FIELD(0x11, 0, 6),
2478c0984e5SSebastian Reichel 	/* REG12 */
2488c0984e5SSebastian Reichel 	[F_ICHGR]		= REG_FIELD(0x12, 0, 6),
2498c0984e5SSebastian Reichel 	/* REG13 */
2508c0984e5SSebastian Reichel 	[F_VDPM_STAT]		= REG_FIELD(0x13, 7, 7),
2518c0984e5SSebastian Reichel 	[F_IDPM_STAT]		= REG_FIELD(0x13, 6, 6),
2528c0984e5SSebastian Reichel 	[F_IDPM_LIM]		= REG_FIELD(0x13, 0, 5),
2538c0984e5SSebastian Reichel 	/* REG14 */
2548c0984e5SSebastian Reichel 	[F_REG_RST]		= REG_FIELD(0x14, 7, 7),
2558c0984e5SSebastian Reichel 	[F_ICO_OPTIMIZED]	= REG_FIELD(0x14, 6, 6),
2568c0984e5SSebastian Reichel 	[F_PN]			= REG_FIELD(0x14, 3, 5),
2578c0984e5SSebastian Reichel 	[F_TS_PROFILE]		= REG_FIELD(0x14, 2, 2),
2588c0984e5SSebastian Reichel 	[F_DEV_REV]		= REG_FIELD(0x14, 0, 1)
2598c0984e5SSebastian Reichel };
2608c0984e5SSebastian Reichel 
2618c0984e5SSebastian Reichel /*
2628c0984e5SSebastian Reichel  * Most of the val -> idx conversions can be computed, given the minimum,
2638c0984e5SSebastian Reichel  * maximum and the step between values. For the rest of conversions, we use
2648c0984e5SSebastian Reichel  * lookup tables.
2658c0984e5SSebastian Reichel  */
2668c0984e5SSebastian Reichel enum bq25890_table_ids {
2678c0984e5SSebastian Reichel 	/* range tables */
2688c0984e5SSebastian Reichel 	TBL_ICHG,
2698c0984e5SSebastian Reichel 	TBL_ITERM,
270766873c1SYauhen Kharuzhy 	TBL_IINLIM,
2718c0984e5SSebastian Reichel 	TBL_VREG,
2728c0984e5SSebastian Reichel 	TBL_BOOSTV,
2738c0984e5SSebastian Reichel 	TBL_SYSVMIN,
27448f45b09SYauhen Kharuzhy 	TBL_VBUSV,
27572408329SMichał Mirosław 	TBL_VBATCOMP,
27672408329SMichał Mirosław 	TBL_RBATCOMP,
2778c0984e5SSebastian Reichel 
2788c0984e5SSebastian Reichel 	/* lookup tables */
2798c0984e5SSebastian Reichel 	TBL_TREG,
2808c0984e5SSebastian Reichel 	TBL_BOOSTI,
2819652c024SAngus Ainslie 	TBL_TSPCT,
2828c0984e5SSebastian Reichel };
2838c0984e5SSebastian Reichel 
2848c0984e5SSebastian Reichel /* Thermal Regulation Threshold lookup table, in degrees Celsius */
2858c0984e5SSebastian Reichel static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 };
2868c0984e5SSebastian Reichel 
2878c0984e5SSebastian Reichel #define BQ25890_TREG_TBL_SIZE		ARRAY_SIZE(bq25890_treg_tbl)
2888c0984e5SSebastian Reichel 
2898c0984e5SSebastian Reichel /* Boost mode current limit lookup table, in uA */
2908c0984e5SSebastian Reichel static const u32 bq25890_boosti_tbl[] = {
2918c0984e5SSebastian Reichel 	500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000
2928c0984e5SSebastian Reichel };
2938c0984e5SSebastian Reichel 
2948c0984e5SSebastian Reichel #define BQ25890_BOOSTI_TBL_SIZE		ARRAY_SIZE(bq25890_boosti_tbl)
2958c0984e5SSebastian Reichel 
2969652c024SAngus Ainslie /* NTC 10K temperature lookup table in tenths of a degree */
2979652c024SAngus Ainslie static const u32 bq25890_tspct_tbl[] = {
2989652c024SAngus Ainslie 	850, 840, 830, 820, 810, 800, 790, 780,
2999652c024SAngus Ainslie 	770, 760, 750, 740, 730, 720, 710, 700,
3009652c024SAngus Ainslie 	690, 685, 680, 675, 670, 660, 650, 645,
3019652c024SAngus Ainslie 	640, 630, 620, 615, 610, 600, 590, 585,
3029652c024SAngus Ainslie 	580, 570, 565, 560, 550, 540, 535, 530,
3039652c024SAngus Ainslie 	520, 515, 510, 500, 495, 490, 480, 475,
3049652c024SAngus Ainslie 	470, 460, 455, 450, 440, 435, 430, 425,
3059652c024SAngus Ainslie 	420, 410, 405, 400, 390, 385, 380, 370,
3069652c024SAngus Ainslie 	365, 360, 355, 350, 340, 335, 330, 320,
3079652c024SAngus Ainslie 	310, 305, 300, 290, 285, 280, 275, 270,
3089652c024SAngus Ainslie 	260, 250, 245, 240, 230, 225, 220, 210,
3099652c024SAngus Ainslie 	205, 200, 190, 180, 175, 170, 160, 150,
3109652c024SAngus Ainslie 	145, 140, 130, 120, 115, 110, 100, 90,
3119652c024SAngus Ainslie 	80, 70, 60, 50, 40, 30, 20, 10,
3129652c024SAngus Ainslie 	0, -10, -20, -30, -40, -60, -70, -80,
3139652c024SAngus Ainslie 	-90, -10, -120, -140, -150, -170, -190, -210,
3149652c024SAngus Ainslie };
3159652c024SAngus Ainslie 
3169652c024SAngus Ainslie #define BQ25890_TSPCT_TBL_SIZE		ARRAY_SIZE(bq25890_tspct_tbl)
3179652c024SAngus Ainslie 
3188c0984e5SSebastian Reichel struct bq25890_range {
3198c0984e5SSebastian Reichel 	u32 min;
3208c0984e5SSebastian Reichel 	u32 max;
3218c0984e5SSebastian Reichel 	u32 step;
3228c0984e5SSebastian Reichel };
3238c0984e5SSebastian Reichel 
3248c0984e5SSebastian Reichel struct bq25890_lookup {
3258c0984e5SSebastian Reichel 	const u32 *tbl;
3268c0984e5SSebastian Reichel 	u32 size;
3278c0984e5SSebastian Reichel };
3288c0984e5SSebastian Reichel 
3298c0984e5SSebastian Reichel static const union {
3308c0984e5SSebastian Reichel 	struct bq25890_range  rt;
3318c0984e5SSebastian Reichel 	struct bq25890_lookup lt;
3328c0984e5SSebastian Reichel } bq25890_tables[] = {
3338c0984e5SSebastian Reichel 	/* range tables */
334d20267c9SYauhen Kharuzhy 	/* TODO: BQ25896 has max ICHG 3008 mA */
3358c0984e5SSebastian Reichel 	[TBL_ICHG] =	 { .rt = {0,        5056000, 64000} },	 /* uA */
3368c0984e5SSebastian Reichel 	[TBL_ITERM] =	 { .rt = {64000,    1024000, 64000} },	 /* uA */
337766873c1SYauhen Kharuzhy 	[TBL_IINLIM] =   { .rt = {100000,   3250000, 50000} },	 /* uA */
3388c0984e5SSebastian Reichel 	[TBL_VREG] =	 { .rt = {3840000,  4608000, 16000} },	 /* uV */
3398c0984e5SSebastian Reichel 	[TBL_BOOSTV] =	 { .rt = {4550000,  5510000, 64000} },	 /* uV */
3408c0984e5SSebastian Reichel 	[TBL_SYSVMIN] =  { .rt = {3000000,  3700000, 100000} },	 /* uV */
34148f45b09SYauhen Kharuzhy 	[TBL_VBUSV] =	 { .rt = {2600000, 15300000, 100000} },	 /* uV */
34272408329SMichał Mirosław 	[TBL_VBATCOMP] = { .rt = {0,         224000, 32000} },	 /* uV */
34372408329SMichał Mirosław 	[TBL_RBATCOMP] = { .rt = {0,         140000, 20000} },	 /* uOhm */
3448c0984e5SSebastian Reichel 
3458c0984e5SSebastian Reichel 	/* lookup tables */
3468c0984e5SSebastian Reichel 	[TBL_TREG] =	{ .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} },
3479652c024SAngus Ainslie 	[TBL_BOOSTI] =	{ .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} },
3489652c024SAngus Ainslie 	[TBL_TSPCT] =	{ .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} }
3498c0984e5SSebastian Reichel };
3508c0984e5SSebastian Reichel 
3518c0984e5SSebastian Reichel static int bq25890_field_read(struct bq25890_device *bq,
3528c0984e5SSebastian Reichel 			      enum bq25890_fields field_id)
3538c0984e5SSebastian Reichel {
3548c0984e5SSebastian Reichel 	int ret;
3558c0984e5SSebastian Reichel 	int val;
3568c0984e5SSebastian Reichel 
3578c0984e5SSebastian Reichel 	ret = regmap_field_read(bq->rmap_fields[field_id], &val);
3588c0984e5SSebastian Reichel 	if (ret < 0)
3598c0984e5SSebastian Reichel 		return ret;
3608c0984e5SSebastian Reichel 
3618c0984e5SSebastian Reichel 	return val;
3628c0984e5SSebastian Reichel }
3638c0984e5SSebastian Reichel 
3648c0984e5SSebastian Reichel static int bq25890_field_write(struct bq25890_device *bq,
3658c0984e5SSebastian Reichel 			       enum bq25890_fields field_id, u8 val)
3668c0984e5SSebastian Reichel {
3678c0984e5SSebastian Reichel 	return regmap_field_write(bq->rmap_fields[field_id], val);
3688c0984e5SSebastian Reichel }
3698c0984e5SSebastian Reichel 
3708c0984e5SSebastian Reichel static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id)
3718c0984e5SSebastian Reichel {
3728c0984e5SSebastian Reichel 	u8 idx;
3738c0984e5SSebastian Reichel 
3748c0984e5SSebastian Reichel 	if (id >= TBL_TREG) {
3758c0984e5SSebastian Reichel 		const u32 *tbl = bq25890_tables[id].lt.tbl;
3768c0984e5SSebastian Reichel 		u32 tbl_size = bq25890_tables[id].lt.size;
3778c0984e5SSebastian Reichel 
3788c0984e5SSebastian Reichel 		for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++)
3798c0984e5SSebastian Reichel 			;
3808c0984e5SSebastian Reichel 	} else {
3818c0984e5SSebastian Reichel 		const struct bq25890_range *rtbl = &bq25890_tables[id].rt;
3828c0984e5SSebastian Reichel 		u8 rtbl_size;
3838c0984e5SSebastian Reichel 
3848c0984e5SSebastian Reichel 		rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1;
3858c0984e5SSebastian Reichel 
3868c0984e5SSebastian Reichel 		for (idx = 1;
3878c0984e5SSebastian Reichel 		     idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value);
3888c0984e5SSebastian Reichel 		     idx++)
3898c0984e5SSebastian Reichel 			;
3908c0984e5SSebastian Reichel 	}
3918c0984e5SSebastian Reichel 
3928c0984e5SSebastian Reichel 	return idx - 1;
3938c0984e5SSebastian Reichel }
3948c0984e5SSebastian Reichel 
3958c0984e5SSebastian Reichel static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id)
3968c0984e5SSebastian Reichel {
3978c0984e5SSebastian Reichel 	const struct bq25890_range *rtbl;
3988c0984e5SSebastian Reichel 
3998c0984e5SSebastian Reichel 	/* lookup table? */
4008c0984e5SSebastian Reichel 	if (id >= TBL_TREG)
4018c0984e5SSebastian Reichel 		return bq25890_tables[id].lt.tbl[idx];
4028c0984e5SSebastian Reichel 
4038c0984e5SSebastian Reichel 	/* range table */
4048c0984e5SSebastian Reichel 	rtbl = &bq25890_tables[id].rt;
4058c0984e5SSebastian Reichel 
4068c0984e5SSebastian Reichel 	return (rtbl->min + idx * rtbl->step);
4078c0984e5SSebastian Reichel }
4088c0984e5SSebastian Reichel 
4098c0984e5SSebastian Reichel enum bq25890_status {
4108c0984e5SSebastian Reichel 	STATUS_NOT_CHARGING,
4118c0984e5SSebastian Reichel 	STATUS_PRE_CHARGING,
4128c0984e5SSebastian Reichel 	STATUS_FAST_CHARGING,
4138c0984e5SSebastian Reichel 	STATUS_TERMINATION_DONE,
4148c0984e5SSebastian Reichel };
4158c0984e5SSebastian Reichel 
4168c0984e5SSebastian Reichel enum bq25890_chrg_fault {
4178c0984e5SSebastian Reichel 	CHRG_FAULT_NORMAL,
4188c0984e5SSebastian Reichel 	CHRG_FAULT_INPUT,
4198c0984e5SSebastian Reichel 	CHRG_FAULT_THERMAL_SHUTDOWN,
4208c0984e5SSebastian Reichel 	CHRG_FAULT_TIMER_EXPIRED,
4218c0984e5SSebastian Reichel };
4228c0984e5SSebastian Reichel 
423c562a43aSYauhen Kharuzhy enum bq25890_ntc_fault {
424c562a43aSYauhen Kharuzhy 	NTC_FAULT_NORMAL = 0,
425c562a43aSYauhen Kharuzhy 	NTC_FAULT_WARM = 2,
426c562a43aSYauhen Kharuzhy 	NTC_FAULT_COOL = 3,
427c562a43aSYauhen Kharuzhy 	NTC_FAULT_COLD = 5,
428c562a43aSYauhen Kharuzhy 	NTC_FAULT_HOT = 6,
429c562a43aSYauhen Kharuzhy };
430c562a43aSYauhen Kharuzhy 
43121d90edaSMichał Mirosław static bool bq25890_is_adc_property(enum power_supply_property psp)
43221d90edaSMichał Mirosław {
43321d90edaSMichał Mirosław 	switch (psp) {
43421d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
43521d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_CURRENT_NOW:
4369652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
43721d90edaSMichał Mirosław 		return true;
43821d90edaSMichał Mirosław 
43921d90edaSMichał Mirosław 	default:
44021d90edaSMichał Mirosław 		return false;
44121d90edaSMichał Mirosław 	}
44221d90edaSMichał Mirosław }
44321d90edaSMichał Mirosław 
4443b4df57bSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq);
4453b4df57bSMichał Mirosław 
44648f45b09SYauhen Kharuzhy static int bq25890_get_vbus_voltage(struct bq25890_device *bq)
44748f45b09SYauhen Kharuzhy {
44848f45b09SYauhen Kharuzhy 	int ret;
44948f45b09SYauhen Kharuzhy 
45048f45b09SYauhen Kharuzhy 	ret = bq25890_field_read(bq, F_VBUSV);
45148f45b09SYauhen Kharuzhy 	if (ret < 0)
45248f45b09SYauhen Kharuzhy 		return ret;
45348f45b09SYauhen Kharuzhy 
45448f45b09SYauhen Kharuzhy 	return bq25890_find_val(ret, TBL_VBUSV);
45548f45b09SYauhen Kharuzhy }
45648f45b09SYauhen Kharuzhy 
4578c0984e5SSebastian Reichel static int bq25890_power_supply_get_property(struct power_supply *psy,
4588c0984e5SSebastian Reichel 					     enum power_supply_property psp,
4598c0984e5SSebastian Reichel 					     union power_supply_propval *val)
4608c0984e5SSebastian Reichel {
4618c0984e5SSebastian Reichel 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
4628c0984e5SSebastian Reichel 	struct bq25890_state state;
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);
4698c0984e5SSebastian Reichel 	state = bq->state;
47021d90edaSMichał Mirosław 	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);
47821d90edaSMichał Mirosław 
4798c0984e5SSebastian Reichel 	switch (psp) {
4808c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_STATUS:
4818c0984e5SSebastian Reichel 		if (!state.online)
4828c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
4838c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_NOT_CHARGING)
4848c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
4858c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_PRE_CHARGING ||
4868c0984e5SSebastian Reichel 			 state.chrg_status == STATUS_FAST_CHARGING)
4878c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
4888c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_TERMINATION_DONE)
4898c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_FULL;
4908c0984e5SSebastian Reichel 		else
4918c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
4928c0984e5SSebastian Reichel 
4938c0984e5SSebastian Reichel 		break;
4948c0984e5SSebastian Reichel 
495b302a0aeSMichał Mirosław 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
496b302a0aeSMichał Mirosław 		if (!state.online || state.chrg_status == STATUS_NOT_CHARGING ||
497b302a0aeSMichał Mirosław 		    state.chrg_status == STATUS_TERMINATION_DONE)
498b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
499b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_PRE_CHARGING)
500b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
501b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_FAST_CHARGING)
502b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
503b302a0aeSMichał Mirosław 		else /* unreachable */
504b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
505b302a0aeSMichał Mirosław 		break;
506b302a0aeSMichał Mirosław 
5078c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MANUFACTURER:
5088c0984e5SSebastian Reichel 		val->strval = BQ25890_MANUFACTURER;
5098c0984e5SSebastian Reichel 		break;
5108c0984e5SSebastian Reichel 
5112e1a2ddeSAngus Ainslie (Purism) 	case POWER_SUPPLY_PROP_MODEL_NAME:
5125956fca7SMichał Mirosław 		val->strval = bq25890_chip_name[bq->chip_version];
5132e1a2ddeSAngus Ainslie (Purism) 		break;
5142e1a2ddeSAngus Ainslie (Purism) 
5158c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
5168c0984e5SSebastian Reichel 		val->intval = state.online;
5178c0984e5SSebastian Reichel 		break;
5188c0984e5SSebastian Reichel 
5198c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_HEALTH:
5208c0984e5SSebastian Reichel 		if (!state.chrg_fault && !state.bat_fault && !state.boost_fault)
5218c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_GOOD;
5228c0984e5SSebastian Reichel 		else if (state.bat_fault)
5238c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
5248c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED)
5258c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
5268c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN)
5278c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
5288c0984e5SSebastian Reichel 		else
5298c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
5308c0984e5SSebastian Reichel 		break;
5318c0984e5SSebastian Reichel 
5328c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
533f83a6eceSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
534c562a43aSYauhen Kharuzhy 
535c562a43aSYauhen Kharuzhy 		/* When temperature is too low, charge current is decreased */
536c562a43aSYauhen Kharuzhy 		if (bq->state.ntc_fault == NTC_FAULT_COOL) {
537c562a43aSYauhen Kharuzhy 			ret = bq25890_field_read(bq, F_JEITA_ISET);
538c562a43aSYauhen Kharuzhy 			if (ret < 0)
539c562a43aSYauhen Kharuzhy 				return ret;
540c562a43aSYauhen Kharuzhy 
541c562a43aSYauhen Kharuzhy 			if (ret)
542c562a43aSYauhen Kharuzhy 				val->intval /= 5;
543c562a43aSYauhen Kharuzhy 			else
544c562a43aSYauhen Kharuzhy 				val->intval /= 2;
545c562a43aSYauhen Kharuzhy 		}
5468c0984e5SSebastian Reichel 		break;
5478c0984e5SSebastian Reichel 
5488c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
5498c0984e5SSebastian Reichel 		if (!state.online) {
5508c0984e5SSebastian Reichel 			val->intval = 0;
5518c0984e5SSebastian Reichel 			break;
5528c0984e5SSebastian Reichel 		}
5538c0984e5SSebastian Reichel 
5548c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, F_BATV); /* read measured value */
5558c0984e5SSebastian Reichel 		if (ret < 0)
5568c0984e5SSebastian Reichel 			return ret;
5578c0984e5SSebastian Reichel 
5588c0984e5SSebastian Reichel 		/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
5598c0984e5SSebastian Reichel 		val->intval = 2304000 + ret * 20000;
5608c0984e5SSebastian Reichel 		break;
5618c0984e5SSebastian Reichel 
5628c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
563f83a6eceSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
5648c0984e5SSebastian Reichel 		break;
5658c0984e5SSebastian Reichel 
566c942656dSMichał Mirosław 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
567c942656dSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM);
568c942656dSMichał Mirosław 		break;
569c942656dSMichał Mirosław 
5708c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
5718c0984e5SSebastian Reichel 		val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM);
5728c0984e5SSebastian Reichel 		break;
5738c0984e5SSebastian Reichel 
574478efc79SMichał Mirosław 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
575766873c1SYauhen Kharuzhy 		ret = bq25890_field_read(bq, F_IINLIM);
576478efc79SMichał Mirosław 		if (ret < 0)
577478efc79SMichał Mirosław 			return ret;
578478efc79SMichał Mirosław 
579766873c1SYauhen Kharuzhy 		val->intval = bq25890_find_val(ret, TBL_IINLIM);
580478efc79SMichał Mirosław 		break;
581478efc79SMichał Mirosław 
582ae6fe7a3SAngus Ainslie (Purism) 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
583ae6fe7a3SAngus Ainslie (Purism) 		ret = bq25890_field_read(bq, F_SYSV); /* read measured value */
584ae6fe7a3SAngus Ainslie (Purism) 		if (ret < 0)
585ae6fe7a3SAngus Ainslie (Purism) 			return ret;
586ae6fe7a3SAngus Ainslie (Purism) 
587ae6fe7a3SAngus Ainslie (Purism) 		/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
588ae6fe7a3SAngus Ainslie (Purism) 		val->intval = 2304000 + ret * 20000;
589ae6fe7a3SAngus Ainslie (Purism) 		break;
590ae6fe7a3SAngus Ainslie (Purism) 
591*ef1ca210SMarek Vasut 	case POWER_SUPPLY_PROP_CURRENT_NOW:	/* I_BAT now */
592*ef1ca210SMarek Vasut 		/*
593*ef1ca210SMarek Vasut 		 * This is ADC-sampled immediate charge current supplied
594*ef1ca210SMarek Vasut 		 * from charger to battery. The property name is confusing,
595*ef1ca210SMarek Vasut 		 * for clarification refer to:
596*ef1ca210SMarek Vasut 		 * Documentation/ABI/testing/sysfs-class-power
597*ef1ca210SMarek Vasut 		 * /sys/class/power_supply/<supply_name>/current_now
598*ef1ca210SMarek Vasut 		 */
5991e4724d0SMichał Mirosław 		ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */
6001e4724d0SMichał Mirosław 		if (ret < 0)
6011e4724d0SMichał Mirosław 			return ret;
6021e4724d0SMichał Mirosław 
6031e4724d0SMichał Mirosław 		/* converted_val = ADC_val * 50mA (table 10.3.19) */
6041e4724d0SMichał Mirosław 		val->intval = ret * -50000;
6051e4724d0SMichał Mirosław 		break;
6061e4724d0SMichał Mirosław 
6079652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
6089652c024SAngus Ainslie 		ret = bq25890_field_read(bq, F_TSPCT);
6099652c024SAngus Ainslie 		if (ret < 0)
6109652c024SAngus Ainslie 			return ret;
6119652c024SAngus Ainslie 
6129652c024SAngus Ainslie 		/* convert TS percentage into rough temperature */
6139652c024SAngus Ainslie 		val->intval = bq25890_find_val(ret, TBL_TSPCT);
6149652c024SAngus Ainslie 		break;
6159652c024SAngus Ainslie 
6168c0984e5SSebastian Reichel 	default:
6178c0984e5SSebastian Reichel 		return -EINVAL;
6188c0984e5SSebastian Reichel 	}
6198c0984e5SSebastian Reichel 
6208c0984e5SSebastian Reichel 	return 0;
6218c0984e5SSebastian Reichel }
6228c0984e5SSebastian Reichel 
6234a4748f2SMarek Vasut static int bq25890_power_supply_set_property(struct power_supply *psy,
6244a4748f2SMarek Vasut 					     enum power_supply_property psp,
6254a4748f2SMarek Vasut 					     const union power_supply_propval *val)
6264a4748f2SMarek Vasut {
6274a4748f2SMarek Vasut 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
6284a4748f2SMarek Vasut 	u8 lval;
6294a4748f2SMarek Vasut 
6304a4748f2SMarek Vasut 	switch (psp) {
6314a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
63255cafd4bSNathan Chancellor 		lval = bq25890_find_idx(val->intval, TBL_IINLIM);
6334a4748f2SMarek Vasut 		return bq25890_field_write(bq, F_IINLIM, lval);
6344a4748f2SMarek Vasut 	default:
6354a4748f2SMarek Vasut 		return -EINVAL;
6364a4748f2SMarek Vasut 	}
6374a4748f2SMarek Vasut }
6384a4748f2SMarek Vasut 
6394a4748f2SMarek Vasut static int bq25890_power_supply_property_is_writeable(struct power_supply *psy,
6404a4748f2SMarek Vasut 						      enum power_supply_property psp)
6414a4748f2SMarek Vasut {
6424a4748f2SMarek Vasut 	switch (psp) {
6434a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
6444a4748f2SMarek Vasut 		return true;
6454a4748f2SMarek Vasut 	default:
6464a4748f2SMarek Vasut 		return false;
6474a4748f2SMarek Vasut 	}
6484a4748f2SMarek Vasut }
6494a4748f2SMarek Vasut 
650eab25b4fSHans de Goede /* On the BQ25892 try to get charger-type info from our supplier */
651eab25b4fSHans de Goede static void bq25890_charger_external_power_changed(struct power_supply *psy)
652eab25b4fSHans de Goede {
653eab25b4fSHans de Goede 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
654eab25b4fSHans de Goede 	union power_supply_propval val;
655eab25b4fSHans de Goede 	int input_current_limit, ret;
656eab25b4fSHans de Goede 
657eab25b4fSHans de Goede 	if (bq->chip_version != BQ25892)
658eab25b4fSHans de Goede 		return;
659eab25b4fSHans de Goede 
660eab25b4fSHans de Goede 	ret = power_supply_get_property_from_supplier(bq->charger,
661eab25b4fSHans de Goede 						      POWER_SUPPLY_PROP_USB_TYPE,
662eab25b4fSHans de Goede 						      &val);
663eab25b4fSHans de Goede 	if (ret)
664eab25b4fSHans de Goede 		return;
665eab25b4fSHans de Goede 
666eab25b4fSHans de Goede 	switch (val.intval) {
667eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_DCP:
668eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM);
66948f45b09SYauhen Kharuzhy 		if (bq->pump_express_vbus_max) {
67048f45b09SYauhen Kharuzhy 			queue_delayed_work(system_power_efficient_wq,
67148f45b09SYauhen Kharuzhy 					   &bq->pump_express_work,
67248f45b09SYauhen Kharuzhy 					   PUMP_EXPRESS_START_DELAY);
67348f45b09SYauhen Kharuzhy 		}
674eab25b4fSHans de Goede 		break;
675eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_CDP:
676eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_ACA:
677eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM);
678eab25b4fSHans de Goede 		break;
679eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_SDP:
680eab25b4fSHans de Goede 	default:
681eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(500000, TBL_IINLIM);
682eab25b4fSHans de Goede 	}
683eab25b4fSHans de Goede 
684eab25b4fSHans de Goede 	bq25890_field_write(bq, F_IINLIM, input_current_limit);
685eab25b4fSHans de Goede }
686eab25b4fSHans de Goede 
6878c0984e5SSebastian Reichel static int bq25890_get_chip_state(struct bq25890_device *bq,
6888c0984e5SSebastian Reichel 				  struct bq25890_state *state)
6898c0984e5SSebastian Reichel {
6908c0984e5SSebastian Reichel 	int i, ret;
6918c0984e5SSebastian Reichel 
6928c0984e5SSebastian Reichel 	struct {
6938c0984e5SSebastian Reichel 		enum bq25890_fields id;
6948c0984e5SSebastian Reichel 		u8 *data;
6958c0984e5SSebastian Reichel 	} state_fields[] = {
6968c0984e5SSebastian Reichel 		{F_CHG_STAT,	&state->chrg_status},
6978c0984e5SSebastian Reichel 		{F_PG_STAT,	&state->online},
6988c0984e5SSebastian Reichel 		{F_VSYS_STAT,	&state->vsys_status},
6998c0984e5SSebastian Reichel 		{F_BOOST_FAULT, &state->boost_fault},
7008c0984e5SSebastian Reichel 		{F_BAT_FAULT,	&state->bat_fault},
701c562a43aSYauhen Kharuzhy 		{F_CHG_FAULT,	&state->chrg_fault},
702c562a43aSYauhen Kharuzhy 		{F_NTC_FAULT,	&state->ntc_fault}
7038c0984e5SSebastian Reichel 	};
7048c0984e5SSebastian Reichel 
7058c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(state_fields); i++) {
7068c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, state_fields[i].id);
7078c0984e5SSebastian Reichel 		if (ret < 0)
7088c0984e5SSebastian Reichel 			return ret;
7098c0984e5SSebastian Reichel 
7108c0984e5SSebastian Reichel 		*state_fields[i].data = ret;
7118c0984e5SSebastian Reichel 	}
7128c0984e5SSebastian Reichel 
713c562a43aSYauhen Kharuzhy 	dev_dbg(bq->dev, "S:CHG/PG/VSYS=%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
7148c0984e5SSebastian Reichel 		state->chrg_status, state->online, state->vsys_status,
715c562a43aSYauhen Kharuzhy 		state->chrg_fault, state->boost_fault, state->bat_fault,
716c562a43aSYauhen Kharuzhy 		state->ntc_fault);
7178c0984e5SSebastian Reichel 
7188c0984e5SSebastian Reichel 	return 0;
7198c0984e5SSebastian Reichel }
7208c0984e5SSebastian Reichel 
72172d9cd9cSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
7228c0984e5SSebastian Reichel {
72372d9cd9cSMichał Mirosław 	struct bq25890_state new_state;
7248c0984e5SSebastian Reichel 	int ret;
7258c0984e5SSebastian Reichel 
72672d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &new_state);
72772d9cd9cSMichał Mirosław 	if (ret < 0)
72872d9cd9cSMichał Mirosław 		return IRQ_NONE;
7298c0984e5SSebastian Reichel 
73072d9cd9cSMichał Mirosław 	if (!memcmp(&bq->state, &new_state, sizeof(new_state)))
73172d9cd9cSMichał Mirosław 		return IRQ_NONE;
73272d9cd9cSMichał Mirosław 
73372d9cd9cSMichał Mirosław 	if (!new_state.online && bq->state.online) {	    /* power removed */
7348c0984e5SSebastian Reichel 		/* disable ADC */
73580211be1SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_CONV_RATE, 0);
7368c0984e5SSebastian Reichel 		if (ret < 0)
7378c0984e5SSebastian Reichel 			goto error;
73872d9cd9cSMichał Mirosław 	} else if (new_state.online && !bq->state.online) { /* power inserted */
7398c0984e5SSebastian Reichel 		/* enable ADC, to have control of charge current/voltage */
74080211be1SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_CONV_RATE, 1);
7418c0984e5SSebastian Reichel 		if (ret < 0)
7428c0984e5SSebastian Reichel 			goto error;
7438c0984e5SSebastian Reichel 	}
7448c0984e5SSebastian Reichel 
74572d9cd9cSMichał Mirosław 	bq->state = new_state;
74672d9cd9cSMichał Mirosław 	power_supply_changed(bq->charger);
7478c0984e5SSebastian Reichel 
74872d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
7498c0984e5SSebastian Reichel error:
75072d9cd9cSMichał Mirosław 	dev_err(bq->dev, "Error communicating with the chip: %pe\n",
75172d9cd9cSMichał Mirosław 		ERR_PTR(ret));
75272d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
7538c0984e5SSebastian Reichel }
7548c0984e5SSebastian Reichel 
7558c0984e5SSebastian Reichel static irqreturn_t bq25890_irq_handler_thread(int irq, void *private)
7568c0984e5SSebastian Reichel {
7578c0984e5SSebastian Reichel 	struct bq25890_device *bq = private;
75872d9cd9cSMichał Mirosław 	irqreturn_t ret;
7598c0984e5SSebastian Reichel 
7608c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
76172d9cd9cSMichał Mirosław 	ret = __bq25890_handle_irq(bq);
7628c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
7638c0984e5SSebastian Reichel 
76472d9cd9cSMichał Mirosław 	return ret;
7658c0984e5SSebastian Reichel }
7668c0984e5SSebastian Reichel 
7678c0984e5SSebastian Reichel static int bq25890_chip_reset(struct bq25890_device *bq)
7688c0984e5SSebastian Reichel {
7698c0984e5SSebastian Reichel 	int ret;
7708c0984e5SSebastian Reichel 	int rst_check_counter = 10;
7718c0984e5SSebastian Reichel 
7728c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_REG_RST, 1);
7738c0984e5SSebastian Reichel 	if (ret < 0)
7748c0984e5SSebastian Reichel 		return ret;
7758c0984e5SSebastian Reichel 
7768c0984e5SSebastian Reichel 	do {
7778c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, F_REG_RST);
7788c0984e5SSebastian Reichel 		if (ret < 0)
7798c0984e5SSebastian Reichel 			return ret;
7808c0984e5SSebastian Reichel 
7818c0984e5SSebastian Reichel 		usleep_range(5, 10);
7828c0984e5SSebastian Reichel 	} while (ret == 1 && --rst_check_counter);
7838c0984e5SSebastian Reichel 
7848c0984e5SSebastian Reichel 	if (!rst_check_counter)
7858c0984e5SSebastian Reichel 		return -ETIMEDOUT;
7868c0984e5SSebastian Reichel 
7878c0984e5SSebastian Reichel 	return 0;
7888c0984e5SSebastian Reichel }
7898c0984e5SSebastian Reichel 
7907b22a974SHans de Goede static int bq25890_rw_init_data(struct bq25890_device *bq)
7918c0984e5SSebastian Reichel {
79240428bd4SHans de Goede 	bool write = !bq->read_back_init_data;
7938c0984e5SSebastian Reichel 	int ret;
7948c0984e5SSebastian Reichel 	int i;
7958c0984e5SSebastian Reichel 
7968c0984e5SSebastian Reichel 	const struct {
7978c0984e5SSebastian Reichel 		enum bq25890_fields id;
7987b22a974SHans de Goede 		u8 *value;
7998c0984e5SSebastian Reichel 	} init_data[] = {
8007b22a974SHans de Goede 		{F_ICHG,	 &bq->init_data.ichg},
8017b22a974SHans de Goede 		{F_VREG,	 &bq->init_data.vreg},
8027b22a974SHans de Goede 		{F_ITERM,	 &bq->init_data.iterm},
8037b22a974SHans de Goede 		{F_IPRECHG,	 &bq->init_data.iprechg},
8047b22a974SHans de Goede 		{F_SYSVMIN,	 &bq->init_data.sysvmin},
8057b22a974SHans de Goede 		{F_BOOSTV,	 &bq->init_data.boostv},
8067b22a974SHans de Goede 		{F_BOOSTI,	 &bq->init_data.boosti},
8077b22a974SHans de Goede 		{F_BOOSTF,	 &bq->init_data.boostf},
8087b22a974SHans de Goede 		{F_EN_ILIM,	 &bq->init_data.ilim_en},
8097b22a974SHans de Goede 		{F_TREG,	 &bq->init_data.treg},
8107b22a974SHans de Goede 		{F_BATCMP,	 &bq->init_data.rbatcomp},
8117b22a974SHans de Goede 		{F_VCLAMP,	 &bq->init_data.vclamp},
8128c0984e5SSebastian Reichel 	};
8138c0984e5SSebastian Reichel 
8147b22a974SHans de Goede 	for (i = 0; i < ARRAY_SIZE(init_data); i++) {
8157b22a974SHans de Goede 		if (write) {
8167b22a974SHans de Goede 			ret = bq25890_field_write(bq, init_data[i].id,
8177b22a974SHans de Goede 						  *init_data[i].value);
8187b22a974SHans de Goede 		} else {
8197b22a974SHans de Goede 			ret = bq25890_field_read(bq, init_data[i].id);
8207b22a974SHans de Goede 			if (ret >= 0)
8217b22a974SHans de Goede 				*init_data[i].value = ret;
8227b22a974SHans de Goede 		}
8237b22a974SHans de Goede 		if (ret < 0) {
8247b22a974SHans de Goede 			dev_dbg(bq->dev, "Accessing init data failed %d\n", ret);
8257b22a974SHans de Goede 			return ret;
8267b22a974SHans de Goede 		}
8277b22a974SHans de Goede 	}
8287b22a974SHans de Goede 
8297b22a974SHans de Goede 	return 0;
8307b22a974SHans de Goede }
8317b22a974SHans de Goede 
8327b22a974SHans de Goede static int bq25890_hw_init(struct bq25890_device *bq)
8337b22a974SHans de Goede {
8347b22a974SHans de Goede 	int ret;
8357b22a974SHans de Goede 
8367e3b8e35SHans de Goede 	if (!bq->skip_reset) {
8378c0984e5SSebastian Reichel 		ret = bq25890_chip_reset(bq);
8389d9ae341SAngus Ainslie (Purism) 		if (ret < 0) {
8399d9ae341SAngus Ainslie (Purism) 			dev_dbg(bq->dev, "Reset failed %d\n", ret);
8408c0984e5SSebastian Reichel 			return ret;
841ad1570d9Skbuild test robot 		}
84206c75095SHans de Goede 	} else {
84306c75095SHans de Goede 		/*
84406c75095SHans de Goede 		 * Ensure charging is enabled, on some boards where the fw
84506c75095SHans de Goede 		 * takes care of initalizition F_CHG_CFG is set to 0 before
84606c75095SHans de Goede 		 * handing control over to the OS.
84706c75095SHans de Goede 		 */
84806c75095SHans de Goede 		ret = bq25890_field_write(bq, F_CHG_CFG, 1);
84906c75095SHans de Goede 		if (ret < 0) {
85006c75095SHans de Goede 			dev_dbg(bq->dev, "Enabling charging failed %d\n", ret);
85106c75095SHans de Goede 			return ret;
85206c75095SHans de Goede 		}
8537e3b8e35SHans de Goede 	}
8548c0984e5SSebastian Reichel 
8558c0984e5SSebastian Reichel 	/* disable watchdog */
8568c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_WD, 0);
8579d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
8589d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret);
8598c0984e5SSebastian Reichel 		return ret;
860ad1570d9Skbuild test robot 	}
8618c0984e5SSebastian Reichel 
8628c0984e5SSebastian Reichel 	/* initialize currents/voltages and other parameters */
8637b22a974SHans de Goede 	ret = bq25890_rw_init_data(bq);
8647b22a974SHans de Goede 	if (ret)
8658c0984e5SSebastian Reichel 		return ret;
8668c0984e5SSebastian Reichel 
86722ad4f99SHans de Goede 	ret = bq25890_get_chip_state(bq, &bq->state);
86822ad4f99SHans de Goede 	if (ret < 0) {
86922ad4f99SHans de Goede 		dev_dbg(bq->dev, "Get state failed %d\n", ret);
87022ad4f99SHans de Goede 		return ret;
87122ad4f99SHans de Goede 	}
87222ad4f99SHans de Goede 
87321d90edaSMichał Mirosław 	/* Configure ADC for continuous conversions when charging */
87421d90edaSMichał Mirosław 	ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
8759d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
8769d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
8778c0984e5SSebastian Reichel 		return ret;
878ad1570d9Skbuild test robot 	}
8798c0984e5SSebastian Reichel 
8808c0984e5SSebastian Reichel 	return 0;
8818c0984e5SSebastian Reichel }
8828c0984e5SSebastian Reichel 
883a6a48facSMichał Mirosław static const enum power_supply_property bq25890_power_supply_props[] = {
8848c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MANUFACTURER,
8852e1a2ddeSAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_MODEL_NAME,
8868c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
887b302a0aeSMichał Mirosław 	POWER_SUPPLY_PROP_CHARGE_TYPE,
8888c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
8898c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_HEALTH,
8908c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
8918c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
8928c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
893c942656dSMichał Mirosław 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
8948c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
895478efc79SMichał Mirosław 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
896ae6fe7a3SAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
8971e4724d0SMichał Mirosław 	POWER_SUPPLY_PROP_CURRENT_NOW,
8989652c024SAngus Ainslie 	POWER_SUPPLY_PROP_TEMP,
8998c0984e5SSebastian Reichel };
9008c0984e5SSebastian Reichel 
9018c0984e5SSebastian Reichel static char *bq25890_charger_supplied_to[] = {
9028c0984e5SSebastian Reichel 	"main-battery",
9038c0984e5SSebastian Reichel };
9048c0984e5SSebastian Reichel 
9058c0984e5SSebastian Reichel static const struct power_supply_desc bq25890_power_supply_desc = {
9068c0984e5SSebastian Reichel 	.name = "bq25890-charger",
9078c0984e5SSebastian Reichel 	.type = POWER_SUPPLY_TYPE_USB,
9088c0984e5SSebastian Reichel 	.properties = bq25890_power_supply_props,
9098c0984e5SSebastian Reichel 	.num_properties = ARRAY_SIZE(bq25890_power_supply_props),
9108c0984e5SSebastian Reichel 	.get_property = bq25890_power_supply_get_property,
9114a4748f2SMarek Vasut 	.set_property = bq25890_power_supply_set_property,
9124a4748f2SMarek Vasut 	.property_is_writeable = bq25890_power_supply_property_is_writeable,
913eab25b4fSHans de Goede 	.external_power_changed	= bq25890_charger_external_power_changed,
9148c0984e5SSebastian Reichel };
9158c0984e5SSebastian Reichel 
9168c0984e5SSebastian Reichel static int bq25890_power_supply_init(struct bq25890_device *bq)
9178c0984e5SSebastian Reichel {
9188c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = { .drv_data = bq, };
9198c0984e5SSebastian Reichel 
9208c0984e5SSebastian Reichel 	psy_cfg.supplied_to = bq25890_charger_supplied_to;
9218c0984e5SSebastian Reichel 	psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
9228c0984e5SSebastian Reichel 
923d01363daSHans de Goede 	bq->charger = devm_power_supply_register(bq->dev,
924d01363daSHans de Goede 						 &bq25890_power_supply_desc,
9258c0984e5SSebastian Reichel 						 &psy_cfg);
9268c0984e5SSebastian Reichel 
9278c0984e5SSebastian Reichel 	return PTR_ERR_OR_ZERO(bq->charger);
9288c0984e5SSebastian Reichel }
9298c0984e5SSebastian Reichel 
9305575802dSHans de Goede static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val)
9315575802dSHans de Goede {
9325575802dSHans de Goede 	int ret;
9335575802dSHans de Goede 
9345575802dSHans de Goede 	ret = bq25890_field_write(bq, F_OTG_CFG, val);
9355575802dSHans de Goede 	if (ret < 0)
9365575802dSHans de Goede 		dev_err(bq->dev, "Error switching to boost/charger mode: %d\n", ret);
9375575802dSHans de Goede 
9385575802dSHans de Goede 	return ret;
9395575802dSHans de Goede }
9405575802dSHans de Goede 
94148f45b09SYauhen Kharuzhy static void bq25890_pump_express_work(struct work_struct *data)
94248f45b09SYauhen Kharuzhy {
94348f45b09SYauhen Kharuzhy 	struct bq25890_device *bq =
94448f45b09SYauhen Kharuzhy 		container_of(data, struct bq25890_device, pump_express_work.work);
94548f45b09SYauhen Kharuzhy 	int voltage, i, ret;
94648f45b09SYauhen Kharuzhy 
94748f45b09SYauhen Kharuzhy 	dev_dbg(bq->dev, "Start to request input voltage increasing\n");
94848f45b09SYauhen Kharuzhy 
94948f45b09SYauhen Kharuzhy 	/* Enable current pulse voltage control protocol */
95048f45b09SYauhen Kharuzhy 	ret = bq25890_field_write(bq, F_PUMPX_EN, 1);
95148f45b09SYauhen Kharuzhy 	if (ret < 0)
95248f45b09SYauhen Kharuzhy 		goto error_print;
95348f45b09SYauhen Kharuzhy 
95448f45b09SYauhen Kharuzhy 	for (i = 0; i < PUMP_EXPRESS_MAX_TRIES; i++) {
95548f45b09SYauhen Kharuzhy 		voltage = bq25890_get_vbus_voltage(bq);
95648f45b09SYauhen Kharuzhy 		if (voltage < 0)
95748f45b09SYauhen Kharuzhy 			goto error_print;
95848f45b09SYauhen Kharuzhy 		dev_dbg(bq->dev, "input voltage = %d uV\n", voltage);
95948f45b09SYauhen Kharuzhy 
96048f45b09SYauhen Kharuzhy 		if ((voltage + PUMP_EXPRESS_VBUS_MARGIN_uV) >
96148f45b09SYauhen Kharuzhy 					bq->pump_express_vbus_max)
96248f45b09SYauhen Kharuzhy 			break;
96348f45b09SYauhen Kharuzhy 
96448f45b09SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_PUMPX_UP, 1);
96548f45b09SYauhen Kharuzhy 		if (ret < 0)
96648f45b09SYauhen Kharuzhy 			goto error_print;
96748f45b09SYauhen Kharuzhy 
96848f45b09SYauhen Kharuzhy 		/* Note a single PUMPX up pulse-sequence takes 2.1s */
96948f45b09SYauhen Kharuzhy 		ret = regmap_field_read_poll_timeout(bq->rmap_fields[F_PUMPX_UP],
97048f45b09SYauhen Kharuzhy 						     ret, !ret, 100000, 3000000);
97148f45b09SYauhen Kharuzhy 		if (ret < 0)
97248f45b09SYauhen Kharuzhy 			goto error_print;
97348f45b09SYauhen Kharuzhy 
97448f45b09SYauhen Kharuzhy 		/* Make sure ADC has sampled Vbus before checking again */
97548f45b09SYauhen Kharuzhy 		msleep(1000);
97648f45b09SYauhen Kharuzhy 	}
97748f45b09SYauhen Kharuzhy 
97848f45b09SYauhen Kharuzhy 	bq25890_field_write(bq, F_PUMPX_EN, 0);
97948f45b09SYauhen Kharuzhy 
98048f45b09SYauhen Kharuzhy 	dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n",
98148f45b09SYauhen Kharuzhy 		 voltage);
98248f45b09SYauhen Kharuzhy 
98348f45b09SYauhen Kharuzhy 	return;
98448f45b09SYauhen Kharuzhy error_print:
98504f7c7dfSHans de Goede 	bq25890_field_write(bq, F_PUMPX_EN, 0);
98648f45b09SYauhen Kharuzhy 	dev_err(bq->dev, "Failed to request hi-voltage charging\n");
98748f45b09SYauhen Kharuzhy }
98848f45b09SYauhen Kharuzhy 
9898c0984e5SSebastian Reichel static void bq25890_usb_work(struct work_struct *data)
9908c0984e5SSebastian Reichel {
9918c0984e5SSebastian Reichel 	int ret;
9928c0984e5SSebastian Reichel 	struct bq25890_device *bq =
9938c0984e5SSebastian Reichel 			container_of(data, struct bq25890_device, usb_work);
9948c0984e5SSebastian Reichel 
9958c0984e5SSebastian Reichel 	switch (bq->usb_event) {
9968c0984e5SSebastian Reichel 	case USB_EVENT_ID:
9978c0984e5SSebastian Reichel 		/* Enable boost mode */
9985575802dSHans de Goede 		bq25890_set_otg_cfg(bq, 1);
9998c0984e5SSebastian Reichel 		break;
10008c0984e5SSebastian Reichel 
10018c0984e5SSebastian Reichel 	case USB_EVENT_NONE:
10028c0984e5SSebastian Reichel 		/* Disable boost mode */
10035575802dSHans de Goede 		ret = bq25890_set_otg_cfg(bq, 0);
10045575802dSHans de Goede 		if (ret == 0)
10058c0984e5SSebastian Reichel 			power_supply_changed(bq->charger);
10068c0984e5SSebastian Reichel 		break;
10078c0984e5SSebastian Reichel 	}
10088c0984e5SSebastian Reichel }
10098c0984e5SSebastian Reichel 
10108c0984e5SSebastian Reichel static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val,
10118c0984e5SSebastian Reichel 				void *priv)
10128c0984e5SSebastian Reichel {
10138c0984e5SSebastian Reichel 	struct bq25890_device *bq =
10148c0984e5SSebastian Reichel 			container_of(nb, struct bq25890_device, usb_nb);
10158c0984e5SSebastian Reichel 
10168c0984e5SSebastian Reichel 	bq->usb_event = val;
10178c0984e5SSebastian Reichel 	queue_work(system_power_efficient_wq, &bq->usb_work);
10188c0984e5SSebastian Reichel 
10198c0984e5SSebastian Reichel 	return NOTIFY_OK;
10208c0984e5SSebastian Reichel }
10218c0984e5SSebastian Reichel 
102279d35365SHans de Goede #ifdef CONFIG_REGULATOR
102379d35365SHans de Goede static int bq25890_vbus_enable(struct regulator_dev *rdev)
102479d35365SHans de Goede {
102579d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
102679d35365SHans de Goede 
102779d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 1);
102879d35365SHans de Goede }
102979d35365SHans de Goede 
103079d35365SHans de Goede static int bq25890_vbus_disable(struct regulator_dev *rdev)
103179d35365SHans de Goede {
103279d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
103379d35365SHans de Goede 
103479d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 0);
103579d35365SHans de Goede }
103679d35365SHans de Goede 
103779d35365SHans de Goede static int bq25890_vbus_is_enabled(struct regulator_dev *rdev)
103879d35365SHans de Goede {
103979d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
104079d35365SHans de Goede 
104179d35365SHans de Goede 	return bq25890_field_read(bq, F_OTG_CFG);
104279d35365SHans de Goede }
104379d35365SHans de Goede 
104479d35365SHans de Goede static const struct regulator_ops bq25890_vbus_ops = {
104579d35365SHans de Goede 	.enable = bq25890_vbus_enable,
104679d35365SHans de Goede 	.disable = bq25890_vbus_disable,
104779d35365SHans de Goede 	.is_enabled = bq25890_vbus_is_enabled,
104879d35365SHans de Goede };
104979d35365SHans de Goede 
105079d35365SHans de Goede static const struct regulator_desc bq25890_vbus_desc = {
105179d35365SHans de Goede 	.name = "usb_otg_vbus",
105279d35365SHans de Goede 	.of_match = "usb-otg-vbus",
105379d35365SHans de Goede 	.type = REGULATOR_VOLTAGE,
105479d35365SHans de Goede 	.owner = THIS_MODULE,
105579d35365SHans de Goede 	.ops = &bq25890_vbus_ops,
105679d35365SHans de Goede 	.fixed_uV = 5000000,
105779d35365SHans de Goede 	.n_voltages = 1,
105879d35365SHans de Goede };
105979d35365SHans de Goede #endif
106079d35365SHans de Goede 
1061d20267c9SYauhen Kharuzhy static int bq25890_get_chip_version(struct bq25890_device *bq)
1062d20267c9SYauhen Kharuzhy {
1063d20267c9SYauhen Kharuzhy 	int id, rev;
1064d20267c9SYauhen Kharuzhy 
1065d20267c9SYauhen Kharuzhy 	id = bq25890_field_read(bq, F_PN);
1066d20267c9SYauhen Kharuzhy 	if (id < 0) {
1067172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip ID: %d\n", id);
1068d20267c9SYauhen Kharuzhy 		return id;
1069d20267c9SYauhen Kharuzhy 	}
1070d20267c9SYauhen Kharuzhy 
1071d20267c9SYauhen Kharuzhy 	rev = bq25890_field_read(bq, F_DEV_REV);
1072d20267c9SYauhen Kharuzhy 	if (rev < 0) {
1073172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip revision: %d\n", rev);
1074cb619e80SColin Ian King 		return rev;
1075d20267c9SYauhen Kharuzhy 	}
1076d20267c9SYauhen Kharuzhy 
1077d20267c9SYauhen Kharuzhy 	switch (id) {
1078d20267c9SYauhen Kharuzhy 	case BQ25890_ID:
1079d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25890;
1080d20267c9SYauhen Kharuzhy 		break;
1081d20267c9SYauhen Kharuzhy 
1082d20267c9SYauhen Kharuzhy 	/* BQ25892 and BQ25896 share same ID 0 */
1083d20267c9SYauhen Kharuzhy 	case BQ25896_ID:
1084d20267c9SYauhen Kharuzhy 		switch (rev) {
1085d20267c9SYauhen Kharuzhy 		case 2:
1086d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25896;
1087d20267c9SYauhen Kharuzhy 			break;
1088d20267c9SYauhen Kharuzhy 		case 1:
1089d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1090d20267c9SYauhen Kharuzhy 			break;
1091d20267c9SYauhen Kharuzhy 		default:
1092d20267c9SYauhen Kharuzhy 			dev_err(bq->dev,
1093d20267c9SYauhen Kharuzhy 				"Unknown device revision %d, assume BQ25892\n",
1094d20267c9SYauhen Kharuzhy 				rev);
1095d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1096d20267c9SYauhen Kharuzhy 		}
1097d20267c9SYauhen Kharuzhy 		break;
1098d20267c9SYauhen Kharuzhy 
1099d20267c9SYauhen Kharuzhy 	case BQ25895_ID:
1100d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25895;
1101d20267c9SYauhen Kharuzhy 		break;
1102d20267c9SYauhen Kharuzhy 
1103d20267c9SYauhen Kharuzhy 	default:
1104d20267c9SYauhen Kharuzhy 		dev_err(bq->dev, "Unknown chip ID %d\n", id);
1105d20267c9SYauhen Kharuzhy 		return -ENODEV;
1106d20267c9SYauhen Kharuzhy 	}
1107d20267c9SYauhen Kharuzhy 
1108d20267c9SYauhen Kharuzhy 	return 0;
1109d20267c9SYauhen Kharuzhy }
1110d20267c9SYauhen Kharuzhy 
11118c0984e5SSebastian Reichel static int bq25890_irq_probe(struct bq25890_device *bq)
11128c0984e5SSebastian Reichel {
11138c0984e5SSebastian Reichel 	struct gpio_desc *irq;
11148c0984e5SSebastian Reichel 
111586775879SAndy Shevchenko 	irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN);
1116172d0cceSMartin Kepplinger 	if (IS_ERR(irq))
1117172d0cceSMartin Kepplinger 		return dev_err_probe(bq->dev, PTR_ERR(irq),
1118172d0cceSMartin Kepplinger 				     "Could not probe irq pin.\n");
11198c0984e5SSebastian Reichel 
11208c0984e5SSebastian Reichel 	return gpiod_to_irq(irq);
11218c0984e5SSebastian Reichel }
11228c0984e5SSebastian Reichel 
11238c0984e5SSebastian Reichel static int bq25890_fw_read_u32_props(struct bq25890_device *bq)
11248c0984e5SSebastian Reichel {
11258c0984e5SSebastian Reichel 	int ret;
11268c0984e5SSebastian Reichel 	u32 property;
11278c0984e5SSebastian Reichel 	int i;
11288c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
11298c0984e5SSebastian Reichel 	struct {
11308c0984e5SSebastian Reichel 		char *name;
11318c0984e5SSebastian Reichel 		bool optional;
11328c0984e5SSebastian Reichel 		enum bq25890_table_ids tbl_id;
11338c0984e5SSebastian Reichel 		u8 *conv_data; /* holds converted value from given property */
11348c0984e5SSebastian Reichel 	} props[] = {
11358c0984e5SSebastian Reichel 		/* required properties */
11368c0984e5SSebastian Reichel 		{"ti,charge-current", false, TBL_ICHG, &init->ichg},
11378c0984e5SSebastian Reichel 		{"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg},
11388c0984e5SSebastian Reichel 		{"ti,termination-current", false, TBL_ITERM, &init->iterm},
11398c0984e5SSebastian Reichel 		{"ti,precharge-current", false, TBL_ITERM, &init->iprechg},
11408c0984e5SSebastian Reichel 		{"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin},
11418c0984e5SSebastian Reichel 		{"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv},
11428c0984e5SSebastian Reichel 		{"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti},
11438c0984e5SSebastian Reichel 
11448c0984e5SSebastian Reichel 		/* optional properties */
114572408329SMichał Mirosław 		{"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg},
114672408329SMichał Mirosław 		{"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp},
114772408329SMichał Mirosław 		{"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp},
11488c0984e5SSebastian Reichel 	};
11498c0984e5SSebastian Reichel 
11508c0984e5SSebastian Reichel 	/* initialize data for optional properties */
11518c0984e5SSebastian Reichel 	init->treg = 3; /* 120 degrees Celsius */
115272408329SMichał Mirosław 	init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */
11538c0984e5SSebastian Reichel 
11548c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(props); i++) {
11558c0984e5SSebastian Reichel 		ret = device_property_read_u32(bq->dev, props[i].name,
11568c0984e5SSebastian Reichel 					       &property);
11578c0984e5SSebastian Reichel 		if (ret < 0) {
11588c0984e5SSebastian Reichel 			if (props[i].optional)
11598c0984e5SSebastian Reichel 				continue;
11608c0984e5SSebastian Reichel 
11619d9ae341SAngus Ainslie (Purism) 			dev_err(bq->dev, "Unable to read property %d %s\n", ret,
11629d9ae341SAngus Ainslie (Purism) 				props[i].name);
11639d9ae341SAngus Ainslie (Purism) 
11648c0984e5SSebastian Reichel 			return ret;
11658c0984e5SSebastian Reichel 		}
11668c0984e5SSebastian Reichel 
11678c0984e5SSebastian Reichel 		*props[i].conv_data = bq25890_find_idx(property,
11688c0984e5SSebastian Reichel 						       props[i].tbl_id);
11698c0984e5SSebastian Reichel 	}
11708c0984e5SSebastian Reichel 
11718c0984e5SSebastian Reichel 	return 0;
11728c0984e5SSebastian Reichel }
11738c0984e5SSebastian Reichel 
11748c0984e5SSebastian Reichel static int bq25890_fw_probe(struct bq25890_device *bq)
11758c0984e5SSebastian Reichel {
11768c0984e5SSebastian Reichel 	int ret;
11778c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
11788c0984e5SSebastian Reichel 
117948f45b09SYauhen Kharuzhy 	/* Optional, left at 0 if property is not present */
118048f45b09SYauhen Kharuzhy 	device_property_read_u32(bq->dev, "linux,pump-express-vbus-max",
118148f45b09SYauhen Kharuzhy 				 &bq->pump_express_vbus_max);
118248f45b09SYauhen Kharuzhy 
11837e3b8e35SHans de Goede 	bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset");
118440428bd4SHans de Goede 	bq->read_back_init_data = device_property_read_bool(bq->dev,
118540428bd4SHans de Goede 						"linux,read-back-settings");
118640428bd4SHans de Goede 	if (bq->read_back_init_data)
118740428bd4SHans de Goede 		return 0;
11887e3b8e35SHans de Goede 
11898c0984e5SSebastian Reichel 	ret = bq25890_fw_read_u32_props(bq);
11908c0984e5SSebastian Reichel 	if (ret < 0)
11918c0984e5SSebastian Reichel 		return ret;
11928c0984e5SSebastian Reichel 
11938c0984e5SSebastian Reichel 	init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin");
11948c0984e5SSebastian Reichel 	init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq");
11958c0984e5SSebastian Reichel 
11968c0984e5SSebastian Reichel 	return 0;
11978c0984e5SSebastian Reichel }
11988c0984e5SSebastian Reichel 
11998c0984e5SSebastian Reichel static int bq25890_probe(struct i2c_client *client,
12008c0984e5SSebastian Reichel 			 const struct i2c_device_id *id)
12018c0984e5SSebastian Reichel {
12028c0984e5SSebastian Reichel 	struct device *dev = &client->dev;
12038c0984e5SSebastian Reichel 	struct bq25890_device *bq;
12048c0984e5SSebastian Reichel 	int ret;
12058c0984e5SSebastian Reichel 
12068c0984e5SSebastian Reichel 	bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL);
12078c0984e5SSebastian Reichel 	if (!bq)
12088c0984e5SSebastian Reichel 		return -ENOMEM;
12098c0984e5SSebastian Reichel 
12108c0984e5SSebastian Reichel 	bq->client = client;
12118c0984e5SSebastian Reichel 	bq->dev = dev;
12128c0984e5SSebastian Reichel 
12138c0984e5SSebastian Reichel 	mutex_init(&bq->lock);
121448f45b09SYauhen Kharuzhy 	INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work);
12158c0984e5SSebastian Reichel 
12168c0984e5SSebastian Reichel 	bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config);
1217172d0cceSMartin Kepplinger 	if (IS_ERR(bq->rmap))
1218172d0cceSMartin Kepplinger 		return dev_err_probe(dev, PTR_ERR(bq->rmap),
1219172d0cceSMartin Kepplinger 				     "failed to allocate register map\n");
12208c0984e5SSebastian Reichel 
1221c1ae3a4eSHans de Goede 	ret = devm_regmap_field_bulk_alloc(dev, bq->rmap, bq->rmap_fields,
1222c1ae3a4eSHans de Goede 					   bq25890_reg_fields, F_MAX_FIELDS);
1223c1ae3a4eSHans de Goede 	if (ret)
1224c1ae3a4eSHans de Goede 		return ret;
12258c0984e5SSebastian Reichel 
12268c0984e5SSebastian Reichel 	i2c_set_clientdata(client, bq);
12278c0984e5SSebastian Reichel 
1228d20267c9SYauhen Kharuzhy 	ret = bq25890_get_chip_version(bq);
1229d20267c9SYauhen Kharuzhy 	if (ret) {
1230172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret);
1231d20267c9SYauhen Kharuzhy 		return ret;
12328c0984e5SSebastian Reichel 	}
12338c0984e5SSebastian Reichel 
12348c0984e5SSebastian Reichel 	ret = bq25890_fw_probe(bq);
1235f481d5b8SHans de Goede 	if (ret < 0)
1236f481d5b8SHans de Goede 		return dev_err_probe(dev, ret, "reading device properties\n");
12378c0984e5SSebastian Reichel 
12388c0984e5SSebastian Reichel 	ret = bq25890_hw_init(bq);
12398c0984e5SSebastian Reichel 	if (ret < 0) {
1240172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot initialize the chip: %d\n", ret);
12418c0984e5SSebastian Reichel 		return ret;
12428c0984e5SSebastian Reichel 	}
12438c0984e5SSebastian Reichel 
12448c0984e5SSebastian Reichel 	if (client->irq <= 0)
12458c0984e5SSebastian Reichel 		client->irq = bq25890_irq_probe(bq);
12468c0984e5SSebastian Reichel 
12478c0984e5SSebastian Reichel 	if (client->irq < 0) {
12488c0984e5SSebastian Reichel 		dev_err(dev, "No irq resource found.\n");
12498c0984e5SSebastian Reichel 		return client->irq;
12508c0984e5SSebastian Reichel 	}
12518c0984e5SSebastian Reichel 
12528c0984e5SSebastian Reichel 	/* OTG reporting */
12538c0984e5SSebastian Reichel 	bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
12548c0984e5SSebastian Reichel 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
12558c0984e5SSebastian Reichel 		INIT_WORK(&bq->usb_work, bq25890_usb_work);
12568c0984e5SSebastian Reichel 		bq->usb_nb.notifier_call = bq25890_usb_notifier;
12578c0984e5SSebastian Reichel 		usb_register_notifier(bq->usb_phy, &bq->usb_nb);
12588c0984e5SSebastian Reichel 	}
125979d35365SHans de Goede #ifdef CONFIG_REGULATOR
126079d35365SHans de Goede 	else {
126179d35365SHans de Goede 		struct bq25890_platform_data *pdata = dev_get_platdata(dev);
126279d35365SHans de Goede 		struct regulator_config cfg = { };
126379d35365SHans de Goede 		struct regulator_dev *reg;
126479d35365SHans de Goede 
126579d35365SHans de Goede 		cfg.dev = dev;
126679d35365SHans de Goede 		cfg.driver_data = bq;
126779d35365SHans de Goede 		if (pdata)
126879d35365SHans de Goede 			cfg.init_data = pdata->regulator_init_data;
126979d35365SHans de Goede 
127079d35365SHans de Goede 		reg = devm_regulator_register(dev, &bq25890_vbus_desc, &cfg);
127179d35365SHans de Goede 		if (IS_ERR(reg))
127279d35365SHans de Goede 			return dev_err_probe(dev, PTR_ERR(reg), "registering regulator");
127379d35365SHans de Goede 	}
127479d35365SHans de Goede #endif
12758c0984e5SSebastian Reichel 
1276d01363daSHans de Goede 	ret = bq25890_power_supply_init(bq);
1277d01363daSHans de Goede 	if (ret < 0) {
1278d01363daSHans de Goede 		dev_err(dev, "Failed to register power supply\n");
1279d01363daSHans de Goede 		goto err_unregister_usb_notifier;
1280d01363daSHans de Goede 	}
1281d01363daSHans de Goede 
12828c0984e5SSebastian Reichel 	ret = devm_request_threaded_irq(dev, client->irq, NULL,
12838c0984e5SSebastian Reichel 					bq25890_irq_handler_thread,
12848c0984e5SSebastian Reichel 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
12858c0984e5SSebastian Reichel 					BQ25890_IRQ_PIN, bq);
12868c0984e5SSebastian Reichel 	if (ret)
1287d01363daSHans de Goede 		goto err_unregister_usb_notifier;
12888c0984e5SSebastian Reichel 
12898c0984e5SSebastian Reichel 	return 0;
12908c0984e5SSebastian Reichel 
1291d01363daSHans de Goede err_unregister_usb_notifier:
12928c0984e5SSebastian Reichel 	if (!IS_ERR_OR_NULL(bq->usb_phy))
12938c0984e5SSebastian Reichel 		usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
12948c0984e5SSebastian Reichel 
12958c0984e5SSebastian Reichel 	return ret;
12968c0984e5SSebastian Reichel }
12978c0984e5SSebastian Reichel 
1298ed5c2f5fSUwe Kleine-König static void bq25890_remove(struct i2c_client *client)
12998c0984e5SSebastian Reichel {
13008c0984e5SSebastian Reichel 	struct bq25890_device *bq = i2c_get_clientdata(client);
13018c0984e5SSebastian Reichel 
13028c0984e5SSebastian Reichel 	if (!IS_ERR_OR_NULL(bq->usb_phy))
13038c0984e5SSebastian Reichel 		usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
13048c0984e5SSebastian Reichel 
13057e3b8e35SHans de Goede 	if (!bq->skip_reset) {
13068c0984e5SSebastian Reichel 		/* reset all registers to default values */
13078c0984e5SSebastian Reichel 		bq25890_chip_reset(bq);
13087e3b8e35SHans de Goede 	}
13098c0984e5SSebastian Reichel }
13108c0984e5SSebastian Reichel 
131179d35365SHans de Goede static void bq25890_shutdown(struct i2c_client *client)
131279d35365SHans de Goede {
131379d35365SHans de Goede 	struct bq25890_device *bq = i2c_get_clientdata(client);
131479d35365SHans de Goede 
131579d35365SHans de Goede 	/*
131679d35365SHans de Goede 	 * TODO this if + return should probably be removed, but that would
131779d35365SHans de Goede 	 * introduce a function change for boards using the usb-phy framework.
131879d35365SHans de Goede 	 * This needs to be tested on such a board before making this change.
131979d35365SHans de Goede 	 */
132079d35365SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy))
132179d35365SHans de Goede 		return;
132279d35365SHans de Goede 
132379d35365SHans de Goede 	/*
132479d35365SHans de Goede 	 * Turn off the 5v Boost regulator which outputs Vbus to the device's
132579d35365SHans de Goede 	 * Micro-USB or Type-C USB port. Leaving this on drains power and
132679d35365SHans de Goede 	 * this avoids the PMIC on some device-models seeing this as Vbus
132779d35365SHans de Goede 	 * getting inserted after shutdown, causing the device to immediately
132879d35365SHans de Goede 	 * power-up again.
132979d35365SHans de Goede 	 */
133079d35365SHans de Goede 	bq25890_set_otg_cfg(bq, 0);
133179d35365SHans de Goede }
133279d35365SHans de Goede 
13338c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
13348c0984e5SSebastian Reichel static int bq25890_suspend(struct device *dev)
13358c0984e5SSebastian Reichel {
13368c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
13378c0984e5SSebastian Reichel 
13388c0984e5SSebastian Reichel 	/*
13398c0984e5SSebastian Reichel 	 * If charger is removed, while in suspend, make sure ADC is diabled
13408c0984e5SSebastian Reichel 	 * since it consumes slightly more power.
13418c0984e5SSebastian Reichel 	 */
134221d90edaSMichał Mirosław 	return bq25890_field_write(bq, F_CONV_RATE, 0);
13438c0984e5SSebastian Reichel }
13448c0984e5SSebastian Reichel 
13458c0984e5SSebastian Reichel static int bq25890_resume(struct device *dev)
13468c0984e5SSebastian Reichel {
13478c0984e5SSebastian Reichel 	int ret;
13488c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
13498c0984e5SSebastian Reichel 
135072d9cd9cSMichał Mirosław 	mutex_lock(&bq->lock);
135172d9cd9cSMichał Mirosław 
135272d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &bq->state);
13538c0984e5SSebastian Reichel 	if (ret < 0)
1354cf5701bfSDan Carpenter 		goto unlock;
13558c0984e5SSebastian Reichel 
13568c0984e5SSebastian Reichel 	/* Re-enable ADC only if charger is plugged in. */
135772d9cd9cSMichał Mirosław 	if (bq->state.online) {
135821d90edaSMichał Mirosław 		ret = bq25890_field_write(bq, F_CONV_RATE, 1);
13598c0984e5SSebastian Reichel 		if (ret < 0)
1360cf5701bfSDan Carpenter 			goto unlock;
13618c0984e5SSebastian Reichel 	}
13628c0984e5SSebastian Reichel 
13638c0984e5SSebastian Reichel 	/* signal userspace, maybe state changed while suspended */
13648c0984e5SSebastian Reichel 	power_supply_changed(bq->charger);
13658c0984e5SSebastian Reichel 
1366cf5701bfSDan Carpenter unlock:
136772d9cd9cSMichał Mirosław 	mutex_unlock(&bq->lock);
136872d9cd9cSMichał Mirosław 
1369cf5701bfSDan Carpenter 	return ret;
13708c0984e5SSebastian Reichel }
13718c0984e5SSebastian Reichel #endif
13728c0984e5SSebastian Reichel 
13738c0984e5SSebastian Reichel static const struct dev_pm_ops bq25890_pm = {
13748c0984e5SSebastian Reichel 	SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume)
13758c0984e5SSebastian Reichel };
13768c0984e5SSebastian Reichel 
13778c0984e5SSebastian Reichel static const struct i2c_device_id bq25890_i2c_ids[] = {
13788c0984e5SSebastian Reichel 	{ "bq25890", 0 },
137946aa27e7SYauhen Kharuzhy 	{ "bq25892", 0 },
138046aa27e7SYauhen Kharuzhy 	{ "bq25895", 0 },
138146aa27e7SYauhen Kharuzhy 	{ "bq25896", 0 },
13828c0984e5SSebastian Reichel 	{},
13838c0984e5SSebastian Reichel };
13848c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids);
13858c0984e5SSebastian Reichel 
13868c0984e5SSebastian Reichel static const struct of_device_id bq25890_of_match[] = {
13878c0984e5SSebastian Reichel 	{ .compatible = "ti,bq25890", },
138846aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25892", },
138946aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25895", },
139046aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25896", },
13918c0984e5SSebastian Reichel 	{ },
13928c0984e5SSebastian Reichel };
13938c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, bq25890_of_match);
13948c0984e5SSebastian Reichel 
139502067dc9SKrzysztof Kozlowski #ifdef CONFIG_ACPI
13968c0984e5SSebastian Reichel static const struct acpi_device_id bq25890_acpi_match[] = {
13978c0984e5SSebastian Reichel 	{"BQ258900", 0},
13988c0984e5SSebastian Reichel 	{},
13998c0984e5SSebastian Reichel };
14008c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match);
140102067dc9SKrzysztof Kozlowski #endif
14028c0984e5SSebastian Reichel 
14038c0984e5SSebastian Reichel static struct i2c_driver bq25890_driver = {
14048c0984e5SSebastian Reichel 	.driver = {
14058c0984e5SSebastian Reichel 		.name = "bq25890-charger",
14068c0984e5SSebastian Reichel 		.of_match_table = of_match_ptr(bq25890_of_match),
14078c0984e5SSebastian Reichel 		.acpi_match_table = ACPI_PTR(bq25890_acpi_match),
14088c0984e5SSebastian Reichel 		.pm = &bq25890_pm,
14098c0984e5SSebastian Reichel 	},
14108c0984e5SSebastian Reichel 	.probe = bq25890_probe,
14118c0984e5SSebastian Reichel 	.remove = bq25890_remove,
141279d35365SHans de Goede 	.shutdown = bq25890_shutdown,
14138c0984e5SSebastian Reichel 	.id_table = bq25890_i2c_ids,
14148c0984e5SSebastian Reichel };
14158c0984e5SSebastian Reichel module_i2c_driver(bq25890_driver);
14168c0984e5SSebastian Reichel 
14178c0984e5SSebastian Reichel MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
14188c0984e5SSebastian Reichel MODULE_DESCRIPTION("bq25890 charger driver");
14198c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
1420