1*1cc017b7SChris Morgan // SPDX-License-Identifier: GPL-2.0 2*1cc017b7SChris Morgan /* 3*1cc017b7SChris Morgan * BQ257XX Battery Charger Driver 4*1cc017b7SChris Morgan * Copyright (C) 2025 Chris Morgan <macromorgan@hotmail.com> 5*1cc017b7SChris Morgan */ 6*1cc017b7SChris Morgan 7*1cc017b7SChris Morgan #include <linux/bitfield.h> 8*1cc017b7SChris Morgan #include <linux/i2c.h> 9*1cc017b7SChris Morgan #include <linux/interrupt.h> 10*1cc017b7SChris Morgan #include <linux/mfd/bq257xx.h> 11*1cc017b7SChris Morgan #include <linux/platform_device.h> 12*1cc017b7SChris Morgan #include <linux/power_supply.h> 13*1cc017b7SChris Morgan #include <linux/property.h> 14*1cc017b7SChris Morgan #include <linux/regmap.h> 15*1cc017b7SChris Morgan 16*1cc017b7SChris Morgan /* Forward declaration of driver data. */ 17*1cc017b7SChris Morgan struct bq257xx_chg; 18*1cc017b7SChris Morgan 19*1cc017b7SChris Morgan /** 20*1cc017b7SChris Morgan * struct bq257xx_chip_info - chip specific routines 21*1cc017b7SChris Morgan * @bq257xx_hw_init: init function for hw 22*1cc017b7SChris Morgan * @bq257xx_hw_shutdown: shutdown function for hw 23*1cc017b7SChris Morgan * @bq257xx_get_state: get and update state of hardware 24*1cc017b7SChris Morgan * @bq257xx_set_ichg: set maximum charge current (in uA) 25*1cc017b7SChris Morgan * @bq257xx_set_vbatreg: set maximum charge voltage (in uV) 26*1cc017b7SChris Morgan * @bq257xx_set_iindpm: set maximum input current (in uA) 27*1cc017b7SChris Morgan */ 28*1cc017b7SChris Morgan struct bq257xx_chip_info { 29*1cc017b7SChris Morgan int (*bq257xx_hw_init)(struct bq257xx_chg *pdata); 30*1cc017b7SChris Morgan void (*bq257xx_hw_shutdown)(struct bq257xx_chg *pdata); 31*1cc017b7SChris Morgan int (*bq257xx_get_state)(struct bq257xx_chg *pdata); 32*1cc017b7SChris Morgan int (*bq257xx_set_ichg)(struct bq257xx_chg *pdata, int ichg); 33*1cc017b7SChris Morgan int (*bq257xx_set_vbatreg)(struct bq257xx_chg *pdata, int vbatreg); 34*1cc017b7SChris Morgan int (*bq257xx_set_iindpm)(struct bq257xx_chg *pdata, int iindpm); 35*1cc017b7SChris Morgan }; 36*1cc017b7SChris Morgan 37*1cc017b7SChris Morgan /** 38*1cc017b7SChris Morgan * struct bq257xx_chg - driver data for charger 39*1cc017b7SChris Morgan * @chip: hw specific functions 40*1cc017b7SChris Morgan * @bq: parent MFD device 41*1cc017b7SChris Morgan * @charger: power supply device 42*1cc017b7SChris Morgan * @online: charger input is present 43*1cc017b7SChris Morgan * @fast_charge: charger is in fast charge mode 44*1cc017b7SChris Morgan * @pre_charge: charger is in pre-charge mode 45*1cc017b7SChris Morgan * @ov_fault: charger reports over voltage fault 46*1cc017b7SChris Morgan * @batoc_fault: charger reports battery over current fault 47*1cc017b7SChris Morgan * @oc_fault: charger reports over current fault 48*1cc017b7SChris Morgan * @usb_type: USB type reported from parent power supply 49*1cc017b7SChris Morgan * @supplied: Status of parent power supply 50*1cc017b7SChris Morgan * @iindpm_max: maximum input current limit (uA) 51*1cc017b7SChris Morgan * @vbat_max: maximum charge voltage (uV) 52*1cc017b7SChris Morgan * @ichg_max: maximum charge current (uA) 53*1cc017b7SChris Morgan * @vsys_min: minimum system voltage (uV) 54*1cc017b7SChris Morgan */ 55*1cc017b7SChris Morgan struct bq257xx_chg { 56*1cc017b7SChris Morgan const struct bq257xx_chip_info *chip; 57*1cc017b7SChris Morgan struct bq257xx_device *bq; 58*1cc017b7SChris Morgan struct power_supply *charger; 59*1cc017b7SChris Morgan bool online; 60*1cc017b7SChris Morgan bool fast_charge; 61*1cc017b7SChris Morgan bool pre_charge; 62*1cc017b7SChris Morgan bool ov_fault; 63*1cc017b7SChris Morgan bool batoc_fault; 64*1cc017b7SChris Morgan bool oc_fault; 65*1cc017b7SChris Morgan int usb_type; 66*1cc017b7SChris Morgan int supplied; 67*1cc017b7SChris Morgan u32 iindpm_max; 68*1cc017b7SChris Morgan u32 vbat_max; 69*1cc017b7SChris Morgan u32 ichg_max; 70*1cc017b7SChris Morgan u32 vsys_min; 71*1cc017b7SChris Morgan }; 72*1cc017b7SChris Morgan 73*1cc017b7SChris Morgan /** 74*1cc017b7SChris Morgan * bq25703_get_state() - Get the current state of the device 75*1cc017b7SChris Morgan * @pdata: driver platform data 76*1cc017b7SChris Morgan * 77*1cc017b7SChris Morgan * Get the current state of the charger. Check if the charger is 78*1cc017b7SChris Morgan * powered, what kind of charge state (if any) the device is in, 79*1cc017b7SChris Morgan * and if there are any active faults. 80*1cc017b7SChris Morgan * 81*1cc017b7SChris Morgan * Return: Returns 0 on success, or error on failure to read device. 82*1cc017b7SChris Morgan */ 83*1cc017b7SChris Morgan static int bq25703_get_state(struct bq257xx_chg *pdata) 84*1cc017b7SChris Morgan { 85*1cc017b7SChris Morgan unsigned int reg; 86*1cc017b7SChris Morgan int ret; 87*1cc017b7SChris Morgan 88*1cc017b7SChris Morgan ret = regmap_read(pdata->bq->regmap, BQ25703_CHARGER_STATUS, ®); 89*1cc017b7SChris Morgan if (ret) 90*1cc017b7SChris Morgan return ret; 91*1cc017b7SChris Morgan 92*1cc017b7SChris Morgan pdata->online = reg & BQ25703_STS_AC_STAT; 93*1cc017b7SChris Morgan pdata->fast_charge = reg & BQ25703_STS_IN_FCHRG; 94*1cc017b7SChris Morgan pdata->pre_charge = reg & BQ25703_STS_IN_PCHRG; 95*1cc017b7SChris Morgan pdata->ov_fault = reg & BQ25703_STS_FAULT_ACOV; 96*1cc017b7SChris Morgan pdata->batoc_fault = reg & BQ25703_STS_FAULT_BATOC; 97*1cc017b7SChris Morgan pdata->oc_fault = reg & BQ25703_STS_FAULT_ACOC; 98*1cc017b7SChris Morgan 99*1cc017b7SChris Morgan return 0; 100*1cc017b7SChris Morgan } 101*1cc017b7SChris Morgan 102*1cc017b7SChris Morgan /** 103*1cc017b7SChris Morgan * bq25703_get_min_vsys() - Get the minimum system voltage 104*1cc017b7SChris Morgan * @pdata: driver platform data 105*1cc017b7SChris Morgan * @intval: value for minimum voltage 106*1cc017b7SChris Morgan * 107*1cc017b7SChris Morgan * Return: Returns 0 on success or error on failure to read. 108*1cc017b7SChris Morgan */ 109*1cc017b7SChris Morgan static int bq25703_get_min_vsys(struct bq257xx_chg *pdata, int *intval) 110*1cc017b7SChris Morgan { 111*1cc017b7SChris Morgan unsigned int reg; 112*1cc017b7SChris Morgan int ret; 113*1cc017b7SChris Morgan 114*1cc017b7SChris Morgan ret = regmap_read(pdata->bq->regmap, BQ25703_MIN_VSYS, 115*1cc017b7SChris Morgan ®); 116*1cc017b7SChris Morgan if (ret) 117*1cc017b7SChris Morgan return ret; 118*1cc017b7SChris Morgan 119*1cc017b7SChris Morgan reg = FIELD_GET(BQ25703_MINVSYS_MASK, reg); 120*1cc017b7SChris Morgan *intval = (reg * BQ25703_MINVSYS_STEP_UV) + BQ25703_MINVSYS_MIN_UV; 121*1cc017b7SChris Morgan 122*1cc017b7SChris Morgan return ret; 123*1cc017b7SChris Morgan } 124*1cc017b7SChris Morgan 125*1cc017b7SChris Morgan /** 126*1cc017b7SChris Morgan * bq25703_set_min_vsys() - Set the minimum system voltage 127*1cc017b7SChris Morgan * @pdata: driver platform data 128*1cc017b7SChris Morgan * @vsys: voltage value to set in uV. 129*1cc017b7SChris Morgan * 130*1cc017b7SChris Morgan * This function takes a requested minimum system voltage value, clamps 131*1cc017b7SChris Morgan * it between the minimum supported value by the charger and a user 132*1cc017b7SChris Morgan * defined minimum system value, and then writes the value to the 133*1cc017b7SChris Morgan * appropriate register. 134*1cc017b7SChris Morgan * 135*1cc017b7SChris Morgan * Return: Returns 0 on success or error if an error occurs. 136*1cc017b7SChris Morgan */ 137*1cc017b7SChris Morgan static int bq25703_set_min_vsys(struct bq257xx_chg *pdata, int vsys) 138*1cc017b7SChris Morgan { 139*1cc017b7SChris Morgan unsigned int reg; 140*1cc017b7SChris Morgan int vsys_min = pdata->vsys_min; 141*1cc017b7SChris Morgan 142*1cc017b7SChris Morgan vsys = clamp(vsys, BQ25703_MINVSYS_MIN_UV, vsys_min); 143*1cc017b7SChris Morgan reg = ((vsys - BQ25703_MINVSYS_MIN_UV) / BQ25703_MINVSYS_STEP_UV); 144*1cc017b7SChris Morgan reg = FIELD_PREP(BQ25703_MINVSYS_MASK, reg); 145*1cc017b7SChris Morgan 146*1cc017b7SChris Morgan return regmap_write(pdata->bq->regmap, BQ25703_MIN_VSYS, 147*1cc017b7SChris Morgan reg); 148*1cc017b7SChris Morgan } 149*1cc017b7SChris Morgan 150*1cc017b7SChris Morgan /** 151*1cc017b7SChris Morgan * bq25703_get_cur() - Get the reported current from the battery 152*1cc017b7SChris Morgan * @pdata: driver platform data 153*1cc017b7SChris Morgan * @intval: value of reported battery current 154*1cc017b7SChris Morgan * 155*1cc017b7SChris Morgan * Read the reported current from the battery. Since value is always 156*1cc017b7SChris Morgan * positive set sign to negative if discharging. 157*1cc017b7SChris Morgan * 158*1cc017b7SChris Morgan * Return: Returns 0 on success or error if unable to read value. 159*1cc017b7SChris Morgan */ 160*1cc017b7SChris Morgan static int bq25703_get_cur(struct bq257xx_chg *pdata, int *intval) 161*1cc017b7SChris Morgan { 162*1cc017b7SChris Morgan unsigned int reg; 163*1cc017b7SChris Morgan int ret; 164*1cc017b7SChris Morgan 165*1cc017b7SChris Morgan ret = regmap_read(pdata->bq->regmap, BQ25703_ADCIBAT_CHG, ®); 166*1cc017b7SChris Morgan if (ret < 0) 167*1cc017b7SChris Morgan return ret; 168*1cc017b7SChris Morgan 169*1cc017b7SChris Morgan if (pdata->online) 170*1cc017b7SChris Morgan *intval = FIELD_GET(BQ25703_ADCIBAT_CHG_MASK, reg) * 171*1cc017b7SChris Morgan BQ25703_ADCIBAT_CHG_STEP_UA; 172*1cc017b7SChris Morgan else 173*1cc017b7SChris Morgan *intval = -(FIELD_GET(BQ25703_ADCIBAT_DISCHG_MASK, reg) * 174*1cc017b7SChris Morgan BQ25703_ADCIBAT_DIS_STEP_UA); 175*1cc017b7SChris Morgan 176*1cc017b7SChris Morgan return ret; 177*1cc017b7SChris Morgan } 178*1cc017b7SChris Morgan 179*1cc017b7SChris Morgan /** 180*1cc017b7SChris Morgan * bq25703_get_ichg_cur() - Get the maximum reported charge current 181*1cc017b7SChris Morgan * @pdata: driver platform data 182*1cc017b7SChris Morgan * @intval: value of maximum reported charge current 183*1cc017b7SChris Morgan * 184*1cc017b7SChris Morgan * Get the maximum reported charge current from the battery. 185*1cc017b7SChris Morgan * 186*1cc017b7SChris Morgan * Return: Returns 0 on success or error if unable to read value. 187*1cc017b7SChris Morgan */ 188*1cc017b7SChris Morgan static int bq25703_get_ichg_cur(struct bq257xx_chg *pdata, int *intval) 189*1cc017b7SChris Morgan { 190*1cc017b7SChris Morgan unsigned int reg; 191*1cc017b7SChris Morgan int ret; 192*1cc017b7SChris Morgan 193*1cc017b7SChris Morgan ret = regmap_read(pdata->bq->regmap, BQ25703_CHARGE_CURRENT, ®); 194*1cc017b7SChris Morgan if (ret) 195*1cc017b7SChris Morgan return ret; 196*1cc017b7SChris Morgan 197*1cc017b7SChris Morgan *intval = FIELD_GET(BQ25703_ICHG_MASK, reg) * BQ25703_ICHG_STEP_UA; 198*1cc017b7SChris Morgan 199*1cc017b7SChris Morgan return ret; 200*1cc017b7SChris Morgan } 201*1cc017b7SChris Morgan 202*1cc017b7SChris Morgan /** 203*1cc017b7SChris Morgan * bq25703_set_ichg_cur() - Set the maximum charge current 204*1cc017b7SChris Morgan * @pdata: driver platform data 205*1cc017b7SChris Morgan * @ichg: current value to set in uA. 206*1cc017b7SChris Morgan * 207*1cc017b7SChris Morgan * This function takes a requested maximum charge current value, clamps 208*1cc017b7SChris Morgan * it between the minimum supported value by the charger and a user 209*1cc017b7SChris Morgan * defined maximum charging value, and then writes the value to the 210*1cc017b7SChris Morgan * appropriate register. 211*1cc017b7SChris Morgan * 212*1cc017b7SChris Morgan * Return: Returns 0 on success or error if an error occurs. 213*1cc017b7SChris Morgan */ 214*1cc017b7SChris Morgan static int bq25703_set_ichg_cur(struct bq257xx_chg *pdata, int ichg) 215*1cc017b7SChris Morgan { 216*1cc017b7SChris Morgan unsigned int reg; 217*1cc017b7SChris Morgan int ichg_max = pdata->ichg_max; 218*1cc017b7SChris Morgan 219*1cc017b7SChris Morgan ichg = clamp(ichg, BQ25703_ICHG_MIN_UA, ichg_max); 220*1cc017b7SChris Morgan reg = FIELD_PREP(BQ25703_ICHG_MASK, (ichg / BQ25703_ICHG_STEP_UA)); 221*1cc017b7SChris Morgan 222*1cc017b7SChris Morgan return regmap_write(pdata->bq->regmap, BQ25703_CHARGE_CURRENT, 223*1cc017b7SChris Morgan reg); 224*1cc017b7SChris Morgan } 225*1cc017b7SChris Morgan 226*1cc017b7SChris Morgan /** 227*1cc017b7SChris Morgan * bq25703_get_chrg_volt() - Get the maximum set charge voltage 228*1cc017b7SChris Morgan * @pdata: driver platform data 229*1cc017b7SChris Morgan * @intval: maximum charge voltage value 230*1cc017b7SChris Morgan * 231*1cc017b7SChris Morgan * Return: Returns 0 on success or error if unable to read value. 232*1cc017b7SChris Morgan */ 233*1cc017b7SChris Morgan static int bq25703_get_chrg_volt(struct bq257xx_chg *pdata, int *intval) 234*1cc017b7SChris Morgan { 235*1cc017b7SChris Morgan unsigned int reg; 236*1cc017b7SChris Morgan int ret; 237*1cc017b7SChris Morgan 238*1cc017b7SChris Morgan ret = regmap_read(pdata->bq->regmap, BQ25703_MAX_CHARGE_VOLT, 239*1cc017b7SChris Morgan ®); 240*1cc017b7SChris Morgan if (ret) 241*1cc017b7SChris Morgan return ret; 242*1cc017b7SChris Morgan 243*1cc017b7SChris Morgan *intval = FIELD_GET(BQ25703_MAX_CHARGE_VOLT_MASK, reg) * 244*1cc017b7SChris Morgan BQ25703_VBATREG_STEP_UV; 245*1cc017b7SChris Morgan 246*1cc017b7SChris Morgan return ret; 247*1cc017b7SChris Morgan } 248*1cc017b7SChris Morgan 249*1cc017b7SChris Morgan /** 250*1cc017b7SChris Morgan * bq25703_set_chrg_volt() - Set the maximum charge voltage 251*1cc017b7SChris Morgan * @pdata: driver platform data 252*1cc017b7SChris Morgan * @vbat: voltage value to set in uV. 253*1cc017b7SChris Morgan * 254*1cc017b7SChris Morgan * This function takes a requested maximum charge voltage value, clamps 255*1cc017b7SChris Morgan * it between the minimum supported value by the charger and a user 256*1cc017b7SChris Morgan * defined maximum charging value, and then writes the value to the 257*1cc017b7SChris Morgan * appropriate register. 258*1cc017b7SChris Morgan * 259*1cc017b7SChris Morgan * Return: Returns 0 on success or error if an error occurs. 260*1cc017b7SChris Morgan */ 261*1cc017b7SChris Morgan static int bq25703_set_chrg_volt(struct bq257xx_chg *pdata, int vbat) 262*1cc017b7SChris Morgan { 263*1cc017b7SChris Morgan unsigned int reg; 264*1cc017b7SChris Morgan int vbat_max = pdata->vbat_max; 265*1cc017b7SChris Morgan 266*1cc017b7SChris Morgan vbat = clamp(vbat, BQ25703_VBATREG_MIN_UV, vbat_max); 267*1cc017b7SChris Morgan 268*1cc017b7SChris Morgan reg = FIELD_PREP(BQ25703_MAX_CHARGE_VOLT_MASK, 269*1cc017b7SChris Morgan (vbat / BQ25703_VBATREG_STEP_UV)); 270*1cc017b7SChris Morgan 271*1cc017b7SChris Morgan return regmap_write(pdata->bq->regmap, BQ25703_MAX_CHARGE_VOLT, 272*1cc017b7SChris Morgan reg); 273*1cc017b7SChris Morgan } 274*1cc017b7SChris Morgan 275*1cc017b7SChris Morgan /** 276*1cc017b7SChris Morgan * bq25703_get_iindpm() - Get the maximum set input current 277*1cc017b7SChris Morgan * @pdata: driver platform data 278*1cc017b7SChris Morgan * @intval: maximum input current value 279*1cc017b7SChris Morgan * 280*1cc017b7SChris Morgan * Read the actual input current limit from the device into intval. 281*1cc017b7SChris Morgan * This can differ from the value programmed due to some autonomous 282*1cc017b7SChris Morgan * functions that may be enabled (but are not currently). This is why 283*1cc017b7SChris Morgan * there is a different register used. 284*1cc017b7SChris Morgan * 285*1cc017b7SChris Morgan * Return: Returns 0 on success or error if unable to read register 286*1cc017b7SChris Morgan * value. 287*1cc017b7SChris Morgan */ 288*1cc017b7SChris Morgan static int bq25703_get_iindpm(struct bq257xx_chg *pdata, int *intval) 289*1cc017b7SChris Morgan { 290*1cc017b7SChris Morgan unsigned int reg; 291*1cc017b7SChris Morgan int ret; 292*1cc017b7SChris Morgan 293*1cc017b7SChris Morgan ret = regmap_read(pdata->bq->regmap, BQ25703_IIN_DPM, ®); 294*1cc017b7SChris Morgan if (ret) 295*1cc017b7SChris Morgan return ret; 296*1cc017b7SChris Morgan 297*1cc017b7SChris Morgan reg = FIELD_GET(BQ25703_IINDPM_MASK, reg); 298*1cc017b7SChris Morgan *intval = (reg * BQ25703_IINDPM_STEP_UA) + BQ25703_IINDPM_OFFSET_UA; 299*1cc017b7SChris Morgan 300*1cc017b7SChris Morgan return ret; 301*1cc017b7SChris Morgan } 302*1cc017b7SChris Morgan 303*1cc017b7SChris Morgan /** 304*1cc017b7SChris Morgan * bq25703_set_iindpm() - Set the maximum input current 305*1cc017b7SChris Morgan * @pdata: driver platform data 306*1cc017b7SChris Morgan * @iindpm: current value in uA. 307*1cc017b7SChris Morgan * 308*1cc017b7SChris Morgan * This function takes a requested maximum input current value, clamps 309*1cc017b7SChris Morgan * it between the minimum supported value by the charger and a user 310*1cc017b7SChris Morgan * defined maximum input value, and then writes the value to the 311*1cc017b7SChris Morgan * appropriate register. 312*1cc017b7SChris Morgan * 313*1cc017b7SChris Morgan * Return: Returns 0 on success or error if an error occurs. 314*1cc017b7SChris Morgan */ 315*1cc017b7SChris Morgan static int bq25703_set_iindpm(struct bq257xx_chg *pdata, int iindpm) 316*1cc017b7SChris Morgan { 317*1cc017b7SChris Morgan unsigned int reg; 318*1cc017b7SChris Morgan int iindpm_max = pdata->iindpm_max; 319*1cc017b7SChris Morgan 320*1cc017b7SChris Morgan iindpm = clamp(iindpm, BQ25703_IINDPM_MIN_UA, iindpm_max); 321*1cc017b7SChris Morgan 322*1cc017b7SChris Morgan reg = ((iindpm - BQ25703_IINDPM_OFFSET_UA) / BQ25703_IINDPM_STEP_UA); 323*1cc017b7SChris Morgan 324*1cc017b7SChris Morgan return regmap_write(pdata->bq->regmap, BQ25703_IIN_HOST, 325*1cc017b7SChris Morgan FIELD_PREP(BQ25703_IINDPM_MASK, reg)); 326*1cc017b7SChris Morgan } 327*1cc017b7SChris Morgan 328*1cc017b7SChris Morgan /** 329*1cc017b7SChris Morgan * bq25703_get_vbat() - Get the reported voltage from the battery 330*1cc017b7SChris Morgan * @pdata: driver platform data 331*1cc017b7SChris Morgan * @intval: value of reported battery voltage 332*1cc017b7SChris Morgan * 333*1cc017b7SChris Morgan * Read value of battery voltage into intval. 334*1cc017b7SChris Morgan * 335*1cc017b7SChris Morgan * Return: Returns 0 on success or error if unable to read value. 336*1cc017b7SChris Morgan */ 337*1cc017b7SChris Morgan static int bq25703_get_vbat(struct bq257xx_chg *pdata, int *intval) 338*1cc017b7SChris Morgan { 339*1cc017b7SChris Morgan unsigned int reg; 340*1cc017b7SChris Morgan int ret; 341*1cc017b7SChris Morgan 342*1cc017b7SChris Morgan ret = regmap_read(pdata->bq->regmap, BQ25703_ADCVSYSVBAT, ®); 343*1cc017b7SChris Morgan if (ret) 344*1cc017b7SChris Morgan return ret; 345*1cc017b7SChris Morgan 346*1cc017b7SChris Morgan reg = FIELD_GET(BQ25703_ADCVBAT_MASK, reg); 347*1cc017b7SChris Morgan *intval = (reg * BQ25703_ADCVSYSVBAT_STEP) + BQ25703_ADCVSYSVBAT_OFFSET_UV; 348*1cc017b7SChris Morgan 349*1cc017b7SChris Morgan return ret; 350*1cc017b7SChris Morgan } 351*1cc017b7SChris Morgan 352*1cc017b7SChris Morgan /** 353*1cc017b7SChris Morgan * bq25703_hw_init() - Set all the required registers to init the charger 354*1cc017b7SChris Morgan * @pdata: driver platform data 355*1cc017b7SChris Morgan * 356*1cc017b7SChris Morgan * Initialize the BQ25703 by first disabling the watchdog timer (which 357*1cc017b7SChris Morgan * shuts off the charger in the absence of periodic writes). Then, set 358*1cc017b7SChris Morgan * the charge current, charge voltage, minimum system voltage, and 359*1cc017b7SChris Morgan * input current limit. Disable low power mode to allow ADCs and 360*1cc017b7SChris Morgan * interrupts. Enable the ADC, start the ADC, set the ADC scale to 361*1cc017b7SChris Morgan * full, and enable each individual ADC channel. 362*1cc017b7SChris Morgan * 363*1cc017b7SChris Morgan * Return: Returns 0 on success or error code on error. 364*1cc017b7SChris Morgan */ 365*1cc017b7SChris Morgan static int bq25703_hw_init(struct bq257xx_chg *pdata) 366*1cc017b7SChris Morgan { 367*1cc017b7SChris Morgan struct regmap *regmap = pdata->bq->regmap; 368*1cc017b7SChris Morgan int ret = 0; 369*1cc017b7SChris Morgan 370*1cc017b7SChris Morgan regmap_update_bits(regmap, BQ25703_CHARGE_OPTION_0, 371*1cc017b7SChris Morgan BQ25703_WDTMR_ADJ_MASK, 372*1cc017b7SChris Morgan FIELD_PREP(BQ25703_WDTMR_ADJ_MASK, 373*1cc017b7SChris Morgan BQ25703_WDTMR_DISABLE)); 374*1cc017b7SChris Morgan 375*1cc017b7SChris Morgan ret = pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max); 376*1cc017b7SChris Morgan if (ret) 377*1cc017b7SChris Morgan return ret; 378*1cc017b7SChris Morgan 379*1cc017b7SChris Morgan ret = pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max); 380*1cc017b7SChris Morgan if (ret) 381*1cc017b7SChris Morgan return ret; 382*1cc017b7SChris Morgan 383*1cc017b7SChris Morgan ret = bq25703_set_min_vsys(pdata, pdata->vsys_min); 384*1cc017b7SChris Morgan if (ret) 385*1cc017b7SChris Morgan return ret; 386*1cc017b7SChris Morgan 387*1cc017b7SChris Morgan ret = pdata->chip->bq257xx_set_iindpm(pdata, pdata->iindpm_max); 388*1cc017b7SChris Morgan if (ret) 389*1cc017b7SChris Morgan return ret; 390*1cc017b7SChris Morgan 391*1cc017b7SChris Morgan /* Disable low power mode by writing 0 to the register. */ 392*1cc017b7SChris Morgan regmap_update_bits(regmap, BQ25703_CHARGE_OPTION_0, 393*1cc017b7SChris Morgan BQ25703_EN_LWPWR, 0); 394*1cc017b7SChris Morgan 395*1cc017b7SChris Morgan /* Enable the ADC. */ 396*1cc017b7SChris Morgan regmap_update_bits(regmap, BQ25703_ADC_OPTION, 397*1cc017b7SChris Morgan BQ25703_ADC_CONV_EN, BQ25703_ADC_CONV_EN); 398*1cc017b7SChris Morgan 399*1cc017b7SChris Morgan /* Start the ADC. */ 400*1cc017b7SChris Morgan regmap_update_bits(regmap, BQ25703_ADC_OPTION, 401*1cc017b7SChris Morgan BQ25703_ADC_START, BQ25703_ADC_START); 402*1cc017b7SChris Morgan 403*1cc017b7SChris Morgan /* Set the scale of the ADC. */ 404*1cc017b7SChris Morgan regmap_update_bits(regmap, BQ25703_ADC_OPTION, 405*1cc017b7SChris Morgan BQ25703_ADC_FULL_SCALE, BQ25703_ADC_FULL_SCALE); 406*1cc017b7SChris Morgan 407*1cc017b7SChris Morgan /* Enable each of the ADC channels available. */ 408*1cc017b7SChris Morgan regmap_update_bits(regmap, BQ25703_ADC_OPTION, 409*1cc017b7SChris Morgan BQ25703_ADC_CH_MASK, 410*1cc017b7SChris Morgan (BQ25703_ADC_CMPIN_EN | BQ25703_ADC_VBUS_EN | 411*1cc017b7SChris Morgan BQ25703_ADC_PSYS_EN | BQ25703_ADC_IIN_EN | 412*1cc017b7SChris Morgan BQ25703_ADC_IDCHG_EN | BQ25703_ADC_ICHG_EN | 413*1cc017b7SChris Morgan BQ25703_ADC_VSYS_EN | BQ25703_ADC_VBAT_EN)); 414*1cc017b7SChris Morgan 415*1cc017b7SChris Morgan return ret; 416*1cc017b7SChris Morgan } 417*1cc017b7SChris Morgan 418*1cc017b7SChris Morgan /** 419*1cc017b7SChris Morgan * bq25703_hw_shutdown() - Set registers for shutdown 420*1cc017b7SChris Morgan * @pdata: driver platform data 421*1cc017b7SChris Morgan * 422*1cc017b7SChris Morgan * Enable low power mode for the device while in shutdown. 423*1cc017b7SChris Morgan */ 424*1cc017b7SChris Morgan static void bq25703_hw_shutdown(struct bq257xx_chg *pdata) 425*1cc017b7SChris Morgan { 426*1cc017b7SChris Morgan regmap_update_bits(pdata->bq->regmap, BQ25703_CHARGE_OPTION_0, 427*1cc017b7SChris Morgan BQ25703_EN_LWPWR, BQ25703_EN_LWPWR); 428*1cc017b7SChris Morgan } 429*1cc017b7SChris Morgan 430*1cc017b7SChris Morgan static int bq257xx_set_charger_property(struct power_supply *psy, 431*1cc017b7SChris Morgan enum power_supply_property prop, 432*1cc017b7SChris Morgan const union power_supply_propval *val) 433*1cc017b7SChris Morgan { 434*1cc017b7SChris Morgan struct bq257xx_chg *pdata = power_supply_get_drvdata(psy); 435*1cc017b7SChris Morgan 436*1cc017b7SChris Morgan switch (prop) { 437*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 438*1cc017b7SChris Morgan return pdata->chip->bq257xx_set_iindpm(pdata, val->intval); 439*1cc017b7SChris Morgan 440*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 441*1cc017b7SChris Morgan return pdata->chip->bq257xx_set_vbatreg(pdata, val->intval); 442*1cc017b7SChris Morgan 443*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 444*1cc017b7SChris Morgan return pdata->chip->bq257xx_set_ichg(pdata, val->intval); 445*1cc017b7SChris Morgan 446*1cc017b7SChris Morgan default: 447*1cc017b7SChris Morgan break; 448*1cc017b7SChris Morgan } 449*1cc017b7SChris Morgan 450*1cc017b7SChris Morgan return -EINVAL; 451*1cc017b7SChris Morgan } 452*1cc017b7SChris Morgan 453*1cc017b7SChris Morgan static int bq257xx_get_charger_property(struct power_supply *psy, 454*1cc017b7SChris Morgan enum power_supply_property psp, 455*1cc017b7SChris Morgan union power_supply_propval *val) 456*1cc017b7SChris Morgan { 457*1cc017b7SChris Morgan struct bq257xx_chg *pdata = power_supply_get_drvdata(psy); 458*1cc017b7SChris Morgan int ret = 0; 459*1cc017b7SChris Morgan 460*1cc017b7SChris Morgan ret = pdata->chip->bq257xx_get_state(pdata); 461*1cc017b7SChris Morgan if (ret) 462*1cc017b7SChris Morgan return ret; 463*1cc017b7SChris Morgan 464*1cc017b7SChris Morgan switch (psp) { 465*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_STATUS: 466*1cc017b7SChris Morgan if (!pdata->online) 467*1cc017b7SChris Morgan val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 468*1cc017b7SChris Morgan else if (pdata->fast_charge || pdata->pre_charge) 469*1cc017b7SChris Morgan val->intval = POWER_SUPPLY_STATUS_CHARGING; 470*1cc017b7SChris Morgan else 471*1cc017b7SChris Morgan val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 472*1cc017b7SChris Morgan break; 473*1cc017b7SChris Morgan 474*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_HEALTH: 475*1cc017b7SChris Morgan if (pdata->ov_fault || pdata->batoc_fault) 476*1cc017b7SChris Morgan val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 477*1cc017b7SChris Morgan else if (pdata->oc_fault) 478*1cc017b7SChris Morgan val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT; 479*1cc017b7SChris Morgan else 480*1cc017b7SChris Morgan val->intval = POWER_SUPPLY_HEALTH_GOOD; 481*1cc017b7SChris Morgan break; 482*1cc017b7SChris Morgan 483*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_MANUFACTURER: 484*1cc017b7SChris Morgan val->strval = "Texas Instruments"; 485*1cc017b7SChris Morgan break; 486*1cc017b7SChris Morgan 487*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_ONLINE: 488*1cc017b7SChris Morgan val->intval = pdata->online; 489*1cc017b7SChris Morgan break; 490*1cc017b7SChris Morgan 491*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 492*1cc017b7SChris Morgan return bq25703_get_iindpm(pdata, &val->intval); 493*1cc017b7SChris Morgan 494*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 495*1cc017b7SChris Morgan return bq25703_get_chrg_volt(pdata, &val->intval); 496*1cc017b7SChris Morgan 497*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_CURRENT_NOW: 498*1cc017b7SChris Morgan return bq25703_get_cur(pdata, &val->intval); 499*1cc017b7SChris Morgan 500*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_VOLTAGE_NOW: 501*1cc017b7SChris Morgan return bq25703_get_vbat(pdata, &val->intval); 502*1cc017b7SChris Morgan 503*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 504*1cc017b7SChris Morgan return bq25703_get_ichg_cur(pdata, &val->intval); 505*1cc017b7SChris Morgan 506*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_VOLTAGE_MIN: 507*1cc017b7SChris Morgan return bq25703_get_min_vsys(pdata, &val->intval); 508*1cc017b7SChris Morgan 509*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_USB_TYPE: 510*1cc017b7SChris Morgan val->intval = pdata->usb_type; 511*1cc017b7SChris Morgan break; 512*1cc017b7SChris Morgan 513*1cc017b7SChris Morgan default: 514*1cc017b7SChris Morgan return -EINVAL; 515*1cc017b7SChris Morgan } 516*1cc017b7SChris Morgan 517*1cc017b7SChris Morgan return ret; 518*1cc017b7SChris Morgan } 519*1cc017b7SChris Morgan 520*1cc017b7SChris Morgan static enum power_supply_property bq257xx_power_supply_props[] = { 521*1cc017b7SChris Morgan POWER_SUPPLY_PROP_MANUFACTURER, 522*1cc017b7SChris Morgan POWER_SUPPLY_PROP_STATUS, 523*1cc017b7SChris Morgan POWER_SUPPLY_PROP_ONLINE, 524*1cc017b7SChris Morgan POWER_SUPPLY_PROP_HEALTH, 525*1cc017b7SChris Morgan POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 526*1cc017b7SChris Morgan POWER_SUPPLY_PROP_CURRENT_NOW, 527*1cc017b7SChris Morgan POWER_SUPPLY_PROP_VOLTAGE_NOW, 528*1cc017b7SChris Morgan POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 529*1cc017b7SChris Morgan POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 530*1cc017b7SChris Morgan POWER_SUPPLY_PROP_VOLTAGE_MIN, 531*1cc017b7SChris Morgan POWER_SUPPLY_PROP_USB_TYPE, 532*1cc017b7SChris Morgan }; 533*1cc017b7SChris Morgan 534*1cc017b7SChris Morgan static int bq257xx_property_is_writeable(struct power_supply *psy, 535*1cc017b7SChris Morgan enum power_supply_property prop) 536*1cc017b7SChris Morgan { 537*1cc017b7SChris Morgan switch (prop) { 538*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 539*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 540*1cc017b7SChris Morgan case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 541*1cc017b7SChris Morgan return true; 542*1cc017b7SChris Morgan default: 543*1cc017b7SChris Morgan return false; 544*1cc017b7SChris Morgan } 545*1cc017b7SChris Morgan } 546*1cc017b7SChris Morgan 547*1cc017b7SChris Morgan /** 548*1cc017b7SChris Morgan * bq257xx_external_power_changed() - Handler for external power change 549*1cc017b7SChris Morgan * @psy: Power supply data 550*1cc017b7SChris Morgan * 551*1cc017b7SChris Morgan * When the external power into the charger is changed, check the USB 552*1cc017b7SChris Morgan * type so that it can be reported. Additionally, update the max input 553*1cc017b7SChris Morgan * current and max charging current to the value reported if it is a 554*1cc017b7SChris Morgan * USB PD charger, otherwise use the default value. Note that each time 555*1cc017b7SChris Morgan * a charger is removed the max charge current register is erased, so 556*1cc017b7SChris Morgan * it must be set again each time the input changes or the device will 557*1cc017b7SChris Morgan * not charge. 558*1cc017b7SChris Morgan */ 559*1cc017b7SChris Morgan static void bq257xx_external_power_changed(struct power_supply *psy) 560*1cc017b7SChris Morgan { 561*1cc017b7SChris Morgan struct bq257xx_chg *pdata = power_supply_get_drvdata(psy); 562*1cc017b7SChris Morgan union power_supply_propval val; 563*1cc017b7SChris Morgan int ret; 564*1cc017b7SChris Morgan int imax = pdata->iindpm_max; 565*1cc017b7SChris Morgan 566*1cc017b7SChris Morgan pdata->chip->bq257xx_get_state(pdata); 567*1cc017b7SChris Morgan 568*1cc017b7SChris Morgan pdata->supplied = power_supply_am_i_supplied(pdata->charger); 569*1cc017b7SChris Morgan if (pdata->supplied < 0) 570*1cc017b7SChris Morgan return; 571*1cc017b7SChris Morgan 572*1cc017b7SChris Morgan if (pdata->supplied == 0) 573*1cc017b7SChris Morgan goto out; 574*1cc017b7SChris Morgan 575*1cc017b7SChris Morgan ret = power_supply_get_property_from_supplier(psy, 576*1cc017b7SChris Morgan POWER_SUPPLY_PROP_USB_TYPE, 577*1cc017b7SChris Morgan &val); 578*1cc017b7SChris Morgan if (ret) 579*1cc017b7SChris Morgan return; 580*1cc017b7SChris Morgan 581*1cc017b7SChris Morgan pdata->usb_type = val.intval; 582*1cc017b7SChris Morgan 583*1cc017b7SChris Morgan if ((pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD) || 584*1cc017b7SChris Morgan (pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD_DRP) || 585*1cc017b7SChris Morgan (pdata->usb_type == POWER_SUPPLY_USB_TYPE_PD_PPS)) { 586*1cc017b7SChris Morgan ret = power_supply_get_property_from_supplier(psy, 587*1cc017b7SChris Morgan POWER_SUPPLY_PROP_CURRENT_MAX, 588*1cc017b7SChris Morgan &val); 589*1cc017b7SChris Morgan if (ret) 590*1cc017b7SChris Morgan return; 591*1cc017b7SChris Morgan 592*1cc017b7SChris Morgan if (val.intval) 593*1cc017b7SChris Morgan imax = val.intval; 594*1cc017b7SChris Morgan } 595*1cc017b7SChris Morgan 596*1cc017b7SChris Morgan if (pdata->supplied) { 597*1cc017b7SChris Morgan pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max); 598*1cc017b7SChris Morgan pdata->chip->bq257xx_set_iindpm(pdata, imax); 599*1cc017b7SChris Morgan pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max); 600*1cc017b7SChris Morgan } 601*1cc017b7SChris Morgan 602*1cc017b7SChris Morgan out: 603*1cc017b7SChris Morgan power_supply_changed(psy); 604*1cc017b7SChris Morgan } 605*1cc017b7SChris Morgan 606*1cc017b7SChris Morgan static irqreturn_t bq257xx_irq_handler_thread(int irq, void *private) 607*1cc017b7SChris Morgan { 608*1cc017b7SChris Morgan struct bq257xx_chg *pdata = private; 609*1cc017b7SChris Morgan 610*1cc017b7SChris Morgan bq257xx_external_power_changed(pdata->charger); 611*1cc017b7SChris Morgan return IRQ_HANDLED; 612*1cc017b7SChris Morgan } 613*1cc017b7SChris Morgan 614*1cc017b7SChris Morgan static const struct power_supply_desc bq257xx_power_supply_desc = { 615*1cc017b7SChris Morgan .name = "bq257xx-charger", 616*1cc017b7SChris Morgan .type = POWER_SUPPLY_TYPE_USB, 617*1cc017b7SChris Morgan .usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | 618*1cc017b7SChris Morgan BIT(POWER_SUPPLY_USB_TYPE_PD) | 619*1cc017b7SChris Morgan BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) | 620*1cc017b7SChris Morgan BIT(POWER_SUPPLY_USB_TYPE_PD_PPS) | 621*1cc017b7SChris Morgan BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), 622*1cc017b7SChris Morgan .properties = bq257xx_power_supply_props, 623*1cc017b7SChris Morgan .num_properties = ARRAY_SIZE(bq257xx_power_supply_props), 624*1cc017b7SChris Morgan .get_property = bq257xx_get_charger_property, 625*1cc017b7SChris Morgan .set_property = bq257xx_set_charger_property, 626*1cc017b7SChris Morgan .property_is_writeable = bq257xx_property_is_writeable, 627*1cc017b7SChris Morgan .external_power_changed = bq257xx_external_power_changed, 628*1cc017b7SChris Morgan }; 629*1cc017b7SChris Morgan 630*1cc017b7SChris Morgan static const struct bq257xx_chip_info bq25703_chip_info = { 631*1cc017b7SChris Morgan .bq257xx_hw_init = &bq25703_hw_init, 632*1cc017b7SChris Morgan .bq257xx_hw_shutdown = &bq25703_hw_shutdown, 633*1cc017b7SChris Morgan .bq257xx_get_state = &bq25703_get_state, 634*1cc017b7SChris Morgan .bq257xx_set_ichg = &bq25703_set_ichg_cur, 635*1cc017b7SChris Morgan .bq257xx_set_vbatreg = &bq25703_set_chrg_volt, 636*1cc017b7SChris Morgan .bq257xx_set_iindpm = &bq25703_set_iindpm, 637*1cc017b7SChris Morgan }; 638*1cc017b7SChris Morgan 639*1cc017b7SChris Morgan /** 640*1cc017b7SChris Morgan * bq257xx_parse_dt() - Parse the device tree for required properties 641*1cc017b7SChris Morgan * @pdata: driver platform data 642*1cc017b7SChris Morgan * @psy_cfg: power supply config data 643*1cc017b7SChris Morgan * @dev: device struct 644*1cc017b7SChris Morgan * 645*1cc017b7SChris Morgan * Read the device tree to identify the minimum system voltage, the 646*1cc017b7SChris Morgan * maximum charge current, the maximum charge voltage, and the maximum 647*1cc017b7SChris Morgan * input current. 648*1cc017b7SChris Morgan * 649*1cc017b7SChris Morgan * Return: Returns 0 on success or error code on error. 650*1cc017b7SChris Morgan */ 651*1cc017b7SChris Morgan static int bq257xx_parse_dt(struct bq257xx_chg *pdata, 652*1cc017b7SChris Morgan struct power_supply_config *psy_cfg, struct device *dev) 653*1cc017b7SChris Morgan { 654*1cc017b7SChris Morgan struct power_supply_battery_info *bat_info; 655*1cc017b7SChris Morgan int ret; 656*1cc017b7SChris Morgan 657*1cc017b7SChris Morgan ret = power_supply_get_battery_info(pdata->charger, 658*1cc017b7SChris Morgan &bat_info); 659*1cc017b7SChris Morgan if (ret) 660*1cc017b7SChris Morgan return dev_err_probe(dev, ret, 661*1cc017b7SChris Morgan "Unable to get battery info\n"); 662*1cc017b7SChris Morgan 663*1cc017b7SChris Morgan if ((bat_info->voltage_min_design_uv <= 0) || 664*1cc017b7SChris Morgan (bat_info->constant_charge_voltage_max_uv <= 0) || 665*1cc017b7SChris Morgan (bat_info->constant_charge_current_max_ua <= 0)) 666*1cc017b7SChris Morgan return dev_err_probe(dev, -EINVAL, 667*1cc017b7SChris Morgan "Required bat info missing or invalid\n"); 668*1cc017b7SChris Morgan 669*1cc017b7SChris Morgan pdata->vsys_min = bat_info->voltage_min_design_uv; 670*1cc017b7SChris Morgan pdata->vbat_max = bat_info->constant_charge_voltage_max_uv; 671*1cc017b7SChris Morgan pdata->ichg_max = bat_info->constant_charge_current_max_ua; 672*1cc017b7SChris Morgan 673*1cc017b7SChris Morgan power_supply_put_battery_info(pdata->charger, bat_info); 674*1cc017b7SChris Morgan 675*1cc017b7SChris Morgan ret = device_property_read_u32(dev, 676*1cc017b7SChris Morgan "input-current-limit-microamp", 677*1cc017b7SChris Morgan &pdata->iindpm_max); 678*1cc017b7SChris Morgan if (ret) 679*1cc017b7SChris Morgan pdata->iindpm_max = BQ25703_IINDPM_DEFAULT_UA; 680*1cc017b7SChris Morgan 681*1cc017b7SChris Morgan return 0; 682*1cc017b7SChris Morgan } 683*1cc017b7SChris Morgan 684*1cc017b7SChris Morgan static int bq257xx_charger_probe(struct platform_device *pdev) 685*1cc017b7SChris Morgan { 686*1cc017b7SChris Morgan struct device *dev = &pdev->dev; 687*1cc017b7SChris Morgan struct bq257xx_device *bq = dev_get_drvdata(pdev->dev.parent); 688*1cc017b7SChris Morgan struct bq257xx_chg *pdata; 689*1cc017b7SChris Morgan struct power_supply_config psy_cfg = { }; 690*1cc017b7SChris Morgan int ret; 691*1cc017b7SChris Morgan 692*1cc017b7SChris Morgan device_set_of_node_from_dev(dev, pdev->dev.parent); 693*1cc017b7SChris Morgan 694*1cc017b7SChris Morgan pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 695*1cc017b7SChris Morgan if (!pdata) 696*1cc017b7SChris Morgan return -ENOMEM; 697*1cc017b7SChris Morgan 698*1cc017b7SChris Morgan pdata->bq = bq; 699*1cc017b7SChris Morgan pdata->chip = &bq25703_chip_info; 700*1cc017b7SChris Morgan 701*1cc017b7SChris Morgan platform_set_drvdata(pdev, pdata); 702*1cc017b7SChris Morgan 703*1cc017b7SChris Morgan psy_cfg.drv_data = pdata; 704*1cc017b7SChris Morgan psy_cfg.fwnode = dev_fwnode(dev); 705*1cc017b7SChris Morgan 706*1cc017b7SChris Morgan pdata->charger = devm_power_supply_register(dev, 707*1cc017b7SChris Morgan &bq257xx_power_supply_desc, 708*1cc017b7SChris Morgan &psy_cfg); 709*1cc017b7SChris Morgan if (IS_ERR(pdata->charger)) 710*1cc017b7SChris Morgan return dev_err_probe(dev, PTR_ERR(pdata->charger), 711*1cc017b7SChris Morgan "Power supply register charger failed\n"); 712*1cc017b7SChris Morgan 713*1cc017b7SChris Morgan ret = bq257xx_parse_dt(pdata, &psy_cfg, dev); 714*1cc017b7SChris Morgan if (ret) 715*1cc017b7SChris Morgan return ret; 716*1cc017b7SChris Morgan 717*1cc017b7SChris Morgan ret = pdata->chip->bq257xx_hw_init(pdata); 718*1cc017b7SChris Morgan if (ret) 719*1cc017b7SChris Morgan return dev_err_probe(dev, ret, "Cannot initialize the charger\n"); 720*1cc017b7SChris Morgan 721*1cc017b7SChris Morgan platform_set_drvdata(pdev, pdata); 722*1cc017b7SChris Morgan 723*1cc017b7SChris Morgan if (bq->client->irq) { 724*1cc017b7SChris Morgan ret = devm_request_threaded_irq(dev, bq->client->irq, NULL, 725*1cc017b7SChris Morgan bq257xx_irq_handler_thread, 726*1cc017b7SChris Morgan IRQF_TRIGGER_RISING | 727*1cc017b7SChris Morgan IRQF_TRIGGER_FALLING | 728*1cc017b7SChris Morgan IRQF_ONESHOT, 729*1cc017b7SChris Morgan dev_name(&bq->client->dev), pdata); 730*1cc017b7SChris Morgan if (ret < 0) 731*1cc017b7SChris Morgan dev_err_probe(dev, ret, "Charger get irq failed\n"); 732*1cc017b7SChris Morgan } 733*1cc017b7SChris Morgan 734*1cc017b7SChris Morgan return ret; 735*1cc017b7SChris Morgan } 736*1cc017b7SChris Morgan 737*1cc017b7SChris Morgan static void bq257xx_charger_shutdown(struct platform_device *pdev) 738*1cc017b7SChris Morgan { 739*1cc017b7SChris Morgan struct bq257xx_chg *pdata = platform_get_drvdata(pdev); 740*1cc017b7SChris Morgan 741*1cc017b7SChris Morgan pdata->chip->bq257xx_hw_shutdown(pdata); 742*1cc017b7SChris Morgan } 743*1cc017b7SChris Morgan 744*1cc017b7SChris Morgan static struct platform_driver bq257xx_chg_driver = { 745*1cc017b7SChris Morgan .driver = { 746*1cc017b7SChris Morgan .name = "bq257xx-charger", 747*1cc017b7SChris Morgan }, 748*1cc017b7SChris Morgan .probe = bq257xx_charger_probe, 749*1cc017b7SChris Morgan .shutdown = bq257xx_charger_shutdown, 750*1cc017b7SChris Morgan }; 751*1cc017b7SChris Morgan module_platform_driver(bq257xx_chg_driver); 752*1cc017b7SChris Morgan 753*1cc017b7SChris Morgan MODULE_DESCRIPTION("bq257xx charger driver"); 754*1cc017b7SChris Morgan MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>"); 755*1cc017b7SChris Morgan MODULE_LICENSE("GPL"); 756