Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Batttery Driver for Dialog DA9052 PMICs
0004  *
0005  * Copyright(c) 2011 Dialog Semiconductor Ltd.
0006  *
0007  * Author: David Dajun Chen <dchen@diasemi.com>
0008  */
0009 
0010 #include <linux/delay.h>
0011 #include <linux/freezer.h>
0012 #include <linux/fs.h>
0013 #include <linux/jiffies.h>
0014 #include <linux/module.h>
0015 #include <linux/timer.h>
0016 #include <linux/uaccess.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/power_supply.h>
0019 
0020 #include <linux/mfd/da9052/da9052.h>
0021 #include <linux/mfd/da9052/pdata.h>
0022 #include <linux/mfd/da9052/reg.h>
0023 
0024 /* STATIC CONFIGURATION */
0025 #define DA9052_BAT_CUTOFF_VOLT      2800
0026 #define DA9052_BAT_TSH          62000
0027 #define DA9052_BAT_LOW_CAP      4
0028 #define DA9052_AVG_SZ           4
0029 #define DA9052_VC_TBL_SZ        68
0030 #define DA9052_VC_TBL_REF_SZ        3
0031 
0032 #define DA9052_ISET_USB_MASK        0x0F
0033 #define DA9052_CHG_USB_ILIM_MASK    0x40
0034 #define DA9052_CHG_LIM_COLS     16
0035 
0036 #define DA9052_MEAN(x, y)       ((x + y) / 2)
0037 
0038 enum charger_type_enum {
0039     DA9052_NOCHARGER = 1,
0040     DA9052_CHARGER,
0041 };
0042 
0043 static const u16 da9052_chg_current_lim[2][DA9052_CHG_LIM_COLS] = {
0044     {70,  80,  90,  100, 110, 120, 400,  450,
0045      500, 550, 600, 650, 700, 900, 1100, 1300},
0046     {80,  90,  100, 110,  120,  400,  450,  500,
0047      550, 600, 800, 1000, 1200, 1400, 1600, 1800},
0048 };
0049 
0050 static const u16 vc_tbl_ref[3] = {10, 25, 40};
0051 /* Lookup table for voltage vs capacity */
0052 static u32 const vc_tbl[3][68][2] = {
0053     /* For temperature 10 degree Celsius */
0054     {
0055     {4082, 100}, {4036, 98},
0056     {4020, 96}, {4008, 95},
0057     {3997, 93}, {3983, 91},
0058     {3964, 90}, {3943, 88},
0059     {3926, 87}, {3912, 85},
0060     {3900, 84}, {3890, 82},
0061     {3881, 80}, {3873, 79},
0062     {3865, 77}, {3857, 76},
0063     {3848, 74}, {3839, 73},
0064     {3829, 71}, {3820, 70},
0065     {3811, 68}, {3802, 67},
0066     {3794, 65}, {3785, 64},
0067     {3778, 62}, {3770, 61},
0068     {3763, 59}, {3756, 58},
0069     {3750, 56}, {3744, 55},
0070     {3738, 53}, {3732, 52},
0071     {3727, 50}, {3722, 49},
0072     {3717, 47}, {3712, 46},
0073     {3708, 44}, {3703, 43},
0074     {3700, 41}, {3696, 40},
0075     {3693, 38}, {3691, 37},
0076     {3688, 35}, {3686, 34},
0077     {3683, 32}, {3681, 31},
0078     {3678, 29}, {3675, 28},
0079     {3672, 26}, {3669, 25},
0080     {3665, 23}, {3661, 22},
0081     {3656, 21}, {3651, 19},
0082     {3645, 18}, {3639, 16},
0083     {3631, 15}, {3622, 13},
0084     {3611, 12}, {3600, 10},
0085     {3587, 9}, {3572, 7},
0086     {3548, 6}, {3503, 5},
0087     {3420, 3}, {3268, 2},
0088     {2992, 1}, {2746, 0}
0089     },
0090     /* For temperature 25 degree Celsius */
0091     {
0092     {4102, 100}, {4065, 98},
0093     {4048, 96}, {4034, 95},
0094     {4021, 93}, {4011, 92},
0095     {4001, 90}, {3986, 88},
0096     {3968, 87}, {3952, 85},
0097     {3938, 84}, {3926, 82},
0098     {3916, 81}, {3908, 79},
0099     {3900, 77}, {3892, 76},
0100     {3883, 74}, {3874, 73},
0101     {3864, 71}, {3855, 70},
0102     {3846, 68}, {3836, 67},
0103     {3827, 65}, {3819, 64},
0104     {3810, 62}, {3801, 61},
0105     {3793, 59}, {3786, 58},
0106     {3778, 56}, {3772, 55},
0107     {3765, 53}, {3759, 52},
0108     {3754, 50}, {3748, 49},
0109     {3743, 47}, {3738, 46},
0110     {3733, 44}, {3728, 43},
0111     {3724, 41}, {3720, 40},
0112     {3716, 38}, {3712, 37},
0113     {3709, 35}, {3706, 34},
0114     {3703, 33}, {3701, 31},
0115     {3698, 30}, {3696, 28},
0116     {3693, 27}, {3690, 25},
0117     {3687, 24}, {3683, 22},
0118     {3680, 21}, {3675, 19},
0119     {3671, 18}, {3666, 17},
0120     {3660, 15}, {3654, 14},
0121     {3647, 12}, {3639, 11},
0122     {3630, 9}, {3621, 8},
0123     {3613, 6}, {3606, 5},
0124     {3597, 4}, {3582, 2},
0125     {3546, 1}, {2747, 0}
0126     },
0127     /* For temperature 40 degree Celsius */
0128     {
0129     {4114, 100}, {4081, 98},
0130     {4065, 96}, {4050, 95},
0131     {4036, 93}, {4024, 92},
0132     {4013, 90}, {4002, 88},
0133     {3990, 87}, {3976, 85},
0134     {3962, 84}, {3950, 82},
0135     {3939, 81}, {3930, 79},
0136     {3921, 77}, {3912, 76},
0137     {3902, 74}, {3893, 73},
0138     {3883, 71}, {3874, 70},
0139     {3865, 68}, {3856, 67},
0140     {3847, 65}, {3838, 64},
0141     {3829, 62}, {3820, 61},
0142     {3812, 59}, {3803, 58},
0143     {3795, 56}, {3787, 55},
0144     {3780, 53}, {3773, 52},
0145     {3767, 50}, {3761, 49},
0146     {3756, 47}, {3751, 46},
0147     {3746, 44}, {3741, 43},
0148     {3736, 41}, {3732, 40},
0149     {3728, 38}, {3724, 37},
0150     {3720, 35}, {3716, 34},
0151     {3713, 33}, {3710, 31},
0152     {3707, 30}, {3704, 28},
0153     {3701, 27}, {3698, 25},
0154     {3695, 24}, {3691, 22},
0155     {3686, 21}, {3681, 19},
0156     {3676, 18}, {3671, 17},
0157     {3666, 15}, {3661, 14},
0158     {3655, 12}, {3648, 11},
0159     {3640, 9}, {3632, 8},
0160     {3622, 6}, {3616, 5},
0161     {3611, 4}, {3604, 2},
0162     {3594, 1}, {2747, 0}
0163     }
0164 };
0165 
0166 struct da9052_battery {
0167     struct da9052 *da9052;
0168     struct power_supply *psy;
0169     struct notifier_block nb;
0170     int charger_type;
0171     int status;
0172     int health;
0173 };
0174 
0175 static inline int volt_reg_to_mV(int value)
0176 {
0177     return ((value * 1000) / 512) + 2500;
0178 }
0179 
0180 static inline int ichg_reg_to_mA(int value)
0181 {
0182     return (value * 3900) / 1000;
0183 }
0184 
0185 static int da9052_read_chgend_current(struct da9052_battery *bat,
0186                        int *current_mA)
0187 {
0188     int ret;
0189 
0190     if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING)
0191         return -EINVAL;
0192 
0193     ret = da9052_reg_read(bat->da9052, DA9052_ICHG_END_REG);
0194     if (ret < 0)
0195         return ret;
0196 
0197     *current_mA = ichg_reg_to_mA(ret & DA9052_ICHGEND_ICHGEND);
0198 
0199     return 0;
0200 }
0201 
0202 static int da9052_read_chg_current(struct da9052_battery *bat, int *current_mA)
0203 {
0204     int ret;
0205 
0206     if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING)
0207         return -EINVAL;
0208 
0209     ret = da9052_reg_read(bat->da9052, DA9052_ICHG_AV_REG);
0210     if (ret < 0)
0211         return ret;
0212 
0213     *current_mA = ichg_reg_to_mA(ret & DA9052_ICHGAV_ICHGAV);
0214 
0215     return 0;
0216 }
0217 
0218 static int da9052_bat_check_status(struct da9052_battery *bat, int *status)
0219 {
0220     u8 v[2] = {0, 0};
0221     u8 bat_status;
0222     u8 chg_end;
0223     int ret;
0224     int chg_current;
0225     int chg_end_current;
0226     bool dcinsel;
0227     bool dcindet;
0228     bool vbussel;
0229     bool vbusdet;
0230     bool dc;
0231     bool vbus;
0232 
0233     ret = da9052_group_read(bat->da9052, DA9052_STATUS_A_REG, 2, v);
0234     if (ret < 0)
0235         return ret;
0236 
0237     bat_status = v[0];
0238     chg_end = v[1];
0239 
0240     dcinsel = bat_status & DA9052_STATUSA_DCINSEL;
0241     dcindet = bat_status & DA9052_STATUSA_DCINDET;
0242     vbussel = bat_status & DA9052_STATUSA_VBUSSEL;
0243     vbusdet = bat_status & DA9052_STATUSA_VBUSDET;
0244     dc = dcinsel && dcindet;
0245     vbus = vbussel && vbusdet;
0246 
0247     /* Preference to WALL(DCIN) charger unit */
0248     if (dc || vbus) {
0249         bat->charger_type = DA9052_CHARGER;
0250 
0251         /* If charging end flag is set and Charging current is greater
0252          * than charging end limit then battery is charging
0253         */
0254         if ((chg_end & DA9052_STATUSB_CHGEND) != 0) {
0255             ret = da9052_read_chg_current(bat, &chg_current);
0256             if (ret < 0)
0257                 return ret;
0258             ret = da9052_read_chgend_current(bat, &chg_end_current);
0259             if (ret < 0)
0260                 return ret;
0261 
0262             if (chg_current >= chg_end_current)
0263                 bat->status = POWER_SUPPLY_STATUS_CHARGING;
0264             else
0265                 bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
0266         } else {
0267             /* If Charging end flag is cleared then battery is
0268              * charging
0269             */
0270             bat->status = POWER_SUPPLY_STATUS_CHARGING;
0271         }
0272     } else if (dcindet || vbusdet) {
0273             bat->charger_type = DA9052_CHARGER;
0274             bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
0275     } else {
0276         bat->charger_type = DA9052_NOCHARGER;
0277         bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
0278     }
0279 
0280     if (status != NULL)
0281         *status = bat->status;
0282     return 0;
0283 }
0284 
0285 static int da9052_bat_read_volt(struct da9052_battery *bat, int *volt_mV)
0286 {
0287     int volt;
0288 
0289     volt = da9052_adc_manual_read(bat->da9052, DA9052_ADC_MAN_MUXSEL_VBAT);
0290     if (volt < 0)
0291         return volt;
0292 
0293     *volt_mV = volt_reg_to_mV(volt);
0294 
0295     return 0;
0296 }
0297 
0298 static int da9052_bat_check_presence(struct da9052_battery *bat, int *illegal)
0299 {
0300     int bat_temp;
0301 
0302     bat_temp = da9052_adc_read_temp(bat->da9052);
0303     if (bat_temp < 0)
0304         return bat_temp;
0305 
0306     if (bat_temp > DA9052_BAT_TSH)
0307         *illegal = 1;
0308     else
0309         *illegal = 0;
0310 
0311     return 0;
0312 }
0313 
0314 static int da9052_bat_interpolate(int vbat_lower, int  vbat_upper,
0315                    int level_lower, int level_upper,
0316                    int bat_voltage)
0317 {
0318     int tmp;
0319 
0320     tmp = ((level_upper - level_lower) * 1000) / (vbat_upper - vbat_lower);
0321     tmp = level_lower + (((bat_voltage - vbat_lower) * tmp) / 1000);
0322 
0323     return tmp;
0324 }
0325 
0326 static unsigned char da9052_determine_vc_tbl_index(unsigned char adc_temp)
0327 {
0328     int i;
0329 
0330     if (adc_temp <= vc_tbl_ref[0])
0331         return 0;
0332 
0333     if (adc_temp > vc_tbl_ref[DA9052_VC_TBL_REF_SZ - 1])
0334         return DA9052_VC_TBL_REF_SZ - 1;
0335 
0336     for (i = 0; i < DA9052_VC_TBL_REF_SZ - 1; i++) {
0337         if ((adc_temp > vc_tbl_ref[i]) &&
0338             (adc_temp <= DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1])))
0339                 return i;
0340         if ((adc_temp > DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1]))
0341              && (adc_temp <= vc_tbl_ref[i]))
0342                 return i + 1;
0343     }
0344     /*
0345      * For some reason authors of the driver didn't presume that we can
0346      * end up here. It might be OK, but might be not, no one knows for
0347      * sure. Go check your battery, is it on fire?
0348      */
0349     WARN_ON(1);
0350     return 0;
0351 }
0352 
0353 static int da9052_bat_read_capacity(struct da9052_battery *bat, int *capacity)
0354 {
0355     int adc_temp;
0356     int bat_voltage;
0357     int vbat_lower;
0358     int vbat_upper;
0359     int level_upper;
0360     int level_lower;
0361     int ret;
0362     int flag;
0363     int i = 0;
0364     int j;
0365 
0366     ret = da9052_bat_read_volt(bat, &bat_voltage);
0367     if (ret < 0)
0368         return ret;
0369 
0370     adc_temp = da9052_adc_read_temp(bat->da9052);
0371     if (adc_temp < 0)
0372         return adc_temp;
0373 
0374     i = da9052_determine_vc_tbl_index(adc_temp);
0375 
0376     if (bat_voltage >= vc_tbl[i][0][0]) {
0377         *capacity = 100;
0378         return 0;
0379     }
0380     if (bat_voltage <= vc_tbl[i][DA9052_VC_TBL_SZ - 1][0]) {
0381         *capacity = 0;
0382         return 0;
0383     }
0384     flag = 0;
0385 
0386     for (j = 0; j < (DA9052_VC_TBL_SZ-1); j++) {
0387         if ((bat_voltage <= vc_tbl[i][j][0]) &&
0388             (bat_voltage >= vc_tbl[i][j + 1][0])) {
0389             vbat_upper = vc_tbl[i][j][0];
0390             vbat_lower = vc_tbl[i][j + 1][0];
0391             level_upper = vc_tbl[i][j][1];
0392             level_lower = vc_tbl[i][j + 1][1];
0393             flag = 1;
0394             break;
0395         }
0396     }
0397     if (!flag)
0398         return -EIO;
0399 
0400     *capacity = da9052_bat_interpolate(vbat_lower, vbat_upper, level_lower,
0401                        level_upper, bat_voltage);
0402 
0403     return 0;
0404 }
0405 
0406 static int da9052_bat_check_health(struct da9052_battery *bat, int *health)
0407 {
0408     int ret;
0409     int bat_illegal;
0410     int capacity;
0411 
0412     ret = da9052_bat_check_presence(bat, &bat_illegal);
0413     if (ret < 0)
0414         return ret;
0415 
0416     if (bat_illegal) {
0417         bat->health = POWER_SUPPLY_HEALTH_UNKNOWN;
0418         return 0;
0419     }
0420 
0421     if (bat->health != POWER_SUPPLY_HEALTH_OVERHEAT) {
0422         ret = da9052_bat_read_capacity(bat, &capacity);
0423         if (ret < 0)
0424             return ret;
0425         if (capacity < DA9052_BAT_LOW_CAP)
0426             bat->health = POWER_SUPPLY_HEALTH_DEAD;
0427         else
0428             bat->health = POWER_SUPPLY_HEALTH_GOOD;
0429     }
0430 
0431     *health = bat->health;
0432 
0433     return 0;
0434 }
0435 
0436 static irqreturn_t da9052_bat_irq(int irq, void *data)
0437 {
0438     struct da9052_battery *bat = data;
0439     int virq;
0440 
0441     virq = regmap_irq_get_virq(bat->da9052->irq_data, irq);
0442     irq -= virq;
0443 
0444     if (irq == DA9052_IRQ_CHGEND)
0445         bat->status = POWER_SUPPLY_STATUS_FULL;
0446     else
0447         da9052_bat_check_status(bat, NULL);
0448 
0449     if (irq == DA9052_IRQ_CHGEND || irq == DA9052_IRQ_DCIN ||
0450         irq == DA9052_IRQ_VBUS || irq == DA9052_IRQ_TBAT) {
0451         power_supply_changed(bat->psy);
0452     }
0453 
0454     return IRQ_HANDLED;
0455 }
0456 
0457 static int da9052_USB_current_notifier(struct notifier_block *nb,
0458                     unsigned long events, void *data)
0459 {
0460     u8 row;
0461     u8 col;
0462     int *current_mA = data;
0463     int ret;
0464     struct da9052_battery *bat = container_of(nb, struct da9052_battery,
0465                           nb);
0466 
0467     if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING)
0468         return -EPERM;
0469 
0470     ret = da9052_reg_read(bat->da9052, DA9052_CHGBUCK_REG);
0471     if (ret & DA9052_CHG_USB_ILIM_MASK)
0472         return -EPERM;
0473 
0474     if (bat->da9052->chip_id == DA9052)
0475         row = 0;
0476     else
0477         row = 1;
0478 
0479     if (*current_mA < da9052_chg_current_lim[row][0] ||
0480         *current_mA > da9052_chg_current_lim[row][DA9052_CHG_LIM_COLS - 1])
0481         return -EINVAL;
0482 
0483     for (col = 0; col <= DA9052_CHG_LIM_COLS - 1 ; col++) {
0484         if (*current_mA <= da9052_chg_current_lim[row][col])
0485             break;
0486     }
0487 
0488     return da9052_reg_update(bat->da9052, DA9052_ISET_REG,
0489                  DA9052_ISET_USB_MASK, col);
0490 }
0491 
0492 static int da9052_bat_get_property(struct power_supply *psy,
0493                     enum power_supply_property psp,
0494                     union power_supply_propval *val)
0495 {
0496     int ret;
0497     int illegal;
0498     struct da9052_battery *bat = power_supply_get_drvdata(psy);
0499 
0500     ret = da9052_bat_check_presence(bat, &illegal);
0501     if (ret < 0)
0502         return ret;
0503 
0504     if (illegal && psp != POWER_SUPPLY_PROP_PRESENT)
0505         return -ENODEV;
0506 
0507     switch (psp) {
0508     case POWER_SUPPLY_PROP_STATUS:
0509         ret = da9052_bat_check_status(bat, &val->intval);
0510         break;
0511     case POWER_SUPPLY_PROP_ONLINE:
0512         val->intval =
0513             (bat->charger_type == DA9052_NOCHARGER) ? 0 : 1;
0514         break;
0515     case POWER_SUPPLY_PROP_PRESENT:
0516         ret = da9052_bat_check_presence(bat, &val->intval);
0517         break;
0518     case POWER_SUPPLY_PROP_HEALTH:
0519         ret = da9052_bat_check_health(bat, &val->intval);
0520         break;
0521     case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
0522         val->intval = DA9052_BAT_CUTOFF_VOLT * 1000;
0523         break;
0524     case POWER_SUPPLY_PROP_VOLTAGE_AVG:
0525         ret = da9052_bat_read_volt(bat, &val->intval);
0526         break;
0527     case POWER_SUPPLY_PROP_CURRENT_AVG:
0528         ret = da9052_read_chg_current(bat, &val->intval);
0529         break;
0530     case POWER_SUPPLY_PROP_CAPACITY:
0531         ret = da9052_bat_read_capacity(bat, &val->intval);
0532         break;
0533     case POWER_SUPPLY_PROP_TEMP:
0534         val->intval = da9052_adc_read_temp(bat->da9052);
0535         ret = val->intval;
0536         break;
0537     case POWER_SUPPLY_PROP_TECHNOLOGY:
0538         val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
0539         break;
0540     default:
0541         return -EINVAL;
0542     }
0543     return ret;
0544 }
0545 
0546 static enum power_supply_property da9052_bat_props[] = {
0547     POWER_SUPPLY_PROP_STATUS,
0548     POWER_SUPPLY_PROP_ONLINE,
0549     POWER_SUPPLY_PROP_PRESENT,
0550     POWER_SUPPLY_PROP_HEALTH,
0551     POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
0552     POWER_SUPPLY_PROP_VOLTAGE_AVG,
0553     POWER_SUPPLY_PROP_CURRENT_AVG,
0554     POWER_SUPPLY_PROP_CAPACITY,
0555     POWER_SUPPLY_PROP_TEMP,
0556     POWER_SUPPLY_PROP_TECHNOLOGY,
0557 };
0558 
0559 static struct power_supply_desc psy_desc = {
0560     .name       = "da9052-bat",
0561     .type       = POWER_SUPPLY_TYPE_BATTERY,
0562     .properties = da9052_bat_props,
0563     .num_properties = ARRAY_SIZE(da9052_bat_props),
0564     .get_property   = da9052_bat_get_property,
0565 };
0566 
0567 static char *da9052_bat_irqs[] = {
0568     "BATT TEMP",
0569     "DCIN DET",
0570     "DCIN REM",
0571     "VBUS DET",
0572     "VBUS REM",
0573     "CHG END",
0574 };
0575 
0576 static int da9052_bat_irq_bits[] = {
0577     DA9052_IRQ_TBAT,
0578     DA9052_IRQ_DCIN,
0579     DA9052_IRQ_DCINREM,
0580     DA9052_IRQ_VBUS,
0581     DA9052_IRQ_VBUSREM,
0582     DA9052_IRQ_CHGEND,
0583 };
0584 
0585 static s32 da9052_bat_probe(struct platform_device *pdev)
0586 {
0587     struct da9052_pdata *pdata;
0588     struct da9052_battery *bat;
0589     struct power_supply_config psy_cfg = {};
0590     int ret;
0591     int i;
0592 
0593     bat = devm_kzalloc(&pdev->dev, sizeof(struct da9052_battery),
0594                 GFP_KERNEL);
0595     if (!bat)
0596         return -ENOMEM;
0597 
0598     psy_cfg.drv_data = bat;
0599 
0600     bat->da9052 = dev_get_drvdata(pdev->dev.parent);
0601     bat->charger_type = DA9052_NOCHARGER;
0602     bat->status = POWER_SUPPLY_STATUS_UNKNOWN;
0603     bat->health = POWER_SUPPLY_HEALTH_UNKNOWN;
0604     bat->nb.notifier_call = da9052_USB_current_notifier;
0605 
0606     pdata = bat->da9052->dev->platform_data;
0607     if (pdata != NULL && pdata->use_for_apm)
0608         psy_desc.use_for_apm = pdata->use_for_apm;
0609     else
0610         psy_desc.use_for_apm = 1;
0611 
0612     for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) {
0613         ret = da9052_request_irq(bat->da9052,
0614                 da9052_bat_irq_bits[i], da9052_bat_irqs[i],
0615                 da9052_bat_irq, bat);
0616 
0617         if (ret != 0) {
0618             dev_err(bat->da9052->dev,
0619                 "DA9052 failed to request %s IRQ: %d\n",
0620                 da9052_bat_irqs[i], ret);
0621             goto err;
0622         }
0623     }
0624 
0625     bat->psy = power_supply_register(&pdev->dev, &psy_desc, &psy_cfg);
0626     if (IS_ERR(bat->psy)) {
0627         ret = PTR_ERR(bat->psy);
0628         goto err;
0629     }
0630 
0631     platform_set_drvdata(pdev, bat);
0632     return 0;
0633 
0634 err:
0635     while (--i >= 0)
0636         da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat);
0637 
0638     return ret;
0639 }
0640 static int da9052_bat_remove(struct platform_device *pdev)
0641 {
0642     int i;
0643     struct da9052_battery *bat = platform_get_drvdata(pdev);
0644 
0645     for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++)
0646         da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat);
0647 
0648     power_supply_unregister(bat->psy);
0649 
0650     return 0;
0651 }
0652 
0653 static struct platform_driver da9052_bat_driver = {
0654     .probe = da9052_bat_probe,
0655     .remove = da9052_bat_remove,
0656     .driver = {
0657         .name = "da9052-bat",
0658     },
0659 };
0660 module_platform_driver(da9052_bat_driver);
0661 
0662 MODULE_DESCRIPTION("DA9052 BAT Device Driver");
0663 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
0664 MODULE_LICENSE("GPL");
0665 MODULE_ALIAS("platform:da9052-bat");