1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 28c0984e5SSebastian Reichel /* 38c0984e5SSebastian Reichel * TI BQ25890 charger driver 48c0984e5SSebastian Reichel * 58c0984e5SSebastian Reichel * Copyright (C) 2015 Intel Corporation 68c0984e5SSebastian Reichel */ 78c0984e5SSebastian Reichel 88c0984e5SSebastian Reichel #include <linux/module.h> 98c0984e5SSebastian Reichel #include <linux/i2c.h> 108c0984e5SSebastian Reichel #include <linux/power_supply.h> 1179d35365SHans de Goede #include <linux/power/bq25890_charger.h> 128c0984e5SSebastian Reichel #include <linux/regmap.h> 1379d35365SHans de Goede #include <linux/regulator/driver.h> 148c0984e5SSebastian Reichel #include <linux/types.h> 158c0984e5SSebastian Reichel #include <linux/gpio/consumer.h> 168c0984e5SSebastian Reichel #include <linux/interrupt.h> 178c0984e5SSebastian Reichel #include <linux/delay.h> 188c0984e5SSebastian Reichel #include <linux/usb/phy.h> 198c0984e5SSebastian Reichel 208c0984e5SSebastian Reichel #include <linux/acpi.h> 218c0984e5SSebastian Reichel #include <linux/of.h> 228c0984e5SSebastian Reichel 238c0984e5SSebastian Reichel #define BQ25890_MANUFACTURER "Texas Instruments" 248c0984e5SSebastian Reichel #define BQ25890_IRQ_PIN "bq25890_irq" 258c0984e5SSebastian Reichel 268c0984e5SSebastian Reichel #define BQ25890_ID 3 275c35ba9bSAngus Ainslie (Purism) #define BQ25895_ID 7 282e1a2ddeSAngus Ainslie (Purism) #define BQ25896_ID 0 298c0984e5SSebastian Reichel 3048f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_START_DELAY (5 * HZ) 3148f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_MAX_TRIES 6 3248f45b09SYauhen Kharuzhy #define PUMP_EXPRESS_VBUS_MARGIN_uV 1000000 3348f45b09SYauhen Kharuzhy 34d20267c9SYauhen Kharuzhy enum bq25890_chip_version { 35d20267c9SYauhen Kharuzhy BQ25890, 36d20267c9SYauhen Kharuzhy BQ25892, 37d20267c9SYauhen Kharuzhy BQ25895, 38d20267c9SYauhen Kharuzhy BQ25896, 39d20267c9SYauhen Kharuzhy }; 40d20267c9SYauhen Kharuzhy 415956fca7SMichał Mirosław static const char *const bq25890_chip_name[] = { 425956fca7SMichał Mirosław "BQ25890", 435956fca7SMichał Mirosław "BQ25892", 445956fca7SMichał Mirosław "BQ25895", 455956fca7SMichał Mirosław "BQ25896", 465956fca7SMichał Mirosław }; 475956fca7SMichał Mirosław 488c0984e5SSebastian Reichel enum bq25890_fields { 49766873c1SYauhen Kharuzhy F_EN_HIZ, F_EN_ILIM, F_IINLIM, /* Reg00 */ 508c0984e5SSebastian Reichel F_BHOT, F_BCOLD, F_VINDPM_OFS, /* Reg01 */ 518c0984e5SSebastian Reichel F_CONV_START, F_CONV_RATE, F_BOOSTF, F_ICO_EN, 528c0984e5SSebastian Reichel F_HVDCP_EN, F_MAXC_EN, F_FORCE_DPM, F_AUTO_DPDM_EN, /* Reg02 */ 53d20267c9SYauhen Kharuzhy F_BAT_LOAD_EN, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_SYSVMIN, 54d20267c9SYauhen Kharuzhy F_MIN_VBAT_SEL, /* Reg03 */ 558c0984e5SSebastian Reichel F_PUMPX_EN, F_ICHG, /* Reg04 */ 568c0984e5SSebastian Reichel F_IPRECHG, F_ITERM, /* Reg05 */ 578c0984e5SSebastian Reichel F_VREG, F_BATLOWV, F_VRECHG, /* Reg06 */ 588c0984e5SSebastian Reichel F_TERM_EN, F_STAT_DIS, F_WD, F_TMR_EN, F_CHG_TMR, 598c0984e5SSebastian Reichel F_JEITA_ISET, /* Reg07 */ 608c0984e5SSebastian Reichel F_BATCMP, F_VCLAMP, F_TREG, /* Reg08 */ 618c0984e5SSebastian Reichel F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JEITA_VSET, 628c0984e5SSebastian Reichel F_BATFET_DLY, F_BATFET_RST_EN, F_PUMPX_UP, F_PUMPX_DN, /* Reg09 */ 63d20267c9SYauhen Kharuzhy F_BOOSTV, F_PFM_OTG_DIS, F_BOOSTI, /* Reg0A */ 64d20267c9SYauhen Kharuzhy F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_SDP_STAT, F_0B_RSVD, 65d20267c9SYauhen Kharuzhy F_VSYS_STAT, /* Reg0B */ 668c0984e5SSebastian Reichel F_WD_FAULT, F_BOOST_FAULT, F_CHG_FAULT, F_BAT_FAULT, 678c0984e5SSebastian Reichel F_NTC_FAULT, /* Reg0C */ 688c0984e5SSebastian Reichel F_FORCE_VINDPM, F_VINDPM, /* Reg0D */ 698c0984e5SSebastian Reichel F_THERM_STAT, F_BATV, /* Reg0E */ 708c0984e5SSebastian Reichel F_SYSV, /* Reg0F */ 718c0984e5SSebastian Reichel F_TSPCT, /* Reg10 */ 728c0984e5SSebastian Reichel F_VBUS_GD, F_VBUSV, /* Reg11 */ 738c0984e5SSebastian Reichel F_ICHGR, /* Reg12 */ 748c0984e5SSebastian Reichel F_VDPM_STAT, F_IDPM_STAT, F_IDPM_LIM, /* Reg13 */ 758c0984e5SSebastian Reichel F_REG_RST, F_ICO_OPTIMIZED, F_PN, F_TS_PROFILE, F_DEV_REV, /* Reg14 */ 768c0984e5SSebastian Reichel 778c0984e5SSebastian Reichel F_MAX_FIELDS 788c0984e5SSebastian Reichel }; 798c0984e5SSebastian Reichel 808c0984e5SSebastian Reichel /* initial field values, converted to register values */ 818c0984e5SSebastian Reichel struct bq25890_init_data { 828c0984e5SSebastian Reichel u8 ichg; /* charge current */ 838c0984e5SSebastian Reichel u8 vreg; /* regulation voltage */ 848c0984e5SSebastian Reichel u8 iterm; /* termination current */ 858c0984e5SSebastian Reichel u8 iprechg; /* precharge current */ 868c0984e5SSebastian Reichel u8 sysvmin; /* minimum system voltage limit */ 878c0984e5SSebastian Reichel u8 boostv; /* boost regulation voltage */ 888c0984e5SSebastian Reichel u8 boosti; /* boost current limit */ 898c0984e5SSebastian Reichel u8 boostf; /* boost frequency */ 908c0984e5SSebastian Reichel u8 ilim_en; /* enable ILIM pin */ 918c0984e5SSebastian Reichel u8 treg; /* thermal regulation threshold */ 9272408329SMichał Mirosław u8 rbatcomp; /* IBAT sense resistor value */ 9372408329SMichał Mirosław u8 vclamp; /* IBAT compensation voltage limit */ 948c0984e5SSebastian Reichel }; 958c0984e5SSebastian Reichel 968c0984e5SSebastian Reichel struct bq25890_state { 978c0984e5SSebastian Reichel u8 online; 98c688e0c4SMarek Vasut u8 hiz; 998c0984e5SSebastian Reichel u8 chrg_status; 1008c0984e5SSebastian Reichel u8 chrg_fault; 1018c0984e5SSebastian Reichel u8 vsys_status; 1028c0984e5SSebastian Reichel u8 boost_fault; 1038c0984e5SSebastian Reichel u8 bat_fault; 104c562a43aSYauhen Kharuzhy u8 ntc_fault; 1058c0984e5SSebastian Reichel }; 1068c0984e5SSebastian Reichel 1078c0984e5SSebastian Reichel struct bq25890_device { 1088c0984e5SSebastian Reichel struct i2c_client *client; 1098c0984e5SSebastian Reichel struct device *dev; 1108c0984e5SSebastian Reichel struct power_supply *charger; 1118c0984e5SSebastian Reichel 1128c0984e5SSebastian Reichel struct usb_phy *usb_phy; 1138c0984e5SSebastian Reichel struct notifier_block usb_nb; 1148c0984e5SSebastian Reichel struct work_struct usb_work; 11548f45b09SYauhen Kharuzhy struct delayed_work pump_express_work; 1168c0984e5SSebastian Reichel unsigned long usb_event; 1178c0984e5SSebastian Reichel 1188c0984e5SSebastian Reichel struct regmap *rmap; 1198c0984e5SSebastian Reichel struct regmap_field *rmap_fields[F_MAX_FIELDS]; 1208c0984e5SSebastian Reichel 1217e3b8e35SHans de Goede bool skip_reset; 12240428bd4SHans de Goede bool read_back_init_data; 123c688e0c4SMarek Vasut bool force_hiz; 12448f45b09SYauhen Kharuzhy u32 pump_express_vbus_max; 125d20267c9SYauhen Kharuzhy enum bq25890_chip_version chip_version; 1268c0984e5SSebastian Reichel struct bq25890_init_data init_data; 1278c0984e5SSebastian Reichel struct bq25890_state state; 1288c0984e5SSebastian Reichel 1298c0984e5SSebastian Reichel struct mutex lock; /* protect state data */ 1308c0984e5SSebastian Reichel }; 1318c0984e5SSebastian Reichel 1328c0984e5SSebastian Reichel static const struct regmap_range bq25890_readonly_reg_ranges[] = { 1338c0984e5SSebastian Reichel regmap_reg_range(0x0b, 0x0c), 1348c0984e5SSebastian Reichel regmap_reg_range(0x0e, 0x13), 1358c0984e5SSebastian Reichel }; 1368c0984e5SSebastian Reichel 1378c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_writeable_regs = { 1388c0984e5SSebastian Reichel .no_ranges = bq25890_readonly_reg_ranges, 1398c0984e5SSebastian Reichel .n_no_ranges = ARRAY_SIZE(bq25890_readonly_reg_ranges), 1408c0984e5SSebastian Reichel }; 1418c0984e5SSebastian Reichel 1428c0984e5SSebastian Reichel static const struct regmap_range bq25890_volatile_reg_ranges[] = { 1438c0984e5SSebastian Reichel regmap_reg_range(0x00, 0x00), 14421d90edaSMichał Mirosław regmap_reg_range(0x02, 0x02), 1458c0984e5SSebastian Reichel regmap_reg_range(0x09, 0x09), 146d20267c9SYauhen Kharuzhy regmap_reg_range(0x0b, 0x14), 1478c0984e5SSebastian Reichel }; 1488c0984e5SSebastian Reichel 1498c0984e5SSebastian Reichel static const struct regmap_access_table bq25890_volatile_regs = { 1508c0984e5SSebastian Reichel .yes_ranges = bq25890_volatile_reg_ranges, 1518c0984e5SSebastian Reichel .n_yes_ranges = ARRAY_SIZE(bq25890_volatile_reg_ranges), 1528c0984e5SSebastian Reichel }; 1538c0984e5SSebastian Reichel 1548c0984e5SSebastian Reichel static const struct regmap_config bq25890_regmap_config = { 1558c0984e5SSebastian Reichel .reg_bits = 8, 1568c0984e5SSebastian Reichel .val_bits = 8, 1578c0984e5SSebastian Reichel 1588c0984e5SSebastian Reichel .max_register = 0x14, 1598c0984e5SSebastian Reichel .cache_type = REGCACHE_RBTREE, 1608c0984e5SSebastian Reichel 1618c0984e5SSebastian Reichel .wr_table = &bq25890_writeable_regs, 1628c0984e5SSebastian Reichel .volatile_table = &bq25890_volatile_regs, 1638c0984e5SSebastian Reichel }; 1648c0984e5SSebastian Reichel 1658c0984e5SSebastian Reichel static const struct reg_field bq25890_reg_fields[] = { 1668c0984e5SSebastian Reichel /* REG00 */ 1678c0984e5SSebastian Reichel [F_EN_HIZ] = REG_FIELD(0x00, 7, 7), 1688c0984e5SSebastian Reichel [F_EN_ILIM] = REG_FIELD(0x00, 6, 6), 169766873c1SYauhen Kharuzhy [F_IINLIM] = REG_FIELD(0x00, 0, 5), 1708c0984e5SSebastian Reichel /* REG01 */ 1718c0984e5SSebastian Reichel [F_BHOT] = REG_FIELD(0x01, 6, 7), 1728c0984e5SSebastian Reichel [F_BCOLD] = REG_FIELD(0x01, 5, 5), 1738c0984e5SSebastian Reichel [F_VINDPM_OFS] = REG_FIELD(0x01, 0, 4), 1748c0984e5SSebastian Reichel /* REG02 */ 1758c0984e5SSebastian Reichel [F_CONV_START] = REG_FIELD(0x02, 7, 7), 1768c0984e5SSebastian Reichel [F_CONV_RATE] = REG_FIELD(0x02, 6, 6), 1778c0984e5SSebastian Reichel [F_BOOSTF] = REG_FIELD(0x02, 5, 5), 1788c0984e5SSebastian Reichel [F_ICO_EN] = REG_FIELD(0x02, 4, 4), 1792e1a2ddeSAngus Ainslie (Purism) [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), // reserved on BQ25896 1802e1a2ddeSAngus Ainslie (Purism) [F_MAXC_EN] = REG_FIELD(0x02, 2, 2), // reserved on BQ25896 1818c0984e5SSebastian Reichel [F_FORCE_DPM] = REG_FIELD(0x02, 1, 1), 1828c0984e5SSebastian Reichel [F_AUTO_DPDM_EN] = REG_FIELD(0x02, 0, 0), 1838c0984e5SSebastian Reichel /* REG03 */ 1848c0984e5SSebastian Reichel [F_BAT_LOAD_EN] = REG_FIELD(0x03, 7, 7), 1858c0984e5SSebastian Reichel [F_WD_RST] = REG_FIELD(0x03, 6, 6), 1868c0984e5SSebastian Reichel [F_OTG_CFG] = REG_FIELD(0x03, 5, 5), 1878c0984e5SSebastian Reichel [F_CHG_CFG] = REG_FIELD(0x03, 4, 4), 1888c0984e5SSebastian Reichel [F_SYSVMIN] = REG_FIELD(0x03, 1, 3), 189d20267c9SYauhen Kharuzhy [F_MIN_VBAT_SEL] = REG_FIELD(0x03, 0, 0), // BQ25896 only 1908c0984e5SSebastian Reichel /* REG04 */ 1918c0984e5SSebastian Reichel [F_PUMPX_EN] = REG_FIELD(0x04, 7, 7), 1928c0984e5SSebastian Reichel [F_ICHG] = REG_FIELD(0x04, 0, 6), 1938c0984e5SSebastian Reichel /* REG05 */ 1948c0984e5SSebastian Reichel [F_IPRECHG] = REG_FIELD(0x05, 4, 7), 1958c0984e5SSebastian Reichel [F_ITERM] = REG_FIELD(0x05, 0, 3), 1968c0984e5SSebastian Reichel /* REG06 */ 1978c0984e5SSebastian Reichel [F_VREG] = REG_FIELD(0x06, 2, 7), 1988c0984e5SSebastian Reichel [F_BATLOWV] = REG_FIELD(0x06, 1, 1), 1998c0984e5SSebastian Reichel [F_VRECHG] = REG_FIELD(0x06, 0, 0), 2008c0984e5SSebastian Reichel /* REG07 */ 2018c0984e5SSebastian Reichel [F_TERM_EN] = REG_FIELD(0x07, 7, 7), 2028c0984e5SSebastian Reichel [F_STAT_DIS] = REG_FIELD(0x07, 6, 6), 2038c0984e5SSebastian Reichel [F_WD] = REG_FIELD(0x07, 4, 5), 2048c0984e5SSebastian Reichel [F_TMR_EN] = REG_FIELD(0x07, 3, 3), 2058c0984e5SSebastian Reichel [F_CHG_TMR] = REG_FIELD(0x07, 1, 2), 2065c35ba9bSAngus Ainslie (Purism) [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), // reserved on BQ25895 2078c0984e5SSebastian Reichel /* REG08 */ 20895809139SMichał Mirosław [F_BATCMP] = REG_FIELD(0x08, 5, 7), 2098c0984e5SSebastian Reichel [F_VCLAMP] = REG_FIELD(0x08, 2, 4), 2108c0984e5SSebastian Reichel [F_TREG] = REG_FIELD(0x08, 0, 1), 2118c0984e5SSebastian Reichel /* REG09 */ 2128c0984e5SSebastian Reichel [F_FORCE_ICO] = REG_FIELD(0x09, 7, 7), 2138c0984e5SSebastian Reichel [F_TMR2X_EN] = REG_FIELD(0x09, 6, 6), 2148c0984e5SSebastian Reichel [F_BATFET_DIS] = REG_FIELD(0x09, 5, 5), 2155c35ba9bSAngus Ainslie (Purism) [F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), // reserved on BQ25895 2168c0984e5SSebastian Reichel [F_BATFET_DLY] = REG_FIELD(0x09, 3, 3), 2178c0984e5SSebastian Reichel [F_BATFET_RST_EN] = REG_FIELD(0x09, 2, 2), 2188c0984e5SSebastian Reichel [F_PUMPX_UP] = REG_FIELD(0x09, 1, 1), 2198c0984e5SSebastian Reichel [F_PUMPX_DN] = REG_FIELD(0x09, 0, 0), 2208c0984e5SSebastian Reichel /* REG0A */ 2218c0984e5SSebastian Reichel [F_BOOSTV] = REG_FIELD(0x0A, 4, 7), 2225c35ba9bSAngus Ainslie (Purism) [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), // reserved on BQ25895 223d20267c9SYauhen Kharuzhy [F_PFM_OTG_DIS] = REG_FIELD(0x0A, 3, 3), // BQ25896 only 2248c0984e5SSebastian Reichel /* REG0B */ 2258c0984e5SSebastian Reichel [F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7), 2268c0984e5SSebastian Reichel [F_CHG_STAT] = REG_FIELD(0x0B, 3, 4), 2278c0984e5SSebastian Reichel [F_PG_STAT] = REG_FIELD(0x0B, 2, 2), 2282e1a2ddeSAngus Ainslie (Purism) [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), // reserved on BQ25896 2298c0984e5SSebastian Reichel [F_VSYS_STAT] = REG_FIELD(0x0B, 0, 0), 2308c0984e5SSebastian Reichel /* REG0C */ 2318c0984e5SSebastian Reichel [F_WD_FAULT] = REG_FIELD(0x0C, 7, 7), 2328c0984e5SSebastian Reichel [F_BOOST_FAULT] = REG_FIELD(0x0C, 6, 6), 2338c0984e5SSebastian Reichel [F_CHG_FAULT] = REG_FIELD(0x0C, 4, 5), 2348c0984e5SSebastian Reichel [F_BAT_FAULT] = REG_FIELD(0x0C, 3, 3), 2358c0984e5SSebastian Reichel [F_NTC_FAULT] = REG_FIELD(0x0C, 0, 2), 2368c0984e5SSebastian Reichel /* REG0D */ 2378c0984e5SSebastian Reichel [F_FORCE_VINDPM] = REG_FIELD(0x0D, 7, 7), 2388c0984e5SSebastian Reichel [F_VINDPM] = REG_FIELD(0x0D, 0, 6), 2398c0984e5SSebastian Reichel /* REG0E */ 2408c0984e5SSebastian Reichel [F_THERM_STAT] = REG_FIELD(0x0E, 7, 7), 2418c0984e5SSebastian Reichel [F_BATV] = REG_FIELD(0x0E, 0, 6), 2428c0984e5SSebastian Reichel /* REG0F */ 2438c0984e5SSebastian Reichel [F_SYSV] = REG_FIELD(0x0F, 0, 6), 2448c0984e5SSebastian Reichel /* REG10 */ 2458c0984e5SSebastian Reichel [F_TSPCT] = REG_FIELD(0x10, 0, 6), 2468c0984e5SSebastian Reichel /* REG11 */ 2478c0984e5SSebastian Reichel [F_VBUS_GD] = REG_FIELD(0x11, 7, 7), 2488c0984e5SSebastian Reichel [F_VBUSV] = REG_FIELD(0x11, 0, 6), 2498c0984e5SSebastian Reichel /* REG12 */ 2508c0984e5SSebastian Reichel [F_ICHGR] = REG_FIELD(0x12, 0, 6), 2518c0984e5SSebastian Reichel /* REG13 */ 2528c0984e5SSebastian Reichel [F_VDPM_STAT] = REG_FIELD(0x13, 7, 7), 2538c0984e5SSebastian Reichel [F_IDPM_STAT] = REG_FIELD(0x13, 6, 6), 2548c0984e5SSebastian Reichel [F_IDPM_LIM] = REG_FIELD(0x13, 0, 5), 2558c0984e5SSebastian Reichel /* REG14 */ 2568c0984e5SSebastian Reichel [F_REG_RST] = REG_FIELD(0x14, 7, 7), 2578c0984e5SSebastian Reichel [F_ICO_OPTIMIZED] = REG_FIELD(0x14, 6, 6), 2588c0984e5SSebastian Reichel [F_PN] = REG_FIELD(0x14, 3, 5), 2598c0984e5SSebastian Reichel [F_TS_PROFILE] = REG_FIELD(0x14, 2, 2), 2608c0984e5SSebastian Reichel [F_DEV_REV] = REG_FIELD(0x14, 0, 1) 2618c0984e5SSebastian Reichel }; 2628c0984e5SSebastian Reichel 2638c0984e5SSebastian Reichel /* 2648c0984e5SSebastian Reichel * Most of the val -> idx conversions can be computed, given the minimum, 2658c0984e5SSebastian Reichel * maximum and the step between values. For the rest of conversions, we use 2668c0984e5SSebastian Reichel * lookup tables. 2678c0984e5SSebastian Reichel */ 2688c0984e5SSebastian Reichel enum bq25890_table_ids { 2698c0984e5SSebastian Reichel /* range tables */ 2708c0984e5SSebastian Reichel TBL_ICHG, 2718c0984e5SSebastian Reichel TBL_ITERM, 272766873c1SYauhen Kharuzhy TBL_IINLIM, 2738c0984e5SSebastian Reichel TBL_VREG, 2748c0984e5SSebastian Reichel TBL_BOOSTV, 2758c0984e5SSebastian Reichel TBL_SYSVMIN, 27648f45b09SYauhen Kharuzhy TBL_VBUSV, 27772408329SMichał Mirosław TBL_VBATCOMP, 27872408329SMichał Mirosław TBL_RBATCOMP, 2798c0984e5SSebastian Reichel 2808c0984e5SSebastian Reichel /* lookup tables */ 2818c0984e5SSebastian Reichel TBL_TREG, 2828c0984e5SSebastian Reichel TBL_BOOSTI, 2839652c024SAngus Ainslie TBL_TSPCT, 2848c0984e5SSebastian Reichel }; 2858c0984e5SSebastian Reichel 2868c0984e5SSebastian Reichel /* Thermal Regulation Threshold lookup table, in degrees Celsius */ 2878c0984e5SSebastian Reichel static const u32 bq25890_treg_tbl[] = { 60, 80, 100, 120 }; 2888c0984e5SSebastian Reichel 2898c0984e5SSebastian Reichel #define BQ25890_TREG_TBL_SIZE ARRAY_SIZE(bq25890_treg_tbl) 2908c0984e5SSebastian Reichel 2918c0984e5SSebastian Reichel /* Boost mode current limit lookup table, in uA */ 2928c0984e5SSebastian Reichel static const u32 bq25890_boosti_tbl[] = { 2938c0984e5SSebastian Reichel 500000, 700000, 1100000, 1300000, 1600000, 1800000, 2100000, 2400000 2948c0984e5SSebastian Reichel }; 2958c0984e5SSebastian Reichel 2968c0984e5SSebastian Reichel #define BQ25890_BOOSTI_TBL_SIZE ARRAY_SIZE(bq25890_boosti_tbl) 2978c0984e5SSebastian Reichel 2989652c024SAngus Ainslie /* NTC 10K temperature lookup table in tenths of a degree */ 2999652c024SAngus Ainslie static const u32 bq25890_tspct_tbl[] = { 3009652c024SAngus Ainslie 850, 840, 830, 820, 810, 800, 790, 780, 3019652c024SAngus Ainslie 770, 760, 750, 740, 730, 720, 710, 700, 3029652c024SAngus Ainslie 690, 685, 680, 675, 670, 660, 650, 645, 3039652c024SAngus Ainslie 640, 630, 620, 615, 610, 600, 590, 585, 3049652c024SAngus Ainslie 580, 570, 565, 560, 550, 540, 535, 530, 3059652c024SAngus Ainslie 520, 515, 510, 500, 495, 490, 480, 475, 3069652c024SAngus Ainslie 470, 460, 455, 450, 440, 435, 430, 425, 3079652c024SAngus Ainslie 420, 410, 405, 400, 390, 385, 380, 370, 3089652c024SAngus Ainslie 365, 360, 355, 350, 340, 335, 330, 320, 3099652c024SAngus Ainslie 310, 305, 300, 290, 285, 280, 275, 270, 3109652c024SAngus Ainslie 260, 250, 245, 240, 230, 225, 220, 210, 3119652c024SAngus Ainslie 205, 200, 190, 180, 175, 170, 160, 150, 3129652c024SAngus Ainslie 145, 140, 130, 120, 115, 110, 100, 90, 3139652c024SAngus Ainslie 80, 70, 60, 50, 40, 30, 20, 10, 3149652c024SAngus Ainslie 0, -10, -20, -30, -40, -60, -70, -80, 3159652c024SAngus Ainslie -90, -10, -120, -140, -150, -170, -190, -210, 3169652c024SAngus Ainslie }; 3179652c024SAngus Ainslie 3189652c024SAngus Ainslie #define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl) 3199652c024SAngus Ainslie 3208c0984e5SSebastian Reichel struct bq25890_range { 3218c0984e5SSebastian Reichel u32 min; 3228c0984e5SSebastian Reichel u32 max; 3238c0984e5SSebastian Reichel u32 step; 3248c0984e5SSebastian Reichel }; 3258c0984e5SSebastian Reichel 3268c0984e5SSebastian Reichel struct bq25890_lookup { 3278c0984e5SSebastian Reichel const u32 *tbl; 3288c0984e5SSebastian Reichel u32 size; 3298c0984e5SSebastian Reichel }; 3308c0984e5SSebastian Reichel 3318c0984e5SSebastian Reichel static const union { 3328c0984e5SSebastian Reichel struct bq25890_range rt; 3338c0984e5SSebastian Reichel struct bq25890_lookup lt; 3348c0984e5SSebastian Reichel } bq25890_tables[] = { 3358c0984e5SSebastian Reichel /* range tables */ 336d20267c9SYauhen Kharuzhy /* TODO: BQ25896 has max ICHG 3008 mA */ 3378c0984e5SSebastian Reichel [TBL_ICHG] = { .rt = {0, 5056000, 64000} }, /* uA */ 3388c0984e5SSebastian Reichel [TBL_ITERM] = { .rt = {64000, 1024000, 64000} }, /* uA */ 339766873c1SYauhen Kharuzhy [TBL_IINLIM] = { .rt = {100000, 3250000, 50000} }, /* uA */ 3408c0984e5SSebastian Reichel [TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */ 3418c0984e5SSebastian Reichel [TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */ 3428c0984e5SSebastian Reichel [TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */ 34348f45b09SYauhen Kharuzhy [TBL_VBUSV] = { .rt = {2600000, 15300000, 100000} }, /* uV */ 34472408329SMichał Mirosław [TBL_VBATCOMP] = { .rt = {0, 224000, 32000} }, /* uV */ 34572408329SMichał Mirosław [TBL_RBATCOMP] = { .rt = {0, 140000, 20000} }, /* uOhm */ 3468c0984e5SSebastian Reichel 3478c0984e5SSebastian Reichel /* lookup tables */ 3488c0984e5SSebastian Reichel [TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} }, 3499652c024SAngus Ainslie [TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} }, 3509652c024SAngus Ainslie [TBL_TSPCT] = { .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} } 3518c0984e5SSebastian Reichel }; 3528c0984e5SSebastian Reichel 3538c0984e5SSebastian Reichel static int bq25890_field_read(struct bq25890_device *bq, 3548c0984e5SSebastian Reichel enum bq25890_fields field_id) 3558c0984e5SSebastian Reichel { 3568c0984e5SSebastian Reichel int ret; 3578c0984e5SSebastian Reichel int val; 3588c0984e5SSebastian Reichel 3598c0984e5SSebastian Reichel ret = regmap_field_read(bq->rmap_fields[field_id], &val); 3608c0984e5SSebastian Reichel if (ret < 0) 3618c0984e5SSebastian Reichel return ret; 3628c0984e5SSebastian Reichel 3638c0984e5SSebastian Reichel return val; 3648c0984e5SSebastian Reichel } 3658c0984e5SSebastian Reichel 3668c0984e5SSebastian Reichel static int bq25890_field_write(struct bq25890_device *bq, 3678c0984e5SSebastian Reichel enum bq25890_fields field_id, u8 val) 3688c0984e5SSebastian Reichel { 3698c0984e5SSebastian Reichel return regmap_field_write(bq->rmap_fields[field_id], val); 3708c0984e5SSebastian Reichel } 3718c0984e5SSebastian Reichel 3728c0984e5SSebastian Reichel static u8 bq25890_find_idx(u32 value, enum bq25890_table_ids id) 3738c0984e5SSebastian Reichel { 3748c0984e5SSebastian Reichel u8 idx; 3758c0984e5SSebastian Reichel 3768c0984e5SSebastian Reichel if (id >= TBL_TREG) { 3778c0984e5SSebastian Reichel const u32 *tbl = bq25890_tables[id].lt.tbl; 3788c0984e5SSebastian Reichel u32 tbl_size = bq25890_tables[id].lt.size; 3798c0984e5SSebastian Reichel 3808c0984e5SSebastian Reichel for (idx = 1; idx < tbl_size && tbl[idx] <= value; idx++) 3818c0984e5SSebastian Reichel ; 3828c0984e5SSebastian Reichel } else { 3838c0984e5SSebastian Reichel const struct bq25890_range *rtbl = &bq25890_tables[id].rt; 3848c0984e5SSebastian Reichel u8 rtbl_size; 3858c0984e5SSebastian Reichel 3868c0984e5SSebastian Reichel rtbl_size = (rtbl->max - rtbl->min) / rtbl->step + 1; 3878c0984e5SSebastian Reichel 3888c0984e5SSebastian Reichel for (idx = 1; 3898c0984e5SSebastian Reichel idx < rtbl_size && (idx * rtbl->step + rtbl->min <= value); 3908c0984e5SSebastian Reichel idx++) 3918c0984e5SSebastian Reichel ; 3928c0984e5SSebastian Reichel } 3938c0984e5SSebastian Reichel 3948c0984e5SSebastian Reichel return idx - 1; 3958c0984e5SSebastian Reichel } 3968c0984e5SSebastian Reichel 3978c0984e5SSebastian Reichel static u32 bq25890_find_val(u8 idx, enum bq25890_table_ids id) 3988c0984e5SSebastian Reichel { 3998c0984e5SSebastian Reichel const struct bq25890_range *rtbl; 4008c0984e5SSebastian Reichel 4018c0984e5SSebastian Reichel /* lookup table? */ 4028c0984e5SSebastian Reichel if (id >= TBL_TREG) 4038c0984e5SSebastian Reichel return bq25890_tables[id].lt.tbl[idx]; 4048c0984e5SSebastian Reichel 4058c0984e5SSebastian Reichel /* range table */ 4068c0984e5SSebastian Reichel rtbl = &bq25890_tables[id].rt; 4078c0984e5SSebastian Reichel 4088c0984e5SSebastian Reichel return (rtbl->min + idx * rtbl->step); 4098c0984e5SSebastian Reichel } 4108c0984e5SSebastian Reichel 4118c0984e5SSebastian Reichel enum bq25890_status { 4128c0984e5SSebastian Reichel STATUS_NOT_CHARGING, 4138c0984e5SSebastian Reichel STATUS_PRE_CHARGING, 4148c0984e5SSebastian Reichel STATUS_FAST_CHARGING, 4158c0984e5SSebastian Reichel STATUS_TERMINATION_DONE, 4168c0984e5SSebastian Reichel }; 4178c0984e5SSebastian Reichel 4188c0984e5SSebastian Reichel enum bq25890_chrg_fault { 4198c0984e5SSebastian Reichel CHRG_FAULT_NORMAL, 4208c0984e5SSebastian Reichel CHRG_FAULT_INPUT, 4218c0984e5SSebastian Reichel CHRG_FAULT_THERMAL_SHUTDOWN, 4228c0984e5SSebastian Reichel CHRG_FAULT_TIMER_EXPIRED, 4238c0984e5SSebastian Reichel }; 4248c0984e5SSebastian Reichel 425c562a43aSYauhen Kharuzhy enum bq25890_ntc_fault { 426c562a43aSYauhen Kharuzhy NTC_FAULT_NORMAL = 0, 427c562a43aSYauhen Kharuzhy NTC_FAULT_WARM = 2, 428c562a43aSYauhen Kharuzhy NTC_FAULT_COOL = 3, 429c562a43aSYauhen Kharuzhy NTC_FAULT_COLD = 5, 430c562a43aSYauhen Kharuzhy NTC_FAULT_HOT = 6, 431c562a43aSYauhen Kharuzhy }; 432c562a43aSYauhen Kharuzhy 43321d90edaSMichał Mirosław static bool bq25890_is_adc_property(enum power_supply_property psp) 43421d90edaSMichał Mirosław { 43521d90edaSMichał Mirosław switch (psp) { 43621d90edaSMichał Mirosław case POWER_SUPPLY_PROP_VOLTAGE_NOW: 43721d90edaSMichał Mirosław case POWER_SUPPLY_PROP_CURRENT_NOW: 4389652c024SAngus Ainslie case POWER_SUPPLY_PROP_TEMP: 43921d90edaSMichał Mirosław return true; 44021d90edaSMichał Mirosław 44121d90edaSMichał Mirosław default: 44221d90edaSMichał Mirosław return false; 44321d90edaSMichał Mirosław } 44421d90edaSMichał Mirosław } 44521d90edaSMichał Mirosław 4463b4df57bSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq); 4473b4df57bSMichał Mirosław 44848f45b09SYauhen Kharuzhy static int bq25890_get_vbus_voltage(struct bq25890_device *bq) 44948f45b09SYauhen Kharuzhy { 45048f45b09SYauhen Kharuzhy int ret; 45148f45b09SYauhen Kharuzhy 45248f45b09SYauhen Kharuzhy ret = bq25890_field_read(bq, F_VBUSV); 45348f45b09SYauhen Kharuzhy if (ret < 0) 45448f45b09SYauhen Kharuzhy return ret; 45548f45b09SYauhen Kharuzhy 45648f45b09SYauhen Kharuzhy return bq25890_find_val(ret, TBL_VBUSV); 45748f45b09SYauhen Kharuzhy } 45848f45b09SYauhen Kharuzhy 459d1b25092SMarek Vasut static void bq25890_update_state(struct bq25890_device *bq, 4608c0984e5SSebastian Reichel enum power_supply_property psp, 461d1b25092SMarek Vasut struct bq25890_state *state) 4628c0984e5SSebastian Reichel { 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); 469d1b25092SMarek Vasut *state = bq->state; 470d1b25092SMarek Vasut 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); 478d1b25092SMarek Vasut } 479d1b25092SMarek Vasut 480d1b25092SMarek Vasut static int bq25890_power_supply_get_property(struct power_supply *psy, 481d1b25092SMarek Vasut enum power_supply_property psp, 482d1b25092SMarek Vasut union power_supply_propval *val) 483d1b25092SMarek Vasut { 484d1b25092SMarek Vasut struct bq25890_device *bq = power_supply_get_drvdata(psy); 485d1b25092SMarek Vasut struct bq25890_state state; 486d1b25092SMarek Vasut int ret; 487d1b25092SMarek Vasut 488d1b25092SMarek Vasut bq25890_update_state(bq, psp, &state); 48921d90edaSMichał Mirosław 4908c0984e5SSebastian Reichel switch (psp) { 4918c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_STATUS: 492c688e0c4SMarek Vasut if (!state.online || state.hiz) 4938c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 4948c0984e5SSebastian Reichel else if (state.chrg_status == STATUS_NOT_CHARGING) 4958c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 4968c0984e5SSebastian Reichel else if (state.chrg_status == STATUS_PRE_CHARGING || 4978c0984e5SSebastian Reichel state.chrg_status == STATUS_FAST_CHARGING) 4988c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_CHARGING; 4998c0984e5SSebastian Reichel else if (state.chrg_status == STATUS_TERMINATION_DONE) 5008c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_FULL; 5018c0984e5SSebastian Reichel else 5028c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 5038c0984e5SSebastian Reichel 5048c0984e5SSebastian Reichel break; 5058c0984e5SSebastian Reichel 506b302a0aeSMichał Mirosław case POWER_SUPPLY_PROP_CHARGE_TYPE: 507c688e0c4SMarek Vasut if (!state.online || state.hiz || 508c688e0c4SMarek Vasut state.chrg_status == STATUS_NOT_CHARGING || 509b302a0aeSMichał Mirosław state.chrg_status == STATUS_TERMINATION_DONE) 510b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 511b302a0aeSMichał Mirosław else if (state.chrg_status == STATUS_PRE_CHARGING) 512b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 513b302a0aeSMichał Mirosław else if (state.chrg_status == STATUS_FAST_CHARGING) 514b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 515b302a0aeSMichał Mirosław else /* unreachable */ 516b302a0aeSMichał Mirosław val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 517b302a0aeSMichał Mirosław break; 518b302a0aeSMichał Mirosław 5198c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_MANUFACTURER: 5208c0984e5SSebastian Reichel val->strval = BQ25890_MANUFACTURER; 5218c0984e5SSebastian Reichel break; 5228c0984e5SSebastian Reichel 5232e1a2ddeSAngus Ainslie (Purism) case POWER_SUPPLY_PROP_MODEL_NAME: 5245956fca7SMichał Mirosław val->strval = bq25890_chip_name[bq->chip_version]; 5252e1a2ddeSAngus Ainslie (Purism) break; 5262e1a2ddeSAngus Ainslie (Purism) 5278c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 528c688e0c4SMarek Vasut val->intval = state.online && !state.hiz; 5298c0984e5SSebastian Reichel break; 5308c0984e5SSebastian Reichel 5318c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 5328c0984e5SSebastian Reichel if (!state.chrg_fault && !state.bat_fault && !state.boost_fault) 5338c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_GOOD; 5348c0984e5SSebastian Reichel else if (state.bat_fault) 5358c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 5368c0984e5SSebastian Reichel else if (state.chrg_fault == CHRG_FAULT_TIMER_EXPIRED) 5378c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 5388c0984e5SSebastian Reichel else if (state.chrg_fault == CHRG_FAULT_THERMAL_SHUTDOWN) 5398c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 5408c0984e5SSebastian Reichel else 5418c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 5428c0984e5SSebastian Reichel break; 5438c0984e5SSebastian Reichel 544c942656dSMichał Mirosław case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 545c942656dSMichał Mirosław val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM); 546c942656dSMichał Mirosław break; 547c942656dSMichał Mirosław 5488c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 5498c0984e5SSebastian Reichel val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM); 5508c0984e5SSebastian Reichel break; 5518c0984e5SSebastian Reichel 552478efc79SMichał Mirosław case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 553766873c1SYauhen Kharuzhy ret = bq25890_field_read(bq, F_IINLIM); 554478efc79SMichał Mirosław if (ret < 0) 555478efc79SMichał Mirosław return ret; 556478efc79SMichał Mirosław 557766873c1SYauhen Kharuzhy val->intval = bq25890_find_val(ret, TBL_IINLIM); 558478efc79SMichał Mirosław break; 559478efc79SMichał Mirosław 560ef1ca210SMarek Vasut case POWER_SUPPLY_PROP_CURRENT_NOW: /* I_BAT now */ 561ef1ca210SMarek Vasut /* 562ef1ca210SMarek Vasut * This is ADC-sampled immediate charge current supplied 563ef1ca210SMarek Vasut * from charger to battery. The property name is confusing, 564ef1ca210SMarek Vasut * for clarification refer to: 565ef1ca210SMarek Vasut * Documentation/ABI/testing/sysfs-class-power 566ef1ca210SMarek Vasut * /sys/class/power_supply/<supply_name>/current_now 567ef1ca210SMarek Vasut */ 5681e4724d0SMichał Mirosław ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */ 5691e4724d0SMichał Mirosław if (ret < 0) 5701e4724d0SMichał Mirosław return ret; 5711e4724d0SMichał Mirosław 5721e4724d0SMichał Mirosław /* converted_val = ADC_val * 50mA (table 10.3.19) */ 5731e4724d0SMichał Mirosław val->intval = ret * -50000; 5741e4724d0SMichał Mirosław break; 5751e4724d0SMichał Mirosław 5768327a8abSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: /* I_BAT user limit */ 5778327a8abSMarek Vasut /* 5788327a8abSMarek Vasut * This is user-configured constant charge current supplied 5798327a8abSMarek Vasut * from charger to battery in first phase of charging, when 5808327a8abSMarek Vasut * battery voltage is below constant charge voltage. 5818327a8abSMarek Vasut * 5828327a8abSMarek Vasut * This value reflects the current hardware setting. 5838327a8abSMarek Vasut * 5848327a8abSMarek Vasut * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX is the 5858327a8abSMarek Vasut * maximum value of this property. 5868327a8abSMarek Vasut */ 5878327a8abSMarek Vasut ret = bq25890_field_read(bq, F_ICHG); 5888327a8abSMarek Vasut if (ret < 0) 5898327a8abSMarek Vasut return ret; 5908327a8abSMarek Vasut val->intval = bq25890_find_val(ret, TBL_ICHG); 5918327a8abSMarek Vasut 5928327a8abSMarek Vasut /* When temperature is too low, charge current is decreased */ 5938327a8abSMarek Vasut if (bq->state.ntc_fault == NTC_FAULT_COOL) { 5948327a8abSMarek Vasut ret = bq25890_field_read(bq, F_JEITA_ISET); 5958327a8abSMarek Vasut if (ret < 0) 5968327a8abSMarek Vasut return ret; 5978327a8abSMarek Vasut 5988327a8abSMarek Vasut if (ret) 5998327a8abSMarek Vasut val->intval /= 5; 6008327a8abSMarek Vasut else 6018327a8abSMarek Vasut val->intval /= 2; 6028327a8abSMarek Vasut } 6038327a8abSMarek Vasut break; 6048327a8abSMarek Vasut 6058327a8abSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: /* I_BAT max */ 6068327a8abSMarek Vasut /* 6078327a8abSMarek Vasut * This is maximum allowed constant charge current supplied 6088327a8abSMarek Vasut * from charger to battery in first phase of charging, when 6098327a8abSMarek Vasut * battery voltage is below constant charge voltage. 6108327a8abSMarek Vasut * 6118327a8abSMarek Vasut * This value is constant for each battery and set from DT. 6128327a8abSMarek Vasut */ 6138327a8abSMarek Vasut val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); 6148327a8abSMarek Vasut break; 6158327a8abSMarek Vasut 6167c852375SMarek Vasut case POWER_SUPPLY_PROP_VOLTAGE_NOW: /* V_BAT now */ 6177c852375SMarek Vasut /* 6187c852375SMarek Vasut * This is ADC-sampled immediate charge voltage supplied 6197c852375SMarek Vasut * from charger to battery. The property name is confusing, 6207c852375SMarek Vasut * for clarification refer to: 6217c852375SMarek Vasut * Documentation/ABI/testing/sysfs-class-power 6227c852375SMarek Vasut * /sys/class/power_supply/<supply_name>/voltage_now 6237c852375SMarek Vasut */ 6247c852375SMarek Vasut ret = bq25890_field_read(bq, F_BATV); /* read measured value */ 6257c852375SMarek Vasut if (ret < 0) 6267c852375SMarek Vasut return ret; 6277c852375SMarek Vasut 6287c852375SMarek Vasut /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ 6297c852375SMarek Vasut val->intval = 2304000 + ret * 20000; 6307c852375SMarek Vasut break; 6317c852375SMarek Vasut 6327c852375SMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: /* V_BAT user limit */ 6337c852375SMarek Vasut /* 6347c852375SMarek Vasut * This is user-configured constant charge voltage supplied 6357c852375SMarek Vasut * from charger to battery in second phase of charging, when 6367c852375SMarek Vasut * battery voltage reached constant charge voltage. 6377c852375SMarek Vasut * 6387c852375SMarek Vasut * This value reflects the current hardware setting. 6397c852375SMarek Vasut * 6407c852375SMarek Vasut * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX is the 6417c852375SMarek Vasut * maximum value of this property. 6427c852375SMarek Vasut */ 6437c852375SMarek Vasut ret = bq25890_field_read(bq, F_VREG); 6447c852375SMarek Vasut if (ret < 0) 6457c852375SMarek Vasut return ret; 6467c852375SMarek Vasut 6477c852375SMarek Vasut val->intval = bq25890_find_val(ret, TBL_VREG); 6487c852375SMarek Vasut break; 6497c852375SMarek Vasut 6507c852375SMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: /* V_BAT max */ 6517c852375SMarek Vasut /* 6527c852375SMarek Vasut * This is maximum allowed constant charge voltage supplied 6537c852375SMarek Vasut * from charger to battery in second phase of charging, when 6547c852375SMarek Vasut * battery voltage reached constant charge voltage. 6557c852375SMarek Vasut * 6567c852375SMarek Vasut * This value is constant for each battery and set from DT. 6577c852375SMarek Vasut */ 6587c852375SMarek Vasut val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); 6597c852375SMarek Vasut break; 6607c852375SMarek Vasut 6619652c024SAngus Ainslie case POWER_SUPPLY_PROP_TEMP: 6629652c024SAngus Ainslie ret = bq25890_field_read(bq, F_TSPCT); 6639652c024SAngus Ainslie if (ret < 0) 6649652c024SAngus Ainslie return ret; 6659652c024SAngus Ainslie 6669652c024SAngus Ainslie /* convert TS percentage into rough temperature */ 6679652c024SAngus Ainslie val->intval = bq25890_find_val(ret, TBL_TSPCT); 6689652c024SAngus Ainslie break; 6699652c024SAngus Ainslie 6708c0984e5SSebastian Reichel default: 6718c0984e5SSebastian Reichel return -EINVAL; 6728c0984e5SSebastian Reichel } 6738c0984e5SSebastian Reichel 6748c0984e5SSebastian Reichel return 0; 6758c0984e5SSebastian Reichel } 6768c0984e5SSebastian Reichel 6774a4748f2SMarek Vasut static int bq25890_power_supply_set_property(struct power_supply *psy, 6784a4748f2SMarek Vasut enum power_supply_property psp, 6794a4748f2SMarek Vasut const union power_supply_propval *val) 6804a4748f2SMarek Vasut { 6814a4748f2SMarek Vasut struct bq25890_device *bq = power_supply_get_drvdata(psy); 682c688e0c4SMarek Vasut struct bq25890_state state; 683c688e0c4SMarek Vasut int maxval, ret; 6844a4748f2SMarek Vasut u8 lval; 6854a4748f2SMarek Vasut 6864a4748f2SMarek Vasut switch (psp) { 687b63e60ebSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 688b63e60ebSMarek Vasut maxval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); 689b63e60ebSMarek Vasut lval = bq25890_find_idx(min(val->intval, maxval), TBL_ICHG); 690b63e60ebSMarek Vasut return bq25890_field_write(bq, F_ICHG, lval); 691b63e60ebSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 692b63e60ebSMarek Vasut maxval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); 693b63e60ebSMarek Vasut lval = bq25890_find_idx(min(val->intval, maxval), TBL_VREG); 694b63e60ebSMarek Vasut return bq25890_field_write(bq, F_VREG, lval); 6954a4748f2SMarek Vasut case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 69655cafd4bSNathan Chancellor lval = bq25890_find_idx(val->intval, TBL_IINLIM); 6974a4748f2SMarek Vasut return bq25890_field_write(bq, F_IINLIM, lval); 698c688e0c4SMarek Vasut case POWER_SUPPLY_PROP_ONLINE: 699c688e0c4SMarek Vasut ret = bq25890_field_write(bq, F_EN_HIZ, !val->intval); 700c688e0c4SMarek Vasut if (!ret) 701c688e0c4SMarek Vasut bq->force_hiz = !val->intval; 702c688e0c4SMarek Vasut bq25890_update_state(bq, psp, &state); 703c688e0c4SMarek Vasut return ret; 7044a4748f2SMarek Vasut default: 7054a4748f2SMarek Vasut return -EINVAL; 7064a4748f2SMarek Vasut } 7074a4748f2SMarek Vasut } 7084a4748f2SMarek Vasut 7094a4748f2SMarek Vasut static int bq25890_power_supply_property_is_writeable(struct power_supply *psy, 7104a4748f2SMarek Vasut enum power_supply_property psp) 7114a4748f2SMarek Vasut { 7124a4748f2SMarek Vasut switch (psp) { 713b63e60ebSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 714b63e60ebSMarek Vasut case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 7154a4748f2SMarek Vasut case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 716c688e0c4SMarek Vasut case POWER_SUPPLY_PROP_ONLINE: 7174a4748f2SMarek Vasut return true; 7184a4748f2SMarek Vasut default: 7194a4748f2SMarek Vasut return false; 7204a4748f2SMarek Vasut } 7214a4748f2SMarek Vasut } 7224a4748f2SMarek Vasut 723eab25b4fSHans de Goede /* On the BQ25892 try to get charger-type info from our supplier */ 724eab25b4fSHans de Goede static void bq25890_charger_external_power_changed(struct power_supply *psy) 725eab25b4fSHans de Goede { 726eab25b4fSHans de Goede struct bq25890_device *bq = power_supply_get_drvdata(psy); 727eab25b4fSHans de Goede union power_supply_propval val; 728eab25b4fSHans de Goede int input_current_limit, ret; 729eab25b4fSHans de Goede 730eab25b4fSHans de Goede if (bq->chip_version != BQ25892) 731eab25b4fSHans de Goede return; 732eab25b4fSHans de Goede 733eab25b4fSHans de Goede ret = power_supply_get_property_from_supplier(bq->charger, 734eab25b4fSHans de Goede POWER_SUPPLY_PROP_USB_TYPE, 735eab25b4fSHans de Goede &val); 736eab25b4fSHans de Goede if (ret) 737eab25b4fSHans de Goede return; 738eab25b4fSHans de Goede 739eab25b4fSHans de Goede switch (val.intval) { 740eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_DCP: 741eab25b4fSHans de Goede input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM); 74248f45b09SYauhen Kharuzhy if (bq->pump_express_vbus_max) { 74348f45b09SYauhen Kharuzhy queue_delayed_work(system_power_efficient_wq, 74448f45b09SYauhen Kharuzhy &bq->pump_express_work, 74548f45b09SYauhen Kharuzhy PUMP_EXPRESS_START_DELAY); 74648f45b09SYauhen Kharuzhy } 747eab25b4fSHans de Goede break; 748eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_CDP: 749eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_ACA: 750eab25b4fSHans de Goede input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM); 751eab25b4fSHans de Goede break; 752eab25b4fSHans de Goede case POWER_SUPPLY_USB_TYPE_SDP: 753eab25b4fSHans de Goede default: 754eab25b4fSHans de Goede input_current_limit = bq25890_find_idx(500000, TBL_IINLIM); 755eab25b4fSHans de Goede } 756eab25b4fSHans de Goede 757eab25b4fSHans de Goede bq25890_field_write(bq, F_IINLIM, input_current_limit); 758eab25b4fSHans de Goede } 759eab25b4fSHans de Goede 7608c0984e5SSebastian Reichel static int bq25890_get_chip_state(struct bq25890_device *bq, 7618c0984e5SSebastian Reichel struct bq25890_state *state) 7628c0984e5SSebastian Reichel { 7638c0984e5SSebastian Reichel int i, ret; 7648c0984e5SSebastian Reichel 7658c0984e5SSebastian Reichel struct { 7668c0984e5SSebastian Reichel enum bq25890_fields id; 7678c0984e5SSebastian Reichel u8 *data; 7688c0984e5SSebastian Reichel } state_fields[] = { 7698c0984e5SSebastian Reichel {F_CHG_STAT, &state->chrg_status}, 7708c0984e5SSebastian Reichel {F_PG_STAT, &state->online}, 771c688e0c4SMarek Vasut {F_EN_HIZ, &state->hiz}, 7728c0984e5SSebastian Reichel {F_VSYS_STAT, &state->vsys_status}, 7738c0984e5SSebastian Reichel {F_BOOST_FAULT, &state->boost_fault}, 7748c0984e5SSebastian Reichel {F_BAT_FAULT, &state->bat_fault}, 775c562a43aSYauhen Kharuzhy {F_CHG_FAULT, &state->chrg_fault}, 776c562a43aSYauhen Kharuzhy {F_NTC_FAULT, &state->ntc_fault} 7778c0984e5SSebastian Reichel }; 7788c0984e5SSebastian Reichel 7798c0984e5SSebastian Reichel for (i = 0; i < ARRAY_SIZE(state_fields); i++) { 7808c0984e5SSebastian Reichel ret = bq25890_field_read(bq, state_fields[i].id); 7818c0984e5SSebastian Reichel if (ret < 0) 7828c0984e5SSebastian Reichel return ret; 7838c0984e5SSebastian Reichel 7848c0984e5SSebastian Reichel *state_fields[i].data = ret; 7858c0984e5SSebastian Reichel } 7868c0984e5SSebastian Reichel 787c688e0c4SMarek Vasut dev_dbg(bq->dev, "S:CHG/PG/HIZ/VSYS=%d/%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n", 788c688e0c4SMarek Vasut state->chrg_status, state->online, 789c688e0c4SMarek Vasut state->hiz, state->vsys_status, 790c688e0c4SMarek Vasut state->chrg_fault, state->boost_fault, 791c688e0c4SMarek Vasut state->bat_fault, state->ntc_fault); 7928c0984e5SSebastian Reichel 7938c0984e5SSebastian Reichel return 0; 7948c0984e5SSebastian Reichel } 7958c0984e5SSebastian Reichel 79672d9cd9cSMichał Mirosław static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq) 7978c0984e5SSebastian Reichel { 798*4413f9e9SHans de Goede bool adc_conv_rate, new_adc_conv_rate; 79972d9cd9cSMichał Mirosław struct bq25890_state new_state; 8008c0984e5SSebastian Reichel int ret; 8018c0984e5SSebastian Reichel 80272d9cd9cSMichał Mirosław ret = bq25890_get_chip_state(bq, &new_state); 80372d9cd9cSMichał Mirosław if (ret < 0) 80472d9cd9cSMichał Mirosław return IRQ_NONE; 8058c0984e5SSebastian Reichel 80672d9cd9cSMichał Mirosław if (!memcmp(&bq->state, &new_state, sizeof(new_state))) 80772d9cd9cSMichał Mirosław return IRQ_NONE; 80872d9cd9cSMichał Mirosław 809c688e0c4SMarek Vasut /* 810*4413f9e9SHans de Goede * Restore HiZ bit in case it was set by user. The chip does not retain 811*4413f9e9SHans de Goede * this bit on cable replug, hence the bit must be reset manually here. 812c688e0c4SMarek Vasut */ 813*4413f9e9SHans de Goede if (new_state.online && !bq->state.online && bq->force_hiz) { 814c688e0c4SMarek Vasut ret = bq25890_field_write(bq, F_EN_HIZ, bq->force_hiz); 815c688e0c4SMarek Vasut if (ret < 0) 816c688e0c4SMarek Vasut goto error; 817c688e0c4SMarek Vasut new_state.hiz = 1; 818c688e0c4SMarek Vasut } 819c688e0c4SMarek Vasut 820*4413f9e9SHans de Goede /* Should period ADC sampling be enabled? */ 821*4413f9e9SHans de Goede adc_conv_rate = bq->state.online && !bq->state.hiz; 822*4413f9e9SHans de Goede new_adc_conv_rate = new_state.online && !new_state.hiz; 823*4413f9e9SHans de Goede 824*4413f9e9SHans de Goede if (new_adc_conv_rate != adc_conv_rate) { 825*4413f9e9SHans de Goede ret = bq25890_field_write(bq, F_CONV_RATE, new_adc_conv_rate); 8268c0984e5SSebastian Reichel if (ret < 0) 8278c0984e5SSebastian Reichel goto error; 8288c0984e5SSebastian Reichel } 8298c0984e5SSebastian Reichel 83072d9cd9cSMichał Mirosław bq->state = new_state; 83172d9cd9cSMichał Mirosław power_supply_changed(bq->charger); 8328c0984e5SSebastian Reichel 83372d9cd9cSMichał Mirosław return IRQ_HANDLED; 8348c0984e5SSebastian Reichel error: 83572d9cd9cSMichał Mirosław dev_err(bq->dev, "Error communicating with the chip: %pe\n", 83672d9cd9cSMichał Mirosław ERR_PTR(ret)); 83772d9cd9cSMichał Mirosław return IRQ_HANDLED; 8388c0984e5SSebastian Reichel } 8398c0984e5SSebastian Reichel 8408c0984e5SSebastian Reichel static irqreturn_t bq25890_irq_handler_thread(int irq, void *private) 8418c0984e5SSebastian Reichel { 8428c0984e5SSebastian Reichel struct bq25890_device *bq = private; 84372d9cd9cSMichał Mirosław irqreturn_t ret; 8448c0984e5SSebastian Reichel 8458c0984e5SSebastian Reichel mutex_lock(&bq->lock); 84672d9cd9cSMichał Mirosław ret = __bq25890_handle_irq(bq); 8478c0984e5SSebastian Reichel mutex_unlock(&bq->lock); 8488c0984e5SSebastian Reichel 84972d9cd9cSMichał Mirosław return ret; 8508c0984e5SSebastian Reichel } 8518c0984e5SSebastian Reichel 8528c0984e5SSebastian Reichel static int bq25890_chip_reset(struct bq25890_device *bq) 8538c0984e5SSebastian Reichel { 8548c0984e5SSebastian Reichel int ret; 8558c0984e5SSebastian Reichel int rst_check_counter = 10; 8568c0984e5SSebastian Reichel 8578c0984e5SSebastian Reichel ret = bq25890_field_write(bq, F_REG_RST, 1); 8588c0984e5SSebastian Reichel if (ret < 0) 8598c0984e5SSebastian Reichel return ret; 8608c0984e5SSebastian Reichel 8618c0984e5SSebastian Reichel do { 8628c0984e5SSebastian Reichel ret = bq25890_field_read(bq, F_REG_RST); 8638c0984e5SSebastian Reichel if (ret < 0) 8648c0984e5SSebastian Reichel return ret; 8658c0984e5SSebastian Reichel 8668c0984e5SSebastian Reichel usleep_range(5, 10); 8678c0984e5SSebastian Reichel } while (ret == 1 && --rst_check_counter); 8688c0984e5SSebastian Reichel 8698c0984e5SSebastian Reichel if (!rst_check_counter) 8708c0984e5SSebastian Reichel return -ETIMEDOUT; 8718c0984e5SSebastian Reichel 8728c0984e5SSebastian Reichel return 0; 8738c0984e5SSebastian Reichel } 8748c0984e5SSebastian Reichel 8757b22a974SHans de Goede static int bq25890_rw_init_data(struct bq25890_device *bq) 8768c0984e5SSebastian Reichel { 87740428bd4SHans de Goede bool write = !bq->read_back_init_data; 8788c0984e5SSebastian Reichel int ret; 8798c0984e5SSebastian Reichel int i; 8808c0984e5SSebastian Reichel 8818c0984e5SSebastian Reichel const struct { 8828c0984e5SSebastian Reichel enum bq25890_fields id; 8837b22a974SHans de Goede u8 *value; 8848c0984e5SSebastian Reichel } init_data[] = { 8857b22a974SHans de Goede {F_ICHG, &bq->init_data.ichg}, 8867b22a974SHans de Goede {F_VREG, &bq->init_data.vreg}, 8877b22a974SHans de Goede {F_ITERM, &bq->init_data.iterm}, 8887b22a974SHans de Goede {F_IPRECHG, &bq->init_data.iprechg}, 8897b22a974SHans de Goede {F_SYSVMIN, &bq->init_data.sysvmin}, 8907b22a974SHans de Goede {F_BOOSTV, &bq->init_data.boostv}, 8917b22a974SHans de Goede {F_BOOSTI, &bq->init_data.boosti}, 8927b22a974SHans de Goede {F_BOOSTF, &bq->init_data.boostf}, 8937b22a974SHans de Goede {F_EN_ILIM, &bq->init_data.ilim_en}, 8947b22a974SHans de Goede {F_TREG, &bq->init_data.treg}, 8957b22a974SHans de Goede {F_BATCMP, &bq->init_data.rbatcomp}, 8967b22a974SHans de Goede {F_VCLAMP, &bq->init_data.vclamp}, 8978c0984e5SSebastian Reichel }; 8988c0984e5SSebastian Reichel 8997b22a974SHans de Goede for (i = 0; i < ARRAY_SIZE(init_data); i++) { 9007b22a974SHans de Goede if (write) { 9017b22a974SHans de Goede ret = bq25890_field_write(bq, init_data[i].id, 9027b22a974SHans de Goede *init_data[i].value); 9037b22a974SHans de Goede } else { 9047b22a974SHans de Goede ret = bq25890_field_read(bq, init_data[i].id); 9057b22a974SHans de Goede if (ret >= 0) 9067b22a974SHans de Goede *init_data[i].value = ret; 9077b22a974SHans de Goede } 9087b22a974SHans de Goede if (ret < 0) { 9097b22a974SHans de Goede dev_dbg(bq->dev, "Accessing init data failed %d\n", ret); 9107b22a974SHans de Goede return ret; 9117b22a974SHans de Goede } 9127b22a974SHans de Goede } 9137b22a974SHans de Goede 9147b22a974SHans de Goede return 0; 9157b22a974SHans de Goede } 9167b22a974SHans de Goede 9177b22a974SHans de Goede static int bq25890_hw_init(struct bq25890_device *bq) 9187b22a974SHans de Goede { 9197b22a974SHans de Goede int ret; 9207b22a974SHans de Goede 9217e3b8e35SHans de Goede if (!bq->skip_reset) { 9228c0984e5SSebastian Reichel ret = bq25890_chip_reset(bq); 9239d9ae341SAngus Ainslie (Purism) if (ret < 0) { 9249d9ae341SAngus Ainslie (Purism) dev_dbg(bq->dev, "Reset failed %d\n", ret); 9258c0984e5SSebastian Reichel return ret; 926ad1570d9Skbuild test robot } 92706c75095SHans de Goede } else { 92806c75095SHans de Goede /* 92906c75095SHans de Goede * Ensure charging is enabled, on some boards where the fw 93006c75095SHans de Goede * takes care of initalizition F_CHG_CFG is set to 0 before 93106c75095SHans de Goede * handing control over to the OS. 93206c75095SHans de Goede */ 93306c75095SHans de Goede ret = bq25890_field_write(bq, F_CHG_CFG, 1); 93406c75095SHans de Goede if (ret < 0) { 93506c75095SHans de Goede dev_dbg(bq->dev, "Enabling charging failed %d\n", ret); 93606c75095SHans de Goede return ret; 93706c75095SHans de Goede } 9387e3b8e35SHans de Goede } 9398c0984e5SSebastian Reichel 9408c0984e5SSebastian Reichel /* disable watchdog */ 9418c0984e5SSebastian Reichel ret = bq25890_field_write(bq, F_WD, 0); 9429d9ae341SAngus Ainslie (Purism) if (ret < 0) { 9439d9ae341SAngus Ainslie (Purism) dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret); 9448c0984e5SSebastian Reichel return ret; 945ad1570d9Skbuild test robot } 9468c0984e5SSebastian Reichel 9478c0984e5SSebastian Reichel /* initialize currents/voltages and other parameters */ 9487b22a974SHans de Goede ret = bq25890_rw_init_data(bq); 9497b22a974SHans de Goede if (ret) 9508c0984e5SSebastian Reichel return ret; 9518c0984e5SSebastian Reichel 95222ad4f99SHans de Goede ret = bq25890_get_chip_state(bq, &bq->state); 95322ad4f99SHans de Goede if (ret < 0) { 95422ad4f99SHans de Goede dev_dbg(bq->dev, "Get state failed %d\n", ret); 95522ad4f99SHans de Goede return ret; 95622ad4f99SHans de Goede } 95722ad4f99SHans de Goede 95821d90edaSMichał Mirosław /* Configure ADC for continuous conversions when charging */ 95921d90edaSMichał Mirosław ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online); 9609d9ae341SAngus Ainslie (Purism) if (ret < 0) { 9619d9ae341SAngus Ainslie (Purism) dev_dbg(bq->dev, "Config ADC failed %d\n", ret); 9628c0984e5SSebastian Reichel return ret; 963ad1570d9Skbuild test robot } 9648c0984e5SSebastian Reichel 9658c0984e5SSebastian Reichel return 0; 9668c0984e5SSebastian Reichel } 9678c0984e5SSebastian Reichel 968a6a48facSMichał Mirosław static const enum power_supply_property bq25890_power_supply_props[] = { 9698c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 9702e1a2ddeSAngus Ainslie (Purism) POWER_SUPPLY_PROP_MODEL_NAME, 9718c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 972b302a0aeSMichał Mirosław POWER_SUPPLY_PROP_CHARGE_TYPE, 9738c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ONLINE, 9748c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 9758327a8abSMarek Vasut POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 9768c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 9778c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 9788c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 979c942656dSMichał Mirosław POWER_SUPPLY_PROP_PRECHARGE_CURRENT, 9808c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 981478efc79SMichał Mirosław POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 982ae6fe7a3SAngus Ainslie (Purism) POWER_SUPPLY_PROP_VOLTAGE_NOW, 9831e4724d0SMichał Mirosław POWER_SUPPLY_PROP_CURRENT_NOW, 9849652c024SAngus Ainslie POWER_SUPPLY_PROP_TEMP, 9858c0984e5SSebastian Reichel }; 9868c0984e5SSebastian Reichel 9878c0984e5SSebastian Reichel static char *bq25890_charger_supplied_to[] = { 9888c0984e5SSebastian Reichel "main-battery", 9898c0984e5SSebastian Reichel }; 9908c0984e5SSebastian Reichel 9918c0984e5SSebastian Reichel static const struct power_supply_desc bq25890_power_supply_desc = { 9928c0984e5SSebastian Reichel .name = "bq25890-charger", 9938c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_USB, 9948c0984e5SSebastian Reichel .properties = bq25890_power_supply_props, 9958c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(bq25890_power_supply_props), 9968c0984e5SSebastian Reichel .get_property = bq25890_power_supply_get_property, 9974a4748f2SMarek Vasut .set_property = bq25890_power_supply_set_property, 9984a4748f2SMarek Vasut .property_is_writeable = bq25890_power_supply_property_is_writeable, 999eab25b4fSHans de Goede .external_power_changed = bq25890_charger_external_power_changed, 10008c0984e5SSebastian Reichel }; 10018c0984e5SSebastian Reichel 10028c0984e5SSebastian Reichel static int bq25890_power_supply_init(struct bq25890_device *bq) 10038c0984e5SSebastian Reichel { 10048c0984e5SSebastian Reichel struct power_supply_config psy_cfg = { .drv_data = bq, }; 10058c0984e5SSebastian Reichel 10068c0984e5SSebastian Reichel psy_cfg.supplied_to = bq25890_charger_supplied_to; 10078c0984e5SSebastian Reichel psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to); 10088c0984e5SSebastian Reichel 1009d01363daSHans de Goede bq->charger = devm_power_supply_register(bq->dev, 1010d01363daSHans de Goede &bq25890_power_supply_desc, 10118c0984e5SSebastian Reichel &psy_cfg); 10128c0984e5SSebastian Reichel 10138c0984e5SSebastian Reichel return PTR_ERR_OR_ZERO(bq->charger); 10148c0984e5SSebastian Reichel } 10158c0984e5SSebastian Reichel 10165575802dSHans de Goede static int bq25890_set_otg_cfg(struct bq25890_device *bq, u8 val) 10175575802dSHans de Goede { 10185575802dSHans de Goede int ret; 10195575802dSHans de Goede 10205575802dSHans de Goede ret = bq25890_field_write(bq, F_OTG_CFG, val); 10215575802dSHans de Goede if (ret < 0) 10225575802dSHans de Goede dev_err(bq->dev, "Error switching to boost/charger mode: %d\n", ret); 10235575802dSHans de Goede 10245575802dSHans de Goede return ret; 10255575802dSHans de Goede } 10265575802dSHans de Goede 102748f45b09SYauhen Kharuzhy static void bq25890_pump_express_work(struct work_struct *data) 102848f45b09SYauhen Kharuzhy { 102948f45b09SYauhen Kharuzhy struct bq25890_device *bq = 103048f45b09SYauhen Kharuzhy container_of(data, struct bq25890_device, pump_express_work.work); 103148f45b09SYauhen Kharuzhy int voltage, i, ret; 103248f45b09SYauhen Kharuzhy 103348f45b09SYauhen Kharuzhy dev_dbg(bq->dev, "Start to request input voltage increasing\n"); 103448f45b09SYauhen Kharuzhy 103548f45b09SYauhen Kharuzhy /* Enable current pulse voltage control protocol */ 103648f45b09SYauhen Kharuzhy ret = bq25890_field_write(bq, F_PUMPX_EN, 1); 103748f45b09SYauhen Kharuzhy if (ret < 0) 103848f45b09SYauhen Kharuzhy goto error_print; 103948f45b09SYauhen Kharuzhy 104048f45b09SYauhen Kharuzhy for (i = 0; i < PUMP_EXPRESS_MAX_TRIES; i++) { 104148f45b09SYauhen Kharuzhy voltage = bq25890_get_vbus_voltage(bq); 104248f45b09SYauhen Kharuzhy if (voltage < 0) 104348f45b09SYauhen Kharuzhy goto error_print; 104448f45b09SYauhen Kharuzhy dev_dbg(bq->dev, "input voltage = %d uV\n", voltage); 104548f45b09SYauhen Kharuzhy 104648f45b09SYauhen Kharuzhy if ((voltage + PUMP_EXPRESS_VBUS_MARGIN_uV) > 104748f45b09SYauhen Kharuzhy bq->pump_express_vbus_max) 104848f45b09SYauhen Kharuzhy break; 104948f45b09SYauhen Kharuzhy 105048f45b09SYauhen Kharuzhy ret = bq25890_field_write(bq, F_PUMPX_UP, 1); 105148f45b09SYauhen Kharuzhy if (ret < 0) 105248f45b09SYauhen Kharuzhy goto error_print; 105348f45b09SYauhen Kharuzhy 105448f45b09SYauhen Kharuzhy /* Note a single PUMPX up pulse-sequence takes 2.1s */ 105548f45b09SYauhen Kharuzhy ret = regmap_field_read_poll_timeout(bq->rmap_fields[F_PUMPX_UP], 105648f45b09SYauhen Kharuzhy ret, !ret, 100000, 3000000); 105748f45b09SYauhen Kharuzhy if (ret < 0) 105848f45b09SYauhen Kharuzhy goto error_print; 105948f45b09SYauhen Kharuzhy 106048f45b09SYauhen Kharuzhy /* Make sure ADC has sampled Vbus before checking again */ 106148f45b09SYauhen Kharuzhy msleep(1000); 106248f45b09SYauhen Kharuzhy } 106348f45b09SYauhen Kharuzhy 106448f45b09SYauhen Kharuzhy bq25890_field_write(bq, F_PUMPX_EN, 0); 106548f45b09SYauhen Kharuzhy 106648f45b09SYauhen Kharuzhy dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n", 106748f45b09SYauhen Kharuzhy voltage); 106848f45b09SYauhen Kharuzhy 106948f45b09SYauhen Kharuzhy return; 107048f45b09SYauhen Kharuzhy error_print: 107104f7c7dfSHans de Goede bq25890_field_write(bq, F_PUMPX_EN, 0); 107248f45b09SYauhen Kharuzhy dev_err(bq->dev, "Failed to request hi-voltage charging\n"); 107348f45b09SYauhen Kharuzhy } 107448f45b09SYauhen Kharuzhy 10758c0984e5SSebastian Reichel static void bq25890_usb_work(struct work_struct *data) 10768c0984e5SSebastian Reichel { 10778c0984e5SSebastian Reichel int ret; 10788c0984e5SSebastian Reichel struct bq25890_device *bq = 10798c0984e5SSebastian Reichel container_of(data, struct bq25890_device, usb_work); 10808c0984e5SSebastian Reichel 10818c0984e5SSebastian Reichel switch (bq->usb_event) { 10828c0984e5SSebastian Reichel case USB_EVENT_ID: 10838c0984e5SSebastian Reichel /* Enable boost mode */ 10845575802dSHans de Goede bq25890_set_otg_cfg(bq, 1); 10858c0984e5SSebastian Reichel break; 10868c0984e5SSebastian Reichel 10878c0984e5SSebastian Reichel case USB_EVENT_NONE: 10888c0984e5SSebastian Reichel /* Disable boost mode */ 10895575802dSHans de Goede ret = bq25890_set_otg_cfg(bq, 0); 10905575802dSHans de Goede if (ret == 0) 10918c0984e5SSebastian Reichel power_supply_changed(bq->charger); 10928c0984e5SSebastian Reichel break; 10938c0984e5SSebastian Reichel } 10948c0984e5SSebastian Reichel } 10958c0984e5SSebastian Reichel 10968c0984e5SSebastian Reichel static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val, 10978c0984e5SSebastian Reichel void *priv) 10988c0984e5SSebastian Reichel { 10998c0984e5SSebastian Reichel struct bq25890_device *bq = 11008c0984e5SSebastian Reichel container_of(nb, struct bq25890_device, usb_nb); 11018c0984e5SSebastian Reichel 11028c0984e5SSebastian Reichel bq->usb_event = val; 11038c0984e5SSebastian Reichel queue_work(system_power_efficient_wq, &bq->usb_work); 11048c0984e5SSebastian Reichel 11058c0984e5SSebastian Reichel return NOTIFY_OK; 11068c0984e5SSebastian Reichel } 11078c0984e5SSebastian Reichel 110879d35365SHans de Goede #ifdef CONFIG_REGULATOR 110979d35365SHans de Goede static int bq25890_vbus_enable(struct regulator_dev *rdev) 111079d35365SHans de Goede { 111179d35365SHans de Goede struct bq25890_device *bq = rdev_get_drvdata(rdev); 111279d35365SHans de Goede 111379d35365SHans de Goede return bq25890_set_otg_cfg(bq, 1); 111479d35365SHans de Goede } 111579d35365SHans de Goede 111679d35365SHans de Goede static int bq25890_vbus_disable(struct regulator_dev *rdev) 111779d35365SHans de Goede { 111879d35365SHans de Goede struct bq25890_device *bq = rdev_get_drvdata(rdev); 111979d35365SHans de Goede 112079d35365SHans de Goede return bq25890_set_otg_cfg(bq, 0); 112179d35365SHans de Goede } 112279d35365SHans de Goede 112379d35365SHans de Goede static int bq25890_vbus_is_enabled(struct regulator_dev *rdev) 112479d35365SHans de Goede { 112579d35365SHans de Goede struct bq25890_device *bq = rdev_get_drvdata(rdev); 112679d35365SHans de Goede 112779d35365SHans de Goede return bq25890_field_read(bq, F_OTG_CFG); 112879d35365SHans de Goede } 112979d35365SHans de Goede 113085052e90SMarek Vasut static int bq25890_vbus_get_voltage(struct regulator_dev *rdev) 113185052e90SMarek Vasut { 113285052e90SMarek Vasut struct bq25890_device *bq = rdev_get_drvdata(rdev); 113385052e90SMarek Vasut 113485052e90SMarek Vasut return bq25890_get_vbus_voltage(bq); 113585052e90SMarek Vasut } 113685052e90SMarek Vasut 113714a3d159SMarek Vasut static int bq25890_vsys_get_voltage(struct regulator_dev *rdev) 113814a3d159SMarek Vasut { 113914a3d159SMarek Vasut struct bq25890_device *bq = rdev_get_drvdata(rdev); 114014a3d159SMarek Vasut int ret; 114114a3d159SMarek Vasut 114214a3d159SMarek Vasut /* Should be some output voltage ? */ 114314a3d159SMarek Vasut ret = bq25890_field_read(bq, F_SYSV); /* read measured value */ 114414a3d159SMarek Vasut if (ret < 0) 114514a3d159SMarek Vasut return ret; 114614a3d159SMarek Vasut 114714a3d159SMarek Vasut /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ 114814a3d159SMarek Vasut return 2304000 + ret * 20000; 114914a3d159SMarek Vasut } 115014a3d159SMarek Vasut 115179d35365SHans de Goede static const struct regulator_ops bq25890_vbus_ops = { 115279d35365SHans de Goede .enable = bq25890_vbus_enable, 115379d35365SHans de Goede .disable = bq25890_vbus_disable, 115479d35365SHans de Goede .is_enabled = bq25890_vbus_is_enabled, 115585052e90SMarek Vasut .get_voltage = bq25890_vbus_get_voltage, 115679d35365SHans de Goede }; 115779d35365SHans de Goede 115879d35365SHans de Goede static const struct regulator_desc bq25890_vbus_desc = { 115979d35365SHans de Goede .name = "usb_otg_vbus", 116079d35365SHans de Goede .of_match = "usb-otg-vbus", 116179d35365SHans de Goede .type = REGULATOR_VOLTAGE, 116279d35365SHans de Goede .owner = THIS_MODULE, 116379d35365SHans de Goede .ops = &bq25890_vbus_ops, 116479d35365SHans de Goede }; 11655f5c10ecSMarek Vasut 116614a3d159SMarek Vasut static const struct regulator_ops bq25890_vsys_ops = { 116714a3d159SMarek Vasut .get_voltage = bq25890_vsys_get_voltage, 116814a3d159SMarek Vasut }; 116914a3d159SMarek Vasut 117014a3d159SMarek Vasut static const struct regulator_desc bq25890_vsys_desc = { 117114a3d159SMarek Vasut .name = "vsys", 117214a3d159SMarek Vasut .of_match = "vsys", 117314a3d159SMarek Vasut .type = REGULATOR_VOLTAGE, 117414a3d159SMarek Vasut .owner = THIS_MODULE, 117514a3d159SMarek Vasut .ops = &bq25890_vsys_ops, 117614a3d159SMarek Vasut }; 117714a3d159SMarek Vasut 11785f5c10ecSMarek Vasut static int bq25890_register_regulator(struct bq25890_device *bq) 11795f5c10ecSMarek Vasut { 11805f5c10ecSMarek Vasut struct bq25890_platform_data *pdata = dev_get_platdata(bq->dev); 11815f5c10ecSMarek Vasut struct regulator_config cfg = { 11825f5c10ecSMarek Vasut .dev = bq->dev, 11835f5c10ecSMarek Vasut .driver_data = bq, 11845f5c10ecSMarek Vasut }; 11855f5c10ecSMarek Vasut struct regulator_dev *reg; 11865f5c10ecSMarek Vasut 11875f5c10ecSMarek Vasut if (pdata) 11885f5c10ecSMarek Vasut cfg.init_data = pdata->regulator_init_data; 11895f5c10ecSMarek Vasut 11905f5c10ecSMarek Vasut reg = devm_regulator_register(bq->dev, &bq25890_vbus_desc, &cfg); 11915f5c10ecSMarek Vasut if (IS_ERR(reg)) { 11925f5c10ecSMarek Vasut return dev_err_probe(bq->dev, PTR_ERR(reg), 11935f5c10ecSMarek Vasut "registering vbus regulator"); 11945f5c10ecSMarek Vasut } 11955f5c10ecSMarek Vasut 1196571650b3SHans de Goede /* pdata->regulator_init_data is for vbus only */ 1197571650b3SHans de Goede cfg.init_data = NULL; 119814a3d159SMarek Vasut reg = devm_regulator_register(bq->dev, &bq25890_vsys_desc, &cfg); 119914a3d159SMarek Vasut if (IS_ERR(reg)) { 120014a3d159SMarek Vasut return dev_err_probe(bq->dev, PTR_ERR(reg), 120114a3d159SMarek Vasut "registering vsys regulator"); 120214a3d159SMarek Vasut } 120314a3d159SMarek Vasut 12045f5c10ecSMarek Vasut return 0; 12055f5c10ecSMarek Vasut } 12065f5c10ecSMarek Vasut #else 12075f5c10ecSMarek Vasut static inline int 12085f5c10ecSMarek Vasut bq25890_register_regulator(struct bq25890_device *bq) 12095f5c10ecSMarek Vasut { 12105f5c10ecSMarek Vasut return 0; 12115f5c10ecSMarek Vasut } 121279d35365SHans de Goede #endif 121379d35365SHans de Goede 1214d20267c9SYauhen Kharuzhy static int bq25890_get_chip_version(struct bq25890_device *bq) 1215d20267c9SYauhen Kharuzhy { 1216d20267c9SYauhen Kharuzhy int id, rev; 1217d20267c9SYauhen Kharuzhy 1218d20267c9SYauhen Kharuzhy id = bq25890_field_read(bq, F_PN); 1219d20267c9SYauhen Kharuzhy if (id < 0) { 1220172d0cceSMartin Kepplinger dev_err(bq->dev, "Cannot read chip ID: %d\n", id); 1221d20267c9SYauhen Kharuzhy return id; 1222d20267c9SYauhen Kharuzhy } 1223d20267c9SYauhen Kharuzhy 1224d20267c9SYauhen Kharuzhy rev = bq25890_field_read(bq, F_DEV_REV); 1225d20267c9SYauhen Kharuzhy if (rev < 0) { 1226172d0cceSMartin Kepplinger dev_err(bq->dev, "Cannot read chip revision: %d\n", rev); 1227cb619e80SColin Ian King return rev; 1228d20267c9SYauhen Kharuzhy } 1229d20267c9SYauhen Kharuzhy 1230d20267c9SYauhen Kharuzhy switch (id) { 1231d20267c9SYauhen Kharuzhy case BQ25890_ID: 1232d20267c9SYauhen Kharuzhy bq->chip_version = BQ25890; 1233d20267c9SYauhen Kharuzhy break; 1234d20267c9SYauhen Kharuzhy 1235d20267c9SYauhen Kharuzhy /* BQ25892 and BQ25896 share same ID 0 */ 1236d20267c9SYauhen Kharuzhy case BQ25896_ID: 1237d20267c9SYauhen Kharuzhy switch (rev) { 1238d20267c9SYauhen Kharuzhy case 2: 1239d20267c9SYauhen Kharuzhy bq->chip_version = BQ25896; 1240d20267c9SYauhen Kharuzhy break; 1241d20267c9SYauhen Kharuzhy case 1: 1242d20267c9SYauhen Kharuzhy bq->chip_version = BQ25892; 1243d20267c9SYauhen Kharuzhy break; 1244d20267c9SYauhen Kharuzhy default: 1245d20267c9SYauhen Kharuzhy dev_err(bq->dev, 1246d20267c9SYauhen Kharuzhy "Unknown device revision %d, assume BQ25892\n", 1247d20267c9SYauhen Kharuzhy rev); 1248d20267c9SYauhen Kharuzhy bq->chip_version = BQ25892; 1249d20267c9SYauhen Kharuzhy } 1250d20267c9SYauhen Kharuzhy break; 1251d20267c9SYauhen Kharuzhy 1252d20267c9SYauhen Kharuzhy case BQ25895_ID: 1253d20267c9SYauhen Kharuzhy bq->chip_version = BQ25895; 1254d20267c9SYauhen Kharuzhy break; 1255d20267c9SYauhen Kharuzhy 1256d20267c9SYauhen Kharuzhy default: 1257d20267c9SYauhen Kharuzhy dev_err(bq->dev, "Unknown chip ID %d\n", id); 1258d20267c9SYauhen Kharuzhy return -ENODEV; 1259d20267c9SYauhen Kharuzhy } 1260d20267c9SYauhen Kharuzhy 1261d20267c9SYauhen Kharuzhy return 0; 1262d20267c9SYauhen Kharuzhy } 1263d20267c9SYauhen Kharuzhy 12648c0984e5SSebastian Reichel static int bq25890_irq_probe(struct bq25890_device *bq) 12658c0984e5SSebastian Reichel { 12668c0984e5SSebastian Reichel struct gpio_desc *irq; 12678c0984e5SSebastian Reichel 126886775879SAndy Shevchenko irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN); 1269172d0cceSMartin Kepplinger if (IS_ERR(irq)) 1270172d0cceSMartin Kepplinger return dev_err_probe(bq->dev, PTR_ERR(irq), 1271172d0cceSMartin Kepplinger "Could not probe irq pin.\n"); 12728c0984e5SSebastian Reichel 12738c0984e5SSebastian Reichel return gpiod_to_irq(irq); 12748c0984e5SSebastian Reichel } 12758c0984e5SSebastian Reichel 12768c0984e5SSebastian Reichel static int bq25890_fw_read_u32_props(struct bq25890_device *bq) 12778c0984e5SSebastian Reichel { 12788c0984e5SSebastian Reichel int ret; 12798c0984e5SSebastian Reichel u32 property; 12808c0984e5SSebastian Reichel int i; 12818c0984e5SSebastian Reichel struct bq25890_init_data *init = &bq->init_data; 12828c0984e5SSebastian Reichel struct { 12838c0984e5SSebastian Reichel char *name; 12848c0984e5SSebastian Reichel bool optional; 12858c0984e5SSebastian Reichel enum bq25890_table_ids tbl_id; 12868c0984e5SSebastian Reichel u8 *conv_data; /* holds converted value from given property */ 12878c0984e5SSebastian Reichel } props[] = { 12888c0984e5SSebastian Reichel /* required properties */ 12898c0984e5SSebastian Reichel {"ti,charge-current", false, TBL_ICHG, &init->ichg}, 12908c0984e5SSebastian Reichel {"ti,battery-regulation-voltage", false, TBL_VREG, &init->vreg}, 12918c0984e5SSebastian Reichel {"ti,termination-current", false, TBL_ITERM, &init->iterm}, 12928c0984e5SSebastian Reichel {"ti,precharge-current", false, TBL_ITERM, &init->iprechg}, 12938c0984e5SSebastian Reichel {"ti,minimum-sys-voltage", false, TBL_SYSVMIN, &init->sysvmin}, 12948c0984e5SSebastian Reichel {"ti,boost-voltage", false, TBL_BOOSTV, &init->boostv}, 12958c0984e5SSebastian Reichel {"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti}, 12968c0984e5SSebastian Reichel 12978c0984e5SSebastian Reichel /* optional properties */ 129872408329SMichał Mirosław {"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg}, 129972408329SMichał Mirosław {"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp}, 130072408329SMichał Mirosław {"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp}, 13018c0984e5SSebastian Reichel }; 13028c0984e5SSebastian Reichel 13038c0984e5SSebastian Reichel /* initialize data for optional properties */ 13048c0984e5SSebastian Reichel init->treg = 3; /* 120 degrees Celsius */ 130572408329SMichał Mirosław init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */ 13068c0984e5SSebastian Reichel 13078c0984e5SSebastian Reichel for (i = 0; i < ARRAY_SIZE(props); i++) { 13088c0984e5SSebastian Reichel ret = device_property_read_u32(bq->dev, props[i].name, 13098c0984e5SSebastian Reichel &property); 13108c0984e5SSebastian Reichel if (ret < 0) { 13118c0984e5SSebastian Reichel if (props[i].optional) 13128c0984e5SSebastian Reichel continue; 13138c0984e5SSebastian Reichel 13149d9ae341SAngus Ainslie (Purism) dev_err(bq->dev, "Unable to read property %d %s\n", ret, 13159d9ae341SAngus Ainslie (Purism) props[i].name); 13169d9ae341SAngus Ainslie (Purism) 13178c0984e5SSebastian Reichel return ret; 13188c0984e5SSebastian Reichel } 13198c0984e5SSebastian Reichel 13208c0984e5SSebastian Reichel *props[i].conv_data = bq25890_find_idx(property, 13218c0984e5SSebastian Reichel props[i].tbl_id); 13228c0984e5SSebastian Reichel } 13238c0984e5SSebastian Reichel 13248c0984e5SSebastian Reichel return 0; 13258c0984e5SSebastian Reichel } 13268c0984e5SSebastian Reichel 13278c0984e5SSebastian Reichel static int bq25890_fw_probe(struct bq25890_device *bq) 13288c0984e5SSebastian Reichel { 13298c0984e5SSebastian Reichel int ret; 13308c0984e5SSebastian Reichel struct bq25890_init_data *init = &bq->init_data; 13318c0984e5SSebastian Reichel 133248f45b09SYauhen Kharuzhy /* Optional, left at 0 if property is not present */ 133348f45b09SYauhen Kharuzhy device_property_read_u32(bq->dev, "linux,pump-express-vbus-max", 133448f45b09SYauhen Kharuzhy &bq->pump_express_vbus_max); 133548f45b09SYauhen Kharuzhy 13367e3b8e35SHans de Goede bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset"); 133740428bd4SHans de Goede bq->read_back_init_data = device_property_read_bool(bq->dev, 133840428bd4SHans de Goede "linux,read-back-settings"); 133940428bd4SHans de Goede if (bq->read_back_init_data) 134040428bd4SHans de Goede return 0; 13417e3b8e35SHans de Goede 13428c0984e5SSebastian Reichel ret = bq25890_fw_read_u32_props(bq); 13438c0984e5SSebastian Reichel if (ret < 0) 13448c0984e5SSebastian Reichel return ret; 13458c0984e5SSebastian Reichel 13468c0984e5SSebastian Reichel init->ilim_en = device_property_read_bool(bq->dev, "ti,use-ilim-pin"); 13478c0984e5SSebastian Reichel init->boostf = device_property_read_bool(bq->dev, "ti,boost-low-freq"); 13488c0984e5SSebastian Reichel 13498c0984e5SSebastian Reichel return 0; 13508c0984e5SSebastian Reichel } 13518c0984e5SSebastian Reichel 1352a7aaa800SHans de Goede static void bq25890_non_devm_cleanup(void *data) 1353a7aaa800SHans de Goede { 1354a7aaa800SHans de Goede struct bq25890_device *bq = data; 1355a7aaa800SHans de Goede 1356a7aaa800SHans de Goede cancel_delayed_work_sync(&bq->pump_express_work); 1357a7aaa800SHans de Goede } 1358a7aaa800SHans de Goede 1359c5cddca2SUwe Kleine-König static int bq25890_probe(struct i2c_client *client) 13608c0984e5SSebastian Reichel { 13618c0984e5SSebastian Reichel struct device *dev = &client->dev; 13628c0984e5SSebastian Reichel struct bq25890_device *bq; 13638c0984e5SSebastian Reichel int ret; 13648c0984e5SSebastian Reichel 13658c0984e5SSebastian Reichel bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); 13668c0984e5SSebastian Reichel if (!bq) 13678c0984e5SSebastian Reichel return -ENOMEM; 13688c0984e5SSebastian Reichel 13698c0984e5SSebastian Reichel bq->client = client; 13708c0984e5SSebastian Reichel bq->dev = dev; 13718c0984e5SSebastian Reichel 13728c0984e5SSebastian Reichel mutex_init(&bq->lock); 137348f45b09SYauhen Kharuzhy INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work); 13748c0984e5SSebastian Reichel 13758c0984e5SSebastian Reichel bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config); 1376172d0cceSMartin Kepplinger if (IS_ERR(bq->rmap)) 1377172d0cceSMartin Kepplinger return dev_err_probe(dev, PTR_ERR(bq->rmap), 1378172d0cceSMartin Kepplinger "failed to allocate register map\n"); 13798c0984e5SSebastian Reichel 1380c1ae3a4eSHans de Goede ret = devm_regmap_field_bulk_alloc(dev, bq->rmap, bq->rmap_fields, 1381c1ae3a4eSHans de Goede bq25890_reg_fields, F_MAX_FIELDS); 1382c1ae3a4eSHans de Goede if (ret) 1383c1ae3a4eSHans de Goede return ret; 13848c0984e5SSebastian Reichel 13858c0984e5SSebastian Reichel i2c_set_clientdata(client, bq); 13868c0984e5SSebastian Reichel 1387d20267c9SYauhen Kharuzhy ret = bq25890_get_chip_version(bq); 1388d20267c9SYauhen Kharuzhy if (ret) { 1389172d0cceSMartin Kepplinger dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret); 1390d20267c9SYauhen Kharuzhy return ret; 13918c0984e5SSebastian Reichel } 13928c0984e5SSebastian Reichel 13938c0984e5SSebastian Reichel ret = bq25890_fw_probe(bq); 1394f481d5b8SHans de Goede if (ret < 0) 1395f481d5b8SHans de Goede return dev_err_probe(dev, ret, "reading device properties\n"); 13968c0984e5SSebastian Reichel 13978c0984e5SSebastian Reichel ret = bq25890_hw_init(bq); 13988c0984e5SSebastian Reichel if (ret < 0) { 1399172d0cceSMartin Kepplinger dev_err(dev, "Cannot initialize the chip: %d\n", ret); 14008c0984e5SSebastian Reichel return ret; 14018c0984e5SSebastian Reichel } 14028c0984e5SSebastian Reichel 14038c0984e5SSebastian Reichel if (client->irq <= 0) 14048c0984e5SSebastian Reichel client->irq = bq25890_irq_probe(bq); 14058c0984e5SSebastian Reichel 14068c0984e5SSebastian Reichel if (client->irq < 0) { 14078c0984e5SSebastian Reichel dev_err(dev, "No irq resource found.\n"); 14088c0984e5SSebastian Reichel return client->irq; 14098c0984e5SSebastian Reichel } 14108c0984e5SSebastian Reichel 14118c0984e5SSebastian Reichel /* OTG reporting */ 14128c0984e5SSebastian Reichel bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 14135f5c10ecSMarek Vasut 1414a7aaa800SHans de Goede /* 1415a7aaa800SHans de Goede * This must be before bq25890_power_supply_init(), so that it runs 1416a7aaa800SHans de Goede * after devm unregisters the power_supply. 1417a7aaa800SHans de Goede */ 1418a7aaa800SHans de Goede ret = devm_add_action_or_reset(dev, bq25890_non_devm_cleanup, bq); 1419a7aaa800SHans de Goede if (ret) 1420a7aaa800SHans de Goede return ret; 1421a7aaa800SHans de Goede 14225f5c10ecSMarek Vasut ret = bq25890_register_regulator(bq); 14235f5c10ecSMarek Vasut if (ret) 14245f5c10ecSMarek Vasut return ret; 14255f5c10ecSMarek Vasut 1426d01363daSHans de Goede ret = bq25890_power_supply_init(bq); 14277e6fb678SHans de Goede if (ret < 0) 14287e6fb678SHans de Goede return dev_err_probe(dev, ret, "registering power supply\n"); 1429d01363daSHans de Goede 14308c0984e5SSebastian Reichel ret = devm_request_threaded_irq(dev, client->irq, NULL, 14318c0984e5SSebastian Reichel bq25890_irq_handler_thread, 14328c0984e5SSebastian Reichel IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 14338c0984e5SSebastian Reichel BQ25890_IRQ_PIN, bq); 14348c0984e5SSebastian Reichel if (ret) 14357e6fb678SHans de Goede return ret; 14367e6fb678SHans de Goede 14377e6fb678SHans de Goede if (!IS_ERR_OR_NULL(bq->usb_phy)) { 14387e6fb678SHans de Goede INIT_WORK(&bq->usb_work, bq25890_usb_work); 14397e6fb678SHans de Goede bq->usb_nb.notifier_call = bq25890_usb_notifier; 14407e6fb678SHans de Goede usb_register_notifier(bq->usb_phy, &bq->usb_nb); 14417e6fb678SHans de Goede } 14428c0984e5SSebastian Reichel 14438c0984e5SSebastian Reichel return 0; 14448c0984e5SSebastian Reichel } 14458c0984e5SSebastian Reichel 1446ed5c2f5fSUwe Kleine-König static void bq25890_remove(struct i2c_client *client) 14478c0984e5SSebastian Reichel { 14488c0984e5SSebastian Reichel struct bq25890_device *bq = i2c_get_clientdata(client); 14498c0984e5SSebastian Reichel 14507e6fb678SHans de Goede if (!IS_ERR_OR_NULL(bq->usb_phy)) { 14518c0984e5SSebastian Reichel usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); 14527e6fb678SHans de Goede cancel_work_sync(&bq->usb_work); 14537e6fb678SHans de Goede } 14548c0984e5SSebastian Reichel 14557e3b8e35SHans de Goede if (!bq->skip_reset) { 14568c0984e5SSebastian Reichel /* reset all registers to default values */ 14578c0984e5SSebastian Reichel bq25890_chip_reset(bq); 14587e3b8e35SHans de Goede } 14598c0984e5SSebastian Reichel } 14608c0984e5SSebastian Reichel 146179d35365SHans de Goede static void bq25890_shutdown(struct i2c_client *client) 146279d35365SHans de Goede { 146379d35365SHans de Goede struct bq25890_device *bq = i2c_get_clientdata(client); 146479d35365SHans de Goede 146579d35365SHans de Goede /* 146679d35365SHans de Goede * TODO this if + return should probably be removed, but that would 146779d35365SHans de Goede * introduce a function change for boards using the usb-phy framework. 146879d35365SHans de Goede * This needs to be tested on such a board before making this change. 146979d35365SHans de Goede */ 147079d35365SHans de Goede if (!IS_ERR_OR_NULL(bq->usb_phy)) 147179d35365SHans de Goede return; 147279d35365SHans de Goede 147379d35365SHans de Goede /* 147479d35365SHans de Goede * Turn off the 5v Boost regulator which outputs Vbus to the device's 147579d35365SHans de Goede * Micro-USB or Type-C USB port. Leaving this on drains power and 147679d35365SHans de Goede * this avoids the PMIC on some device-models seeing this as Vbus 147779d35365SHans de Goede * getting inserted after shutdown, causing the device to immediately 147879d35365SHans de Goede * power-up again. 147979d35365SHans de Goede */ 148079d35365SHans de Goede bq25890_set_otg_cfg(bq, 0); 148179d35365SHans de Goede } 148279d35365SHans de Goede 14838c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP 14848c0984e5SSebastian Reichel static int bq25890_suspend(struct device *dev) 14858c0984e5SSebastian Reichel { 14868c0984e5SSebastian Reichel struct bq25890_device *bq = dev_get_drvdata(dev); 14878c0984e5SSebastian Reichel 14888c0984e5SSebastian Reichel /* 14898c0984e5SSebastian Reichel * If charger is removed, while in suspend, make sure ADC is diabled 14908c0984e5SSebastian Reichel * since it consumes slightly more power. 14918c0984e5SSebastian Reichel */ 149221d90edaSMichał Mirosław return bq25890_field_write(bq, F_CONV_RATE, 0); 14938c0984e5SSebastian Reichel } 14948c0984e5SSebastian Reichel 14958c0984e5SSebastian Reichel static int bq25890_resume(struct device *dev) 14968c0984e5SSebastian Reichel { 14978c0984e5SSebastian Reichel int ret; 14988c0984e5SSebastian Reichel struct bq25890_device *bq = dev_get_drvdata(dev); 14998c0984e5SSebastian Reichel 150072d9cd9cSMichał Mirosław mutex_lock(&bq->lock); 150172d9cd9cSMichał Mirosław 150272d9cd9cSMichał Mirosław ret = bq25890_get_chip_state(bq, &bq->state); 15038c0984e5SSebastian Reichel if (ret < 0) 1504cf5701bfSDan Carpenter goto unlock; 15058c0984e5SSebastian Reichel 15068c0984e5SSebastian Reichel /* Re-enable ADC only if charger is plugged in. */ 150772d9cd9cSMichał Mirosław if (bq->state.online) { 150821d90edaSMichał Mirosław ret = bq25890_field_write(bq, F_CONV_RATE, 1); 15098c0984e5SSebastian Reichel if (ret < 0) 1510cf5701bfSDan Carpenter goto unlock; 15118c0984e5SSebastian Reichel } 15128c0984e5SSebastian Reichel 15138c0984e5SSebastian Reichel /* signal userspace, maybe state changed while suspended */ 15148c0984e5SSebastian Reichel power_supply_changed(bq->charger); 15158c0984e5SSebastian Reichel 1516cf5701bfSDan Carpenter unlock: 151772d9cd9cSMichał Mirosław mutex_unlock(&bq->lock); 151872d9cd9cSMichał Mirosław 1519cf5701bfSDan Carpenter return ret; 15208c0984e5SSebastian Reichel } 15218c0984e5SSebastian Reichel #endif 15228c0984e5SSebastian Reichel 15238c0984e5SSebastian Reichel static const struct dev_pm_ops bq25890_pm = { 15248c0984e5SSebastian Reichel SET_SYSTEM_SLEEP_PM_OPS(bq25890_suspend, bq25890_resume) 15258c0984e5SSebastian Reichel }; 15268c0984e5SSebastian Reichel 15278c0984e5SSebastian Reichel static const struct i2c_device_id bq25890_i2c_ids[] = { 15288c0984e5SSebastian Reichel { "bq25890", 0 }, 152946aa27e7SYauhen Kharuzhy { "bq25892", 0 }, 153046aa27e7SYauhen Kharuzhy { "bq25895", 0 }, 153146aa27e7SYauhen Kharuzhy { "bq25896", 0 }, 15328c0984e5SSebastian Reichel {}, 15338c0984e5SSebastian Reichel }; 15348c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids); 15358c0984e5SSebastian Reichel 15368c0984e5SSebastian Reichel static const struct of_device_id bq25890_of_match[] = { 15378c0984e5SSebastian Reichel { .compatible = "ti,bq25890", }, 153846aa27e7SYauhen Kharuzhy { .compatible = "ti,bq25892", }, 153946aa27e7SYauhen Kharuzhy { .compatible = "ti,bq25895", }, 154046aa27e7SYauhen Kharuzhy { .compatible = "ti,bq25896", }, 15418c0984e5SSebastian Reichel { }, 15428c0984e5SSebastian Reichel }; 15438c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, bq25890_of_match); 15448c0984e5SSebastian Reichel 154502067dc9SKrzysztof Kozlowski #ifdef CONFIG_ACPI 15468c0984e5SSebastian Reichel static const struct acpi_device_id bq25890_acpi_match[] = { 15478c0984e5SSebastian Reichel {"BQ258900", 0}, 15488c0984e5SSebastian Reichel {}, 15498c0984e5SSebastian Reichel }; 15508c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match); 155102067dc9SKrzysztof Kozlowski #endif 15528c0984e5SSebastian Reichel 15538c0984e5SSebastian Reichel static struct i2c_driver bq25890_driver = { 15548c0984e5SSebastian Reichel .driver = { 15558c0984e5SSebastian Reichel .name = "bq25890-charger", 15568c0984e5SSebastian Reichel .of_match_table = of_match_ptr(bq25890_of_match), 15578c0984e5SSebastian Reichel .acpi_match_table = ACPI_PTR(bq25890_acpi_match), 15588c0984e5SSebastian Reichel .pm = &bq25890_pm, 15598c0984e5SSebastian Reichel }, 1560c5cddca2SUwe Kleine-König .probe_new = bq25890_probe, 15618c0984e5SSebastian Reichel .remove = bq25890_remove, 156279d35365SHans de Goede .shutdown = bq25890_shutdown, 15638c0984e5SSebastian Reichel .id_table = bq25890_i2c_ids, 15648c0984e5SSebastian Reichel }; 15658c0984e5SSebastian Reichel module_i2c_driver(bq25890_driver); 15668c0984e5SSebastian Reichel 15678c0984e5SSebastian Reichel MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>"); 15688c0984e5SSebastian Reichel MODULE_DESCRIPTION("bq25890 charger driver"); 15698c0984e5SSebastian Reichel MODULE_LICENSE("GPL"); 1570