1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 28c0984e5SSebastian Reichel /* 38c0984e5SSebastian Reichel * TI BQ25890 charger driver 48c0984e5SSebastian Reichel * 58c0984e5SSebastian Reichel * Copyright (C) 2015 Intel Corporation 68c0984e5SSebastian Reichel */ 78c0984e5SSebastian Reichel 88c0984e5SSebastian Reichel #include <linux/module.h> 98c0984e5SSebastian Reichel #include <linux/i2c.h> 108c0984e5SSebastian Reichel #include <linux/power_supply.h> 1179d35365SHans de Goede #include <linux/power/bq25890_charger.h> 128c0984e5SSebastian Reichel #include <linux/regmap.h> 1379d35365SHans de Goede #include <linux/regulator/driver.h> 148c0984e5SSebastian Reichel #include <linux/types.h> 158c0984e5SSebastian Reichel #include <linux/gpio/consumer.h> 168c0984e5SSebastian Reichel #include <linux/interrupt.h> 178c0984e5SSebastian Reichel #include <linux/delay.h> 188c0984e5SSebastian Reichel #include <linux/usb/phy.h> 198c0984e5SSebastian Reichel 208c0984e5SSebastian Reichel #include <linux/acpi.h> 218c0984e5SSebastian Reichel #include <linux/of.h> 228c0984e5SSebastian Reichel 238c0984e5SSebastian Reichel #define BQ25890_MANUFACTURER "Texas Instruments" 248c0984e5SSebastian Reichel #define BQ25890_IRQ_PIN "bq25890_irq" 258c0984e5SSebastian Reichel 268c0984e5SSebastian Reichel #define BQ25890_ID 3 275c35ba9bSAngus Ainslie (Purism) #define BQ25895_ID 7 282e1a2ddeSAngus Ainslie (Purism) #define BQ25896_ID 0 298c0984e5SSebastian Reichel 3048f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_START_DELAY (5 * HZ) 3148f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_MAX_TRIES 6 3248f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_VBUS_MARGIN_uV 1000000 3348f45b09SYauhen Kharuzhy 34d20267c9SYauhen Kharuzhy enum bq25890_chip_version { 35d20267c9SYauhen Kharuzhy BQ25890, 36d20267c9SYauhen Kharuzhy BQ25892, 37d20267c9SYauhen Kharuzhy BQ25895, 38d20267c9SYauhen Kharuzhy BQ25896, 39d20267c9SYauhen Kharuzhy }; 40d20267c9SYauhen Kharuzhy 415956fca7SMichał Mirosław static const char *const bq25890_chip_name[] = { 425956fca7SMichał Mirosław "BQ25890", 435956fca7SMichał Mirosław "BQ25892", 445956fca7SMichał Mirosław "BQ25895", 455956fca7SMichał Mirosław "BQ25896", 465956fca7SMichał Mirosław }; 475956fca7SMichał Mirosław 488c0984e5SSebastian Reichel enum bq25890_fields { 49766873c1SYauhen Kharuzhy F_EN_HIZ, F_EN_ILIM, F_IINLIM, /* Reg00 */ 508c0984e5SSebastian Reichel F_BHOT, F_BCOLD, F_VINDPM_OFS, /* Reg01 */ 518c0984e5SSebastian Reichel F_CONV_START, F_CONV_RATE, F_BOOSTF, F_ICO_EN, 528c0984e5SSebastian Reichel F_HVDCP_EN, F_MAXC_EN, F_FORCE_DPM, F_AUTO_DPDM_EN, /* Reg02 */ 53d20267c9SYauhen Kharuzhy F_BAT_LOAD_EN, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_SYSVMIN, 54d20267c9SYauhen Kharuzhy F_MIN_VBAT_SEL, /* Reg03 */ 558c0984e5SSebastian Reichel F_PUMPX_EN, F_ICHG, /* Reg04 */ 568c0984e5SSebastian Reichel F_IPRECHG, F_ITERM, /* Reg05 */ 578c0984e5SSebastian Reichel F_VREG, F_BATLOWV, F_VRECHG, /* Reg06 */ 588c0984e5SSebastian Reichel F_TERM_EN, F_STAT_DIS, F_WD, F_TMR_EN, F_CHG_TMR, 598c0984e5SSebastian Reichel F_JEITA_ISET, /* Reg07 */ 608c0984e5SSebastian Reichel F_BATCMP, F_VCLAMP, F_TREG, /* Reg08 */ 618c0984e5SSebastian Reichel F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JEITA_VSET, 628c0984e5SSebastian Reichel F_BATFET_DLY, F_BATFET_RST_EN, F_PUMPX_UP, F_PUMPX_DN, /* Reg09 */ 63d20267c9SYauhen Kharuzhy F_BOOSTV, F_PFM_OTG_DIS, F_BOOSTI, /* Reg0A */ 64d20267c9SYauhen Kharuzhy F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_SDP_STAT, F_0B_RSVD, 65d20267c9SYauhen Kharuzhy F_VSYS_STAT, /* Reg0B */ 668c0984e5SSebastian Reichel F_WD_FAULT, F_BOOST_FAULT, F_CHG_FAULT, F_BAT_FAULT, 678c0984e5SSebastian Reichel F_NTC_FAULT, /* Reg0C */ 688c0984e5SSebastian Reichel F_FORCE_VINDPM, F_VINDPM, /* Reg0D */ 698c0984e5SSebastian Reichel F_THERM_STAT, F_BATV, /* Reg0E */ 708c0984e5SSebastian Reichel F_SYSV, /* Reg0F */ 718c0984e5SSebastian Reichel F_TSPCT, /* Reg10 */ 728c0984e5SSebastian Reichel F_VBUS_GD, F_VBUSV, /* Reg11 */ 738c0984e5SSebastian Reichel F_ICHGR, /* Reg12 */ 748c0984e5SSebastian Reichel F_VDPM_STAT, F_IDPM_STAT, F_IDPM_LIM, /* Reg13 */ 758c0984e5SSebastian Reichel F_REG_RST, F_ICO_OPTIMIZED, F_PN, F_TS_PROFILE, F_DEV_REV, /* Reg14 */ 768c0984e5SSebastian Reichel 778c0984e5SSebastian Reichel F_MAX_FIELDS 788c0984e5SSebastian Reichel }; 798c0984e5SSebastian Reichel 808c0984e5SSebastian Reichel /* initial field values, converted to register values */ 818c0984e5SSebastian Reichel struct bq25890_init_data { 828c0984e5SSebastian Reichel u8 ichg; /* charge current */ 838c0984e5SSebastian Reichel u8 vreg; /* regulation voltage */ 848c0984e5SSebastian Reichel u8 iterm; /* termination current */ 858c0984e5SSebastian Reichel u8 iprechg; /* precharge current */ 868c0984e5SSebastian Reichel u8 sysvmin; /* minimum system voltage limit */ 878c0984e5SSebastian Reichel u8 boostv; /* boost regulation voltage */ 888c0984e5SSebastian Reichel u8 boosti; /* boost current limit */ 898c0984e5SSebastian Reichel u8 boostf; /* boost frequency */ 908c0984e5SSebastian Reichel u8 ilim_en; /* enable ILIM pin */ 918c0984e5SSebastian Reichel u8 treg; /* thermal regulation threshold */ 9272408329SMichał Mirosław u8 rbatcomp; /* IBAT sense resistor value */ 9372408329SMichał Mirosław u8 vclamp; /* IBAT compensation voltage limit */ 948c0984e5SSebastian Reichel }; 958c0984e5SSebastian Reichel 968c0984e5SSebastian Reichel struct bq25890_state { 978c0984e5SSebastian Reichel u8 online; 988c0984e5SSebastian Reichel u8 chrg_status; 998c0984e5SSebastian Reichel u8 chrg_fault; 1008c0984e5SSebastian Reichel u8 vsys_status; 1018c0984e5SSebastian Reichel u8 boost_fault; 1028c0984e5SSebastian Reichel u8 bat_fault; 103c562a43aSYauhen Kharuzhy u8 ntc_fault; 1048c0984e5SSebastian Reichel }; 1058c0984e5SSebastian Reichel 1068c0984e5SSebastian Reichel struct bq25890_device { 1078c0984e5SSebastian Reichel struct i2c_client *client; 1088c0984e5SSebastian Reichel struct device *dev; 1098c0984e5SSebastian Reichel struct power_supply *charger; 1108c0984e5SSebastian Reichel 1118c0984e5SSebastian Reichel struct usb_phy *usb_phy; 1128c0984e5SSebastian Reichel struct notifier_block usb_nb; 1138c0984e5SSebastian Reichel struct work_struct usb_work; 11448f45b09SYauhen Kharuzhy struct delayed_work pump_express_work; 1158c0984e5SSebastian Reichel unsigned long usb_event; 1168c0984e5SSebastian Reichel 1178c0984e5SSebastian Reichel struct regmap *rmap; 1188c0984e5SSebastian Reichel struct regmap_field *rmap_fields[F_MAX_FIELDS]; 1198c0984e5SSebastian Reichel 1207e3b8e35SHans de Goede bool skip_reset; 12140428bd4SHans de Goede bool read_back_init_data; 12248f45b09SYauhen Kharuzhy u32 pump_express_vbus_max; 123d20267c9SYauhen Kharuzhy enum bq25890_chip_version chip_version; 1248c0984e5SSebastian Reichel struct bq25890_init_data init_data; 1258c0984e5SSebastian Reichel struct bq25890_state state; 1268c0984e5SSebastian Reichel 1278c0984e5SSebastian Reichel struct mutex lock; /* protect state data */ 1288c0984e5SSebastian Reichel }; 1298c0984e5SSebastian Reichel 1308c0984e5SSebastian Reichel static const struct regmap_range bq25890_readonly_reg_ranges[] = { 1318c0984e5SSebastian Reichel regmap_reg_range(0x0b, 0x0c), 1328c0984e5SSebastian Reichel regmap_reg_range(0x0e, 0x13), 1338c0984e5SSebastian Reichel }; 1348c0984e5SSebastian Reichel 1358c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_writeable_regs = { 1368c0984e5SSebastian Reichel .no_ranges = bq25890_readonly_reg_ranges, 1378c0984e5SSebastian Reichel .n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges), 1388c0984e5SSebastian Reichel }; 1398c0984e5SSebastian Reichel 1408c0984e5SSebastian Reichel static const struct regmap_range bq25890_volatile_reg_ranges[] = { 1418c0984e5SSebastian Reichel regmap_reg_range(0x00, 0x00), 14221d90edaSMichał Mirosław regmap_reg_range(0x02, 0x02), 1438c0984e5SSebastian Reichel regmap_reg_range(0x09, 0x09), 144d20267c9SYauhen Kharuzhy regmap_reg_range(0x0b, 0x14), 1458c0984e5SSebastian Reichel }; 1468c0984e5SSebastian Reichel 1478c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_volatile_regs = { 1488c0984e5SSebastian Reichel .yes_ranges = bq25890_volatile_reg_ranges, 1498c0984e5SSebastian Reichel .n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges), 1508c0984e5SSebastian Reichel }; 1518c0984e5SSebastian Reichel 1528c0984e5SSebastian Reichel static const struct regmap_config bq25890_regmap_config = { 1538c0984e5SSebastian Reichel .reg_bits = 8, 1548c0984e5SSebastian Reichel .val_bits = 8, 1558c0984e5SSebastian Reichel 1568c0984e5SSebastian Reichel .max_register = 0x14, 1578c0984e5SSebastian Reichel .cache_type = REGCACHE_RBTREE, 1588c0984e5SSebastian Reichel 1598c0984e5SSebastian Reichel .wr_table = &bq25890_writeable_regs, 1608c0984e5SSebastian Reichel .volatile_table = &bq25890_volatile_regs, 1618c0984e5SSebastian Reichel }; 1628c0984e5SSebastian Reichel 1638c0984e5SSebastian Reichel static const struct reg_field bq25890_reg_fields[] = { 1648c0984e5SSebastian Reichel /* REG00 */ 1658c0984e5SSebastian Reichel [F_EN_HIZ] = REG_FIELD(0x00, 7, 7), 1668c0984e5SSebastian Reichel [F_EN_ILIM] = REG_FIELD(0x00, 6, 6), 167766873c1SYauhen Kharuzhy [F_IINLIM] = REG_FIELD(0x00, 0, 5), 1688c0984e5SSebastian Reichel /* REG01 */ 1698c0984e5SSebastian Reichel [F_BHOT] = REG_FIELD(0x01, 6, 7), 1708c0984e5SSebastian Reichel [F_BCOLD] = REG_FIELD(0x01, 5, 5), 1718c0984e5SSebastian Reichel [F_VINDPM_OFS] = REG_FIELD(0x01, 0, 4), 1728c0984e5SSebastian Reichel /* REG02 */ 1738c0984e5SSebastian Reichel [F_CONV_START] = REG_FIELD(0x02, 7, 7), 1748c0984e5SSebastian Reichel [F_CONV_RATE] = REG_FIELD(0x02, 6, 6), 1758c0984e5SSebastian Reichel [F_BOOSTF] = REG_FIELD(0x02, 5, 5), 1768c0984e5SSebastian Reichel [F_ICO_EN] = REG_FIELD(0x02, 4, 4), 1772e1a2ddeSAngus Ainslie (Purism) [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), // reserved on BQ25896 1782e1a2ddeSAngus Ainslie (Purism) [F_MAXC_EN] = REG_FIELD(0x02, 2, 2), // reserved on BQ25896 1798c0984e5SSebastian Reichel [F_FORCE_DPM] = REG_FIELD(0x02, 1, 1), 1808c0984e5SSebastian Reichel [F_AUTO_DPDM_EN] = REG_FIELD(0x02, 0, 0), 1818c0984e5SSebastian Reichel /* REG03 */ 1828c0984e5SSebastian Reichel [F_BAT_LOAD_EN] = REG_FIELD(0x03, 7, 7), 1838c0984e5SSebastian Reichel [F_WD_RST] = REG_FIELD(0x03, 6, 6), 1848c0984e5SSebastian Reichel [F_OTG_CFG] = REG_FIELD(0x03, 5, 5), 1858c0984e5SSebastian Reichel [F_CHG_CFG] = REG_FIELD(0x03, 4, 4), 1868c0984e5SSebastian Reichel [F_SYSVMIN] = REG_FIELD(0x03, 1, 3), 187d20267c9SYauhen Kharuzhy [F_MIN_VBAT_SEL] = REG_FIELD(0x03, 0, 0), // BQ25896 only 1888c0984e5SSebastian Reichel /* REG04 */ 1898c0984e5SSebastian Reichel [F_PUMPX_EN] = REG_FIELD(0x04, 7, 7), 1908c0984e5SSebastian Reichel [F_ICHG] = REG_FIELD(0x04, 0, 6), 1918c0984e5SSebastian Reichel /* REG05 */ 1928c0984e5SSebastian Reichel [F_IPRECHG] = REG_FIELD(0x05, 4, 7), 1938c0984e5SSebastian Reichel [F_ITERM] = REG_FIELD(0x05, 0, 3), 1948c0984e5SSebastian Reichel /* REG06 */ 1958c0984e5SSebastian Reichel [F_VREG] = REG_FIELD(0x06, 2, 7), 1968c0984e5SSebastian Reichel [F_BATLOWV] = REG_FIELD(0x06, 1, 1), 1978c0984e5SSebastian Reichel [F_VRECHG] = REG_FIELD(0x06, 0, 0), 1988c0984e5SSebastian Reichel /* REG07 */ 1998c0984e5SSebastian Reichel [F_TERM_EN] = REG_FIELD(0x07, 7, 7), 2008c0984e5SSebastian Reichel [F_STAT_DIS] = REG_FIELD(0x07, 6, 6), 2018c0984e5SSebastian Reichel [F_WD] = REG_FIELD(0x07, 4, 5), 2028c0984e5SSebastian Reichel [F_TMR_EN] = REG_FIELD(0x07, 3, 3), 2038c0984e5SSebastian Reichel [F_CHG_TMR] = REG_FIELD(0x07, 1, 2), 2045c35ba9bSAngus Ainslie (Purism) [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), // reserved on BQ25895 2058c0984e5SSebastian Reichel /* REG08 */ 20695809139SMichał Mirosław [F_BATCMP] = REG_FIELD(0x08, 5, 7), 2078c0984e5SSebastian Reichel [F_VCLAMP] = REG_FIELD(0x08, 2, 4), 2088c0984e5SSebastian Reichel [F_TREG] = REG_FIELD(0x08, 0, 1), 2098c0984e5SSebastian Reichel /* REG09 */ 2108c0984e5SSebastian Reichel [F_FORCE_ICO] = REG_FIELD(0x09, 7, 7), 2118c0984e5SSebastian Reichel [F_TMR2X_EN] = REG_FIELD(0x09, 6, 6), 2128c0984e5SSebastian Reichel [F_BATFET_DIS] = REG_FIELD(0x09, 5, 5), 2135c35ba9bSAngus Ainslie (Purism) [F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), // reserved on BQ25895 2148c0984e5SSebastian Reichel [F_BATFET_DLY] = REG_FIELD(0x09, 3, 3), 2158c0984e5SSebastian Reichel [F_BATFET_RST_EN] = REG_FIELD(0x09, 2, 2), 2168c0984e5SSebastian Reichel [F_PUMPX_UP] = REG_FIELD(0x09, 1, 1), 2178c0984e5SSebastian Reichel [F_PUMPX_DN] = REG_FIELD(0x09, 0, 0), 2188c0984e5SSebastian Reichel /* REG0A */ 2198c0984e5SSebastian Reichel [F_BOOSTV] = REG_FIELD(0x0A, 4, 7), 2205c35ba9bSAngus Ainslie (Purism) [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), // reserved on BQ25895 221d20267c9SYauhen Kharuzhy [F_PFM_OTG_DIS] = REG_FIELD(0x0A, 3, 3), // BQ25896 only 2228c0984e5SSebastian Reichel /* REG0B */ 2238c0984e5SSebastian Reichel [F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7), 2248c0984e5SSebastian Reichel [F_CHG_STAT] = REG_FIELD(0x0B, 3, 4), 2258c0984e5SSebastian Reichel [F_PG_STAT] = REG_FIELD(0x0B, 2, 2), 2262e1a2ddeSAngus Ainslie (Purism) [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), // reserved on BQ25896 2278c0984e5SSebastian Reichel [F_VSYS_STAT] = REG_FIELD(0x0B, 0, 0), 2288c0984e5SSebastian Reichel /* REG0C */ 2298c0984e5SSebastian Reichel [F_WD_FAULT] = REG_FIELD(0x0C, 7, 7), 2308c0984e5SSebastian Reichel [F_BOOST_FAULT] = REG_FIELD(0x0C, 6, 6), 2318c0984e5SSebastian Reichel [F_CHG_FAULT] = REG_FIELD(0x0C, 4, 5), 2328c0984e5SSebastian Reichel [F_BAT_FAULT] = REG_FIELD(0x0C, 3, 3), 2338c0984e5SSebastian Reichel [F_NTC_FAULT] = REG_FIELD(0x0C, 0, 2), 2348c0984e5SSebastian Reichel /* REG0D */ 2358c0984e5SSebastian Reichel [F_FORCE_VINDPM] = REG_FIELD(0x0D, 7, 7), 2368c0984e5SSebastian Reichel [F_VINDPM] = REG_FIELD(0x0D, 0, 6), 2378c0984e5SSebastian Reichel /* REG0E */ 2388c0984e5SSebastian Reichel [F_THERM_STAT] = REG_FIELD(0x0E, 7, 7), 2398c0984e5SSebastian Reichel [F_BATV] = REG_FIELD(0x0E, 0, 6), 2408c0984e5SSebastian Reichel /* REG0F */ 2418c0984e5SSebastian Reichel [F_SYSV] = REG_FIELD(0x0F, 0, 6), 2428c0984e5SSebastian Reichel /* REG10 */ 2438c0984e5SSebastian Reichel [F_TSPCT] = REG_FIELD(0x10, 0, 6), 2448c0984e5SSebastian Reichel /* REG11 */ 2458c0984e5SSebastian Reichel [F_VBUS_GD] = REG_FIELD(0x11, 7, 7), 2468c0984e5SSebastian Reichel [F_VBUSV] = REG_FIELD(0x11, 0, 6), 2478c0984e5SSebastian Reichel /* REG12 */ 2488c0984e5SSebastian Reichel [F_ICHGR] = REG_FIELD(0x12, 0, 6), 2498c0984e5SSebastian Reichel /* REG13 */ 2508c0984e5SSebastian Reichel [F_VDPM_STAT] = REG_FIELD(0x13, 7, 7), 2518c0984e5SSebastian Reichel [F_IDPM_STAT] = REG_FIELD(0x13, 6, 6), 2528c0984e5SSebastian Reichel [F_IDPM_LIM] = REG_FIELD(0x13, 0, 5), 2538c0984e5SSebastian Reichel /* REG14 */ 2548c0984e5SSebastian Reichel [F_REG_RST] = REG_FIELD(0x14, 7, 7), 2558c0984e5SSebastian Reichel [F_ICO_OPTIMIZED] = REG_FIELD(0x14, 6, 6), 2568c0984e5SSebastian Reichel [F_PN] = REG_FIELD(0x14, 3, 5), 2578c0984e5SSebastian Reichel [F_TS_PROFILE] = REG_FIELD(0x14, 2, 2), 2588c0984e5SSebastian Reichel [F_DEV_REV] = REG_FIELD(0x14, 0, 1) 2598c0984e5SSebastian Reichel }; 2608c0984e5SSebastian Reichel 2618c0984e5SSebastian Reichel /* 2628c0984e5SSebastian Reichel * Most of the val -> idx conversions can be computed, given the minimum, 2638c0984e5SSebastian Reichel * maximum and the step between values. For the rest of conversions, we use 2648c0984e5SSebastian Reichel * lookup tables. 2658c0984e5SSebastian Reichel */ 2668c0984e5SSebastian Reichel enum bq25890_table_ids { 2678c0984e5SSebastian Reichel /* range tables */ 2688c0984e5SSebastian Reichel TBL_ICHG, 2698c0984e5SSebastian Reichel TBL_ITERM, 270766873c1SYauhen Kharuzhy TBL_IINLIM, 2718c0984e5SSebastian Reichel TBL_VREG, 2728c0984e5SSebastian Reichel TBL_BOOSTV, 2738c0984e5SSebastian Reichel TBL_SYSVMIN, 27448f45b09SYauhen Kharuzhy TBL_VBUSV, 27572408329SMichał Mirosław TBL_VBATCOMP, 27672408329SMichał Mirosław TBL_RBATCOMP, 2778c0984e5SSebastian Reichel 2788c0984e5SSebastian Reichel /* lookup tables */ 2798c0984e5SSebastian Reichel TBL_TREG, 2808c0984e5SSebastian Reichel TBL_BOOSTI, 2819652c024SAngus Ainslie TBL_TSPCT, 2828c0984e5SSebastian Reichel }; 2838c0984e5SSebastian Reichel 2848c0984e5SSebastian Reichel /* Thermal Regulation Threshold lookup table, in degrees Celsius */ 2858c0984e5SSebastian Reichel static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 }; 2868c0984e5SSebastian Reichel 2878c0984e5SSebastian Reichel #define BQ25890_TREG_TBL_SIZE ARRAY_SIZE(bq25890_treg_tbl) 2888c0984e5SSebastian Reichel 2898c0984e5SSebastian Reichel /* Boost mode current limit lookup table, in uA */ 2908c0984e5SSebastian Reichel static const u32 bq25890_boosti_tbl[] = { 2918c0984e5SSebastian Reichel 500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000 2928c0984e5SSebastian Reichel }; 2938c0984e5SSebastian Reichel 2948c0984e5SSebastian Reichel #define BQ25890_BOOSTI_TBL_SIZE ARRAY_SIZE(bq25890_boosti_tbl) 2958c0984e5SSebastian Reichel 2969652c024SAngus Ainslie /* NTC 10K temperature lookup table in tenths of a degree */ 2979652c024SAngus Ainslie static const u32 bq25890_tspct_tbl[] = { 2989652c024SAngus Ainslie 850, 840, 830, 820, 810, 800, 790, 780, 2999652c024SAngus Ainslie 770, 760, 750, 740, 730, 720, 710, 700, 3009652c024SAngus Ainslie 690, 685, 680, 675, 670, 660, 650, 645, 3019652c024SAngus Ainslie 640, 630, 620, 615, 610, 600, 590, 585, 3029652c024SAngus Ainslie 580, 570, 565, 560, 550, 540, 535, 530, 3039652c024SAngus Ainslie 520, 515, 510, 500, 495, 490, 480, 475, 3049652c024SAngus Ainslie 470, 460, 455, 450, 440, 435, 430, 425, 3059652c024SAngus Ainslie 420, 410, 405, 400, 390, 385, 380, 370, 3069652c024SAngus Ainslie 365, 360, 355, 350, 340, 335, 330, 320, 3079652c024SAngus Ainslie 310, 305, 300, 290, 285, 280, 275, 270, 3089652c024SAngus Ainslie 260, 250, 245, 240, 230, 225, 220, 210, 3099652c024SAngus Ainslie 205, 200, 190, 180, 175, 170, 160, 150, 3109652c024SAngus Ainslie 145, 140, 130, 120, 115, 110, 100, 90, 3119652c024SAngus Ainslie 80, 70, 60, 50, 40, 30, 20, 10, 3129652c024SAngus Ainslie 0, -10, -20, -30, -40, -60, -70, -80, 3139652c024SAngus Ainslie -90, -10, -120, -140, -150, -170, -190, -210, 3149652c024SAngus Ainslie }; 3159652c024SAngus Ainslie 3169652c024SAngus Ainslie #define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl) 3179652c024SAngus Ainslie 3188c0984e5SSebastian Reichel struct bq25890_range { 3198c0984e5SSebastian Reichel u32 min; 3208c0984e5SSebastian Reichel u32 max; 3218c0984e5SSebastian Reichel u32 step; 3228c0984e5SSebastian Reichel }; 3238c0984e5SSebastian Reichel 3248c0984e5SSebastian Reichel struct bq25890_lookup { 3258c0984e5SSebastian Reichel const u32 *tbl; 3268c0984e5SSebastian Reichel u32 size; 3278c0984e5SSebastian Reichel }; 3288c0984e5SSebastian Reichel 3298c0984e5SSebastian Reichel static const union { 3308c0984e5SSebastian Reichel struct bq25890_range rt; 3318c0984e5SSebastian Reichel struct bq25890_lookup lt; 3328c0984e5SSebastian Reichel } bq25890_tables[] = { 3338c0984e5SSebastian Reichel /* range tables */ 334d20267c9SYauhen Kharuzhy /* TODO: BQ25896 has max ICHG 3008 mA */ 3358c0984e5SSebastian Reichel [TBL_ICHG] = { .rt = {0, 5056000, 64000} }, /* uA */ 3368c0984e5SSebastian Reichel [TBL_ITERM] = { .rt = {64000, 1024000, 64000} }, /* uA */ 337766873c1SYauhen Kharuzhy [TBL_IINLIM] = { .rt = {100000, 3250000, 50000} }, /* uA */ 3388c0984e5SSebastian Reichel [TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */ 3398c0984e5SSebastian Reichel [TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */ 3408c0984e5SSebastian Reichel [TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */ 34148f45b09SYauhen Kharuzhy [TBL_VBUSV] = { .rt = {2600000, 15300000, 100000} }, /* uV */ 34272408329SMichał Mirosław [TBL_VBATCOMP] = { .rt = {0, 224000, 32000} }, /* uV */ 34372408329SMichał Mirosław [TBL_RBATCOMP] = { .rt = {0, 140000, 20000} }, /* uOhm */ 3448c0984e5SSebastian Reichel 3458c0984e5SSebastian Reichel /* lookup tables */ 3468c0984e5SSebastian Reichel [TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} }, 3479652c024SAngus Ainslie [TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} }, 3489652c024SAngus Ainslie [TBL_TSPCT] = { .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} } 3498c0984e5SSebastian Reichel }; 3508c0984e5SSebastian Reichel 3518c0984e5SSebastian Reichel static int bq25890_field_read(struct bq25890_device *bq, 3528c0984e5SSebastian Reichel enum bq25890_fields field_id) 3538c0984e5SSebastian Reichel { 3548c0984e5SSebastian Reichel int ret; 3558c0984e5SSebastian Reichel int val; 3568c0984e5SSebastian Reichel 3578c0984e5SSebastian Reichel ret = regmap_field_read(bq->rmap_fields[field_id], &val); 3588c0984e5SSebastian Reichel if (ret < 0) 3598c0984e5SSebastian Reichel return ret; 3608c0984e5SSebastian Reichel 3618c0984e5SSebastian Reichel return val; 3628c0984e5SSebastian Reichel } 3638c0984e5SSebastian Reichel 3648c0984e5SSebastian Reichel static int bq25890_field_write(struct bq25890_device *bq, 3658c0984e5SSebastian Reichel enum bq25890_fields field_id, u8 val) 3668c0984e5SSebastian Reichel { 3678c0984e5SSebastian Reichel return regmap_field_write(bq->rmap_fields[field_id], val); 3688c0984e5SSebastian Reichel } 3698c0984e5SSebastian Reichel 3708c0984e5SSebastian Reichel static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id) 3718c0984e5SSebastian Reichel { 3728c0984e5SSebastian Reichel u8 idx; 3738c0984e5SSebastian Reichel 3748c0984e5SSebastian Reichel if (id >= TBL_TREG) { 3758c0984e5SSebastian Reichel const u32 *tbl = bq25890_tables[id].lt.tbl; 3768c0984e5SSebastian Reichel u32 tbl_size = bq25890_tables[id].lt.size; 3778c0984e5SSebastian Reichel 3788c0984e5SSebastian Reichel for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++) 3798c0984e5SSebastian Reichel ; 3808c0984e5SSebastian Reichel } else { 3818c0984e5SSebastian Reichel const struct bq25890_range *rtbl = &bq25890_tables[id].rt; 3828c0984e5SSebastian Reichel u8 rtbl_size; 3838c0984e5SSebastian Reichel 3848c0984e5SSebastian Reichel rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1; 3858c0984e5SSebastian Reichel 3868c0984e5SSebastian Reichel for (idx = 1; 3878c0984e5SSebastian Reichel idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value); 3888c0984e5SSebastian Reichel idx++) 3898c0984e5SSebastian Reichel ; 3908c0984e5SSebastian Reichel } 3918c0984e5SSebastian Reichel 3928c0984e5SSebastian Reichel return idx - 1; 3938c0984e5SSebastian Reichel } 3948c0984e5SSebastian Reichel 3958c0984e5SSebastian Reichel static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id) 3968c0984e5SSebastian Reichel { 3978c0984e5SSebastian Reichel const struct bq25890_range *rtbl; 3988c0984e5SSebastian Reichel 3998c0984e5SSebastian Reichel /* lookup table? */ 4008c0984e5SSebastian Reichel if (id >= TBL_TREG) 4018c0984e5SSebastian Reichel return bq25890_tables[id].lt.tbl[idx]; 4028c0984e5SSebastian Reichel 4038c0984e5SSebastian Reichel /* range table */ 4048c0984e5SSebastian Reichel rtbl = &bq25890_tables[id].rt; 4058c0984e5SSebastian Reichel 4068c0984e5SSebastian Reichel return (rtbl->min + idx * rtbl->step); 4078c0984e5SSebastian Reichel } 4088c0984e5SSebastian Reichel 4098c0984e5SSebastian Reichel enum bq25890_status { 4108c0984e5SSebastian Reichel STATUS_NOT_CHARGING, 4118c0984e5SSebastian Reichel STATUS_PRE_CHARGING, 4128c0984e5SSebastian Reichel STATUS_FAST_CHARGING, 4138c0984e5SSebastian Reichel STATUS_TERMINATION_DONE, 4148c0984e5SSebastian Reichel }; 4158c0984e5SSebastian Reichel 4168c0984e5SSebastian Reichel enum bq25890_chrg_fault { 4178c0984e5SSebastian Reichel CHRG_FAULT_NORMAL, 4188c0984e5SSebastian Reichel CHRG_FAULT_INPUT, 4198c0984e5SSebastian Reichel CHRG_FAULT_THERMAL_SHUTDOWN, 4208c0984e5SSebastian Reichel CHRG_FAULT_TIMER_EXPIRED, 4218c0984e5SSebastian Reichel }; 4228c0984e5SSebastian Reichel 423c562a43aSYauhen Kharuzhy enum bq25890_ntc_fault { 424c562a43aSYauhen Kharuzhy NTC_FAULT_NORMAL = 0, 425c562a43aSYauhen Kharuzhy NTC_FAULT_WARM = 2, 426c562a43aSYauhen Kharuzhy NTC_FAULT_COOL = 3, 427c562a43aSYauhen Kharuzhy NTC_FAULT_COLD = 5, 428c562a43aSYauhen Kharuzhy NTC_FAULT_HOT = 6, 429c562a43aSYauhen Kharuzhy }; 430c562a43aSYauhen Kharuzhy 43121d90edaSMichał Mirosław static bool bq25890_is_adc_property(enum power_supply_property psp) 43221d90edaSMichał Mirosław { 43321d90edaSMichał Mirosław switch (psp) { 43421d90edaSMichał Mirosław case POWER_SUPPLY_PROP_VOLTAGE_NOW: 43521d90edaSMichał Mirosław case POWER_SUPPLY_PROP_CURRENT_NOW: 4369652c024SAngus Ainslie case POWER_SUPPLY_PROP_TEMP: 43721d90edaSMichał Mirosław return true; 43821d90edaSMichał Mirosław 43921d90edaSMichał Mirosław default: 44021d90edaSMichał Mirosław return false; 44121d90edaSMichał Mirosław } 44221d90edaSMichał Mirosław } 44321d90edaSMichał Mirosław 4443b4df57bSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq); 4453b4df57bSMichał Mirosław 44648f45b09SYauhen Kharuzhy static int bq25890_get_vbus_voltage(struct bq25890_device *bq) 44748f45b09SYauhen Kharuzhy { 44848f45b09SYauhen Kharuzhy int ret; 44948f45b09SYauhen Kharuzhy 45048f45b09SYauhen Kharuzhy ret = bq25890_field_read(bq, F_VBUSV); 45148f45b09SYauhen Kharuzhy if (ret < 0) 45248f45b09SYauhen Kharuzhy return ret; 45348f45b09SYauhen Kharuzhy 45448f45b09SYauhen Kharuzhy return bq25890_find_val(ret, TBL_VBUSV); 45548f45b09SYauhen Kharuzhy } 45648f45b09SYauhen Kharuzhy 4578c0984e5SSebastian Reichel static int bq25890_power_supply_get_property(struct power_supply *psy, 4588c0984e5SSebastian Reichel enum power_supply_property psp, 4598c0984e5SSebastian Reichel union power_supply_propval *val) 4608c0984e5SSebastian Reichel { 4618c0984e5SSebastian Reichel struct bq25890_device *bq = power_supply_get_drvdata(psy); 4628c0984e5SSebastian Reichel struct bq25890_state state; 46321d90edaSMichał Mirosław bool do_adc_conv; 46421d90edaSMichał Mirosław int ret; 4658c0984e5SSebastian Reichel 4668c0984e5SSebastian Reichel mutex_lock(&bq->lock); 4673b4df57bSMichał Mirosław /* update state in case we lost an interrupt */ 4683b4df57bSMichał Mirosław __bq25890_handle_irq(bq); 4698c0984e5SSebastian Reichel state = bq->state; 47021d90edaSMichał Mirosław do_adc_conv = !state.online && bq25890_is_adc_property(psp); 47121d90edaSMichał Mirosław if (do_adc_conv) 47221d90edaSMichał Mirosław bq25890_field_write(bq, F_CONV_START, 1); 4738c0984e5SSebastian Reichel mutex_unlock(&bq->lock); 4748c0984e5SSebastian Reichel 47521d90edaSMichał Mirosław if (do_adc_conv) 47621d90edaSMichał Mirosław regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START], 47721d90edaSMichał Mirosław ret, !ret, 25000, 1000000); 47821d90edaSMichał Mirosław 4798c0984e5SSebastian Reichel switch (psp) { 4808c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_STATUS: 4818c0984e5SSebastian Reichel if (!state.online) 4828c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 4838c0984e5SSebastian Reichel else if (state.chrg_status == STATUS_NOT_CHARGING) 4848c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 4858c0984e5SSebastian Reichel else if (state.chrg_status == STATUS_PRE_CHARGING || 4868c0984e5SSebastian Reichel state.chrg_status == STATUS_FAST_CHARGING) 4878c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_CHARGING; 4888c0984e5SSebastian Reichel else if (state.chrg_status == STATUS_TERMINATION_DONE) 4898c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_FULL; 4908c0984e5SSebastian Reichel else 4918c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 4928c0984e5SSebastian Reichel 4938c0984e5SSebastian Reichel break; 4948c0984e5SSebastian Reichel 495b302a0aeSMichał Mirosław case POWER_SUPPLY_PROP_CHARGE_TYPE: 496b302a0aeSMichał Mirosław if (!state.online || state.chrg_status == STATUS_NOT_CHARGING || 497b302a0aeSMichał Mirosław state.chrg_status == STATUS_TERMINATION_DONE) 498b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 499b302a0aeSMichał Mirosław else if (state.chrg_status == STATUS_PRE_CHARGING) 500b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 501b302a0aeSMichał Mirosław else if (state.chrg_status == STATUS_FAST_CHARGING) 502b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 503b302a0aeSMichał Mirosław else /* unreachable */ 504b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 505b302a0aeSMichał Mirosław break; 506b302a0aeSMichał Mirosław 5078c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_MANUFACTURER: 5088c0984e5SSebastian Reichel val->strval = BQ25890_MANUFACTURER; 5098c0984e5SSebastian Reichel break; 5108c0984e5SSebastian Reichel 5112e1a2ddeSAngus Ainslie (Purism) case POWER_SUPPLY_PROP_MODEL_NAME: 5125956fca7SMichał Mirosław val->strval = bq25890_chip_name[bq->chip_version]; 5132e1a2ddeSAngus Ainslie (Purism) break; 5142e1a2ddeSAngus Ainslie (Purism) 5158c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 5168c0984e5SSebastian Reichel val->intval = state.online; 5178c0984e5SSebastian Reichel break; 5188c0984e5SSebastian Reichel 5198c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 5208c0984e5SSebastian Reichel if (!state.chrg_fault && !state.bat_fault && !state.boost_fault) 5218c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_GOOD; 5228c0984e5SSebastian Reichel else if (state.bat_fault) 5238c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 5248c0984e5SSebastian Reichel else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED) 5258c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 5268c0984e5SSebastian Reichel else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN) 5278c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 5288c0984e5SSebastian Reichel else 5298c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 5308c0984e5SSebastian Reichel break; 5318c0984e5SSebastian Reichel 532c942656dSMichał Mirosław case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 533c942656dSMichał Mirosław val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM); 534c942656dSMichał Mirosław break; 535c942656dSMichał Mirosław 5368c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 5378c0984e5SSebastian Reichel val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM); 5388c0984e5SSebastian Reichel break; 5398c0984e5SSebastian Reichel 540478efc79SMichał Mirosław case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 541766873c1SYauhen Kharuzhy ret = bq25890_field_read(bq, F_IINLIM); 542478efc79SMichał Mirosław if (ret < 0) 543478efc79SMichał Mirosław return ret; 544478efc79SMichał Mirosław 545766873c1SYauhen Kharuzhy val->intval = bq25890_find_val(ret, TBL_IINLIM); 546478efc79SMichał Mirosław break; 547478efc79SMichał Mirosław 548ef1ca210SMarek Vasut case POWER_SUPPLY_PROP_CURRENT_NOW: /* I_BAT now */ 549ef1ca210SMarek Vasut /* 550ef1ca210SMarek Vasut * This is ADC-sampled immediate charge current supplied 551ef1ca210SMarek Vasut * from charger to battery. The property name is confusing, 552ef1ca210SMarek Vasut * for clarification refer to: 553ef1ca210SMarek Vasut * Documentation/ABI/testing/sysfs-class-power 554ef1ca210SMarek Vasut * /sys/class/power_supply/<supply_name>/current_now 555ef1ca210SMarek Vasut */ 5561e4724d0SMichał Mirosław ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */ 5571e4724d0SMichał Mirosław if (ret < 0) 5581e4724d0SMichał Mirosław return ret; 5591e4724d0SMichał Mirosław 5601e4724d0SMichał Mirosław /* converted_val = ADC_val * 50mA (table 10.3.19) */ 5611e4724d0SMichał Mirosław val->intval = ret * -50000; 5621e4724d0SMichał Mirosław break; 5631e4724d0SMichał Mirosław 5648327a8abSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: /* I_BAT user limit */ 5658327a8abSMarek Vasut /* 5668327a8abSMarek Vasut * This is user-configured constant charge current supplied 5678327a8abSMarek Vasut * from charger to battery in first phase of charging, when 5688327a8abSMarek Vasut * battery voltage is below constant charge voltage. 5698327a8abSMarek Vasut * 5708327a8abSMarek Vasut * This value reflects the current hardware setting. 5718327a8abSMarek Vasut * 5728327a8abSMarek Vasut * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX is the 5738327a8abSMarek Vasut * maximum value of this property. 5748327a8abSMarek Vasut */ 5758327a8abSMarek Vasut ret = bq25890_field_read(bq, F_ICHG); 5768327a8abSMarek Vasut if (ret < 0) 5778327a8abSMarek Vasut return ret; 5788327a8abSMarek Vasut val->intval = bq25890_find_val(ret, TBL_ICHG); 5798327a8abSMarek Vasut 5808327a8abSMarek Vasut /* When temperature is too low, charge current is decreased */ 5818327a8abSMarek Vasut if (bq->state.ntc_fault == NTC_FAULT_COOL) { 5828327a8abSMarek Vasut ret = bq25890_field_read(bq, F_JEITA_ISET); 5838327a8abSMarek Vasut if (ret < 0) 5848327a8abSMarek Vasut return ret; 5858327a8abSMarek Vasut 5868327a8abSMarek Vasut if (ret) 5878327a8abSMarek Vasut val->intval /= 5; 5888327a8abSMarek Vasut else 5898327a8abSMarek Vasut val->intval /= 2; 5908327a8abSMarek Vasut } 5918327a8abSMarek Vasut break; 5928327a8abSMarek Vasut 5938327a8abSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: /* I_BAT max */ 5948327a8abSMarek Vasut /* 5958327a8abSMarek Vasut * This is maximum allowed constant charge current supplied 5968327a8abSMarek Vasut * from charger to battery in first phase of charging, when 5978327a8abSMarek Vasut * battery voltage is below constant charge voltage. 5988327a8abSMarek Vasut * 5998327a8abSMarek Vasut * This value is constant for each battery and set from DT. 6008327a8abSMarek Vasut */ 6018327a8abSMarek Vasut val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); 6028327a8abSMarek Vasut break; 6038327a8abSMarek Vasut 6047c852375SMarek Vasut case POWER_SUPPLY_PROP_VOLTAGE_NOW: /* V_BAT now */ 6057c852375SMarek Vasut /* 6067c852375SMarek Vasut * This is ADC-sampled immediate charge voltage supplied 6077c852375SMarek Vasut * from charger to battery. The property name is confusing, 6087c852375SMarek Vasut * for clarification refer to: 6097c852375SMarek Vasut * Documentation/ABI/testing/sysfs-class-power 6107c852375SMarek Vasut * /sys/class/power_supply/<supply_name>/voltage_now 6117c852375SMarek Vasut */ 6127c852375SMarek Vasut ret = bq25890_field_read(bq, F_BATV); /* read measured value */ 6137c852375SMarek Vasut if (ret < 0) 6147c852375SMarek Vasut return ret; 6157c852375SMarek Vasut 6167c852375SMarek Vasut /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ 6177c852375SMarek Vasut val->intval = 2304000 + ret * 20000; 6187c852375SMarek Vasut break; 6197c852375SMarek Vasut 6207c852375SMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: /* V_BAT user limit */ 6217c852375SMarek Vasut /* 6227c852375SMarek Vasut * This is user-configured constant charge voltage supplied 6237c852375SMarek Vasut * from charger to battery in second phase of charging, when 6247c852375SMarek Vasut * battery voltage reached constant charge voltage. 6257c852375SMarek Vasut * 6267c852375SMarek Vasut * This value reflects the current hardware setting. 6277c852375SMarek Vasut * 6287c852375SMarek Vasut * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX is the 6297c852375SMarek Vasut * maximum value of this property. 6307c852375SMarek Vasut */ 6317c852375SMarek Vasut ret = bq25890_field_read(bq, F_VREG); 6327c852375SMarek Vasut if (ret < 0) 6337c852375SMarek Vasut return ret; 6347c852375SMarek Vasut 6357c852375SMarek Vasut val->intval = bq25890_find_val(ret, TBL_VREG); 6367c852375SMarek Vasut break; 6377c852375SMarek Vasut 6387c852375SMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: /* V_BAT max */ 6397c852375SMarek Vasut /* 6407c852375SMarek Vasut * This is maximum allowed constant charge voltage supplied 6417c852375SMarek Vasut * from charger to battery in second phase of charging, when 6427c852375SMarek Vasut * battery voltage reached constant charge voltage. 6437c852375SMarek Vasut * 6447c852375SMarek Vasut * This value is constant for each battery and set from DT. 6457c852375SMarek Vasut */ 6467c852375SMarek Vasut val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); 6477c852375SMarek Vasut break; 6487c852375SMarek Vasut 6499652c024SAngus Ainslie case POWER_SUPPLY_PROP_TEMP: 6509652c024SAngus Ainslie ret = bq25890_field_read(bq, F_TSPCT); 6519652c024SAngus Ainslie if (ret < 0) 6529652c024SAngus Ainslie return ret; 6539652c024SAngus Ainslie 6549652c024SAngus Ainslie /* convert TS percentage into rough temperature */ 6559652c024SAngus Ainslie val->intval = bq25890_find_val(ret, TBL_TSPCT); 6569652c024SAngus Ainslie break; 6579652c024SAngus Ainslie 6588c0984e5SSebastian Reichel default: 6598c0984e5SSebastian Reichel return -EINVAL; 6608c0984e5SSebastian Reichel } 6618c0984e5SSebastian Reichel 6628c0984e5SSebastian Reichel return 0; 6638c0984e5SSebastian Reichel } 6648c0984e5SSebastian Reichel 6654a4748f2SMarek Vasut static int bq25890_power_supply_set_property(struct power_supply *psy, 6664a4748f2SMarek Vasut enum power_supply_property psp, 6674a4748f2SMarek Vasut const union power_supply_propval *val) 6684a4748f2SMarek Vasut { 6694a4748f2SMarek Vasut struct bq25890_device *bq = power_supply_get_drvdata(psy); 670b63e60ebSMarek Vasut int maxval; 6714a4748f2SMarek Vasut u8 lval; 6724a4748f2SMarek Vasut 6734a4748f2SMarek Vasut switch (psp) { 674b63e60ebSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 675b63e60ebSMarek Vasut maxval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); 676b63e60ebSMarek Vasut lval = bq25890_find_idx(min(val->intval, maxval), TBL_ICHG); 677b63e60ebSMarek Vasut return bq25890_field_write(bq, F_ICHG, lval); 678b63e60ebSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 679b63e60ebSMarek Vasut maxval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); 680b63e60ebSMarek Vasut lval = bq25890_find_idx(min(val->intval, maxval), TBL_VREG); 681b63e60ebSMarek Vasut return bq25890_field_write(bq, F_VREG, lval); 6824a4748f2SMarek Vasut case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 68355cafd4bSNathan Chancellor lval = bq25890_find_idx(val->intval, TBL_IINLIM); 6844a4748f2SMarek Vasut return bq25890_field_write(bq, F_IINLIM, lval); 6854a4748f2SMarek Vasut default: 6864a4748f2SMarek Vasut return -EINVAL; 6874a4748f2SMarek Vasut } 6884a4748f2SMarek Vasut } 6894a4748f2SMarek Vasut 6904a4748f2SMarek Vasut static int bq25890_power_supply_property_is_writeable(struct power_supply *psy, 6914a4748f2SMarek Vasut enum power_supply_property psp) 6924a4748f2SMarek Vasut { 6934a4748f2SMarek Vasut switch (psp) { 694b63e60ebSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 695b63e60ebSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 6964a4748f2SMarek Vasut case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 6974a4748f2SMarek Vasut return true; 6984a4748f2SMarek Vasut default: 6994a4748f2SMarek Vasut return false; 7004a4748f2SMarek Vasut } 7014a4748f2SMarek Vasut } 7024a4748f2SMarek Vasut 703eab25b4fSHans de Goede /* On the BQ25892 try to get charger-type info from our supplier */ 704eab25b4fSHans de Goede static void bq25890_charger_external_power_changed(struct power_supply *psy) 705eab25b4fSHans de Goede { 706eab25b4fSHans de Goede struct bq25890_device *bq = power_supply_get_drvdata(psy); 707eab25b4fSHans de Goede union power_supply_propval val; 708eab25b4fSHans de Goede int input_current_limit, ret; 709eab25b4fSHans de Goede 710eab25b4fSHans de Goede if (bq->chip_version != BQ25892) 711eab25b4fSHans de Goede return; 712eab25b4fSHans de Goede 713eab25b4fSHans de Goede ret = power_supply_get_property_from_supplier(bq->charger, 714eab25b4fSHans de Goede POWER_SUPPLY_PROP_USB_TYPE, 715eab25b4fSHans de Goede &val); 716eab25b4fSHans de Goede if (ret) 717eab25b4fSHans de Goede return; 718eab25b4fSHans de Goede 719eab25b4fSHans de Goede switch (val.intval) { 720eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_DCP: 721eab25b4fSHans de Goede input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM); 72248f45b09SYauhen Kharuzhy if (bq->pump_express_vbus_max) { 72348f45b09SYauhen Kharuzhy queue_delayed_work(system_power_efficient_wq, 72448f45b09SYauhen Kharuzhy &bq->pump_express_work, 72548f45b09SYauhen Kharuzhy PUMP_EXPRESS_START_DELAY); 72648f45b09SYauhen Kharuzhy } 727eab25b4fSHans de Goede break; 728eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_CDP: 729eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_ACA: 730eab25b4fSHans de Goede input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM); 731eab25b4fSHans de Goede break; 732eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_SDP: 733eab25b4fSHans de Goede default: 734eab25b4fSHans de Goede input_current_limit = bq25890_find_idx(500000, TBL_IINLIM); 735eab25b4fSHans de Goede } 736eab25b4fSHans de Goede 737eab25b4fSHans de Goede bq25890_field_write(bq, F_IINLIM, input_current_limit); 738eab25b4fSHans de Goede } 739eab25b4fSHans de Goede 7408c0984e5SSebastian Reichel static int bq25890_get_chip_state(struct bq25890_device *bq, 7418c0984e5SSebastian Reichel struct bq25890_state *state) 7428c0984e5SSebastian Reichel { 7438c0984e5SSebastian Reichel int i, ret; 7448c0984e5SSebastian Reichel 7458c0984e5SSebastian Reichel struct { 7468c0984e5SSebastian Reichel enum bq25890_fields id; 7478c0984e5SSebastian Reichel u8 *data; 7488c0984e5SSebastian Reichel } state_fields[] = { 7498c0984e5SSebastian Reichel {F_CHG_STAT, &state->chrg_status}, 7508c0984e5SSebastian Reichel {F_PG_STAT, &state->online}, 7518c0984e5SSebastian Reichel {F_VSYS_STAT, &state->vsys_status}, 7528c0984e5SSebastian Reichel {F_BOOST_FAULT, &state->boost_fault}, 7538c0984e5SSebastian Reichel {F_BAT_FAULT, &state->bat_fault}, 754c562a43aSYauhen Kharuzhy {F_CHG_FAULT, &state->chrg_fault}, 755c562a43aSYauhen Kharuzhy {F_NTC_FAULT, &state->ntc_fault} 7568c0984e5SSebastian Reichel }; 7578c0984e5SSebastian Reichel 7588c0984e5SSebastian Reichel for (i = 0; i < ARRAY_SIZE(state_fields); i++) { 7598c0984e5SSebastian Reichel ret = bq25890_field_read(bq, state_fields[i].id); 7608c0984e5SSebastian Reichel if (ret < 0) 7618c0984e5SSebastian Reichel return ret; 7628c0984e5SSebastian Reichel 7638c0984e5SSebastian Reichel *state_fields[i].data = ret; 7648c0984e5SSebastian Reichel } 7658c0984e5SSebastian Reichel 766c562a43aSYauhen Kharuzhy dev_dbg(bq->dev, "S:CHG/PG/VSYS=%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n", 7678c0984e5SSebastian Reichel state->chrg_status, state->online, state->vsys_status, 768c562a43aSYauhen Kharuzhy state->chrg_fault, state->boost_fault, state->bat_fault, 769c562a43aSYauhen Kharuzhy state->ntc_fault); 7708c0984e5SSebastian Reichel 7718c0984e5SSebastian Reichel return 0; 7728c0984e5SSebastian Reichel } 7738c0984e5SSebastian Reichel 77472d9cd9cSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq) 7758c0984e5SSebastian Reichel { 77672d9cd9cSMichał Mirosław struct bq25890_state new_state; 7778c0984e5SSebastian Reichel int ret; 7788c0984e5SSebastian Reichel 77972d9cd9cSMichał Mirosław ret = bq25890_get_chip_state(bq, &new_state); 78072d9cd9cSMichał Mirosław if (ret < 0) 78172d9cd9cSMichał Mirosław return IRQ_NONE; 7828c0984e5SSebastian Reichel 78372d9cd9cSMichał Mirosław if (!memcmp(&bq->state, &new_state, sizeof(new_state))) 78472d9cd9cSMichał Mirosław return IRQ_NONE; 78572d9cd9cSMichał Mirosław 78672d9cd9cSMichał Mirosław if (!new_state.online && bq->state.online) { /* power removed */ 7878c0984e5SSebastian Reichel /* disable ADC */ 78880211be1SYauhen Kharuzhy ret = bq25890_field_write(bq, F_CONV_RATE, 0); 7898c0984e5SSebastian Reichel if (ret < 0) 7908c0984e5SSebastian Reichel goto error; 79172d9cd9cSMichał Mirosław } else if (new_state.online && !bq->state.online) { /* power inserted */ 7928c0984e5SSebastian Reichel /* enable ADC, to have control of charge current/voltage */ 79380211be1SYauhen Kharuzhy ret = bq25890_field_write(bq, F_CONV_RATE, 1); 7948c0984e5SSebastian Reichel if (ret < 0) 7958c0984e5SSebastian Reichel goto error; 7968c0984e5SSebastian Reichel } 7978c0984e5SSebastian Reichel 79872d9cd9cSMichał Mirosław bq->state = new_state; 79972d9cd9cSMichał Mirosław power_supply_changed(bq->charger); 8008c0984e5SSebastian Reichel 80172d9cd9cSMichał Mirosław return IRQ_HANDLED; 8028c0984e5SSebastian Reichel error: 80372d9cd9cSMichał Mirosław dev_err(bq->dev, "Error communicating with the chip: %pe\n", 80472d9cd9cSMichał Mirosław ERR_PTR(ret)); 80572d9cd9cSMichał Mirosław return IRQ_HANDLED; 8068c0984e5SSebastian Reichel } 8078c0984e5SSebastian Reichel 8088c0984e5SSebastian Reichel static irqreturn_t bq25890_irq_handler_thread(int irq, void *private) 8098c0984e5SSebastian Reichel { 8108c0984e5SSebastian Reichel struct bq25890_device *bq = private; 81172d9cd9cSMichał Mirosław irqreturn_t ret; 8128c0984e5SSebastian Reichel 8138c0984e5SSebastian Reichel mutex_lock(&bq->lock); 81472d9cd9cSMichał Mirosław ret = __bq25890_handle_irq(bq); 8158c0984e5SSebastian Reichel mutex_unlock(&bq->lock); 8168c0984e5SSebastian Reichel 81772d9cd9cSMichał Mirosław return ret; 8188c0984e5SSebastian Reichel } 8198c0984e5SSebastian Reichel 8208c0984e5SSebastian Reichel static int bq25890_chip_reset(struct bq25890_device *bq) 8218c0984e5SSebastian Reichel { 8228c0984e5SSebastian Reichel int ret; 8238c0984e5SSebastian Reichel int rst_check_counter = 10; 8248c0984e5SSebastian Reichel 8258c0984e5SSebastian Reichel ret = bq25890_field_write(bq, F_REG_RST, 1); 8268c0984e5SSebastian Reichel if (ret < 0) 8278c0984e5SSebastian Reichel return ret; 8288c0984e5SSebastian Reichel 8298c0984e5SSebastian Reichel do { 8308c0984e5SSebastian Reichel ret = bq25890_field_read(bq, F_REG_RST); 8318c0984e5SSebastian Reichel if (ret < 0) 8328c0984e5SSebastian Reichel return ret; 8338c0984e5SSebastian Reichel 8348c0984e5SSebastian Reichel usleep_range(5, 10); 8358c0984e5SSebastian Reichel } while (ret == 1 && --rst_check_counter); 8368c0984e5SSebastian Reichel 8378c0984e5SSebastian Reichel if (!rst_check_counter) 8388c0984e5SSebastian Reichel return -ETIMEDOUT; 8398c0984e5SSebastian Reichel 8408c0984e5SSebastian Reichel return 0; 8418c0984e5SSebastian Reichel } 8428c0984e5SSebastian Reichel 8437b22a974SHans de Goede static int bq25890_rw_init_data(struct bq25890_device *bq) 8448c0984e5SSebastian Reichel { 84540428bd4SHans de Goede bool write = !bq->read_back_init_data; 8468c0984e5SSebastian Reichel int ret; 8478c0984e5SSebastian Reichel int i; 8488c0984e5SSebastian Reichel 8498c0984e5SSebastian Reichel const struct { 8508c0984e5SSebastian Reichel enum bq25890_fields id; 8517b22a974SHans de Goede u8 *value; 8528c0984e5SSebastian Reichel } init_data[] = { 8537b22a974SHans de Goede {F_ICHG, &bq->init_data.ichg}, 8547b22a974SHans de Goede {F_VREG, &bq->init_data.vreg}, 8557b22a974SHans de Goede {F_ITERM, &bq->init_data.iterm}, 8567b22a974SHans de Goede {F_IPRECHG, &bq->init_data.iprechg}, 8577b22a974SHans de Goede {F_SYSVMIN, &bq->init_data.sysvmin}, 8587b22a974SHans de Goede {F_BOOSTV, &bq->init_data.boostv}, 8597b22a974SHans de Goede {F_BOOSTI, &bq->init_data.boosti}, 8607b22a974SHans de Goede {F_BOOSTF, &bq->init_data.boostf}, 8617b22a974SHans de Goede {F_EN_ILIM, &bq->init_data.ilim_en}, 8627b22a974SHans de Goede {F_TREG, &bq->init_data.treg}, 8637b22a974SHans de Goede {F_BATCMP, &bq->init_data.rbatcomp}, 8647b22a974SHans de Goede {F_VCLAMP, &bq->init_data.vclamp}, 8658c0984e5SSebastian Reichel }; 8668c0984e5SSebastian Reichel 8677b22a974SHans de Goede for (i = 0; i < ARRAY_SIZE(init_data); i++) { 8687b22a974SHans de Goede if (write) { 8697b22a974SHans de Goede ret = bq25890_field_write(bq, init_data[i].id, 8707b22a974SHans de Goede *init_data[i].value); 8717b22a974SHans de Goede } else { 8727b22a974SHans de Goede ret = bq25890_field_read(bq, init_data[i].id); 8737b22a974SHans de Goede if (ret >= 0) 8747b22a974SHans de Goede *init_data[i].value = ret; 8757b22a974SHans de Goede } 8767b22a974SHans de Goede if (ret < 0) { 8777b22a974SHans de Goede dev_dbg(bq->dev, "Accessing init data failed %d\n", ret); 8787b22a974SHans de Goede return ret; 8797b22a974SHans de Goede } 8807b22a974SHans de Goede } 8817b22a974SHans de Goede 8827b22a974SHans de Goede return 0; 8837b22a974SHans de Goede } 8847b22a974SHans de Goede 8857b22a974SHans de Goede static int bq25890_hw_init(struct bq25890_device *bq) 8867b22a974SHans de Goede { 8877b22a974SHans de Goede int ret; 8887b22a974SHans de Goede 8897e3b8e35SHans de Goede if (!bq->skip_reset) { 8908c0984e5SSebastian Reichel ret = bq25890_chip_reset(bq); 8919d9ae341SAngus Ainslie (Purism) if (ret < 0) { 8929d9ae341SAngus Ainslie (Purism) dev_dbg(bq->dev, "Reset failed %d\n", ret); 8938c0984e5SSebastian Reichel return ret; 894ad1570d9Skbuild test robot } 89506c75095SHans de Goede } else { 89606c75095SHans de Goede /* 89706c75095SHans de Goede * Ensure charging is enabled, on some boards where the fw 89806c75095SHans de Goede * takes care of initalizition F_CHG_CFG is set to 0 before 89906c75095SHans de Goede * handing control over to the OS. 90006c75095SHans de Goede */ 90106c75095SHans de Goede ret = bq25890_field_write(bq, F_CHG_CFG, 1); 90206c75095SHans de Goede if (ret < 0) { 90306c75095SHans de Goede dev_dbg(bq->dev, "Enabling charging failed %d\n", ret); 90406c75095SHans de Goede return ret; 90506c75095SHans de Goede } 9067e3b8e35SHans de Goede } 9078c0984e5SSebastian Reichel 9088c0984e5SSebastian Reichel /* disable watchdog */ 9098c0984e5SSebastian Reichel ret = bq25890_field_write(bq, F_WD, 0); 9109d9ae341SAngus Ainslie (Purism) if (ret < 0) { 9119d9ae341SAngus Ainslie (Purism) dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret); 9128c0984e5SSebastian Reichel return ret; 913ad1570d9Skbuild test robot } 9148c0984e5SSebastian Reichel 9158c0984e5SSebastian Reichel /* initialize currents/voltages and other parameters */ 9167b22a974SHans de Goede ret = bq25890_rw_init_data(bq); 9177b22a974SHans de Goede if (ret) 9188c0984e5SSebastian Reichel return ret; 9198c0984e5SSebastian Reichel 92022ad4f99SHans de Goede ret = bq25890_get_chip_state(bq, &bq->state); 92122ad4f99SHans de Goede if (ret < 0) { 92222ad4f99SHans de Goede dev_dbg(bq->dev, "Get state failed %d\n", ret); 92322ad4f99SHans de Goede return ret; 92422ad4f99SHans de Goede } 92522ad4f99SHans de Goede 92621d90edaSMichał Mirosław /* Configure ADC for continuous conversions when charging */ 92721d90edaSMichał Mirosław ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online); 9289d9ae341SAngus Ainslie (Purism) if (ret < 0) { 9299d9ae341SAngus Ainslie (Purism) dev_dbg(bq->dev, "Config ADC failed %d\n", ret); 9308c0984e5SSebastian Reichel return ret; 931ad1570d9Skbuild test robot } 9328c0984e5SSebastian Reichel 9338c0984e5SSebastian Reichel return 0; 9348c0984e5SSebastian Reichel } 9358c0984e5SSebastian Reichel 936a6a48facSMichał Mirosław static const enum power_supply_property bq25890_power_supply_props[] = { 9378c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 9382e1a2ddeSAngus Ainslie (Purism) POWER_SUPPLY_PROP_MODEL_NAME, 9398c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 940b302a0aeSMichał Mirosław POWER_SUPPLY_PROP_CHARGE_TYPE, 9418c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ONLINE, 9428c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 9438327a8abSMarek Vasut POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 9448c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 9458c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 9468c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 947c942656dSMichał Mirosław POWER_SUPPLY_PROP_PRECHARGE_CURRENT, 9488c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 949478efc79SMichał Mirosław POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 950ae6fe7a3SAngus Ainslie (Purism) POWER_SUPPLY_PROP_VOLTAGE_NOW, 9511e4724d0SMichał Mirosław POWER_SUPPLY_PROP_CURRENT_NOW, 9529652c024SAngus Ainslie POWER_SUPPLY_PROP_TEMP, 9538c0984e5SSebastian Reichel }; 9548c0984e5SSebastian Reichel 9558c0984e5SSebastian Reichel static char *bq25890_charger_supplied_to[] = { 9568c0984e5SSebastian Reichel "main-battery", 9578c0984e5SSebastian Reichel }; 9588c0984e5SSebastian Reichel 9598c0984e5SSebastian Reichel static const struct power_supply_desc bq25890_power_supply_desc = { 9608c0984e5SSebastian Reichel .name = "bq25890-charger", 9618c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_USB, 9628c0984e5SSebastian Reichel .properties = bq25890_power_supply_props, 9638c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(bq25890_power_supply_props), 9648c0984e5SSebastian Reichel .get_property = bq25890_power_supply_get_property, 9654a4748f2SMarek Vasut .set_property = bq25890_power_supply_set_property, 9664a4748f2SMarek Vasut .property_is_writeable = bq25890_power_supply_property_is_writeable, 967eab25b4fSHans de Goede .external_power_changed = bq25890_charger_external_power_changed, 9688c0984e5SSebastian Reichel }; 9698c0984e5SSebastian Reichel 9708c0984e5SSebastian Reichel static int bq25890_power_supply_init(struct bq25890_device *bq) 9718c0984e5SSebastian Reichel { 9728c0984e5SSebastian Reichel struct power_supply_config psy_cfg = { .drv_data = bq, }; 9738c0984e5SSebastian Reichel 9748c0984e5SSebastian Reichel psy_cfg.supplied_to = bq25890_charger_supplied_to; 9758c0984e5SSebastian Reichel psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to); 9768c0984e5SSebastian Reichel 977d01363daSHans de Goede bq->charger = devm_power_supply_register(bq->dev, 978d01363daSHans de Goede &bq25890_power_supply_desc, 9798c0984e5SSebastian Reichel &psy_cfg); 9808c0984e5SSebastian Reichel 9818c0984e5SSebastian Reichel return PTR_ERR_OR_ZERO(bq->charger); 9828c0984e5SSebastian Reichel } 9838c0984e5SSebastian Reichel 9845575802dSHans de Goede static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val) 9855575802dSHans de Goede { 9865575802dSHans de Goede int ret; 9875575802dSHans de Goede 9885575802dSHans de Goede ret = bq25890_field_write(bq, F_OTG_CFG, val); 9895575802dSHans de Goede if (ret < 0) 9905575802dSHans de Goede dev_err(bq->dev, "Error switching to boost/charger mode: %d\n", ret); 9915575802dSHans de Goede 9925575802dSHans de Goede return ret; 9935575802dSHans de Goede } 9945575802dSHans de Goede 99548f45b09SYauhen Kharuzhy static void bq25890_pump_express_work(struct work_struct *data) 99648f45b09SYauhen Kharuzhy { 99748f45b09SYauhen Kharuzhy struct bq25890_device *bq = 99848f45b09SYauhen Kharuzhy container_of(data, struct bq25890_device, pump_express_work.work); 99948f45b09SYauhen Kharuzhy int voltage, i, ret; 100048f45b09SYauhen Kharuzhy 100148f45b09SYauhen Kharuzhy dev_dbg(bq->dev, "Start to request input voltage increasing\n"); 100248f45b09SYauhen Kharuzhy 100348f45b09SYauhen Kharuzhy /* Enable current pulse voltage control protocol */ 100448f45b09SYauhen Kharuzhy ret = bq25890_field_write(bq, F_PUMPX_EN, 1); 100548f45b09SYauhen Kharuzhy if (ret < 0) 100648f45b09SYauhen Kharuzhy goto error_print; 100748f45b09SYauhen Kharuzhy 100848f45b09SYauhen Kharuzhy for (i = 0; i < PUMP_EXPRESS_MAX_TRIES; i++) { 100948f45b09SYauhen Kharuzhy voltage = bq25890_get_vbus_voltage(bq); 101048f45b09SYauhen Kharuzhy if (voltage < 0) 101148f45b09SYauhen Kharuzhy goto error_print; 101248f45b09SYauhen Kharuzhy dev_dbg(bq->dev, "input voltage = %d uV\n", voltage); 101348f45b09SYauhen Kharuzhy 101448f45b09SYauhen Kharuzhy if ((voltage + PUMP_EXPRESS_VBUS_MARGIN_uV) > 101548f45b09SYauhen Kharuzhy bq->pump_express_vbus_max) 101648f45b09SYauhen Kharuzhy break; 101748f45b09SYauhen Kharuzhy 101848f45b09SYauhen Kharuzhy ret = bq25890_field_write(bq, F_PUMPX_UP, 1); 101948f45b09SYauhen Kharuzhy if (ret < 0) 102048f45b09SYauhen Kharuzhy goto error_print; 102148f45b09SYauhen Kharuzhy 102248f45b09SYauhen Kharuzhy /* Note a single PUMPX up pulse-sequence takes 2.1s */ 102348f45b09SYauhen Kharuzhy ret = regmap_field_read_poll_timeout(bq->rmap_fields[F_PUMPX_UP], 102448f45b09SYauhen Kharuzhy ret, !ret, 100000, 3000000); 102548f45b09SYauhen Kharuzhy if (ret < 0) 102648f45b09SYauhen Kharuzhy goto error_print; 102748f45b09SYauhen Kharuzhy 102848f45b09SYauhen Kharuzhy /* Make sure ADC has sampled Vbus before checking again */ 102948f45b09SYauhen Kharuzhy msleep(1000); 103048f45b09SYauhen Kharuzhy } 103148f45b09SYauhen Kharuzhy 103248f45b09SYauhen Kharuzhy bq25890_field_write(bq, F_PUMPX_EN, 0); 103348f45b09SYauhen Kharuzhy 103448f45b09SYauhen Kharuzhy dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n", 103548f45b09SYauhen Kharuzhy voltage); 103648f45b09SYauhen Kharuzhy 103748f45b09SYauhen Kharuzhy return; 103848f45b09SYauhen Kharuzhy error_print: 103904f7c7dfSHans de Goede bq25890_field_write(bq, F_PUMPX_EN, 0); 104048f45b09SYauhen Kharuzhy dev_err(bq->dev, "Failed to request hi-voltage charging\n"); 104148f45b09SYauhen Kharuzhy } 104248f45b09SYauhen Kharuzhy 10438c0984e5SSebastian Reichel static void bq25890_usb_work(struct work_struct *data) 10448c0984e5SSebastian Reichel { 10458c0984e5SSebastian Reichel int ret; 10468c0984e5SSebastian Reichel struct bq25890_device *bq = 10478c0984e5SSebastian Reichel container_of(data, struct bq25890_device, usb_work); 10488c0984e5SSebastian Reichel 10498c0984e5SSebastian Reichel switch (bq->usb_event) { 10508c0984e5SSebastian Reichel case USB_EVENT_ID: 10518c0984e5SSebastian Reichel /* Enable boost mode */ 10525575802dSHans de Goede bq25890_set_otg_cfg(bq, 1); 10538c0984e5SSebastian Reichel break; 10548c0984e5SSebastian Reichel 10558c0984e5SSebastian Reichel case USB_EVENT_NONE: 10568c0984e5SSebastian Reichel /* Disable boost mode */ 10575575802dSHans de Goede ret = bq25890_set_otg_cfg(bq, 0); 10585575802dSHans de Goede if (ret == 0) 10598c0984e5SSebastian Reichel power_supply_changed(bq->charger); 10608c0984e5SSebastian Reichel break; 10618c0984e5SSebastian Reichel } 10628c0984e5SSebastian Reichel } 10638c0984e5SSebastian Reichel 10648c0984e5SSebastian Reichel static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val, 10658c0984e5SSebastian Reichel void *priv) 10668c0984e5SSebastian Reichel { 10678c0984e5SSebastian Reichel struct bq25890_device *bq = 10688c0984e5SSebastian Reichel container_of(nb, struct bq25890_device, usb_nb); 10698c0984e5SSebastian Reichel 10708c0984e5SSebastian Reichel bq->usb_event = val; 10718c0984e5SSebastian Reichel queue_work(system_power_efficient_wq, &bq->usb_work); 10728c0984e5SSebastian Reichel 10738c0984e5SSebastian Reichel return NOTIFY_OK; 10748c0984e5SSebastian Reichel } 10758c0984e5SSebastian Reichel 107679d35365SHans de Goede #ifdef CONFIG_REGULATOR 107779d35365SHans de Goede static int bq25890_vbus_enable(struct regulator_dev *rdev) 107879d35365SHans de Goede { 107979d35365SHans de Goede struct bq25890_device *bq = rdev_get_drvdata(rdev); 108079d35365SHans de Goede 108179d35365SHans de Goede return bq25890_set_otg_cfg(bq, 1); 108279d35365SHans de Goede } 108379d35365SHans de Goede 108479d35365SHans de Goede static int bq25890_vbus_disable(struct regulator_dev *rdev) 108579d35365SHans de Goede { 108679d35365SHans de Goede struct bq25890_device *bq = rdev_get_drvdata(rdev); 108779d35365SHans de Goede 108879d35365SHans de Goede return bq25890_set_otg_cfg(bq, 0); 108979d35365SHans de Goede } 109079d35365SHans de Goede 109179d35365SHans de Goede static int bq25890_vbus_is_enabled(struct regulator_dev *rdev) 109279d35365SHans de Goede { 109379d35365SHans de Goede struct bq25890_device *bq = rdev_get_drvdata(rdev); 109479d35365SHans de Goede 109579d35365SHans de Goede return bq25890_field_read(bq, F_OTG_CFG); 109679d35365SHans de Goede } 109779d35365SHans de Goede 109885052e90SMarek Vasut static int bq25890_vbus_get_voltage(struct regulator_dev *rdev) 109985052e90SMarek Vasut { 110085052e90SMarek Vasut struct bq25890_device *bq = rdev_get_drvdata(rdev); 110185052e90SMarek Vasut 110285052e90SMarek Vasut return bq25890_get_vbus_voltage(bq); 110385052e90SMarek Vasut } 110485052e90SMarek Vasut 1105*14a3d159SMarek Vasut static int bq25890_vsys_get_voltage(struct regulator_dev *rdev) 1106*14a3d159SMarek Vasut { 1107*14a3d159SMarek Vasut struct bq25890_device *bq = rdev_get_drvdata(rdev); 1108*14a3d159SMarek Vasut int ret; 1109*14a3d159SMarek Vasut 1110*14a3d159SMarek Vasut /* Should be some output voltage ? */ 1111*14a3d159SMarek Vasut ret = bq25890_field_read(bq, F_SYSV); /* read measured value */ 1112*14a3d159SMarek Vasut if (ret < 0) 1113*14a3d159SMarek Vasut return ret; 1114*14a3d159SMarek Vasut 1115*14a3d159SMarek Vasut /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ 1116*14a3d159SMarek Vasut return 2304000 + ret * 20000; 1117*14a3d159SMarek Vasut } 1118*14a3d159SMarek Vasut 111979d35365SHans de Goede static const struct regulator_ops bq25890_vbus_ops = { 112079d35365SHans de Goede .enable = bq25890_vbus_enable, 112179d35365SHans de Goede .disable = bq25890_vbus_disable, 112279d35365SHans de Goede .is_enabled = bq25890_vbus_is_enabled, 112385052e90SMarek Vasut .get_voltage = bq25890_vbus_get_voltage, 112479d35365SHans de Goede }; 112579d35365SHans de Goede 112679d35365SHans de Goede static const struct regulator_desc bq25890_vbus_desc = { 112779d35365SHans de Goede .name = "usb_otg_vbus", 112879d35365SHans de Goede .of_match = "usb-otg-vbus", 112979d35365SHans de Goede .type = REGULATOR_VOLTAGE, 113079d35365SHans de Goede .owner = THIS_MODULE, 113179d35365SHans de Goede .ops = &bq25890_vbus_ops, 113279d35365SHans de Goede }; 11335f5c10ecSMarek Vasut 1134*14a3d159SMarek Vasut static const struct regulator_ops bq25890_vsys_ops = { 1135*14a3d159SMarek Vasut .get_voltage = bq25890_vsys_get_voltage, 1136*14a3d159SMarek Vasut }; 1137*14a3d159SMarek Vasut 1138*14a3d159SMarek Vasut static const struct regulator_desc bq25890_vsys_desc = { 1139*14a3d159SMarek Vasut .name = "vsys", 1140*14a3d159SMarek Vasut .of_match = "vsys", 1141*14a3d159SMarek Vasut .type = REGULATOR_VOLTAGE, 1142*14a3d159SMarek Vasut .owner = THIS_MODULE, 1143*14a3d159SMarek Vasut .ops = &bq25890_vsys_ops, 1144*14a3d159SMarek Vasut }; 1145*14a3d159SMarek Vasut 11465f5c10ecSMarek Vasut static int bq25890_register_regulator(struct bq25890_device *bq) 11475f5c10ecSMarek Vasut { 11485f5c10ecSMarek Vasut struct bq25890_platform_data *pdata = dev_get_platdata(bq->dev); 11495f5c10ecSMarek Vasut struct regulator_config cfg = { 11505f5c10ecSMarek Vasut .dev = bq->dev, 11515f5c10ecSMarek Vasut .driver_data = bq, 11525f5c10ecSMarek Vasut }; 11535f5c10ecSMarek Vasut struct regulator_dev *reg; 11545f5c10ecSMarek Vasut 11555f5c10ecSMarek Vasut if (pdata) 11565f5c10ecSMarek Vasut cfg.init_data = pdata->regulator_init_data; 11575f5c10ecSMarek Vasut 11585f5c10ecSMarek Vasut reg = devm_regulator_register(bq->dev, &bq25890_vbus_desc, &cfg); 11595f5c10ecSMarek Vasut if (IS_ERR(reg)) { 11605f5c10ecSMarek Vasut return dev_err_probe(bq->dev, PTR_ERR(reg), 11615f5c10ecSMarek Vasut "registering vbus regulator"); 11625f5c10ecSMarek Vasut } 11635f5c10ecSMarek Vasut 1164*14a3d159SMarek Vasut reg = devm_regulator_register(bq->dev, &bq25890_vsys_desc, &cfg); 1165*14a3d159SMarek Vasut if (IS_ERR(reg)) { 1166*14a3d159SMarek Vasut return dev_err_probe(bq->dev, PTR_ERR(reg), 1167*14a3d159SMarek Vasut "registering vsys regulator"); 1168*14a3d159SMarek Vasut } 1169*14a3d159SMarek Vasut 11705f5c10ecSMarek Vasut return 0; 11715f5c10ecSMarek Vasut } 11725f5c10ecSMarek Vasut #else 11735f5c10ecSMarek Vasut static inline int 11745f5c10ecSMarek Vasut bq25890_register_regulator(struct bq25890_device *bq) 11755f5c10ecSMarek Vasut { 11765f5c10ecSMarek Vasut return 0; 11775f5c10ecSMarek Vasut } 117879d35365SHans de Goede #endif 117979d35365SHans de Goede 1180d20267c9SYauhen Kharuzhy static int bq25890_get_chip_version(struct bq25890_device *bq) 1181d20267c9SYauhen Kharuzhy { 1182d20267c9SYauhen Kharuzhy int id, rev; 1183d20267c9SYauhen Kharuzhy 1184d20267c9SYauhen Kharuzhy id = bq25890_field_read(bq, F_PN); 1185d20267c9SYauhen Kharuzhy if (id < 0) { 1186172d0cceSMartin Kepplinger dev_err(bq->dev, "Cannot read chip ID: %d\n", id); 1187d20267c9SYauhen Kharuzhy return id; 1188d20267c9SYauhen Kharuzhy } 1189d20267c9SYauhen Kharuzhy 1190d20267c9SYauhen Kharuzhy rev = bq25890_field_read(bq, F_DEV_REV); 1191d20267c9SYauhen Kharuzhy if (rev < 0) { 1192172d0cceSMartin Kepplinger dev_err(bq->dev, "Cannot read chip revision: %d\n", rev); 1193cb619e80SColin Ian King return rev; 1194d20267c9SYauhen Kharuzhy } 1195d20267c9SYauhen Kharuzhy 1196d20267c9SYauhen Kharuzhy switch (id) { 1197d20267c9SYauhen Kharuzhy case BQ25890_ID: 1198d20267c9SYauhen Kharuzhy bq->chip_version = BQ25890; 1199d20267c9SYauhen Kharuzhy break; 1200d20267c9SYauhen Kharuzhy 1201d20267c9SYauhen Kharuzhy /* BQ25892 and BQ25896 share same ID 0 */ 1202d20267c9SYauhen Kharuzhy case BQ25896_ID: 1203d20267c9SYauhen Kharuzhy switch (rev) { 1204d20267c9SYauhen Kharuzhy case 2: 1205d20267c9SYauhen Kharuzhy bq->chip_version = BQ25896; 1206d20267c9SYauhen Kharuzhy break; 1207d20267c9SYauhen Kharuzhy case 1: 1208d20267c9SYauhen Kharuzhy bq->chip_version = BQ25892; 1209d20267c9SYauhen Kharuzhy break; 1210d20267c9SYauhen Kharuzhy default: 1211d20267c9SYauhen Kharuzhy dev_err(bq->dev, 1212d20267c9SYauhen Kharuzhy "Unknown device revision %d, assume BQ25892\n", 1213d20267c9SYauhen Kharuzhy rev); 1214d20267c9SYauhen Kharuzhy bq->chip_version = BQ25892; 1215d20267c9SYauhen Kharuzhy } 1216d20267c9SYauhen Kharuzhy break; 1217d20267c9SYauhen Kharuzhy 1218d20267c9SYauhen Kharuzhy case BQ25895_ID: 1219d20267c9SYauhen Kharuzhy bq->chip_version = BQ25895; 1220d20267c9SYauhen Kharuzhy break; 1221d20267c9SYauhen Kharuzhy 1222d20267c9SYauhen Kharuzhy default: 1223d20267c9SYauhen Kharuzhy dev_err(bq->dev, "Unknown chip ID %d\n", id); 1224d20267c9SYauhen Kharuzhy return -ENODEV; 1225d20267c9SYauhen Kharuzhy } 1226d20267c9SYauhen Kharuzhy 1227d20267c9SYauhen Kharuzhy return 0; 1228d20267c9SYauhen Kharuzhy } 1229d20267c9SYauhen Kharuzhy 12308c0984e5SSebastian Reichel static int bq25890_irq_probe(struct bq25890_device *bq) 12318c0984e5SSebastian Reichel { 12328c0984e5SSebastian Reichel struct gpio_desc *irq; 12338c0984e5SSebastian Reichel 123486775879SAndy Shevchenko irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN); 1235172d0cceSMartin Kepplinger if (IS_ERR(irq)) 1236172d0cceSMartin Kepplinger return dev_err_probe(bq->dev, PTR_ERR(irq), 1237172d0cceSMartin Kepplinger "Could not probe irq pin.\n"); 12388c0984e5SSebastian Reichel 12398c0984e5SSebastian Reichel return gpiod_to_irq(irq); 12408c0984e5SSebastian Reichel } 12418c0984e5SSebastian Reichel 12428c0984e5SSebastian Reichel static int bq25890_fw_read_u32_props(struct bq25890_device *bq) 12438c0984e5SSebastian Reichel { 12448c0984e5SSebastian Reichel int ret; 12458c0984e5SSebastian Reichel u32 property; 12468c0984e5SSebastian Reichel int i; 12478c0984e5SSebastian Reichel struct bq25890_init_data *init = &bq->init_data; 12488c0984e5SSebastian Reichel struct { 12498c0984e5SSebastian Reichel char *name; 12508c0984e5SSebastian Reichel bool optional; 12518c0984e5SSebastian Reichel enum bq25890_table_ids tbl_id; 12528c0984e5SSebastian Reichel u8 *conv_data; /* holds converted value from given property */ 12538c0984e5SSebastian Reichel } props[] = { 12548c0984e5SSebastian Reichel /* required properties */ 12558c0984e5SSebastian Reichel {"ti,charge-current", false, TBL_ICHG, &init->ichg}, 12568c0984e5SSebastian Reichel {"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg}, 12578c0984e5SSebastian Reichel {"ti,termination-current", false, TBL_ITERM, &init->iterm}, 12588c0984e5SSebastian Reichel {"ti,precharge-current", false, TBL_ITERM, &init->iprechg}, 12598c0984e5SSebastian Reichel {"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin}, 12608c0984e5SSebastian Reichel {"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv}, 12618c0984e5SSebastian Reichel {"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti}, 12628c0984e5SSebastian Reichel 12638c0984e5SSebastian Reichel /* optional properties */ 126472408329SMichał Mirosław {"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg}, 126572408329SMichał Mirosław {"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp}, 126672408329SMichał Mirosław {"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp}, 12678c0984e5SSebastian Reichel }; 12688c0984e5SSebastian Reichel 12698c0984e5SSebastian Reichel /* initialize data for optional properties */ 12708c0984e5SSebastian Reichel init->treg = 3; /* 120 degrees Celsius */ 127172408329SMichał Mirosław init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */ 12728c0984e5SSebastian Reichel 12738c0984e5SSebastian Reichel for (i = 0; i < ARRAY_SIZE(props); i++) { 12748c0984e5SSebastian Reichel ret = device_property_read_u32(bq->dev, props[i].name, 12758c0984e5SSebastian Reichel &property); 12768c0984e5SSebastian Reichel if (ret < 0) { 12778c0984e5SSebastian Reichel if (props[i].optional) 12788c0984e5SSebastian Reichel continue; 12798c0984e5SSebastian Reichel 12809d9ae341SAngus Ainslie (Purism) dev_err(bq->dev, "Unable to read property %d %s\n", ret, 12819d9ae341SAngus Ainslie (Purism) props[i].name); 12829d9ae341SAngus Ainslie (Purism) 12838c0984e5SSebastian Reichel return ret; 12848c0984e5SSebastian Reichel } 12858c0984e5SSebastian Reichel 12868c0984e5SSebastian Reichel *props[i].conv_data = bq25890_find_idx(property, 12878c0984e5SSebastian Reichel props[i].tbl_id); 12888c0984e5SSebastian Reichel } 12898c0984e5SSebastian Reichel 12908c0984e5SSebastian Reichel return 0; 12918c0984e5SSebastian Reichel } 12928c0984e5SSebastian Reichel 12938c0984e5SSebastian Reichel static int bq25890_fw_probe(struct bq25890_device *bq) 12948c0984e5SSebastian Reichel { 12958c0984e5SSebastian Reichel int ret; 12968c0984e5SSebastian Reichel struct bq25890_init_data *init = &bq->init_data; 12978c0984e5SSebastian Reichel 129848f45b09SYauhen Kharuzhy /* Optional, left at 0 if property is not present */ 129948f45b09SYauhen Kharuzhy device_property_read_u32(bq->dev, "linux,pump-express-vbus-max", 130048f45b09SYauhen Kharuzhy &bq->pump_express_vbus_max); 130148f45b09SYauhen Kharuzhy 13027e3b8e35SHans de Goede bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset"); 130340428bd4SHans de Goede bq->read_back_init_data = device_property_read_bool(bq->dev, 130440428bd4SHans de Goede "linux,read-back-settings"); 130540428bd4SHans de Goede if (bq->read_back_init_data) 130640428bd4SHans de Goede return 0; 13077e3b8e35SHans de Goede 13088c0984e5SSebastian Reichel ret = bq25890_fw_read_u32_props(bq); 13098c0984e5SSebastian Reichel if (ret < 0) 13108c0984e5SSebastian Reichel return ret; 13118c0984e5SSebastian Reichel 13128c0984e5SSebastian Reichel init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin"); 13138c0984e5SSebastian Reichel init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq"); 13148c0984e5SSebastian Reichel 13158c0984e5SSebastian Reichel return 0; 13168c0984e5SSebastian Reichel } 13178c0984e5SSebastian Reichel 13188c0984e5SSebastian Reichel static int bq25890_probe(struct i2c_client *client, 13198c0984e5SSebastian Reichel const struct i2c_device_id *id) 13208c0984e5SSebastian Reichel { 13218c0984e5SSebastian Reichel struct device *dev = &client->dev; 13228c0984e5SSebastian Reichel struct bq25890_device *bq; 13238c0984e5SSebastian Reichel int ret; 13248c0984e5SSebastian Reichel 13258c0984e5SSebastian Reichel bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); 13268c0984e5SSebastian Reichel if (!bq) 13278c0984e5SSebastian Reichel return -ENOMEM; 13288c0984e5SSebastian Reichel 13298c0984e5SSebastian Reichel bq->client = client; 13308c0984e5SSebastian Reichel bq->dev = dev; 13318c0984e5SSebastian Reichel 13328c0984e5SSebastian Reichel mutex_init(&bq->lock); 133348f45b09SYauhen Kharuzhy INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work); 13348c0984e5SSebastian Reichel 13358c0984e5SSebastian Reichel bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config); 1336172d0cceSMartin Kepplinger if (IS_ERR(bq->rmap)) 1337172d0cceSMartin Kepplinger return dev_err_probe(dev, PTR_ERR(bq->rmap), 1338172d0cceSMartin Kepplinger "failed to allocate register map\n"); 13398c0984e5SSebastian Reichel 1340c1ae3a4eSHans de Goede ret = devm_regmap_field_bulk_alloc(dev, bq->rmap, bq->rmap_fields, 1341c1ae3a4eSHans de Goede bq25890_reg_fields, F_MAX_FIELDS); 1342c1ae3a4eSHans de Goede if (ret) 1343c1ae3a4eSHans de Goede return ret; 13448c0984e5SSebastian Reichel 13458c0984e5SSebastian Reichel i2c_set_clientdata(client, bq); 13468c0984e5SSebastian Reichel 1347d20267c9SYauhen Kharuzhy ret = bq25890_get_chip_version(bq); 1348d20267c9SYauhen Kharuzhy if (ret) { 1349172d0cceSMartin Kepplinger dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret); 1350d20267c9SYauhen Kharuzhy return ret; 13518c0984e5SSebastian Reichel } 13528c0984e5SSebastian Reichel 13538c0984e5SSebastian Reichel ret = bq25890_fw_probe(bq); 1354f481d5b8SHans de Goede if (ret < 0) 1355f481d5b8SHans de Goede return dev_err_probe(dev, ret, "reading device properties\n"); 13568c0984e5SSebastian Reichel 13578c0984e5SSebastian Reichel ret = bq25890_hw_init(bq); 13588c0984e5SSebastian Reichel if (ret < 0) { 1359172d0cceSMartin Kepplinger dev_err(dev, "Cannot initialize the chip: %d\n", ret); 13608c0984e5SSebastian Reichel return ret; 13618c0984e5SSebastian Reichel } 13628c0984e5SSebastian Reichel 13638c0984e5SSebastian Reichel if (client->irq <= 0) 13648c0984e5SSebastian Reichel client->irq = bq25890_irq_probe(bq); 13658c0984e5SSebastian Reichel 13668c0984e5SSebastian Reichel if (client->irq < 0) { 13678c0984e5SSebastian Reichel dev_err(dev, "No irq resource found.\n"); 13688c0984e5SSebastian Reichel return client->irq; 13698c0984e5SSebastian Reichel } 13708c0984e5SSebastian Reichel 13718c0984e5SSebastian Reichel /* OTG reporting */ 13728c0984e5SSebastian Reichel bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 13735f5c10ecSMarek Vasut 13745f5c10ecSMarek Vasut ret = bq25890_register_regulator(bq); 13755f5c10ecSMarek Vasut if (ret) 13765f5c10ecSMarek Vasut return ret; 13775f5c10ecSMarek Vasut 13788c0984e5SSebastian Reichel if (!IS_ERR_OR_NULL(bq->usb_phy)) { 13798c0984e5SSebastian Reichel INIT_WORK(&bq->usb_work, bq25890_usb_work); 13808c0984e5SSebastian Reichel bq->usb_nb.notifier_call = bq25890_usb_notifier; 13818c0984e5SSebastian Reichel usb_register_notifier(bq->usb_phy, &bq->usb_nb); 13828c0984e5SSebastian Reichel } 13838c0984e5SSebastian Reichel 1384d01363daSHans de Goede ret = bq25890_power_supply_init(bq); 1385d01363daSHans de Goede if (ret < 0) { 1386d01363daSHans de Goede dev_err(dev, "Failed to register power supply\n"); 1387d01363daSHans de Goede goto err_unregister_usb_notifier; 1388d01363daSHans de Goede } 1389d01363daSHans de Goede 13908c0984e5SSebastian Reichel ret = devm_request_threaded_irq(dev, client->irq, NULL, 13918c0984e5SSebastian Reichel bq25890_irq_handler_thread, 13928c0984e5SSebastian Reichel IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 13938c0984e5SSebastian Reichel BQ25890_IRQ_PIN, bq); 13948c0984e5SSebastian Reichel if (ret) 1395d01363daSHans de Goede goto err_unregister_usb_notifier; 13968c0984e5SSebastian Reichel 13978c0984e5SSebastian Reichel return 0; 13988c0984e5SSebastian Reichel 1399d01363daSHans de Goede err_unregister_usb_notifier: 14008c0984e5SSebastian Reichel if (!IS_ERR_OR_NULL(bq->usb_phy)) 14018c0984e5SSebastian Reichel usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); 14028c0984e5SSebastian Reichel 14038c0984e5SSebastian Reichel return ret; 14048c0984e5SSebastian Reichel } 14058c0984e5SSebastian Reichel 1406ed5c2f5fSUwe Kleine-König static void bq25890_remove(struct i2c_client *client) 14078c0984e5SSebastian Reichel { 14088c0984e5SSebastian Reichel struct bq25890_device *bq = i2c_get_clientdata(client); 14098c0984e5SSebastian Reichel 14108c0984e5SSebastian Reichel if (!IS_ERR_OR_NULL(bq->usb_phy)) 14118c0984e5SSebastian Reichel usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); 14128c0984e5SSebastian Reichel 14137e3b8e35SHans de Goede if (!bq->skip_reset) { 14148c0984e5SSebastian Reichel /* reset all registers to default values */ 14158c0984e5SSebastian Reichel bq25890_chip_reset(bq); 14167e3b8e35SHans de Goede } 14178c0984e5SSebastian Reichel } 14188c0984e5SSebastian Reichel 141979d35365SHans de Goede static void bq25890_shutdown(struct i2c_client *client) 142079d35365SHans de Goede { 142179d35365SHans de Goede struct bq25890_device *bq = i2c_get_clientdata(client); 142279d35365SHans de Goede 142379d35365SHans de Goede /* 142479d35365SHans de Goede * TODO this if + return should probably be removed, but that would 142579d35365SHans de Goede * introduce a function change for boards using the usb-phy framework. 142679d35365SHans de Goede * This needs to be tested on such a board before making this change. 142779d35365SHans de Goede */ 142879d35365SHans de Goede if (!IS_ERR_OR_NULL(bq->usb_phy)) 142979d35365SHans de Goede return; 143079d35365SHans de Goede 143179d35365SHans de Goede /* 143279d35365SHans de Goede * Turn off the 5v Boost regulator which outputs Vbus to the device's 143379d35365SHans de Goede * Micro-USB or Type-C USB port. Leaving this on drains power and 143479d35365SHans de Goede * this avoids the PMIC on some device-models seeing this as Vbus 143579d35365SHans de Goede * getting inserted after shutdown, causing the device to immediately 143679d35365SHans de Goede * power-up again. 143779d35365SHans de Goede */ 143879d35365SHans de Goede bq25890_set_otg_cfg(bq, 0); 143979d35365SHans de Goede } 144079d35365SHans de Goede 14418c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP 14428c0984e5SSebastian Reichel static int bq25890_suspend(struct device *dev) 14438c0984e5SSebastian Reichel { 14448c0984e5SSebastian Reichel struct bq25890_device *bq = dev_get_drvdata(dev); 14458c0984e5SSebastian Reichel 14468c0984e5SSebastian Reichel /* 14478c0984e5SSebastian Reichel * If charger is removed, while in suspend, make sure ADC is diabled 14488c0984e5SSebastian Reichel * since it consumes slightly more power. 14498c0984e5SSebastian Reichel */ 145021d90edaSMichał Mirosław return bq25890_field_write(bq, F_CONV_RATE, 0); 14518c0984e5SSebastian Reichel } 14528c0984e5SSebastian Reichel 14538c0984e5SSebastian Reichel static int bq25890_resume(struct device *dev) 14548c0984e5SSebastian Reichel { 14558c0984e5SSebastian Reichel int ret; 14568c0984e5SSebastian Reichel struct bq25890_device *bq = dev_get_drvdata(dev); 14578c0984e5SSebastian Reichel 145872d9cd9cSMichał Mirosław mutex_lock(&bq->lock); 145972d9cd9cSMichał Mirosław 146072d9cd9cSMichał Mirosław ret = bq25890_get_chip_state(bq, &bq->state); 14618c0984e5SSebastian Reichel if (ret < 0) 1462cf5701bfSDan Carpenter goto unlock; 14638c0984e5SSebastian Reichel 14648c0984e5SSebastian Reichel /* Re-enable ADC only if charger is plugged in. */ 146572d9cd9cSMichał Mirosław if (bq->state.online) { 146621d90edaSMichał Mirosław ret = bq25890_field_write(bq, F_CONV_RATE, 1); 14678c0984e5SSebastian Reichel if (ret < 0) 1468cf5701bfSDan Carpenter goto unlock; 14698c0984e5SSebastian Reichel } 14708c0984e5SSebastian Reichel 14718c0984e5SSebastian Reichel /* signal userspace, maybe state changed while suspended */ 14728c0984e5SSebastian Reichel power_supply_changed(bq->charger); 14738c0984e5SSebastian Reichel 1474cf5701bfSDan Carpenter unlock: 147572d9cd9cSMichał Mirosław mutex_unlock(&bq->lock); 147672d9cd9cSMichał Mirosław 1477cf5701bfSDan Carpenter return ret; 14788c0984e5SSebastian Reichel } 14798c0984e5SSebastian Reichel #endif 14808c0984e5SSebastian Reichel 14818c0984e5SSebastian Reichel static const struct dev_pm_ops bq25890_pm = { 14828c0984e5SSebastian Reichel SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume) 14838c0984e5SSebastian Reichel }; 14848c0984e5SSebastian Reichel 14858c0984e5SSebastian Reichel static const struct i2c_device_id bq25890_i2c_ids[] = { 14868c0984e5SSebastian Reichel { "bq25890", 0 }, 148746aa27e7SYauhen Kharuzhy { "bq25892", 0 }, 148846aa27e7SYauhen Kharuzhy { "bq25895", 0 }, 148946aa27e7SYauhen Kharuzhy { "bq25896", 0 }, 14908c0984e5SSebastian Reichel {}, 14918c0984e5SSebastian Reichel }; 14928c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids); 14938c0984e5SSebastian Reichel 14948c0984e5SSebastian Reichel static const struct of_device_id bq25890_of_match[] = { 14958c0984e5SSebastian Reichel { .compatible = "ti,bq25890", }, 149646aa27e7SYauhen Kharuzhy { .compatible = "ti,bq25892", }, 149746aa27e7SYauhen Kharuzhy { .compatible = "ti,bq25895", }, 149846aa27e7SYauhen Kharuzhy { .compatible = "ti,bq25896", }, 14998c0984e5SSebastian Reichel { }, 15008c0984e5SSebastian Reichel }; 15018c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, bq25890_of_match); 15028c0984e5SSebastian Reichel 150302067dc9SKrzysztof Kozlowski #ifdef CONFIG_ACPI 15048c0984e5SSebastian Reichel static const struct acpi_device_id bq25890_acpi_match[] = { 15058c0984e5SSebastian Reichel {"BQ258900", 0}, 15068c0984e5SSebastian Reichel {}, 15078c0984e5SSebastian Reichel }; 15088c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match); 150902067dc9SKrzysztof Kozlowski #endif 15108c0984e5SSebastian Reichel 15118c0984e5SSebastian Reichel static struct i2c_driver bq25890_driver = { 15128c0984e5SSebastian Reichel .driver = { 15138c0984e5SSebastian Reichel .name = "bq25890-charger", 15148c0984e5SSebastian Reichel .of_match_table = of_match_ptr(bq25890_of_match), 15158c0984e5SSebastian Reichel .acpi_match_table = ACPI_PTR(bq25890_acpi_match), 15168c0984e5SSebastian Reichel .pm = &bq25890_pm, 15178c0984e5SSebastian Reichel }, 15188c0984e5SSebastian Reichel .probe = bq25890_probe, 15198c0984e5SSebastian Reichel .remove = bq25890_remove, 152079d35365SHans de Goede .shutdown = bq25890_shutdown, 15218c0984e5SSebastian Reichel .id_table = bq25890_i2c_ids, 15228c0984e5SSebastian Reichel }; 15238c0984e5SSebastian Reichel module_i2c_driver(bq25890_driver); 15248c0984e5SSebastian Reichel 15258c0984e5SSebastian Reichel MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>"); 15268c0984e5SSebastian Reichel MODULE_DESCRIPTION("bq25890 charger driver"); 15278c0984e5SSebastian Reichel MODULE_LICENSE("GPL"); 1528