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 30*48f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_START_DELAY (5 * HZ) 31*48f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_MAX_TRIES 6 32*48f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_VBUS_MARGIN_uV 1000000 33*48f45b09SYauhen Kharuzhy 34d20267c9SYauhen Kharuzhy enum bq25890_chip_version { 35d20267c9SYauhen Kharuzhy BQ25890, 36d20267c9SYauhen Kharuzhy BQ25892, 37d20267c9SYauhen Kharuzhy BQ25895, 38d20267c9SYauhen Kharuzhy BQ25896, 39d20267c9SYauhen Kharuzhy }; 40d20267c9SYauhen Kharuzhy 415956fca7SMichał Mirosław static const char *const bq25890_chip_name[] = { 425956fca7SMichał Mirosław "BQ25890", 435956fca7SMichał Mirosław "BQ25892", 445956fca7SMichał Mirosław "BQ25895", 455956fca7SMichał Mirosław "BQ25896", 465956fca7SMichał Mirosław }; 475956fca7SMichał Mirosław 488c0984e5SSebastian Reichel enum bq25890_fields { 49766873c1SYauhen Kharuzhy F_EN_HIZ, F_EN_ILIM, F_IINLIM, /* Reg00 */ 508c0984e5SSebastian Reichel F_BHOT, F_BCOLD, F_VINDPM_OFS, /* Reg01 */ 518c0984e5SSebastian Reichel F_CONV_START, F_CONV_RATE, F_BOOSTF, F_ICO_EN, 528c0984e5SSebastian Reichel F_HVDCP_EN, F_MAXC_EN, F_FORCE_DPM, F_AUTO_DPDM_EN, /* Reg02 */ 53d20267c9SYauhen Kharuzhy F_BAT_LOAD_EN, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_SYSVMIN, 54d20267c9SYauhen Kharuzhy F_MIN_VBAT_SEL, /* Reg03 */ 558c0984e5SSebastian Reichel F_PUMPX_EN, F_ICHG, /* Reg04 */ 568c0984e5SSebastian Reichel F_IPRECHG, F_ITERM, /* Reg05 */ 578c0984e5SSebastian Reichel F_VREG, F_BATLOWV, F_VRECHG, /* Reg06 */ 588c0984e5SSebastian Reichel F_TERM_EN, F_STAT_DIS, F_WD, F_TMR_EN, F_CHG_TMR, 598c0984e5SSebastian Reichel F_JEITA_ISET, /* Reg07 */ 608c0984e5SSebastian Reichel F_BATCMP, F_VCLAMP, F_TREG, /* Reg08 */ 618c0984e5SSebastian Reichel F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JEITA_VSET, 628c0984e5SSebastian Reichel F_BATFET_DLY, F_BATFET_RST_EN, F_PUMPX_UP, F_PUMPX_DN, /* Reg09 */ 63d20267c9SYauhen Kharuzhy F_BOOSTV, F_PFM_OTG_DIS, F_BOOSTI, /* Reg0A */ 64d20267c9SYauhen Kharuzhy F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_SDP_STAT, F_0B_RSVD, 65d20267c9SYauhen Kharuzhy F_VSYS_STAT, /* Reg0B */ 668c0984e5SSebastian Reichel F_WD_FAULT, F_BOOST_FAULT, F_CHG_FAULT, F_BAT_FAULT, 678c0984e5SSebastian Reichel F_NTC_FAULT, /* Reg0C */ 688c0984e5SSebastian Reichel F_FORCE_VINDPM, F_VINDPM, /* Reg0D */ 698c0984e5SSebastian Reichel F_THERM_STAT, F_BATV, /* Reg0E */ 708c0984e5SSebastian Reichel F_SYSV, /* Reg0F */ 718c0984e5SSebastian Reichel F_TSPCT, /* Reg10 */ 728c0984e5SSebastian Reichel F_VBUS_GD, F_VBUSV, /* Reg11 */ 738c0984e5SSebastian Reichel F_ICHGR, /* Reg12 */ 748c0984e5SSebastian Reichel F_VDPM_STAT, F_IDPM_STAT, F_IDPM_LIM, /* Reg13 */ 758c0984e5SSebastian Reichel F_REG_RST, F_ICO_OPTIMIZED, F_PN, F_TS_PROFILE, F_DEV_REV, /* Reg14 */ 768c0984e5SSebastian Reichel 778c0984e5SSebastian Reichel F_MAX_FIELDS 788c0984e5SSebastian Reichel }; 798c0984e5SSebastian Reichel 808c0984e5SSebastian Reichel /* initial field values, converted to register values */ 818c0984e5SSebastian Reichel struct bq25890_init_data { 828c0984e5SSebastian Reichel u8 ichg; /* charge current */ 838c0984e5SSebastian Reichel u8 vreg; /* regulation voltage */ 848c0984e5SSebastian Reichel u8 iterm; /* termination current */ 858c0984e5SSebastian Reichel u8 iprechg; /* precharge current */ 868c0984e5SSebastian Reichel u8 sysvmin; /* minimum system voltage limit */ 878c0984e5SSebastian Reichel u8 boostv; /* boost regulation voltage */ 888c0984e5SSebastian Reichel u8 boosti; /* boost current limit */ 898c0984e5SSebastian Reichel u8 boostf; /* boost frequency */ 908c0984e5SSebastian Reichel u8 ilim_en; /* enable ILIM pin */ 918c0984e5SSebastian Reichel u8 treg; /* thermal regulation threshold */ 9272408329SMichał Mirosław u8 rbatcomp; /* IBAT sense resistor value */ 9372408329SMichał Mirosław u8 vclamp; /* IBAT compensation voltage limit */ 948c0984e5SSebastian Reichel }; 958c0984e5SSebastian Reichel 968c0984e5SSebastian Reichel struct bq25890_state { 978c0984e5SSebastian Reichel u8 online; 988c0984e5SSebastian Reichel u8 chrg_status; 998c0984e5SSebastian Reichel u8 chrg_fault; 1008c0984e5SSebastian Reichel u8 vsys_status; 1018c0984e5SSebastian Reichel u8 boost_fault; 1028c0984e5SSebastian Reichel u8 bat_fault; 103c562a43aSYauhen Kharuzhy u8 ntc_fault; 1048c0984e5SSebastian Reichel }; 1058c0984e5SSebastian Reichel 1068c0984e5SSebastian Reichel struct bq25890_device { 1078c0984e5SSebastian Reichel struct i2c_client *client; 1088c0984e5SSebastian Reichel struct device *dev; 1098c0984e5SSebastian Reichel struct power_supply *charger; 1108c0984e5SSebastian Reichel 1118c0984e5SSebastian Reichel struct usb_phy *usb_phy; 1128c0984e5SSebastian Reichel struct notifier_block usb_nb; 1138c0984e5SSebastian Reichel struct work_struct usb_work; 114*48f45b09SYauhen Kharuzhy struct delayed_work pump_express_work; 1158c0984e5SSebastian Reichel unsigned long usb_event; 1168c0984e5SSebastian Reichel 1178c0984e5SSebastian Reichel struct regmap *rmap; 1188c0984e5SSebastian Reichel struct regmap_field *rmap_fields[F_MAX_FIELDS]; 1198c0984e5SSebastian Reichel 1207e3b8e35SHans de Goede bool skip_reset; 12140428bd4SHans de Goede bool read_back_init_data; 122*48f45b09SYauhen Kharuzhy u32 pump_express_vbus_max; 123d20267c9SYauhen Kharuzhy enum bq25890_chip_version chip_version; 1248c0984e5SSebastian Reichel struct bq25890_init_data init_data; 1258c0984e5SSebastian Reichel struct bq25890_state state; 1268c0984e5SSebastian Reichel 1278c0984e5SSebastian Reichel struct mutex lock; /* protect state data */ 1288c0984e5SSebastian Reichel }; 1298c0984e5SSebastian Reichel 1308c0984e5SSebastian Reichel static const struct regmap_range bq25890_readonly_reg_ranges[] = { 1318c0984e5SSebastian Reichel regmap_reg_range(0x0b, 0x0c), 1328c0984e5SSebastian Reichel regmap_reg_range(0x0e, 0x13), 1338c0984e5SSebastian Reichel }; 1348c0984e5SSebastian Reichel 1358c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_writeable_regs = { 1368c0984e5SSebastian Reichel .no_ranges = bq25890_readonly_reg_ranges, 1378c0984e5SSebastian Reichel .n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges), 1388c0984e5SSebastian Reichel }; 1398c0984e5SSebastian Reichel 1408c0984e5SSebastian Reichel static const struct regmap_range bq25890_volatile_reg_ranges[] = { 1418c0984e5SSebastian Reichel regmap_reg_range(0x00, 0x00), 14221d90edaSMichał Mirosław regmap_reg_range(0x02, 0x02), 1438c0984e5SSebastian Reichel regmap_reg_range(0x09, 0x09), 144d20267c9SYauhen Kharuzhy regmap_reg_range(0x0b, 0x14), 1458c0984e5SSebastian Reichel }; 1468c0984e5SSebastian Reichel 1478c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_volatile_regs = { 1488c0984e5SSebastian Reichel .yes_ranges = bq25890_volatile_reg_ranges, 1498c0984e5SSebastian Reichel .n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges), 1508c0984e5SSebastian Reichel }; 1518c0984e5SSebastian Reichel 1528c0984e5SSebastian Reichel static const struct regmap_config bq25890_regmap_config = { 1538c0984e5SSebastian Reichel .reg_bits = 8, 1548c0984e5SSebastian Reichel .val_bits = 8, 1558c0984e5SSebastian Reichel 1568c0984e5SSebastian Reichel .max_register = 0x14, 1578c0984e5SSebastian Reichel .cache_type = REGCACHE_RBTREE, 1588c0984e5SSebastian Reichel 1598c0984e5SSebastian Reichel .wr_table = &bq25890_writeable_regs, 1608c0984e5SSebastian Reichel .volatile_table = &bq25890_volatile_regs, 1618c0984e5SSebastian Reichel }; 1628c0984e5SSebastian Reichel 1638c0984e5SSebastian Reichel static const struct reg_field bq25890_reg_fields[] = { 1648c0984e5SSebastian Reichel /* REG00 */ 1658c0984e5SSebastian Reichel [F_EN_HIZ] = REG_FIELD(0x00, 7, 7), 1668c0984e5SSebastian Reichel [F_EN_ILIM] = REG_FIELD(0x00, 6, 6), 167766873c1SYauhen Kharuzhy [F_IINLIM] = REG_FIELD(0x00, 0, 5), 1688c0984e5SSebastian Reichel /* REG01 */ 1698c0984e5SSebastian Reichel [F_BHOT] = REG_FIELD(0x01, 6, 7), 1708c0984e5SSebastian Reichel [F_BCOLD] = REG_FIELD(0x01, 5, 5), 1718c0984e5SSebastian Reichel [F_VINDPM_OFS] = REG_FIELD(0x01, 0, 4), 1728c0984e5SSebastian Reichel /* REG02 */ 1738c0984e5SSebastian Reichel [F_CONV_START] = REG_FIELD(0x02, 7, 7), 1748c0984e5SSebastian Reichel [F_CONV_RATE] = REG_FIELD(0x02, 6, 6), 1758c0984e5SSebastian Reichel [F_BOOSTF] = REG_FIELD(0x02, 5, 5), 1768c0984e5SSebastian Reichel [F_ICO_EN] = REG_FIELD(0x02, 4, 4), 1772e1a2ddeSAngus Ainslie (Purism) [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), // reserved on BQ25896 1782e1a2ddeSAngus Ainslie (Purism) [F_MAXC_EN] = REG_FIELD(0x02, 2, 2), // reserved on BQ25896 1798c0984e5SSebastian Reichel [F_FORCE_DPM] = REG_FIELD(0x02, 1, 1), 1808c0984e5SSebastian Reichel [F_AUTO_DPDM_EN] = REG_FIELD(0x02, 0, 0), 1818c0984e5SSebastian Reichel /* REG03 */ 1828c0984e5SSebastian Reichel [F_BAT_LOAD_EN] = REG_FIELD(0x03, 7, 7), 1838c0984e5SSebastian Reichel [F_WD_RST] = REG_FIELD(0x03, 6, 6), 1848c0984e5SSebastian Reichel [F_OTG_CFG] = REG_FIELD(0x03, 5, 5), 1858c0984e5SSebastian Reichel [F_CHG_CFG] = REG_FIELD(0x03, 4, 4), 1868c0984e5SSebastian Reichel [F_SYSVMIN] = REG_FIELD(0x03, 1, 3), 187d20267c9SYauhen Kharuzhy [F_MIN_VBAT_SEL] = REG_FIELD(0x03, 0, 0), // BQ25896 only 1888c0984e5SSebastian Reichel /* REG04 */ 1898c0984e5SSebastian Reichel [F_PUMPX_EN] = REG_FIELD(0x04, 7, 7), 1908c0984e5SSebastian Reichel [F_ICHG] = REG_FIELD(0x04, 0, 6), 1918c0984e5SSebastian Reichel /* REG05 */ 1928c0984e5SSebastian Reichel [F_IPRECHG] = REG_FIELD(0x05, 4, 7), 1938c0984e5SSebastian Reichel [F_ITERM] = REG_FIELD(0x05, 0, 3), 1948c0984e5SSebastian Reichel /* REG06 */ 1958c0984e5SSebastian Reichel [F_VREG] = REG_FIELD(0x06, 2, 7), 1968c0984e5SSebastian Reichel [F_BATLOWV] = REG_FIELD(0x06, 1, 1), 1978c0984e5SSebastian Reichel [F_VRECHG] = REG_FIELD(0x06, 0, 0), 1988c0984e5SSebastian Reichel /* REG07 */ 1998c0984e5SSebastian Reichel [F_TERM_EN] = REG_FIELD(0x07, 7, 7), 2008c0984e5SSebastian Reichel [F_STAT_DIS] = REG_FIELD(0x07, 6, 6), 2018c0984e5SSebastian Reichel [F_WD] = REG_FIELD(0x07, 4, 5), 2028c0984e5SSebastian Reichel [F_TMR_EN] = REG_FIELD(0x07, 3, 3), 2038c0984e5SSebastian Reichel [F_CHG_TMR] = REG_FIELD(0x07, 1, 2), 2045c35ba9bSAngus Ainslie (Purism) [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), // reserved on BQ25895 2058c0984e5SSebastian Reichel /* REG08 */ 20695809139SMichał Mirosław [F_BATCMP] = REG_FIELD(0x08, 5, 7), 2078c0984e5SSebastian Reichel [F_VCLAMP] = REG_FIELD(0x08, 2, 4), 2088c0984e5SSebastian Reichel [F_TREG] = REG_FIELD(0x08, 0, 1), 2098c0984e5SSebastian Reichel /* REG09 */ 2108c0984e5SSebastian Reichel [F_FORCE_ICO] = REG_FIELD(0x09, 7, 7), 2118c0984e5SSebastian Reichel [F_TMR2X_EN] = REG_FIELD(0x09, 6, 6), 2128c0984e5SSebastian Reichel [F_BATFET_DIS] = REG_FIELD(0x09, 5, 5), 2135c35ba9bSAngus Ainslie (Purism) [F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), // reserved on BQ25895 2148c0984e5SSebastian Reichel [F_BATFET_DLY] = REG_FIELD(0x09, 3, 3), 2158c0984e5SSebastian Reichel [F_BATFET_RST_EN] = REG_FIELD(0x09, 2, 2), 2168c0984e5SSebastian Reichel [F_PUMPX_UP] = REG_FIELD(0x09, 1, 1), 2178c0984e5SSebastian Reichel [F_PUMPX_DN] = REG_FIELD(0x09, 0, 0), 2188c0984e5SSebastian Reichel /* REG0A */ 2198c0984e5SSebastian Reichel [F_BOOSTV] = REG_FIELD(0x0A, 4, 7), 2205c35ba9bSAngus Ainslie (Purism) [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), // reserved on BQ25895 221d20267c9SYauhen Kharuzhy [F_PFM_OTG_DIS] = REG_FIELD(0x0A, 3, 3), // BQ25896 only 2228c0984e5SSebastian Reichel /* REG0B */ 2238c0984e5SSebastian Reichel [F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7), 2248c0984e5SSebastian Reichel [F_CHG_STAT] = REG_FIELD(0x0B, 3, 4), 2258c0984e5SSebastian Reichel [F_PG_STAT] = REG_FIELD(0x0B, 2, 2), 2262e1a2ddeSAngus Ainslie (Purism) [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), // reserved on BQ25896 2278c0984e5SSebastian Reichel [F_VSYS_STAT] = REG_FIELD(0x0B, 0, 0), 2288c0984e5SSebastian Reichel /* REG0C */ 2298c0984e5SSebastian Reichel [F_WD_FAULT] = REG_FIELD(0x0C, 7, 7), 2308c0984e5SSebastian Reichel [F_BOOST_FAULT] = REG_FIELD(0x0C, 6, 6), 2318c0984e5SSebastian Reichel [F_CHG_FAULT] = REG_FIELD(0x0C, 4, 5), 2328c0984e5SSebastian Reichel [F_BAT_FAULT] = REG_FIELD(0x0C, 3, 3), 2338c0984e5SSebastian Reichel [F_NTC_FAULT] = REG_FIELD(0x0C, 0, 2), 2348c0984e5SSebastian Reichel /* REG0D */ 2358c0984e5SSebastian Reichel [F_FORCE_VINDPM] = REG_FIELD(0x0D, 7, 7), 2368c0984e5SSebastian Reichel [F_VINDPM] = REG_FIELD(0x0D, 0, 6), 2378c0984e5SSebastian Reichel /* REG0E */ 2388c0984e5SSebastian Reichel [F_THERM_STAT] = REG_FIELD(0x0E, 7, 7), 2398c0984e5SSebastian Reichel [F_BATV] = REG_FIELD(0x0E, 0, 6), 2408c0984e5SSebastian Reichel /* REG0F */ 2418c0984e5SSebastian Reichel [F_SYSV] = REG_FIELD(0x0F, 0, 6), 2428c0984e5SSebastian Reichel /* REG10 */ 2438c0984e5SSebastian Reichel [F_TSPCT] = REG_FIELD(0x10, 0, 6), 2448c0984e5SSebastian Reichel /* REG11 */ 2458c0984e5SSebastian Reichel [F_VBUS_GD] = REG_FIELD(0x11, 7, 7), 2468c0984e5SSebastian Reichel [F_VBUSV] = REG_FIELD(0x11, 0, 6), 2478c0984e5SSebastian Reichel /* REG12 */ 2488c0984e5SSebastian Reichel [F_ICHGR] = REG_FIELD(0x12, 0, 6), 2498c0984e5SSebastian Reichel /* REG13 */ 2508c0984e5SSebastian Reichel [F_VDPM_STAT] = REG_FIELD(0x13, 7, 7), 2518c0984e5SSebastian Reichel [F_IDPM_STAT] = REG_FIELD(0x13, 6, 6), 2528c0984e5SSebastian Reichel [F_IDPM_LIM] = REG_FIELD(0x13, 0, 5), 2538c0984e5SSebastian Reichel /* REG14 */ 2548c0984e5SSebastian Reichel [F_REG_RST] = REG_FIELD(0x14, 7, 7), 2558c0984e5SSebastian Reichel [F_ICO_OPTIMIZED] = REG_FIELD(0x14, 6, 6), 2568c0984e5SSebastian Reichel [F_PN] = REG_FIELD(0x14, 3, 5), 2578c0984e5SSebastian Reichel [F_TS_PROFILE] = REG_FIELD(0x14, 2, 2), 2588c0984e5SSebastian Reichel [F_DEV_REV] = REG_FIELD(0x14, 0, 1) 2598c0984e5SSebastian Reichel }; 2608c0984e5SSebastian Reichel 2618c0984e5SSebastian Reichel /* 2628c0984e5SSebastian Reichel * Most of the val -> idx conversions can be computed, given the minimum, 2638c0984e5SSebastian Reichel * maximum and the step between values. For the rest of conversions, we use 2648c0984e5SSebastian Reichel * lookup tables. 2658c0984e5SSebastian Reichel */ 2668c0984e5SSebastian Reichel enum bq25890_table_ids { 2678c0984e5SSebastian Reichel /* range tables */ 2688c0984e5SSebastian Reichel TBL_ICHG, 2698c0984e5SSebastian Reichel TBL_ITERM, 270766873c1SYauhen Kharuzhy TBL_IINLIM, 2718c0984e5SSebastian Reichel TBL_VREG, 2728c0984e5SSebastian Reichel TBL_BOOSTV, 2738c0984e5SSebastian Reichel TBL_SYSVMIN, 274*48f45b09SYauhen Kharuzhy TBL_VBUSV, 27572408329SMichał Mirosław TBL_VBATCOMP, 27672408329SMichał Mirosław TBL_RBATCOMP, 2778c0984e5SSebastian Reichel 2788c0984e5SSebastian Reichel /* lookup tables */ 2798c0984e5SSebastian Reichel TBL_TREG, 2808c0984e5SSebastian Reichel TBL_BOOSTI, 2819652c024SAngus Ainslie TBL_TSPCT, 2828c0984e5SSebastian Reichel }; 2838c0984e5SSebastian Reichel 2848c0984e5SSebastian Reichel /* Thermal Regulation Threshold lookup table, in degrees Celsius */ 2858c0984e5SSebastian Reichel static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 }; 2868c0984e5SSebastian Reichel 2878c0984e5SSebastian Reichel #define BQ25890_TREG_TBL_SIZE ARRAY_SIZE(bq25890_treg_tbl) 2888c0984e5SSebastian Reichel 2898c0984e5SSebastian Reichel /* Boost mode current limit lookup table, in uA */ 2908c0984e5SSebastian Reichel static const u32 bq25890_boosti_tbl[] = { 2918c0984e5SSebastian Reichel 500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000 2928c0984e5SSebastian Reichel }; 2938c0984e5SSebastian Reichel 2948c0984e5SSebastian Reichel #define BQ25890_BOOSTI_TBL_SIZE ARRAY_SIZE(bq25890_boosti_tbl) 2958c0984e5SSebastian Reichel 2969652c024SAngus Ainslie /* NTC 10K temperature lookup table in tenths of a degree */ 2979652c024SAngus Ainslie static const u32 bq25890_tspct_tbl[] = { 2989652c024SAngus Ainslie 850, 840, 830, 820, 810, 800, 790, 780, 2999652c024SAngus Ainslie 770, 760, 750, 740, 730, 720, 710, 700, 3009652c024SAngus Ainslie 690, 685, 680, 675, 670, 660, 650, 645, 3019652c024SAngus Ainslie 640, 630, 620, 615, 610, 600, 590, 585, 3029652c024SAngus Ainslie 580, 570, 565, 560, 550, 540, 535, 530, 3039652c024SAngus Ainslie 520, 515, 510, 500, 495, 490, 480, 475, 3049652c024SAngus Ainslie 470, 460, 455, 450, 440, 435, 430, 425, 3059652c024SAngus Ainslie 420, 410, 405, 400, 390, 385, 380, 370, 3069652c024SAngus Ainslie 365, 360, 355, 350, 340, 335, 330, 320, 3079652c024SAngus Ainslie 310, 305, 300, 290, 285, 280, 275, 270, 3089652c024SAngus Ainslie 260, 250, 245, 240, 230, 225, 220, 210, 3099652c024SAngus Ainslie 205, 200, 190, 180, 175, 170, 160, 150, 3109652c024SAngus Ainslie 145, 140, 130, 120, 115, 110, 100, 90, 3119652c024SAngus Ainslie 80, 70, 60, 50, 40, 30, 20, 10, 3129652c024SAngus Ainslie 0, -10, -20, -30, -40, -60, -70, -80, 3139652c024SAngus Ainslie -90, -10, -120, -140, -150, -170, -190, -210, 3149652c024SAngus Ainslie }; 3159652c024SAngus Ainslie 3169652c024SAngus Ainslie #define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl) 3179652c024SAngus Ainslie 3188c0984e5SSebastian Reichel struct bq25890_range { 3198c0984e5SSebastian Reichel u32 min; 3208c0984e5SSebastian Reichel u32 max; 3218c0984e5SSebastian Reichel u32 step; 3228c0984e5SSebastian Reichel }; 3238c0984e5SSebastian Reichel 3248c0984e5SSebastian Reichel struct bq25890_lookup { 3258c0984e5SSebastian Reichel const u32 *tbl; 3268c0984e5SSebastian Reichel u32 size; 3278c0984e5SSebastian Reichel }; 3288c0984e5SSebastian Reichel 3298c0984e5SSebastian Reichel static const union { 3308c0984e5SSebastian Reichel struct bq25890_range rt; 3318c0984e5SSebastian Reichel struct bq25890_lookup lt; 3328c0984e5SSebastian Reichel } bq25890_tables[] = { 3338c0984e5SSebastian Reichel /* range tables */ 334d20267c9SYauhen Kharuzhy /* TODO: BQ25896 has max ICHG 3008 mA */ 3358c0984e5SSebastian Reichel [TBL_ICHG] = { .rt = {0, 5056000, 64000} }, /* uA */ 3368c0984e5SSebastian Reichel [TBL_ITERM] = { .rt = {64000, 1024000, 64000} }, /* uA */ 337766873c1SYauhen Kharuzhy [TBL_IINLIM] = { .rt = {100000, 3250000, 50000} }, /* uA */ 3388c0984e5SSebastian Reichel [TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */ 3398c0984e5SSebastian Reichel [TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */ 3408c0984e5SSebastian Reichel [TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */ 341*48f45b09SYauhen Kharuzhy [TBL_VBUSV] = { .rt = {2600000, 15300000, 100000} }, /* uV */ 34272408329SMichał Mirosław [TBL_VBATCOMP] = { .rt = {0, 224000, 32000} }, /* uV */ 34372408329SMichał Mirosław [TBL_RBATCOMP] = { .rt = {0, 140000, 20000} }, /* uOhm */ 3448c0984e5SSebastian Reichel 3458c0984e5SSebastian Reichel /* lookup tables */ 3468c0984e5SSebastian Reichel [TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} }, 3479652c024SAngus Ainslie [TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} }, 3489652c024SAngus Ainslie [TBL_TSPCT] = { .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} } 3498c0984e5SSebastian Reichel }; 3508c0984e5SSebastian Reichel 3518c0984e5SSebastian Reichel static int bq25890_field_read(struct bq25890_device *bq, 3528c0984e5SSebastian Reichel enum bq25890_fields field_id) 3538c0984e5SSebastian Reichel { 3548c0984e5SSebastian Reichel int ret; 3558c0984e5SSebastian Reichel int val; 3568c0984e5SSebastian Reichel 3578c0984e5SSebastian Reichel ret = regmap_field_read(bq->rmap_fields[field_id], &val); 3588c0984e5SSebastian Reichel if (ret < 0) 3598c0984e5SSebastian Reichel return ret; 3608c0984e5SSebastian Reichel 3618c0984e5SSebastian Reichel return val; 3628c0984e5SSebastian Reichel } 3638c0984e5SSebastian Reichel 3648c0984e5SSebastian Reichel static int bq25890_field_write(struct bq25890_device *bq, 3658c0984e5SSebastian Reichel enum bq25890_fields field_id, u8 val) 3668c0984e5SSebastian Reichel { 3678c0984e5SSebastian Reichel return regmap_field_write(bq->rmap_fields[field_id], val); 3688c0984e5SSebastian Reichel } 3698c0984e5SSebastian Reichel 3708c0984e5SSebastian Reichel static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id) 3718c0984e5SSebastian Reichel { 3728c0984e5SSebastian Reichel u8 idx; 3738c0984e5SSebastian Reichel 3748c0984e5SSebastian Reichel if (id >= TBL_TREG) { 3758c0984e5SSebastian Reichel const u32 *tbl = bq25890_tables[id].lt.tbl; 3768c0984e5SSebastian Reichel u32 tbl_size = bq25890_tables[id].lt.size; 3778c0984e5SSebastian Reichel 3788c0984e5SSebastian Reichel for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++) 3798c0984e5SSebastian Reichel ; 3808c0984e5SSebastian Reichel } else { 3818c0984e5SSebastian Reichel const struct bq25890_range *rtbl = &bq25890_tables[id].rt; 3828c0984e5SSebastian Reichel u8 rtbl_size; 3838c0984e5SSebastian Reichel 3848c0984e5SSebastian Reichel rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1; 3858c0984e5SSebastian Reichel 3868c0984e5SSebastian Reichel for (idx = 1; 3878c0984e5SSebastian Reichel idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value); 3888c0984e5SSebastian Reichel idx++) 3898c0984e5SSebastian Reichel ; 3908c0984e5SSebastian Reichel } 3918c0984e5SSebastian Reichel 3928c0984e5SSebastian Reichel return idx - 1; 3938c0984e5SSebastian Reichel } 3948c0984e5SSebastian Reichel 3958c0984e5SSebastian Reichel static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id) 3968c0984e5SSebastian Reichel { 3978c0984e5SSebastian Reichel const struct bq25890_range *rtbl; 3988c0984e5SSebastian Reichel 3998c0984e5SSebastian Reichel /* lookup table? */ 4008c0984e5SSebastian Reichel if (id >= TBL_TREG) 4018c0984e5SSebastian Reichel return bq25890_tables[id].lt.tbl[idx]; 4028c0984e5SSebastian Reichel 4038c0984e5SSebastian Reichel /* range table */ 4048c0984e5SSebastian Reichel rtbl = &bq25890_tables[id].rt; 4058c0984e5SSebastian Reichel 4068c0984e5SSebastian Reichel return (rtbl->min + idx * rtbl->step); 4078c0984e5SSebastian Reichel } 4088c0984e5SSebastian Reichel 4098c0984e5SSebastian Reichel enum bq25890_status { 4108c0984e5SSebastian Reichel STATUS_NOT_CHARGING, 4118c0984e5SSebastian Reichel STATUS_PRE_CHARGING, 4128c0984e5SSebastian Reichel STATUS_FAST_CHARGING, 4138c0984e5SSebastian Reichel STATUS_TERMINATION_DONE, 4148c0984e5SSebastian Reichel }; 4158c0984e5SSebastian Reichel 4168c0984e5SSebastian Reichel enum bq25890_chrg_fault { 4178c0984e5SSebastian Reichel CHRG_FAULT_NORMAL, 4188c0984e5SSebastian Reichel CHRG_FAULT_INPUT, 4198c0984e5SSebastian Reichel CHRG_FAULT_THERMAL_SHUTDOWN, 4208c0984e5SSebastian Reichel CHRG_FAULT_TIMER_EXPIRED, 4218c0984e5SSebastian Reichel }; 4228c0984e5SSebastian Reichel 423c562a43aSYauhen Kharuzhy enum bq25890_ntc_fault { 424c562a43aSYauhen Kharuzhy NTC_FAULT_NORMAL = 0, 425c562a43aSYauhen Kharuzhy NTC_FAULT_WARM = 2, 426c562a43aSYauhen Kharuzhy NTC_FAULT_COOL = 3, 427c562a43aSYauhen Kharuzhy NTC_FAULT_COLD = 5, 428c562a43aSYauhen Kharuzhy NTC_FAULT_HOT = 6, 429c562a43aSYauhen Kharuzhy }; 430c562a43aSYauhen Kharuzhy 43121d90edaSMichał Mirosław static bool bq25890_is_adc_property(enum power_supply_property psp) 43221d90edaSMichał Mirosław { 43321d90edaSMichał Mirosław switch (psp) { 43421d90edaSMichał Mirosław case POWER_SUPPLY_PROP_VOLTAGE_NOW: 43521d90edaSMichał Mirosław case POWER_SUPPLY_PROP_CURRENT_NOW: 4369652c024SAngus Ainslie case POWER_SUPPLY_PROP_TEMP: 43721d90edaSMichał Mirosław return true; 43821d90edaSMichał Mirosław 43921d90edaSMichał Mirosław default: 44021d90edaSMichał Mirosław return false; 44121d90edaSMichał Mirosław } 44221d90edaSMichał Mirosław } 44321d90edaSMichał Mirosław 4443b4df57bSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq); 4453b4df57bSMichał Mirosław 446*48f45b09SYauhen Kharuzhy static int bq25890_get_vbus_voltage(struct bq25890_device *bq) 447*48f45b09SYauhen Kharuzhy { 448*48f45b09SYauhen Kharuzhy int ret; 449*48f45b09SYauhen Kharuzhy 450*48f45b09SYauhen Kharuzhy ret = bq25890_field_read(bq, F_VBUSV); 451*48f45b09SYauhen Kharuzhy if (ret < 0) 452*48f45b09SYauhen Kharuzhy return ret; 453*48f45b09SYauhen Kharuzhy 454*48f45b09SYauhen Kharuzhy return bq25890_find_val(ret, TBL_VBUSV); 455*48f45b09SYauhen Kharuzhy } 456*48f45b09SYauhen Kharuzhy 4578c0984e5SSebastian Reichel static int bq25890_power_supply_get_property(struct power_supply *psy, 4588c0984e5SSebastian Reichel enum power_supply_property psp, 4598c0984e5SSebastian Reichel union power_supply_propval *val) 4608c0984e5SSebastian Reichel { 4618c0984e5SSebastian Reichel struct bq25890_device *bq = power_supply_get_drvdata(psy); 4628c0984e5SSebastian Reichel struct bq25890_state state; 46321d90edaSMichał Mirosław bool do_adc_conv; 46421d90edaSMichał Mirosław int ret; 4658c0984e5SSebastian Reichel 4668c0984e5SSebastian Reichel mutex_lock(&bq->lock); 4673b4df57bSMichał Mirosław /* update state in case we lost an interrupt */ 4683b4df57bSMichał Mirosław __bq25890_handle_irq(bq); 4698c0984e5SSebastian Reichel state = bq->state; 47021d90edaSMichał Mirosław do_adc_conv = !state.online && bq25890_is_adc_property(psp); 47121d90edaSMichał Mirosław if (do_adc_conv) 47221d90edaSMichał Mirosław bq25890_field_write(bq, F_CONV_START, 1); 4738c0984e5SSebastian Reichel mutex_unlock(&bq->lock); 4748c0984e5SSebastian Reichel 47521d90edaSMichał Mirosław if (do_adc_conv) 47621d90edaSMichał Mirosław regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START], 47721d90edaSMichał Mirosław ret, !ret, 25000, 1000000); 47821d90edaSMichał Mirosław 4798c0984e5SSebastian Reichel switch (psp) { 4808c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_STATUS: 4818c0984e5SSebastian Reichel if (!state.online) 4828c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 4838c0984e5SSebastian Reichel else if (state.chrg_status == STATUS_NOT_CHARGING) 4848c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 4858c0984e5SSebastian Reichel else if (state.chrg_status == STATUS_PRE_CHARGING || 4868c0984e5SSebastian Reichel state.chrg_status == STATUS_FAST_CHARGING) 4878c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_CHARGING; 4888c0984e5SSebastian Reichel else if (state.chrg_status == STATUS_TERMINATION_DONE) 4898c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_FULL; 4908c0984e5SSebastian Reichel else 4918c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 4928c0984e5SSebastian Reichel 4938c0984e5SSebastian Reichel break; 4948c0984e5SSebastian Reichel 495b302a0aeSMichał Mirosław case POWER_SUPPLY_PROP_CHARGE_TYPE: 496b302a0aeSMichał Mirosław if (!state.online || state.chrg_status == STATUS_NOT_CHARGING || 497b302a0aeSMichał Mirosław state.chrg_status == STATUS_TERMINATION_DONE) 498b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 499b302a0aeSMichał Mirosław else if (state.chrg_status == STATUS_PRE_CHARGING) 500b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 501b302a0aeSMichał Mirosław else if (state.chrg_status == STATUS_FAST_CHARGING) 502b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 503b302a0aeSMichał Mirosław else /* unreachable */ 504b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 505b302a0aeSMichał Mirosław break; 506b302a0aeSMichał Mirosław 5078c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_MANUFACTURER: 5088c0984e5SSebastian Reichel val->strval = BQ25890_MANUFACTURER; 5098c0984e5SSebastian Reichel break; 5108c0984e5SSebastian Reichel 5112e1a2ddeSAngus Ainslie (Purism) case POWER_SUPPLY_PROP_MODEL_NAME: 5125956fca7SMichał Mirosław val->strval = bq25890_chip_name[bq->chip_version]; 5132e1a2ddeSAngus Ainslie (Purism) break; 5142e1a2ddeSAngus Ainslie (Purism) 5158c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 5168c0984e5SSebastian Reichel val->intval = state.online; 5178c0984e5SSebastian Reichel break; 5188c0984e5SSebastian Reichel 5198c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 5208c0984e5SSebastian Reichel if (!state.chrg_fault && !state.bat_fault && !state.boost_fault) 5218c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_GOOD; 5228c0984e5SSebastian Reichel else if (state.bat_fault) 5238c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 5248c0984e5SSebastian Reichel else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED) 5258c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 5268c0984e5SSebastian Reichel else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN) 5278c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 5288c0984e5SSebastian Reichel else 5298c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 5308c0984e5SSebastian Reichel break; 5318c0984e5SSebastian Reichel 5328c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 533f83a6eceSMichał Mirosław val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); 534c562a43aSYauhen Kharuzhy 535c562a43aSYauhen Kharuzhy /* When temperature is too low, charge current is decreased */ 536c562a43aSYauhen Kharuzhy if (bq->state.ntc_fault == NTC_FAULT_COOL) { 537c562a43aSYauhen Kharuzhy ret = bq25890_field_read(bq, F_JEITA_ISET); 538c562a43aSYauhen Kharuzhy if (ret < 0) 539c562a43aSYauhen Kharuzhy return ret; 540c562a43aSYauhen Kharuzhy 541c562a43aSYauhen Kharuzhy if (ret) 542c562a43aSYauhen Kharuzhy val->intval /= 5; 543c562a43aSYauhen Kharuzhy else 544c562a43aSYauhen Kharuzhy val->intval /= 2; 545c562a43aSYauhen Kharuzhy } 5468c0984e5SSebastian Reichel break; 5478c0984e5SSebastian Reichel 5488c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 5498c0984e5SSebastian Reichel if (!state.online) { 5508c0984e5SSebastian Reichel val->intval = 0; 5518c0984e5SSebastian Reichel break; 5528c0984e5SSebastian Reichel } 5538c0984e5SSebastian Reichel 5548c0984e5SSebastian Reichel ret = bq25890_field_read(bq, F_BATV); /* read measured value */ 5558c0984e5SSebastian Reichel if (ret < 0) 5568c0984e5SSebastian Reichel return ret; 5578c0984e5SSebastian Reichel 5588c0984e5SSebastian Reichel /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ 5598c0984e5SSebastian Reichel val->intval = 2304000 + ret * 20000; 5608c0984e5SSebastian Reichel break; 5618c0984e5SSebastian Reichel 5628c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 563f83a6eceSMichał Mirosław val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); 5648c0984e5SSebastian Reichel break; 5658c0984e5SSebastian Reichel 566c942656dSMichał Mirosław case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 567c942656dSMichał Mirosław val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM); 568c942656dSMichał Mirosław break; 569c942656dSMichał Mirosław 5708c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 5718c0984e5SSebastian Reichel val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM); 5728c0984e5SSebastian Reichel break; 5738c0984e5SSebastian Reichel 574478efc79SMichał Mirosław case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 575766873c1SYauhen Kharuzhy ret = bq25890_field_read(bq, F_IINLIM); 576478efc79SMichał Mirosław if (ret < 0) 577478efc79SMichał Mirosław return ret; 578478efc79SMichał Mirosław 579766873c1SYauhen Kharuzhy val->intval = bq25890_find_val(ret, TBL_IINLIM); 580478efc79SMichał Mirosław break; 581478efc79SMichał Mirosław 582ae6fe7a3SAngus Ainslie (Purism) case POWER_SUPPLY_PROP_VOLTAGE_NOW: 583ae6fe7a3SAngus Ainslie (Purism) ret = bq25890_field_read(bq, F_SYSV); /* read measured value */ 584ae6fe7a3SAngus Ainslie (Purism) if (ret < 0) 585ae6fe7a3SAngus Ainslie (Purism) return ret; 586ae6fe7a3SAngus Ainslie (Purism) 587ae6fe7a3SAngus Ainslie (Purism) /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ 588ae6fe7a3SAngus Ainslie (Purism) val->intval = 2304000 + ret * 20000; 589ae6fe7a3SAngus Ainslie (Purism) break; 590ae6fe7a3SAngus Ainslie (Purism) 5911e4724d0SMichał Mirosław case POWER_SUPPLY_PROP_CURRENT_NOW: 5921e4724d0SMichał Mirosław ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */ 5931e4724d0SMichał Mirosław if (ret < 0) 5941e4724d0SMichał Mirosław return ret; 5951e4724d0SMichał Mirosław 5961e4724d0SMichał Mirosław /* converted_val = ADC_val * 50mA (table 10.3.19) */ 5971e4724d0SMichał Mirosław val->intval = ret * -50000; 5981e4724d0SMichał Mirosław break; 5991e4724d0SMichał Mirosław 6009652c024SAngus Ainslie case POWER_SUPPLY_PROP_TEMP: 6019652c024SAngus Ainslie ret = bq25890_field_read(bq, F_TSPCT); 6029652c024SAngus Ainslie if (ret < 0) 6039652c024SAngus Ainslie return ret; 6049652c024SAngus Ainslie 6059652c024SAngus Ainslie /* convert TS percentage into rough temperature */ 6069652c024SAngus Ainslie val->intval = bq25890_find_val(ret, TBL_TSPCT); 6079652c024SAngus Ainslie break; 6089652c024SAngus Ainslie 6098c0984e5SSebastian Reichel default: 6108c0984e5SSebastian Reichel return -EINVAL; 6118c0984e5SSebastian Reichel } 6128c0984e5SSebastian Reichel 6138c0984e5SSebastian Reichel return 0; 6148c0984e5SSebastian Reichel } 6158c0984e5SSebastian Reichel 616eab25b4fSHans de Goede /* On the BQ25892 try to get charger-type info from our supplier */ 617eab25b4fSHans de Goede static void bq25890_charger_external_power_changed(struct power_supply *psy) 618eab25b4fSHans de Goede { 619eab25b4fSHans de Goede struct bq25890_device *bq = power_supply_get_drvdata(psy); 620eab25b4fSHans de Goede union power_supply_propval val; 621eab25b4fSHans de Goede int input_current_limit, ret; 622eab25b4fSHans de Goede 623eab25b4fSHans de Goede if (bq->chip_version != BQ25892) 624eab25b4fSHans de Goede return; 625eab25b4fSHans de Goede 626eab25b4fSHans de Goede ret = power_supply_get_property_from_supplier(bq->charger, 627eab25b4fSHans de Goede POWER_SUPPLY_PROP_USB_TYPE, 628eab25b4fSHans de Goede &val); 629eab25b4fSHans de Goede if (ret) 630eab25b4fSHans de Goede return; 631eab25b4fSHans de Goede 632eab25b4fSHans de Goede switch (val.intval) { 633eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_DCP: 634eab25b4fSHans de Goede input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM); 635*48f45b09SYauhen Kharuzhy if (bq->pump_express_vbus_max) { 636*48f45b09SYauhen Kharuzhy queue_delayed_work(system_power_efficient_wq, 637*48f45b09SYauhen Kharuzhy &bq->pump_express_work, 638*48f45b09SYauhen Kharuzhy PUMP_EXPRESS_START_DELAY); 639*48f45b09SYauhen Kharuzhy } 640eab25b4fSHans de Goede break; 641eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_CDP: 642eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_ACA: 643eab25b4fSHans de Goede input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM); 644eab25b4fSHans de Goede break; 645eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_SDP: 646eab25b4fSHans de Goede default: 647eab25b4fSHans de Goede input_current_limit = bq25890_find_idx(500000, TBL_IINLIM); 648eab25b4fSHans de Goede } 649eab25b4fSHans de Goede 650eab25b4fSHans de Goede bq25890_field_write(bq, F_IINLIM, input_current_limit); 651eab25b4fSHans de Goede } 652eab25b4fSHans de Goede 6538c0984e5SSebastian Reichel static int bq25890_get_chip_state(struct bq25890_device *bq, 6548c0984e5SSebastian Reichel struct bq25890_state *state) 6558c0984e5SSebastian Reichel { 6568c0984e5SSebastian Reichel int i, ret; 6578c0984e5SSebastian Reichel 6588c0984e5SSebastian Reichel struct { 6598c0984e5SSebastian Reichel enum bq25890_fields id; 6608c0984e5SSebastian Reichel u8 *data; 6618c0984e5SSebastian Reichel } state_fields[] = { 6628c0984e5SSebastian Reichel {F_CHG_STAT, &state->chrg_status}, 6638c0984e5SSebastian Reichel {F_PG_STAT, &state->online}, 6648c0984e5SSebastian Reichel {F_VSYS_STAT, &state->vsys_status}, 6658c0984e5SSebastian Reichel {F_BOOST_FAULT, &state->boost_fault}, 6668c0984e5SSebastian Reichel {F_BAT_FAULT, &state->bat_fault}, 667c562a43aSYauhen Kharuzhy {F_CHG_FAULT, &state->chrg_fault}, 668c562a43aSYauhen Kharuzhy {F_NTC_FAULT, &state->ntc_fault} 6698c0984e5SSebastian Reichel }; 6708c0984e5SSebastian Reichel 6718c0984e5SSebastian Reichel for (i = 0; i < ARRAY_SIZE(state_fields); i++) { 6728c0984e5SSebastian Reichel ret = bq25890_field_read(bq, state_fields[i].id); 6738c0984e5SSebastian Reichel if (ret < 0) 6748c0984e5SSebastian Reichel return ret; 6758c0984e5SSebastian Reichel 6768c0984e5SSebastian Reichel *state_fields[i].data = ret; 6778c0984e5SSebastian Reichel } 6788c0984e5SSebastian Reichel 679c562a43aSYauhen Kharuzhy dev_dbg(bq->dev, "S:CHG/PG/VSYS=%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n", 6808c0984e5SSebastian Reichel state->chrg_status, state->online, state->vsys_status, 681c562a43aSYauhen Kharuzhy state->chrg_fault, state->boost_fault, state->bat_fault, 682c562a43aSYauhen Kharuzhy state->ntc_fault); 6838c0984e5SSebastian Reichel 6848c0984e5SSebastian Reichel return 0; 6858c0984e5SSebastian Reichel } 6868c0984e5SSebastian Reichel 68772d9cd9cSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq) 6888c0984e5SSebastian Reichel { 68972d9cd9cSMichał Mirosław struct bq25890_state new_state; 6908c0984e5SSebastian Reichel int ret; 6918c0984e5SSebastian Reichel 69272d9cd9cSMichał Mirosław ret = bq25890_get_chip_state(bq, &new_state); 69372d9cd9cSMichał Mirosław if (ret < 0) 69472d9cd9cSMichał Mirosław return IRQ_NONE; 6958c0984e5SSebastian Reichel 69672d9cd9cSMichał Mirosław if (!memcmp(&bq->state, &new_state, sizeof(new_state))) 69772d9cd9cSMichał Mirosław return IRQ_NONE; 69872d9cd9cSMichał Mirosław 69972d9cd9cSMichał Mirosław if (!new_state.online && bq->state.online) { /* power removed */ 7008c0984e5SSebastian Reichel /* disable ADC */ 70180211be1SYauhen Kharuzhy ret = bq25890_field_write(bq, F_CONV_RATE, 0); 7028c0984e5SSebastian Reichel if (ret < 0) 7038c0984e5SSebastian Reichel goto error; 70472d9cd9cSMichał Mirosław } else if (new_state.online && !bq->state.online) { /* power inserted */ 7058c0984e5SSebastian Reichel /* enable ADC, to have control of charge current/voltage */ 70680211be1SYauhen Kharuzhy ret = bq25890_field_write(bq, F_CONV_RATE, 1); 7078c0984e5SSebastian Reichel if (ret < 0) 7088c0984e5SSebastian Reichel goto error; 7098c0984e5SSebastian Reichel } 7108c0984e5SSebastian Reichel 71172d9cd9cSMichał Mirosław bq->state = new_state; 71272d9cd9cSMichał Mirosław power_supply_changed(bq->charger); 7138c0984e5SSebastian Reichel 71472d9cd9cSMichał Mirosław return IRQ_HANDLED; 7158c0984e5SSebastian Reichel error: 71672d9cd9cSMichał Mirosław dev_err(bq->dev, "Error communicating with the chip: %pe\n", 71772d9cd9cSMichał Mirosław ERR_PTR(ret)); 71872d9cd9cSMichał Mirosław return IRQ_HANDLED; 7198c0984e5SSebastian Reichel } 7208c0984e5SSebastian Reichel 7218c0984e5SSebastian Reichel static irqreturn_t bq25890_irq_handler_thread(int irq, void *private) 7228c0984e5SSebastian Reichel { 7238c0984e5SSebastian Reichel struct bq25890_device *bq = private; 72472d9cd9cSMichał Mirosław irqreturn_t ret; 7258c0984e5SSebastian Reichel 7268c0984e5SSebastian Reichel mutex_lock(&bq->lock); 72772d9cd9cSMichał Mirosław ret = __bq25890_handle_irq(bq); 7288c0984e5SSebastian Reichel mutex_unlock(&bq->lock); 7298c0984e5SSebastian Reichel 73072d9cd9cSMichał Mirosław return ret; 7318c0984e5SSebastian Reichel } 7328c0984e5SSebastian Reichel 7338c0984e5SSebastian Reichel static int bq25890_chip_reset(struct bq25890_device *bq) 7348c0984e5SSebastian Reichel { 7358c0984e5SSebastian Reichel int ret; 7368c0984e5SSebastian Reichel int rst_check_counter = 10; 7378c0984e5SSebastian Reichel 7388c0984e5SSebastian Reichel ret = bq25890_field_write(bq, F_REG_RST, 1); 7398c0984e5SSebastian Reichel if (ret < 0) 7408c0984e5SSebastian Reichel return ret; 7418c0984e5SSebastian Reichel 7428c0984e5SSebastian Reichel do { 7438c0984e5SSebastian Reichel ret = bq25890_field_read(bq, F_REG_RST); 7448c0984e5SSebastian Reichel if (ret < 0) 7458c0984e5SSebastian Reichel return ret; 7468c0984e5SSebastian Reichel 7478c0984e5SSebastian Reichel usleep_range(5, 10); 7488c0984e5SSebastian Reichel } while (ret == 1 && --rst_check_counter); 7498c0984e5SSebastian Reichel 7508c0984e5SSebastian Reichel if (!rst_check_counter) 7518c0984e5SSebastian Reichel return -ETIMEDOUT; 7528c0984e5SSebastian Reichel 7538c0984e5SSebastian Reichel return 0; 7548c0984e5SSebastian Reichel } 7558c0984e5SSebastian Reichel 7567b22a974SHans de Goede static int bq25890_rw_init_data(struct bq25890_device *bq) 7578c0984e5SSebastian Reichel { 75840428bd4SHans de Goede bool write = !bq->read_back_init_data; 7598c0984e5SSebastian Reichel int ret; 7608c0984e5SSebastian Reichel int i; 7618c0984e5SSebastian Reichel 7628c0984e5SSebastian Reichel const struct { 7638c0984e5SSebastian Reichel enum bq25890_fields id; 7647b22a974SHans de Goede u8 *value; 7658c0984e5SSebastian Reichel } init_data[] = { 7667b22a974SHans de Goede {F_ICHG, &bq->init_data.ichg}, 7677b22a974SHans de Goede {F_VREG, &bq->init_data.vreg}, 7687b22a974SHans de Goede {F_ITERM, &bq->init_data.iterm}, 7697b22a974SHans de Goede {F_IPRECHG, &bq->init_data.iprechg}, 7707b22a974SHans de Goede {F_SYSVMIN, &bq->init_data.sysvmin}, 7717b22a974SHans de Goede {F_BOOSTV, &bq->init_data.boostv}, 7727b22a974SHans de Goede {F_BOOSTI, &bq->init_data.boosti}, 7737b22a974SHans de Goede {F_BOOSTF, &bq->init_data.boostf}, 7747b22a974SHans de Goede {F_EN_ILIM, &bq->init_data.ilim_en}, 7757b22a974SHans de Goede {F_TREG, &bq->init_data.treg}, 7767b22a974SHans de Goede {F_BATCMP, &bq->init_data.rbatcomp}, 7777b22a974SHans de Goede {F_VCLAMP, &bq->init_data.vclamp}, 7788c0984e5SSebastian Reichel }; 7798c0984e5SSebastian Reichel 7807b22a974SHans de Goede for (i = 0; i < ARRAY_SIZE(init_data); i++) { 7817b22a974SHans de Goede if (write) { 7827b22a974SHans de Goede ret = bq25890_field_write(bq, init_data[i].id, 7837b22a974SHans de Goede *init_data[i].value); 7847b22a974SHans de Goede } else { 7857b22a974SHans de Goede ret = bq25890_field_read(bq, init_data[i].id); 7867b22a974SHans de Goede if (ret >= 0) 7877b22a974SHans de Goede *init_data[i].value = ret; 7887b22a974SHans de Goede } 7897b22a974SHans de Goede if (ret < 0) { 7907b22a974SHans de Goede dev_dbg(bq->dev, "Accessing init data failed %d\n", ret); 7917b22a974SHans de Goede return ret; 7927b22a974SHans de Goede } 7937b22a974SHans de Goede } 7947b22a974SHans de Goede 7957b22a974SHans de Goede return 0; 7967b22a974SHans de Goede } 7977b22a974SHans de Goede 7987b22a974SHans de Goede static int bq25890_hw_init(struct bq25890_device *bq) 7997b22a974SHans de Goede { 8007b22a974SHans de Goede int ret; 8017b22a974SHans de Goede 8027e3b8e35SHans de Goede if (!bq->skip_reset) { 8038c0984e5SSebastian Reichel ret = bq25890_chip_reset(bq); 8049d9ae341SAngus Ainslie (Purism) if (ret < 0) { 8059d9ae341SAngus Ainslie (Purism) dev_dbg(bq->dev, "Reset failed %d\n", ret); 8068c0984e5SSebastian Reichel return ret; 807ad1570d9Skbuild test robot } 80806c75095SHans de Goede } else { 80906c75095SHans de Goede /* 81006c75095SHans de Goede * Ensure charging is enabled, on some boards where the fw 81106c75095SHans de Goede * takes care of initalizition F_CHG_CFG is set to 0 before 81206c75095SHans de Goede * handing control over to the OS. 81306c75095SHans de Goede */ 81406c75095SHans de Goede ret = bq25890_field_write(bq, F_CHG_CFG, 1); 81506c75095SHans de Goede if (ret < 0) { 81606c75095SHans de Goede dev_dbg(bq->dev, "Enabling charging failed %d\n", ret); 81706c75095SHans de Goede return ret; 81806c75095SHans de Goede } 8197e3b8e35SHans de Goede } 8208c0984e5SSebastian Reichel 8218c0984e5SSebastian Reichel /* disable watchdog */ 8228c0984e5SSebastian Reichel ret = bq25890_field_write(bq, F_WD, 0); 8239d9ae341SAngus Ainslie (Purism) if (ret < 0) { 8249d9ae341SAngus Ainslie (Purism) dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret); 8258c0984e5SSebastian Reichel return ret; 826ad1570d9Skbuild test robot } 8278c0984e5SSebastian Reichel 8288c0984e5SSebastian Reichel /* initialize currents/voltages and other parameters */ 8297b22a974SHans de Goede ret = bq25890_rw_init_data(bq); 8307b22a974SHans de Goede if (ret) 8318c0984e5SSebastian Reichel return ret; 8328c0984e5SSebastian Reichel 83322ad4f99SHans de Goede ret = bq25890_get_chip_state(bq, &bq->state); 83422ad4f99SHans de Goede if (ret < 0) { 83522ad4f99SHans de Goede dev_dbg(bq->dev, "Get state failed %d\n", ret); 83622ad4f99SHans de Goede return ret; 83722ad4f99SHans de Goede } 83822ad4f99SHans de Goede 83921d90edaSMichał Mirosław /* Configure ADC for continuous conversions when charging */ 84021d90edaSMichał Mirosław ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online); 8419d9ae341SAngus Ainslie (Purism) if (ret < 0) { 8429d9ae341SAngus Ainslie (Purism) dev_dbg(bq->dev, "Config ADC failed %d\n", ret); 8438c0984e5SSebastian Reichel return ret; 844ad1570d9Skbuild test robot } 8458c0984e5SSebastian Reichel 8468c0984e5SSebastian Reichel return 0; 8478c0984e5SSebastian Reichel } 8488c0984e5SSebastian Reichel 849a6a48facSMichał Mirosław static const enum power_supply_property bq25890_power_supply_props[] = { 8508c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 8512e1a2ddeSAngus Ainslie (Purism) POWER_SUPPLY_PROP_MODEL_NAME, 8528c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 853b302a0aeSMichał Mirosław POWER_SUPPLY_PROP_CHARGE_TYPE, 8548c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ONLINE, 8558c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 8568c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 8578c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 8588c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 859c942656dSMichał Mirosław POWER_SUPPLY_PROP_PRECHARGE_CURRENT, 8608c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 861478efc79SMichał Mirosław POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 862ae6fe7a3SAngus Ainslie (Purism) POWER_SUPPLY_PROP_VOLTAGE_NOW, 8631e4724d0SMichał Mirosław POWER_SUPPLY_PROP_CURRENT_NOW, 8649652c024SAngus Ainslie POWER_SUPPLY_PROP_TEMP, 8658c0984e5SSebastian Reichel }; 8668c0984e5SSebastian Reichel 8678c0984e5SSebastian Reichel static char *bq25890_charger_supplied_to[] = { 8688c0984e5SSebastian Reichel "main-battery", 8698c0984e5SSebastian Reichel }; 8708c0984e5SSebastian Reichel 8718c0984e5SSebastian Reichel static const struct power_supply_desc bq25890_power_supply_desc = { 8728c0984e5SSebastian Reichel .name = "bq25890-charger", 8738c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_USB, 8748c0984e5SSebastian Reichel .properties = bq25890_power_supply_props, 8758c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(bq25890_power_supply_props), 8768c0984e5SSebastian Reichel .get_property = bq25890_power_supply_get_property, 877eab25b4fSHans de Goede .external_power_changed = bq25890_charger_external_power_changed, 8788c0984e5SSebastian Reichel }; 8798c0984e5SSebastian Reichel 8808c0984e5SSebastian Reichel static int bq25890_power_supply_init(struct bq25890_device *bq) 8818c0984e5SSebastian Reichel { 8828c0984e5SSebastian Reichel struct power_supply_config psy_cfg = { .drv_data = bq, }; 8838c0984e5SSebastian Reichel 8848c0984e5SSebastian Reichel psy_cfg.supplied_to = bq25890_charger_supplied_to; 8858c0984e5SSebastian Reichel psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to); 8868c0984e5SSebastian Reichel 887d01363daSHans de Goede bq->charger = devm_power_supply_register(bq->dev, 888d01363daSHans de Goede &bq25890_power_supply_desc, 8898c0984e5SSebastian Reichel &psy_cfg); 8908c0984e5SSebastian Reichel 8918c0984e5SSebastian Reichel return PTR_ERR_OR_ZERO(bq->charger); 8928c0984e5SSebastian Reichel } 8938c0984e5SSebastian Reichel 8945575802dSHans de Goede static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val) 8955575802dSHans de Goede { 8965575802dSHans de Goede int ret; 8975575802dSHans de Goede 8985575802dSHans de Goede ret = bq25890_field_write(bq, F_OTG_CFG, val); 8995575802dSHans de Goede if (ret < 0) 9005575802dSHans de Goede dev_err(bq->dev, "Error switching to boost/charger mode: %d\n", ret); 9015575802dSHans de Goede 9025575802dSHans de Goede return ret; 9035575802dSHans de Goede } 9045575802dSHans de Goede 905*48f45b09SYauhen Kharuzhy static void bq25890_pump_express_work(struct work_struct *data) 906*48f45b09SYauhen Kharuzhy { 907*48f45b09SYauhen Kharuzhy struct bq25890_device *bq = 908*48f45b09SYauhen Kharuzhy container_of(data, struct bq25890_device, pump_express_work.work); 909*48f45b09SYauhen Kharuzhy int voltage, i, ret; 910*48f45b09SYauhen Kharuzhy 911*48f45b09SYauhen Kharuzhy dev_dbg(bq->dev, "Start to request input voltage increasing\n"); 912*48f45b09SYauhen Kharuzhy 913*48f45b09SYauhen Kharuzhy /* Enable current pulse voltage control protocol */ 914*48f45b09SYauhen Kharuzhy ret = bq25890_field_write(bq, F_PUMPX_EN, 1); 915*48f45b09SYauhen Kharuzhy if (ret < 0) 916*48f45b09SYauhen Kharuzhy goto error_print; 917*48f45b09SYauhen Kharuzhy 918*48f45b09SYauhen Kharuzhy for (i = 0; i < PUMP_EXPRESS_MAX_TRIES; i++) { 919*48f45b09SYauhen Kharuzhy voltage = bq25890_get_vbus_voltage(bq); 920*48f45b09SYauhen Kharuzhy if (voltage < 0) 921*48f45b09SYauhen Kharuzhy goto error_print; 922*48f45b09SYauhen Kharuzhy dev_dbg(bq->dev, "input voltage = %d uV\n", voltage); 923*48f45b09SYauhen Kharuzhy 924*48f45b09SYauhen Kharuzhy if ((voltage + PUMP_EXPRESS_VBUS_MARGIN_uV) > 925*48f45b09SYauhen Kharuzhy bq->pump_express_vbus_max) 926*48f45b09SYauhen Kharuzhy break; 927*48f45b09SYauhen Kharuzhy 928*48f45b09SYauhen Kharuzhy ret = bq25890_field_write(bq, F_PUMPX_UP, 1); 929*48f45b09SYauhen Kharuzhy if (ret < 0) 930*48f45b09SYauhen Kharuzhy goto error_print; 931*48f45b09SYauhen Kharuzhy 932*48f45b09SYauhen Kharuzhy /* Note a single PUMPX up pulse-sequence takes 2.1s */ 933*48f45b09SYauhen Kharuzhy ret = regmap_field_read_poll_timeout(bq->rmap_fields[F_PUMPX_UP], 934*48f45b09SYauhen Kharuzhy ret, !ret, 100000, 3000000); 935*48f45b09SYauhen Kharuzhy if (ret < 0) 936*48f45b09SYauhen Kharuzhy goto error_print; 937*48f45b09SYauhen Kharuzhy 938*48f45b09SYauhen Kharuzhy /* Make sure ADC has sampled Vbus before checking again */ 939*48f45b09SYauhen Kharuzhy msleep(1000); 940*48f45b09SYauhen Kharuzhy } 941*48f45b09SYauhen Kharuzhy 942*48f45b09SYauhen Kharuzhy bq25890_field_write(bq, F_PUMPX_EN, 0); 943*48f45b09SYauhen Kharuzhy 944*48f45b09SYauhen Kharuzhy dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n", 945*48f45b09SYauhen Kharuzhy voltage); 946*48f45b09SYauhen Kharuzhy 947*48f45b09SYauhen Kharuzhy return; 948*48f45b09SYauhen Kharuzhy error_print: 949*48f45b09SYauhen Kharuzhy dev_err(bq->dev, "Failed to request hi-voltage charging\n"); 950*48f45b09SYauhen Kharuzhy } 951*48f45b09SYauhen Kharuzhy 9528c0984e5SSebastian Reichel static void bq25890_usb_work(struct work_struct *data) 9538c0984e5SSebastian Reichel { 9548c0984e5SSebastian Reichel int ret; 9558c0984e5SSebastian Reichel struct bq25890_device *bq = 9568c0984e5SSebastian Reichel container_of(data, struct bq25890_device, usb_work); 9578c0984e5SSebastian Reichel 9588c0984e5SSebastian Reichel switch (bq->usb_event) { 9598c0984e5SSebastian Reichel case USB_EVENT_ID: 9608c0984e5SSebastian Reichel /* Enable boost mode */ 9615575802dSHans de Goede bq25890_set_otg_cfg(bq, 1); 9628c0984e5SSebastian Reichel break; 9638c0984e5SSebastian Reichel 9648c0984e5SSebastian Reichel case USB_EVENT_NONE: 9658c0984e5SSebastian Reichel /* Disable boost mode */ 9665575802dSHans de Goede ret = bq25890_set_otg_cfg(bq, 0); 9675575802dSHans de Goede if (ret == 0) 9688c0984e5SSebastian Reichel power_supply_changed(bq->charger); 9698c0984e5SSebastian Reichel break; 9708c0984e5SSebastian Reichel } 9718c0984e5SSebastian Reichel } 9728c0984e5SSebastian Reichel 9738c0984e5SSebastian Reichel static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val, 9748c0984e5SSebastian Reichel void *priv) 9758c0984e5SSebastian Reichel { 9768c0984e5SSebastian Reichel struct bq25890_device *bq = 9778c0984e5SSebastian Reichel container_of(nb, struct bq25890_device, usb_nb); 9788c0984e5SSebastian Reichel 9798c0984e5SSebastian Reichel bq->usb_event = val; 9808c0984e5SSebastian Reichel queue_work(system_power_efficient_wq, &bq->usb_work); 9818c0984e5SSebastian Reichel 9828c0984e5SSebastian Reichel return NOTIFY_OK; 9838c0984e5SSebastian Reichel } 9848c0984e5SSebastian Reichel 98579d35365SHans de Goede #ifdef CONFIG_REGULATOR 98679d35365SHans de Goede static int bq25890_vbus_enable(struct regulator_dev *rdev) 98779d35365SHans de Goede { 98879d35365SHans de Goede struct bq25890_device *bq = rdev_get_drvdata(rdev); 98979d35365SHans de Goede 99079d35365SHans de Goede return bq25890_set_otg_cfg(bq, 1); 99179d35365SHans de Goede } 99279d35365SHans de Goede 99379d35365SHans de Goede static int bq25890_vbus_disable(struct regulator_dev *rdev) 99479d35365SHans de Goede { 99579d35365SHans de Goede struct bq25890_device *bq = rdev_get_drvdata(rdev); 99679d35365SHans de Goede 99779d35365SHans de Goede return bq25890_set_otg_cfg(bq, 0); 99879d35365SHans de Goede } 99979d35365SHans de Goede 100079d35365SHans de Goede static int bq25890_vbus_is_enabled(struct regulator_dev *rdev) 100179d35365SHans de Goede { 100279d35365SHans de Goede struct bq25890_device *bq = rdev_get_drvdata(rdev); 100379d35365SHans de Goede 100479d35365SHans de Goede return bq25890_field_read(bq, F_OTG_CFG); 100579d35365SHans de Goede } 100679d35365SHans de Goede 100779d35365SHans de Goede static const struct regulator_ops bq25890_vbus_ops = { 100879d35365SHans de Goede .enable = bq25890_vbus_enable, 100979d35365SHans de Goede .disable = bq25890_vbus_disable, 101079d35365SHans de Goede .is_enabled = bq25890_vbus_is_enabled, 101179d35365SHans de Goede }; 101279d35365SHans de Goede 101379d35365SHans de Goede static const struct regulator_desc bq25890_vbus_desc = { 101479d35365SHans de Goede .name = "usb_otg_vbus", 101579d35365SHans de Goede .of_match = "usb-otg-vbus", 101679d35365SHans de Goede .type = REGULATOR_VOLTAGE, 101779d35365SHans de Goede .owner = THIS_MODULE, 101879d35365SHans de Goede .ops = &bq25890_vbus_ops, 101979d35365SHans de Goede .fixed_uV = 5000000, 102079d35365SHans de Goede .n_voltages = 1, 102179d35365SHans de Goede }; 102279d35365SHans de Goede #endif 102379d35365SHans de Goede 1024d20267c9SYauhen Kharuzhy static int bq25890_get_chip_version(struct bq25890_device *bq) 1025d20267c9SYauhen Kharuzhy { 1026d20267c9SYauhen Kharuzhy int id, rev; 1027d20267c9SYauhen Kharuzhy 1028d20267c9SYauhen Kharuzhy id = bq25890_field_read(bq, F_PN); 1029d20267c9SYauhen Kharuzhy if (id < 0) { 1030172d0cceSMartin Kepplinger dev_err(bq->dev, "Cannot read chip ID: %d\n", id); 1031d20267c9SYauhen Kharuzhy return id; 1032d20267c9SYauhen Kharuzhy } 1033d20267c9SYauhen Kharuzhy 1034d20267c9SYauhen Kharuzhy rev = bq25890_field_read(bq, F_DEV_REV); 1035d20267c9SYauhen Kharuzhy if (rev < 0) { 1036172d0cceSMartin Kepplinger dev_err(bq->dev, "Cannot read chip revision: %d\n", rev); 1037cb619e80SColin Ian King return rev; 1038d20267c9SYauhen Kharuzhy } 1039d20267c9SYauhen Kharuzhy 1040d20267c9SYauhen Kharuzhy switch (id) { 1041d20267c9SYauhen Kharuzhy case BQ25890_ID: 1042d20267c9SYauhen Kharuzhy bq->chip_version = BQ25890; 1043d20267c9SYauhen Kharuzhy break; 1044d20267c9SYauhen Kharuzhy 1045d20267c9SYauhen Kharuzhy /* BQ25892 and BQ25896 share same ID 0 */ 1046d20267c9SYauhen Kharuzhy case BQ25896_ID: 1047d20267c9SYauhen Kharuzhy switch (rev) { 1048d20267c9SYauhen Kharuzhy case 2: 1049d20267c9SYauhen Kharuzhy bq->chip_version = BQ25896; 1050d20267c9SYauhen Kharuzhy break; 1051d20267c9SYauhen Kharuzhy case 1: 1052d20267c9SYauhen Kharuzhy bq->chip_version = BQ25892; 1053d20267c9SYauhen Kharuzhy break; 1054d20267c9SYauhen Kharuzhy default: 1055d20267c9SYauhen Kharuzhy dev_err(bq->dev, 1056d20267c9SYauhen Kharuzhy "Unknown device revision %d, assume BQ25892\n", 1057d20267c9SYauhen Kharuzhy rev); 1058d20267c9SYauhen Kharuzhy bq->chip_version = BQ25892; 1059d20267c9SYauhen Kharuzhy } 1060d20267c9SYauhen Kharuzhy break; 1061d20267c9SYauhen Kharuzhy 1062d20267c9SYauhen Kharuzhy case BQ25895_ID: 1063d20267c9SYauhen Kharuzhy bq->chip_version = BQ25895; 1064d20267c9SYauhen Kharuzhy break; 1065d20267c9SYauhen Kharuzhy 1066d20267c9SYauhen Kharuzhy default: 1067d20267c9SYauhen Kharuzhy dev_err(bq->dev, "Unknown chip ID %d\n", id); 1068d20267c9SYauhen Kharuzhy return -ENODEV; 1069d20267c9SYauhen Kharuzhy } 1070d20267c9SYauhen Kharuzhy 1071d20267c9SYauhen Kharuzhy return 0; 1072d20267c9SYauhen Kharuzhy } 1073d20267c9SYauhen Kharuzhy 10748c0984e5SSebastian Reichel static int bq25890_irq_probe(struct bq25890_device *bq) 10758c0984e5SSebastian Reichel { 10768c0984e5SSebastian Reichel struct gpio_desc *irq; 10778c0984e5SSebastian Reichel 107886775879SAndy Shevchenko irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN); 1079172d0cceSMartin Kepplinger if (IS_ERR(irq)) 1080172d0cceSMartin Kepplinger return dev_err_probe(bq->dev, PTR_ERR(irq), 1081172d0cceSMartin Kepplinger "Could not probe irq pin.\n"); 10828c0984e5SSebastian Reichel 10838c0984e5SSebastian Reichel return gpiod_to_irq(irq); 10848c0984e5SSebastian Reichel } 10858c0984e5SSebastian Reichel 10868c0984e5SSebastian Reichel static int bq25890_fw_read_u32_props(struct bq25890_device *bq) 10878c0984e5SSebastian Reichel { 10888c0984e5SSebastian Reichel int ret; 10898c0984e5SSebastian Reichel u32 property; 10908c0984e5SSebastian Reichel int i; 10918c0984e5SSebastian Reichel struct bq25890_init_data *init = &bq->init_data; 10928c0984e5SSebastian Reichel struct { 10938c0984e5SSebastian Reichel char *name; 10948c0984e5SSebastian Reichel bool optional; 10958c0984e5SSebastian Reichel enum bq25890_table_ids tbl_id; 10968c0984e5SSebastian Reichel u8 *conv_data; /* holds converted value from given property */ 10978c0984e5SSebastian Reichel } props[] = { 10988c0984e5SSebastian Reichel /* required properties */ 10998c0984e5SSebastian Reichel {"ti,charge-current", false, TBL_ICHG, &init->ichg}, 11008c0984e5SSebastian Reichel {"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg}, 11018c0984e5SSebastian Reichel {"ti,termination-current", false, TBL_ITERM, &init->iterm}, 11028c0984e5SSebastian Reichel {"ti,precharge-current", false, TBL_ITERM, &init->iprechg}, 11038c0984e5SSebastian Reichel {"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin}, 11048c0984e5SSebastian Reichel {"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv}, 11058c0984e5SSebastian Reichel {"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti}, 11068c0984e5SSebastian Reichel 11078c0984e5SSebastian Reichel /* optional properties */ 110872408329SMichał Mirosław {"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg}, 110972408329SMichał Mirosław {"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp}, 111072408329SMichał Mirosław {"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp}, 11118c0984e5SSebastian Reichel }; 11128c0984e5SSebastian Reichel 11138c0984e5SSebastian Reichel /* initialize data for optional properties */ 11148c0984e5SSebastian Reichel init->treg = 3; /* 120 degrees Celsius */ 111572408329SMichał Mirosław init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */ 11168c0984e5SSebastian Reichel 11178c0984e5SSebastian Reichel for (i = 0; i < ARRAY_SIZE(props); i++) { 11188c0984e5SSebastian Reichel ret = device_property_read_u32(bq->dev, props[i].name, 11198c0984e5SSebastian Reichel &property); 11208c0984e5SSebastian Reichel if (ret < 0) { 11218c0984e5SSebastian Reichel if (props[i].optional) 11228c0984e5SSebastian Reichel continue; 11238c0984e5SSebastian Reichel 11249d9ae341SAngus Ainslie (Purism) dev_err(bq->dev, "Unable to read property %d %s\n", ret, 11259d9ae341SAngus Ainslie (Purism) props[i].name); 11269d9ae341SAngus Ainslie (Purism) 11278c0984e5SSebastian Reichel return ret; 11288c0984e5SSebastian Reichel } 11298c0984e5SSebastian Reichel 11308c0984e5SSebastian Reichel *props[i].conv_data = bq25890_find_idx(property, 11318c0984e5SSebastian Reichel props[i].tbl_id); 11328c0984e5SSebastian Reichel } 11338c0984e5SSebastian Reichel 11348c0984e5SSebastian Reichel return 0; 11358c0984e5SSebastian Reichel } 11368c0984e5SSebastian Reichel 11378c0984e5SSebastian Reichel static int bq25890_fw_probe(struct bq25890_device *bq) 11388c0984e5SSebastian Reichel { 11398c0984e5SSebastian Reichel int ret; 11408c0984e5SSebastian Reichel struct bq25890_init_data *init = &bq->init_data; 11418c0984e5SSebastian Reichel 1142*48f45b09SYauhen Kharuzhy /* Optional, left at 0 if property is not present */ 1143*48f45b09SYauhen Kharuzhy device_property_read_u32(bq->dev, "linux,pump-express-vbus-max", 1144*48f45b09SYauhen Kharuzhy &bq->pump_express_vbus_max); 1145*48f45b09SYauhen Kharuzhy 11467e3b8e35SHans de Goede bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset"); 114740428bd4SHans de Goede bq->read_back_init_data = device_property_read_bool(bq->dev, 114840428bd4SHans de Goede "linux,read-back-settings"); 114940428bd4SHans de Goede if (bq->read_back_init_data) 115040428bd4SHans de Goede return 0; 11517e3b8e35SHans de Goede 11528c0984e5SSebastian Reichel ret = bq25890_fw_read_u32_props(bq); 11538c0984e5SSebastian Reichel if (ret < 0) 11548c0984e5SSebastian Reichel return ret; 11558c0984e5SSebastian Reichel 11568c0984e5SSebastian Reichel init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin"); 11578c0984e5SSebastian Reichel init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq"); 11588c0984e5SSebastian Reichel 11598c0984e5SSebastian Reichel return 0; 11608c0984e5SSebastian Reichel } 11618c0984e5SSebastian Reichel 11628c0984e5SSebastian Reichel static int bq25890_probe(struct i2c_client *client, 11638c0984e5SSebastian Reichel const struct i2c_device_id *id) 11648c0984e5SSebastian Reichel { 11658c0984e5SSebastian Reichel struct device *dev = &client->dev; 11668c0984e5SSebastian Reichel struct bq25890_device *bq; 11678c0984e5SSebastian Reichel int ret; 11688c0984e5SSebastian Reichel int i; 11698c0984e5SSebastian Reichel 11708c0984e5SSebastian Reichel bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); 11718c0984e5SSebastian Reichel if (!bq) 11728c0984e5SSebastian Reichel return -ENOMEM; 11738c0984e5SSebastian Reichel 11748c0984e5SSebastian Reichel bq->client = client; 11758c0984e5SSebastian Reichel bq->dev = dev; 11768c0984e5SSebastian Reichel 11778c0984e5SSebastian Reichel mutex_init(&bq->lock); 1178*48f45b09SYauhen Kharuzhy INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work); 11798c0984e5SSebastian Reichel 11808c0984e5SSebastian Reichel bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config); 1181172d0cceSMartin Kepplinger if (IS_ERR(bq->rmap)) 1182172d0cceSMartin Kepplinger return dev_err_probe(dev, PTR_ERR(bq->rmap), 1183172d0cceSMartin Kepplinger "failed to allocate register map\n"); 11848c0984e5SSebastian Reichel 11858c0984e5SSebastian Reichel for (i = 0; i < ARRAY_SIZE(bq25890_reg_fields); i++) { 11868c0984e5SSebastian Reichel const struct reg_field *reg_fields = bq25890_reg_fields; 11878c0984e5SSebastian Reichel 11888c0984e5SSebastian Reichel bq->rmap_fields[i] = devm_regmap_field_alloc(dev, bq->rmap, 11898c0984e5SSebastian Reichel reg_fields[i]); 1190172d0cceSMartin Kepplinger if (IS_ERR(bq->rmap_fields[i])) 1191172d0cceSMartin Kepplinger return dev_err_probe(dev, PTR_ERR(bq->rmap_fields[i]), 1192172d0cceSMartin Kepplinger "cannot allocate regmap field\n"); 11938c0984e5SSebastian Reichel } 11948c0984e5SSebastian Reichel 11958c0984e5SSebastian Reichel i2c_set_clientdata(client, bq); 11968c0984e5SSebastian Reichel 1197d20267c9SYauhen Kharuzhy ret = bq25890_get_chip_version(bq); 1198d20267c9SYauhen Kharuzhy if (ret) { 1199172d0cceSMartin Kepplinger dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret); 1200d20267c9SYauhen Kharuzhy return ret; 12018c0984e5SSebastian Reichel } 12028c0984e5SSebastian Reichel 12038c0984e5SSebastian Reichel ret = bq25890_fw_probe(bq); 1204f481d5b8SHans de Goede if (ret < 0) 1205f481d5b8SHans de Goede return dev_err_probe(dev, ret, "reading device properties\n"); 12068c0984e5SSebastian Reichel 12078c0984e5SSebastian Reichel ret = bq25890_hw_init(bq); 12088c0984e5SSebastian Reichel if (ret < 0) { 1209172d0cceSMartin Kepplinger dev_err(dev, "Cannot initialize the chip: %d\n", ret); 12108c0984e5SSebastian Reichel return ret; 12118c0984e5SSebastian Reichel } 12128c0984e5SSebastian Reichel 12138c0984e5SSebastian Reichel if (client->irq <= 0) 12148c0984e5SSebastian Reichel client->irq = bq25890_irq_probe(bq); 12158c0984e5SSebastian Reichel 12168c0984e5SSebastian Reichel if (client->irq < 0) { 12178c0984e5SSebastian Reichel dev_err(dev, "No irq resource found.\n"); 12188c0984e5SSebastian Reichel return client->irq; 12198c0984e5SSebastian Reichel } 12208c0984e5SSebastian Reichel 12218c0984e5SSebastian Reichel /* OTG reporting */ 12228c0984e5SSebastian Reichel bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 12238c0984e5SSebastian Reichel if (!IS_ERR_OR_NULL(bq->usb_phy)) { 12248c0984e5SSebastian Reichel INIT_WORK(&bq->usb_work, bq25890_usb_work); 12258c0984e5SSebastian Reichel bq->usb_nb.notifier_call = bq25890_usb_notifier; 12268c0984e5SSebastian Reichel usb_register_notifier(bq->usb_phy, &bq->usb_nb); 12278c0984e5SSebastian Reichel } 122879d35365SHans de Goede #ifdef CONFIG_REGULATOR 122979d35365SHans de Goede else { 123079d35365SHans de Goede struct bq25890_platform_data *pdata = dev_get_platdata(dev); 123179d35365SHans de Goede struct regulator_config cfg = { }; 123279d35365SHans de Goede struct regulator_dev *reg; 123379d35365SHans de Goede 123479d35365SHans de Goede cfg.dev = dev; 123579d35365SHans de Goede cfg.driver_data = bq; 123679d35365SHans de Goede if (pdata) 123779d35365SHans de Goede cfg.init_data = pdata->regulator_init_data; 123879d35365SHans de Goede 123979d35365SHans de Goede reg = devm_regulator_register(dev, &bq25890_vbus_desc, &cfg); 124079d35365SHans de Goede if (IS_ERR(reg)) 124179d35365SHans de Goede return dev_err_probe(dev, PTR_ERR(reg), "registering regulator"); 124279d35365SHans de Goede } 124379d35365SHans de Goede #endif 12448c0984e5SSebastian Reichel 1245d01363daSHans de Goede ret = bq25890_power_supply_init(bq); 1246d01363daSHans de Goede if (ret < 0) { 1247d01363daSHans de Goede dev_err(dev, "Failed to register power supply\n"); 1248d01363daSHans de Goede goto err_unregister_usb_notifier; 1249d01363daSHans de Goede } 1250d01363daSHans de Goede 12518c0984e5SSebastian Reichel ret = devm_request_threaded_irq(dev, client->irq, NULL, 12528c0984e5SSebastian Reichel bq25890_irq_handler_thread, 12538c0984e5SSebastian Reichel IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 12548c0984e5SSebastian Reichel BQ25890_IRQ_PIN, bq); 12558c0984e5SSebastian Reichel if (ret) 1256d01363daSHans de Goede goto err_unregister_usb_notifier; 12578c0984e5SSebastian Reichel 12588c0984e5SSebastian Reichel return 0; 12598c0984e5SSebastian Reichel 1260d01363daSHans de Goede err_unregister_usb_notifier: 12618c0984e5SSebastian Reichel if (!IS_ERR_OR_NULL(bq->usb_phy)) 12628c0984e5SSebastian Reichel usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); 12638c0984e5SSebastian Reichel 12648c0984e5SSebastian Reichel return ret; 12658c0984e5SSebastian Reichel } 12668c0984e5SSebastian Reichel 12678c0984e5SSebastian Reichel static int bq25890_remove(struct i2c_client *client) 12688c0984e5SSebastian Reichel { 12698c0984e5SSebastian Reichel struct bq25890_device *bq = i2c_get_clientdata(client); 12708c0984e5SSebastian Reichel 12718c0984e5SSebastian Reichel if (!IS_ERR_OR_NULL(bq->usb_phy)) 12728c0984e5SSebastian Reichel usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); 12738c0984e5SSebastian Reichel 12747e3b8e35SHans de Goede if (!bq->skip_reset) { 12758c0984e5SSebastian Reichel /* reset all registers to default values */ 12768c0984e5SSebastian Reichel bq25890_chip_reset(bq); 12777e3b8e35SHans de Goede } 12788c0984e5SSebastian Reichel 12798c0984e5SSebastian Reichel return 0; 12808c0984e5SSebastian Reichel } 12818c0984e5SSebastian Reichel 128279d35365SHans de Goede static void bq25890_shutdown(struct i2c_client *client) 128379d35365SHans de Goede { 128479d35365SHans de Goede struct bq25890_device *bq = i2c_get_clientdata(client); 128579d35365SHans de Goede 128679d35365SHans de Goede /* 128779d35365SHans de Goede * TODO this if + return should probably be removed, but that would 128879d35365SHans de Goede * introduce a function change for boards using the usb-phy framework. 128979d35365SHans de Goede * This needs to be tested on such a board before making this change. 129079d35365SHans de Goede */ 129179d35365SHans de Goede if (!IS_ERR_OR_NULL(bq->usb_phy)) 129279d35365SHans de Goede return; 129379d35365SHans de Goede 129479d35365SHans de Goede /* 129579d35365SHans de Goede * Turn off the 5v Boost regulator which outputs Vbus to the device's 129679d35365SHans de Goede * Micro-USB or Type-C USB port. Leaving this on drains power and 129779d35365SHans de Goede * this avoids the PMIC on some device-models seeing this as Vbus 129879d35365SHans de Goede * getting inserted after shutdown, causing the device to immediately 129979d35365SHans de Goede * power-up again. 130079d35365SHans de Goede */ 130179d35365SHans de Goede bq25890_set_otg_cfg(bq, 0); 130279d35365SHans de Goede } 130379d35365SHans de Goede 13048c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP 13058c0984e5SSebastian Reichel static int bq25890_suspend(struct device *dev) 13068c0984e5SSebastian Reichel { 13078c0984e5SSebastian Reichel struct bq25890_device *bq = dev_get_drvdata(dev); 13088c0984e5SSebastian Reichel 13098c0984e5SSebastian Reichel /* 13108c0984e5SSebastian Reichel * If charger is removed, while in suspend, make sure ADC is diabled 13118c0984e5SSebastian Reichel * since it consumes slightly more power. 13128c0984e5SSebastian Reichel */ 131321d90edaSMichał Mirosław return bq25890_field_write(bq, F_CONV_RATE, 0); 13148c0984e5SSebastian Reichel } 13158c0984e5SSebastian Reichel 13168c0984e5SSebastian Reichel static int bq25890_resume(struct device *dev) 13178c0984e5SSebastian Reichel { 13188c0984e5SSebastian Reichel int ret; 13198c0984e5SSebastian Reichel struct bq25890_device *bq = dev_get_drvdata(dev); 13208c0984e5SSebastian Reichel 132172d9cd9cSMichał Mirosław mutex_lock(&bq->lock); 132272d9cd9cSMichał Mirosław 132372d9cd9cSMichał Mirosław ret = bq25890_get_chip_state(bq, &bq->state); 13248c0984e5SSebastian Reichel if (ret < 0) 1325cf5701bfSDan Carpenter goto unlock; 13268c0984e5SSebastian Reichel 13278c0984e5SSebastian Reichel /* Re-enable ADC only if charger is plugged in. */ 132872d9cd9cSMichał Mirosław if (bq->state.online) { 132921d90edaSMichał Mirosław ret = bq25890_field_write(bq, F_CONV_RATE, 1); 13308c0984e5SSebastian Reichel if (ret < 0) 1331cf5701bfSDan Carpenter goto unlock; 13328c0984e5SSebastian Reichel } 13338c0984e5SSebastian Reichel 13348c0984e5SSebastian Reichel /* signal userspace, maybe state changed while suspended */ 13358c0984e5SSebastian Reichel power_supply_changed(bq->charger); 13368c0984e5SSebastian Reichel 1337cf5701bfSDan Carpenter unlock: 133872d9cd9cSMichał Mirosław mutex_unlock(&bq->lock); 133972d9cd9cSMichał Mirosław 1340cf5701bfSDan Carpenter return ret; 13418c0984e5SSebastian Reichel } 13428c0984e5SSebastian Reichel #endif 13438c0984e5SSebastian Reichel 13448c0984e5SSebastian Reichel static const struct dev_pm_ops bq25890_pm = { 13458c0984e5SSebastian Reichel SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume) 13468c0984e5SSebastian Reichel }; 13478c0984e5SSebastian Reichel 13488c0984e5SSebastian Reichel static const struct i2c_device_id bq25890_i2c_ids[] = { 13498c0984e5SSebastian Reichel { "bq25890", 0 }, 135046aa27e7SYauhen Kharuzhy { "bq25892", 0 }, 135146aa27e7SYauhen Kharuzhy { "bq25895", 0 }, 135246aa27e7SYauhen Kharuzhy { "bq25896", 0 }, 13538c0984e5SSebastian Reichel {}, 13548c0984e5SSebastian Reichel }; 13558c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids); 13568c0984e5SSebastian Reichel 13578c0984e5SSebastian Reichel static const struct of_device_id bq25890_of_match[] = { 13588c0984e5SSebastian Reichel { .compatible = "ti,bq25890", }, 135946aa27e7SYauhen Kharuzhy { .compatible = "ti,bq25892", }, 136046aa27e7SYauhen Kharuzhy { .compatible = "ti,bq25895", }, 136146aa27e7SYauhen Kharuzhy { .compatible = "ti,bq25896", }, 13628c0984e5SSebastian Reichel { }, 13638c0984e5SSebastian Reichel }; 13648c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, bq25890_of_match); 13658c0984e5SSebastian Reichel 136602067dc9SKrzysztof Kozlowski #ifdef CONFIG_ACPI 13678c0984e5SSebastian Reichel static const struct acpi_device_id bq25890_acpi_match[] = { 13688c0984e5SSebastian Reichel {"BQ258900", 0}, 13698c0984e5SSebastian Reichel {}, 13708c0984e5SSebastian Reichel }; 13718c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match); 137202067dc9SKrzysztof Kozlowski #endif 13738c0984e5SSebastian Reichel 13748c0984e5SSebastian Reichel static struct i2c_driver bq25890_driver = { 13758c0984e5SSebastian Reichel .driver = { 13768c0984e5SSebastian Reichel .name = "bq25890-charger", 13778c0984e5SSebastian Reichel .of_match_table = of_match_ptr(bq25890_of_match), 13788c0984e5SSebastian Reichel .acpi_match_table = ACPI_PTR(bq25890_acpi_match), 13798c0984e5SSebastian Reichel .pm = &bq25890_pm, 13808c0984e5SSebastian Reichel }, 13818c0984e5SSebastian Reichel .probe = bq25890_probe, 13828c0984e5SSebastian Reichel .remove = bq25890_remove, 138379d35365SHans de Goede .shutdown = bq25890_shutdown, 13848c0984e5SSebastian Reichel .id_table = bq25890_i2c_ids, 13858c0984e5SSebastian Reichel }; 13868c0984e5SSebastian Reichel module_i2c_driver(bq25890_driver); 13878c0984e5SSebastian Reichel 13888c0984e5SSebastian Reichel MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>"); 13898c0984e5SSebastian Reichel MODULE_DESCRIPTION("bq25890 charger driver"); 13908c0984e5SSebastian Reichel MODULE_LICENSE("GPL"); 1391