xref: /openbmc/linux/drivers/power/supply/bq25890_charger.c (revision eab25b4f93aa771728127705eb4b235a3b5aad94)
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 
30d20267c9SYauhen Kharuzhy enum bq25890_chip_version {
31d20267c9SYauhen Kharuzhy 	BQ25890,
32d20267c9SYauhen Kharuzhy 	BQ25892,
33d20267c9SYauhen Kharuzhy 	BQ25895,
34d20267c9SYauhen Kharuzhy 	BQ25896,
35d20267c9SYauhen Kharuzhy };
36d20267c9SYauhen Kharuzhy 
375956fca7SMichał Mirosław static const char *const bq25890_chip_name[] = {
385956fca7SMichał Mirosław 	"BQ25890",
395956fca7SMichał Mirosław 	"BQ25892",
405956fca7SMichał Mirosław 	"BQ25895",
415956fca7SMichał Mirosław 	"BQ25896",
425956fca7SMichał Mirosław };
435956fca7SMichał Mirosław 
448c0984e5SSebastian Reichel enum bq25890_fields {
45766873c1SYauhen Kharuzhy 	F_EN_HIZ, F_EN_ILIM, F_IINLIM,				     /* Reg00 */
468c0984e5SSebastian Reichel 	F_BHOT, F_BCOLD, F_VINDPM_OFS,				     /* Reg01 */
478c0984e5SSebastian Reichel 	F_CONV_START, F_CONV_RATE, F_BOOSTF, F_ICO_EN,
488c0984e5SSebastian Reichel 	F_HVDCP_EN, F_MAXC_EN, F_FORCE_DPM, F_AUTO_DPDM_EN,	     /* Reg02 */
49d20267c9SYauhen Kharuzhy 	F_BAT_LOAD_EN, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_SYSVMIN,
50d20267c9SYauhen Kharuzhy 	F_MIN_VBAT_SEL,						     /* Reg03 */
518c0984e5SSebastian Reichel 	F_PUMPX_EN, F_ICHG,					     /* Reg04 */
528c0984e5SSebastian Reichel 	F_IPRECHG, F_ITERM,					     /* Reg05 */
538c0984e5SSebastian Reichel 	F_VREG, F_BATLOWV, F_VRECHG,				     /* Reg06 */
548c0984e5SSebastian Reichel 	F_TERM_EN, F_STAT_DIS, F_WD, F_TMR_EN, F_CHG_TMR,
558c0984e5SSebastian Reichel 	F_JEITA_ISET,						     /* Reg07 */
568c0984e5SSebastian Reichel 	F_BATCMP, F_VCLAMP, F_TREG,				     /* Reg08 */
578c0984e5SSebastian Reichel 	F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JEITA_VSET,
588c0984e5SSebastian Reichel 	F_BATFET_DLY, F_BATFET_RST_EN, F_PUMPX_UP, F_PUMPX_DN,	     /* Reg09 */
59d20267c9SYauhen Kharuzhy 	F_BOOSTV, F_PFM_OTG_DIS, F_BOOSTI,			     /* Reg0A */
60d20267c9SYauhen Kharuzhy 	F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_SDP_STAT, F_0B_RSVD,
61d20267c9SYauhen Kharuzhy 	F_VSYS_STAT,						     /* Reg0B */
628c0984e5SSebastian Reichel 	F_WD_FAULT, F_BOOST_FAULT, F_CHG_FAULT, F_BAT_FAULT,
638c0984e5SSebastian Reichel 	F_NTC_FAULT,						     /* Reg0C */
648c0984e5SSebastian Reichel 	F_FORCE_VINDPM, F_VINDPM,				     /* Reg0D */
658c0984e5SSebastian Reichel 	F_THERM_STAT, F_BATV,					     /* Reg0E */
668c0984e5SSebastian Reichel 	F_SYSV,							     /* Reg0F */
678c0984e5SSebastian Reichel 	F_TSPCT,						     /* Reg10 */
688c0984e5SSebastian Reichel 	F_VBUS_GD, F_VBUSV,					     /* Reg11 */
698c0984e5SSebastian Reichel 	F_ICHGR,						     /* Reg12 */
708c0984e5SSebastian Reichel 	F_VDPM_STAT, F_IDPM_STAT, F_IDPM_LIM,			     /* Reg13 */
718c0984e5SSebastian Reichel 	F_REG_RST, F_ICO_OPTIMIZED, F_PN, F_TS_PROFILE, F_DEV_REV,   /* Reg14 */
728c0984e5SSebastian Reichel 
738c0984e5SSebastian Reichel 	F_MAX_FIELDS
748c0984e5SSebastian Reichel };
758c0984e5SSebastian Reichel 
768c0984e5SSebastian Reichel /* initial field values, converted to register values */
778c0984e5SSebastian Reichel struct bq25890_init_data {
788c0984e5SSebastian Reichel 	u8 ichg;	/* charge current		*/
798c0984e5SSebastian Reichel 	u8 vreg;	/* regulation voltage		*/
808c0984e5SSebastian Reichel 	u8 iterm;	/* termination current		*/
818c0984e5SSebastian Reichel 	u8 iprechg;	/* precharge current		*/
828c0984e5SSebastian Reichel 	u8 sysvmin;	/* minimum system voltage limit */
838c0984e5SSebastian Reichel 	u8 boostv;	/* boost regulation voltage	*/
848c0984e5SSebastian Reichel 	u8 boosti;	/* boost current limit		*/
858c0984e5SSebastian Reichel 	u8 boostf;	/* boost frequency		*/
868c0984e5SSebastian Reichel 	u8 ilim_en;	/* enable ILIM pin		*/
878c0984e5SSebastian Reichel 	u8 treg;	/* thermal regulation threshold */
8872408329SMichał Mirosław 	u8 rbatcomp;	/* IBAT sense resistor value    */
8972408329SMichał Mirosław 	u8 vclamp;	/* IBAT compensation voltage limit */
908c0984e5SSebastian Reichel };
918c0984e5SSebastian Reichel 
928c0984e5SSebastian Reichel struct bq25890_state {
938c0984e5SSebastian Reichel 	u8 online;
948c0984e5SSebastian Reichel 	u8 chrg_status;
958c0984e5SSebastian Reichel 	u8 chrg_fault;
968c0984e5SSebastian Reichel 	u8 vsys_status;
978c0984e5SSebastian Reichel 	u8 boost_fault;
988c0984e5SSebastian Reichel 	u8 bat_fault;
99c562a43aSYauhen Kharuzhy 	u8 ntc_fault;
1008c0984e5SSebastian Reichel };
1018c0984e5SSebastian Reichel 
1028c0984e5SSebastian Reichel struct bq25890_device {
1038c0984e5SSebastian Reichel 	struct i2c_client *client;
1048c0984e5SSebastian Reichel 	struct device *dev;
1058c0984e5SSebastian Reichel 	struct power_supply *charger;
1068c0984e5SSebastian Reichel 
1078c0984e5SSebastian Reichel 	struct usb_phy *usb_phy;
1088c0984e5SSebastian Reichel 	struct notifier_block usb_nb;
1098c0984e5SSebastian Reichel 	struct work_struct usb_work;
1108c0984e5SSebastian Reichel 	unsigned long usb_event;
1118c0984e5SSebastian Reichel 
1128c0984e5SSebastian Reichel 	struct regmap *rmap;
1138c0984e5SSebastian Reichel 	struct regmap_field *rmap_fields[F_MAX_FIELDS];
1148c0984e5SSebastian Reichel 
1157e3b8e35SHans de Goede 	bool skip_reset;
11640428bd4SHans de Goede 	bool read_back_init_data;
117d20267c9SYauhen Kharuzhy 	enum bq25890_chip_version chip_version;
1188c0984e5SSebastian Reichel 	struct bq25890_init_data init_data;
1198c0984e5SSebastian Reichel 	struct bq25890_state state;
1208c0984e5SSebastian Reichel 
1218c0984e5SSebastian Reichel 	struct mutex lock; /* protect state data */
1228c0984e5SSebastian Reichel };
1238c0984e5SSebastian Reichel 
1248c0984e5SSebastian Reichel static const struct regmap_range bq25890_readonly_reg_ranges[] = {
1258c0984e5SSebastian Reichel 	regmap_reg_range(0x0b, 0x0c),
1268c0984e5SSebastian Reichel 	regmap_reg_range(0x0e, 0x13),
1278c0984e5SSebastian Reichel };
1288c0984e5SSebastian Reichel 
1298c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_writeable_regs = {
1308c0984e5SSebastian Reichel 	.no_ranges = bq25890_readonly_reg_ranges,
1318c0984e5SSebastian Reichel 	.n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges),
1328c0984e5SSebastian Reichel };
1338c0984e5SSebastian Reichel 
1348c0984e5SSebastian Reichel static const struct regmap_range bq25890_volatile_reg_ranges[] = {
1358c0984e5SSebastian Reichel 	regmap_reg_range(0x00, 0x00),
13621d90edaSMichał Mirosław 	regmap_reg_range(0x02, 0x02),
1378c0984e5SSebastian Reichel 	regmap_reg_range(0x09, 0x09),
138d20267c9SYauhen Kharuzhy 	regmap_reg_range(0x0b, 0x14),
1398c0984e5SSebastian Reichel };
1408c0984e5SSebastian Reichel 
1418c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_volatile_regs = {
1428c0984e5SSebastian Reichel 	.yes_ranges = bq25890_volatile_reg_ranges,
1438c0984e5SSebastian Reichel 	.n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges),
1448c0984e5SSebastian Reichel };
1458c0984e5SSebastian Reichel 
1468c0984e5SSebastian Reichel static const struct regmap_config bq25890_regmap_config = {
1478c0984e5SSebastian Reichel 	.reg_bits = 8,
1488c0984e5SSebastian Reichel 	.val_bits = 8,
1498c0984e5SSebastian Reichel 
1508c0984e5SSebastian Reichel 	.max_register = 0x14,
1518c0984e5SSebastian Reichel 	.cache_type = REGCACHE_RBTREE,
1528c0984e5SSebastian Reichel 
1538c0984e5SSebastian Reichel 	.wr_table = &bq25890_writeable_regs,
1548c0984e5SSebastian Reichel 	.volatile_table = &bq25890_volatile_regs,
1558c0984e5SSebastian Reichel };
1568c0984e5SSebastian Reichel 
1578c0984e5SSebastian Reichel static const struct reg_field bq25890_reg_fields[] = {
1588c0984e5SSebastian Reichel 	/* REG00 */
1598c0984e5SSebastian Reichel 	[F_EN_HIZ]		= REG_FIELD(0x00, 7, 7),
1608c0984e5SSebastian Reichel 	[F_EN_ILIM]		= REG_FIELD(0x00, 6, 6),
161766873c1SYauhen Kharuzhy 	[F_IINLIM]		= REG_FIELD(0x00, 0, 5),
1628c0984e5SSebastian Reichel 	/* REG01 */
1638c0984e5SSebastian Reichel 	[F_BHOT]		= REG_FIELD(0x01, 6, 7),
1648c0984e5SSebastian Reichel 	[F_BCOLD]		= REG_FIELD(0x01, 5, 5),
1658c0984e5SSebastian Reichel 	[F_VINDPM_OFS]		= REG_FIELD(0x01, 0, 4),
1668c0984e5SSebastian Reichel 	/* REG02 */
1678c0984e5SSebastian Reichel 	[F_CONV_START]		= REG_FIELD(0x02, 7, 7),
1688c0984e5SSebastian Reichel 	[F_CONV_RATE]		= REG_FIELD(0x02, 6, 6),
1698c0984e5SSebastian Reichel 	[F_BOOSTF]		= REG_FIELD(0x02, 5, 5),
1708c0984e5SSebastian Reichel 	[F_ICO_EN]		= REG_FIELD(0x02, 4, 4),
1712e1a2ddeSAngus Ainslie (Purism) 	[F_HVDCP_EN]		= REG_FIELD(0x02, 3, 3),  // reserved on BQ25896
1722e1a2ddeSAngus Ainslie (Purism) 	[F_MAXC_EN]		= REG_FIELD(0x02, 2, 2),  // reserved on BQ25896
1738c0984e5SSebastian Reichel 	[F_FORCE_DPM]		= REG_FIELD(0x02, 1, 1),
1748c0984e5SSebastian Reichel 	[F_AUTO_DPDM_EN]	= REG_FIELD(0x02, 0, 0),
1758c0984e5SSebastian Reichel 	/* REG03 */
1768c0984e5SSebastian Reichel 	[F_BAT_LOAD_EN]		= REG_FIELD(0x03, 7, 7),
1778c0984e5SSebastian Reichel 	[F_WD_RST]		= REG_FIELD(0x03, 6, 6),
1788c0984e5SSebastian Reichel 	[F_OTG_CFG]		= REG_FIELD(0x03, 5, 5),
1798c0984e5SSebastian Reichel 	[F_CHG_CFG]		= REG_FIELD(0x03, 4, 4),
1808c0984e5SSebastian Reichel 	[F_SYSVMIN]		= REG_FIELD(0x03, 1, 3),
181d20267c9SYauhen Kharuzhy 	[F_MIN_VBAT_SEL]	= REG_FIELD(0x03, 0, 0), // BQ25896 only
1828c0984e5SSebastian Reichel 	/* REG04 */
1838c0984e5SSebastian Reichel 	[F_PUMPX_EN]		= REG_FIELD(0x04, 7, 7),
1848c0984e5SSebastian Reichel 	[F_ICHG]		= REG_FIELD(0x04, 0, 6),
1858c0984e5SSebastian Reichel 	/* REG05 */
1868c0984e5SSebastian Reichel 	[F_IPRECHG]		= REG_FIELD(0x05, 4, 7),
1878c0984e5SSebastian Reichel 	[F_ITERM]		= REG_FIELD(0x05, 0, 3),
1888c0984e5SSebastian Reichel 	/* REG06 */
1898c0984e5SSebastian Reichel 	[F_VREG]		= REG_FIELD(0x06, 2, 7),
1908c0984e5SSebastian Reichel 	[F_BATLOWV]		= REG_FIELD(0x06, 1, 1),
1918c0984e5SSebastian Reichel 	[F_VRECHG]		= REG_FIELD(0x06, 0, 0),
1928c0984e5SSebastian Reichel 	/* REG07 */
1938c0984e5SSebastian Reichel 	[F_TERM_EN]		= REG_FIELD(0x07, 7, 7),
1948c0984e5SSebastian Reichel 	[F_STAT_DIS]		= REG_FIELD(0x07, 6, 6),
1958c0984e5SSebastian Reichel 	[F_WD]			= REG_FIELD(0x07, 4, 5),
1968c0984e5SSebastian Reichel 	[F_TMR_EN]		= REG_FIELD(0x07, 3, 3),
1978c0984e5SSebastian Reichel 	[F_CHG_TMR]		= REG_FIELD(0x07, 1, 2),
1985c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_ISET]		= REG_FIELD(0x07, 0, 0), // reserved on BQ25895
1998c0984e5SSebastian Reichel 	/* REG08 */
20095809139SMichał Mirosław 	[F_BATCMP]		= REG_FIELD(0x08, 5, 7),
2018c0984e5SSebastian Reichel 	[F_VCLAMP]		= REG_FIELD(0x08, 2, 4),
2028c0984e5SSebastian Reichel 	[F_TREG]		= REG_FIELD(0x08, 0, 1),
2038c0984e5SSebastian Reichel 	/* REG09 */
2048c0984e5SSebastian Reichel 	[F_FORCE_ICO]		= REG_FIELD(0x09, 7, 7),
2058c0984e5SSebastian Reichel 	[F_TMR2X_EN]		= REG_FIELD(0x09, 6, 6),
2068c0984e5SSebastian Reichel 	[F_BATFET_DIS]		= REG_FIELD(0x09, 5, 5),
2075c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_VSET]		= REG_FIELD(0x09, 4, 4), // reserved on BQ25895
2088c0984e5SSebastian Reichel 	[F_BATFET_DLY]		= REG_FIELD(0x09, 3, 3),
2098c0984e5SSebastian Reichel 	[F_BATFET_RST_EN]	= REG_FIELD(0x09, 2, 2),
2108c0984e5SSebastian Reichel 	[F_PUMPX_UP]		= REG_FIELD(0x09, 1, 1),
2118c0984e5SSebastian Reichel 	[F_PUMPX_DN]		= REG_FIELD(0x09, 0, 0),
2128c0984e5SSebastian Reichel 	/* REG0A */
2138c0984e5SSebastian Reichel 	[F_BOOSTV]		= REG_FIELD(0x0A, 4, 7),
2145c35ba9bSAngus Ainslie (Purism) 	[F_BOOSTI]		= REG_FIELD(0x0A, 0, 2), // reserved on BQ25895
215d20267c9SYauhen Kharuzhy 	[F_PFM_OTG_DIS]		= REG_FIELD(0x0A, 3, 3), // BQ25896 only
2168c0984e5SSebastian Reichel 	/* REG0B */
2178c0984e5SSebastian Reichel 	[F_VBUS_STAT]		= REG_FIELD(0x0B, 5, 7),
2188c0984e5SSebastian Reichel 	[F_CHG_STAT]		= REG_FIELD(0x0B, 3, 4),
2198c0984e5SSebastian Reichel 	[F_PG_STAT]		= REG_FIELD(0x0B, 2, 2),
2202e1a2ddeSAngus Ainslie (Purism) 	[F_SDP_STAT]		= REG_FIELD(0x0B, 1, 1), // reserved on BQ25896
2218c0984e5SSebastian Reichel 	[F_VSYS_STAT]		= REG_FIELD(0x0B, 0, 0),
2228c0984e5SSebastian Reichel 	/* REG0C */
2238c0984e5SSebastian Reichel 	[F_WD_FAULT]		= REG_FIELD(0x0C, 7, 7),
2248c0984e5SSebastian Reichel 	[F_BOOST_FAULT]		= REG_FIELD(0x0C, 6, 6),
2258c0984e5SSebastian Reichel 	[F_CHG_FAULT]		= REG_FIELD(0x0C, 4, 5),
2268c0984e5SSebastian Reichel 	[F_BAT_FAULT]		= REG_FIELD(0x0C, 3, 3),
2278c0984e5SSebastian Reichel 	[F_NTC_FAULT]		= REG_FIELD(0x0C, 0, 2),
2288c0984e5SSebastian Reichel 	/* REG0D */
2298c0984e5SSebastian Reichel 	[F_FORCE_VINDPM]	= REG_FIELD(0x0D, 7, 7),
2308c0984e5SSebastian Reichel 	[F_VINDPM]		= REG_FIELD(0x0D, 0, 6),
2318c0984e5SSebastian Reichel 	/* REG0E */
2328c0984e5SSebastian Reichel 	[F_THERM_STAT]		= REG_FIELD(0x0E, 7, 7),
2338c0984e5SSebastian Reichel 	[F_BATV]		= REG_FIELD(0x0E, 0, 6),
2348c0984e5SSebastian Reichel 	/* REG0F */
2358c0984e5SSebastian Reichel 	[F_SYSV]		= REG_FIELD(0x0F, 0, 6),
2368c0984e5SSebastian Reichel 	/* REG10 */
2378c0984e5SSebastian Reichel 	[F_TSPCT]		= REG_FIELD(0x10, 0, 6),
2388c0984e5SSebastian Reichel 	/* REG11 */
2398c0984e5SSebastian Reichel 	[F_VBUS_GD]		= REG_FIELD(0x11, 7, 7),
2408c0984e5SSebastian Reichel 	[F_VBUSV]		= REG_FIELD(0x11, 0, 6),
2418c0984e5SSebastian Reichel 	/* REG12 */
2428c0984e5SSebastian Reichel 	[F_ICHGR]		= REG_FIELD(0x12, 0, 6),
2438c0984e5SSebastian Reichel 	/* REG13 */
2448c0984e5SSebastian Reichel 	[F_VDPM_STAT]		= REG_FIELD(0x13, 7, 7),
2458c0984e5SSebastian Reichel 	[F_IDPM_STAT]		= REG_FIELD(0x13, 6, 6),
2468c0984e5SSebastian Reichel 	[F_IDPM_LIM]		= REG_FIELD(0x13, 0, 5),
2478c0984e5SSebastian Reichel 	/* REG14 */
2488c0984e5SSebastian Reichel 	[F_REG_RST]		= REG_FIELD(0x14, 7, 7),
2498c0984e5SSebastian Reichel 	[F_ICO_OPTIMIZED]	= REG_FIELD(0x14, 6, 6),
2508c0984e5SSebastian Reichel 	[F_PN]			= REG_FIELD(0x14, 3, 5),
2518c0984e5SSebastian Reichel 	[F_TS_PROFILE]		= REG_FIELD(0x14, 2, 2),
2528c0984e5SSebastian Reichel 	[F_DEV_REV]		= REG_FIELD(0x14, 0, 1)
2538c0984e5SSebastian Reichel };
2548c0984e5SSebastian Reichel 
2558c0984e5SSebastian Reichel /*
2568c0984e5SSebastian Reichel  * Most of the val -> idx conversions can be computed, given the minimum,
2578c0984e5SSebastian Reichel  * maximum and the step between values. For the rest of conversions, we use
2588c0984e5SSebastian Reichel  * lookup tables.
2598c0984e5SSebastian Reichel  */
2608c0984e5SSebastian Reichel enum bq25890_table_ids {
2618c0984e5SSebastian Reichel 	/* range tables */
2628c0984e5SSebastian Reichel 	TBL_ICHG,
2638c0984e5SSebastian Reichel 	TBL_ITERM,
264766873c1SYauhen Kharuzhy 	TBL_IINLIM,
2658c0984e5SSebastian Reichel 	TBL_VREG,
2668c0984e5SSebastian Reichel 	TBL_BOOSTV,
2678c0984e5SSebastian Reichel 	TBL_SYSVMIN,
26872408329SMichał Mirosław 	TBL_VBATCOMP,
26972408329SMichał Mirosław 	TBL_RBATCOMP,
2708c0984e5SSebastian Reichel 
2718c0984e5SSebastian Reichel 	/* lookup tables */
2728c0984e5SSebastian Reichel 	TBL_TREG,
2738c0984e5SSebastian Reichel 	TBL_BOOSTI,
2749652c024SAngus Ainslie 	TBL_TSPCT,
2758c0984e5SSebastian Reichel };
2768c0984e5SSebastian Reichel 
2778c0984e5SSebastian Reichel /* Thermal Regulation Threshold lookup table, in degrees Celsius */
2788c0984e5SSebastian Reichel static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 };
2798c0984e5SSebastian Reichel 
2808c0984e5SSebastian Reichel #define BQ25890_TREG_TBL_SIZE		ARRAY_SIZE(bq25890_treg_tbl)
2818c0984e5SSebastian Reichel 
2828c0984e5SSebastian Reichel /* Boost mode current limit lookup table, in uA */
2838c0984e5SSebastian Reichel static const u32 bq25890_boosti_tbl[] = {
2848c0984e5SSebastian Reichel 	500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000
2858c0984e5SSebastian Reichel };
2868c0984e5SSebastian Reichel 
2878c0984e5SSebastian Reichel #define BQ25890_BOOSTI_TBL_SIZE		ARRAY_SIZE(bq25890_boosti_tbl)
2888c0984e5SSebastian Reichel 
2899652c024SAngus Ainslie /* NTC 10K temperature lookup table in tenths of a degree */
2909652c024SAngus Ainslie static const u32 bq25890_tspct_tbl[] = {
2919652c024SAngus Ainslie 	850, 840, 830, 820, 810, 800, 790, 780,
2929652c024SAngus Ainslie 	770, 760, 750, 740, 730, 720, 710, 700,
2939652c024SAngus Ainslie 	690, 685, 680, 675, 670, 660, 650, 645,
2949652c024SAngus Ainslie 	640, 630, 620, 615, 610, 600, 590, 585,
2959652c024SAngus Ainslie 	580, 570, 565, 560, 550, 540, 535, 530,
2969652c024SAngus Ainslie 	520, 515, 510, 500, 495, 490, 480, 475,
2979652c024SAngus Ainslie 	470, 460, 455, 450, 440, 435, 430, 425,
2989652c024SAngus Ainslie 	420, 410, 405, 400, 390, 385, 380, 370,
2999652c024SAngus Ainslie 	365, 360, 355, 350, 340, 335, 330, 320,
3009652c024SAngus Ainslie 	310, 305, 300, 290, 285, 280, 275, 270,
3019652c024SAngus Ainslie 	260, 250, 245, 240, 230, 225, 220, 210,
3029652c024SAngus Ainslie 	205, 200, 190, 180, 175, 170, 160, 150,
3039652c024SAngus Ainslie 	145, 140, 130, 120, 115, 110, 100, 90,
3049652c024SAngus Ainslie 	80, 70, 60, 50, 40, 30, 20, 10,
3059652c024SAngus Ainslie 	0, -10, -20, -30, -40, -60, -70, -80,
3069652c024SAngus Ainslie 	-90, -10, -120, -140, -150, -170, -190, -210,
3079652c024SAngus Ainslie };
3089652c024SAngus Ainslie 
3099652c024SAngus Ainslie #define BQ25890_TSPCT_TBL_SIZE		ARRAY_SIZE(bq25890_tspct_tbl)
3109652c024SAngus Ainslie 
3118c0984e5SSebastian Reichel struct bq25890_range {
3128c0984e5SSebastian Reichel 	u32 min;
3138c0984e5SSebastian Reichel 	u32 max;
3148c0984e5SSebastian Reichel 	u32 step;
3158c0984e5SSebastian Reichel };
3168c0984e5SSebastian Reichel 
3178c0984e5SSebastian Reichel struct bq25890_lookup {
3188c0984e5SSebastian Reichel 	const u32 *tbl;
3198c0984e5SSebastian Reichel 	u32 size;
3208c0984e5SSebastian Reichel };
3218c0984e5SSebastian Reichel 
3228c0984e5SSebastian Reichel static const union {
3238c0984e5SSebastian Reichel 	struct bq25890_range  rt;
3248c0984e5SSebastian Reichel 	struct bq25890_lookup lt;
3258c0984e5SSebastian Reichel } bq25890_tables[] = {
3268c0984e5SSebastian Reichel 	/* range tables */
327d20267c9SYauhen Kharuzhy 	/* TODO: BQ25896 has max ICHG 3008 mA */
3288c0984e5SSebastian Reichel 	[TBL_ICHG] =	{ .rt = {0,	  5056000, 64000} },	 /* uA */
3298c0984e5SSebastian Reichel 	[TBL_ITERM] =	{ .rt = {64000,   1024000, 64000} },	 /* uA */
330766873c1SYauhen Kharuzhy 	[TBL_IINLIM] =  { .rt = {100000,  3250000, 50000} },	 /* uA */
3318c0984e5SSebastian Reichel 	[TBL_VREG] =	{ .rt = {3840000, 4608000, 16000} },	 /* uV */
3328c0984e5SSebastian Reichel 	[TBL_BOOSTV] =	{ .rt = {4550000, 5510000, 64000} },	 /* uV */
3338c0984e5SSebastian Reichel 	[TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} },	 /* uV */
33472408329SMichał Mirosław 	[TBL_VBATCOMP] ={ .rt = {0,        224000, 32000} },	 /* uV */
33572408329SMichał Mirosław 	[TBL_RBATCOMP] ={ .rt = {0,        140000, 20000} },	 /* uOhm */
3368c0984e5SSebastian Reichel 
3378c0984e5SSebastian Reichel 	/* lookup tables */
3388c0984e5SSebastian Reichel 	[TBL_TREG] =	{ .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} },
3399652c024SAngus Ainslie 	[TBL_BOOSTI] =	{ .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} },
3409652c024SAngus Ainslie 	[TBL_TSPCT] =	{ .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} }
3418c0984e5SSebastian Reichel };
3428c0984e5SSebastian Reichel 
3438c0984e5SSebastian Reichel static int bq25890_field_read(struct bq25890_device *bq,
3448c0984e5SSebastian Reichel 			      enum bq25890_fields field_id)
3458c0984e5SSebastian Reichel {
3468c0984e5SSebastian Reichel 	int ret;
3478c0984e5SSebastian Reichel 	int val;
3488c0984e5SSebastian Reichel 
3498c0984e5SSebastian Reichel 	ret = regmap_field_read(bq->rmap_fields[field_id], &val);
3508c0984e5SSebastian Reichel 	if (ret < 0)
3518c0984e5SSebastian Reichel 		return ret;
3528c0984e5SSebastian Reichel 
3538c0984e5SSebastian Reichel 	return val;
3548c0984e5SSebastian Reichel }
3558c0984e5SSebastian Reichel 
3568c0984e5SSebastian Reichel static int bq25890_field_write(struct bq25890_device *bq,
3578c0984e5SSebastian Reichel 			       enum bq25890_fields field_id, u8 val)
3588c0984e5SSebastian Reichel {
3598c0984e5SSebastian Reichel 	return regmap_field_write(bq->rmap_fields[field_id], val);
3608c0984e5SSebastian Reichel }
3618c0984e5SSebastian Reichel 
3628c0984e5SSebastian Reichel static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id)
3638c0984e5SSebastian Reichel {
3648c0984e5SSebastian Reichel 	u8 idx;
3658c0984e5SSebastian Reichel 
3668c0984e5SSebastian Reichel 	if (id >= TBL_TREG) {
3678c0984e5SSebastian Reichel 		const u32 *tbl = bq25890_tables[id].lt.tbl;
3688c0984e5SSebastian Reichel 		u32 tbl_size = bq25890_tables[id].lt.size;
3698c0984e5SSebastian Reichel 
3708c0984e5SSebastian Reichel 		for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++)
3718c0984e5SSebastian Reichel 			;
3728c0984e5SSebastian Reichel 	} else {
3738c0984e5SSebastian Reichel 		const struct bq25890_range *rtbl = &bq25890_tables[id].rt;
3748c0984e5SSebastian Reichel 		u8 rtbl_size;
3758c0984e5SSebastian Reichel 
3768c0984e5SSebastian Reichel 		rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1;
3778c0984e5SSebastian Reichel 
3788c0984e5SSebastian Reichel 		for (idx = 1;
3798c0984e5SSebastian Reichel 		     idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value);
3808c0984e5SSebastian Reichel 		     idx++)
3818c0984e5SSebastian Reichel 			;
3828c0984e5SSebastian Reichel 	}
3838c0984e5SSebastian Reichel 
3848c0984e5SSebastian Reichel 	return idx - 1;
3858c0984e5SSebastian Reichel }
3868c0984e5SSebastian Reichel 
3878c0984e5SSebastian Reichel static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id)
3888c0984e5SSebastian Reichel {
3898c0984e5SSebastian Reichel 	const struct bq25890_range *rtbl;
3908c0984e5SSebastian Reichel 
3918c0984e5SSebastian Reichel 	/* lookup table? */
3928c0984e5SSebastian Reichel 	if (id >= TBL_TREG)
3938c0984e5SSebastian Reichel 		return bq25890_tables[id].lt.tbl[idx];
3948c0984e5SSebastian Reichel 
3958c0984e5SSebastian Reichel 	/* range table */
3968c0984e5SSebastian Reichel 	rtbl = &bq25890_tables[id].rt;
3978c0984e5SSebastian Reichel 
3988c0984e5SSebastian Reichel 	return (rtbl->min + idx * rtbl->step);
3998c0984e5SSebastian Reichel }
4008c0984e5SSebastian Reichel 
4018c0984e5SSebastian Reichel enum bq25890_status {
4028c0984e5SSebastian Reichel 	STATUS_NOT_CHARGING,
4038c0984e5SSebastian Reichel 	STATUS_PRE_CHARGING,
4048c0984e5SSebastian Reichel 	STATUS_FAST_CHARGING,
4058c0984e5SSebastian Reichel 	STATUS_TERMINATION_DONE,
4068c0984e5SSebastian Reichel };
4078c0984e5SSebastian Reichel 
4088c0984e5SSebastian Reichel enum bq25890_chrg_fault {
4098c0984e5SSebastian Reichel 	CHRG_FAULT_NORMAL,
4108c0984e5SSebastian Reichel 	CHRG_FAULT_INPUT,
4118c0984e5SSebastian Reichel 	CHRG_FAULT_THERMAL_SHUTDOWN,
4128c0984e5SSebastian Reichel 	CHRG_FAULT_TIMER_EXPIRED,
4138c0984e5SSebastian Reichel };
4148c0984e5SSebastian Reichel 
415c562a43aSYauhen Kharuzhy enum bq25890_ntc_fault {
416c562a43aSYauhen Kharuzhy 	NTC_FAULT_NORMAL = 0,
417c562a43aSYauhen Kharuzhy 	NTC_FAULT_WARM = 2,
418c562a43aSYauhen Kharuzhy 	NTC_FAULT_COOL = 3,
419c562a43aSYauhen Kharuzhy 	NTC_FAULT_COLD = 5,
420c562a43aSYauhen Kharuzhy 	NTC_FAULT_HOT = 6,
421c562a43aSYauhen Kharuzhy };
422c562a43aSYauhen Kharuzhy 
42321d90edaSMichał Mirosław static bool bq25890_is_adc_property(enum power_supply_property psp)
42421d90edaSMichał Mirosław {
42521d90edaSMichał Mirosław 	switch (psp) {
42621d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
42721d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_CURRENT_NOW:
4289652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
42921d90edaSMichał Mirosław 		return true;
43021d90edaSMichał Mirosław 
43121d90edaSMichał Mirosław 	default:
43221d90edaSMichał Mirosław 		return false;
43321d90edaSMichał Mirosław 	}
43421d90edaSMichał Mirosław }
43521d90edaSMichał Mirosław 
4363b4df57bSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq);
4373b4df57bSMichał Mirosław 
4388c0984e5SSebastian Reichel static int bq25890_power_supply_get_property(struct power_supply *psy,
4398c0984e5SSebastian Reichel 					     enum power_supply_property psp,
4408c0984e5SSebastian Reichel 					     union power_supply_propval *val)
4418c0984e5SSebastian Reichel {
4428c0984e5SSebastian Reichel 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
4438c0984e5SSebastian Reichel 	struct bq25890_state state;
44421d90edaSMichał Mirosław 	bool do_adc_conv;
44521d90edaSMichał Mirosław 	int ret;
4468c0984e5SSebastian Reichel 
4478c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
4483b4df57bSMichał Mirosław 	/* update state in case we lost an interrupt */
4493b4df57bSMichał Mirosław 	__bq25890_handle_irq(bq);
4508c0984e5SSebastian Reichel 	state = bq->state;
45121d90edaSMichał Mirosław 	do_adc_conv = !state.online && bq25890_is_adc_property(psp);
45221d90edaSMichał Mirosław 	if (do_adc_conv)
45321d90edaSMichał Mirosław 		bq25890_field_write(bq, F_CONV_START, 1);
4548c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
4558c0984e5SSebastian Reichel 
45621d90edaSMichał Mirosław 	if (do_adc_conv)
45721d90edaSMichał Mirosław 		regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START],
45821d90edaSMichał Mirosław 			ret, !ret, 25000, 1000000);
45921d90edaSMichał Mirosław 
4608c0984e5SSebastian Reichel 	switch (psp) {
4618c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_STATUS:
4628c0984e5SSebastian Reichel 		if (!state.online)
4638c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
4648c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_NOT_CHARGING)
4658c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
4668c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_PRE_CHARGING ||
4678c0984e5SSebastian Reichel 			 state.chrg_status == STATUS_FAST_CHARGING)
4688c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
4698c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_TERMINATION_DONE)
4708c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_FULL;
4718c0984e5SSebastian Reichel 		else
4728c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
4738c0984e5SSebastian Reichel 
4748c0984e5SSebastian Reichel 		break;
4758c0984e5SSebastian Reichel 
476b302a0aeSMichał Mirosław 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
477b302a0aeSMichał Mirosław 		if (!state.online || state.chrg_status == STATUS_NOT_CHARGING ||
478b302a0aeSMichał Mirosław 		    state.chrg_status == STATUS_TERMINATION_DONE)
479b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
480b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_PRE_CHARGING)
481b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
482b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_FAST_CHARGING)
483b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
484b302a0aeSMichał Mirosław 		else /* unreachable */
485b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
486b302a0aeSMichał Mirosław 		break;
487b302a0aeSMichał Mirosław 
4888c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MANUFACTURER:
4898c0984e5SSebastian Reichel 		val->strval = BQ25890_MANUFACTURER;
4908c0984e5SSebastian Reichel 		break;
4918c0984e5SSebastian Reichel 
4922e1a2ddeSAngus Ainslie (Purism) 	case POWER_SUPPLY_PROP_MODEL_NAME:
4935956fca7SMichał Mirosław 		val->strval = bq25890_chip_name[bq->chip_version];
4942e1a2ddeSAngus Ainslie (Purism) 		break;
4952e1a2ddeSAngus Ainslie (Purism) 
4968c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
4978c0984e5SSebastian Reichel 		val->intval = state.online;
4988c0984e5SSebastian Reichel 		break;
4998c0984e5SSebastian Reichel 
5008c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_HEALTH:
5018c0984e5SSebastian Reichel 		if (!state.chrg_fault && !state.bat_fault && !state.boost_fault)
5028c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_GOOD;
5038c0984e5SSebastian Reichel 		else if (state.bat_fault)
5048c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
5058c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED)
5068c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
5078c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN)
5088c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
5098c0984e5SSebastian Reichel 		else
5108c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
5118c0984e5SSebastian Reichel 		break;
5128c0984e5SSebastian Reichel 
5138c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
514f83a6eceSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
515c562a43aSYauhen Kharuzhy 
516c562a43aSYauhen Kharuzhy 		/* When temperature is too low, charge current is decreased */
517c562a43aSYauhen Kharuzhy 		if (bq->state.ntc_fault == NTC_FAULT_COOL) {
518c562a43aSYauhen Kharuzhy 			ret = bq25890_field_read(bq, F_JEITA_ISET);
519c562a43aSYauhen Kharuzhy 			if (ret < 0)
520c562a43aSYauhen Kharuzhy 				return ret;
521c562a43aSYauhen Kharuzhy 
522c562a43aSYauhen Kharuzhy 			if (ret)
523c562a43aSYauhen Kharuzhy 				val->intval /= 5;
524c562a43aSYauhen Kharuzhy 			else
525c562a43aSYauhen Kharuzhy 				val->intval /= 2;
526c562a43aSYauhen Kharuzhy 		}
5278c0984e5SSebastian Reichel 		break;
5288c0984e5SSebastian Reichel 
5298c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
5308c0984e5SSebastian Reichel 		if (!state.online) {
5318c0984e5SSebastian Reichel 			val->intval = 0;
5328c0984e5SSebastian Reichel 			break;
5338c0984e5SSebastian Reichel 		}
5348c0984e5SSebastian Reichel 
5358c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, F_BATV); /* read measured value */
5368c0984e5SSebastian Reichel 		if (ret < 0)
5378c0984e5SSebastian Reichel 			return ret;
5388c0984e5SSebastian Reichel 
5398c0984e5SSebastian Reichel 		/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
5408c0984e5SSebastian Reichel 		val->intval = 2304000 + ret * 20000;
5418c0984e5SSebastian Reichel 		break;
5428c0984e5SSebastian Reichel 
5438c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
544f83a6eceSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
5458c0984e5SSebastian Reichel 		break;
5468c0984e5SSebastian Reichel 
547c942656dSMichał Mirosław 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
548c942656dSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM);
549c942656dSMichał Mirosław 		break;
550c942656dSMichał Mirosław 
5518c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
5528c0984e5SSebastian Reichel 		val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM);
5538c0984e5SSebastian Reichel 		break;
5548c0984e5SSebastian Reichel 
555478efc79SMichał Mirosław 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
556766873c1SYauhen Kharuzhy 		ret = bq25890_field_read(bq, F_IINLIM);
557478efc79SMichał Mirosław 		if (ret < 0)
558478efc79SMichał Mirosław 			return ret;
559478efc79SMichał Mirosław 
560766873c1SYauhen Kharuzhy 		val->intval = bq25890_find_val(ret, TBL_IINLIM);
561478efc79SMichał Mirosław 		break;
562478efc79SMichał Mirosław 
563ae6fe7a3SAngus Ainslie (Purism) 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
564ae6fe7a3SAngus Ainslie (Purism) 		ret = bq25890_field_read(bq, F_SYSV); /* read measured value */
565ae6fe7a3SAngus Ainslie (Purism) 		if (ret < 0)
566ae6fe7a3SAngus Ainslie (Purism) 			return ret;
567ae6fe7a3SAngus Ainslie (Purism) 
568ae6fe7a3SAngus Ainslie (Purism) 		/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
569ae6fe7a3SAngus Ainslie (Purism) 		val->intval = 2304000 + ret * 20000;
570ae6fe7a3SAngus Ainslie (Purism) 		break;
571ae6fe7a3SAngus Ainslie (Purism) 
5721e4724d0SMichał Mirosław 	case POWER_SUPPLY_PROP_CURRENT_NOW:
5731e4724d0SMichał Mirosław 		ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */
5741e4724d0SMichał Mirosław 		if (ret < 0)
5751e4724d0SMichał Mirosław 			return ret;
5761e4724d0SMichał Mirosław 
5771e4724d0SMichał Mirosław 		/* converted_val = ADC_val * 50mA (table 10.3.19) */
5781e4724d0SMichał Mirosław 		val->intval = ret * -50000;
5791e4724d0SMichał Mirosław 		break;
5801e4724d0SMichał Mirosław 
5819652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
5829652c024SAngus Ainslie 		ret = bq25890_field_read(bq, F_TSPCT);
5839652c024SAngus Ainslie 		if (ret < 0)
5849652c024SAngus Ainslie 			return ret;
5859652c024SAngus Ainslie 
5869652c024SAngus Ainslie 		/* convert TS percentage into rough temperature */
5879652c024SAngus Ainslie 		val->intval = bq25890_find_val(ret, TBL_TSPCT);
5889652c024SAngus Ainslie 		break;
5899652c024SAngus Ainslie 
5908c0984e5SSebastian Reichel 	default:
5918c0984e5SSebastian Reichel 		return -EINVAL;
5928c0984e5SSebastian Reichel 	}
5938c0984e5SSebastian Reichel 
5948c0984e5SSebastian Reichel 	return 0;
5958c0984e5SSebastian Reichel }
5968c0984e5SSebastian Reichel 
597*eab25b4fSHans de Goede /* On the BQ25892 try to get charger-type info from our supplier */
598*eab25b4fSHans de Goede static void bq25890_charger_external_power_changed(struct power_supply *psy)
599*eab25b4fSHans de Goede {
600*eab25b4fSHans de Goede 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
601*eab25b4fSHans de Goede 	union power_supply_propval val;
602*eab25b4fSHans de Goede 	int input_current_limit, ret;
603*eab25b4fSHans de Goede 
604*eab25b4fSHans de Goede 	if (bq->chip_version != BQ25892)
605*eab25b4fSHans de Goede 		return;
606*eab25b4fSHans de Goede 
607*eab25b4fSHans de Goede 	ret = power_supply_get_property_from_supplier(bq->charger,
608*eab25b4fSHans de Goede 						      POWER_SUPPLY_PROP_USB_TYPE,
609*eab25b4fSHans de Goede 						      &val);
610*eab25b4fSHans de Goede 	if (ret)
611*eab25b4fSHans de Goede 		return;
612*eab25b4fSHans de Goede 
613*eab25b4fSHans de Goede 	switch (val.intval) {
614*eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_DCP:
615*eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM);
616*eab25b4fSHans de Goede 		break;
617*eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_CDP:
618*eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_ACA:
619*eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM);
620*eab25b4fSHans de Goede 		break;
621*eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_SDP:
622*eab25b4fSHans de Goede 	default:
623*eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(500000, TBL_IINLIM);
624*eab25b4fSHans de Goede 	}
625*eab25b4fSHans de Goede 
626*eab25b4fSHans de Goede 	bq25890_field_write(bq, F_IINLIM, input_current_limit);
627*eab25b4fSHans de Goede }
628*eab25b4fSHans de Goede 
6298c0984e5SSebastian Reichel static int bq25890_get_chip_state(struct bq25890_device *bq,
6308c0984e5SSebastian Reichel 				  struct bq25890_state *state)
6318c0984e5SSebastian Reichel {
6328c0984e5SSebastian Reichel 	int i, ret;
6338c0984e5SSebastian Reichel 
6348c0984e5SSebastian Reichel 	struct {
6358c0984e5SSebastian Reichel 		enum bq25890_fields id;
6368c0984e5SSebastian Reichel 		u8 *data;
6378c0984e5SSebastian Reichel 	} state_fields[] = {
6388c0984e5SSebastian Reichel 		{F_CHG_STAT,	&state->chrg_status},
6398c0984e5SSebastian Reichel 		{F_PG_STAT,	&state->online},
6408c0984e5SSebastian Reichel 		{F_VSYS_STAT,	&state->vsys_status},
6418c0984e5SSebastian Reichel 		{F_BOOST_FAULT, &state->boost_fault},
6428c0984e5SSebastian Reichel 		{F_BAT_FAULT,	&state->bat_fault},
643c562a43aSYauhen Kharuzhy 		{F_CHG_FAULT,	&state->chrg_fault},
644c562a43aSYauhen Kharuzhy 		{F_NTC_FAULT,	&state->ntc_fault}
6458c0984e5SSebastian Reichel 	};
6468c0984e5SSebastian Reichel 
6478c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(state_fields); i++) {
6488c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, state_fields[i].id);
6498c0984e5SSebastian Reichel 		if (ret < 0)
6508c0984e5SSebastian Reichel 			return ret;
6518c0984e5SSebastian Reichel 
6528c0984e5SSebastian Reichel 		*state_fields[i].data = ret;
6538c0984e5SSebastian Reichel 	}
6548c0984e5SSebastian Reichel 
655c562a43aSYauhen Kharuzhy 	dev_dbg(bq->dev, "S:CHG/PG/VSYS=%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
6568c0984e5SSebastian Reichel 		state->chrg_status, state->online, state->vsys_status,
657c562a43aSYauhen Kharuzhy 		state->chrg_fault, state->boost_fault, state->bat_fault,
658c562a43aSYauhen Kharuzhy 		state->ntc_fault);
6598c0984e5SSebastian Reichel 
6608c0984e5SSebastian Reichel 	return 0;
6618c0984e5SSebastian Reichel }
6628c0984e5SSebastian Reichel 
66372d9cd9cSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
6648c0984e5SSebastian Reichel {
66572d9cd9cSMichał Mirosław 	struct bq25890_state new_state;
6668c0984e5SSebastian Reichel 	int ret;
6678c0984e5SSebastian Reichel 
66872d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &new_state);
66972d9cd9cSMichał Mirosław 	if (ret < 0)
67072d9cd9cSMichał Mirosław 		return IRQ_NONE;
6718c0984e5SSebastian Reichel 
67272d9cd9cSMichał Mirosław 	if (!memcmp(&bq->state, &new_state, sizeof(new_state)))
67372d9cd9cSMichał Mirosław 		return IRQ_NONE;
67472d9cd9cSMichał Mirosław 
67572d9cd9cSMichał Mirosław 	if (!new_state.online && bq->state.online) {	    /* power removed */
6768c0984e5SSebastian Reichel 		/* disable ADC */
67780211be1SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_CONV_RATE, 0);
6788c0984e5SSebastian Reichel 		if (ret < 0)
6798c0984e5SSebastian Reichel 			goto error;
68072d9cd9cSMichał Mirosław 	} else if (new_state.online && !bq->state.online) { /* power inserted */
6818c0984e5SSebastian Reichel 		/* enable ADC, to have control of charge current/voltage */
68280211be1SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_CONV_RATE, 1);
6838c0984e5SSebastian Reichel 		if (ret < 0)
6848c0984e5SSebastian Reichel 			goto error;
6858c0984e5SSebastian Reichel 	}
6868c0984e5SSebastian Reichel 
68772d9cd9cSMichał Mirosław 	bq->state = new_state;
68872d9cd9cSMichał Mirosław 	power_supply_changed(bq->charger);
6898c0984e5SSebastian Reichel 
69072d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
6918c0984e5SSebastian Reichel error:
69272d9cd9cSMichał Mirosław 	dev_err(bq->dev, "Error communicating with the chip: %pe\n",
69372d9cd9cSMichał Mirosław 		ERR_PTR(ret));
69472d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
6958c0984e5SSebastian Reichel }
6968c0984e5SSebastian Reichel 
6978c0984e5SSebastian Reichel static irqreturn_t bq25890_irq_handler_thread(int irq, void *private)
6988c0984e5SSebastian Reichel {
6998c0984e5SSebastian Reichel 	struct bq25890_device *bq = private;
70072d9cd9cSMichał Mirosław 	irqreturn_t ret;
7018c0984e5SSebastian Reichel 
7028c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
70372d9cd9cSMichał Mirosław 	ret = __bq25890_handle_irq(bq);
7048c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
7058c0984e5SSebastian Reichel 
70672d9cd9cSMichał Mirosław 	return ret;
7078c0984e5SSebastian Reichel }
7088c0984e5SSebastian Reichel 
7098c0984e5SSebastian Reichel static int bq25890_chip_reset(struct bq25890_device *bq)
7108c0984e5SSebastian Reichel {
7118c0984e5SSebastian Reichel 	int ret;
7128c0984e5SSebastian Reichel 	int rst_check_counter = 10;
7138c0984e5SSebastian Reichel 
7148c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_REG_RST, 1);
7158c0984e5SSebastian Reichel 	if (ret < 0)
7168c0984e5SSebastian Reichel 		return ret;
7178c0984e5SSebastian Reichel 
7188c0984e5SSebastian Reichel 	do {
7198c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, F_REG_RST);
7208c0984e5SSebastian Reichel 		if (ret < 0)
7218c0984e5SSebastian Reichel 			return ret;
7228c0984e5SSebastian Reichel 
7238c0984e5SSebastian Reichel 		usleep_range(5, 10);
7248c0984e5SSebastian Reichel 	} while (ret == 1 && --rst_check_counter);
7258c0984e5SSebastian Reichel 
7268c0984e5SSebastian Reichel 	if (!rst_check_counter)
7278c0984e5SSebastian Reichel 		return -ETIMEDOUT;
7288c0984e5SSebastian Reichel 
7298c0984e5SSebastian Reichel 	return 0;
7308c0984e5SSebastian Reichel }
7318c0984e5SSebastian Reichel 
7327b22a974SHans de Goede static int bq25890_rw_init_data(struct bq25890_device *bq)
7338c0984e5SSebastian Reichel {
73440428bd4SHans de Goede 	bool write = !bq->read_back_init_data;
7358c0984e5SSebastian Reichel 	int ret;
7368c0984e5SSebastian Reichel 	int i;
7378c0984e5SSebastian Reichel 
7388c0984e5SSebastian Reichel 	const struct {
7398c0984e5SSebastian Reichel 		enum bq25890_fields id;
7407b22a974SHans de Goede 		u8 *value;
7418c0984e5SSebastian Reichel 	} init_data[] = {
7427b22a974SHans de Goede 		{F_ICHG,	 &bq->init_data.ichg},
7437b22a974SHans de Goede 		{F_VREG,	 &bq->init_data.vreg},
7447b22a974SHans de Goede 		{F_ITERM,	 &bq->init_data.iterm},
7457b22a974SHans de Goede 		{F_IPRECHG,	 &bq->init_data.iprechg},
7467b22a974SHans de Goede 		{F_SYSVMIN,	 &bq->init_data.sysvmin},
7477b22a974SHans de Goede 		{F_BOOSTV,	 &bq->init_data.boostv},
7487b22a974SHans de Goede 		{F_BOOSTI,	 &bq->init_data.boosti},
7497b22a974SHans de Goede 		{F_BOOSTF,	 &bq->init_data.boostf},
7507b22a974SHans de Goede 		{F_EN_ILIM,	 &bq->init_data.ilim_en},
7517b22a974SHans de Goede 		{F_TREG,	 &bq->init_data.treg},
7527b22a974SHans de Goede 		{F_BATCMP,	 &bq->init_data.rbatcomp},
7537b22a974SHans de Goede 		{F_VCLAMP,	 &bq->init_data.vclamp},
7548c0984e5SSebastian Reichel 	};
7558c0984e5SSebastian Reichel 
7567b22a974SHans de Goede 	for (i = 0; i < ARRAY_SIZE(init_data); i++) {
7577b22a974SHans de Goede 		if (write) {
7587b22a974SHans de Goede 			ret = bq25890_field_write(bq, init_data[i].id,
7597b22a974SHans de Goede 						  *init_data[i].value);
7607b22a974SHans de Goede 		} else {
7617b22a974SHans de Goede 			ret = bq25890_field_read(bq, init_data[i].id);
7627b22a974SHans de Goede 			if (ret >= 0)
7637b22a974SHans de Goede 				*init_data[i].value = ret;
7647b22a974SHans de Goede 		}
7657b22a974SHans de Goede 		if (ret < 0) {
7667b22a974SHans de Goede 			dev_dbg(bq->dev, "Accessing init data failed %d\n", ret);
7677b22a974SHans de Goede 			return ret;
7687b22a974SHans de Goede 		}
7697b22a974SHans de Goede 	}
7707b22a974SHans de Goede 
7717b22a974SHans de Goede 	return 0;
7727b22a974SHans de Goede }
7737b22a974SHans de Goede 
7747b22a974SHans de Goede static int bq25890_hw_init(struct bq25890_device *bq)
7757b22a974SHans de Goede {
7767b22a974SHans de Goede 	int ret;
7777b22a974SHans de Goede 
7787e3b8e35SHans de Goede 	if (!bq->skip_reset) {
7798c0984e5SSebastian Reichel 		ret = bq25890_chip_reset(bq);
7809d9ae341SAngus Ainslie (Purism) 		if (ret < 0) {
7819d9ae341SAngus Ainslie (Purism) 			dev_dbg(bq->dev, "Reset failed %d\n", ret);
7828c0984e5SSebastian Reichel 			return ret;
783ad1570d9Skbuild test robot 		}
78406c75095SHans de Goede 	} else {
78506c75095SHans de Goede 		/*
78606c75095SHans de Goede 		 * Ensure charging is enabled, on some boards where the fw
78706c75095SHans de Goede 		 * takes care of initalizition F_CHG_CFG is set to 0 before
78806c75095SHans de Goede 		 * handing control over to the OS.
78906c75095SHans de Goede 		 */
79006c75095SHans de Goede 		ret = bq25890_field_write(bq, F_CHG_CFG, 1);
79106c75095SHans de Goede 		if (ret < 0) {
79206c75095SHans de Goede 			dev_dbg(bq->dev, "Enabling charging failed %d\n", ret);
79306c75095SHans de Goede 			return ret;
79406c75095SHans de Goede 		}
7957e3b8e35SHans de Goede 	}
7968c0984e5SSebastian Reichel 
7978c0984e5SSebastian Reichel 	/* disable watchdog */
7988c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_WD, 0);
7999d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
8009d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret);
8018c0984e5SSebastian Reichel 		return ret;
802ad1570d9Skbuild test robot 	}
8038c0984e5SSebastian Reichel 
8048c0984e5SSebastian Reichel 	/* initialize currents/voltages and other parameters */
8057b22a974SHans de Goede 	ret = bq25890_rw_init_data(bq);
8067b22a974SHans de Goede 	if (ret)
8078c0984e5SSebastian Reichel 		return ret;
8088c0984e5SSebastian Reichel 
80922ad4f99SHans de Goede 	ret = bq25890_get_chip_state(bq, &bq->state);
81022ad4f99SHans de Goede 	if (ret < 0) {
81122ad4f99SHans de Goede 		dev_dbg(bq->dev, "Get state failed %d\n", ret);
81222ad4f99SHans de Goede 		return ret;
81322ad4f99SHans de Goede 	}
81422ad4f99SHans de Goede 
81521d90edaSMichał Mirosław 	/* Configure ADC for continuous conversions when charging */
81621d90edaSMichał Mirosław 	ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
8179d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
8189d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
8198c0984e5SSebastian Reichel 		return ret;
820ad1570d9Skbuild test robot 	}
8218c0984e5SSebastian Reichel 
8228c0984e5SSebastian Reichel 	return 0;
8238c0984e5SSebastian Reichel }
8248c0984e5SSebastian Reichel 
825a6a48facSMichał Mirosław static const enum power_supply_property bq25890_power_supply_props[] = {
8268c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MANUFACTURER,
8272e1a2ddeSAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_MODEL_NAME,
8288c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
829b302a0aeSMichał Mirosław 	POWER_SUPPLY_PROP_CHARGE_TYPE,
8308c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
8318c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_HEALTH,
8328c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
8338c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
8348c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
835c942656dSMichał Mirosław 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
8368c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
837478efc79SMichał Mirosław 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
838ae6fe7a3SAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
8391e4724d0SMichał Mirosław 	POWER_SUPPLY_PROP_CURRENT_NOW,
8409652c024SAngus Ainslie 	POWER_SUPPLY_PROP_TEMP,
8418c0984e5SSebastian Reichel };
8428c0984e5SSebastian Reichel 
8438c0984e5SSebastian Reichel static char *bq25890_charger_supplied_to[] = {
8448c0984e5SSebastian Reichel 	"main-battery",
8458c0984e5SSebastian Reichel };
8468c0984e5SSebastian Reichel 
8478c0984e5SSebastian Reichel static const struct power_supply_desc bq25890_power_supply_desc = {
8488c0984e5SSebastian Reichel 	.name = "bq25890-charger",
8498c0984e5SSebastian Reichel 	.type = POWER_SUPPLY_TYPE_USB,
8508c0984e5SSebastian Reichel 	.properties = bq25890_power_supply_props,
8518c0984e5SSebastian Reichel 	.num_properties = ARRAY_SIZE(bq25890_power_supply_props),
8528c0984e5SSebastian Reichel 	.get_property = bq25890_power_supply_get_property,
853*eab25b4fSHans de Goede 	.external_power_changed	= bq25890_charger_external_power_changed,
8548c0984e5SSebastian Reichel };
8558c0984e5SSebastian Reichel 
8568c0984e5SSebastian Reichel static int bq25890_power_supply_init(struct bq25890_device *bq)
8578c0984e5SSebastian Reichel {
8588c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = { .drv_data = bq, };
8598c0984e5SSebastian Reichel 
8608c0984e5SSebastian Reichel 	psy_cfg.supplied_to = bq25890_charger_supplied_to;
8618c0984e5SSebastian Reichel 	psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
8628c0984e5SSebastian Reichel 
863d01363daSHans de Goede 	bq->charger = devm_power_supply_register(bq->dev,
864d01363daSHans de Goede 						 &bq25890_power_supply_desc,
8658c0984e5SSebastian Reichel 						 &psy_cfg);
8668c0984e5SSebastian Reichel 
8678c0984e5SSebastian Reichel 	return PTR_ERR_OR_ZERO(bq->charger);
8688c0984e5SSebastian Reichel }
8698c0984e5SSebastian Reichel 
8705575802dSHans de Goede static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val)
8715575802dSHans de Goede {
8725575802dSHans de Goede 	int ret;
8735575802dSHans de Goede 
8745575802dSHans de Goede 	ret = bq25890_field_write(bq, F_OTG_CFG, val);
8755575802dSHans de Goede 	if (ret < 0)
8765575802dSHans de Goede 		dev_err(bq->dev, "Error switching to boost/charger mode: %d\n", ret);
8775575802dSHans de Goede 
8785575802dSHans de Goede 	return ret;
8795575802dSHans de Goede }
8805575802dSHans de Goede 
8818c0984e5SSebastian Reichel static void bq25890_usb_work(struct work_struct *data)
8828c0984e5SSebastian Reichel {
8838c0984e5SSebastian Reichel 	int ret;
8848c0984e5SSebastian Reichel 	struct bq25890_device *bq =
8858c0984e5SSebastian Reichel 			container_of(data, struct bq25890_device, usb_work);
8868c0984e5SSebastian Reichel 
8878c0984e5SSebastian Reichel 	switch (bq->usb_event) {
8888c0984e5SSebastian Reichel 	case USB_EVENT_ID:
8898c0984e5SSebastian Reichel 		/* Enable boost mode */
8905575802dSHans de Goede 		bq25890_set_otg_cfg(bq, 1);
8918c0984e5SSebastian Reichel 		break;
8928c0984e5SSebastian Reichel 
8938c0984e5SSebastian Reichel 	case USB_EVENT_NONE:
8948c0984e5SSebastian Reichel 		/* Disable boost mode */
8955575802dSHans de Goede 		ret = bq25890_set_otg_cfg(bq, 0);
8965575802dSHans de Goede 		if (ret == 0)
8978c0984e5SSebastian Reichel 			power_supply_changed(bq->charger);
8988c0984e5SSebastian Reichel 		break;
8998c0984e5SSebastian Reichel 	}
9008c0984e5SSebastian Reichel }
9018c0984e5SSebastian Reichel 
9028c0984e5SSebastian Reichel static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val,
9038c0984e5SSebastian Reichel 				void *priv)
9048c0984e5SSebastian Reichel {
9058c0984e5SSebastian Reichel 	struct bq25890_device *bq =
9068c0984e5SSebastian Reichel 			container_of(nb, struct bq25890_device, usb_nb);
9078c0984e5SSebastian Reichel 
9088c0984e5SSebastian Reichel 	bq->usb_event = val;
9098c0984e5SSebastian Reichel 	queue_work(system_power_efficient_wq, &bq->usb_work);
9108c0984e5SSebastian Reichel 
9118c0984e5SSebastian Reichel 	return NOTIFY_OK;
9128c0984e5SSebastian Reichel }
9138c0984e5SSebastian Reichel 
91479d35365SHans de Goede #ifdef CONFIG_REGULATOR
91579d35365SHans de Goede static int bq25890_vbus_enable(struct regulator_dev *rdev)
91679d35365SHans de Goede {
91779d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
91879d35365SHans de Goede 
91979d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 1);
92079d35365SHans de Goede }
92179d35365SHans de Goede 
92279d35365SHans de Goede static int bq25890_vbus_disable(struct regulator_dev *rdev)
92379d35365SHans de Goede {
92479d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
92579d35365SHans de Goede 
92679d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 0);
92779d35365SHans de Goede }
92879d35365SHans de Goede 
92979d35365SHans de Goede static int bq25890_vbus_is_enabled(struct regulator_dev *rdev)
93079d35365SHans de Goede {
93179d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
93279d35365SHans de Goede 
93379d35365SHans de Goede 	return bq25890_field_read(bq, F_OTG_CFG);
93479d35365SHans de Goede }
93579d35365SHans de Goede 
93679d35365SHans de Goede static const struct regulator_ops bq25890_vbus_ops = {
93779d35365SHans de Goede 	.enable = bq25890_vbus_enable,
93879d35365SHans de Goede 	.disable = bq25890_vbus_disable,
93979d35365SHans de Goede 	.is_enabled = bq25890_vbus_is_enabled,
94079d35365SHans de Goede };
94179d35365SHans de Goede 
94279d35365SHans de Goede static const struct regulator_desc bq25890_vbus_desc = {
94379d35365SHans de Goede 	.name = "usb_otg_vbus",
94479d35365SHans de Goede 	.of_match = "usb-otg-vbus",
94579d35365SHans de Goede 	.type = REGULATOR_VOLTAGE,
94679d35365SHans de Goede 	.owner = THIS_MODULE,
94779d35365SHans de Goede 	.ops = &bq25890_vbus_ops,
94879d35365SHans de Goede 	.fixed_uV = 5000000,
94979d35365SHans de Goede 	.n_voltages = 1,
95079d35365SHans de Goede };
95179d35365SHans de Goede #endif
95279d35365SHans de Goede 
953d20267c9SYauhen Kharuzhy static int bq25890_get_chip_version(struct bq25890_device *bq)
954d20267c9SYauhen Kharuzhy {
955d20267c9SYauhen Kharuzhy 	int id, rev;
956d20267c9SYauhen Kharuzhy 
957d20267c9SYauhen Kharuzhy 	id = bq25890_field_read(bq, F_PN);
958d20267c9SYauhen Kharuzhy 	if (id < 0) {
959172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip ID: %d\n", id);
960d20267c9SYauhen Kharuzhy 		return id;
961d20267c9SYauhen Kharuzhy 	}
962d20267c9SYauhen Kharuzhy 
963d20267c9SYauhen Kharuzhy 	rev = bq25890_field_read(bq, F_DEV_REV);
964d20267c9SYauhen Kharuzhy 	if (rev < 0) {
965172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip revision: %d\n", rev);
966cb619e80SColin Ian King 		return rev;
967d20267c9SYauhen Kharuzhy 	}
968d20267c9SYauhen Kharuzhy 
969d20267c9SYauhen Kharuzhy 	switch (id) {
970d20267c9SYauhen Kharuzhy 	case BQ25890_ID:
971d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25890;
972d20267c9SYauhen Kharuzhy 		break;
973d20267c9SYauhen Kharuzhy 
974d20267c9SYauhen Kharuzhy 	/* BQ25892 and BQ25896 share same ID 0 */
975d20267c9SYauhen Kharuzhy 	case BQ25896_ID:
976d20267c9SYauhen Kharuzhy 		switch (rev) {
977d20267c9SYauhen Kharuzhy 		case 2:
978d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25896;
979d20267c9SYauhen Kharuzhy 			break;
980d20267c9SYauhen Kharuzhy 		case 1:
981d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
982d20267c9SYauhen Kharuzhy 			break;
983d20267c9SYauhen Kharuzhy 		default:
984d20267c9SYauhen Kharuzhy 			dev_err(bq->dev,
985d20267c9SYauhen Kharuzhy 				"Unknown device revision %d, assume BQ25892\n",
986d20267c9SYauhen Kharuzhy 				rev);
987d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
988d20267c9SYauhen Kharuzhy 		}
989d20267c9SYauhen Kharuzhy 		break;
990d20267c9SYauhen Kharuzhy 
991d20267c9SYauhen Kharuzhy 	case BQ25895_ID:
992d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25895;
993d20267c9SYauhen Kharuzhy 		break;
994d20267c9SYauhen Kharuzhy 
995d20267c9SYauhen Kharuzhy 	default:
996d20267c9SYauhen Kharuzhy 		dev_err(bq->dev, "Unknown chip ID %d\n", id);
997d20267c9SYauhen Kharuzhy 		return -ENODEV;
998d20267c9SYauhen Kharuzhy 	}
999d20267c9SYauhen Kharuzhy 
1000d20267c9SYauhen Kharuzhy 	return 0;
1001d20267c9SYauhen Kharuzhy }
1002d20267c9SYauhen Kharuzhy 
10038c0984e5SSebastian Reichel static int bq25890_irq_probe(struct bq25890_device *bq)
10048c0984e5SSebastian Reichel {
10058c0984e5SSebastian Reichel 	struct gpio_desc *irq;
10068c0984e5SSebastian Reichel 
100786775879SAndy Shevchenko 	irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN);
1008172d0cceSMartin Kepplinger 	if (IS_ERR(irq))
1009172d0cceSMartin Kepplinger 		return dev_err_probe(bq->dev, PTR_ERR(irq),
1010172d0cceSMartin Kepplinger 				     "Could not probe irq pin.\n");
10118c0984e5SSebastian Reichel 
10128c0984e5SSebastian Reichel 	return gpiod_to_irq(irq);
10138c0984e5SSebastian Reichel }
10148c0984e5SSebastian Reichel 
10158c0984e5SSebastian Reichel static int bq25890_fw_read_u32_props(struct bq25890_device *bq)
10168c0984e5SSebastian Reichel {
10178c0984e5SSebastian Reichel 	int ret;
10188c0984e5SSebastian Reichel 	u32 property;
10198c0984e5SSebastian Reichel 	int i;
10208c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
10218c0984e5SSebastian Reichel 	struct {
10228c0984e5SSebastian Reichel 		char *name;
10238c0984e5SSebastian Reichel 		bool optional;
10248c0984e5SSebastian Reichel 		enum bq25890_table_ids tbl_id;
10258c0984e5SSebastian Reichel 		u8 *conv_data; /* holds converted value from given property */
10268c0984e5SSebastian Reichel 	} props[] = {
10278c0984e5SSebastian Reichel 		/* required properties */
10288c0984e5SSebastian Reichel 		{"ti,charge-current", false, TBL_ICHG, &init->ichg},
10298c0984e5SSebastian Reichel 		{"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg},
10308c0984e5SSebastian Reichel 		{"ti,termination-current", false, TBL_ITERM, &init->iterm},
10318c0984e5SSebastian Reichel 		{"ti,precharge-current", false, TBL_ITERM, &init->iprechg},
10328c0984e5SSebastian Reichel 		{"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin},
10338c0984e5SSebastian Reichel 		{"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv},
10348c0984e5SSebastian Reichel 		{"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti},
10358c0984e5SSebastian Reichel 
10368c0984e5SSebastian Reichel 		/* optional properties */
103772408329SMichał Mirosław 		{"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg},
103872408329SMichał Mirosław 		{"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp},
103972408329SMichał Mirosław 		{"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp},
10408c0984e5SSebastian Reichel 	};
10418c0984e5SSebastian Reichel 
10428c0984e5SSebastian Reichel 	/* initialize data for optional properties */
10438c0984e5SSebastian Reichel 	init->treg = 3; /* 120 degrees Celsius */
104472408329SMichał Mirosław 	init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */
10458c0984e5SSebastian Reichel 
10468c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(props); i++) {
10478c0984e5SSebastian Reichel 		ret = device_property_read_u32(bq->dev, props[i].name,
10488c0984e5SSebastian Reichel 					       &property);
10498c0984e5SSebastian Reichel 		if (ret < 0) {
10508c0984e5SSebastian Reichel 			if (props[i].optional)
10518c0984e5SSebastian Reichel 				continue;
10528c0984e5SSebastian Reichel 
10539d9ae341SAngus Ainslie (Purism) 			dev_err(bq->dev, "Unable to read property %d %s\n", ret,
10549d9ae341SAngus Ainslie (Purism) 				props[i].name);
10559d9ae341SAngus Ainslie (Purism) 
10568c0984e5SSebastian Reichel 			return ret;
10578c0984e5SSebastian Reichel 		}
10588c0984e5SSebastian Reichel 
10598c0984e5SSebastian Reichel 		*props[i].conv_data = bq25890_find_idx(property,
10608c0984e5SSebastian Reichel 						       props[i].tbl_id);
10618c0984e5SSebastian Reichel 	}
10628c0984e5SSebastian Reichel 
10638c0984e5SSebastian Reichel 	return 0;
10648c0984e5SSebastian Reichel }
10658c0984e5SSebastian Reichel 
10668c0984e5SSebastian Reichel static int bq25890_fw_probe(struct bq25890_device *bq)
10678c0984e5SSebastian Reichel {
10688c0984e5SSebastian Reichel 	int ret;
10698c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
10708c0984e5SSebastian Reichel 
10717e3b8e35SHans de Goede 	bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset");
107240428bd4SHans de Goede 	bq->read_back_init_data = device_property_read_bool(bq->dev,
107340428bd4SHans de Goede 						"linux,read-back-settings");
107440428bd4SHans de Goede 	if (bq->read_back_init_data)
107540428bd4SHans de Goede 		return 0;
10767e3b8e35SHans de Goede 
10778c0984e5SSebastian Reichel 	ret = bq25890_fw_read_u32_props(bq);
10788c0984e5SSebastian Reichel 	if (ret < 0)
10798c0984e5SSebastian Reichel 		return ret;
10808c0984e5SSebastian Reichel 
10818c0984e5SSebastian Reichel 	init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin");
10828c0984e5SSebastian Reichel 	init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq");
10838c0984e5SSebastian Reichel 
10848c0984e5SSebastian Reichel 	return 0;
10858c0984e5SSebastian Reichel }
10868c0984e5SSebastian Reichel 
10878c0984e5SSebastian Reichel static int bq25890_probe(struct i2c_client *client,
10888c0984e5SSebastian Reichel 			 const struct i2c_device_id *id)
10898c0984e5SSebastian Reichel {
10908c0984e5SSebastian Reichel 	struct device *dev = &client->dev;
10918c0984e5SSebastian Reichel 	struct bq25890_device *bq;
10928c0984e5SSebastian Reichel 	int ret;
10938c0984e5SSebastian Reichel 	int i;
10948c0984e5SSebastian Reichel 
10958c0984e5SSebastian Reichel 	bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL);
10968c0984e5SSebastian Reichel 	if (!bq)
10978c0984e5SSebastian Reichel 		return -ENOMEM;
10988c0984e5SSebastian Reichel 
10998c0984e5SSebastian Reichel 	bq->client = client;
11008c0984e5SSebastian Reichel 	bq->dev = dev;
11018c0984e5SSebastian Reichel 
11028c0984e5SSebastian Reichel 	mutex_init(&bq->lock);
11038c0984e5SSebastian Reichel 
11048c0984e5SSebastian Reichel 	bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config);
1105172d0cceSMartin Kepplinger 	if (IS_ERR(bq->rmap))
1106172d0cceSMartin Kepplinger 		return dev_err_probe(dev, PTR_ERR(bq->rmap),
1107172d0cceSMartin Kepplinger 				     "failed to allocate register map\n");
11088c0984e5SSebastian Reichel 
11098c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(bq25890_reg_fields); i++) {
11108c0984e5SSebastian Reichel 		const struct reg_field *reg_fields = bq25890_reg_fields;
11118c0984e5SSebastian Reichel 
11128c0984e5SSebastian Reichel 		bq->rmap_fields[i] = devm_regmap_field_alloc(dev, bq->rmap,
11138c0984e5SSebastian Reichel 							     reg_fields[i]);
1114172d0cceSMartin Kepplinger 		if (IS_ERR(bq->rmap_fields[i]))
1115172d0cceSMartin Kepplinger 			return dev_err_probe(dev, PTR_ERR(bq->rmap_fields[i]),
1116172d0cceSMartin Kepplinger 					     "cannot allocate regmap field\n");
11178c0984e5SSebastian Reichel 	}
11188c0984e5SSebastian Reichel 
11198c0984e5SSebastian Reichel 	i2c_set_clientdata(client, bq);
11208c0984e5SSebastian Reichel 
1121d20267c9SYauhen Kharuzhy 	ret = bq25890_get_chip_version(bq);
1122d20267c9SYauhen Kharuzhy 	if (ret) {
1123172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret);
1124d20267c9SYauhen Kharuzhy 		return ret;
11258c0984e5SSebastian Reichel 	}
11268c0984e5SSebastian Reichel 
11278c0984e5SSebastian Reichel 	ret = bq25890_fw_probe(bq);
1128f481d5b8SHans de Goede 	if (ret < 0)
1129f481d5b8SHans de Goede 		return dev_err_probe(dev, ret, "reading device properties\n");
11308c0984e5SSebastian Reichel 
11318c0984e5SSebastian Reichel 	ret = bq25890_hw_init(bq);
11328c0984e5SSebastian Reichel 	if (ret < 0) {
1133172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot initialize the chip: %d\n", ret);
11348c0984e5SSebastian Reichel 		return ret;
11358c0984e5SSebastian Reichel 	}
11368c0984e5SSebastian Reichel 
11378c0984e5SSebastian Reichel 	if (client->irq <= 0)
11388c0984e5SSebastian Reichel 		client->irq = bq25890_irq_probe(bq);
11398c0984e5SSebastian Reichel 
11408c0984e5SSebastian Reichel 	if (client->irq < 0) {
11418c0984e5SSebastian Reichel 		dev_err(dev, "No irq resource found.\n");
11428c0984e5SSebastian Reichel 		return client->irq;
11438c0984e5SSebastian Reichel 	}
11448c0984e5SSebastian Reichel 
11458c0984e5SSebastian Reichel 	/* OTG reporting */
11468c0984e5SSebastian Reichel 	bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
11478c0984e5SSebastian Reichel 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
11488c0984e5SSebastian Reichel 		INIT_WORK(&bq->usb_work, bq25890_usb_work);
11498c0984e5SSebastian Reichel 		bq->usb_nb.notifier_call = bq25890_usb_notifier;
11508c0984e5SSebastian Reichel 		usb_register_notifier(bq->usb_phy, &bq->usb_nb);
11518c0984e5SSebastian Reichel 	}
115279d35365SHans de Goede #ifdef CONFIG_REGULATOR
115379d35365SHans de Goede 	else {
115479d35365SHans de Goede 		struct bq25890_platform_data *pdata = dev_get_platdata(dev);
115579d35365SHans de Goede 		struct regulator_config cfg = { };
115679d35365SHans de Goede 		struct regulator_dev *reg;
115779d35365SHans de Goede 
115879d35365SHans de Goede 		cfg.dev = dev;
115979d35365SHans de Goede 		cfg.driver_data = bq;
116079d35365SHans de Goede 		if (pdata)
116179d35365SHans de Goede 			cfg.init_data = pdata->regulator_init_data;
116279d35365SHans de Goede 
116379d35365SHans de Goede 		reg = devm_regulator_register(dev, &bq25890_vbus_desc, &cfg);
116479d35365SHans de Goede 		if (IS_ERR(reg))
116579d35365SHans de Goede 			return dev_err_probe(dev, PTR_ERR(reg), "registering regulator");
116679d35365SHans de Goede 	}
116779d35365SHans de Goede #endif
11688c0984e5SSebastian Reichel 
1169d01363daSHans de Goede 	ret = bq25890_power_supply_init(bq);
1170d01363daSHans de Goede 	if (ret < 0) {
1171d01363daSHans de Goede 		dev_err(dev, "Failed to register power supply\n");
1172d01363daSHans de Goede 		goto err_unregister_usb_notifier;
1173d01363daSHans de Goede 	}
1174d01363daSHans de Goede 
11758c0984e5SSebastian Reichel 	ret = devm_request_threaded_irq(dev, client->irq, NULL,
11768c0984e5SSebastian Reichel 					bq25890_irq_handler_thread,
11778c0984e5SSebastian Reichel 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
11788c0984e5SSebastian Reichel 					BQ25890_IRQ_PIN, bq);
11798c0984e5SSebastian Reichel 	if (ret)
1180d01363daSHans de Goede 		goto err_unregister_usb_notifier;
11818c0984e5SSebastian Reichel 
11828c0984e5SSebastian Reichel 	return 0;
11838c0984e5SSebastian Reichel 
1184d01363daSHans de Goede err_unregister_usb_notifier:
11858c0984e5SSebastian Reichel 	if (!IS_ERR_OR_NULL(bq->usb_phy))
11868c0984e5SSebastian Reichel 		usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
11878c0984e5SSebastian Reichel 
11888c0984e5SSebastian Reichel 	return ret;
11898c0984e5SSebastian Reichel }
11908c0984e5SSebastian Reichel 
11918c0984e5SSebastian Reichel static int bq25890_remove(struct i2c_client *client)
11928c0984e5SSebastian Reichel {
11938c0984e5SSebastian Reichel 	struct bq25890_device *bq = i2c_get_clientdata(client);
11948c0984e5SSebastian Reichel 
11958c0984e5SSebastian Reichel 	if (!IS_ERR_OR_NULL(bq->usb_phy))
11968c0984e5SSebastian Reichel 		usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
11978c0984e5SSebastian Reichel 
11987e3b8e35SHans de Goede 	if (!bq->skip_reset) {
11998c0984e5SSebastian Reichel 		/* reset all registers to default values */
12008c0984e5SSebastian Reichel 		bq25890_chip_reset(bq);
12017e3b8e35SHans de Goede 	}
12028c0984e5SSebastian Reichel 
12038c0984e5SSebastian Reichel 	return 0;
12048c0984e5SSebastian Reichel }
12058c0984e5SSebastian Reichel 
120679d35365SHans de Goede static void bq25890_shutdown(struct i2c_client *client)
120779d35365SHans de Goede {
120879d35365SHans de Goede 	struct bq25890_device *bq = i2c_get_clientdata(client);
120979d35365SHans de Goede 
121079d35365SHans de Goede 	/*
121179d35365SHans de Goede 	 * TODO this if + return should probably be removed, but that would
121279d35365SHans de Goede 	 * introduce a function change for boards using the usb-phy framework.
121379d35365SHans de Goede 	 * This needs to be tested on such a board before making this change.
121479d35365SHans de Goede 	 */
121579d35365SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy))
121679d35365SHans de Goede 		return;
121779d35365SHans de Goede 
121879d35365SHans de Goede 	/*
121979d35365SHans de Goede 	 * Turn off the 5v Boost regulator which outputs Vbus to the device's
122079d35365SHans de Goede 	 * Micro-USB or Type-C USB port. Leaving this on drains power and
122179d35365SHans de Goede 	 * this avoids the PMIC on some device-models seeing this as Vbus
122279d35365SHans de Goede 	 * getting inserted after shutdown, causing the device to immediately
122379d35365SHans de Goede 	 * power-up again.
122479d35365SHans de Goede 	 */
122579d35365SHans de Goede 	bq25890_set_otg_cfg(bq, 0);
122679d35365SHans de Goede }
122779d35365SHans de Goede 
12288c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
12298c0984e5SSebastian Reichel static int bq25890_suspend(struct device *dev)
12308c0984e5SSebastian Reichel {
12318c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
12328c0984e5SSebastian Reichel 
12338c0984e5SSebastian Reichel 	/*
12348c0984e5SSebastian Reichel 	 * If charger is removed, while in suspend, make sure ADC is diabled
12358c0984e5SSebastian Reichel 	 * since it consumes slightly more power.
12368c0984e5SSebastian Reichel 	 */
123721d90edaSMichał Mirosław 	return bq25890_field_write(bq, F_CONV_RATE, 0);
12388c0984e5SSebastian Reichel }
12398c0984e5SSebastian Reichel 
12408c0984e5SSebastian Reichel static int bq25890_resume(struct device *dev)
12418c0984e5SSebastian Reichel {
12428c0984e5SSebastian Reichel 	int ret;
12438c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
12448c0984e5SSebastian Reichel 
124572d9cd9cSMichał Mirosław 	mutex_lock(&bq->lock);
124672d9cd9cSMichał Mirosław 
124772d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &bq->state);
12488c0984e5SSebastian Reichel 	if (ret < 0)
1249cf5701bfSDan Carpenter 		goto unlock;
12508c0984e5SSebastian Reichel 
12518c0984e5SSebastian Reichel 	/* Re-enable ADC only if charger is plugged in. */
125272d9cd9cSMichał Mirosław 	if (bq->state.online) {
125321d90edaSMichał Mirosław 		ret = bq25890_field_write(bq, F_CONV_RATE, 1);
12548c0984e5SSebastian Reichel 		if (ret < 0)
1255cf5701bfSDan Carpenter 			goto unlock;
12568c0984e5SSebastian Reichel 	}
12578c0984e5SSebastian Reichel 
12588c0984e5SSebastian Reichel 	/* signal userspace, maybe state changed while suspended */
12598c0984e5SSebastian Reichel 	power_supply_changed(bq->charger);
12608c0984e5SSebastian Reichel 
1261cf5701bfSDan Carpenter unlock:
126272d9cd9cSMichał Mirosław 	mutex_unlock(&bq->lock);
126372d9cd9cSMichał Mirosław 
1264cf5701bfSDan Carpenter 	return ret;
12658c0984e5SSebastian Reichel }
12668c0984e5SSebastian Reichel #endif
12678c0984e5SSebastian Reichel 
12688c0984e5SSebastian Reichel static const struct dev_pm_ops bq25890_pm = {
12698c0984e5SSebastian Reichel 	SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume)
12708c0984e5SSebastian Reichel };
12718c0984e5SSebastian Reichel 
12728c0984e5SSebastian Reichel static const struct i2c_device_id bq25890_i2c_ids[] = {
12738c0984e5SSebastian Reichel 	{ "bq25890", 0 },
127446aa27e7SYauhen Kharuzhy 	{ "bq25892", 0 },
127546aa27e7SYauhen Kharuzhy 	{ "bq25895", 0 },
127646aa27e7SYauhen Kharuzhy 	{ "bq25896", 0 },
12778c0984e5SSebastian Reichel 	{},
12788c0984e5SSebastian Reichel };
12798c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids);
12808c0984e5SSebastian Reichel 
12818c0984e5SSebastian Reichel static const struct of_device_id bq25890_of_match[] = {
12828c0984e5SSebastian Reichel 	{ .compatible = "ti,bq25890", },
128346aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25892", },
128446aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25895", },
128546aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25896", },
12868c0984e5SSebastian Reichel 	{ },
12878c0984e5SSebastian Reichel };
12888c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, bq25890_of_match);
12898c0984e5SSebastian Reichel 
129002067dc9SKrzysztof Kozlowski #ifdef CONFIG_ACPI
12918c0984e5SSebastian Reichel static const struct acpi_device_id bq25890_acpi_match[] = {
12928c0984e5SSebastian Reichel 	{"BQ258900", 0},
12938c0984e5SSebastian Reichel 	{},
12948c0984e5SSebastian Reichel };
12958c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match);
129602067dc9SKrzysztof Kozlowski #endif
12978c0984e5SSebastian Reichel 
12988c0984e5SSebastian Reichel static struct i2c_driver bq25890_driver = {
12998c0984e5SSebastian Reichel 	.driver = {
13008c0984e5SSebastian Reichel 		.name = "bq25890-charger",
13018c0984e5SSebastian Reichel 		.of_match_table = of_match_ptr(bq25890_of_match),
13028c0984e5SSebastian Reichel 		.acpi_match_table = ACPI_PTR(bq25890_acpi_match),
13038c0984e5SSebastian Reichel 		.pm = &bq25890_pm,
13048c0984e5SSebastian Reichel 	},
13058c0984e5SSebastian Reichel 	.probe = bq25890_probe,
13068c0984e5SSebastian Reichel 	.remove = bq25890_remove,
130779d35365SHans de Goede 	.shutdown = bq25890_shutdown,
13088c0984e5SSebastian Reichel 	.id_table = bq25890_i2c_ids,
13098c0984e5SSebastian Reichel };
13108c0984e5SSebastian Reichel module_i2c_driver(bq25890_driver);
13118c0984e5SSebastian Reichel 
13128c0984e5SSebastian Reichel MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
13138c0984e5SSebastian Reichel MODULE_DESCRIPTION("bq25890 charger driver");
13148c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
1315