xref: /openbmc/linux/drivers/power/supply/bq25890_charger.c (revision d54bf877fd878ee45cbc88d399fb98b0b1c4484d)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28c0984e5SSebastian Reichel /*
38c0984e5SSebastian Reichel  * TI BQ25890 charger driver
48c0984e5SSebastian Reichel  *
58c0984e5SSebastian Reichel  * Copyright (C) 2015 Intel Corporation
68c0984e5SSebastian Reichel  */
78c0984e5SSebastian Reichel 
88c0984e5SSebastian Reichel #include <linux/module.h>
98c0984e5SSebastian Reichel #include <linux/i2c.h>
108c0984e5SSebastian Reichel #include <linux/power_supply.h>
1179d35365SHans de Goede #include <linux/power/bq25890_charger.h>
128c0984e5SSebastian Reichel #include <linux/regmap.h>
1379d35365SHans de Goede #include <linux/regulator/driver.h>
148c0984e5SSebastian Reichel #include <linux/types.h>
158c0984e5SSebastian Reichel #include <linux/gpio/consumer.h>
168c0984e5SSebastian Reichel #include <linux/interrupt.h>
178c0984e5SSebastian Reichel #include <linux/delay.h>
188c0984e5SSebastian Reichel #include <linux/usb/phy.h>
198c0984e5SSebastian Reichel 
208c0984e5SSebastian Reichel #include <linux/acpi.h>
218c0984e5SSebastian Reichel #include <linux/of.h>
228c0984e5SSebastian Reichel 
238c0984e5SSebastian Reichel #define BQ25890_MANUFACTURER		"Texas Instruments"
248c0984e5SSebastian Reichel #define BQ25890_IRQ_PIN			"bq25890_irq"
258c0984e5SSebastian Reichel 
268c0984e5SSebastian Reichel #define BQ25890_ID			3
275c35ba9bSAngus Ainslie (Purism) #define BQ25895_ID			7
282e1a2ddeSAngus Ainslie (Purism) #define BQ25896_ID			0
298c0984e5SSebastian Reichel 
3048f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_START_DELAY	(5 * HZ)
3148f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_MAX_TRIES		6
3248f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_VBUS_MARGIN_uV	1000000
3348f45b09SYauhen Kharuzhy 
34d20267c9SYauhen Kharuzhy enum bq25890_chip_version {
35d20267c9SYauhen Kharuzhy 	BQ25890,
36d20267c9SYauhen Kharuzhy 	BQ25892,
37d20267c9SYauhen Kharuzhy 	BQ25895,
38d20267c9SYauhen Kharuzhy 	BQ25896,
39d20267c9SYauhen Kharuzhy };
40d20267c9SYauhen Kharuzhy 
415956fca7SMichał Mirosław static const char *const bq25890_chip_name[] = {
425956fca7SMichał Mirosław 	"BQ25890",
435956fca7SMichał Mirosław 	"BQ25892",
445956fca7SMichał Mirosław 	"BQ25895",
455956fca7SMichał Mirosław 	"BQ25896",
465956fca7SMichał Mirosław };
475956fca7SMichał Mirosław 
488c0984e5SSebastian Reichel enum bq25890_fields {
49766873c1SYauhen Kharuzhy 	F_EN_HIZ, F_EN_ILIM, F_IINLIM,				     /* Reg00 */
508c0984e5SSebastian Reichel 	F_BHOT, F_BCOLD, F_VINDPM_OFS,				     /* Reg01 */
518c0984e5SSebastian Reichel 	F_CONV_START, F_CONV_RATE, F_BOOSTF, F_ICO_EN,
528c0984e5SSebastian Reichel 	F_HVDCP_EN, F_MAXC_EN, F_FORCE_DPM, F_AUTO_DPDM_EN,	     /* Reg02 */
53d20267c9SYauhen Kharuzhy 	F_BAT_LOAD_EN, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_SYSVMIN,
54d20267c9SYauhen Kharuzhy 	F_MIN_VBAT_SEL,						     /* Reg03 */
558c0984e5SSebastian Reichel 	F_PUMPX_EN, F_ICHG,					     /* Reg04 */
568c0984e5SSebastian Reichel 	F_IPRECHG, F_ITERM,					     /* Reg05 */
578c0984e5SSebastian Reichel 	F_VREG, F_BATLOWV, F_VRECHG,				     /* Reg06 */
588c0984e5SSebastian Reichel 	F_TERM_EN, F_STAT_DIS, F_WD, F_TMR_EN, F_CHG_TMR,
598c0984e5SSebastian Reichel 	F_JEITA_ISET,						     /* Reg07 */
608c0984e5SSebastian Reichel 	F_BATCMP, F_VCLAMP, F_TREG,				     /* Reg08 */
618c0984e5SSebastian Reichel 	F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JEITA_VSET,
628c0984e5SSebastian Reichel 	F_BATFET_DLY, F_BATFET_RST_EN, F_PUMPX_UP, F_PUMPX_DN,	     /* Reg09 */
63d20267c9SYauhen Kharuzhy 	F_BOOSTV, F_PFM_OTG_DIS, F_BOOSTI,			     /* Reg0A */
64d20267c9SYauhen Kharuzhy 	F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_SDP_STAT, F_0B_RSVD,
65d20267c9SYauhen Kharuzhy 	F_VSYS_STAT,						     /* Reg0B */
668c0984e5SSebastian Reichel 	F_WD_FAULT, F_BOOST_FAULT, F_CHG_FAULT, F_BAT_FAULT,
678c0984e5SSebastian Reichel 	F_NTC_FAULT,						     /* Reg0C */
688c0984e5SSebastian Reichel 	F_FORCE_VINDPM, F_VINDPM,				     /* Reg0D */
698c0984e5SSebastian Reichel 	F_THERM_STAT, F_BATV,					     /* Reg0E */
708c0984e5SSebastian Reichel 	F_SYSV,							     /* Reg0F */
718c0984e5SSebastian Reichel 	F_TSPCT,						     /* Reg10 */
728c0984e5SSebastian Reichel 	F_VBUS_GD, F_VBUSV,					     /* Reg11 */
738c0984e5SSebastian Reichel 	F_ICHGR,						     /* Reg12 */
748c0984e5SSebastian Reichel 	F_VDPM_STAT, F_IDPM_STAT, F_IDPM_LIM,			     /* Reg13 */
758c0984e5SSebastian Reichel 	F_REG_RST, F_ICO_OPTIMIZED, F_PN, F_TS_PROFILE, F_DEV_REV,   /* Reg14 */
768c0984e5SSebastian Reichel 
778c0984e5SSebastian Reichel 	F_MAX_FIELDS
788c0984e5SSebastian Reichel };
798c0984e5SSebastian Reichel 
808c0984e5SSebastian Reichel /* initial field values, converted to register values */
818c0984e5SSebastian Reichel struct bq25890_init_data {
828c0984e5SSebastian Reichel 	u8 ichg;	/* charge current		*/
838c0984e5SSebastian Reichel 	u8 vreg;	/* regulation voltage		*/
848c0984e5SSebastian Reichel 	u8 iterm;	/* termination current		*/
858c0984e5SSebastian Reichel 	u8 iprechg;	/* precharge current		*/
868c0984e5SSebastian Reichel 	u8 sysvmin;	/* minimum system voltage limit */
878c0984e5SSebastian Reichel 	u8 boostv;	/* boost regulation voltage	*/
888c0984e5SSebastian Reichel 	u8 boosti;	/* boost current limit		*/
898c0984e5SSebastian Reichel 	u8 boostf;	/* boost frequency		*/
908c0984e5SSebastian Reichel 	u8 ilim_en;	/* enable ILIM pin		*/
918c0984e5SSebastian Reichel 	u8 treg;	/* thermal regulation threshold */
9272408329SMichał Mirosław 	u8 rbatcomp;	/* IBAT sense resistor value    */
9372408329SMichał Mirosław 	u8 vclamp;	/* IBAT compensation voltage limit */
948c0984e5SSebastian Reichel };
958c0984e5SSebastian Reichel 
968c0984e5SSebastian Reichel struct bq25890_state {
978c0984e5SSebastian Reichel 	u8 online;
98c688e0c4SMarek Vasut 	u8 hiz;
998c0984e5SSebastian Reichel 	u8 chrg_status;
1008c0984e5SSebastian Reichel 	u8 chrg_fault;
1018c0984e5SSebastian Reichel 	u8 vsys_status;
1028c0984e5SSebastian Reichel 	u8 boost_fault;
1038c0984e5SSebastian Reichel 	u8 bat_fault;
104c562a43aSYauhen Kharuzhy 	u8 ntc_fault;
1058c0984e5SSebastian Reichel };
1068c0984e5SSebastian Reichel 
1078c0984e5SSebastian Reichel struct bq25890_device {
1088c0984e5SSebastian Reichel 	struct i2c_client *client;
1098c0984e5SSebastian Reichel 	struct device *dev;
1108c0984e5SSebastian Reichel 	struct power_supply *charger;
111*d54bf877SHans de Goede 	struct power_supply *secondary_chrg;
1124e9498b8SHans de Goede 	struct power_supply_desc desc;
1134e9498b8SHans de Goede 	char name[28]; /* "bq25890-charger-%d" */
1144e9498b8SHans de Goede 	int id;
1158c0984e5SSebastian Reichel 
1168c0984e5SSebastian Reichel 	struct usb_phy *usb_phy;
1178c0984e5SSebastian Reichel 	struct notifier_block usb_nb;
1188c0984e5SSebastian Reichel 	struct work_struct usb_work;
11948f45b09SYauhen Kharuzhy 	struct delayed_work pump_express_work;
1208c0984e5SSebastian Reichel 	unsigned long usb_event;
1218c0984e5SSebastian Reichel 
1228c0984e5SSebastian Reichel 	struct regmap *rmap;
1238c0984e5SSebastian Reichel 	struct regmap_field *rmap_fields[F_MAX_FIELDS];
1248c0984e5SSebastian Reichel 
1257e3b8e35SHans de Goede 	bool skip_reset;
12640428bd4SHans de Goede 	bool read_back_init_data;
127c688e0c4SMarek Vasut 	bool force_hiz;
12848f45b09SYauhen Kharuzhy 	u32 pump_express_vbus_max;
129d20267c9SYauhen Kharuzhy 	enum bq25890_chip_version chip_version;
1308c0984e5SSebastian Reichel 	struct bq25890_init_data init_data;
1318c0984e5SSebastian Reichel 	struct bq25890_state state;
1328c0984e5SSebastian Reichel 
1338c0984e5SSebastian Reichel 	struct mutex lock; /* protect state data */
1348c0984e5SSebastian Reichel };
1358c0984e5SSebastian Reichel 
1364e9498b8SHans de Goede static DEFINE_IDR(bq25890_id);
1374e9498b8SHans de Goede static DEFINE_MUTEX(bq25890_id_mutex);
1384e9498b8SHans de Goede 
1398c0984e5SSebastian Reichel static const struct regmap_range bq25890_readonly_reg_ranges[] = {
1408c0984e5SSebastian Reichel 	regmap_reg_range(0x0b, 0x0c),
1418c0984e5SSebastian Reichel 	regmap_reg_range(0x0e, 0x13),
1428c0984e5SSebastian Reichel };
1438c0984e5SSebastian Reichel 
1448c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_writeable_regs = {
1458c0984e5SSebastian Reichel 	.no_ranges = bq25890_readonly_reg_ranges,
1468c0984e5SSebastian Reichel 	.n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges),
1478c0984e5SSebastian Reichel };
1488c0984e5SSebastian Reichel 
1498c0984e5SSebastian Reichel static const struct regmap_range bq25890_volatile_reg_ranges[] = {
1508c0984e5SSebastian Reichel 	regmap_reg_range(0x00, 0x00),
15121d90edaSMichał Mirosław 	regmap_reg_range(0x02, 0x02),
1528c0984e5SSebastian Reichel 	regmap_reg_range(0x09, 0x09),
153d20267c9SYauhen Kharuzhy 	regmap_reg_range(0x0b, 0x14),
1548c0984e5SSebastian Reichel };
1558c0984e5SSebastian Reichel 
1568c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_volatile_regs = {
1578c0984e5SSebastian Reichel 	.yes_ranges = bq25890_volatile_reg_ranges,
1588c0984e5SSebastian Reichel 	.n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges),
1598c0984e5SSebastian Reichel };
1608c0984e5SSebastian Reichel 
1618c0984e5SSebastian Reichel static const struct regmap_config bq25890_regmap_config = {
1628c0984e5SSebastian Reichel 	.reg_bits = 8,
1638c0984e5SSebastian Reichel 	.val_bits = 8,
1648c0984e5SSebastian Reichel 
1658c0984e5SSebastian Reichel 	.max_register = 0x14,
1668c0984e5SSebastian Reichel 	.cache_type = REGCACHE_RBTREE,
1678c0984e5SSebastian Reichel 
1688c0984e5SSebastian Reichel 	.wr_table = &bq25890_writeable_regs,
1698c0984e5SSebastian Reichel 	.volatile_table = &bq25890_volatile_regs,
1708c0984e5SSebastian Reichel };
1718c0984e5SSebastian Reichel 
1728c0984e5SSebastian Reichel static const struct reg_field bq25890_reg_fields[] = {
1738c0984e5SSebastian Reichel 	/* REG00 */
1748c0984e5SSebastian Reichel 	[F_EN_HIZ]		= REG_FIELD(0x00, 7, 7),
1758c0984e5SSebastian Reichel 	[F_EN_ILIM]		= REG_FIELD(0x00, 6, 6),
176766873c1SYauhen Kharuzhy 	[F_IINLIM]		= REG_FIELD(0x00, 0, 5),
1778c0984e5SSebastian Reichel 	/* REG01 */
1788c0984e5SSebastian Reichel 	[F_BHOT]		= REG_FIELD(0x01, 6, 7),
1798c0984e5SSebastian Reichel 	[F_BCOLD]		= REG_FIELD(0x01, 5, 5),
1808c0984e5SSebastian Reichel 	[F_VINDPM_OFS]		= REG_FIELD(0x01, 0, 4),
1818c0984e5SSebastian Reichel 	/* REG02 */
1828c0984e5SSebastian Reichel 	[F_CONV_START]		= REG_FIELD(0x02, 7, 7),
1838c0984e5SSebastian Reichel 	[F_CONV_RATE]		= REG_FIELD(0x02, 6, 6),
1848c0984e5SSebastian Reichel 	[F_BOOSTF]		= REG_FIELD(0x02, 5, 5),
1858c0984e5SSebastian Reichel 	[F_ICO_EN]		= REG_FIELD(0x02, 4, 4),
1862e1a2ddeSAngus Ainslie (Purism) 	[F_HVDCP_EN]		= REG_FIELD(0x02, 3, 3),  // reserved on BQ25896
1872e1a2ddeSAngus Ainslie (Purism) 	[F_MAXC_EN]		= REG_FIELD(0x02, 2, 2),  // reserved on BQ25896
1888c0984e5SSebastian Reichel 	[F_FORCE_DPM]		= REG_FIELD(0x02, 1, 1),
1898c0984e5SSebastian Reichel 	[F_AUTO_DPDM_EN]	= REG_FIELD(0x02, 0, 0),
1908c0984e5SSebastian Reichel 	/* REG03 */
1918c0984e5SSebastian Reichel 	[F_BAT_LOAD_EN]		= REG_FIELD(0x03, 7, 7),
1928c0984e5SSebastian Reichel 	[F_WD_RST]		= REG_FIELD(0x03, 6, 6),
1938c0984e5SSebastian Reichel 	[F_OTG_CFG]		= REG_FIELD(0x03, 5, 5),
1948c0984e5SSebastian Reichel 	[F_CHG_CFG]		= REG_FIELD(0x03, 4, 4),
1958c0984e5SSebastian Reichel 	[F_SYSVMIN]		= REG_FIELD(0x03, 1, 3),
196d20267c9SYauhen Kharuzhy 	[F_MIN_VBAT_SEL]	= REG_FIELD(0x03, 0, 0), // BQ25896 only
1978c0984e5SSebastian Reichel 	/* REG04 */
1988c0984e5SSebastian Reichel 	[F_PUMPX_EN]		= REG_FIELD(0x04, 7, 7),
1998c0984e5SSebastian Reichel 	[F_ICHG]		= REG_FIELD(0x04, 0, 6),
2008c0984e5SSebastian Reichel 	/* REG05 */
2018c0984e5SSebastian Reichel 	[F_IPRECHG]		= REG_FIELD(0x05, 4, 7),
2028c0984e5SSebastian Reichel 	[F_ITERM]		= REG_FIELD(0x05, 0, 3),
2038c0984e5SSebastian Reichel 	/* REG06 */
2048c0984e5SSebastian Reichel 	[F_VREG]		= REG_FIELD(0x06, 2, 7),
2058c0984e5SSebastian Reichel 	[F_BATLOWV]		= REG_FIELD(0x06, 1, 1),
2068c0984e5SSebastian Reichel 	[F_VRECHG]		= REG_FIELD(0x06, 0, 0),
2078c0984e5SSebastian Reichel 	/* REG07 */
2088c0984e5SSebastian Reichel 	[F_TERM_EN]		= REG_FIELD(0x07, 7, 7),
2098c0984e5SSebastian Reichel 	[F_STAT_DIS]		= REG_FIELD(0x07, 6, 6),
2108c0984e5SSebastian Reichel 	[F_WD]			= REG_FIELD(0x07, 4, 5),
2118c0984e5SSebastian Reichel 	[F_TMR_EN]		= REG_FIELD(0x07, 3, 3),
2128c0984e5SSebastian Reichel 	[F_CHG_TMR]		= REG_FIELD(0x07, 1, 2),
2135c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_ISET]		= REG_FIELD(0x07, 0, 0), // reserved on BQ25895
2148c0984e5SSebastian Reichel 	/* REG08 */
21595809139SMichał Mirosław 	[F_BATCMP]		= REG_FIELD(0x08, 5, 7),
2168c0984e5SSebastian Reichel 	[F_VCLAMP]		= REG_FIELD(0x08, 2, 4),
2178c0984e5SSebastian Reichel 	[F_TREG]		= REG_FIELD(0x08, 0, 1),
2188c0984e5SSebastian Reichel 	/* REG09 */
2198c0984e5SSebastian Reichel 	[F_FORCE_ICO]		= REG_FIELD(0x09, 7, 7),
2208c0984e5SSebastian Reichel 	[F_TMR2X_EN]		= REG_FIELD(0x09, 6, 6),
2218c0984e5SSebastian Reichel 	[F_BATFET_DIS]		= REG_FIELD(0x09, 5, 5),
2225c35ba9bSAngus Ainslie (Purism) 	[F_JEITA_VSET]		= REG_FIELD(0x09, 4, 4), // reserved on BQ25895
2238c0984e5SSebastian Reichel 	[F_BATFET_DLY]		= REG_FIELD(0x09, 3, 3),
2248c0984e5SSebastian Reichel 	[F_BATFET_RST_EN]	= REG_FIELD(0x09, 2, 2),
2258c0984e5SSebastian Reichel 	[F_PUMPX_UP]		= REG_FIELD(0x09, 1, 1),
2268c0984e5SSebastian Reichel 	[F_PUMPX_DN]		= REG_FIELD(0x09, 0, 0),
2278c0984e5SSebastian Reichel 	/* REG0A */
2288c0984e5SSebastian Reichel 	[F_BOOSTV]		= REG_FIELD(0x0A, 4, 7),
2295c35ba9bSAngus Ainslie (Purism) 	[F_BOOSTI]		= REG_FIELD(0x0A, 0, 2), // reserved on BQ25895
230d20267c9SYauhen Kharuzhy 	[F_PFM_OTG_DIS]		= REG_FIELD(0x0A, 3, 3), // BQ25896 only
2318c0984e5SSebastian Reichel 	/* REG0B */
2328c0984e5SSebastian Reichel 	[F_VBUS_STAT]		= REG_FIELD(0x0B, 5, 7),
2338c0984e5SSebastian Reichel 	[F_CHG_STAT]		= REG_FIELD(0x0B, 3, 4),
2348c0984e5SSebastian Reichel 	[F_PG_STAT]		= REG_FIELD(0x0B, 2, 2),
2352e1a2ddeSAngus Ainslie (Purism) 	[F_SDP_STAT]		= REG_FIELD(0x0B, 1, 1), // reserved on BQ25896
2368c0984e5SSebastian Reichel 	[F_VSYS_STAT]		= REG_FIELD(0x0B, 0, 0),
2378c0984e5SSebastian Reichel 	/* REG0C */
2388c0984e5SSebastian Reichel 	[F_WD_FAULT]		= REG_FIELD(0x0C, 7, 7),
2398c0984e5SSebastian Reichel 	[F_BOOST_FAULT]		= REG_FIELD(0x0C, 6, 6),
2408c0984e5SSebastian Reichel 	[F_CHG_FAULT]		= REG_FIELD(0x0C, 4, 5),
2418c0984e5SSebastian Reichel 	[F_BAT_FAULT]		= REG_FIELD(0x0C, 3, 3),
2428c0984e5SSebastian Reichel 	[F_NTC_FAULT]		= REG_FIELD(0x0C, 0, 2),
2438c0984e5SSebastian Reichel 	/* REG0D */
2448c0984e5SSebastian Reichel 	[F_FORCE_VINDPM]	= REG_FIELD(0x0D, 7, 7),
2458c0984e5SSebastian Reichel 	[F_VINDPM]		= REG_FIELD(0x0D, 0, 6),
2468c0984e5SSebastian Reichel 	/* REG0E */
2478c0984e5SSebastian Reichel 	[F_THERM_STAT]		= REG_FIELD(0x0E, 7, 7),
2488c0984e5SSebastian Reichel 	[F_BATV]		= REG_FIELD(0x0E, 0, 6),
2498c0984e5SSebastian Reichel 	/* REG0F */
2508c0984e5SSebastian Reichel 	[F_SYSV]		= REG_FIELD(0x0F, 0, 6),
2518c0984e5SSebastian Reichel 	/* REG10 */
2528c0984e5SSebastian Reichel 	[F_TSPCT]		= REG_FIELD(0x10, 0, 6),
2538c0984e5SSebastian Reichel 	/* REG11 */
2548c0984e5SSebastian Reichel 	[F_VBUS_GD]		= REG_FIELD(0x11, 7, 7),
2558c0984e5SSebastian Reichel 	[F_VBUSV]		= REG_FIELD(0x11, 0, 6),
2568c0984e5SSebastian Reichel 	/* REG12 */
2578c0984e5SSebastian Reichel 	[F_ICHGR]		= REG_FIELD(0x12, 0, 6),
2588c0984e5SSebastian Reichel 	/* REG13 */
2598c0984e5SSebastian Reichel 	[F_VDPM_STAT]		= REG_FIELD(0x13, 7, 7),
2608c0984e5SSebastian Reichel 	[F_IDPM_STAT]		= REG_FIELD(0x13, 6, 6),
2618c0984e5SSebastian Reichel 	[F_IDPM_LIM]		= REG_FIELD(0x13, 0, 5),
2628c0984e5SSebastian Reichel 	/* REG14 */
2638c0984e5SSebastian Reichel 	[F_REG_RST]		= REG_FIELD(0x14, 7, 7),
2648c0984e5SSebastian Reichel 	[F_ICO_OPTIMIZED]	= REG_FIELD(0x14, 6, 6),
2658c0984e5SSebastian Reichel 	[F_PN]			= REG_FIELD(0x14, 3, 5),
2668c0984e5SSebastian Reichel 	[F_TS_PROFILE]		= REG_FIELD(0x14, 2, 2),
2678c0984e5SSebastian Reichel 	[F_DEV_REV]		= REG_FIELD(0x14, 0, 1)
2688c0984e5SSebastian Reichel };
2698c0984e5SSebastian Reichel 
2708c0984e5SSebastian Reichel /*
2718c0984e5SSebastian Reichel  * Most of the val -> idx conversions can be computed, given the minimum,
2728c0984e5SSebastian Reichel  * maximum and the step between values. For the rest of conversions, we use
2738c0984e5SSebastian Reichel  * lookup tables.
2748c0984e5SSebastian Reichel  */
2758c0984e5SSebastian Reichel enum bq25890_table_ids {
2768c0984e5SSebastian Reichel 	/* range tables */
2778c0984e5SSebastian Reichel 	TBL_ICHG,
2788c0984e5SSebastian Reichel 	TBL_ITERM,
279766873c1SYauhen Kharuzhy 	TBL_IINLIM,
2808c0984e5SSebastian Reichel 	TBL_VREG,
2818c0984e5SSebastian Reichel 	TBL_BOOSTV,
2828c0984e5SSebastian Reichel 	TBL_SYSVMIN,
28348f45b09SYauhen Kharuzhy 	TBL_VBUSV,
28472408329SMichał Mirosław 	TBL_VBATCOMP,
28572408329SMichał Mirosław 	TBL_RBATCOMP,
2868c0984e5SSebastian Reichel 
2878c0984e5SSebastian Reichel 	/* lookup tables */
2888c0984e5SSebastian Reichel 	TBL_TREG,
2898c0984e5SSebastian Reichel 	TBL_BOOSTI,
2909652c024SAngus Ainslie 	TBL_TSPCT,
2918c0984e5SSebastian Reichel };
2928c0984e5SSebastian Reichel 
2938c0984e5SSebastian Reichel /* Thermal Regulation Threshold lookup table, in degrees Celsius */
2948c0984e5SSebastian Reichel static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 };
2958c0984e5SSebastian Reichel 
2968c0984e5SSebastian Reichel #define BQ25890_TREG_TBL_SIZE		ARRAY_SIZE(bq25890_treg_tbl)
2978c0984e5SSebastian Reichel 
2988c0984e5SSebastian Reichel /* Boost mode current limit lookup table, in uA */
2998c0984e5SSebastian Reichel static const u32 bq25890_boosti_tbl[] = {
3008c0984e5SSebastian Reichel 	500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000
3018c0984e5SSebastian Reichel };
3028c0984e5SSebastian Reichel 
3038c0984e5SSebastian Reichel #define BQ25890_BOOSTI_TBL_SIZE		ARRAY_SIZE(bq25890_boosti_tbl)
3048c0984e5SSebastian Reichel 
3059652c024SAngus Ainslie /* NTC 10K temperature lookup table in tenths of a degree */
3069652c024SAngus Ainslie static const u32 bq25890_tspct_tbl[] = {
3079652c024SAngus Ainslie 	850, 840, 830, 820, 810, 800, 790, 780,
3089652c024SAngus Ainslie 	770, 760, 750, 740, 730, 720, 710, 700,
3099652c024SAngus Ainslie 	690, 685, 680, 675, 670, 660, 650, 645,
3109652c024SAngus Ainslie 	640, 630, 620, 615, 610, 600, 590, 585,
3119652c024SAngus Ainslie 	580, 570, 565, 560, 550, 540, 535, 530,
3129652c024SAngus Ainslie 	520, 515, 510, 500, 495, 490, 480, 475,
3139652c024SAngus Ainslie 	470, 460, 455, 450, 440, 435, 430, 425,
3149652c024SAngus Ainslie 	420, 410, 405, 400, 390, 385, 380, 370,
3159652c024SAngus Ainslie 	365, 360, 355, 350, 340, 335, 330, 320,
3169652c024SAngus Ainslie 	310, 305, 300, 290, 285, 280, 275, 270,
3179652c024SAngus Ainslie 	260, 250, 245, 240, 230, 225, 220, 210,
3189652c024SAngus Ainslie 	205, 200, 190, 180, 175, 170, 160, 150,
3199652c024SAngus Ainslie 	145, 140, 130, 120, 115, 110, 100, 90,
3209652c024SAngus Ainslie 	80, 70, 60, 50, 40, 30, 20, 10,
3219652c024SAngus Ainslie 	0, -10, -20, -30, -40, -60, -70, -80,
3229652c024SAngus Ainslie 	-90, -10, -120, -140, -150, -170, -190, -210,
3239652c024SAngus Ainslie };
3249652c024SAngus Ainslie 
3259652c024SAngus Ainslie #define BQ25890_TSPCT_TBL_SIZE		ARRAY_SIZE(bq25890_tspct_tbl)
3269652c024SAngus Ainslie 
3278c0984e5SSebastian Reichel struct bq25890_range {
3288c0984e5SSebastian Reichel 	u32 min;
3298c0984e5SSebastian Reichel 	u32 max;
3308c0984e5SSebastian Reichel 	u32 step;
3318c0984e5SSebastian Reichel };
3328c0984e5SSebastian Reichel 
3338c0984e5SSebastian Reichel struct bq25890_lookup {
3348c0984e5SSebastian Reichel 	const u32 *tbl;
3358c0984e5SSebastian Reichel 	u32 size;
3368c0984e5SSebastian Reichel };
3378c0984e5SSebastian Reichel 
3388c0984e5SSebastian Reichel static const union {
3398c0984e5SSebastian Reichel 	struct bq25890_range  rt;
3408c0984e5SSebastian Reichel 	struct bq25890_lookup lt;
3418c0984e5SSebastian Reichel } bq25890_tables[] = {
3428c0984e5SSebastian Reichel 	/* range tables */
343d20267c9SYauhen Kharuzhy 	/* TODO: BQ25896 has max ICHG 3008 mA */
3448c0984e5SSebastian Reichel 	[TBL_ICHG] =	 { .rt = {0,        5056000, 64000} },	 /* uA */
3458c0984e5SSebastian Reichel 	[TBL_ITERM] =	 { .rt = {64000,    1024000, 64000} },	 /* uA */
346766873c1SYauhen Kharuzhy 	[TBL_IINLIM] =   { .rt = {100000,   3250000, 50000} },	 /* uA */
3478c0984e5SSebastian Reichel 	[TBL_VREG] =	 { .rt = {3840000,  4608000, 16000} },	 /* uV */
3488c0984e5SSebastian Reichel 	[TBL_BOOSTV] =	 { .rt = {4550000,  5510000, 64000} },	 /* uV */
3498c0984e5SSebastian Reichel 	[TBL_SYSVMIN] =  { .rt = {3000000,  3700000, 100000} },	 /* uV */
35048f45b09SYauhen Kharuzhy 	[TBL_VBUSV] =	 { .rt = {2600000, 15300000, 100000} },	 /* uV */
35172408329SMichał Mirosław 	[TBL_VBATCOMP] = { .rt = {0,         224000, 32000} },	 /* uV */
35272408329SMichał Mirosław 	[TBL_RBATCOMP] = { .rt = {0,         140000, 20000} },	 /* uOhm */
3538c0984e5SSebastian Reichel 
3548c0984e5SSebastian Reichel 	/* lookup tables */
3558c0984e5SSebastian Reichel 	[TBL_TREG] =	{ .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} },
3569652c024SAngus Ainslie 	[TBL_BOOSTI] =	{ .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} },
3579652c024SAngus Ainslie 	[TBL_TSPCT] =	{ .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} }
3588c0984e5SSebastian Reichel };
3598c0984e5SSebastian Reichel 
3608c0984e5SSebastian Reichel static int bq25890_field_read(struct bq25890_device *bq,
3618c0984e5SSebastian Reichel 			      enum bq25890_fields field_id)
3628c0984e5SSebastian Reichel {
3638c0984e5SSebastian Reichel 	int ret;
3648c0984e5SSebastian Reichel 	int val;
3658c0984e5SSebastian Reichel 
3668c0984e5SSebastian Reichel 	ret = regmap_field_read(bq->rmap_fields[field_id], &val);
3678c0984e5SSebastian Reichel 	if (ret < 0)
3688c0984e5SSebastian Reichel 		return ret;
3698c0984e5SSebastian Reichel 
3708c0984e5SSebastian Reichel 	return val;
3718c0984e5SSebastian Reichel }
3728c0984e5SSebastian Reichel 
3738c0984e5SSebastian Reichel static int bq25890_field_write(struct bq25890_device *bq,
3748c0984e5SSebastian Reichel 			       enum bq25890_fields field_id, u8 val)
3758c0984e5SSebastian Reichel {
3768c0984e5SSebastian Reichel 	return regmap_field_write(bq->rmap_fields[field_id], val);
3778c0984e5SSebastian Reichel }
3788c0984e5SSebastian Reichel 
3798c0984e5SSebastian Reichel static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id)
3808c0984e5SSebastian Reichel {
3818c0984e5SSebastian Reichel 	u8 idx;
3828c0984e5SSebastian Reichel 
3838c0984e5SSebastian Reichel 	if (id >= TBL_TREG) {
3848c0984e5SSebastian Reichel 		const u32 *tbl = bq25890_tables[id].lt.tbl;
3858c0984e5SSebastian Reichel 		u32 tbl_size = bq25890_tables[id].lt.size;
3868c0984e5SSebastian Reichel 
3878c0984e5SSebastian Reichel 		for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++)
3888c0984e5SSebastian Reichel 			;
3898c0984e5SSebastian Reichel 	} else {
3908c0984e5SSebastian Reichel 		const struct bq25890_range *rtbl = &bq25890_tables[id].rt;
3918c0984e5SSebastian Reichel 		u8 rtbl_size;
3928c0984e5SSebastian Reichel 
3938c0984e5SSebastian Reichel 		rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1;
3948c0984e5SSebastian Reichel 
3958c0984e5SSebastian Reichel 		for (idx = 1;
3968c0984e5SSebastian Reichel 		     idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value);
3978c0984e5SSebastian Reichel 		     idx++)
3988c0984e5SSebastian Reichel 			;
3998c0984e5SSebastian Reichel 	}
4008c0984e5SSebastian Reichel 
4018c0984e5SSebastian Reichel 	return idx - 1;
4028c0984e5SSebastian Reichel }
4038c0984e5SSebastian Reichel 
4048c0984e5SSebastian Reichel static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id)
4058c0984e5SSebastian Reichel {
4068c0984e5SSebastian Reichel 	const struct bq25890_range *rtbl;
4078c0984e5SSebastian Reichel 
4088c0984e5SSebastian Reichel 	/* lookup table? */
4098c0984e5SSebastian Reichel 	if (id >= TBL_TREG)
4108c0984e5SSebastian Reichel 		return bq25890_tables[id].lt.tbl[idx];
4118c0984e5SSebastian Reichel 
4128c0984e5SSebastian Reichel 	/* range table */
4138c0984e5SSebastian Reichel 	rtbl = &bq25890_tables[id].rt;
4148c0984e5SSebastian Reichel 
4158c0984e5SSebastian Reichel 	return (rtbl->min + idx * rtbl->step);
4168c0984e5SSebastian Reichel }
4178c0984e5SSebastian Reichel 
4188c0984e5SSebastian Reichel enum bq25890_status {
4198c0984e5SSebastian Reichel 	STATUS_NOT_CHARGING,
4208c0984e5SSebastian Reichel 	STATUS_PRE_CHARGING,
4218c0984e5SSebastian Reichel 	STATUS_FAST_CHARGING,
4228c0984e5SSebastian Reichel 	STATUS_TERMINATION_DONE,
4238c0984e5SSebastian Reichel };
4248c0984e5SSebastian Reichel 
4258c0984e5SSebastian Reichel enum bq25890_chrg_fault {
4268c0984e5SSebastian Reichel 	CHRG_FAULT_NORMAL,
4278c0984e5SSebastian Reichel 	CHRG_FAULT_INPUT,
4288c0984e5SSebastian Reichel 	CHRG_FAULT_THERMAL_SHUTDOWN,
4298c0984e5SSebastian Reichel 	CHRG_FAULT_TIMER_EXPIRED,
4308c0984e5SSebastian Reichel };
4318c0984e5SSebastian Reichel 
432c562a43aSYauhen Kharuzhy enum bq25890_ntc_fault {
433c562a43aSYauhen Kharuzhy 	NTC_FAULT_NORMAL = 0,
434c562a43aSYauhen Kharuzhy 	NTC_FAULT_WARM = 2,
435c562a43aSYauhen Kharuzhy 	NTC_FAULT_COOL = 3,
436c562a43aSYauhen Kharuzhy 	NTC_FAULT_COLD = 5,
437c562a43aSYauhen Kharuzhy 	NTC_FAULT_HOT = 6,
438c562a43aSYauhen Kharuzhy };
439c562a43aSYauhen Kharuzhy 
44021d90edaSMichał Mirosław static bool bq25890_is_adc_property(enum power_supply_property psp)
44121d90edaSMichał Mirosław {
44221d90edaSMichał Mirosław 	switch (psp) {
44321d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
44421d90edaSMichał Mirosław 	case POWER_SUPPLY_PROP_CURRENT_NOW:
4459652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
44621d90edaSMichał Mirosław 		return true;
44721d90edaSMichał Mirosław 
44821d90edaSMichał Mirosław 	default:
44921d90edaSMichał Mirosław 		return false;
45021d90edaSMichał Mirosław 	}
45121d90edaSMichał Mirosław }
45221d90edaSMichał Mirosław 
4533b4df57bSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq);
4543b4df57bSMichał Mirosław 
45548f45b09SYauhen Kharuzhy static int bq25890_get_vbus_voltage(struct bq25890_device *bq)
45648f45b09SYauhen Kharuzhy {
45748f45b09SYauhen Kharuzhy 	int ret;
45848f45b09SYauhen Kharuzhy 
45948f45b09SYauhen Kharuzhy 	ret = bq25890_field_read(bq, F_VBUSV);
46048f45b09SYauhen Kharuzhy 	if (ret < 0)
46148f45b09SYauhen Kharuzhy 		return ret;
46248f45b09SYauhen Kharuzhy 
46348f45b09SYauhen Kharuzhy 	return bq25890_find_val(ret, TBL_VBUSV);
46448f45b09SYauhen Kharuzhy }
46548f45b09SYauhen Kharuzhy 
466d1b25092SMarek Vasut static void bq25890_update_state(struct bq25890_device *bq,
4678c0984e5SSebastian Reichel 				 enum power_supply_property psp,
468d1b25092SMarek Vasut 				 struct bq25890_state *state)
4698c0984e5SSebastian Reichel {
47021d90edaSMichał Mirosław 	bool do_adc_conv;
47121d90edaSMichał Mirosław 	int ret;
4728c0984e5SSebastian Reichel 
4738c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
4743b4df57bSMichał Mirosław 	/* update state in case we lost an interrupt */
4753b4df57bSMichał Mirosław 	__bq25890_handle_irq(bq);
476d1b25092SMarek Vasut 	*state = bq->state;
477dee0df84SHans de Goede 	do_adc_conv = (!state->online || state->hiz) && bq25890_is_adc_property(psp);
47821d90edaSMichał Mirosław 	if (do_adc_conv)
47921d90edaSMichał Mirosław 		bq25890_field_write(bq, F_CONV_START, 1);
4808c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
4818c0984e5SSebastian Reichel 
48221d90edaSMichał Mirosław 	if (do_adc_conv)
48321d90edaSMichał Mirosław 		regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START],
48421d90edaSMichał Mirosław 			ret, !ret, 25000, 1000000);
485d1b25092SMarek Vasut }
486d1b25092SMarek Vasut 
487d1b25092SMarek Vasut static int bq25890_power_supply_get_property(struct power_supply *psy,
488d1b25092SMarek Vasut 					     enum power_supply_property psp,
489d1b25092SMarek Vasut 					     union power_supply_propval *val)
490d1b25092SMarek Vasut {
491d1b25092SMarek Vasut 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
492d1b25092SMarek Vasut 	struct bq25890_state state;
493d1b25092SMarek Vasut 	int ret;
494d1b25092SMarek Vasut 
495d1b25092SMarek Vasut 	bq25890_update_state(bq, psp, &state);
49621d90edaSMichał Mirosław 
4978c0984e5SSebastian Reichel 	switch (psp) {
4988c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_STATUS:
499c688e0c4SMarek Vasut 		if (!state.online || state.hiz)
5008c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
5018c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_NOT_CHARGING)
5028c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
5038c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_PRE_CHARGING ||
5048c0984e5SSebastian Reichel 			 state.chrg_status == STATUS_FAST_CHARGING)
5058c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
5068c0984e5SSebastian Reichel 		else if (state.chrg_status == STATUS_TERMINATION_DONE)
5078c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_FULL;
5088c0984e5SSebastian Reichel 		else
5098c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
5108c0984e5SSebastian Reichel 
5118c0984e5SSebastian Reichel 		break;
5128c0984e5SSebastian Reichel 
513b302a0aeSMichał Mirosław 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
514c688e0c4SMarek Vasut 		if (!state.online || state.hiz ||
515c688e0c4SMarek Vasut 		    state.chrg_status == STATUS_NOT_CHARGING ||
516b302a0aeSMichał Mirosław 		    state.chrg_status == STATUS_TERMINATION_DONE)
517b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
518b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_PRE_CHARGING)
519b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
520b302a0aeSMichał Mirosław 		else if (state.chrg_status == STATUS_FAST_CHARGING)
521b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
522b302a0aeSMichał Mirosław 		else /* unreachable */
523b302a0aeSMichał Mirosław 			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
524b302a0aeSMichał Mirosław 		break;
525b302a0aeSMichał Mirosław 
5268c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MANUFACTURER:
5278c0984e5SSebastian Reichel 		val->strval = BQ25890_MANUFACTURER;
5288c0984e5SSebastian Reichel 		break;
5298c0984e5SSebastian Reichel 
5302e1a2ddeSAngus Ainslie (Purism) 	case POWER_SUPPLY_PROP_MODEL_NAME:
5315956fca7SMichał Mirosław 		val->strval = bq25890_chip_name[bq->chip_version];
5322e1a2ddeSAngus Ainslie (Purism) 		break;
5332e1a2ddeSAngus Ainslie (Purism) 
5348c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
535c688e0c4SMarek Vasut 		val->intval = state.online && !state.hiz;
5368c0984e5SSebastian Reichel 		break;
5378c0984e5SSebastian Reichel 
5388c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_HEALTH:
5398c0984e5SSebastian Reichel 		if (!state.chrg_fault && !state.bat_fault && !state.boost_fault)
5408c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_GOOD;
5418c0984e5SSebastian Reichel 		else if (state.bat_fault)
5428c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
5438c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED)
5448c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
5458c0984e5SSebastian Reichel 		else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN)
5468c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
5478c0984e5SSebastian Reichel 		else
5488c0984e5SSebastian Reichel 			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
5498c0984e5SSebastian Reichel 		break;
5508c0984e5SSebastian Reichel 
551c942656dSMichał Mirosław 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
552c942656dSMichał Mirosław 		val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM);
553c942656dSMichał Mirosław 		break;
554c942656dSMichał Mirosław 
5558c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
5568c0984e5SSebastian Reichel 		val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM);
5578c0984e5SSebastian Reichel 		break;
5588c0984e5SSebastian Reichel 
559478efc79SMichał Mirosław 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
560766873c1SYauhen Kharuzhy 		ret = bq25890_field_read(bq, F_IINLIM);
561478efc79SMichał Mirosław 		if (ret < 0)
562478efc79SMichał Mirosław 			return ret;
563478efc79SMichał Mirosław 
564766873c1SYauhen Kharuzhy 		val->intval = bq25890_find_val(ret, TBL_IINLIM);
565478efc79SMichał Mirosław 		break;
566478efc79SMichał Mirosław 
567ef1ca210SMarek Vasut 	case POWER_SUPPLY_PROP_CURRENT_NOW:	/* I_BAT now */
568ef1ca210SMarek Vasut 		/*
569ef1ca210SMarek Vasut 		 * This is ADC-sampled immediate charge current supplied
570ef1ca210SMarek Vasut 		 * from charger to battery. The property name is confusing,
571ef1ca210SMarek Vasut 		 * for clarification refer to:
572ef1ca210SMarek Vasut 		 * Documentation/ABI/testing/sysfs-class-power
573ef1ca210SMarek Vasut 		 * /sys/class/power_supply/<supply_name>/current_now
574ef1ca210SMarek Vasut 		 */
5751e4724d0SMichał Mirosław 		ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */
5761e4724d0SMichał Mirosław 		if (ret < 0)
5771e4724d0SMichał Mirosław 			return ret;
5781e4724d0SMichał Mirosław 
5791e4724d0SMichał Mirosław 		/* converted_val = ADC_val * 50mA (table 10.3.19) */
5801e4724d0SMichał Mirosław 		val->intval = ret * -50000;
5811e4724d0SMichał Mirosław 		break;
5821e4724d0SMichał Mirosław 
5838327a8abSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:	/* I_BAT user limit */
5848327a8abSMarek Vasut 		/*
5858327a8abSMarek Vasut 		 * This is user-configured constant charge current supplied
5868327a8abSMarek Vasut 		 * from charger to battery in first phase of charging, when
5878327a8abSMarek Vasut 		 * battery voltage is below constant charge voltage.
5888327a8abSMarek Vasut 		 *
5898327a8abSMarek Vasut 		 * This value reflects the current hardware setting.
5908327a8abSMarek Vasut 		 *
5918327a8abSMarek Vasut 		 * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX is the
5928327a8abSMarek Vasut 		 * maximum value of this property.
5938327a8abSMarek Vasut 		 */
5948327a8abSMarek Vasut 		ret = bq25890_field_read(bq, F_ICHG);
5958327a8abSMarek Vasut 		if (ret < 0)
5968327a8abSMarek Vasut 			return ret;
5978327a8abSMarek Vasut 		val->intval = bq25890_find_val(ret, TBL_ICHG);
5988327a8abSMarek Vasut 
5998327a8abSMarek Vasut 		/* When temperature is too low, charge current is decreased */
6008327a8abSMarek Vasut 		if (bq->state.ntc_fault == NTC_FAULT_COOL) {
6018327a8abSMarek Vasut 			ret = bq25890_field_read(bq, F_JEITA_ISET);
6028327a8abSMarek Vasut 			if (ret < 0)
6038327a8abSMarek Vasut 				return ret;
6048327a8abSMarek Vasut 
6058327a8abSMarek Vasut 			if (ret)
6068327a8abSMarek Vasut 				val->intval /= 5;
6078327a8abSMarek Vasut 			else
6088327a8abSMarek Vasut 				val->intval /= 2;
6098327a8abSMarek Vasut 		}
6108327a8abSMarek Vasut 		break;
6118327a8abSMarek Vasut 
6128327a8abSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:	/* I_BAT max */
6138327a8abSMarek Vasut 		/*
6148327a8abSMarek Vasut 		 * This is maximum allowed constant charge current supplied
6158327a8abSMarek Vasut 		 * from charger to battery in first phase of charging, when
6168327a8abSMarek Vasut 		 * battery voltage is below constant charge voltage.
6178327a8abSMarek Vasut 		 *
6188327a8abSMarek Vasut 		 * This value is constant for each battery and set from DT.
6198327a8abSMarek Vasut 		 */
6208327a8abSMarek Vasut 		val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
6218327a8abSMarek Vasut 		break;
6228327a8abSMarek Vasut 
6237c852375SMarek Vasut 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:	/* V_BAT now */
6247c852375SMarek Vasut 		/*
6257c852375SMarek Vasut 		 * This is ADC-sampled immediate charge voltage supplied
6267c852375SMarek Vasut 		 * from charger to battery. The property name is confusing,
6277c852375SMarek Vasut 		 * for clarification refer to:
6287c852375SMarek Vasut 		 * Documentation/ABI/testing/sysfs-class-power
6297c852375SMarek Vasut 		 * /sys/class/power_supply/<supply_name>/voltage_now
6307c852375SMarek Vasut 		 */
6317c852375SMarek Vasut 		ret = bq25890_field_read(bq, F_BATV); /* read measured value */
6327c852375SMarek Vasut 		if (ret < 0)
6337c852375SMarek Vasut 			return ret;
6347c852375SMarek Vasut 
6357c852375SMarek Vasut 		/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
6367c852375SMarek Vasut 		val->intval = 2304000 + ret * 20000;
6377c852375SMarek Vasut 		break;
6387c852375SMarek Vasut 
6397c852375SMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:	/* V_BAT user limit */
6407c852375SMarek Vasut 		/*
6417c852375SMarek Vasut 		 * This is user-configured constant charge voltage supplied
6427c852375SMarek Vasut 		 * from charger to battery in second phase of charging, when
6437c852375SMarek Vasut 		 * battery voltage reached constant charge voltage.
6447c852375SMarek Vasut 		 *
6457c852375SMarek Vasut 		 * This value reflects the current hardware setting.
6467c852375SMarek Vasut 		 *
6477c852375SMarek Vasut 		 * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX is the
6487c852375SMarek Vasut 		 * maximum value of this property.
6497c852375SMarek Vasut 		 */
6507c852375SMarek Vasut 		ret = bq25890_field_read(bq, F_VREG);
6517c852375SMarek Vasut 		if (ret < 0)
6527c852375SMarek Vasut 			return ret;
6537c852375SMarek Vasut 
6547c852375SMarek Vasut 		val->intval = bq25890_find_val(ret, TBL_VREG);
6557c852375SMarek Vasut 		break;
6567c852375SMarek Vasut 
6577c852375SMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:	/* V_BAT max */
6587c852375SMarek Vasut 		/*
6597c852375SMarek Vasut 		 * This is maximum allowed constant charge voltage supplied
6607c852375SMarek Vasut 		 * from charger to battery in second phase of charging, when
6617c852375SMarek Vasut 		 * battery voltage reached constant charge voltage.
6627c852375SMarek Vasut 		 *
6637c852375SMarek Vasut 		 * This value is constant for each battery and set from DT.
6647c852375SMarek Vasut 		 */
6657c852375SMarek Vasut 		val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
6667c852375SMarek Vasut 		break;
6677c852375SMarek Vasut 
6689652c024SAngus Ainslie 	case POWER_SUPPLY_PROP_TEMP:
6699652c024SAngus Ainslie 		ret = bq25890_field_read(bq, F_TSPCT);
6709652c024SAngus Ainslie 		if (ret < 0)
6719652c024SAngus Ainslie 			return ret;
6729652c024SAngus Ainslie 
6739652c024SAngus Ainslie 		/* convert TS percentage into rough temperature */
6749652c024SAngus Ainslie 		val->intval = bq25890_find_val(ret, TBL_TSPCT);
6759652c024SAngus Ainslie 		break;
6769652c024SAngus Ainslie 
6778c0984e5SSebastian Reichel 	default:
6788c0984e5SSebastian Reichel 		return -EINVAL;
6798c0984e5SSebastian Reichel 	}
6808c0984e5SSebastian Reichel 
6818c0984e5SSebastian Reichel 	return 0;
6828c0984e5SSebastian Reichel }
6838c0984e5SSebastian Reichel 
6844a4748f2SMarek Vasut static int bq25890_power_supply_set_property(struct power_supply *psy,
6854a4748f2SMarek Vasut 					     enum power_supply_property psp,
6864a4748f2SMarek Vasut 					     const union power_supply_propval *val)
6874a4748f2SMarek Vasut {
6884a4748f2SMarek Vasut 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
689c688e0c4SMarek Vasut 	struct bq25890_state state;
690c688e0c4SMarek Vasut 	int maxval, ret;
6914a4748f2SMarek Vasut 	u8 lval;
6924a4748f2SMarek Vasut 
6934a4748f2SMarek Vasut 	switch (psp) {
694b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
695b63e60ebSMarek Vasut 		maxval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
696b63e60ebSMarek Vasut 		lval = bq25890_find_idx(min(val->intval, maxval), TBL_ICHG);
697b63e60ebSMarek Vasut 		return bq25890_field_write(bq, F_ICHG, lval);
698b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
699b63e60ebSMarek Vasut 		maxval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
700b63e60ebSMarek Vasut 		lval = bq25890_find_idx(min(val->intval, maxval), TBL_VREG);
701b63e60ebSMarek Vasut 		return bq25890_field_write(bq, F_VREG, lval);
7024a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
70355cafd4bSNathan Chancellor 		lval = bq25890_find_idx(val->intval, TBL_IINLIM);
7044a4748f2SMarek Vasut 		return bq25890_field_write(bq, F_IINLIM, lval);
705c688e0c4SMarek Vasut 	case POWER_SUPPLY_PROP_ONLINE:
706c688e0c4SMarek Vasut 		ret = bq25890_field_write(bq, F_EN_HIZ, !val->intval);
707c688e0c4SMarek Vasut 		if (!ret)
708c688e0c4SMarek Vasut 			bq->force_hiz = !val->intval;
709c688e0c4SMarek Vasut 		bq25890_update_state(bq, psp, &state);
710c688e0c4SMarek Vasut 		return ret;
7114a4748f2SMarek Vasut 	default:
7124a4748f2SMarek Vasut 		return -EINVAL;
7134a4748f2SMarek Vasut 	}
7144a4748f2SMarek Vasut }
7154a4748f2SMarek Vasut 
7164a4748f2SMarek Vasut static int bq25890_power_supply_property_is_writeable(struct power_supply *psy,
7174a4748f2SMarek Vasut 						      enum power_supply_property psp)
7184a4748f2SMarek Vasut {
7194a4748f2SMarek Vasut 	switch (psp) {
720b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
721b63e60ebSMarek Vasut 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
7224a4748f2SMarek Vasut 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
723c688e0c4SMarek Vasut 	case POWER_SUPPLY_PROP_ONLINE:
7244a4748f2SMarek Vasut 		return true;
7254a4748f2SMarek Vasut 	default:
7264a4748f2SMarek Vasut 		return false;
7274a4748f2SMarek Vasut 	}
7284a4748f2SMarek Vasut }
7294a4748f2SMarek Vasut 
730eab25b4fSHans de Goede /* On the BQ25892 try to get charger-type info from our supplier */
731eab25b4fSHans de Goede static void bq25890_charger_external_power_changed(struct power_supply *psy)
732eab25b4fSHans de Goede {
733eab25b4fSHans de Goede 	struct bq25890_device *bq = power_supply_get_drvdata(psy);
734eab25b4fSHans de Goede 	union power_supply_propval val;
735eab25b4fSHans de Goede 	int input_current_limit, ret;
736eab25b4fSHans de Goede 
737eab25b4fSHans de Goede 	if (bq->chip_version != BQ25892)
738eab25b4fSHans de Goede 		return;
739eab25b4fSHans de Goede 
740eab25b4fSHans de Goede 	ret = power_supply_get_property_from_supplier(bq->charger,
741eab25b4fSHans de Goede 						      POWER_SUPPLY_PROP_USB_TYPE,
742eab25b4fSHans de Goede 						      &val);
743eab25b4fSHans de Goede 	if (ret)
744eab25b4fSHans de Goede 		return;
745eab25b4fSHans de Goede 
746eab25b4fSHans de Goede 	switch (val.intval) {
747eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_DCP:
748eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM);
74948f45b09SYauhen Kharuzhy 		if (bq->pump_express_vbus_max) {
75048f45b09SYauhen Kharuzhy 			queue_delayed_work(system_power_efficient_wq,
75148f45b09SYauhen Kharuzhy 					   &bq->pump_express_work,
75248f45b09SYauhen Kharuzhy 					   PUMP_EXPRESS_START_DELAY);
75348f45b09SYauhen Kharuzhy 		}
754eab25b4fSHans de Goede 		break;
755eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_CDP:
756eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_ACA:
757eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM);
758eab25b4fSHans de Goede 		break;
759eab25b4fSHans de Goede 	case POWER_SUPPLY_USB_TYPE_SDP:
760eab25b4fSHans de Goede 	default:
761eab25b4fSHans de Goede 		input_current_limit = bq25890_find_idx(500000, TBL_IINLIM);
762eab25b4fSHans de Goede 	}
763eab25b4fSHans de Goede 
764eab25b4fSHans de Goede 	bq25890_field_write(bq, F_IINLIM, input_current_limit);
765eab25b4fSHans de Goede }
766eab25b4fSHans de Goede 
7678c0984e5SSebastian Reichel static int bq25890_get_chip_state(struct bq25890_device *bq,
7688c0984e5SSebastian Reichel 				  struct bq25890_state *state)
7698c0984e5SSebastian Reichel {
7708c0984e5SSebastian Reichel 	int i, ret;
7718c0984e5SSebastian Reichel 
7728c0984e5SSebastian Reichel 	struct {
7738c0984e5SSebastian Reichel 		enum bq25890_fields id;
7748c0984e5SSebastian Reichel 		u8 *data;
7758c0984e5SSebastian Reichel 	} state_fields[] = {
7768c0984e5SSebastian Reichel 		{F_CHG_STAT,	&state->chrg_status},
7778c0984e5SSebastian Reichel 		{F_PG_STAT,	&state->online},
778c688e0c4SMarek Vasut 		{F_EN_HIZ,	&state->hiz},
7798c0984e5SSebastian Reichel 		{F_VSYS_STAT,	&state->vsys_status},
7808c0984e5SSebastian Reichel 		{F_BOOST_FAULT, &state->boost_fault},
7818c0984e5SSebastian Reichel 		{F_BAT_FAULT,	&state->bat_fault},
782c562a43aSYauhen Kharuzhy 		{F_CHG_FAULT,	&state->chrg_fault},
783c562a43aSYauhen Kharuzhy 		{F_NTC_FAULT,	&state->ntc_fault}
7848c0984e5SSebastian Reichel 	};
7858c0984e5SSebastian Reichel 
7868c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(state_fields); i++) {
7878c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, state_fields[i].id);
7888c0984e5SSebastian Reichel 		if (ret < 0)
7898c0984e5SSebastian Reichel 			return ret;
7908c0984e5SSebastian Reichel 
7918c0984e5SSebastian Reichel 		*state_fields[i].data = ret;
7928c0984e5SSebastian Reichel 	}
7938c0984e5SSebastian Reichel 
794c688e0c4SMarek Vasut 	dev_dbg(bq->dev, "S:CHG/PG/HIZ/VSYS=%d/%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
795c688e0c4SMarek Vasut 		state->chrg_status, state->online,
796c688e0c4SMarek Vasut 		state->hiz, state->vsys_status,
797c688e0c4SMarek Vasut 		state->chrg_fault, state->boost_fault,
798c688e0c4SMarek Vasut 		state->bat_fault, state->ntc_fault);
7998c0984e5SSebastian Reichel 
8008c0984e5SSebastian Reichel 	return 0;
8018c0984e5SSebastian Reichel }
8028c0984e5SSebastian Reichel 
80372d9cd9cSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
8048c0984e5SSebastian Reichel {
8054413f9e9SHans de Goede 	bool adc_conv_rate, new_adc_conv_rate;
80672d9cd9cSMichał Mirosław 	struct bq25890_state new_state;
8078c0984e5SSebastian Reichel 	int ret;
8088c0984e5SSebastian Reichel 
80972d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &new_state);
81072d9cd9cSMichał Mirosław 	if (ret < 0)
81172d9cd9cSMichał Mirosław 		return IRQ_NONE;
8128c0984e5SSebastian Reichel 
81372d9cd9cSMichał Mirosław 	if (!memcmp(&bq->state, &new_state, sizeof(new_state)))
81472d9cd9cSMichał Mirosław 		return IRQ_NONE;
81572d9cd9cSMichał Mirosław 
816c688e0c4SMarek Vasut 	/*
8174413f9e9SHans de Goede 	 * Restore HiZ bit in case it was set by user. The chip does not retain
8184413f9e9SHans de Goede 	 * this bit on cable replug, hence the bit must be reset manually here.
819c688e0c4SMarek Vasut 	 */
8204413f9e9SHans de Goede 	if (new_state.online && !bq->state.online && bq->force_hiz) {
821c688e0c4SMarek Vasut 		ret = bq25890_field_write(bq, F_EN_HIZ, bq->force_hiz);
822c688e0c4SMarek Vasut 		if (ret < 0)
823c688e0c4SMarek Vasut 			goto error;
824c688e0c4SMarek Vasut 		new_state.hiz = 1;
825c688e0c4SMarek Vasut 	}
826c688e0c4SMarek Vasut 
8274413f9e9SHans de Goede 	/* Should period ADC sampling be enabled? */
8284413f9e9SHans de Goede 	adc_conv_rate = bq->state.online && !bq->state.hiz;
8294413f9e9SHans de Goede 	new_adc_conv_rate = new_state.online && !new_state.hiz;
8304413f9e9SHans de Goede 
8314413f9e9SHans de Goede 	if (new_adc_conv_rate != adc_conv_rate) {
8324413f9e9SHans de Goede 		ret = bq25890_field_write(bq, F_CONV_RATE, new_adc_conv_rate);
8338c0984e5SSebastian Reichel 		if (ret < 0)
8348c0984e5SSebastian Reichel 			goto error;
8358c0984e5SSebastian Reichel 	}
8368c0984e5SSebastian Reichel 
83772d9cd9cSMichał Mirosław 	bq->state = new_state;
83872d9cd9cSMichał Mirosław 	power_supply_changed(bq->charger);
8398c0984e5SSebastian Reichel 
84072d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
8418c0984e5SSebastian Reichel error:
84272d9cd9cSMichał Mirosław 	dev_err(bq->dev, "Error communicating with the chip: %pe\n",
84372d9cd9cSMichał Mirosław 		ERR_PTR(ret));
84472d9cd9cSMichał Mirosław 	return IRQ_HANDLED;
8458c0984e5SSebastian Reichel }
8468c0984e5SSebastian Reichel 
8478c0984e5SSebastian Reichel static irqreturn_t bq25890_irq_handler_thread(int irq, void *private)
8488c0984e5SSebastian Reichel {
8498c0984e5SSebastian Reichel 	struct bq25890_device *bq = private;
85072d9cd9cSMichał Mirosław 	irqreturn_t ret;
8518c0984e5SSebastian Reichel 
8528c0984e5SSebastian Reichel 	mutex_lock(&bq->lock);
85372d9cd9cSMichał Mirosław 	ret = __bq25890_handle_irq(bq);
8548c0984e5SSebastian Reichel 	mutex_unlock(&bq->lock);
8558c0984e5SSebastian Reichel 
85672d9cd9cSMichał Mirosław 	return ret;
8578c0984e5SSebastian Reichel }
8588c0984e5SSebastian Reichel 
8598c0984e5SSebastian Reichel static int bq25890_chip_reset(struct bq25890_device *bq)
8608c0984e5SSebastian Reichel {
8618c0984e5SSebastian Reichel 	int ret;
8628c0984e5SSebastian Reichel 	int rst_check_counter = 10;
8638c0984e5SSebastian Reichel 
8648c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_REG_RST, 1);
8658c0984e5SSebastian Reichel 	if (ret < 0)
8668c0984e5SSebastian Reichel 		return ret;
8678c0984e5SSebastian Reichel 
8688c0984e5SSebastian Reichel 	do {
8698c0984e5SSebastian Reichel 		ret = bq25890_field_read(bq, F_REG_RST);
8708c0984e5SSebastian Reichel 		if (ret < 0)
8718c0984e5SSebastian Reichel 			return ret;
8728c0984e5SSebastian Reichel 
8738c0984e5SSebastian Reichel 		usleep_range(5, 10);
8748c0984e5SSebastian Reichel 	} while (ret == 1 && --rst_check_counter);
8758c0984e5SSebastian Reichel 
8768c0984e5SSebastian Reichel 	if (!rst_check_counter)
8778c0984e5SSebastian Reichel 		return -ETIMEDOUT;
8788c0984e5SSebastian Reichel 
8798c0984e5SSebastian Reichel 	return 0;
8808c0984e5SSebastian Reichel }
8818c0984e5SSebastian Reichel 
8827b22a974SHans de Goede static int bq25890_rw_init_data(struct bq25890_device *bq)
8838c0984e5SSebastian Reichel {
88440428bd4SHans de Goede 	bool write = !bq->read_back_init_data;
8858c0984e5SSebastian Reichel 	int ret;
8868c0984e5SSebastian Reichel 	int i;
8878c0984e5SSebastian Reichel 
8888c0984e5SSebastian Reichel 	const struct {
8898c0984e5SSebastian Reichel 		enum bq25890_fields id;
8907b22a974SHans de Goede 		u8 *value;
8918c0984e5SSebastian Reichel 	} init_data[] = {
8927b22a974SHans de Goede 		{F_ICHG,	 &bq->init_data.ichg},
8937b22a974SHans de Goede 		{F_VREG,	 &bq->init_data.vreg},
8947b22a974SHans de Goede 		{F_ITERM,	 &bq->init_data.iterm},
8957b22a974SHans de Goede 		{F_IPRECHG,	 &bq->init_data.iprechg},
8967b22a974SHans de Goede 		{F_SYSVMIN,	 &bq->init_data.sysvmin},
8977b22a974SHans de Goede 		{F_BOOSTV,	 &bq->init_data.boostv},
8987b22a974SHans de Goede 		{F_BOOSTI,	 &bq->init_data.boosti},
8997b22a974SHans de Goede 		{F_BOOSTF,	 &bq->init_data.boostf},
9007b22a974SHans de Goede 		{F_EN_ILIM,	 &bq->init_data.ilim_en},
9017b22a974SHans de Goede 		{F_TREG,	 &bq->init_data.treg},
9027b22a974SHans de Goede 		{F_BATCMP,	 &bq->init_data.rbatcomp},
9037b22a974SHans de Goede 		{F_VCLAMP,	 &bq->init_data.vclamp},
9048c0984e5SSebastian Reichel 	};
9058c0984e5SSebastian Reichel 
9067b22a974SHans de Goede 	for (i = 0; i < ARRAY_SIZE(init_data); i++) {
9077b22a974SHans de Goede 		if (write) {
9087b22a974SHans de Goede 			ret = bq25890_field_write(bq, init_data[i].id,
9097b22a974SHans de Goede 						  *init_data[i].value);
9107b22a974SHans de Goede 		} else {
9117b22a974SHans de Goede 			ret = bq25890_field_read(bq, init_data[i].id);
9127b22a974SHans de Goede 			if (ret >= 0)
9137b22a974SHans de Goede 				*init_data[i].value = ret;
9147b22a974SHans de Goede 		}
9157b22a974SHans de Goede 		if (ret < 0) {
9167b22a974SHans de Goede 			dev_dbg(bq->dev, "Accessing init data failed %d\n", ret);
9177b22a974SHans de Goede 			return ret;
9187b22a974SHans de Goede 		}
9197b22a974SHans de Goede 	}
9207b22a974SHans de Goede 
9217b22a974SHans de Goede 	return 0;
9227b22a974SHans de Goede }
9237b22a974SHans de Goede 
9247b22a974SHans de Goede static int bq25890_hw_init(struct bq25890_device *bq)
9257b22a974SHans de Goede {
9267b22a974SHans de Goede 	int ret;
9277b22a974SHans de Goede 
9287e3b8e35SHans de Goede 	if (!bq->skip_reset) {
9298c0984e5SSebastian Reichel 		ret = bq25890_chip_reset(bq);
9309d9ae341SAngus Ainslie (Purism) 		if (ret < 0) {
9319d9ae341SAngus Ainslie (Purism) 			dev_dbg(bq->dev, "Reset failed %d\n", ret);
9328c0984e5SSebastian Reichel 			return ret;
933ad1570d9Skbuild test robot 		}
93406c75095SHans de Goede 	} else {
93506c75095SHans de Goede 		/*
93606c75095SHans de Goede 		 * Ensure charging is enabled, on some boards where the fw
93706c75095SHans de Goede 		 * takes care of initalizition F_CHG_CFG is set to 0 before
93806c75095SHans de Goede 		 * handing control over to the OS.
93906c75095SHans de Goede 		 */
94006c75095SHans de Goede 		ret = bq25890_field_write(bq, F_CHG_CFG, 1);
94106c75095SHans de Goede 		if (ret < 0) {
94206c75095SHans de Goede 			dev_dbg(bq->dev, "Enabling charging failed %d\n", ret);
94306c75095SHans de Goede 			return ret;
94406c75095SHans de Goede 		}
9457e3b8e35SHans de Goede 	}
9468c0984e5SSebastian Reichel 
9478c0984e5SSebastian Reichel 	/* disable watchdog */
9488c0984e5SSebastian Reichel 	ret = bq25890_field_write(bq, F_WD, 0);
9499d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
9509d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret);
9518c0984e5SSebastian Reichel 		return ret;
952ad1570d9Skbuild test robot 	}
9538c0984e5SSebastian Reichel 
9548c0984e5SSebastian Reichel 	/* initialize currents/voltages and other parameters */
9557b22a974SHans de Goede 	ret = bq25890_rw_init_data(bq);
9567b22a974SHans de Goede 	if (ret)
9578c0984e5SSebastian Reichel 		return ret;
9588c0984e5SSebastian Reichel 
95922ad4f99SHans de Goede 	ret = bq25890_get_chip_state(bq, &bq->state);
96022ad4f99SHans de Goede 	if (ret < 0) {
96122ad4f99SHans de Goede 		dev_dbg(bq->dev, "Get state failed %d\n", ret);
96222ad4f99SHans de Goede 		return ret;
96322ad4f99SHans de Goede 	}
96422ad4f99SHans de Goede 
96521d90edaSMichał Mirosław 	/* Configure ADC for continuous conversions when charging */
966dee0df84SHans de Goede 	ret = bq25890_field_write(bq, F_CONV_RATE, bq->state.online && !bq->state.hiz);
9679d9ae341SAngus Ainslie (Purism) 	if (ret < 0) {
9689d9ae341SAngus Ainslie (Purism) 		dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
9698c0984e5SSebastian Reichel 		return ret;
970ad1570d9Skbuild test robot 	}
9718c0984e5SSebastian Reichel 
9728c0984e5SSebastian Reichel 	return 0;
9738c0984e5SSebastian Reichel }
9748c0984e5SSebastian Reichel 
975a6a48facSMichał Mirosław static const enum power_supply_property bq25890_power_supply_props[] = {
9768c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MANUFACTURER,
9772e1a2ddeSAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_MODEL_NAME,
9788c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
979b302a0aeSMichał Mirosław 	POWER_SUPPLY_PROP_CHARGE_TYPE,
9808c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
9818c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_HEALTH,
9828327a8abSMarek Vasut 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
9838c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
9848c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
9858c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
986c942656dSMichał Mirosław 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
9878c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
988478efc79SMichał Mirosław 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
989ae6fe7a3SAngus Ainslie (Purism) 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
9901e4724d0SMichał Mirosław 	POWER_SUPPLY_PROP_CURRENT_NOW,
9919652c024SAngus Ainslie 	POWER_SUPPLY_PROP_TEMP,
9928c0984e5SSebastian Reichel };
9938c0984e5SSebastian Reichel 
9948c0984e5SSebastian Reichel static char *bq25890_charger_supplied_to[] = {
9958c0984e5SSebastian Reichel 	"main-battery",
9968c0984e5SSebastian Reichel };
9978c0984e5SSebastian Reichel 
9988c0984e5SSebastian Reichel static const struct power_supply_desc bq25890_power_supply_desc = {
9998c0984e5SSebastian Reichel 	.type = POWER_SUPPLY_TYPE_USB,
10008c0984e5SSebastian Reichel 	.properties = bq25890_power_supply_props,
10018c0984e5SSebastian Reichel 	.num_properties = ARRAY_SIZE(bq25890_power_supply_props),
10028c0984e5SSebastian Reichel 	.get_property = bq25890_power_supply_get_property,
10034a4748f2SMarek Vasut 	.set_property = bq25890_power_supply_set_property,
10044a4748f2SMarek Vasut 	.property_is_writeable = bq25890_power_supply_property_is_writeable,
1005eab25b4fSHans de Goede 	.external_power_changed	= bq25890_charger_external_power_changed,
10068c0984e5SSebastian Reichel };
10078c0984e5SSebastian Reichel 
10088c0984e5SSebastian Reichel static int bq25890_power_supply_init(struct bq25890_device *bq)
10098c0984e5SSebastian Reichel {
10108c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = { .drv_data = bq, };
10118c0984e5SSebastian Reichel 
10124e9498b8SHans de Goede 	/* Get ID for the device */
10134e9498b8SHans de Goede 	mutex_lock(&bq25890_id_mutex);
10144e9498b8SHans de Goede 	bq->id = idr_alloc(&bq25890_id, bq, 0, 0, GFP_KERNEL);
10154e9498b8SHans de Goede 	mutex_unlock(&bq25890_id_mutex);
10164e9498b8SHans de Goede 	if (bq->id < 0)
10174e9498b8SHans de Goede 		return bq->id;
10184e9498b8SHans de Goede 
10194e9498b8SHans de Goede 	snprintf(bq->name, sizeof(bq->name), "bq25890-charger-%d", bq->id);
10204e9498b8SHans de Goede 	bq->desc = bq25890_power_supply_desc;
10214e9498b8SHans de Goede 	bq->desc.name = bq->name;
10224e9498b8SHans de Goede 
10238c0984e5SSebastian Reichel 	psy_cfg.supplied_to = bq25890_charger_supplied_to;
10248c0984e5SSebastian Reichel 	psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
10258c0984e5SSebastian Reichel 
10264e9498b8SHans de Goede 	bq->charger = devm_power_supply_register(bq->dev, &bq->desc, &psy_cfg);
10278c0984e5SSebastian Reichel 
10288c0984e5SSebastian Reichel 	return PTR_ERR_OR_ZERO(bq->charger);
10298c0984e5SSebastian Reichel }
10308c0984e5SSebastian Reichel 
10315575802dSHans de Goede static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val)
10325575802dSHans de Goede {
10335575802dSHans de Goede 	int ret;
10345575802dSHans de Goede 
10355575802dSHans de Goede 	ret = bq25890_field_write(bq, F_OTG_CFG, val);
10365575802dSHans de Goede 	if (ret < 0)
10375575802dSHans de Goede 		dev_err(bq->dev, "Error switching to boost/charger mode: %d\n", ret);
10385575802dSHans de Goede 
10395575802dSHans de Goede 	return ret;
10405575802dSHans de Goede }
10415575802dSHans de Goede 
104248f45b09SYauhen Kharuzhy static void bq25890_pump_express_work(struct work_struct *data)
104348f45b09SYauhen Kharuzhy {
104448f45b09SYauhen Kharuzhy 	struct bq25890_device *bq =
104548f45b09SYauhen Kharuzhy 		container_of(data, struct bq25890_device, pump_express_work.work);
1046*d54bf877SHans de Goede 	union power_supply_propval value;
104748f45b09SYauhen Kharuzhy 	int voltage, i, ret;
104848f45b09SYauhen Kharuzhy 
104948f45b09SYauhen Kharuzhy 	dev_dbg(bq->dev, "Start to request input voltage increasing\n");
105048f45b09SYauhen Kharuzhy 
1051*d54bf877SHans de Goede 	/* If there is a second charger put in Hi-Z mode */
1052*d54bf877SHans de Goede 	if (bq->secondary_chrg) {
1053*d54bf877SHans de Goede 		value.intval = 0;
1054*d54bf877SHans de Goede 		power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value);
1055*d54bf877SHans de Goede 	}
1056*d54bf877SHans de Goede 
105748f45b09SYauhen Kharuzhy 	/* Enable current pulse voltage control protocol */
105848f45b09SYauhen Kharuzhy 	ret = bq25890_field_write(bq, F_PUMPX_EN, 1);
105948f45b09SYauhen Kharuzhy 	if (ret < 0)
106048f45b09SYauhen Kharuzhy 		goto error_print;
106148f45b09SYauhen Kharuzhy 
106248f45b09SYauhen Kharuzhy 	for (i = 0; i < PUMP_EXPRESS_MAX_TRIES; i++) {
106348f45b09SYauhen Kharuzhy 		voltage = bq25890_get_vbus_voltage(bq);
106448f45b09SYauhen Kharuzhy 		if (voltage < 0)
106548f45b09SYauhen Kharuzhy 			goto error_print;
106648f45b09SYauhen Kharuzhy 		dev_dbg(bq->dev, "input voltage = %d uV\n", voltage);
106748f45b09SYauhen Kharuzhy 
106848f45b09SYauhen Kharuzhy 		if ((voltage + PUMP_EXPRESS_VBUS_MARGIN_uV) >
106948f45b09SYauhen Kharuzhy 					bq->pump_express_vbus_max)
107048f45b09SYauhen Kharuzhy 			break;
107148f45b09SYauhen Kharuzhy 
107248f45b09SYauhen Kharuzhy 		ret = bq25890_field_write(bq, F_PUMPX_UP, 1);
107348f45b09SYauhen Kharuzhy 		if (ret < 0)
107448f45b09SYauhen Kharuzhy 			goto error_print;
107548f45b09SYauhen Kharuzhy 
107648f45b09SYauhen Kharuzhy 		/* Note a single PUMPX up pulse-sequence takes 2.1s */
107748f45b09SYauhen Kharuzhy 		ret = regmap_field_read_poll_timeout(bq->rmap_fields[F_PUMPX_UP],
107848f45b09SYauhen Kharuzhy 						     ret, !ret, 100000, 3000000);
107948f45b09SYauhen Kharuzhy 		if (ret < 0)
108048f45b09SYauhen Kharuzhy 			goto error_print;
108148f45b09SYauhen Kharuzhy 
108248f45b09SYauhen Kharuzhy 		/* Make sure ADC has sampled Vbus before checking again */
108348f45b09SYauhen Kharuzhy 		msleep(1000);
108448f45b09SYauhen Kharuzhy 	}
108548f45b09SYauhen Kharuzhy 
108648f45b09SYauhen Kharuzhy 	bq25890_field_write(bq, F_PUMPX_EN, 0);
108748f45b09SYauhen Kharuzhy 
1088*d54bf877SHans de Goede 	if (bq->secondary_chrg) {
1089*d54bf877SHans de Goede 		value.intval = 1;
1090*d54bf877SHans de Goede 		power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value);
1091*d54bf877SHans de Goede 	}
1092*d54bf877SHans de Goede 
109348f45b09SYauhen Kharuzhy 	dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n",
109448f45b09SYauhen Kharuzhy 		 voltage);
109548f45b09SYauhen Kharuzhy 
109648f45b09SYauhen Kharuzhy 	return;
109748f45b09SYauhen Kharuzhy error_print:
109804f7c7dfSHans de Goede 	bq25890_field_write(bq, F_PUMPX_EN, 0);
109948f45b09SYauhen Kharuzhy 	dev_err(bq->dev, "Failed to request hi-voltage charging\n");
110048f45b09SYauhen Kharuzhy }
110148f45b09SYauhen Kharuzhy 
11028c0984e5SSebastian Reichel static void bq25890_usb_work(struct work_struct *data)
11038c0984e5SSebastian Reichel {
11048c0984e5SSebastian Reichel 	int ret;
11058c0984e5SSebastian Reichel 	struct bq25890_device *bq =
11068c0984e5SSebastian Reichel 			container_of(data, struct bq25890_device, usb_work);
11078c0984e5SSebastian Reichel 
11088c0984e5SSebastian Reichel 	switch (bq->usb_event) {
11098c0984e5SSebastian Reichel 	case USB_EVENT_ID:
11108c0984e5SSebastian Reichel 		/* Enable boost mode */
11115575802dSHans de Goede 		bq25890_set_otg_cfg(bq, 1);
11128c0984e5SSebastian Reichel 		break;
11138c0984e5SSebastian Reichel 
11148c0984e5SSebastian Reichel 	case USB_EVENT_NONE:
11158c0984e5SSebastian Reichel 		/* Disable boost mode */
11165575802dSHans de Goede 		ret = bq25890_set_otg_cfg(bq, 0);
11175575802dSHans de Goede 		if (ret == 0)
11188c0984e5SSebastian Reichel 			power_supply_changed(bq->charger);
11198c0984e5SSebastian Reichel 		break;
11208c0984e5SSebastian Reichel 	}
11218c0984e5SSebastian Reichel }
11228c0984e5SSebastian Reichel 
11238c0984e5SSebastian Reichel static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val,
11248c0984e5SSebastian Reichel 				void *priv)
11258c0984e5SSebastian Reichel {
11268c0984e5SSebastian Reichel 	struct bq25890_device *bq =
11278c0984e5SSebastian Reichel 			container_of(nb, struct bq25890_device, usb_nb);
11288c0984e5SSebastian Reichel 
11298c0984e5SSebastian Reichel 	bq->usb_event = val;
11308c0984e5SSebastian Reichel 	queue_work(system_power_efficient_wq, &bq->usb_work);
11318c0984e5SSebastian Reichel 
11328c0984e5SSebastian Reichel 	return NOTIFY_OK;
11338c0984e5SSebastian Reichel }
11348c0984e5SSebastian Reichel 
113579d35365SHans de Goede #ifdef CONFIG_REGULATOR
113679d35365SHans de Goede static int bq25890_vbus_enable(struct regulator_dev *rdev)
113779d35365SHans de Goede {
113879d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
1139*d54bf877SHans de Goede 	union power_supply_propval val = {
1140*d54bf877SHans de Goede 		.intval = 0,
1141*d54bf877SHans de Goede 	};
1142*d54bf877SHans de Goede 
1143*d54bf877SHans de Goede 	/*
1144*d54bf877SHans de Goede 	 * When enabling 5V boost / Vbus output, we need to put the secondary
1145*d54bf877SHans de Goede 	 * charger in Hi-Z mode to avoid it trying to charge the secondary
1146*d54bf877SHans de Goede 	 * battery from the 5V boost output.
1147*d54bf877SHans de Goede 	 */
1148*d54bf877SHans de Goede 	if (bq->secondary_chrg)
1149*d54bf877SHans de Goede 		power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val);
115079d35365SHans de Goede 
115179d35365SHans de Goede 	return bq25890_set_otg_cfg(bq, 1);
115279d35365SHans de Goede }
115379d35365SHans de Goede 
115479d35365SHans de Goede static int bq25890_vbus_disable(struct regulator_dev *rdev)
115579d35365SHans de Goede {
115679d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
1157*d54bf877SHans de Goede 	union power_supply_propval val = {
1158*d54bf877SHans de Goede 		.intval = 1,
1159*d54bf877SHans de Goede 	};
1160*d54bf877SHans de Goede 	int ret;
116179d35365SHans de Goede 
1162*d54bf877SHans de Goede 	ret = bq25890_set_otg_cfg(bq, 0);
1163*d54bf877SHans de Goede 	if (ret)
1164*d54bf877SHans de Goede 		return ret;
1165*d54bf877SHans de Goede 
1166*d54bf877SHans de Goede 	if (bq->secondary_chrg)
1167*d54bf877SHans de Goede 		power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val);
1168*d54bf877SHans de Goede 
1169*d54bf877SHans de Goede 	return 0;
117079d35365SHans de Goede }
117179d35365SHans de Goede 
117279d35365SHans de Goede static int bq25890_vbus_is_enabled(struct regulator_dev *rdev)
117379d35365SHans de Goede {
117479d35365SHans de Goede 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
117579d35365SHans de Goede 
117679d35365SHans de Goede 	return bq25890_field_read(bq, F_OTG_CFG);
117779d35365SHans de Goede }
117879d35365SHans de Goede 
117985052e90SMarek Vasut static int bq25890_vbus_get_voltage(struct regulator_dev *rdev)
118085052e90SMarek Vasut {
118185052e90SMarek Vasut 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
118285052e90SMarek Vasut 
118385052e90SMarek Vasut 	return bq25890_get_vbus_voltage(bq);
118485052e90SMarek Vasut }
118585052e90SMarek Vasut 
118614a3d159SMarek Vasut static int bq25890_vsys_get_voltage(struct regulator_dev *rdev)
118714a3d159SMarek Vasut {
118814a3d159SMarek Vasut 	struct bq25890_device *bq = rdev_get_drvdata(rdev);
118914a3d159SMarek Vasut 	int ret;
119014a3d159SMarek Vasut 
119114a3d159SMarek Vasut 	/* Should be some output voltage ? */
119214a3d159SMarek Vasut 	ret = bq25890_field_read(bq, F_SYSV); /* read measured value */
119314a3d159SMarek Vasut 	if (ret < 0)
119414a3d159SMarek Vasut 		return ret;
119514a3d159SMarek Vasut 
119614a3d159SMarek Vasut 	/* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
119714a3d159SMarek Vasut 	return 2304000 + ret * 20000;
119814a3d159SMarek Vasut }
119914a3d159SMarek Vasut 
120079d35365SHans de Goede static const struct regulator_ops bq25890_vbus_ops = {
120179d35365SHans de Goede 	.enable = bq25890_vbus_enable,
120279d35365SHans de Goede 	.disable = bq25890_vbus_disable,
120379d35365SHans de Goede 	.is_enabled = bq25890_vbus_is_enabled,
120485052e90SMarek Vasut 	.get_voltage = bq25890_vbus_get_voltage,
120579d35365SHans de Goede };
120679d35365SHans de Goede 
120779d35365SHans de Goede static const struct regulator_desc bq25890_vbus_desc = {
120879d35365SHans de Goede 	.name = "usb_otg_vbus",
120979d35365SHans de Goede 	.of_match = "usb-otg-vbus",
121079d35365SHans de Goede 	.type = REGULATOR_VOLTAGE,
121179d35365SHans de Goede 	.owner = THIS_MODULE,
121279d35365SHans de Goede 	.ops = &bq25890_vbus_ops,
121379d35365SHans de Goede };
12145f5c10ecSMarek Vasut 
121514a3d159SMarek Vasut static const struct regulator_ops bq25890_vsys_ops = {
121614a3d159SMarek Vasut 	.get_voltage = bq25890_vsys_get_voltage,
121714a3d159SMarek Vasut };
121814a3d159SMarek Vasut 
121914a3d159SMarek Vasut static const struct regulator_desc bq25890_vsys_desc = {
122014a3d159SMarek Vasut 	.name = "vsys",
122114a3d159SMarek Vasut 	.of_match = "vsys",
122214a3d159SMarek Vasut 	.type = REGULATOR_VOLTAGE,
122314a3d159SMarek Vasut 	.owner = THIS_MODULE,
122414a3d159SMarek Vasut 	.ops = &bq25890_vsys_ops,
122514a3d159SMarek Vasut };
122614a3d159SMarek Vasut 
12275f5c10ecSMarek Vasut static int bq25890_register_regulator(struct bq25890_device *bq)
12285f5c10ecSMarek Vasut {
12295f5c10ecSMarek Vasut 	struct bq25890_platform_data *pdata = dev_get_platdata(bq->dev);
12305f5c10ecSMarek Vasut 	struct regulator_config cfg = {
12315f5c10ecSMarek Vasut 		.dev = bq->dev,
12325f5c10ecSMarek Vasut 		.driver_data = bq,
12335f5c10ecSMarek Vasut 	};
12345f5c10ecSMarek Vasut 	struct regulator_dev *reg;
12355f5c10ecSMarek Vasut 
12365f5c10ecSMarek Vasut 	if (pdata)
12375f5c10ecSMarek Vasut 		cfg.init_data = pdata->regulator_init_data;
12385f5c10ecSMarek Vasut 
12395f5c10ecSMarek Vasut 	reg = devm_regulator_register(bq->dev, &bq25890_vbus_desc, &cfg);
12405f5c10ecSMarek Vasut 	if (IS_ERR(reg)) {
12415f5c10ecSMarek Vasut 		return dev_err_probe(bq->dev, PTR_ERR(reg),
12425f5c10ecSMarek Vasut 				     "registering vbus regulator");
12435f5c10ecSMarek Vasut 	}
12445f5c10ecSMarek Vasut 
1245571650b3SHans de Goede 	/* pdata->regulator_init_data is for vbus only */
1246571650b3SHans de Goede 	cfg.init_data = NULL;
124714a3d159SMarek Vasut 	reg = devm_regulator_register(bq->dev, &bq25890_vsys_desc, &cfg);
124814a3d159SMarek Vasut 	if (IS_ERR(reg)) {
124914a3d159SMarek Vasut 		return dev_err_probe(bq->dev, PTR_ERR(reg),
125014a3d159SMarek Vasut 				     "registering vsys regulator");
125114a3d159SMarek Vasut 	}
125214a3d159SMarek Vasut 
12535f5c10ecSMarek Vasut 	return 0;
12545f5c10ecSMarek Vasut }
12555f5c10ecSMarek Vasut #else
12565f5c10ecSMarek Vasut static inline int
12575f5c10ecSMarek Vasut bq25890_register_regulator(struct bq25890_device *bq)
12585f5c10ecSMarek Vasut {
12595f5c10ecSMarek Vasut 	return 0;
12605f5c10ecSMarek Vasut }
126179d35365SHans de Goede #endif
126279d35365SHans de Goede 
1263d20267c9SYauhen Kharuzhy static int bq25890_get_chip_version(struct bq25890_device *bq)
1264d20267c9SYauhen Kharuzhy {
1265d20267c9SYauhen Kharuzhy 	int id, rev;
1266d20267c9SYauhen Kharuzhy 
1267d20267c9SYauhen Kharuzhy 	id = bq25890_field_read(bq, F_PN);
1268d20267c9SYauhen Kharuzhy 	if (id < 0) {
1269172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip ID: %d\n", id);
1270d20267c9SYauhen Kharuzhy 		return id;
1271d20267c9SYauhen Kharuzhy 	}
1272d20267c9SYauhen Kharuzhy 
1273d20267c9SYauhen Kharuzhy 	rev = bq25890_field_read(bq, F_DEV_REV);
1274d20267c9SYauhen Kharuzhy 	if (rev < 0) {
1275172d0cceSMartin Kepplinger 		dev_err(bq->dev, "Cannot read chip revision: %d\n", rev);
1276cb619e80SColin Ian King 		return rev;
1277d20267c9SYauhen Kharuzhy 	}
1278d20267c9SYauhen Kharuzhy 
1279d20267c9SYauhen Kharuzhy 	switch (id) {
1280d20267c9SYauhen Kharuzhy 	case BQ25890_ID:
1281d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25890;
1282d20267c9SYauhen Kharuzhy 		break;
1283d20267c9SYauhen Kharuzhy 
1284d20267c9SYauhen Kharuzhy 	/* BQ25892 and BQ25896 share same ID 0 */
1285d20267c9SYauhen Kharuzhy 	case BQ25896_ID:
1286d20267c9SYauhen Kharuzhy 		switch (rev) {
1287d20267c9SYauhen Kharuzhy 		case 2:
1288d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25896;
1289d20267c9SYauhen Kharuzhy 			break;
1290d20267c9SYauhen Kharuzhy 		case 1:
1291d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1292d20267c9SYauhen Kharuzhy 			break;
1293d20267c9SYauhen Kharuzhy 		default:
1294d20267c9SYauhen Kharuzhy 			dev_err(bq->dev,
1295d20267c9SYauhen Kharuzhy 				"Unknown device revision %d, assume BQ25892\n",
1296d20267c9SYauhen Kharuzhy 				rev);
1297d20267c9SYauhen Kharuzhy 			bq->chip_version = BQ25892;
1298d20267c9SYauhen Kharuzhy 		}
1299d20267c9SYauhen Kharuzhy 		break;
1300d20267c9SYauhen Kharuzhy 
1301d20267c9SYauhen Kharuzhy 	case BQ25895_ID:
1302d20267c9SYauhen Kharuzhy 		bq->chip_version = BQ25895;
1303d20267c9SYauhen Kharuzhy 		break;
1304d20267c9SYauhen Kharuzhy 
1305d20267c9SYauhen Kharuzhy 	default:
1306d20267c9SYauhen Kharuzhy 		dev_err(bq->dev, "Unknown chip ID %d\n", id);
1307d20267c9SYauhen Kharuzhy 		return -ENODEV;
1308d20267c9SYauhen Kharuzhy 	}
1309d20267c9SYauhen Kharuzhy 
1310d20267c9SYauhen Kharuzhy 	return 0;
1311d20267c9SYauhen Kharuzhy }
1312d20267c9SYauhen Kharuzhy 
13138c0984e5SSebastian Reichel static int bq25890_irq_probe(struct bq25890_device *bq)
13148c0984e5SSebastian Reichel {
13158c0984e5SSebastian Reichel 	struct gpio_desc *irq;
13168c0984e5SSebastian Reichel 
131786775879SAndy Shevchenko 	irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN);
1318172d0cceSMartin Kepplinger 	if (IS_ERR(irq))
1319172d0cceSMartin Kepplinger 		return dev_err_probe(bq->dev, PTR_ERR(irq),
1320172d0cceSMartin Kepplinger 				     "Could not probe irq pin.\n");
13218c0984e5SSebastian Reichel 
13228c0984e5SSebastian Reichel 	return gpiod_to_irq(irq);
13238c0984e5SSebastian Reichel }
13248c0984e5SSebastian Reichel 
13258c0984e5SSebastian Reichel static int bq25890_fw_read_u32_props(struct bq25890_device *bq)
13268c0984e5SSebastian Reichel {
13278c0984e5SSebastian Reichel 	int ret;
13288c0984e5SSebastian Reichel 	u32 property;
13298c0984e5SSebastian Reichel 	int i;
13308c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
13318c0984e5SSebastian Reichel 	struct {
13328c0984e5SSebastian Reichel 		char *name;
13338c0984e5SSebastian Reichel 		bool optional;
13348c0984e5SSebastian Reichel 		enum bq25890_table_ids tbl_id;
13358c0984e5SSebastian Reichel 		u8 *conv_data; /* holds converted value from given property */
13368c0984e5SSebastian Reichel 	} props[] = {
13378c0984e5SSebastian Reichel 		/* required properties */
13388c0984e5SSebastian Reichel 		{"ti,charge-current", false, TBL_ICHG, &init->ichg},
13398c0984e5SSebastian Reichel 		{"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg},
13408c0984e5SSebastian Reichel 		{"ti,termination-current", false, TBL_ITERM, &init->iterm},
13418c0984e5SSebastian Reichel 		{"ti,precharge-current", false, TBL_ITERM, &init->iprechg},
13428c0984e5SSebastian Reichel 		{"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin},
13438c0984e5SSebastian Reichel 		{"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv},
13448c0984e5SSebastian Reichel 		{"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti},
13458c0984e5SSebastian Reichel 
13468c0984e5SSebastian Reichel 		/* optional properties */
134772408329SMichał Mirosław 		{"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg},
134872408329SMichał Mirosław 		{"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp},
134972408329SMichał Mirosław 		{"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp},
13508c0984e5SSebastian Reichel 	};
13518c0984e5SSebastian Reichel 
13528c0984e5SSebastian Reichel 	/* initialize data for optional properties */
13538c0984e5SSebastian Reichel 	init->treg = 3; /* 120 degrees Celsius */
135472408329SMichał Mirosław 	init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */
13558c0984e5SSebastian Reichel 
13568c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(props); i++) {
13578c0984e5SSebastian Reichel 		ret = device_property_read_u32(bq->dev, props[i].name,
13588c0984e5SSebastian Reichel 					       &property);
13598c0984e5SSebastian Reichel 		if (ret < 0) {
13608c0984e5SSebastian Reichel 			if (props[i].optional)
13618c0984e5SSebastian Reichel 				continue;
13628c0984e5SSebastian Reichel 
13639d9ae341SAngus Ainslie (Purism) 			dev_err(bq->dev, "Unable to read property %d %s\n", ret,
13649d9ae341SAngus Ainslie (Purism) 				props[i].name);
13659d9ae341SAngus Ainslie (Purism) 
13668c0984e5SSebastian Reichel 			return ret;
13678c0984e5SSebastian Reichel 		}
13688c0984e5SSebastian Reichel 
13698c0984e5SSebastian Reichel 		*props[i].conv_data = bq25890_find_idx(property,
13708c0984e5SSebastian Reichel 						       props[i].tbl_id);
13718c0984e5SSebastian Reichel 	}
13728c0984e5SSebastian Reichel 
13738c0984e5SSebastian Reichel 	return 0;
13748c0984e5SSebastian Reichel }
13758c0984e5SSebastian Reichel 
13768c0984e5SSebastian Reichel static int bq25890_fw_probe(struct bq25890_device *bq)
13778c0984e5SSebastian Reichel {
13788c0984e5SSebastian Reichel 	int ret;
13798c0984e5SSebastian Reichel 	struct bq25890_init_data *init = &bq->init_data;
1380*d54bf877SHans de Goede 	const char *str;
1381*d54bf877SHans de Goede 
1382*d54bf877SHans de Goede 	ret = device_property_read_string(bq->dev, "linux,secondary-charger-name", &str);
1383*d54bf877SHans de Goede 	if (ret == 0) {
1384*d54bf877SHans de Goede 		bq->secondary_chrg = power_supply_get_by_name(str);
1385*d54bf877SHans de Goede 		if (!bq->secondary_chrg)
1386*d54bf877SHans de Goede 			return -EPROBE_DEFER;
1387*d54bf877SHans de Goede 	}
13888c0984e5SSebastian Reichel 
138948f45b09SYauhen Kharuzhy 	/* Optional, left at 0 if property is not present */
139048f45b09SYauhen Kharuzhy 	device_property_read_u32(bq->dev, "linux,pump-express-vbus-max",
139148f45b09SYauhen Kharuzhy 				 &bq->pump_express_vbus_max);
139248f45b09SYauhen Kharuzhy 
13937e3b8e35SHans de Goede 	bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset");
139440428bd4SHans de Goede 	bq->read_back_init_data = device_property_read_bool(bq->dev,
139540428bd4SHans de Goede 						"linux,read-back-settings");
139640428bd4SHans de Goede 	if (bq->read_back_init_data)
139740428bd4SHans de Goede 		return 0;
13987e3b8e35SHans de Goede 
13998c0984e5SSebastian Reichel 	ret = bq25890_fw_read_u32_props(bq);
14008c0984e5SSebastian Reichel 	if (ret < 0)
14018c0984e5SSebastian Reichel 		return ret;
14028c0984e5SSebastian Reichel 
14038c0984e5SSebastian Reichel 	init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin");
14048c0984e5SSebastian Reichel 	init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq");
14058c0984e5SSebastian Reichel 
14068c0984e5SSebastian Reichel 	return 0;
14078c0984e5SSebastian Reichel }
14088c0984e5SSebastian Reichel 
1409a7aaa800SHans de Goede static void bq25890_non_devm_cleanup(void *data)
1410a7aaa800SHans de Goede {
1411a7aaa800SHans de Goede 	struct bq25890_device *bq = data;
1412a7aaa800SHans de Goede 
1413a7aaa800SHans de Goede 	cancel_delayed_work_sync(&bq->pump_express_work);
14144e9498b8SHans de Goede 
14154e9498b8SHans de Goede 	if (bq->id >= 0) {
14164e9498b8SHans de Goede 		mutex_lock(&bq25890_id_mutex);
14174e9498b8SHans de Goede 		idr_remove(&bq25890_id, bq->id);
14184e9498b8SHans de Goede 		mutex_unlock(&bq25890_id_mutex);
14194e9498b8SHans de Goede 	}
1420a7aaa800SHans de Goede }
1421a7aaa800SHans de Goede 
1422c5cddca2SUwe Kleine-König static int bq25890_probe(struct i2c_client *client)
14238c0984e5SSebastian Reichel {
14248c0984e5SSebastian Reichel 	struct device *dev = &client->dev;
14258c0984e5SSebastian Reichel 	struct bq25890_device *bq;
14268c0984e5SSebastian Reichel 	int ret;
14278c0984e5SSebastian Reichel 
14288c0984e5SSebastian Reichel 	bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL);
14298c0984e5SSebastian Reichel 	if (!bq)
14308c0984e5SSebastian Reichel 		return -ENOMEM;
14318c0984e5SSebastian Reichel 
14328c0984e5SSebastian Reichel 	bq->client = client;
14338c0984e5SSebastian Reichel 	bq->dev = dev;
14344e9498b8SHans de Goede 	bq->id = -1;
14358c0984e5SSebastian Reichel 
14368c0984e5SSebastian Reichel 	mutex_init(&bq->lock);
143748f45b09SYauhen Kharuzhy 	INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work);
14388c0984e5SSebastian Reichel 
14398c0984e5SSebastian Reichel 	bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config);
1440172d0cceSMartin Kepplinger 	if (IS_ERR(bq->rmap))
1441172d0cceSMartin Kepplinger 		return dev_err_probe(dev, PTR_ERR(bq->rmap),
1442172d0cceSMartin Kepplinger 				     "failed to allocate register map\n");
14438c0984e5SSebastian Reichel 
1444c1ae3a4eSHans de Goede 	ret = devm_regmap_field_bulk_alloc(dev, bq->rmap, bq->rmap_fields,
1445c1ae3a4eSHans de Goede 					   bq25890_reg_fields, F_MAX_FIELDS);
1446c1ae3a4eSHans de Goede 	if (ret)
1447c1ae3a4eSHans de Goede 		return ret;
14488c0984e5SSebastian Reichel 
14498c0984e5SSebastian Reichel 	i2c_set_clientdata(client, bq);
14508c0984e5SSebastian Reichel 
1451d20267c9SYauhen Kharuzhy 	ret = bq25890_get_chip_version(bq);
1452d20267c9SYauhen Kharuzhy 	if (ret) {
1453172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret);
1454d20267c9SYauhen Kharuzhy 		return ret;
14558c0984e5SSebastian Reichel 	}
14568c0984e5SSebastian Reichel 
14578c0984e5SSebastian Reichel 	ret = bq25890_fw_probe(bq);
1458f481d5b8SHans de Goede 	if (ret < 0)
1459f481d5b8SHans de Goede 		return dev_err_probe(dev, ret, "reading device properties\n");
14608c0984e5SSebastian Reichel 
14618c0984e5SSebastian Reichel 	ret = bq25890_hw_init(bq);
14628c0984e5SSebastian Reichel 	if (ret < 0) {
1463172d0cceSMartin Kepplinger 		dev_err(dev, "Cannot initialize the chip: %d\n", ret);
14648c0984e5SSebastian Reichel 		return ret;
14658c0984e5SSebastian Reichel 	}
14668c0984e5SSebastian Reichel 
14678c0984e5SSebastian Reichel 	if (client->irq <= 0)
14688c0984e5SSebastian Reichel 		client->irq = bq25890_irq_probe(bq);
14698c0984e5SSebastian Reichel 
14708c0984e5SSebastian Reichel 	if (client->irq < 0) {
14718c0984e5SSebastian Reichel 		dev_err(dev, "No irq resource found.\n");
14728c0984e5SSebastian Reichel 		return client->irq;
14738c0984e5SSebastian Reichel 	}
14748c0984e5SSebastian Reichel 
14758c0984e5SSebastian Reichel 	/* OTG reporting */
14768c0984e5SSebastian Reichel 	bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
14775f5c10ecSMarek Vasut 
1478a7aaa800SHans de Goede 	/*
1479a7aaa800SHans de Goede 	 * This must be before bq25890_power_supply_init(), so that it runs
1480a7aaa800SHans de Goede 	 * after devm unregisters the power_supply.
1481a7aaa800SHans de Goede 	 */
1482a7aaa800SHans de Goede 	ret = devm_add_action_or_reset(dev, bq25890_non_devm_cleanup, bq);
1483a7aaa800SHans de Goede 	if (ret)
1484a7aaa800SHans de Goede 		return ret;
1485a7aaa800SHans de Goede 
14865f5c10ecSMarek Vasut 	ret = bq25890_register_regulator(bq);
14875f5c10ecSMarek Vasut 	if (ret)
14885f5c10ecSMarek Vasut 		return ret;
14895f5c10ecSMarek Vasut 
1490d01363daSHans de Goede 	ret = bq25890_power_supply_init(bq);
14917e6fb678SHans de Goede 	if (ret < 0)
14927e6fb678SHans de Goede 		return dev_err_probe(dev, ret, "registering power supply\n");
1493d01363daSHans de Goede 
14948c0984e5SSebastian Reichel 	ret = devm_request_threaded_irq(dev, client->irq, NULL,
14958c0984e5SSebastian Reichel 					bq25890_irq_handler_thread,
14968c0984e5SSebastian Reichel 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
14978c0984e5SSebastian Reichel 					BQ25890_IRQ_PIN, bq);
14988c0984e5SSebastian Reichel 	if (ret)
14997e6fb678SHans de Goede 		return ret;
15007e6fb678SHans de Goede 
15017e6fb678SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
15027e6fb678SHans de Goede 		INIT_WORK(&bq->usb_work, bq25890_usb_work);
15037e6fb678SHans de Goede 		bq->usb_nb.notifier_call = bq25890_usb_notifier;
15047e6fb678SHans de Goede 		usb_register_notifier(bq->usb_phy, &bq->usb_nb);
15057e6fb678SHans de Goede 	}
15068c0984e5SSebastian Reichel 
15078c0984e5SSebastian Reichel 	return 0;
15088c0984e5SSebastian Reichel }
15098c0984e5SSebastian Reichel 
1510ed5c2f5fSUwe Kleine-König static void bq25890_remove(struct i2c_client *client)
15118c0984e5SSebastian Reichel {
15128c0984e5SSebastian Reichel 	struct bq25890_device *bq = i2c_get_clientdata(client);
15138c0984e5SSebastian Reichel 
15147e6fb678SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy)) {
15158c0984e5SSebastian Reichel 		usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
15167e6fb678SHans de Goede 		cancel_work_sync(&bq->usb_work);
15177e6fb678SHans de Goede 	}
15188c0984e5SSebastian Reichel 
15197e3b8e35SHans de Goede 	if (!bq->skip_reset) {
15208c0984e5SSebastian Reichel 		/* reset all registers to default values */
15218c0984e5SSebastian Reichel 		bq25890_chip_reset(bq);
15227e3b8e35SHans de Goede 	}
15238c0984e5SSebastian Reichel }
15248c0984e5SSebastian Reichel 
152579d35365SHans de Goede static void bq25890_shutdown(struct i2c_client *client)
152679d35365SHans de Goede {
152779d35365SHans de Goede 	struct bq25890_device *bq = i2c_get_clientdata(client);
152879d35365SHans de Goede 
152979d35365SHans de Goede 	/*
153079d35365SHans de Goede 	 * TODO this if + return should probably be removed, but that would
153179d35365SHans de Goede 	 * introduce a function change for boards using the usb-phy framework.
153279d35365SHans de Goede 	 * This needs to be tested on such a board before making this change.
153379d35365SHans de Goede 	 */
153479d35365SHans de Goede 	if (!IS_ERR_OR_NULL(bq->usb_phy))
153579d35365SHans de Goede 		return;
153679d35365SHans de Goede 
153779d35365SHans de Goede 	/*
153879d35365SHans de Goede 	 * Turn off the 5v Boost regulator which outputs Vbus to the device's
153979d35365SHans de Goede 	 * Micro-USB or Type-C USB port. Leaving this on drains power and
154079d35365SHans de Goede 	 * this avoids the PMIC on some device-models seeing this as Vbus
154179d35365SHans de Goede 	 * getting inserted after shutdown, causing the device to immediately
154279d35365SHans de Goede 	 * power-up again.
154379d35365SHans de Goede 	 */
154479d35365SHans de Goede 	bq25890_set_otg_cfg(bq, 0);
154579d35365SHans de Goede }
154679d35365SHans de Goede 
15478c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
15488c0984e5SSebastian Reichel static int bq25890_suspend(struct device *dev)
15498c0984e5SSebastian Reichel {
15508c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
15518c0984e5SSebastian Reichel 
15528c0984e5SSebastian Reichel 	/*
15538c0984e5SSebastian Reichel 	 * If charger is removed, while in suspend, make sure ADC is diabled
15548c0984e5SSebastian Reichel 	 * since it consumes slightly more power.
15558c0984e5SSebastian Reichel 	 */
155621d90edaSMichał Mirosław 	return bq25890_field_write(bq, F_CONV_RATE, 0);
15578c0984e5SSebastian Reichel }
15588c0984e5SSebastian Reichel 
15598c0984e5SSebastian Reichel static int bq25890_resume(struct device *dev)
15608c0984e5SSebastian Reichel {
15618c0984e5SSebastian Reichel 	int ret;
15628c0984e5SSebastian Reichel 	struct bq25890_device *bq = dev_get_drvdata(dev);
15638c0984e5SSebastian Reichel 
156472d9cd9cSMichał Mirosław 	mutex_lock(&bq->lock);
156572d9cd9cSMichał Mirosław 
156672d9cd9cSMichał Mirosław 	ret = bq25890_get_chip_state(bq, &bq->state);
15678c0984e5SSebastian Reichel 	if (ret < 0)
1568cf5701bfSDan Carpenter 		goto unlock;
15698c0984e5SSebastian Reichel 
15708c0984e5SSebastian Reichel 	/* Re-enable ADC only if charger is plugged in. */
157172d9cd9cSMichał Mirosław 	if (bq->state.online) {
157221d90edaSMichał Mirosław 		ret = bq25890_field_write(bq, F_CONV_RATE, 1);
15738c0984e5SSebastian Reichel 		if (ret < 0)
1574cf5701bfSDan Carpenter 			goto unlock;
15758c0984e5SSebastian Reichel 	}
15768c0984e5SSebastian Reichel 
15778c0984e5SSebastian Reichel 	/* signal userspace, maybe state changed while suspended */
15788c0984e5SSebastian Reichel 	power_supply_changed(bq->charger);
15798c0984e5SSebastian Reichel 
1580cf5701bfSDan Carpenter unlock:
158172d9cd9cSMichał Mirosław 	mutex_unlock(&bq->lock);
158272d9cd9cSMichał Mirosław 
1583cf5701bfSDan Carpenter 	return ret;
15848c0984e5SSebastian Reichel }
15858c0984e5SSebastian Reichel #endif
15868c0984e5SSebastian Reichel 
15878c0984e5SSebastian Reichel static const struct dev_pm_ops bq25890_pm = {
15888c0984e5SSebastian Reichel 	SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume)
15898c0984e5SSebastian Reichel };
15908c0984e5SSebastian Reichel 
15918c0984e5SSebastian Reichel static const struct i2c_device_id bq25890_i2c_ids[] = {
15928c0984e5SSebastian Reichel 	{ "bq25890", 0 },
159346aa27e7SYauhen Kharuzhy 	{ "bq25892", 0 },
159446aa27e7SYauhen Kharuzhy 	{ "bq25895", 0 },
159546aa27e7SYauhen Kharuzhy 	{ "bq25896", 0 },
15968c0984e5SSebastian Reichel 	{},
15978c0984e5SSebastian Reichel };
15988c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids);
15998c0984e5SSebastian Reichel 
16008c0984e5SSebastian Reichel static const struct of_device_id bq25890_of_match[] = {
16018c0984e5SSebastian Reichel 	{ .compatible = "ti,bq25890", },
160246aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25892", },
160346aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25895", },
160446aa27e7SYauhen Kharuzhy 	{ .compatible = "ti,bq25896", },
16058c0984e5SSebastian Reichel 	{ },
16068c0984e5SSebastian Reichel };
16078c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, bq25890_of_match);
16088c0984e5SSebastian Reichel 
160902067dc9SKrzysztof Kozlowski #ifdef CONFIG_ACPI
16108c0984e5SSebastian Reichel static const struct acpi_device_id bq25890_acpi_match[] = {
16118c0984e5SSebastian Reichel 	{"BQ258900", 0},
16128c0984e5SSebastian Reichel 	{},
16138c0984e5SSebastian Reichel };
16148c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match);
161502067dc9SKrzysztof Kozlowski #endif
16168c0984e5SSebastian Reichel 
16178c0984e5SSebastian Reichel static struct i2c_driver bq25890_driver = {
16188c0984e5SSebastian Reichel 	.driver = {
16198c0984e5SSebastian Reichel 		.name = "bq25890-charger",
16208c0984e5SSebastian Reichel 		.of_match_table = of_match_ptr(bq25890_of_match),
16218c0984e5SSebastian Reichel 		.acpi_match_table = ACPI_PTR(bq25890_acpi_match),
16228c0984e5SSebastian Reichel 		.pm = &bq25890_pm,
16238c0984e5SSebastian Reichel 	},
1624c5cddca2SUwe Kleine-König 	.probe_new = bq25890_probe,
16258c0984e5SSebastian Reichel 	.remove = bq25890_remove,
162679d35365SHans de Goede 	.shutdown = bq25890_shutdown,
16278c0984e5SSebastian Reichel 	.id_table = bq25890_i2c_ids,
16288c0984e5SSebastian Reichel };
16298c0984e5SSebastian Reichel module_i2c_driver(bq25890_driver);
16308c0984e5SSebastian Reichel 
16318c0984e5SSebastian Reichel MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
16328c0984e5SSebastian Reichel MODULE_DESCRIPTION("bq25890 charger driver");
16338c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
1634