1*195ca170SBaolin Wang // SPDX-License-Identifier: GPL-2.0 2*195ca170SBaolin Wang // Copyright (C) 2018 Spreadtrum Communications Inc. 3*195ca170SBaolin Wang 4*195ca170SBaolin Wang #include <linux/gpio/consumer.h> 5*195ca170SBaolin Wang #include <linux/iio/consumer.h> 6*195ca170SBaolin Wang #include <linux/interrupt.h> 7*195ca170SBaolin Wang #include <linux/kernel.h> 8*195ca170SBaolin Wang #include <linux/module.h> 9*195ca170SBaolin Wang #include <linux/of.h> 10*195ca170SBaolin Wang #include <linux/platform_device.h> 11*195ca170SBaolin Wang #include <linux/power_supply.h> 12*195ca170SBaolin Wang #include <linux/regmap.h> 13*195ca170SBaolin Wang 14*195ca170SBaolin Wang /* PMIC global control registers definition */ 15*195ca170SBaolin Wang #define SC27XX_MODULE_EN0 0xc08 16*195ca170SBaolin Wang #define SC27XX_CLK_EN0 0xc18 17*195ca170SBaolin Wang #define SC27XX_FGU_EN BIT(7) 18*195ca170SBaolin Wang #define SC27XX_FGU_RTC_EN BIT(6) 19*195ca170SBaolin Wang 20*195ca170SBaolin Wang /* FGU registers definition */ 21*195ca170SBaolin Wang #define SC27XX_FGU_START 0x0 22*195ca170SBaolin Wang #define SC27XX_FGU_CONFIG 0x4 23*195ca170SBaolin Wang #define SC27XX_FGU_ADC_CONFIG 0x8 24*195ca170SBaolin Wang #define SC27XX_FGU_STATUS 0xc 25*195ca170SBaolin Wang #define SC27XX_FGU_INT_EN 0x10 26*195ca170SBaolin Wang #define SC27XX_FGU_INT_CLR 0x14 27*195ca170SBaolin Wang #define SC27XX_FGU_INT_STS 0x1c 28*195ca170SBaolin Wang #define SC27XX_FGU_VOLTAGE 0x20 29*195ca170SBaolin Wang #define SC27XX_FGU_OCV 0x24 30*195ca170SBaolin Wang #define SC27XX_FGU_POCV 0x28 31*195ca170SBaolin Wang #define SC27XX_FGU_CURRENT 0x2c 32*195ca170SBaolin Wang #define SC27XX_FGU_CLBCNT_SETH 0x50 33*195ca170SBaolin Wang #define SC27XX_FGU_CLBCNT_SETL 0x54 34*195ca170SBaolin Wang #define SC27XX_FGU_CLBCNT_VALH 0x68 35*195ca170SBaolin Wang #define SC27XX_FGU_CLBCNT_VALL 0x6c 36*195ca170SBaolin Wang #define SC27XX_FGU_CLBCNT_QMAXL 0x74 37*195ca170SBaolin Wang 38*195ca170SBaolin Wang #define SC27XX_WRITE_SELCLB_EN BIT(0) 39*195ca170SBaolin Wang #define SC27XX_FGU_CLBCNT_MASK GENMASK(15, 0) 40*195ca170SBaolin Wang #define SC27XX_FGU_CLBCNT_SHIFT 16 41*195ca170SBaolin Wang 42*195ca170SBaolin Wang #define SC27XX_FGU_1000MV_ADC 686 43*195ca170SBaolin Wang #define SC27XX_FGU_1000MA_ADC 1372 44*195ca170SBaolin Wang #define SC27XX_FGU_CUR_BASIC_ADC 8192 45*195ca170SBaolin Wang #define SC27XX_FGU_SAMPLE_HZ 2 46*195ca170SBaolin Wang 47*195ca170SBaolin Wang /* 48*195ca170SBaolin Wang * struct sc27xx_fgu_data: describe the FGU device 49*195ca170SBaolin Wang * @regmap: regmap for register access 50*195ca170SBaolin Wang * @dev: platform device 51*195ca170SBaolin Wang * @battery: battery power supply 52*195ca170SBaolin Wang * @base: the base offset for the controller 53*195ca170SBaolin Wang * @lock: protect the structure 54*195ca170SBaolin Wang * @gpiod: GPIO for battery detection 55*195ca170SBaolin Wang * @channel: IIO channel to get battery temperature 56*195ca170SBaolin Wang * @internal_resist: the battery internal resistance in mOhm 57*195ca170SBaolin Wang * @total_cap: the total capacity of the battery in mAh 58*195ca170SBaolin Wang * @init_cap: the initial capacity of the battery in mAh 59*195ca170SBaolin Wang * @init_clbcnt: the initial coulomb counter 60*195ca170SBaolin Wang * @max_volt: the maximum constant input voltage in millivolt 61*195ca170SBaolin Wang * @table_len: the capacity table length 62*195ca170SBaolin Wang * @cap_table: capacity table with corresponding ocv 63*195ca170SBaolin Wang */ 64*195ca170SBaolin Wang struct sc27xx_fgu_data { 65*195ca170SBaolin Wang struct regmap *regmap; 66*195ca170SBaolin Wang struct device *dev; 67*195ca170SBaolin Wang struct power_supply *battery; 68*195ca170SBaolin Wang u32 base; 69*195ca170SBaolin Wang struct mutex lock; 70*195ca170SBaolin Wang struct gpio_desc *gpiod; 71*195ca170SBaolin Wang struct iio_channel *channel; 72*195ca170SBaolin Wang bool bat_present; 73*195ca170SBaolin Wang int internal_resist; 74*195ca170SBaolin Wang int total_cap; 75*195ca170SBaolin Wang int init_cap; 76*195ca170SBaolin Wang int init_clbcnt; 77*195ca170SBaolin Wang int max_volt; 78*195ca170SBaolin Wang int table_len; 79*195ca170SBaolin Wang struct power_supply_battery_ocv_table *cap_table; 80*195ca170SBaolin Wang }; 81*195ca170SBaolin Wang 82*195ca170SBaolin Wang static const char * const sc27xx_charger_supply_name[] = { 83*195ca170SBaolin Wang "sc2731_charger", 84*195ca170SBaolin Wang "sc2720_charger", 85*195ca170SBaolin Wang "sc2721_charger", 86*195ca170SBaolin Wang "sc2723_charger", 87*195ca170SBaolin Wang }; 88*195ca170SBaolin Wang 89*195ca170SBaolin Wang static int sc27xx_fgu_adc_to_current(int adc) 90*195ca170SBaolin Wang { 91*195ca170SBaolin Wang return DIV_ROUND_CLOSEST(adc * 1000, SC27XX_FGU_1000MA_ADC); 92*195ca170SBaolin Wang } 93*195ca170SBaolin Wang 94*195ca170SBaolin Wang static int sc27xx_fgu_adc_to_voltage(int adc) 95*195ca170SBaolin Wang { 96*195ca170SBaolin Wang return DIV_ROUND_CLOSEST(adc * 1000, SC27XX_FGU_1000MV_ADC); 97*195ca170SBaolin Wang } 98*195ca170SBaolin Wang 99*195ca170SBaolin Wang /* 100*195ca170SBaolin Wang * When system boots on, we can not read battery capacity from coulomb 101*195ca170SBaolin Wang * registers, since now the coulomb registers are invalid. So we should 102*195ca170SBaolin Wang * calculate the battery open circuit voltage, and get current battery 103*195ca170SBaolin Wang * capacity according to the capacity table. 104*195ca170SBaolin Wang */ 105*195ca170SBaolin Wang static int sc27xx_fgu_get_boot_capacity(struct sc27xx_fgu_data *data, int *cap) 106*195ca170SBaolin Wang { 107*195ca170SBaolin Wang int volt, cur, oci, ocv, ret; 108*195ca170SBaolin Wang 109*195ca170SBaolin Wang /* 110*195ca170SBaolin Wang * After system booting on, the SC27XX_FGU_CLBCNT_QMAXL register saved 111*195ca170SBaolin Wang * the first sampled open circuit current. 112*195ca170SBaolin Wang */ 113*195ca170SBaolin Wang ret = regmap_read(data->regmap, data->base + SC27XX_FGU_CLBCNT_QMAXL, 114*195ca170SBaolin Wang &cur); 115*195ca170SBaolin Wang if (ret) 116*195ca170SBaolin Wang return ret; 117*195ca170SBaolin Wang 118*195ca170SBaolin Wang cur <<= 1; 119*195ca170SBaolin Wang oci = sc27xx_fgu_adc_to_current(cur - SC27XX_FGU_CUR_BASIC_ADC); 120*195ca170SBaolin Wang 121*195ca170SBaolin Wang /* 122*195ca170SBaolin Wang * Should get the OCV from SC27XX_FGU_POCV register at the system 123*195ca170SBaolin Wang * beginning. It is ADC values reading from registers which need to 124*195ca170SBaolin Wang * convert the corresponding voltage. 125*195ca170SBaolin Wang */ 126*195ca170SBaolin Wang ret = regmap_read(data->regmap, data->base + SC27XX_FGU_POCV, &volt); 127*195ca170SBaolin Wang if (ret) 128*195ca170SBaolin Wang return ret; 129*195ca170SBaolin Wang 130*195ca170SBaolin Wang volt = sc27xx_fgu_adc_to_voltage(volt); 131*195ca170SBaolin Wang ocv = volt * 1000 - oci * data->internal_resist; 132*195ca170SBaolin Wang 133*195ca170SBaolin Wang /* 134*195ca170SBaolin Wang * Parse the capacity table to look up the correct capacity percent 135*195ca170SBaolin Wang * according to current battery's corresponding OCV values. 136*195ca170SBaolin Wang */ 137*195ca170SBaolin Wang *cap = power_supply_ocv2cap_simple(data->cap_table, data->table_len, 138*195ca170SBaolin Wang ocv); 139*195ca170SBaolin Wang 140*195ca170SBaolin Wang return 0; 141*195ca170SBaolin Wang } 142*195ca170SBaolin Wang 143*195ca170SBaolin Wang static int sc27xx_fgu_set_clbcnt(struct sc27xx_fgu_data *data, int clbcnt) 144*195ca170SBaolin Wang { 145*195ca170SBaolin Wang int ret; 146*195ca170SBaolin Wang 147*195ca170SBaolin Wang clbcnt *= SC27XX_FGU_SAMPLE_HZ; 148*195ca170SBaolin Wang 149*195ca170SBaolin Wang ret = regmap_update_bits(data->regmap, 150*195ca170SBaolin Wang data->base + SC27XX_FGU_CLBCNT_SETL, 151*195ca170SBaolin Wang SC27XX_FGU_CLBCNT_MASK, clbcnt); 152*195ca170SBaolin Wang if (ret) 153*195ca170SBaolin Wang return ret; 154*195ca170SBaolin Wang 155*195ca170SBaolin Wang ret = regmap_update_bits(data->regmap, 156*195ca170SBaolin Wang data->base + SC27XX_FGU_CLBCNT_SETH, 157*195ca170SBaolin Wang SC27XX_FGU_CLBCNT_MASK, 158*195ca170SBaolin Wang clbcnt >> SC27XX_FGU_CLBCNT_SHIFT); 159*195ca170SBaolin Wang if (ret) 160*195ca170SBaolin Wang return ret; 161*195ca170SBaolin Wang 162*195ca170SBaolin Wang return regmap_update_bits(data->regmap, data->base + SC27XX_FGU_START, 163*195ca170SBaolin Wang SC27XX_WRITE_SELCLB_EN, 164*195ca170SBaolin Wang SC27XX_WRITE_SELCLB_EN); 165*195ca170SBaolin Wang } 166*195ca170SBaolin Wang 167*195ca170SBaolin Wang static int sc27xx_fgu_get_clbcnt(struct sc27xx_fgu_data *data, int *clb_cnt) 168*195ca170SBaolin Wang { 169*195ca170SBaolin Wang int ccl, cch, ret; 170*195ca170SBaolin Wang 171*195ca170SBaolin Wang ret = regmap_read(data->regmap, data->base + SC27XX_FGU_CLBCNT_VALL, 172*195ca170SBaolin Wang &ccl); 173*195ca170SBaolin Wang if (ret) 174*195ca170SBaolin Wang return ret; 175*195ca170SBaolin Wang 176*195ca170SBaolin Wang ret = regmap_read(data->regmap, data->base + SC27XX_FGU_CLBCNT_VALH, 177*195ca170SBaolin Wang &cch); 178*195ca170SBaolin Wang if (ret) 179*195ca170SBaolin Wang return ret; 180*195ca170SBaolin Wang 181*195ca170SBaolin Wang *clb_cnt = ccl & SC27XX_FGU_CLBCNT_MASK; 182*195ca170SBaolin Wang *clb_cnt |= (cch & SC27XX_FGU_CLBCNT_MASK) << SC27XX_FGU_CLBCNT_SHIFT; 183*195ca170SBaolin Wang *clb_cnt /= SC27XX_FGU_SAMPLE_HZ; 184*195ca170SBaolin Wang 185*195ca170SBaolin Wang return 0; 186*195ca170SBaolin Wang } 187*195ca170SBaolin Wang 188*195ca170SBaolin Wang static int sc27xx_fgu_get_capacity(struct sc27xx_fgu_data *data, int *cap) 189*195ca170SBaolin Wang { 190*195ca170SBaolin Wang int ret, cur_clbcnt, delta_clbcnt, delta_cap, temp; 191*195ca170SBaolin Wang 192*195ca170SBaolin Wang /* Get current coulomb counters firstly */ 193*195ca170SBaolin Wang ret = sc27xx_fgu_get_clbcnt(data, &cur_clbcnt); 194*195ca170SBaolin Wang if (ret) 195*195ca170SBaolin Wang return ret; 196*195ca170SBaolin Wang 197*195ca170SBaolin Wang delta_clbcnt = cur_clbcnt - data->init_clbcnt; 198*195ca170SBaolin Wang 199*195ca170SBaolin Wang /* 200*195ca170SBaolin Wang * Convert coulomb counter to delta capacity (mAh), and set multiplier 201*195ca170SBaolin Wang * as 100 to improve the precision. 202*195ca170SBaolin Wang */ 203*195ca170SBaolin Wang temp = DIV_ROUND_CLOSEST(delta_clbcnt, 360); 204*195ca170SBaolin Wang temp = sc27xx_fgu_adc_to_current(temp); 205*195ca170SBaolin Wang 206*195ca170SBaolin Wang /* 207*195ca170SBaolin Wang * Convert to capacity percent of the battery total capacity, 208*195ca170SBaolin Wang * and multiplier is 100 too. 209*195ca170SBaolin Wang */ 210*195ca170SBaolin Wang delta_cap = DIV_ROUND_CLOSEST(temp * 100, data->total_cap); 211*195ca170SBaolin Wang *cap = delta_cap + data->init_cap; 212*195ca170SBaolin Wang 213*195ca170SBaolin Wang return 0; 214*195ca170SBaolin Wang } 215*195ca170SBaolin Wang 216*195ca170SBaolin Wang static int sc27xx_fgu_get_vbat_vol(struct sc27xx_fgu_data *data, int *val) 217*195ca170SBaolin Wang { 218*195ca170SBaolin Wang int ret, vol; 219*195ca170SBaolin Wang 220*195ca170SBaolin Wang ret = regmap_read(data->regmap, data->base + SC27XX_FGU_VOLTAGE, &vol); 221*195ca170SBaolin Wang if (ret) 222*195ca170SBaolin Wang return ret; 223*195ca170SBaolin Wang 224*195ca170SBaolin Wang /* 225*195ca170SBaolin Wang * It is ADC values reading from registers which need to convert to 226*195ca170SBaolin Wang * corresponding voltage values. 227*195ca170SBaolin Wang */ 228*195ca170SBaolin Wang *val = sc27xx_fgu_adc_to_voltage(vol); 229*195ca170SBaolin Wang 230*195ca170SBaolin Wang return 0; 231*195ca170SBaolin Wang } 232*195ca170SBaolin Wang 233*195ca170SBaolin Wang static int sc27xx_fgu_get_current(struct sc27xx_fgu_data *data, int *val) 234*195ca170SBaolin Wang { 235*195ca170SBaolin Wang int ret, cur; 236*195ca170SBaolin Wang 237*195ca170SBaolin Wang ret = regmap_read(data->regmap, data->base + SC27XX_FGU_CURRENT, &cur); 238*195ca170SBaolin Wang if (ret) 239*195ca170SBaolin Wang return ret; 240*195ca170SBaolin Wang 241*195ca170SBaolin Wang /* 242*195ca170SBaolin Wang * It is ADC values reading from registers which need to convert to 243*195ca170SBaolin Wang * corresponding current values. 244*195ca170SBaolin Wang */ 245*195ca170SBaolin Wang *val = sc27xx_fgu_adc_to_current(cur - SC27XX_FGU_CUR_BASIC_ADC); 246*195ca170SBaolin Wang 247*195ca170SBaolin Wang return 0; 248*195ca170SBaolin Wang } 249*195ca170SBaolin Wang 250*195ca170SBaolin Wang static int sc27xx_fgu_get_vbat_ocv(struct sc27xx_fgu_data *data, int *val) 251*195ca170SBaolin Wang { 252*195ca170SBaolin Wang int vol, cur, ret; 253*195ca170SBaolin Wang 254*195ca170SBaolin Wang ret = sc27xx_fgu_get_vbat_vol(data, &vol); 255*195ca170SBaolin Wang if (ret) 256*195ca170SBaolin Wang return ret; 257*195ca170SBaolin Wang 258*195ca170SBaolin Wang ret = sc27xx_fgu_get_current(data, &cur); 259*195ca170SBaolin Wang if (ret) 260*195ca170SBaolin Wang return ret; 261*195ca170SBaolin Wang 262*195ca170SBaolin Wang /* Return the battery OCV in micro volts. */ 263*195ca170SBaolin Wang *val = vol * 1000 - cur * data->internal_resist; 264*195ca170SBaolin Wang 265*195ca170SBaolin Wang return 0; 266*195ca170SBaolin Wang } 267*195ca170SBaolin Wang 268*195ca170SBaolin Wang static int sc27xx_fgu_get_temp(struct sc27xx_fgu_data *data, int *temp) 269*195ca170SBaolin Wang { 270*195ca170SBaolin Wang return iio_read_channel_processed(data->channel, temp); 271*195ca170SBaolin Wang } 272*195ca170SBaolin Wang 273*195ca170SBaolin Wang static int sc27xx_fgu_get_health(struct sc27xx_fgu_data *data, int *health) 274*195ca170SBaolin Wang { 275*195ca170SBaolin Wang int ret, vol; 276*195ca170SBaolin Wang 277*195ca170SBaolin Wang ret = sc27xx_fgu_get_vbat_vol(data, &vol); 278*195ca170SBaolin Wang if (ret) 279*195ca170SBaolin Wang return ret; 280*195ca170SBaolin Wang 281*195ca170SBaolin Wang if (vol > data->max_volt) 282*195ca170SBaolin Wang *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 283*195ca170SBaolin Wang else 284*195ca170SBaolin Wang *health = POWER_SUPPLY_HEALTH_GOOD; 285*195ca170SBaolin Wang 286*195ca170SBaolin Wang return 0; 287*195ca170SBaolin Wang } 288*195ca170SBaolin Wang 289*195ca170SBaolin Wang static int sc27xx_fgu_get_status(struct sc27xx_fgu_data *data, int *status) 290*195ca170SBaolin Wang { 291*195ca170SBaolin Wang union power_supply_propval val; 292*195ca170SBaolin Wang struct power_supply *psy; 293*195ca170SBaolin Wang int i, ret = -EINVAL; 294*195ca170SBaolin Wang 295*195ca170SBaolin Wang for (i = 0; i < ARRAY_SIZE(sc27xx_charger_supply_name); i++) { 296*195ca170SBaolin Wang psy = power_supply_get_by_name(sc27xx_charger_supply_name[i]); 297*195ca170SBaolin Wang if (!psy) 298*195ca170SBaolin Wang continue; 299*195ca170SBaolin Wang 300*195ca170SBaolin Wang ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_STATUS, 301*195ca170SBaolin Wang &val); 302*195ca170SBaolin Wang power_supply_put(psy); 303*195ca170SBaolin Wang if (ret) 304*195ca170SBaolin Wang return ret; 305*195ca170SBaolin Wang 306*195ca170SBaolin Wang *status = val.intval; 307*195ca170SBaolin Wang } 308*195ca170SBaolin Wang 309*195ca170SBaolin Wang return ret; 310*195ca170SBaolin Wang } 311*195ca170SBaolin Wang 312*195ca170SBaolin Wang static int sc27xx_fgu_get_property(struct power_supply *psy, 313*195ca170SBaolin Wang enum power_supply_property psp, 314*195ca170SBaolin Wang union power_supply_propval *val) 315*195ca170SBaolin Wang { 316*195ca170SBaolin Wang struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy); 317*195ca170SBaolin Wang int ret = 0; 318*195ca170SBaolin Wang int value; 319*195ca170SBaolin Wang 320*195ca170SBaolin Wang mutex_lock(&data->lock); 321*195ca170SBaolin Wang 322*195ca170SBaolin Wang switch (psp) { 323*195ca170SBaolin Wang case POWER_SUPPLY_PROP_STATUS: 324*195ca170SBaolin Wang ret = sc27xx_fgu_get_status(data, &value); 325*195ca170SBaolin Wang if (ret) 326*195ca170SBaolin Wang goto error; 327*195ca170SBaolin Wang 328*195ca170SBaolin Wang val->intval = value; 329*195ca170SBaolin Wang break; 330*195ca170SBaolin Wang 331*195ca170SBaolin Wang case POWER_SUPPLY_PROP_HEALTH: 332*195ca170SBaolin Wang ret = sc27xx_fgu_get_health(data, &value); 333*195ca170SBaolin Wang if (ret) 334*195ca170SBaolin Wang goto error; 335*195ca170SBaolin Wang 336*195ca170SBaolin Wang val->intval = value; 337*195ca170SBaolin Wang break; 338*195ca170SBaolin Wang 339*195ca170SBaolin Wang case POWER_SUPPLY_PROP_PRESENT: 340*195ca170SBaolin Wang val->intval = data->bat_present; 341*195ca170SBaolin Wang break; 342*195ca170SBaolin Wang 343*195ca170SBaolin Wang case POWER_SUPPLY_PROP_TEMP: 344*195ca170SBaolin Wang ret = sc27xx_fgu_get_temp(data, &value); 345*195ca170SBaolin Wang if (ret) 346*195ca170SBaolin Wang goto error; 347*195ca170SBaolin Wang 348*195ca170SBaolin Wang val->intval = value; 349*195ca170SBaolin Wang break; 350*195ca170SBaolin Wang 351*195ca170SBaolin Wang case POWER_SUPPLY_PROP_TECHNOLOGY: 352*195ca170SBaolin Wang val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 353*195ca170SBaolin Wang break; 354*195ca170SBaolin Wang 355*195ca170SBaolin Wang case POWER_SUPPLY_PROP_CAPACITY: 356*195ca170SBaolin Wang ret = sc27xx_fgu_get_capacity(data, &value); 357*195ca170SBaolin Wang if (ret) 358*195ca170SBaolin Wang goto error; 359*195ca170SBaolin Wang 360*195ca170SBaolin Wang val->intval = value; 361*195ca170SBaolin Wang break; 362*195ca170SBaolin Wang 363*195ca170SBaolin Wang case POWER_SUPPLY_PROP_VOLTAGE_NOW: 364*195ca170SBaolin Wang ret = sc27xx_fgu_get_vbat_vol(data, &value); 365*195ca170SBaolin Wang if (ret) 366*195ca170SBaolin Wang goto error; 367*195ca170SBaolin Wang 368*195ca170SBaolin Wang val->intval = value * 1000; 369*195ca170SBaolin Wang break; 370*195ca170SBaolin Wang 371*195ca170SBaolin Wang case POWER_SUPPLY_PROP_VOLTAGE_OCV: 372*195ca170SBaolin Wang ret = sc27xx_fgu_get_vbat_ocv(data, &value); 373*195ca170SBaolin Wang if (ret) 374*195ca170SBaolin Wang goto error; 375*195ca170SBaolin Wang 376*195ca170SBaolin Wang val->intval = value; 377*195ca170SBaolin Wang break; 378*195ca170SBaolin Wang 379*195ca170SBaolin Wang case POWER_SUPPLY_PROP_CURRENT_NOW: 380*195ca170SBaolin Wang case POWER_SUPPLY_PROP_CURRENT_AVG: 381*195ca170SBaolin Wang ret = sc27xx_fgu_get_current(data, &value); 382*195ca170SBaolin Wang if (ret) 383*195ca170SBaolin Wang goto error; 384*195ca170SBaolin Wang 385*195ca170SBaolin Wang val->intval = value * 1000; 386*195ca170SBaolin Wang break; 387*195ca170SBaolin Wang 388*195ca170SBaolin Wang default: 389*195ca170SBaolin Wang ret = -EINVAL; 390*195ca170SBaolin Wang break; 391*195ca170SBaolin Wang } 392*195ca170SBaolin Wang 393*195ca170SBaolin Wang error: 394*195ca170SBaolin Wang mutex_unlock(&data->lock); 395*195ca170SBaolin Wang return ret; 396*195ca170SBaolin Wang } 397*195ca170SBaolin Wang 398*195ca170SBaolin Wang static void sc27xx_fgu_external_power_changed(struct power_supply *psy) 399*195ca170SBaolin Wang { 400*195ca170SBaolin Wang struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy); 401*195ca170SBaolin Wang 402*195ca170SBaolin Wang power_supply_changed(data->battery); 403*195ca170SBaolin Wang } 404*195ca170SBaolin Wang 405*195ca170SBaolin Wang static enum power_supply_property sc27xx_fgu_props[] = { 406*195ca170SBaolin Wang POWER_SUPPLY_PROP_STATUS, 407*195ca170SBaolin Wang POWER_SUPPLY_PROP_HEALTH, 408*195ca170SBaolin Wang POWER_SUPPLY_PROP_PRESENT, 409*195ca170SBaolin Wang POWER_SUPPLY_PROP_TEMP, 410*195ca170SBaolin Wang POWER_SUPPLY_PROP_TECHNOLOGY, 411*195ca170SBaolin Wang POWER_SUPPLY_PROP_CAPACITY, 412*195ca170SBaolin Wang POWER_SUPPLY_PROP_VOLTAGE_NOW, 413*195ca170SBaolin Wang POWER_SUPPLY_PROP_VOLTAGE_OCV, 414*195ca170SBaolin Wang POWER_SUPPLY_PROP_CURRENT_NOW, 415*195ca170SBaolin Wang POWER_SUPPLY_PROP_CURRENT_AVG, 416*195ca170SBaolin Wang }; 417*195ca170SBaolin Wang 418*195ca170SBaolin Wang static const struct power_supply_desc sc27xx_fgu_desc = { 419*195ca170SBaolin Wang .name = "sc27xx-fgu", 420*195ca170SBaolin Wang .type = POWER_SUPPLY_TYPE_BATTERY, 421*195ca170SBaolin Wang .properties = sc27xx_fgu_props, 422*195ca170SBaolin Wang .num_properties = ARRAY_SIZE(sc27xx_fgu_props), 423*195ca170SBaolin Wang .get_property = sc27xx_fgu_get_property, 424*195ca170SBaolin Wang .external_power_changed = sc27xx_fgu_external_power_changed, 425*195ca170SBaolin Wang }; 426*195ca170SBaolin Wang 427*195ca170SBaolin Wang static irqreturn_t sc27xx_fgu_bat_detection(int irq, void *dev_id) 428*195ca170SBaolin Wang { 429*195ca170SBaolin Wang struct sc27xx_fgu_data *data = dev_id; 430*195ca170SBaolin Wang int state; 431*195ca170SBaolin Wang 432*195ca170SBaolin Wang mutex_lock(&data->lock); 433*195ca170SBaolin Wang 434*195ca170SBaolin Wang state = gpiod_get_value_cansleep(data->gpiod); 435*195ca170SBaolin Wang if (state < 0) { 436*195ca170SBaolin Wang dev_err(data->dev, "failed to get gpio state\n"); 437*195ca170SBaolin Wang mutex_unlock(&data->lock); 438*195ca170SBaolin Wang return IRQ_RETVAL(state); 439*195ca170SBaolin Wang } 440*195ca170SBaolin Wang 441*195ca170SBaolin Wang data->bat_present = !!state; 442*195ca170SBaolin Wang 443*195ca170SBaolin Wang mutex_unlock(&data->lock); 444*195ca170SBaolin Wang 445*195ca170SBaolin Wang power_supply_changed(data->battery); 446*195ca170SBaolin Wang return IRQ_HANDLED; 447*195ca170SBaolin Wang } 448*195ca170SBaolin Wang 449*195ca170SBaolin Wang static void sc27xx_fgu_disable(void *_data) 450*195ca170SBaolin Wang { 451*195ca170SBaolin Wang struct sc27xx_fgu_data *data = _data; 452*195ca170SBaolin Wang 453*195ca170SBaolin Wang regmap_update_bits(data->regmap, SC27XX_CLK_EN0, SC27XX_FGU_RTC_EN, 0); 454*195ca170SBaolin Wang regmap_update_bits(data->regmap, SC27XX_MODULE_EN0, SC27XX_FGU_EN, 0); 455*195ca170SBaolin Wang } 456*195ca170SBaolin Wang 457*195ca170SBaolin Wang static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity) 458*195ca170SBaolin Wang { 459*195ca170SBaolin Wang /* 460*195ca170SBaolin Wang * Get current capacity (mAh) = battery total capacity (mAh) * 461*195ca170SBaolin Wang * current capacity percent (capacity / 100). 462*195ca170SBaolin Wang */ 463*195ca170SBaolin Wang int cur_cap = DIV_ROUND_CLOSEST(data->total_cap * capacity, 100); 464*195ca170SBaolin Wang 465*195ca170SBaolin Wang /* 466*195ca170SBaolin Wang * Convert current capacity (mAh) to coulomb counter according to the 467*195ca170SBaolin Wang * formula: 1 mAh =3.6 coulomb. 468*195ca170SBaolin Wang */ 469*195ca170SBaolin Wang return DIV_ROUND_CLOSEST(cur_cap * 36, 10); 470*195ca170SBaolin Wang } 471*195ca170SBaolin Wang 472*195ca170SBaolin Wang static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data) 473*195ca170SBaolin Wang { 474*195ca170SBaolin Wang struct power_supply_battery_info info = { }; 475*195ca170SBaolin Wang struct power_supply_battery_ocv_table *table; 476*195ca170SBaolin Wang int ret; 477*195ca170SBaolin Wang 478*195ca170SBaolin Wang ret = power_supply_get_battery_info(data->battery, &info); 479*195ca170SBaolin Wang if (ret) { 480*195ca170SBaolin Wang dev_err(data->dev, "failed to get battery information\n"); 481*195ca170SBaolin Wang return ret; 482*195ca170SBaolin Wang } 483*195ca170SBaolin Wang 484*195ca170SBaolin Wang data->total_cap = info.charge_full_design_uah / 1000; 485*195ca170SBaolin Wang data->max_volt = info.constant_charge_voltage_max_uv / 1000; 486*195ca170SBaolin Wang data->internal_resist = info.factory_internal_resistance_uohm / 1000; 487*195ca170SBaolin Wang 488*195ca170SBaolin Wang /* 489*195ca170SBaolin Wang * For SC27XX fuel gauge device, we only use one ocv-capacity 490*195ca170SBaolin Wang * table in normal temperature 20 Celsius. 491*195ca170SBaolin Wang */ 492*195ca170SBaolin Wang table = power_supply_find_ocv2cap_table(&info, 20, &data->table_len); 493*195ca170SBaolin Wang if (!table) 494*195ca170SBaolin Wang return -EINVAL; 495*195ca170SBaolin Wang 496*195ca170SBaolin Wang data->cap_table = devm_kmemdup(data->dev, table, 497*195ca170SBaolin Wang data->table_len * sizeof(*table), 498*195ca170SBaolin Wang GFP_KERNEL); 499*195ca170SBaolin Wang if (!data->cap_table) { 500*195ca170SBaolin Wang power_supply_put_battery_info(data->battery, &info); 501*195ca170SBaolin Wang return -ENOMEM; 502*195ca170SBaolin Wang } 503*195ca170SBaolin Wang 504*195ca170SBaolin Wang power_supply_put_battery_info(data->battery, &info); 505*195ca170SBaolin Wang 506*195ca170SBaolin Wang /* Enable the FGU module */ 507*195ca170SBaolin Wang ret = regmap_update_bits(data->regmap, SC27XX_MODULE_EN0, 508*195ca170SBaolin Wang SC27XX_FGU_EN, SC27XX_FGU_EN); 509*195ca170SBaolin Wang if (ret) { 510*195ca170SBaolin Wang dev_err(data->dev, "failed to enable fgu\n"); 511*195ca170SBaolin Wang return ret; 512*195ca170SBaolin Wang } 513*195ca170SBaolin Wang 514*195ca170SBaolin Wang /* Enable the FGU RTC clock to make it work */ 515*195ca170SBaolin Wang ret = regmap_update_bits(data->regmap, SC27XX_CLK_EN0, 516*195ca170SBaolin Wang SC27XX_FGU_RTC_EN, SC27XX_FGU_RTC_EN); 517*195ca170SBaolin Wang if (ret) { 518*195ca170SBaolin Wang dev_err(data->dev, "failed to enable fgu RTC clock\n"); 519*195ca170SBaolin Wang goto disable_fgu; 520*195ca170SBaolin Wang } 521*195ca170SBaolin Wang 522*195ca170SBaolin Wang /* 523*195ca170SBaolin Wang * Get the boot battery capacity when system powers on, which is used to 524*195ca170SBaolin Wang * initialize the coulomb counter. After that, we can read the coulomb 525*195ca170SBaolin Wang * counter to measure the battery capacity. 526*195ca170SBaolin Wang */ 527*195ca170SBaolin Wang ret = sc27xx_fgu_get_boot_capacity(data, &data->init_cap); 528*195ca170SBaolin Wang if (ret) { 529*195ca170SBaolin Wang dev_err(data->dev, "failed to get boot capacity\n"); 530*195ca170SBaolin Wang goto disable_clk; 531*195ca170SBaolin Wang } 532*195ca170SBaolin Wang 533*195ca170SBaolin Wang /* 534*195ca170SBaolin Wang * Convert battery capacity to the corresponding initial coulomb counter 535*195ca170SBaolin Wang * and set into coulomb counter registers. 536*195ca170SBaolin Wang */ 537*195ca170SBaolin Wang data->init_clbcnt = sc27xx_fgu_cap_to_clbcnt(data, data->init_cap); 538*195ca170SBaolin Wang ret = sc27xx_fgu_set_clbcnt(data, data->init_clbcnt); 539*195ca170SBaolin Wang if (ret) { 540*195ca170SBaolin Wang dev_err(data->dev, "failed to initialize coulomb counter\n"); 541*195ca170SBaolin Wang goto disable_clk; 542*195ca170SBaolin Wang } 543*195ca170SBaolin Wang 544*195ca170SBaolin Wang return 0; 545*195ca170SBaolin Wang 546*195ca170SBaolin Wang disable_clk: 547*195ca170SBaolin Wang regmap_update_bits(data->regmap, SC27XX_CLK_EN0, SC27XX_FGU_RTC_EN, 0); 548*195ca170SBaolin Wang disable_fgu: 549*195ca170SBaolin Wang regmap_update_bits(data->regmap, SC27XX_MODULE_EN0, SC27XX_FGU_EN, 0); 550*195ca170SBaolin Wang 551*195ca170SBaolin Wang return ret; 552*195ca170SBaolin Wang } 553*195ca170SBaolin Wang 554*195ca170SBaolin Wang static int sc27xx_fgu_probe(struct platform_device *pdev) 555*195ca170SBaolin Wang { 556*195ca170SBaolin Wang struct device_node *np = pdev->dev.of_node; 557*195ca170SBaolin Wang struct power_supply_config fgu_cfg = { }; 558*195ca170SBaolin Wang struct sc27xx_fgu_data *data; 559*195ca170SBaolin Wang int ret, irq; 560*195ca170SBaolin Wang 561*195ca170SBaolin Wang data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 562*195ca170SBaolin Wang if (!data) 563*195ca170SBaolin Wang return -ENOMEM; 564*195ca170SBaolin Wang 565*195ca170SBaolin Wang data->regmap = dev_get_regmap(pdev->dev.parent, NULL); 566*195ca170SBaolin Wang if (!data->regmap) { 567*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to get regmap\n"); 568*195ca170SBaolin Wang return -ENODEV; 569*195ca170SBaolin Wang } 570*195ca170SBaolin Wang 571*195ca170SBaolin Wang ret = device_property_read_u32(&pdev->dev, "reg", &data->base); 572*195ca170SBaolin Wang if (ret) { 573*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to get fgu address\n"); 574*195ca170SBaolin Wang return ret; 575*195ca170SBaolin Wang } 576*195ca170SBaolin Wang 577*195ca170SBaolin Wang data->channel = devm_iio_channel_get(&pdev->dev, "bat-temp"); 578*195ca170SBaolin Wang if (IS_ERR(data->channel)) { 579*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to get IIO channel\n"); 580*195ca170SBaolin Wang return PTR_ERR(data->channel); 581*195ca170SBaolin Wang } 582*195ca170SBaolin Wang 583*195ca170SBaolin Wang data->gpiod = devm_gpiod_get(&pdev->dev, "bat-detect", GPIOD_IN); 584*195ca170SBaolin Wang if (IS_ERR(data->gpiod)) { 585*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to get battery detection GPIO\n"); 586*195ca170SBaolin Wang return PTR_ERR(data->gpiod); 587*195ca170SBaolin Wang } 588*195ca170SBaolin Wang 589*195ca170SBaolin Wang ret = gpiod_get_value_cansleep(data->gpiod); 590*195ca170SBaolin Wang if (ret < 0) { 591*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to get gpio state\n"); 592*195ca170SBaolin Wang return ret; 593*195ca170SBaolin Wang } 594*195ca170SBaolin Wang 595*195ca170SBaolin Wang data->bat_present = !!ret; 596*195ca170SBaolin Wang mutex_init(&data->lock); 597*195ca170SBaolin Wang data->dev = &pdev->dev; 598*195ca170SBaolin Wang 599*195ca170SBaolin Wang fgu_cfg.drv_data = data; 600*195ca170SBaolin Wang fgu_cfg.of_node = np; 601*195ca170SBaolin Wang data->battery = devm_power_supply_register(&pdev->dev, &sc27xx_fgu_desc, 602*195ca170SBaolin Wang &fgu_cfg); 603*195ca170SBaolin Wang if (IS_ERR(data->battery)) { 604*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to register power supply\n"); 605*195ca170SBaolin Wang return PTR_ERR(data->battery); 606*195ca170SBaolin Wang } 607*195ca170SBaolin Wang 608*195ca170SBaolin Wang ret = sc27xx_fgu_hw_init(data); 609*195ca170SBaolin Wang if (ret) { 610*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to initialize fgu hardware\n"); 611*195ca170SBaolin Wang return ret; 612*195ca170SBaolin Wang } 613*195ca170SBaolin Wang 614*195ca170SBaolin Wang ret = devm_add_action(&pdev->dev, sc27xx_fgu_disable, data); 615*195ca170SBaolin Wang if (ret) { 616*195ca170SBaolin Wang sc27xx_fgu_disable(data); 617*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to add fgu disable action\n"); 618*195ca170SBaolin Wang return ret; 619*195ca170SBaolin Wang } 620*195ca170SBaolin Wang 621*195ca170SBaolin Wang irq = gpiod_to_irq(data->gpiod); 622*195ca170SBaolin Wang if (irq < 0) { 623*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to translate GPIO to IRQ\n"); 624*195ca170SBaolin Wang return irq; 625*195ca170SBaolin Wang } 626*195ca170SBaolin Wang 627*195ca170SBaolin Wang ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 628*195ca170SBaolin Wang sc27xx_fgu_bat_detection, 629*195ca170SBaolin Wang IRQF_ONESHOT | IRQF_TRIGGER_RISING | 630*195ca170SBaolin Wang IRQF_TRIGGER_FALLING, 631*195ca170SBaolin Wang pdev->name, data); 632*195ca170SBaolin Wang if (ret) { 633*195ca170SBaolin Wang dev_err(&pdev->dev, "failed to request IRQ\n"); 634*195ca170SBaolin Wang return ret; 635*195ca170SBaolin Wang } 636*195ca170SBaolin Wang 637*195ca170SBaolin Wang return 0; 638*195ca170SBaolin Wang } 639*195ca170SBaolin Wang 640*195ca170SBaolin Wang static const struct of_device_id sc27xx_fgu_of_match[] = { 641*195ca170SBaolin Wang { .compatible = "sprd,sc2731-fgu", }, 642*195ca170SBaolin Wang { } 643*195ca170SBaolin Wang }; 644*195ca170SBaolin Wang 645*195ca170SBaolin Wang static struct platform_driver sc27xx_fgu_driver = { 646*195ca170SBaolin Wang .probe = sc27xx_fgu_probe, 647*195ca170SBaolin Wang .driver = { 648*195ca170SBaolin Wang .name = "sc27xx-fgu", 649*195ca170SBaolin Wang .of_match_table = sc27xx_fgu_of_match, 650*195ca170SBaolin Wang } 651*195ca170SBaolin Wang }; 652*195ca170SBaolin Wang 653*195ca170SBaolin Wang module_platform_driver(sc27xx_fgu_driver); 654*195ca170SBaolin Wang 655*195ca170SBaolin Wang MODULE_DESCRIPTION("Spreadtrum SC27XX PMICs Fual Gauge Unit Driver"); 656*195ca170SBaolin Wang MODULE_LICENSE("GPL v2"); 657