xref: /openbmc/linux/drivers/power/supply/bq25890_charger.c (revision d1b25092b3dce96a69fc31b462e61291848fda9f)
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 
457*d1b25092SMarek Vasut static void bq25890_update_state(struct bq25890_device *bq,
4588c0984e5SSebastian Reichel 				 enum power_supply_property psp,
459*d1b25092SMarek Vasut 				 struct bq25890_state *state)
4608c0984e5SSebastian Reichel {
46121d90edaSMichał Mirosław 	bool do_adc_conv;
46221d90edaSMichał Mirosław 	int ret;
4638c0984e5SSebastian Reichel 
4648c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
4653b4df57bSMichał Mirosław 	/* update state in case we lost an interrupt */
4663b4df57bSMichał Mirosław 	__bq25890_handle_irq(bq);
467*d1b25092SMarek Vasut 	*state = bq->state;
468*d1b25092SMarek Vasut 	do_adc_conv = !state->online && bq25890_is_adc_property(psp);
46921d90edaSMichał Mirosław 	if (do_adc_conv)
47021d90edaSMichał Mirosław 		bq25890_field_write(bq, F_CONV_START, 1);
4718c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
4728c0984e5SSebastian Reichel 
47321d90edaSMichał Mirosław 	if (do_adc_conv)
47421d90edaSMichał Mirosław 		regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START],
47521d90edaSMichał Mirosław 			ret, !ret, 25000, 1000000);
476*d1b25092SMarek Vasut }
477*d1b25092SMarek Vasut 
478*d1b25092SMarek Vasut static int bq25890_power_supply_get_property(struct power_supply *psy,
479*d1b25092SMarek Vasut 					     enum power_supply_property psp,
480*d1b25092SMarek Vasut 					     union power_supply_propval *val)
481*d1b25092SMarek Vasut {
482*d1b25092SMarek Vasut 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
483*d1b25092SMarek Vasut 	struct bq25890_state state;
484*d1b25092SMarek Vasut 	int ret;
485*d1b25092SMarek Vasut 
486*d1b25092SMarek Vasut 	bq25890_update_state(bq, psp, &state);
48721d90edaSMichał Mirosław 
4888c0984e5SSebastian Reichel 	switch (psp) {
4898c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_STATUS:
4908c0984e5SSebastian Reichel 		if (!state.online)
4918c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
4928c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_NOT_CHARGING)
4938c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
4948c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_PRE_CHARGING ||
4958c0984e5SSebastian Reichel 			 state.chrg_status == STATUS_FAST_CHARGING)
4968c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
4978c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_TERMINATION_DONE)
4988c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_FULL;
4998c0984e5SSebastian Reichel 		else
5008c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
5018c0984e5SSebastian Reichel 
5028c0984e5SSebastian Reichel 		break;
5038c0984e5SSebastian Reichel 
504b302a0aeSMichał Mirosław 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
505b302a0aeSMichał Mirosław 		if (!state.online || state.chrg_status == STATUS_NOT_CHARGING ||
506b302a0aeSMichał Mirosław 		    state.chrg_status == STATUS_TERMINATION_DONE)
507b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
508b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_PRE_CHARGING)
509b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
510b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_FAST_CHARGING)
511b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
512b302a0aeSMichał Mirosław 		else /* unreachable */
513b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
514b302a0aeSMichał Mirosław 		break;
515b302a0aeSMichał Mirosław 
5168c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MANUFACTURER:
5178c0984e5SSebastian Reichel 		val->strval = BQ25890_MANUFACTURER;
5188c0984e5SSebastian Reichel 		break;
5198c0984e5SSebastian Reichel 
5202e1a2ddeSAngus Ainslie (Purism) 	case POWER_SUPPLY_PROP_MODEL_NAME:
5215956fca7SMichał Mirosław 		val->strval = bq25890_chip_name[bq->chip_version];
5222e1a2ddeSAngus Ainslie (Purism) 		break;
5232e1a2ddeSAngus Ainslie (Purism) 
5248c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
5258c0984e5SSebastian Reichel 		val->intval = state.online;
5268c0984e5SSebastian Reichel 		break;
5278c0984e5SSebastian Reichel 
5288c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_HEALTH:
5298c0984e5SSebastian Reichel 		if (!state.chrg_fault && !state.bat_fault && !state.boost_fault)
5308c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_GOOD;
5318c0984e5SSebastian Reichel 		else if (state.bat_fault)
5328c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
5338c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED)
5348c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
5358c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN)
5368c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
5378c0984e5SSebastian Reichel 		else
5388c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
5398c0984e5SSebastian Reichel 		break;
5408c0984e5SSebastian Reichel 
541c942656dSMichał Mirosław 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
542c942656dSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM);
543c942656dSMichał Mirosław 		break;
544c942656dSMichał Mirosław 
5458c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
5468c0984e5SSebastian Reichel 		val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM);
5478c0984e5SSebastian Reichel 		break;
5488c0984e5SSebastian Reichel 
549478efc79SMichał Mirosław 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
550766873c1SYauhen Kharuzhy 		ret = bq25890_field_read(bq, F_IINLIM);
551478efc79SMichał Mirosław 		if (ret < 0)
552478efc79SMichał Mirosław 			return ret;
553478efc79SMichał Mirosław 
554766873c1SYauhen Kharuzhy 		val->intval = bq25890_find_val(ret, TBL_IINLIM);
555478efc79SMichał Mirosław 		break;
556478efc79SMichał Mirosław 
557ef1ca210SMarek Vasut 	case POWER_SUPPLY_PROP_CURRENT_NOW:	/* I_BAT now */
558ef1ca210SMarek Vasut 		/*
559ef1ca210SMarek Vasut 		 * This is ADC-sampled immediate charge current supplied
560ef1ca210SMarek Vasut 		 * from charger to battery. The property name is confusing,
561ef1ca210SMarek Vasut 		 * for clarification refer to:
562ef1ca210SMarek Vasut 		 * Documentation/ABI/testing/sysfs-class-power
563ef1ca210SMarek Vasut 		 * /sys/class/power_supply/<supply_name>/current_now
564ef1ca210SMarek Vasut 		 */
5651e4724d0SMichał Mirosław 		ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */
5661e4724d0SMichał Mirosław 		if (ret < 0)
5671e4724d0SMichał Mirosław 			return ret;
5681e4724d0SMichał Mirosław 
5691e4724d0SMichał Mirosław 		/* converted_val = ADC_val * 50mA (table 10.3.19) */
5701e4724d0SMichał Mirosław 		val->intval = ret * -50000;
5711e4724d0SMichał Mirosław 		break;
5721e4724d0SMichał Mirosław 
5738327a8abSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:	/* I_BAT user limit */
5748327a8abSMarek Vasut 		/*
5758327a8abSMarek Vasut 		 * This is user-configured constant charge current supplied
5768327a8abSMarek Vasut 		 * from charger to battery in first phase of charging, when
5778327a8abSMarek Vasut 		 * battery voltage is below constant charge voltage.
5788327a8abSMarek Vasut 		 *
5798327a8abSMarek Vasut 		 * This value reflects the current hardware setting.
5808327a8abSMarek Vasut 		 *
5818327a8abSMarek Vasut 		 * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX is the
5828327a8abSMarek Vasut 		 * maximum value of this property.
5838327a8abSMarek Vasut 		 */
5848327a8abSMarek Vasut 		ret = bq25890_field_read(bq, F_ICHG);
5858327a8abSMarek Vasut 		if (ret < 0)
5868327a8abSMarek Vasut 			return ret;
5878327a8abSMarek Vasut 		val->intval = bq25890_find_val(ret, TBL_ICHG);
5888327a8abSMarek Vasut 
5898327a8abSMarek Vasut 		/* When temperature is too low, charge current is decreased */
5908327a8abSMarek Vasut 		if (bq->state.ntc_fault == NTC_FAULT_COOL) {
5918327a8abSMarek Vasut 			ret = bq25890_field_read(bq, F_JEITA_ISET);
5928327a8abSMarek Vasut 			if (ret < 0)
5938327a8abSMarek Vasut 				return ret;
5948327a8abSMarek Vasut 
5958327a8abSMarek Vasut 			if (ret)
5968327a8abSMarek Vasut 				val->intval /= 5;
5978327a8abSMarek Vasut 			else
5988327a8abSMarek Vasut 				val->intval /= 2;
5998327a8abSMarek Vasut 		}
6008327a8abSMarek Vasut 		break;
6018327a8abSMarek Vasut 
6028327a8abSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:	/* I_BAT max */
6038327a8abSMarek Vasut 		/*
6048327a8abSMarek Vasut 		 * This is maximum allowed constant charge current supplied
6058327a8abSMarek Vasut 		 * from charger to battery in first phase of charging, when
6068327a8abSMarek Vasut 		 * battery voltage is below constant charge voltage.
6078327a8abSMarek Vasut 		 *
6088327a8abSMarek Vasut 		 * This value is constant for each battery and set from DT.
6098327a8abSMarek Vasut 		 */
6108327a8abSMarek Vasut 		val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
6118327a8abSMarek Vasut 		break;
6128327a8abSMarek Vasut 
6137c852375SMarek Vasut 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:	/* V_BAT now */
6147c852375SMarek Vasut 		/*
6157c852375SMarek Vasut 		 * This is ADC-sampled immediate charge voltage supplied
6167c852375SMarek Vasut 		 * from charger to battery. The property name is confusing,
6177c852375SMarek Vasut 		 * for clarification refer to:
6187c852375SMarek Vasut 		 * Documentation/ABI/testing/sysfs-class-power
6197c852375SMarek Vasut 		 * /sys/class/power_supply/<supply_name>/voltage_now
6207c852375SMarek Vasut 		 */
6217c852375SMarek Vasut 		ret = bq25890_field_read(bq, F_BATV); /* read measured value */
6227c852375SMarek Vasut 		if (ret < 0)
6237c852375SMarek Vasut 			return ret;
6247c852375SMarek Vasut 
6257c852375SMarek Vasut 		/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
6267c852375SMarek Vasut 		val->intval = 2304000 + ret * 20000;
6277c852375SMarek Vasut 		break;
6287c852375SMarek Vasut 
6297c852375SMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:	/* V_BAT user limit */
6307c852375SMarek Vasut 		/*
6317c852375SMarek Vasut 		 * This is user-configured constant charge voltage supplied
6327c852375SMarek Vasut 		 * from charger to battery in second phase of charging, when
6337c852375SMarek Vasut 		 * battery voltage reached constant charge voltage.
6347c852375SMarek Vasut 		 *
6357c852375SMarek Vasut 		 * This value reflects the current hardware setting.
6367c852375SMarek Vasut 		 *
6377c852375SMarek Vasut 		 * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX is the
6387c852375SMarek Vasut 		 * maximum value of this property.
6397c852375SMarek Vasut 		 */
6407c852375SMarek Vasut 		ret = bq25890_field_read(bq, F_VREG);
6417c852375SMarek Vasut 		if (ret < 0)
6427c852375SMarek Vasut 			return ret;
6437c852375SMarek Vasut 
6447c852375SMarek Vasut 		val->intval = bq25890_find_val(ret, TBL_VREG);
6457c852375SMarek Vasut 		break;
6467c852375SMarek Vasut 
6477c852375SMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:	/* V_BAT max */
6487c852375SMarek Vasut 		/*
6497c852375SMarek Vasut 		 * This is maximum allowed constant charge voltage supplied
6507c852375SMarek Vasut 		 * from charger to battery in second phase of charging, when
6517c852375SMarek Vasut 		 * battery voltage reached constant charge voltage.
6527c852375SMarek Vasut 		 *
6537c852375SMarek Vasut 		 * This value is constant for each battery and set from DT.
6547c852375SMarek Vasut 		 */
6557c852375SMarek Vasut 		val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
6567c852375SMarek Vasut 		break;
6577c852375SMarek Vasut 
6589652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
6599652c024SAngus Ainslie 		ret = bq25890_field_read(bq, F_TSPCT);
6609652c024SAngus Ainslie 		if (ret < 0)
6619652c024SAngus Ainslie 			return ret;
6629652c024SAngus Ainslie 
6639652c024SAngus Ainslie 		/* convert TS percentage into rough temperature */
6649652c024SAngus Ainslie 		val->intval = bq25890_find_val(ret, TBL_TSPCT);
6659652c024SAngus Ainslie 		break;
6669652c024SAngus Ainslie 
6678c0984e5SSebastian Reichel 	default:
6688c0984e5SSebastian Reichel 		return -EINVAL;
6698c0984e5SSebastian Reichel 	}
6708c0984e5SSebastian Reichel 
6718c0984e5SSebastian Reichel 	return 0;
6728c0984e5SSebastian Reichel }
6738c0984e5SSebastian Reichel 
6744a4748f2SMarek Vasut static int bq25890_power_supply_set_property(struct power_supply *psy,
6754a4748f2SMarek Vasut 					     enum power_supply_property psp,
6764a4748f2SMarek Vasut 					     const union power_supply_propval *val)
6774a4748f2SMarek Vasut {
6784a4748f2SMarek Vasut 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
679b63e60ebSMarek Vasut 	int maxval;
6804a4748f2SMarek Vasut 	u8 lval;
6814a4748f2SMarek Vasut 
6824a4748f2SMarek Vasut 	switch (psp) {
683b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
684b63e60ebSMarek Vasut 		maxval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
685b63e60ebSMarek Vasut 		lval = bq25890_find_idx(min(val->intval, maxval), TBL_ICHG);
686b63e60ebSMarek Vasut 		return bq25890_field_write(bq, F_ICHG, lval);
687b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
688b63e60ebSMarek Vasut 		maxval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
689b63e60ebSMarek Vasut 		lval = bq25890_find_idx(min(val->intval, maxval), TBL_VREG);
690b63e60ebSMarek Vasut 		return bq25890_field_write(bq, F_VREG, lval);
6914a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
69255cafd4bSNathan Chancellor 		lval = bq25890_find_idx(val->intval, TBL_IINLIM);
6934a4748f2SMarek Vasut 		return bq25890_field_write(bq, F_IINLIM, lval);
6944a4748f2SMarek Vasut 	default:
6954a4748f2SMarek Vasut 		return -EINVAL;
6964a4748f2SMarek Vasut 	}
6974a4748f2SMarek Vasut }
6984a4748f2SMarek Vasut 
6994a4748f2SMarek Vasut static int bq25890_power_supply_property_is_writeable(struct power_supply *psy,
7004a4748f2SMarek Vasut 						      enum power_supply_property psp)
7014a4748f2SMarek Vasut {
7024a4748f2SMarek Vasut 	switch (psp) {
703b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
704b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
7054a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
7064a4748f2SMarek Vasut 		return true;
7074a4748f2SMarek Vasut 	default:
7084a4748f2SMarek Vasut 		return false;
7094a4748f2SMarek Vasut 	}
7104a4748f2SMarek Vasut }
7114a4748f2SMarek Vasut 
712eab25b4fSHans de Goede /* On the BQ25892 try to get charger-type info from our supplier */
713eab25b4fSHans de Goede static void bq25890_charger_external_power_changed(struct power_supply *psy)
714eab25b4fSHans de Goede {
715eab25b4fSHans de Goede 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
716eab25b4fSHans de Goede 	union power_supply_propval val;
717eab25b4fSHans de Goede 	int input_current_limit, ret;
718eab25b4fSHans de Goede 
719eab25b4fSHans de Goede 	if (bq->chip_version != BQ25892)
720eab25b4fSHans de Goede 		return;
721eab25b4fSHans de Goede 
722eab25b4fSHans de Goede 	ret = power_supply_get_property_from_supplier(bq->charger,
723eab25b4fSHans de Goede 						      POWER_SUPPLY_PROP_USB_TYPE,
724eab25b4fSHans de Goede 						      &val);
725eab25b4fSHans de Goede 	if (ret)
726eab25b4fSHans de Goede 		return;
727eab25b4fSHans de Goede 
728eab25b4fSHans de Goede 	switch (val.intval) {
729eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_DCP:
730eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM);
73148f45b09SYauhen Kharuzhy 		if (bq->pump_express_vbus_max) {
73248f45b09SYauhen Kharuzhy 			queue_delayed_work(system_power_efficient_wq,
73348f45b09SYauhen Kharuzhy 					   &bq->pump_express_work,
73448f45b09SYauhen Kharuzhy 					   PUMP_EXPRESS_START_DELAY);
73548f45b09SYauhen Kharuzhy 		}
736eab25b4fSHans de Goede 		break;
737eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_CDP:
738eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_ACA:
739eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM);
740eab25b4fSHans de Goede 		break;
741eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_SDP:
742eab25b4fSHans de Goede 	default:
743eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(500000, TBL_IINLIM);
744eab25b4fSHans de Goede 	}
745eab25b4fSHans de Goede 
746eab25b4fSHans de Goede 	bq25890_field_write(bq, F_IINLIM, input_current_limit);
747eab25b4fSHans de Goede }
748eab25b4fSHans de Goede 
7498c0984e5SSebastian Reichel static int bq25890_get_chip_state(struct bq25890_device *bq,
7508c0984e5SSebastian Reichel 				  struct bq25890_state *state)
7518c0984e5SSebastian Reichel {
7528c0984e5SSebastian Reichel 	int i, ret;
7538c0984e5SSebastian Reichel 
7548c0984e5SSebastian Reichel 	struct {
7558c0984e5SSebastian Reichel 		enum bq25890_fields id;
7568c0984e5SSebastian Reichel 		u8 *data;
7578c0984e5SSebastian Reichel 	} state_fields[] = {
7588c0984e5SSebastian Reichel 		{F_CHG_STAT,	&state->chrg_status},
7598c0984e5SSebastian Reichel 		{F_PG_STAT,	&state->online},
7608c0984e5SSebastian Reichel 		{F_VSYS_STAT,	&state->vsys_status},
7618c0984e5SSebastian Reichel 		{F_BOOST_FAULT, &state->boost_fault},
7628c0984e5SSebastian Reichel 		{F_BAT_FAULT,	&state->bat_fault},
763c562a43aSYauhen Kharuzhy 		{F_CHG_FAULT,	&state->chrg_fault},
764c562a43aSYauhen Kharuzhy 		{F_NTC_FAULT,	&state->ntc_fault}
7658c0984e5SSebastian Reichel 	};
7668c0984e5SSebastian Reichel 
7678c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(state_fields); i++) {
7688c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, state_fields[i].id);
7698c0984e5SSebastian Reichel 		if (ret < 0)
7708c0984e5SSebastian Reichel 			return ret;
7718c0984e5SSebastian Reichel 
7728c0984e5SSebastian Reichel 		*state_fields[i].data = ret;
7738c0984e5SSebastian Reichel 	}
7748c0984e5SSebastian Reichel 
775c562a43aSYauhen Kharuzhy 	dev_dbg(bq->dev, "S:CHG/PG/VSYS=%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
7768c0984e5SSebastian Reichel 		state->chrg_status, state->online, state->vsys_status,
777c562a43aSYauhen Kharuzhy 		state->chrg_fault, state->boost_fault, state->bat_fault,
778c562a43aSYauhen Kharuzhy 		state->ntc_fault);
7798c0984e5SSebastian Reichel 
7808c0984e5SSebastian Reichel 	return 0;
7818c0984e5SSebastian Reichel }
7828c0984e5SSebastian Reichel 
78372d9cd9cSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
7848c0984e5SSebastian Reichel {
78572d9cd9cSMichał Mirosław 	struct bq25890_state new_state;
7868c0984e5SSebastian Reichel 	int ret;
7878c0984e5SSebastian Reichel 
78872d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &new_state);
78972d9cd9cSMichał Mirosław 	if (ret < 0)
79072d9cd9cSMichał Mirosław 		return IRQ_NONE;
7918c0984e5SSebastian Reichel 
79272d9cd9cSMichał Mirosław 	if (!memcmp(&bq->state, &new_state, sizeof(new_state)))
79372d9cd9cSMichał Mirosław 		return IRQ_NONE;
79472d9cd9cSMichał Mirosław 
79572d9cd9cSMichał Mirosław 	if (!new_state.online && bq->state.online) {	    /* power removed */
7968c0984e5SSebastian Reichel 		/* disable ADC */
79780211be1SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_CONV_RATE, 0);
7988c0984e5SSebastian Reichel 		if (ret < 0)
7998c0984e5SSebastian Reichel 			goto error;
80072d9cd9cSMichał Mirosław 	} else if (new_state.online && !bq->state.online) { /* power inserted */
8018c0984e5SSebastian Reichel 		/* enable ADC, to have control of charge current/voltage */
80280211be1SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_CONV_RATE, 1);
8038c0984e5SSebastian Reichel 		if (ret < 0)
8048c0984e5SSebastian Reichel 			goto error;
8058c0984e5SSebastian Reichel 	}
8068c0984e5SSebastian Reichel 
80772d9cd9cSMichał Mirosław 	bq->state = new_state;
80872d9cd9cSMichał Mirosław 	power_supply_changed(bq->charger);
8098c0984e5SSebastian Reichel 
81072d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
8118c0984e5SSebastian Reichel error:
81272d9cd9cSMichał Mirosław 	dev_err(bq->dev, "Error communicating with the chip: %pe\n",
81372d9cd9cSMichał Mirosław 		ERR_PTR(ret));
81472d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
8158c0984e5SSebastian Reichel }
8168c0984e5SSebastian Reichel 
8178c0984e5SSebastian Reichel static irqreturn_t bq25890_irq_handler_thread(int irq, void *private)
8188c0984e5SSebastian Reichel {
8198c0984e5SSebastian Reichel 	struct bq25890_device *bq = private;
82072d9cd9cSMichał Mirosław 	irqreturn_t ret;
8218c0984e5SSebastian Reichel 
8228c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
82372d9cd9cSMichał Mirosław 	ret = __bq25890_handle_irq(bq);
8248c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
8258c0984e5SSebastian Reichel 
82672d9cd9cSMichał Mirosław 	return ret;
8278c0984e5SSebastian Reichel }
8288c0984e5SSebastian Reichel 
8298c0984e5SSebastian Reichel static int bq25890_chip_reset(struct bq25890_device *bq)
8308c0984e5SSebastian Reichel {
8318c0984e5SSebastian Reichel 	int ret;
8328c0984e5SSebastian Reichel 	int rst_check_counter = 10;
8338c0984e5SSebastian Reichel 
8348c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_REG_RST, 1);
8358c0984e5SSebastian Reichel 	if (ret < 0)
8368c0984e5SSebastian Reichel 		return ret;
8378c0984e5SSebastian Reichel 
8388c0984e5SSebastian Reichel 	do {
8398c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, F_REG_RST);
8408c0984e5SSebastian Reichel 		if (ret < 0)
8418c0984e5SSebastian Reichel 			return ret;
8428c0984e5SSebastian Reichel 
8438c0984e5SSebastian Reichel 		usleep_range(5, 10);
8448c0984e5SSebastian Reichel 	} while (ret == 1 && --rst_check_counter);
8458c0984e5SSebastian Reichel 
8468c0984e5SSebastian Reichel 	if (!rst_check_counter)
8478c0984e5SSebastian Reichel 		return -ETIMEDOUT;
8488c0984e5SSebastian Reichel 
8498c0984e5SSebastian Reichel 	return 0;
8508c0984e5SSebastian Reichel }
8518c0984e5SSebastian Reichel 
8527b22a974SHans de Goede static int bq25890_rw_init_data(struct bq25890_device *bq)
8538c0984e5SSebastian Reichel {
85440428bd4SHans de Goede 	bool write = !bq->read_back_init_data;
8558c0984e5SSebastian Reichel 	int ret;
8568c0984e5SSebastian Reichel 	int i;
8578c0984e5SSebastian Reichel 
8588c0984e5SSebastian Reichel 	const struct {
8598c0984e5SSebastian Reichel 		enum bq25890_fields id;
8607b22a974SHans de Goede 		u8 *value;
8618c0984e5SSebastian Reichel 	} init_data[] = {
8627b22a974SHans de Goede 		{F_ICHG,	 &bq->init_data.ichg},
8637b22a974SHans de Goede 		{F_VREG,	 &bq->init_data.vreg},
8647b22a974SHans de Goede 		{F_ITERM,	 &bq->init_data.iterm},
8657b22a974SHans de Goede 		{F_IPRECHG,	 &bq->init_data.iprechg},
8667b22a974SHans de Goede 		{F_SYSVMIN,	 &bq->init_data.sysvmin},
8677b22a974SHans de Goede 		{F_BOOSTV,	 &bq->init_data.boostv},
8687b22a974SHans de Goede 		{F_BOOSTI,	 &bq->init_data.boosti},
8697b22a974SHans de Goede 		{F_BOOSTF,	 &bq->init_data.boostf},
8707b22a974SHans de Goede 		{F_EN_ILIM,	 &bq->init_data.ilim_en},
8717b22a974SHans de Goede 		{F_TREG,	 &bq->init_data.treg},
8727b22a974SHans de Goede 		{F_BATCMP,	 &bq->init_data.rbatcomp},
8737b22a974SHans de Goede 		{F_VCLAMP,	 &bq->init_data.vclamp},
8748c0984e5SSebastian Reichel 	};
8758c0984e5SSebastian Reichel 
8767b22a974SHans de Goede 	for (i = 0; i < ARRAY_SIZE(init_data); i++) {
8777b22a974SHans de Goede 		if (write) {
8787b22a974SHans de Goede 			ret = bq25890_field_write(bq, init_data[i].id,
8797b22a974SHans de Goede 						  *init_data[i].value);
8807b22a974SHans de Goede 		} else {
8817b22a974SHans de Goede 			ret = bq25890_field_read(bq, init_data[i].id);
8827b22a974SHans de Goede 			if (ret >= 0)
8837b22a974SHans de Goede 				*init_data[i].value = ret;
8847b22a974SHans de Goede 		}
8857b22a974SHans de Goede 		if (ret < 0) {
8867b22a974SHans de Goede 			dev_dbg(bq->dev, "Accessing init data failed %d\n", ret);
8877b22a974SHans de Goede 			return ret;
8887b22a974SHans de Goede 		}
8897b22a974SHans de Goede 	}
8907b22a974SHans de Goede 
8917b22a974SHans de Goede 	return 0;
8927b22a974SHans de Goede }
8937b22a974SHans de Goede 
8947b22a974SHans de Goede static int bq25890_hw_init(struct bq25890_device *bq)
8957b22a974SHans de Goede {
8967b22a974SHans de Goede 	int ret;
8977b22a974SHans de Goede 
8987e3b8e35SHans de Goede 	if (!bq->skip_reset) {
8998c0984e5SSebastian Reichel 		ret = bq25890_chip_reset(bq);
9009d9ae341SAngus Ainslie (Purism) 		if (ret < 0) {
9019d9ae341SAngus Ainslie (Purism) 			dev_dbg(bq->dev, "Reset failed %d\n", ret);
9028c0984e5SSebastian Reichel 			return ret;
903ad1570d9Skbuild test robot 		}
90406c75095SHans de Goede 	} else {
90506c75095SHans de Goede 		/*
90606c75095SHans de Goede 		 * Ensure charging is enabled, on some boards where the fw
90706c75095SHans de Goede 		 * takes care of initalizition F_CHG_CFG is set to 0 before
90806c75095SHans de Goede 		 * handing control over to the OS.
90906c75095SHans de Goede 		 */
91006c75095SHans de Goede 		ret = bq25890_field_write(bq, F_CHG_CFG, 1);
91106c75095SHans de Goede 		if (ret < 0) {
91206c75095SHans de Goede 			dev_dbg(bq->dev, "Enabling charging failed %d\n", ret);
91306c75095SHans de Goede 			return ret;
91406c75095SHans de Goede 		}
9157e3b8e35SHans de Goede 	}
9168c0984e5SSebastian Reichel 
9178c0984e5SSebastian Reichel 	/* disable watchdog */
9188c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_WD, 0);
9199d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
9209d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret);
9218c0984e5SSebastian Reichel 		return ret;
922ad1570d9Skbuild test robot 	}
9238c0984e5SSebastian Reichel 
9248c0984e5SSebastian Reichel 	/* initialize currents/voltages and other parameters */
9257b22a974SHans de Goede 	ret = bq25890_rw_init_data(bq);
9267b22a974SHans de Goede 	if (ret)
9278c0984e5SSebastian Reichel 		return ret;
9288c0984e5SSebastian Reichel 
92922ad4f99SHans de Goede 	ret = bq25890_get_chip_state(bq, &bq->state);
93022ad4f99SHans de Goede 	if (ret < 0) {
93122ad4f99SHans de Goede 		dev_dbg(bq->dev, "Get state failed %d\n", ret);
93222ad4f99SHans de Goede 		return ret;
93322ad4f99SHans de Goede 	}
93422ad4f99SHans de Goede 
93521d90edaSMichał Mirosław 	/* Configure ADC for continuous conversions when charging */
93621d90edaSMichał Mirosław 	ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
9379d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
9389d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
9398c0984e5SSebastian Reichel 		return ret;
940ad1570d9Skbuild test robot 	}
9418c0984e5SSebastian Reichel 
9428c0984e5SSebastian Reichel 	return 0;
9438c0984e5SSebastian Reichel }
9448c0984e5SSebastian Reichel 
945a6a48facSMichał Mirosław static const enum power_supply_property bq25890_power_supply_props[] = {
9468c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MANUFACTURER,
9472e1a2ddeSAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_MODEL_NAME,
9488c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
949b302a0aeSMichał Mirosław 	POWER_SUPPLY_PROP_CHARGE_TYPE,
9508c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
9518c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_HEALTH,
9528327a8abSMarek Vasut 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
9538c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
9548c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
9558c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
956c942656dSMichał Mirosław 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
9578c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
958478efc79SMichał Mirosław 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
959ae6fe7a3SAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
9601e4724d0SMichał Mirosław 	POWER_SUPPLY_PROP_CURRENT_NOW,
9619652c024SAngus Ainslie 	POWER_SUPPLY_PROP_TEMP,
9628c0984e5SSebastian Reichel };
9638c0984e5SSebastian Reichel 
9648c0984e5SSebastian Reichel static char *bq25890_charger_supplied_to[] = {
9658c0984e5SSebastian Reichel 	"main-battery",
9668c0984e5SSebastian Reichel };
9678c0984e5SSebastian Reichel 
9688c0984e5SSebastian Reichel static const struct power_supply_desc bq25890_power_supply_desc = {
9698c0984e5SSebastian Reichel 	.name = "bq25890-charger",
9708c0984e5SSebastian Reichel 	.type = POWER_SUPPLY_TYPE_USB,
9718c0984e5SSebastian Reichel 	.properties = bq25890_power_supply_props,
9728c0984e5SSebastian Reichel 	.num_properties = ARRAY_SIZE(bq25890_power_supply_props),
9738c0984e5SSebastian Reichel 	.get_property = bq25890_power_supply_get_property,
9744a4748f2SMarek Vasut 	.set_property = bq25890_power_supply_set_property,
9754a4748f2SMarek Vasut 	.property_is_writeable = bq25890_power_supply_property_is_writeable,
976eab25b4fSHans de Goede 	.external_power_changed	= bq25890_charger_external_power_changed,
9778c0984e5SSebastian Reichel };
9788c0984e5SSebastian Reichel 
9798c0984e5SSebastian Reichel static int bq25890_power_supply_init(struct bq25890_device *bq)
9808c0984e5SSebastian Reichel {
9818c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = { .drv_data = bq, };
9828c0984e5SSebastian Reichel 
9838c0984e5SSebastian Reichel 	psy_cfg.supplied_to = bq25890_charger_supplied_to;
9848c0984e5SSebastian Reichel 	psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
9858c0984e5SSebastian Reichel 
986d01363daSHans de Goede 	bq->charger = devm_power_supply_register(bq->dev,
987d01363daSHans de Goede 						 &bq25890_power_supply_desc,
9888c0984e5SSebastian Reichel 						 &psy_cfg);
9898c0984e5SSebastian Reichel 
9908c0984e5SSebastian Reichel 	return PTR_ERR_OR_ZERO(bq->charger);
9918c0984e5SSebastian Reichel }
9928c0984e5SSebastian Reichel 
9935575802dSHans de Goede static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val)
9945575802dSHans de Goede {
9955575802dSHans de Goede 	int ret;
9965575802dSHans de Goede 
9975575802dSHans de Goede 	ret = bq25890_field_write(bq, F_OTG_CFG, val);
9985575802dSHans de Goede 	if (ret < 0)
9995575802dSHans de Goede 		dev_err(bq->dev, "Error switching to boost/charger mode: %d\n", ret);
10005575802dSHans de Goede 
10015575802dSHans de Goede 	return ret;
10025575802dSHans de Goede }
10035575802dSHans de Goede 
100448f45b09SYauhen Kharuzhy static void bq25890_pump_express_work(struct work_struct *data)
100548f45b09SYauhen Kharuzhy {
100648f45b09SYauhen Kharuzhy 	struct bq25890_device *bq =
100748f45b09SYauhen Kharuzhy 		container_of(data, struct bq25890_device, pump_express_work.work);
100848f45b09SYauhen Kharuzhy 	int voltage, i, ret;
100948f45b09SYauhen Kharuzhy 
101048f45b09SYauhen Kharuzhy 	dev_dbg(bq->dev, "Start to request input voltage increasing\n");
101148f45b09SYauhen Kharuzhy 
101248f45b09SYauhen Kharuzhy 	/* Enable current pulse voltage control protocol */
101348f45b09SYauhen Kharuzhy 	ret = bq25890_field_write(bq, F_PUMPX_EN, 1);
101448f45b09SYauhen Kharuzhy 	if (ret < 0)
101548f45b09SYauhen Kharuzhy 		goto error_print;
101648f45b09SYauhen Kharuzhy 
101748f45b09SYauhen Kharuzhy 	for (i = 0; i < PUMP_EXPRESS_MAX_TRIES; i++) {
101848f45b09SYauhen Kharuzhy 		voltage = bq25890_get_vbus_voltage(bq);
101948f45b09SYauhen Kharuzhy 		if (voltage < 0)
102048f45b09SYauhen Kharuzhy 			goto error_print;
102148f45b09SYauhen Kharuzhy 		dev_dbg(bq->dev, "input voltage = %d uV\n", voltage);
102248f45b09SYauhen Kharuzhy 
102348f45b09SYauhen Kharuzhy 		if ((voltage + PUMP_EXPRESS_VBUS_MARGIN_uV) >
102448f45b09SYauhen Kharuzhy 					bq->pump_express_vbus_max)
102548f45b09SYauhen Kharuzhy 			break;
102648f45b09SYauhen Kharuzhy 
102748f45b09SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_PUMPX_UP, 1);
102848f45b09SYauhen Kharuzhy 		if (ret < 0)
102948f45b09SYauhen Kharuzhy 			goto error_print;
103048f45b09SYauhen Kharuzhy 
103148f45b09SYauhen Kharuzhy 		/* Note a single PUMPX up pulse-sequence takes 2.1s */
103248f45b09SYauhen Kharuzhy 		ret = regmap_field_read_poll_timeout(bq->rmap_fields[F_PUMPX_UP],
103348f45b09SYauhen Kharuzhy 						     ret, !ret, 100000, 3000000);
103448f45b09SYauhen Kharuzhy 		if (ret < 0)
103548f45b09SYauhen Kharuzhy 			goto error_print;
103648f45b09SYauhen Kharuzhy 
103748f45b09SYauhen Kharuzhy 		/* Make sure ADC has sampled Vbus before checking again */
103848f45b09SYauhen Kharuzhy 		msleep(1000);
103948f45b09SYauhen Kharuzhy 	}
104048f45b09SYauhen Kharuzhy 
104148f45b09SYauhen Kharuzhy 	bq25890_field_write(bq, F_PUMPX_EN, 0);
104248f45b09SYauhen Kharuzhy 
104348f45b09SYauhen Kharuzhy 	dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n",
104448f45b09SYauhen Kharuzhy 		 voltage);
104548f45b09SYauhen Kharuzhy 
104648f45b09SYauhen Kharuzhy 	return;
104748f45b09SYauhen Kharuzhy error_print:
104804f7c7dfSHans de Goede 	bq25890_field_write(bq, F_PUMPX_EN, 0);
104948f45b09SYauhen Kharuzhy 	dev_err(bq->dev, "Failed to request hi-voltage charging\n");
105048f45b09SYauhen Kharuzhy }
105148f45b09SYauhen Kharuzhy 
10528c0984e5SSebastian Reichel static void bq25890_usb_work(struct work_struct *data)
10538c0984e5SSebastian Reichel {
10548c0984e5SSebastian Reichel 	int ret;
10558c0984e5SSebastian Reichel 	struct bq25890_device *bq =
10568c0984e5SSebastian Reichel 			container_of(data, struct bq25890_device, usb_work);
10578c0984e5SSebastian Reichel 
10588c0984e5SSebastian Reichel 	switch (bq->usb_event) {
10598c0984e5SSebastian Reichel 	case USB_EVENT_ID:
10608c0984e5SSebastian Reichel 		/* Enable boost mode */
10615575802dSHans de Goede 		bq25890_set_otg_cfg(bq, 1);
10628c0984e5SSebastian Reichel 		break;
10638c0984e5SSebastian Reichel 
10648c0984e5SSebastian Reichel 	case USB_EVENT_NONE:
10658c0984e5SSebastian Reichel 		/* Disable boost mode */
10665575802dSHans de Goede 		ret = bq25890_set_otg_cfg(bq, 0);
10675575802dSHans de Goede 		if (ret == 0)
10688c0984e5SSebastian Reichel 			power_supply_changed(bq->charger);
10698c0984e5SSebastian Reichel 		break;
10708c0984e5SSebastian Reichel 	}
10718c0984e5SSebastian Reichel }
10728c0984e5SSebastian Reichel 
10738c0984e5SSebastian Reichel static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val,
10748c0984e5SSebastian Reichel 				void *priv)
10758c0984e5SSebastian Reichel {
10768c0984e5SSebastian Reichel 	struct bq25890_device *bq =
10778c0984e5SSebastian Reichel 			container_of(nb, struct bq25890_device, usb_nb);
10788c0984e5SSebastian Reichel 
10798c0984e5SSebastian Reichel 	bq->usb_event = val;
10808c0984e5SSebastian Reichel 	queue_work(system_power_efficient_wq, &bq->usb_work);
10818c0984e5SSebastian Reichel 
10828c0984e5SSebastian Reichel 	return NOTIFY_OK;
10838c0984e5SSebastian Reichel }
10848c0984e5SSebastian Reichel 
108579d35365SHans de Goede #ifdef CONFIG_REGULATOR
108679d35365SHans de Goede static int bq25890_vbus_enable(struct regulator_dev *rdev)
108779d35365SHans de Goede {
108879d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
108979d35365SHans de Goede 
109079d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 1);
109179d35365SHans de Goede }
109279d35365SHans de Goede 
109379d35365SHans de Goede static int bq25890_vbus_disable(struct regulator_dev *rdev)
109479d35365SHans de Goede {
109579d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
109679d35365SHans de Goede 
109779d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 0);
109879d35365SHans de Goede }
109979d35365SHans de Goede 
110079d35365SHans de Goede static int bq25890_vbus_is_enabled(struct regulator_dev *rdev)
110179d35365SHans de Goede {
110279d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
110379d35365SHans de Goede 
110479d35365SHans de Goede 	return bq25890_field_read(bq, F_OTG_CFG);
110579d35365SHans de Goede }
110679d35365SHans de Goede 
110785052e90SMarek Vasut static int bq25890_vbus_get_voltage(struct regulator_dev *rdev)
110885052e90SMarek Vasut {
110985052e90SMarek Vasut 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
111085052e90SMarek Vasut 
111185052e90SMarek Vasut 	return bq25890_get_vbus_voltage(bq);
111285052e90SMarek Vasut }
111385052e90SMarek Vasut 
111414a3d159SMarek Vasut static int bq25890_vsys_get_voltage(struct regulator_dev *rdev)
111514a3d159SMarek Vasut {
111614a3d159SMarek Vasut 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
111714a3d159SMarek Vasut 	int ret;
111814a3d159SMarek Vasut 
111914a3d159SMarek Vasut 	/* Should be some output voltage ? */
112014a3d159SMarek Vasut 	ret = bq25890_field_read(bq, F_SYSV); /* read measured value */
112114a3d159SMarek Vasut 	if (ret < 0)
112214a3d159SMarek Vasut 		return ret;
112314a3d159SMarek Vasut 
112414a3d159SMarek Vasut 	/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
112514a3d159SMarek Vasut 	return 2304000 + ret * 20000;
112614a3d159SMarek Vasut }
112714a3d159SMarek Vasut 
112879d35365SHans de Goede static const struct regulator_ops bq25890_vbus_ops = {
112979d35365SHans de Goede 	.enable = bq25890_vbus_enable,
113079d35365SHans de Goede 	.disable = bq25890_vbus_disable,
113179d35365SHans de Goede 	.is_enabled = bq25890_vbus_is_enabled,
113285052e90SMarek Vasut 	.get_voltage = bq25890_vbus_get_voltage,
113379d35365SHans de Goede };
113479d35365SHans de Goede 
113579d35365SHans de Goede static const struct regulator_desc bq25890_vbus_desc = {
113679d35365SHans de Goede 	.name = "usb_otg_vbus",
113779d35365SHans de Goede 	.of_match = "usb-otg-vbus",
113879d35365SHans de Goede 	.type = REGULATOR_VOLTAGE,
113979d35365SHans de Goede 	.owner = THIS_MODULE,
114079d35365SHans de Goede 	.ops = &bq25890_vbus_ops,
114179d35365SHans de Goede };
11425f5c10ecSMarek Vasut 
114314a3d159SMarek Vasut static const struct regulator_ops bq25890_vsys_ops = {
114414a3d159SMarek Vasut 	.get_voltage = bq25890_vsys_get_voltage,
114514a3d159SMarek Vasut };
114614a3d159SMarek Vasut 
114714a3d159SMarek Vasut static const struct regulator_desc bq25890_vsys_desc = {
114814a3d159SMarek Vasut 	.name = "vsys",
114914a3d159SMarek Vasut 	.of_match = "vsys",
115014a3d159SMarek Vasut 	.type = REGULATOR_VOLTAGE,
115114a3d159SMarek Vasut 	.owner = THIS_MODULE,
115214a3d159SMarek Vasut 	.ops = &bq25890_vsys_ops,
115314a3d159SMarek Vasut };
115414a3d159SMarek Vasut 
11555f5c10ecSMarek Vasut static int bq25890_register_regulator(struct bq25890_device *bq)
11565f5c10ecSMarek Vasut {
11575f5c10ecSMarek Vasut 	struct bq25890_platform_data *pdata = dev_get_platdata(bq->dev);
11585f5c10ecSMarek Vasut 	struct regulator_config cfg = {
11595f5c10ecSMarek Vasut 		.dev = bq->dev,
11605f5c10ecSMarek Vasut 		.driver_data = bq,
11615f5c10ecSMarek Vasut 	};
11625f5c10ecSMarek Vasut 	struct regulator_dev *reg;
11635f5c10ecSMarek Vasut 
11645f5c10ecSMarek Vasut 	if (pdata)
11655f5c10ecSMarek Vasut 		cfg.init_data = pdata->regulator_init_data;
11665f5c10ecSMarek Vasut 
11675f5c10ecSMarek Vasut 	reg = devm_regulator_register(bq->dev, &bq25890_vbus_desc, &cfg);
11685f5c10ecSMarek Vasut 	if (IS_ERR(reg)) {
11695f5c10ecSMarek Vasut 		return dev_err_probe(bq->dev, PTR_ERR(reg),
11705f5c10ecSMarek Vasut 				     "registering vbus regulator");
11715f5c10ecSMarek Vasut 	}
11725f5c10ecSMarek Vasut 
1173571650b3SHans de Goede 	/* pdata->regulator_init_data is for vbus only */
1174571650b3SHans de Goede 	cfg.init_data = NULL;
117514a3d159SMarek Vasut 	reg = devm_regulator_register(bq->dev, &bq25890_vsys_desc, &cfg);
117614a3d159SMarek Vasut 	if (IS_ERR(reg)) {
117714a3d159SMarek Vasut 		return dev_err_probe(bq->dev, PTR_ERR(reg),
117814a3d159SMarek Vasut 				     "registering vsys regulator");
117914a3d159SMarek Vasut 	}
118014a3d159SMarek Vasut 
11815f5c10ecSMarek Vasut 	return 0;
11825f5c10ecSMarek Vasut }
11835f5c10ecSMarek Vasut #else
11845f5c10ecSMarek Vasut static inline int
11855f5c10ecSMarek Vasut bq25890_register_regulator(struct bq25890_device *bq)
11865f5c10ecSMarek Vasut {
11875f5c10ecSMarek Vasut 	return 0;
11885f5c10ecSMarek Vasut }
118979d35365SHans de Goede #endif
119079d35365SHans de Goede 
1191d20267c9SYauhen Kharuzhy static int bq25890_get_chip_version(struct bq25890_device *bq)
1192d20267c9SYauhen Kharuzhy {
1193d20267c9SYauhen Kharuzhy 	int id, rev;
1194d20267c9SYauhen Kharuzhy 
1195d20267c9SYauhen Kharuzhy 	id = bq25890_field_read(bq, F_PN);
1196d20267c9SYauhen Kharuzhy 	if (id < 0) {
1197172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip ID: %d\n", id);
1198d20267c9SYauhen Kharuzhy 		return id;
1199d20267c9SYauhen Kharuzhy 	}
1200d20267c9SYauhen Kharuzhy 
1201d20267c9SYauhen Kharuzhy 	rev = bq25890_field_read(bq, F_DEV_REV);
1202d20267c9SYauhen Kharuzhy 	if (rev < 0) {
1203172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip revision: %d\n", rev);
1204cb619e80SColin Ian King 		return rev;
1205d20267c9SYauhen Kharuzhy 	}
1206d20267c9SYauhen Kharuzhy 
1207d20267c9SYauhen Kharuzhy 	switch (id) {
1208d20267c9SYauhen Kharuzhy 	case BQ25890_ID:
1209d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25890;
1210d20267c9SYauhen Kharuzhy 		break;
1211d20267c9SYauhen Kharuzhy 
1212d20267c9SYauhen Kharuzhy 	/* BQ25892 and BQ25896 share same ID 0 */
1213d20267c9SYauhen Kharuzhy 	case BQ25896_ID:
1214d20267c9SYauhen Kharuzhy 		switch (rev) {
1215d20267c9SYauhen Kharuzhy 		case 2:
1216d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25896;
1217d20267c9SYauhen Kharuzhy 			break;
1218d20267c9SYauhen Kharuzhy 		case 1:
1219d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1220d20267c9SYauhen Kharuzhy 			break;
1221d20267c9SYauhen Kharuzhy 		default:
1222d20267c9SYauhen Kharuzhy 			dev_err(bq->dev,
1223d20267c9SYauhen Kharuzhy 				"Unknown device revision %d, assume BQ25892\n",
1224d20267c9SYauhen Kharuzhy 				rev);
1225d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1226d20267c9SYauhen Kharuzhy 		}
1227d20267c9SYauhen Kharuzhy 		break;
1228d20267c9SYauhen Kharuzhy 
1229d20267c9SYauhen Kharuzhy 	case BQ25895_ID:
1230d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25895;
1231d20267c9SYauhen Kharuzhy 		break;
1232d20267c9SYauhen Kharuzhy 
1233d20267c9SYauhen Kharuzhy 	default:
1234d20267c9SYauhen Kharuzhy 		dev_err(bq->dev, "Unknown chip ID %d\n", id);
1235d20267c9SYauhen Kharuzhy 		return -ENODEV;
1236d20267c9SYauhen Kharuzhy 	}
1237d20267c9SYauhen Kharuzhy 
1238d20267c9SYauhen Kharuzhy 	return 0;
1239d20267c9SYauhen Kharuzhy }
1240d20267c9SYauhen Kharuzhy 
12418c0984e5SSebastian Reichel static int bq25890_irq_probe(struct bq25890_device *bq)
12428c0984e5SSebastian Reichel {
12438c0984e5SSebastian Reichel 	struct gpio_desc *irq;
12448c0984e5SSebastian Reichel 
124586775879SAndy Shevchenko 	irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN);
1246172d0cceSMartin Kepplinger 	if (IS_ERR(irq))
1247172d0cceSMartin Kepplinger 		return dev_err_probe(bq->dev, PTR_ERR(irq),
1248172d0cceSMartin Kepplinger 				     "Could not probe irq pin.\n");
12498c0984e5SSebastian Reichel 
12508c0984e5SSebastian Reichel 	return gpiod_to_irq(irq);
12518c0984e5SSebastian Reichel }
12528c0984e5SSebastian Reichel 
12538c0984e5SSebastian Reichel static int bq25890_fw_read_u32_props(struct bq25890_device *bq)
12548c0984e5SSebastian Reichel {
12558c0984e5SSebastian Reichel 	int ret;
12568c0984e5SSebastian Reichel 	u32 property;
12578c0984e5SSebastian Reichel 	int i;
12588c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
12598c0984e5SSebastian Reichel 	struct {
12608c0984e5SSebastian Reichel 		char *name;
12618c0984e5SSebastian Reichel 		bool optional;
12628c0984e5SSebastian Reichel 		enum bq25890_table_ids tbl_id;
12638c0984e5SSebastian Reichel 		u8 *conv_data; /* holds converted value from given property */
12648c0984e5SSebastian Reichel 	} props[] = {
12658c0984e5SSebastian Reichel 		/* required properties */
12668c0984e5SSebastian Reichel 		{"ti,charge-current", false, TBL_ICHG, &init->ichg},
12678c0984e5SSebastian Reichel 		{"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg},
12688c0984e5SSebastian Reichel 		{"ti,termination-current", false, TBL_ITERM, &init->iterm},
12698c0984e5SSebastian Reichel 		{"ti,precharge-current", false, TBL_ITERM, &init->iprechg},
12708c0984e5SSebastian Reichel 		{"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin},
12718c0984e5SSebastian Reichel 		{"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv},
12728c0984e5SSebastian Reichel 		{"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti},
12738c0984e5SSebastian Reichel 
12748c0984e5SSebastian Reichel 		/* optional properties */
127572408329SMichał Mirosław 		{"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg},
127672408329SMichał Mirosław 		{"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp},
127772408329SMichał Mirosław 		{"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp},
12788c0984e5SSebastian Reichel 	};
12798c0984e5SSebastian Reichel 
12808c0984e5SSebastian Reichel 	/* initialize data for optional properties */
12818c0984e5SSebastian Reichel 	init->treg = 3; /* 120 degrees Celsius */
128272408329SMichał Mirosław 	init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */
12838c0984e5SSebastian Reichel 
12848c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(props); i++) {
12858c0984e5SSebastian Reichel 		ret = device_property_read_u32(bq->dev, props[i].name,
12868c0984e5SSebastian Reichel 					       &property);
12878c0984e5SSebastian Reichel 		if (ret < 0) {
12888c0984e5SSebastian Reichel 			if (props[i].optional)
12898c0984e5SSebastian Reichel 				continue;
12908c0984e5SSebastian Reichel 
12919d9ae341SAngus Ainslie (Purism) 			dev_err(bq->dev, "Unable to read property %d %s\n", ret,
12929d9ae341SAngus Ainslie (Purism) 				props[i].name);
12939d9ae341SAngus Ainslie (Purism) 
12948c0984e5SSebastian Reichel 			return ret;
12958c0984e5SSebastian Reichel 		}
12968c0984e5SSebastian Reichel 
12978c0984e5SSebastian Reichel 		*props[i].conv_data = bq25890_find_idx(property,
12988c0984e5SSebastian Reichel 						       props[i].tbl_id);
12998c0984e5SSebastian Reichel 	}
13008c0984e5SSebastian Reichel 
13018c0984e5SSebastian Reichel 	return 0;
13028c0984e5SSebastian Reichel }
13038c0984e5SSebastian Reichel 
13048c0984e5SSebastian Reichel static int bq25890_fw_probe(struct bq25890_device *bq)
13058c0984e5SSebastian Reichel {
13068c0984e5SSebastian Reichel 	int ret;
13078c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
13088c0984e5SSebastian Reichel 
130948f45b09SYauhen Kharuzhy 	/* Optional, left at 0 if property is not present */
131048f45b09SYauhen Kharuzhy 	device_property_read_u32(bq->dev, "linux,pump-express-vbus-max",
131148f45b09SYauhen Kharuzhy 				 &bq->pump_express_vbus_max);
131248f45b09SYauhen Kharuzhy 
13137e3b8e35SHans de Goede 	bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset");
131440428bd4SHans de Goede 	bq->read_back_init_data = device_property_read_bool(bq->dev,
131540428bd4SHans de Goede 						"linux,read-back-settings");
131640428bd4SHans de Goede 	if (bq->read_back_init_data)
131740428bd4SHans de Goede 		return 0;
13187e3b8e35SHans de Goede 
13198c0984e5SSebastian Reichel 	ret = bq25890_fw_read_u32_props(bq);
13208c0984e5SSebastian Reichel 	if (ret < 0)
13218c0984e5SSebastian Reichel 		return ret;
13228c0984e5SSebastian Reichel 
13238c0984e5SSebastian Reichel 	init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin");
13248c0984e5SSebastian Reichel 	init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq");
13258c0984e5SSebastian Reichel 
13268c0984e5SSebastian Reichel 	return 0;
13278c0984e5SSebastian Reichel }
13288c0984e5SSebastian Reichel 
1329a7aaa800SHans de Goede static void bq25890_non_devm_cleanup(void *data)
1330a7aaa800SHans de Goede {
1331a7aaa800SHans de Goede 	struct bq25890_device *bq = data;
1332a7aaa800SHans de Goede 
1333a7aaa800SHans de Goede 	cancel_delayed_work_sync(&bq->pump_express_work);
1334a7aaa800SHans de Goede }
1335a7aaa800SHans de Goede 
1336c5cddca2SUwe Kleine-König static int bq25890_probe(struct i2c_client *client)
13378c0984e5SSebastian Reichel {
13388c0984e5SSebastian Reichel 	struct device *dev = &client->dev;
13398c0984e5SSebastian Reichel 	struct bq25890_device *bq;
13408c0984e5SSebastian Reichel 	int ret;
13418c0984e5SSebastian Reichel 
13428c0984e5SSebastian Reichel 	bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL);
13438c0984e5SSebastian Reichel 	if (!bq)
13448c0984e5SSebastian Reichel 		return -ENOMEM;
13458c0984e5SSebastian Reichel 
13468c0984e5SSebastian Reichel 	bq->client = client;
13478c0984e5SSebastian Reichel 	bq->dev = dev;
13488c0984e5SSebastian Reichel 
13498c0984e5SSebastian Reichel 	mutex_init(&bq->lock);
135048f45b09SYauhen Kharuzhy 	INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work);
13518c0984e5SSebastian Reichel 
13528c0984e5SSebastian Reichel 	bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config);
1353172d0cceSMartin Kepplinger 	if (IS_ERR(bq->rmap))
1354172d0cceSMartin Kepplinger 		return dev_err_probe(dev, PTR_ERR(bq->rmap),
1355172d0cceSMartin Kepplinger 				     "failed to allocate register map\n");
13568c0984e5SSebastian Reichel 
1357c1ae3a4eSHans de Goede 	ret = devm_regmap_field_bulk_alloc(dev, bq->rmap, bq->rmap_fields,
1358c1ae3a4eSHans de Goede 					   bq25890_reg_fields, F_MAX_FIELDS);
1359c1ae3a4eSHans de Goede 	if (ret)
1360c1ae3a4eSHans de Goede 		return ret;
13618c0984e5SSebastian Reichel 
13628c0984e5SSebastian Reichel 	i2c_set_clientdata(client, bq);
13638c0984e5SSebastian Reichel 
1364d20267c9SYauhen Kharuzhy 	ret = bq25890_get_chip_version(bq);
1365d20267c9SYauhen Kharuzhy 	if (ret) {
1366172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret);
1367d20267c9SYauhen Kharuzhy 		return ret;
13688c0984e5SSebastian Reichel 	}
13698c0984e5SSebastian Reichel 
13708c0984e5SSebastian Reichel 	ret = bq25890_fw_probe(bq);
1371f481d5b8SHans de Goede 	if (ret < 0)
1372f481d5b8SHans de Goede 		return dev_err_probe(dev, ret, "reading device properties\n");
13738c0984e5SSebastian Reichel 
13748c0984e5SSebastian Reichel 	ret = bq25890_hw_init(bq);
13758c0984e5SSebastian Reichel 	if (ret < 0) {
1376172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot initialize the chip: %d\n", ret);
13778c0984e5SSebastian Reichel 		return ret;
13788c0984e5SSebastian Reichel 	}
13798c0984e5SSebastian Reichel 
13808c0984e5SSebastian Reichel 	if (client->irq <= 0)
13818c0984e5SSebastian Reichel 		client->irq = bq25890_irq_probe(bq);
13828c0984e5SSebastian Reichel 
13838c0984e5SSebastian Reichel 	if (client->irq < 0) {
13848c0984e5SSebastian Reichel 		dev_err(dev, "No irq resource found.\n");
13858c0984e5SSebastian Reichel 		return client->irq;
13868c0984e5SSebastian Reichel 	}
13878c0984e5SSebastian Reichel 
13888c0984e5SSebastian Reichel 	/* OTG reporting */
13898c0984e5SSebastian Reichel 	bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
13905f5c10ecSMarek Vasut 
1391a7aaa800SHans de Goede 	/*
1392a7aaa800SHans de Goede 	 * This must be before bq25890_power_supply_init(), so that it runs
1393a7aaa800SHans de Goede 	 * after devm unregisters the power_supply.
1394a7aaa800SHans de Goede 	 */
1395a7aaa800SHans de Goede 	ret = devm_add_action_or_reset(dev, bq25890_non_devm_cleanup, bq);
1396a7aaa800SHans de Goede 	if (ret)
1397a7aaa800SHans de Goede 		return ret;
1398a7aaa800SHans de Goede 
13995f5c10ecSMarek Vasut 	ret = bq25890_register_regulator(bq);
14005f5c10ecSMarek Vasut 	if (ret)
14015f5c10ecSMarek Vasut 		return ret;
14025f5c10ecSMarek Vasut 
1403d01363daSHans de Goede 	ret = bq25890_power_supply_init(bq);
14047e6fb678SHans de Goede 	if (ret < 0)
14057e6fb678SHans de Goede 		return dev_err_probe(dev, ret, "registering power supply\n");
1406d01363daSHans de Goede 
14078c0984e5SSebastian Reichel 	ret = devm_request_threaded_irq(dev, client->irq, NULL,
14088c0984e5SSebastian Reichel 					bq25890_irq_handler_thread,
14098c0984e5SSebastian Reichel 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
14108c0984e5SSebastian Reichel 					BQ25890_IRQ_PIN, bq);
14118c0984e5SSebastian Reichel 	if (ret)
14127e6fb678SHans de Goede 		return ret;
14137e6fb678SHans de Goede 
14147e6fb678SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
14157e6fb678SHans de Goede 		INIT_WORK(&bq->usb_work, bq25890_usb_work);
14167e6fb678SHans de Goede 		bq->usb_nb.notifier_call = bq25890_usb_notifier;
14177e6fb678SHans de Goede 		usb_register_notifier(bq->usb_phy, &bq->usb_nb);
14187e6fb678SHans de Goede 	}
14198c0984e5SSebastian Reichel 
14208c0984e5SSebastian Reichel 	return 0;
14218c0984e5SSebastian Reichel }
14228c0984e5SSebastian Reichel 
1423ed5c2f5fSUwe Kleine-König static void bq25890_remove(struct i2c_client *client)
14248c0984e5SSebastian Reichel {
14258c0984e5SSebastian Reichel 	struct bq25890_device *bq = i2c_get_clientdata(client);
14268c0984e5SSebastian Reichel 
14277e6fb678SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
14288c0984e5SSebastian Reichel 		usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
14297e6fb678SHans de Goede 		cancel_work_sync(&bq->usb_work);
14307e6fb678SHans de Goede 	}
14318c0984e5SSebastian Reichel 
14327e3b8e35SHans de Goede 	if (!bq->skip_reset) {
14338c0984e5SSebastian Reichel 		/* reset all registers to default values */
14348c0984e5SSebastian Reichel 		bq25890_chip_reset(bq);
14357e3b8e35SHans de Goede 	}
14368c0984e5SSebastian Reichel }
14378c0984e5SSebastian Reichel 
143879d35365SHans de Goede static void bq25890_shutdown(struct i2c_client *client)
143979d35365SHans de Goede {
144079d35365SHans de Goede 	struct bq25890_device *bq = i2c_get_clientdata(client);
144179d35365SHans de Goede 
144279d35365SHans de Goede 	/*
144379d35365SHans de Goede 	 * TODO this if + return should probably be removed, but that would
144479d35365SHans de Goede 	 * introduce a function change for boards using the usb-phy framework.
144579d35365SHans de Goede 	 * This needs to be tested on such a board before making this change.
144679d35365SHans de Goede 	 */
144779d35365SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy))
144879d35365SHans de Goede 		return;
144979d35365SHans de Goede 
145079d35365SHans de Goede 	/*
145179d35365SHans de Goede 	 * Turn off the 5v Boost regulator which outputs Vbus to the device's
145279d35365SHans de Goede 	 * Micro-USB or Type-C USB port. Leaving this on drains power and
145379d35365SHans de Goede 	 * this avoids the PMIC on some device-models seeing this as Vbus
145479d35365SHans de Goede 	 * getting inserted after shutdown, causing the device to immediately
145579d35365SHans de Goede 	 * power-up again.
145679d35365SHans de Goede 	 */
145779d35365SHans de Goede 	bq25890_set_otg_cfg(bq, 0);
145879d35365SHans de Goede }
145979d35365SHans de Goede 
14608c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
14618c0984e5SSebastian Reichel static int bq25890_suspend(struct device *dev)
14628c0984e5SSebastian Reichel {
14638c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
14648c0984e5SSebastian Reichel 
14658c0984e5SSebastian Reichel 	/*
14668c0984e5SSebastian Reichel 	 * If charger is removed, while in suspend, make sure ADC is diabled
14678c0984e5SSebastian Reichel 	 * since it consumes slightly more power.
14688c0984e5SSebastian Reichel 	 */
146921d90edaSMichał Mirosław 	return bq25890_field_write(bq, F_CONV_RATE, 0);
14708c0984e5SSebastian Reichel }
14718c0984e5SSebastian Reichel 
14728c0984e5SSebastian Reichel static int bq25890_resume(struct device *dev)
14738c0984e5SSebastian Reichel {
14748c0984e5SSebastian Reichel 	int ret;
14758c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
14768c0984e5SSebastian Reichel 
147772d9cd9cSMichał Mirosław 	mutex_lock(&bq->lock);
147872d9cd9cSMichał Mirosław 
147972d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &bq->state);
14808c0984e5SSebastian Reichel 	if (ret < 0)
1481cf5701bfSDan Carpenter 		goto unlock;
14828c0984e5SSebastian Reichel 
14838c0984e5SSebastian Reichel 	/* Re-enable ADC only if charger is plugged in. */
148472d9cd9cSMichał Mirosław 	if (bq->state.online) {
148521d90edaSMichał Mirosław 		ret = bq25890_field_write(bq, F_CONV_RATE, 1);
14868c0984e5SSebastian Reichel 		if (ret < 0)
1487cf5701bfSDan Carpenter 			goto unlock;
14888c0984e5SSebastian Reichel 	}
14898c0984e5SSebastian Reichel 
14908c0984e5SSebastian Reichel 	/* signal userspace, maybe state changed while suspended */
14918c0984e5SSebastian Reichel 	power_supply_changed(bq->charger);
14928c0984e5SSebastian Reichel 
1493cf5701bfSDan Carpenter unlock:
149472d9cd9cSMichał Mirosław 	mutex_unlock(&bq->lock);
149572d9cd9cSMichał Mirosław 
1496cf5701bfSDan Carpenter 	return ret;
14978c0984e5SSebastian Reichel }
14988c0984e5SSebastian Reichel #endif
14998c0984e5SSebastian Reichel 
15008c0984e5SSebastian Reichel static const struct dev_pm_ops bq25890_pm = {
15018c0984e5SSebastian Reichel 	SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume)
15028c0984e5SSebastian Reichel };
15038c0984e5SSebastian Reichel 
15048c0984e5SSebastian Reichel static const struct i2c_device_id bq25890_i2c_ids[] = {
15058c0984e5SSebastian Reichel 	{ "bq25890", 0 },
150646aa27e7SYauhen Kharuzhy 	{ "bq25892", 0 },
150746aa27e7SYauhen Kharuzhy 	{ "bq25895", 0 },
150846aa27e7SYauhen Kharuzhy 	{ "bq25896", 0 },
15098c0984e5SSebastian Reichel 	{},
15108c0984e5SSebastian Reichel };
15118c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids);
15128c0984e5SSebastian Reichel 
15138c0984e5SSebastian Reichel static const struct of_device_id bq25890_of_match[] = {
15148c0984e5SSebastian Reichel 	{ .compatible = "ti,bq25890", },
151546aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25892", },
151646aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25895", },
151746aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25896", },
15188c0984e5SSebastian Reichel 	{ },
15198c0984e5SSebastian Reichel };
15208c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, bq25890_of_match);
15218c0984e5SSebastian Reichel 
152202067dc9SKrzysztof Kozlowski #ifdef CONFIG_ACPI
15238c0984e5SSebastian Reichel static const struct acpi_device_id bq25890_acpi_match[] = {
15248c0984e5SSebastian Reichel 	{"BQ258900", 0},
15258c0984e5SSebastian Reichel 	{},
15268c0984e5SSebastian Reichel };
15278c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match);
152802067dc9SKrzysztof Kozlowski #endif
15298c0984e5SSebastian Reichel 
15308c0984e5SSebastian Reichel static struct i2c_driver bq25890_driver = {
15318c0984e5SSebastian Reichel 	.driver = {
15328c0984e5SSebastian Reichel 		.name = "bq25890-charger",
15338c0984e5SSebastian Reichel 		.of_match_table = of_match_ptr(bq25890_of_match),
15348c0984e5SSebastian Reichel 		.acpi_match_table = ACPI_PTR(bq25890_acpi_match),
15358c0984e5SSebastian Reichel 		.pm = &bq25890_pm,
15368c0984e5SSebastian Reichel 	},
1537c5cddca2SUwe Kleine-König 	.probe_new = bq25890_probe,
15388c0984e5SSebastian Reichel 	.remove = bq25890_remove,
153979d35365SHans de Goede 	.shutdown = bq25890_shutdown,
15408c0984e5SSebastian Reichel 	.id_table = bq25890_i2c_ids,
15418c0984e5SSebastian Reichel };
15428c0984e5SSebastian Reichel module_i2c_driver(bq25890_driver);
15438c0984e5SSebastian Reichel 
15448c0984e5SSebastian Reichel MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
15458c0984e5SSebastian Reichel MODULE_DESCRIPTION("bq25890 charger driver");
15468c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
1547