1*8c5795feSHans de Goede // SPDX-License-Identifier: GPL-2.0-only 2*8c5795feSHans de Goede /* 3*8c5795feSHans de Goede * Battery driver for the coulomb-counter of the Intel Dollar Cove TI PMIC 4*8c5795feSHans de Goede * 5*8c5795feSHans de Goede * Note the Intel Dollar Cove TI PMIC coulomb-counter is not a full-featured 6*8c5795feSHans de Goede * autonomous fuel-gauge. It is intended to work together with an always on 7*8c5795feSHans de Goede * micro-controller monitoring it. 8*8c5795feSHans de Goede * 9*8c5795feSHans de Goede * Since Linux does not monitor coulomb-counter changes while the device 10*8c5795feSHans de Goede * is off or suspended, voltage based capacity estimation from 11*8c5795feSHans de Goede * the adc-battery-helper code is used. 12*8c5795feSHans de Goede * 13*8c5795feSHans de Goede * Copyright (C) 2024 Hans de Goede <hansg@kernel.org> 14*8c5795feSHans de Goede * 15*8c5795feSHans de Goede * Register definitions and calibration code was taken from 16*8c5795feSHans de Goede * kernel/drivers/platform/x86/dc_ti_cc.c from the Acer A1-840 Android kernel 17*8c5795feSHans de Goede * which has the following copyright header: 18*8c5795feSHans de Goede * 19*8c5795feSHans de Goede * Copyright (C) 2014 Intel Corporation 20*8c5795feSHans de Goede * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com> 21*8c5795feSHans de Goede * 22*8c5795feSHans de Goede * dc_ti_cc.c is part of the Acer A1-840 Android kernel source-code archive 23*8c5795feSHans de Goede * named: "App. Guide_Acer_20151221_A_A.zip" 24*8c5795feSHans de Goede * which is distributed by Acer from the Acer A1-840 support page: 25*8c5795feSHans de Goede * https://www.acer.com/us-en/support/product-support/A1-840/downloads 26*8c5795feSHans de Goede */ 27*8c5795feSHans de Goede 28*8c5795feSHans de Goede #include <linux/acpi.h> 29*8c5795feSHans de Goede #include <linux/bits.h> 30*8c5795feSHans de Goede #include <linux/bitfield.h> 31*8c5795feSHans de Goede #include <linux/cleanup.h> 32*8c5795feSHans de Goede #include <linux/err.h> 33*8c5795feSHans de Goede #include <linux/gpio/consumer.h> 34*8c5795feSHans de Goede #include <linux/iio/consumer.h> 35*8c5795feSHans de Goede #include <linux/mfd/intel_soc_pmic.h> 36*8c5795feSHans de Goede #include <linux/module.h> 37*8c5795feSHans de Goede #include <linux/platform_device.h> 38*8c5795feSHans de Goede #include <linux/pm_runtime.h> 39*8c5795feSHans de Goede #include <linux/power_supply.h> 40*8c5795feSHans de Goede #include <linux/property.h> 41*8c5795feSHans de Goede #include <linux/regmap.h> 42*8c5795feSHans de Goede #include <linux/timekeeping.h> 43*8c5795feSHans de Goede 44*8c5795feSHans de Goede #include "adc-battery-helper.h" 45*8c5795feSHans de Goede 46*8c5795feSHans de Goede #define DC_TI_PMIC_VERSION_REG 0x00 47*8c5795feSHans de Goede #define PMIC_VERSION_A0 0xC0 48*8c5795feSHans de Goede #define PMIC_VERSION_A1 0xC1 49*8c5795feSHans de Goede 50*8c5795feSHans de Goede #define DC_TI_CC_CNTL_REG 0x60 51*8c5795feSHans de Goede #define CC_CNTL_CC_CTR_EN BIT(0) 52*8c5795feSHans de Goede #define CC_CNTL_CC_CLR_EN BIT(1) 53*8c5795feSHans de Goede #define CC_CNTL_CC_CAL_EN BIT(2) 54*8c5795feSHans de Goede #define CC_CNTL_CC_OFFSET_EN BIT(3) 55*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL GENMASK(5, 4) 56*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL_15MS FIELD_PREP(CC_CNTL_SMPL_INTVL, 0) 57*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL_62MS FIELD_PREP(CC_CNTL_SMPL_INTVL, 1) 58*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL_125MS FIELD_PREP(CC_CNTL_SMPL_INTVL, 2) 59*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL_250MS FIELD_PREP(CC_CNTL_SMPL_INTVL, 3) 60*8c5795feSHans de Goede 61*8c5795feSHans de Goede #define DC_TI_SMPL_CTR0_REG 0x69 62*8c5795feSHans de Goede #define DC_TI_SMPL_CTR1_REG 0x68 63*8c5795feSHans de Goede #define DC_TI_SMPL_CTR2_REG 0x67 64*8c5795feSHans de Goede 65*8c5795feSHans de Goede #define DC_TI_CC_OFFSET_HI_REG 0x61 66*8c5795feSHans de Goede #define CC_OFFSET_HI_MASK 0x3F 67*8c5795feSHans de Goede #define DC_TI_CC_OFFSET_LO_REG 0x62 68*8c5795feSHans de Goede 69*8c5795feSHans de Goede #define DC_TI_SW_OFFSET_REG 0x6C 70*8c5795feSHans de Goede 71*8c5795feSHans de Goede #define DC_TI_CC_ACC3_REG 0x63 72*8c5795feSHans de Goede #define DC_TI_CC_ACC2_REG 0x64 73*8c5795feSHans de Goede #define DC_TI_CC_ACC1_REG 0x65 74*8c5795feSHans de Goede #define DC_TI_CC_ACC0_REG 0x66 75*8c5795feSHans de Goede 76*8c5795feSHans de Goede #define DC_TI_CC_INTG1_REG 0x6A 77*8c5795feSHans de Goede #define DC_TI_CC_INTG1_MASK 0x3F 78*8c5795feSHans de Goede #define DC_TI_CC_INTG0_REG 0x6B 79*8c5795feSHans de Goede 80*8c5795feSHans de Goede #define DC_TI_EEPROM_ACCESS_CONTROL 0x88 81*8c5795feSHans de Goede #define EEPROM_UNLOCK 0xDA 82*8c5795feSHans de Goede #define EEPROM_LOCK 0x00 83*8c5795feSHans de Goede 84*8c5795feSHans de Goede #define DC_TI_EEPROM_CC_GAIN_REG 0xF4 85*8c5795feSHans de Goede #define CC_TRIM_REVISION GENMASK(3, 0) 86*8c5795feSHans de Goede #define CC_GAIN_CORRECTION GENMASK(7, 4) 87*8c5795feSHans de Goede 88*8c5795feSHans de Goede #define PMIC_VERSION_A0_TRIM_REV 3 89*8c5795feSHans de Goede #define PMIC_VERSION_A1_MIN_TRIM_REV 1 90*8c5795feSHans de Goede 91*8c5795feSHans de Goede #define DC_TI_EEPROM_CC_OFFSET_REG 0xFD 92*8c5795feSHans de Goede 93*8c5795feSHans de Goede #define DC_TI_EEPROM_CTRL 0xFE 94*8c5795feSHans de Goede #define EEPROM_BANK0_SEL 0x01 95*8c5795feSHans de Goede #define EEPROM_BANK1_SEL 0x02 96*8c5795feSHans de Goede 97*8c5795feSHans de Goede #define SMPL_INTVL_US 15000 98*8c5795feSHans de Goede #define SMPL_INTVL_MS (SMPL_INTVL_US / USEC_PER_MSEC) 99*8c5795feSHans de Goede #define CALIBRATION_TIME_US (10 * SMPL_INTVL_US) 100*8c5795feSHans de Goede #define SLEEP_SLACK_US 2500 101*8c5795feSHans de Goede 102*8c5795feSHans de Goede /* CC gain correction is in 0.0025 increments */ 103*8c5795feSHans de Goede #define CC_GAIN_STEP 25 104*8c5795feSHans de Goede #define CC_GAIN_DIV 10000 105*8c5795feSHans de Goede 106*8c5795feSHans de Goede /* CC offset is in 0.5 units per 250ms (default sample interval) */ 107*8c5795feSHans de Goede #define CC_OFFSET_DIV 2 108*8c5795feSHans de Goede #define CC_OFFSET_SMPL_INTVL_MS 250 109*8c5795feSHans de Goede 110*8c5795feSHans de Goede /* CC accumulator scale is 366.2 ųCoulumb / unit */ 111*8c5795feSHans de Goede #define CC_ACC_TO_UA(acc, smpl_ctr) \ 112*8c5795feSHans de Goede ((acc) * (3662 * MSEC_PER_SEC / 10) / ((smpl_ctr) * SMPL_INTVL_MS)) 113*8c5795feSHans de Goede 114*8c5795feSHans de Goede #define DEV_NAME "chtdc_ti_battery" 115*8c5795feSHans de Goede 116*8c5795feSHans de Goede struct dc_ti_battery_chip { 117*8c5795feSHans de Goede /* Must be the first member see adc-battery-helper documentation */ 118*8c5795feSHans de Goede struct adc_battery_helper helper; 119*8c5795feSHans de Goede struct device *dev; 120*8c5795feSHans de Goede struct regmap *regmap; 121*8c5795feSHans de Goede struct iio_channel *vbat_channel; 122*8c5795feSHans de Goede struct power_supply *psy; 123*8c5795feSHans de Goede int cc_gain; 124*8c5795feSHans de Goede int cc_offset; 125*8c5795feSHans de Goede }; 126*8c5795feSHans de Goede 127*8c5795feSHans de Goede static int dc_ti_battery_get_voltage_and_current_now(struct power_supply *psy, int *volt, int *curr) 128*8c5795feSHans de Goede { 129*8c5795feSHans de Goede struct dc_ti_battery_chip *chip = power_supply_get_drvdata(psy); 130*8c5795feSHans de Goede s64 cnt_start_usec, now_usec, sleep_usec; 131*8c5795feSHans de Goede unsigned int reg_val; 132*8c5795feSHans de Goede s32 acc, smpl_ctr; 133*8c5795feSHans de Goede int ret; 134*8c5795feSHans de Goede 135*8c5795feSHans de Goede /* 136*8c5795feSHans de Goede * Enable coulomb-counter before reading Vbat from ADC, so that the CC 137*8c5795feSHans de Goede * samples are from the same time period as the Vbat reading. 138*8c5795feSHans de Goede */ 139*8c5795feSHans de Goede ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG, 140*8c5795feSHans de Goede CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN | CC_CNTL_CC_CTR_EN); 141*8c5795feSHans de Goede if (ret) 142*8c5795feSHans de Goede goto out_err; 143*8c5795feSHans de Goede 144*8c5795feSHans de Goede cnt_start_usec = ktime_get_ns() / NSEC_PER_USEC; 145*8c5795feSHans de Goede 146*8c5795feSHans de Goede /* Read Vbat, convert IIO mV to power-supply ųV */ 147*8c5795feSHans de Goede ret = iio_read_channel_processed_scale(chip->vbat_channel, volt, 1000); 148*8c5795feSHans de Goede if (ret < 0) 149*8c5795feSHans de Goede goto out_err; 150*8c5795feSHans de Goede 151*8c5795feSHans de Goede /* Sleep at least 3 sample-times + slack to get 3+ CC samples */ 152*8c5795feSHans de Goede now_usec = ktime_get_ns() / NSEC_PER_USEC; 153*8c5795feSHans de Goede sleep_usec = 3 * SMPL_INTVL_US + SLEEP_SLACK_US - (now_usec - cnt_start_usec); 154*8c5795feSHans de Goede if (sleep_usec > 0 && sleep_usec < 1000000) 155*8c5795feSHans de Goede usleep_range(sleep_usec, sleep_usec + SLEEP_SLACK_US); 156*8c5795feSHans de Goede 157*8c5795feSHans de Goede /* 158*8c5795feSHans de Goede * The PMIC latches the coulomb- and sample-counters upon reading the 159*8c5795feSHans de Goede * CC_ACC0 register. Reading multiple registers at once is not supported. 160*8c5795feSHans de Goede * 161*8c5795feSHans de Goede * Step 1: Read CC_ACC0 - CC_ACC3 162*8c5795feSHans de Goede */ 163*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_CC_ACC0_REG, ®_val); 164*8c5795feSHans de Goede if (ret) 165*8c5795feSHans de Goede goto out_err; 166*8c5795feSHans de Goede 167*8c5795feSHans de Goede acc = reg_val; 168*8c5795feSHans de Goede 169*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_CC_ACC1_REG, ®_val); 170*8c5795feSHans de Goede if (ret) 171*8c5795feSHans de Goede goto out_err; 172*8c5795feSHans de Goede 173*8c5795feSHans de Goede acc |= reg_val << 8; 174*8c5795feSHans de Goede 175*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_CC_ACC2_REG, ®_val); 176*8c5795feSHans de Goede if (ret) 177*8c5795feSHans de Goede goto out_err; 178*8c5795feSHans de Goede 179*8c5795feSHans de Goede acc |= reg_val << 16; 180*8c5795feSHans de Goede 181*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_CC_ACC3_REG, ®_val); 182*8c5795feSHans de Goede if (ret) 183*8c5795feSHans de Goede goto out_err; 184*8c5795feSHans de Goede 185*8c5795feSHans de Goede acc |= reg_val << 24; 186*8c5795feSHans de Goede 187*8c5795feSHans de Goede /* Step 2: Read SMPL_CTR0 - SMPL_CTR2 */ 188*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR0_REG, ®_val); 189*8c5795feSHans de Goede if (ret) 190*8c5795feSHans de Goede goto out_err; 191*8c5795feSHans de Goede 192*8c5795feSHans de Goede smpl_ctr = reg_val; 193*8c5795feSHans de Goede 194*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR1_REG, ®_val); 195*8c5795feSHans de Goede if (ret) 196*8c5795feSHans de Goede goto out_err; 197*8c5795feSHans de Goede 198*8c5795feSHans de Goede smpl_ctr |= reg_val << 8; 199*8c5795feSHans de Goede 200*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR2_REG, ®_val); 201*8c5795feSHans de Goede if (ret) 202*8c5795feSHans de Goede goto out_err; 203*8c5795feSHans de Goede 204*8c5795feSHans de Goede smpl_ctr |= reg_val << 16; 205*8c5795feSHans de Goede 206*8c5795feSHans de Goede /* Disable the coulumb-counter again */ 207*8c5795feSHans de Goede ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG, 208*8c5795feSHans de Goede CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN); 209*8c5795feSHans de Goede if (ret) 210*8c5795feSHans de Goede goto out_err; 211*8c5795feSHans de Goede 212*8c5795feSHans de Goede /* Apply calibration */ 213*8c5795feSHans de Goede acc -= chip->cc_offset * smpl_ctr * SMPL_INTVL_MS / 214*8c5795feSHans de Goede (CC_OFFSET_SMPL_INTVL_MS * CC_OFFSET_DIV); 215*8c5795feSHans de Goede acc = acc * (CC_GAIN_DIV - chip->cc_gain * CC_GAIN_STEP) / CC_GAIN_DIV; 216*8c5795feSHans de Goede *curr = CC_ACC_TO_UA(acc, smpl_ctr); 217*8c5795feSHans de Goede 218*8c5795feSHans de Goede return 0; 219*8c5795feSHans de Goede 220*8c5795feSHans de Goede out_err: 221*8c5795feSHans de Goede dev_err(chip->dev, "IO-error %d communicating with PMIC\n", ret); 222*8c5795feSHans de Goede return ret; 223*8c5795feSHans de Goede } 224*8c5795feSHans de Goede 225*8c5795feSHans de Goede static const struct power_supply_desc dc_ti_battery_psy_desc = { 226*8c5795feSHans de Goede .name = "intel_dc_ti_battery", 227*8c5795feSHans de Goede .type = POWER_SUPPLY_TYPE_BATTERY, 228*8c5795feSHans de Goede .get_property = adc_battery_helper_get_property, 229*8c5795feSHans de Goede .external_power_changed = adc_battery_helper_external_power_changed, 230*8c5795feSHans de Goede .properties = adc_battery_helper_properties, 231*8c5795feSHans de Goede .num_properties = ADC_HELPER_NUM_PROPERTIES, 232*8c5795feSHans de Goede }; 233*8c5795feSHans de Goede 234*8c5795feSHans de Goede static int dc_ti_battery_hw_init(struct dc_ti_battery_chip *chip) 235*8c5795feSHans de Goede { 236*8c5795feSHans de Goede u8 pmic_version, cc_trim_rev; 237*8c5795feSHans de Goede unsigned int reg_val; 238*8c5795feSHans de Goede int ret; 239*8c5795feSHans de Goede 240*8c5795feSHans de Goede /* Set sample rate to 15 ms and calibrate the coulomb-counter */ 241*8c5795feSHans de Goede ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG, 242*8c5795feSHans de Goede CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN | 243*8c5795feSHans de Goede CC_CNTL_CC_CAL_EN | CC_CNTL_CC_CTR_EN); 244*8c5795feSHans de Goede if (ret) 245*8c5795feSHans de Goede goto out; 246*8c5795feSHans de Goede 247*8c5795feSHans de Goede fsleep(CALIBRATION_TIME_US); 248*8c5795feSHans de Goede 249*8c5795feSHans de Goede /* Disable coulomb-counter it is only used while getting the current */ 250*8c5795feSHans de Goede ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG, 251*8c5795feSHans de Goede CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN); 252*8c5795feSHans de Goede if (ret) 253*8c5795feSHans de Goede goto out; 254*8c5795feSHans de Goede 255*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_PMIC_VERSION_REG, ®_val); 256*8c5795feSHans de Goede if (ret) 257*8c5795feSHans de Goede goto out; 258*8c5795feSHans de Goede 259*8c5795feSHans de Goede pmic_version = reg_val; 260*8c5795feSHans de Goede 261*8c5795feSHans de Goede /* 262*8c5795feSHans de Goede * As per the PMIC vendor (TI), the calibration offset and gain err 263*8c5795feSHans de Goede * values are stored in EEPROM Bank 0 and Bank 1 of the PMIC. 264*8c5795feSHans de Goede * We need to read the stored offset and gain margins and need 265*8c5795feSHans de Goede * to apply the corrections to the raw coulomb counter value. 266*8c5795feSHans de Goede */ 267*8c5795feSHans de Goede 268*8c5795feSHans de Goede /* Unlock the EEPROM Access */ 269*8c5795feSHans de Goede ret = regmap_write(chip->regmap, DC_TI_EEPROM_ACCESS_CONTROL, EEPROM_UNLOCK); 270*8c5795feSHans de Goede if (ret) 271*8c5795feSHans de Goede goto out; 272*8c5795feSHans de Goede 273*8c5795feSHans de Goede /* Select Bank 1 to read CC GAIN Err correction */ 274*8c5795feSHans de Goede ret = regmap_write(chip->regmap, DC_TI_EEPROM_CTRL, EEPROM_BANK1_SEL); 275*8c5795feSHans de Goede if (ret) 276*8c5795feSHans de Goede goto out; 277*8c5795feSHans de Goede 278*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_EEPROM_CC_GAIN_REG, ®_val); 279*8c5795feSHans de Goede if (ret) 280*8c5795feSHans de Goede goto out; 281*8c5795feSHans de Goede 282*8c5795feSHans de Goede cc_trim_rev = FIELD_GET(CC_TRIM_REVISION, reg_val); 283*8c5795feSHans de Goede 284*8c5795feSHans de Goede dev_dbg(chip->dev, "pmic-ver 0x%02x trim-rev %d\n", pmic_version, cc_trim_rev); 285*8c5795feSHans de Goede 286*8c5795feSHans de Goede if (!(pmic_version == PMIC_VERSION_A0 && cc_trim_rev == PMIC_VERSION_A0_TRIM_REV) && 287*8c5795feSHans de Goede !(pmic_version == PMIC_VERSION_A1 && cc_trim_rev >= PMIC_VERSION_A1_MIN_TRIM_REV)) { 288*8c5795feSHans de Goede dev_dbg(chip->dev, "unsupported trim-revision, using uncalibrated CC values\n"); 289*8c5795feSHans de Goede goto out_relock; 290*8c5795feSHans de Goede } 291*8c5795feSHans de Goede 292*8c5795feSHans de Goede chip->cc_gain = 1 - (int)FIELD_GET(CC_GAIN_CORRECTION, reg_val); 293*8c5795feSHans de Goede 294*8c5795feSHans de Goede /* Select Bank 0 to read CC OFFSET Correction */ 295*8c5795feSHans de Goede ret = regmap_write(chip->regmap, DC_TI_EEPROM_CTRL, EEPROM_BANK0_SEL); 296*8c5795feSHans de Goede if (ret) 297*8c5795feSHans de Goede goto out_relock; 298*8c5795feSHans de Goede 299*8c5795feSHans de Goede ret = regmap_read(chip->regmap, DC_TI_EEPROM_CC_OFFSET_REG, ®_val); 300*8c5795feSHans de Goede if (ret) 301*8c5795feSHans de Goede goto out_relock; 302*8c5795feSHans de Goede 303*8c5795feSHans de Goede chip->cc_offset = (s8)reg_val; 304*8c5795feSHans de Goede 305*8c5795feSHans de Goede dev_dbg(chip->dev, "cc-offset %d cc-gain %d\n", chip->cc_offset, chip->cc_gain); 306*8c5795feSHans de Goede 307*8c5795feSHans de Goede out_relock: 308*8c5795feSHans de Goede /* Re-lock the EEPROM Access */ 309*8c5795feSHans de Goede regmap_write(chip->regmap, DC_TI_EEPROM_ACCESS_CONTROL, EEPROM_LOCK); 310*8c5795feSHans de Goede out: 311*8c5795feSHans de Goede if (ret) 312*8c5795feSHans de Goede dev_err(chip->dev, "IO-error %d initializing PMIC\n", ret); 313*8c5795feSHans de Goede 314*8c5795feSHans de Goede return ret; 315*8c5795feSHans de Goede } 316*8c5795feSHans de Goede 317*8c5795feSHans de Goede static int dc_ti_battery_probe(struct platform_device *pdev) 318*8c5795feSHans de Goede { 319*8c5795feSHans de Goede struct device *dev = &pdev->dev; 320*8c5795feSHans de Goede struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent); 321*8c5795feSHans de Goede struct power_supply_config psy_cfg = {}; 322*8c5795feSHans de Goede struct fwnode_reference_args args; 323*8c5795feSHans de Goede struct gpio_desc *charge_finished; 324*8c5795feSHans de Goede struct dc_ti_battery_chip *chip; 325*8c5795feSHans de Goede int ret; 326*8c5795feSHans de Goede 327*8c5795feSHans de Goede /* On most devices with a Dollar Cove TI the battery is handled by ACPI */ 328*8c5795feSHans de Goede if (!acpi_quirk_skip_acpi_ac_and_battery()) 329*8c5795feSHans de Goede return -ENODEV; 330*8c5795feSHans de Goede 331*8c5795feSHans de Goede /* ACPI glue code adds a "monitored-battery" fwnode, wait for this */ 332*8c5795feSHans de Goede ret = fwnode_property_get_reference_args(dev_fwnode(dev), "monitored-battery", 333*8c5795feSHans de Goede NULL, 0, 0, &args); 334*8c5795feSHans de Goede if (ret) { 335*8c5795feSHans de Goede dev_dbg(dev, "fwnode_property_get_ref() ret %d\n", ret); 336*8c5795feSHans de Goede return dev_err_probe(dev, -EPROBE_DEFER, "Waiting for monitored-battery fwnode\n"); 337*8c5795feSHans de Goede } 338*8c5795feSHans de Goede 339*8c5795feSHans de Goede fwnode_handle_put(args.fwnode); 340*8c5795feSHans de Goede 341*8c5795feSHans de Goede chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 342*8c5795feSHans de Goede if (!chip) 343*8c5795feSHans de Goede return -ENOMEM; 344*8c5795feSHans de Goede 345*8c5795feSHans de Goede chip->dev = dev; 346*8c5795feSHans de Goede chip->regmap = pmic->regmap; 347*8c5795feSHans de Goede 348*8c5795feSHans de Goede chip->vbat_channel = devm_iio_channel_get(dev, "VBAT"); 349*8c5795feSHans de Goede if (IS_ERR(chip->vbat_channel)) { 350*8c5795feSHans de Goede dev_dbg(dev, "devm_iio_channel_get() ret %ld\n", PTR_ERR(chip->vbat_channel)); 351*8c5795feSHans de Goede return dev_err_probe(dev, -EPROBE_DEFER, "Waiting for VBAT IIO channel\n"); 352*8c5795feSHans de Goede } 353*8c5795feSHans de Goede 354*8c5795feSHans de Goede charge_finished = devm_gpiod_get_optional(dev, "charged", GPIOD_IN); 355*8c5795feSHans de Goede if (IS_ERR(charge_finished)) 356*8c5795feSHans de Goede return dev_err_probe(dev, PTR_ERR(charge_finished), "Getting charged GPIO\n"); 357*8c5795feSHans de Goede 358*8c5795feSHans de Goede ret = dc_ti_battery_hw_init(chip); 359*8c5795feSHans de Goede if (ret) 360*8c5795feSHans de Goede return ret; 361*8c5795feSHans de Goede 362*8c5795feSHans de Goede platform_set_drvdata(pdev, chip); 363*8c5795feSHans de Goede 364*8c5795feSHans de Goede psy_cfg.drv_data = chip; 365*8c5795feSHans de Goede chip->psy = devm_power_supply_register(dev, &dc_ti_battery_psy_desc, &psy_cfg); 366*8c5795feSHans de Goede if (IS_ERR(chip->psy)) 367*8c5795feSHans de Goede return PTR_ERR(chip->psy); 368*8c5795feSHans de Goede 369*8c5795feSHans de Goede return adc_battery_helper_init(&chip->helper, chip->psy, 370*8c5795feSHans de Goede dc_ti_battery_get_voltage_and_current_now, 371*8c5795feSHans de Goede charge_finished); 372*8c5795feSHans de Goede } 373*8c5795feSHans de Goede 374*8c5795feSHans de Goede static DEFINE_RUNTIME_DEV_PM_OPS(dc_ti_battery_pm_ops, adc_battery_helper_suspend, 375*8c5795feSHans de Goede adc_battery_helper_resume, NULL); 376*8c5795feSHans de Goede 377*8c5795feSHans de Goede static struct platform_driver dc_ti_battery_driver = { 378*8c5795feSHans de Goede .driver = { 379*8c5795feSHans de Goede .name = DEV_NAME, 380*8c5795feSHans de Goede .pm = pm_sleep_ptr(&dc_ti_battery_pm_ops), 381*8c5795feSHans de Goede }, 382*8c5795feSHans de Goede .probe = dc_ti_battery_probe, 383*8c5795feSHans de Goede }; 384*8c5795feSHans de Goede module_platform_driver(dc_ti_battery_driver); 385*8c5795feSHans de Goede 386*8c5795feSHans de Goede MODULE_ALIAS("platform:" DEV_NAME); 387*8c5795feSHans de Goede MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); 388*8c5795feSHans de Goede MODULE_DESCRIPTION("Intel Dollar Cove (TI) battery driver"); 389*8c5795feSHans de Goede MODULE_LICENSE("GPL"); 390