Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power_supply: Add DA9052 battery driver

Driver for DA9052 battery charger. This driver depends on DA9052 MFD core
dirver for definitions and methods.

This patch is functionally tested on Samsung SMDKV6410.

Signed-off-by: David Dajun Chen <dchen@diasemi.com>
Signed-off-by: Ashish Jangam <ashish.jangam@kpitcummins.com>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>

authored by

Ashish Jangam and committed by
Anton Vorontsov
ded7fc7b c934502d

+672
+7
drivers/power/Kconfig
··· 150 150 Say Y here to enable support for batteries charger integrated into 151 151 DA9030 PMIC. 152 152 153 + config BATTERY_DA9052 154 + tristate "Dialog DA9052 Battery" 155 + depends on PMIC_DA9052 156 + help 157 + Say Y here to enable support for batteries charger integrated into 158 + DA9052 PMIC. 159 + 153 160 config BATTERY_MAX17040 154 161 tristate "Maxim MAX17040 Fuel Gauge" 155 162 depends on I2C
+1
drivers/power/Makefile
··· 25 25 obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o 26 26 obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o 27 27 obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o 28 + obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o 28 29 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o 29 30 obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o 30 31 obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
+664
drivers/power/da9052-battery.c
··· 1 + /* 2 + * Batttery Driver for Dialog DA9052 PMICs 3 + * 4 + * Copyright(c) 2011 Dialog Semiconductor Ltd. 5 + * 6 + * Author: David Dajun Chen <dchen@diasemi.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify it 9 + * under the terms of the GNU General Public License as published by the 10 + * Free Software Foundation; either version 2 of the License, or (at your 11 + * option) any later version. 12 + */ 13 + 14 + #include <linux/delay.h> 15 + #include <linux/freezer.h> 16 + #include <linux/fs.h> 17 + #include <linux/jiffies.h> 18 + #include <linux/module.h> 19 + #include <linux/timer.h> 20 + #include <linux/uaccess.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/power_supply.h> 23 + 24 + #include <linux/mfd/da9052/da9052.h> 25 + #include <linux/mfd/da9052/pdata.h> 26 + #include <linux/mfd/da9052/reg.h> 27 + 28 + /* STATIC CONFIGURATION */ 29 + #define DA9052_BAT_CUTOFF_VOLT 2800 30 + #define DA9052_BAT_TSH 62000 31 + #define DA9052_BAT_LOW_CAP 4 32 + #define DA9052_AVG_SZ 4 33 + #define DA9052_VC_TBL_SZ 68 34 + #define DA9052_VC_TBL_REF_SZ 3 35 + 36 + #define DA9052_ISET_USB_MASK 0x0F 37 + #define DA9052_CHG_USB_ILIM_MASK 0x40 38 + #define DA9052_CHG_LIM_COLS 16 39 + 40 + #define DA9052_MEAN(x, y) ((x + y) / 2) 41 + 42 + enum charger_type_enum { 43 + DA9052_NOCHARGER = 1, 44 + DA9052_CHARGER, 45 + }; 46 + 47 + static const u16 da9052_chg_current_lim[2][DA9052_CHG_LIM_COLS] = { 48 + {70, 80, 90, 100, 110, 120, 400, 450, 49 + 500, 550, 600, 650, 700, 900, 1100, 1300}, 50 + {80, 90, 100, 110, 120, 400, 450, 500, 51 + 550, 600, 800, 1000, 1200, 1400, 1600, 1800}, 52 + }; 53 + 54 + static const u16 vc_tbl_ref[3] = {10, 25, 40}; 55 + /* Lookup table for voltage vs capacity */ 56 + static u32 const vc_tbl[3][68][2] = { 57 + /* For temperature 10 degree Celsius */ 58 + { 59 + {4082, 100}, {4036, 98}, 60 + {4020, 96}, {4008, 95}, 61 + {3997, 93}, {3983, 91}, 62 + {3964, 90}, {3943, 88}, 63 + {3926, 87}, {3912, 85}, 64 + {3900, 84}, {3890, 82}, 65 + {3881, 80}, {3873, 79}, 66 + {3865, 77}, {3857, 76}, 67 + {3848, 74}, {3839, 73}, 68 + {3829, 71}, {3820, 70}, 69 + {3811, 68}, {3802, 67}, 70 + {3794, 65}, {3785, 64}, 71 + {3778, 62}, {3770, 61}, 72 + {3763, 59}, {3756, 58}, 73 + {3750, 56}, {3744, 55}, 74 + {3738, 53}, {3732, 52}, 75 + {3727, 50}, {3722, 49}, 76 + {3717, 47}, {3712, 46}, 77 + {3708, 44}, {3703, 43}, 78 + {3700, 41}, {3696, 40}, 79 + {3693, 38}, {3691, 37}, 80 + {3688, 35}, {3686, 34}, 81 + {3683, 32}, {3681, 31}, 82 + {3678, 29}, {3675, 28}, 83 + {3672, 26}, {3669, 25}, 84 + {3665, 23}, {3661, 22}, 85 + {3656, 21}, {3651, 19}, 86 + {3645, 18}, {3639, 16}, 87 + {3631, 15}, {3622, 13}, 88 + {3611, 12}, {3600, 10}, 89 + {3587, 9}, {3572, 7}, 90 + {3548, 6}, {3503, 5}, 91 + {3420, 3}, {3268, 2}, 92 + {2992, 1}, {2746, 0} 93 + }, 94 + /* For temperature 25 degree Celsius */ 95 + { 96 + {4102, 100}, {4065, 98}, 97 + {4048, 96}, {4034, 95}, 98 + {4021, 93}, {4011, 92}, 99 + {4001, 90}, {3986, 88}, 100 + {3968, 87}, {3952, 85}, 101 + {3938, 84}, {3926, 82}, 102 + {3916, 81}, {3908, 79}, 103 + {3900, 77}, {3892, 76}, 104 + {3883, 74}, {3874, 73}, 105 + {3864, 71}, {3855, 70}, 106 + {3846, 68}, {3836, 67}, 107 + {3827, 65}, {3819, 64}, 108 + {3810, 62}, {3801, 61}, 109 + {3793, 59}, {3786, 58}, 110 + {3778, 56}, {3772, 55}, 111 + {3765, 53}, {3759, 52}, 112 + {3754, 50}, {3748, 49}, 113 + {3743, 47}, {3738, 46}, 114 + {3733, 44}, {3728, 43}, 115 + {3724, 41}, {3720, 40}, 116 + {3716, 38}, {3712, 37}, 117 + {3709, 35}, {3706, 34}, 118 + {3703, 33}, {3701, 31}, 119 + {3698, 30}, {3696, 28}, 120 + {3693, 27}, {3690, 25}, 121 + {3687, 24}, {3683, 22}, 122 + {3680, 21}, {3675, 19}, 123 + {3671, 18}, {3666, 17}, 124 + {3660, 15}, {3654, 14}, 125 + {3647, 12}, {3639, 11}, 126 + {3630, 9}, {3621, 8}, 127 + {3613, 6}, {3606, 5}, 128 + {3597, 4}, {3582, 2}, 129 + {3546, 1}, {2747, 0} 130 + }, 131 + /* For temperature 40 degree Celsius */ 132 + { 133 + {4114, 100}, {4081, 98}, 134 + {4065, 96}, {4050, 95}, 135 + {4036, 93}, {4024, 92}, 136 + {4013, 90}, {4002, 88}, 137 + {3990, 87}, {3976, 85}, 138 + {3962, 84}, {3950, 82}, 139 + {3939, 81}, {3930, 79}, 140 + {3921, 77}, {3912, 76}, 141 + {3902, 74}, {3893, 73}, 142 + {3883, 71}, {3874, 70}, 143 + {3865, 68}, {3856, 67}, 144 + {3847, 65}, {3838, 64}, 145 + {3829, 62}, {3820, 61}, 146 + {3812, 59}, {3803, 58}, 147 + {3795, 56}, {3787, 55}, 148 + {3780, 53}, {3773, 52}, 149 + {3767, 50}, {3761, 49}, 150 + {3756, 47}, {3751, 46}, 151 + {3746, 44}, {3741, 43}, 152 + {3736, 41}, {3732, 40}, 153 + {3728, 38}, {3724, 37}, 154 + {3720, 35}, {3716, 34}, 155 + {3713, 33}, {3710, 31}, 156 + {3707, 30}, {3704, 28}, 157 + {3701, 27}, {3698, 25}, 158 + {3695, 24}, {3691, 22}, 159 + {3686, 21}, {3681, 19}, 160 + {3676, 18}, {3671, 17}, 161 + {3666, 15}, {3661, 14}, 162 + {3655, 12}, {3648, 11}, 163 + {3640, 9}, {3632, 8}, 164 + {3622, 6}, {3616, 5}, 165 + {3611, 4}, {3604, 2}, 166 + {3594, 1}, {2747, 0} 167 + } 168 + }; 169 + 170 + struct da9052_battery { 171 + struct da9052 *da9052; 172 + struct power_supply psy; 173 + struct notifier_block nb; 174 + int charger_type; 175 + int status; 176 + int health; 177 + }; 178 + 179 + static inline int volt_reg_to_mV(int value) 180 + { 181 + return ((value * 1000) / 512) + 2500; 182 + } 183 + 184 + static inline int ichg_reg_to_mA(int value) 185 + { 186 + return (value * 3900) / 1000; 187 + } 188 + 189 + static int da9052_read_chgend_current(struct da9052_battery *bat, 190 + int *current_mA) 191 + { 192 + int ret; 193 + 194 + if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) 195 + return -EINVAL; 196 + 197 + ret = da9052_reg_read(bat->da9052, DA9052_ICHG_END_REG); 198 + if (ret < 0) 199 + return ret; 200 + 201 + *current_mA = ichg_reg_to_mA(ret & DA9052_ICHGEND_ICHGEND); 202 + 203 + return 0; 204 + } 205 + 206 + static int da9052_read_chg_current(struct da9052_battery *bat, int *current_mA) 207 + { 208 + int ret; 209 + 210 + if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) 211 + return -EINVAL; 212 + 213 + ret = da9052_reg_read(bat->da9052, DA9052_ICHG_AV_REG); 214 + if (ret < 0) 215 + return ret; 216 + 217 + *current_mA = ichg_reg_to_mA(ret & DA9052_ICHGAV_ICHGAV); 218 + 219 + return 0; 220 + } 221 + 222 + static int da9052_bat_check_status(struct da9052_battery *bat, int *status) 223 + { 224 + u8 v[2] = {0, 0}; 225 + u8 bat_status; 226 + u8 chg_end; 227 + int ret; 228 + int chg_current; 229 + int chg_end_current; 230 + bool dcinsel; 231 + bool dcindet; 232 + bool vbussel; 233 + bool vbusdet; 234 + bool dc; 235 + bool vbus; 236 + 237 + ret = da9052_group_read(bat->da9052, DA9052_STATUS_A_REG, 2, v); 238 + if (ret < 0) 239 + return ret; 240 + 241 + bat_status = v[0]; 242 + chg_end = v[1]; 243 + 244 + dcinsel = bat_status & DA9052_STATUSA_DCINSEL; 245 + dcindet = bat_status & DA9052_STATUSA_DCINDET; 246 + vbussel = bat_status & DA9052_STATUSA_VBUSSEL; 247 + vbusdet = bat_status & DA9052_STATUSA_VBUSDET; 248 + dc = dcinsel && dcindet; 249 + vbus = vbussel && vbusdet; 250 + 251 + /* Preference to WALL(DCIN) charger unit */ 252 + if (dc || vbus) { 253 + bat->charger_type = DA9052_CHARGER; 254 + 255 + /* If charging end flag is set and Charging current is greater 256 + * than charging end limit then battery is charging 257 + */ 258 + if ((chg_end & DA9052_STATUSB_CHGEND) != 0) { 259 + ret = da9052_read_chg_current(bat, &chg_current); 260 + if (ret < 0) 261 + return ret; 262 + ret = da9052_read_chgend_current(bat, &chg_end_current); 263 + if (ret < 0) 264 + return ret; 265 + 266 + if (chg_current >= chg_end_current) 267 + bat->status = POWER_SUPPLY_STATUS_CHARGING; 268 + else 269 + bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING; 270 + } else { 271 + /* If Charging end flag is cleared then battery is 272 + * charging 273 + */ 274 + bat->status = POWER_SUPPLY_STATUS_CHARGING; 275 + } 276 + } else if (dcindet || vbusdet) { 277 + bat->charger_type = DA9052_CHARGER; 278 + bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING; 279 + } else { 280 + bat->charger_type = DA9052_NOCHARGER; 281 + bat->status = POWER_SUPPLY_STATUS_DISCHARGING; 282 + } 283 + 284 + if (status != NULL) 285 + *status = bat->status; 286 + return 0; 287 + } 288 + 289 + static int da9052_bat_read_volt(struct da9052_battery *bat, int *volt_mV) 290 + { 291 + int volt; 292 + 293 + volt = da9052_adc_manual_read(bat->da9052, DA9052_ADC_MAN_MUXSEL_VBAT); 294 + if (volt < 0) 295 + return volt; 296 + 297 + *volt_mV = volt_reg_to_mV(volt); 298 + 299 + return 0; 300 + } 301 + 302 + static int da9052_bat_check_presence(struct da9052_battery *bat, int *illegal) 303 + { 304 + int bat_temp; 305 + 306 + bat_temp = da9052_adc_read_temp(bat->da9052); 307 + if (bat_temp < 0) 308 + return bat_temp; 309 + 310 + if (bat_temp > DA9052_BAT_TSH) 311 + *illegal = 1; 312 + else 313 + *illegal = 0; 314 + 315 + return 0; 316 + } 317 + 318 + static int da9052_bat_interpolate(int vbat_lower, int vbat_upper, 319 + int level_lower, int level_upper, 320 + int bat_voltage) 321 + { 322 + int tmp; 323 + 324 + tmp = ((level_upper - level_lower) * 1000) / (vbat_upper - vbat_lower); 325 + tmp = level_lower + (((bat_voltage - vbat_lower) * tmp) / 1000); 326 + 327 + return tmp; 328 + } 329 + 330 + unsigned char da9052_determine_vc_tbl_index(unsigned char adc_temp) 331 + { 332 + int i; 333 + 334 + if (adc_temp <= vc_tbl_ref[0]) 335 + return 0; 336 + 337 + if (adc_temp > vc_tbl_ref[DA9052_VC_TBL_REF_SZ - 1]) 338 + return DA9052_VC_TBL_REF_SZ - 1; 339 + 340 + for (i = 0; i < DA9052_VC_TBL_REF_SZ; i++) { 341 + if ((adc_temp > vc_tbl_ref[i]) && 342 + (adc_temp <= DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1]))) 343 + return i; 344 + if ((adc_temp > DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1])) 345 + && (adc_temp <= vc_tbl_ref[i])) 346 + return i + 1; 347 + } 348 + } 349 + 350 + static int da9052_bat_read_capacity(struct da9052_battery *bat, int *capacity) 351 + { 352 + int adc_temp; 353 + int bat_voltage; 354 + int vbat_lower; 355 + int vbat_upper; 356 + int level_upper; 357 + int level_lower; 358 + int ret; 359 + int flag; 360 + int i = 0; 361 + int j; 362 + 363 + ret = da9052_bat_read_volt(bat, &bat_voltage); 364 + if (ret < 0) 365 + return ret; 366 + 367 + adc_temp = da9052_adc_read_temp(bat->da9052); 368 + if (adc_temp < 0) 369 + return adc_temp; 370 + 371 + i = da9052_determine_vc_tbl_index(adc_temp); 372 + 373 + if (bat_voltage >= vc_tbl[i][0][0]) { 374 + *capacity = 100; 375 + return 0; 376 + } 377 + if (bat_voltage <= vc_tbl[i][DA9052_VC_TBL_SZ - 1][0]) { 378 + *capacity = 0; 379 + return 0; 380 + } 381 + flag = 0; 382 + 383 + for (j = 0; j < (DA9052_VC_TBL_SZ-1); j++) { 384 + if ((bat_voltage <= vc_tbl[i][j][0]) && 385 + (bat_voltage >= vc_tbl[i][j + 1][0])) { 386 + vbat_upper = vc_tbl[i][j][0]; 387 + vbat_lower = vc_tbl[i][j + 1][0]; 388 + level_upper = vc_tbl[i][j][1]; 389 + level_lower = vc_tbl[i][j + 1][1]; 390 + flag = 1; 391 + break; 392 + } 393 + } 394 + if (!flag) 395 + return -EIO; 396 + 397 + *capacity = da9052_bat_interpolate(vbat_lower, vbat_upper, level_lower, 398 + level_upper, bat_voltage); 399 + 400 + return 0; 401 + } 402 + 403 + static int da9052_bat_check_health(struct da9052_battery *bat, int *health) 404 + { 405 + int ret; 406 + int bat_illegal; 407 + int capacity; 408 + 409 + ret = da9052_bat_check_presence(bat, &bat_illegal); 410 + if (ret < 0) 411 + return ret; 412 + 413 + if (bat_illegal) { 414 + bat->health = POWER_SUPPLY_HEALTH_UNKNOWN; 415 + return 0; 416 + } 417 + 418 + if (bat->health != POWER_SUPPLY_HEALTH_OVERHEAT) { 419 + ret = da9052_bat_read_capacity(bat, &capacity); 420 + if (ret < 0) 421 + return ret; 422 + if (capacity < DA9052_BAT_LOW_CAP) 423 + bat->health = POWER_SUPPLY_HEALTH_DEAD; 424 + else 425 + bat->health = POWER_SUPPLY_HEALTH_GOOD; 426 + } 427 + 428 + *health = bat->health; 429 + 430 + return 0; 431 + } 432 + 433 + static irqreturn_t da9052_bat_irq(int irq, void *data) 434 + { 435 + struct da9052_battery *bat = data; 436 + 437 + irq -= bat->da9052->irq_base; 438 + 439 + if (irq == DA9052_IRQ_CHGEND) 440 + bat->status = POWER_SUPPLY_STATUS_FULL; 441 + else 442 + da9052_bat_check_status(bat, NULL); 443 + 444 + if (irq == DA9052_IRQ_CHGEND || irq == DA9052_IRQ_DCIN || 445 + irq == DA9052_IRQ_VBUS || irq == DA9052_IRQ_TBAT) { 446 + power_supply_changed(&bat->psy); 447 + } 448 + 449 + return IRQ_HANDLED; 450 + } 451 + 452 + static int da9052_USB_current_notifier(struct notifier_block *nb, 453 + unsigned long events, void *data) 454 + { 455 + u8 row; 456 + u8 col; 457 + int *current_mA = data; 458 + int ret; 459 + struct da9052_battery *bat = container_of(nb, struct da9052_battery, 460 + nb); 461 + 462 + if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) 463 + return -EPERM; 464 + 465 + ret = da9052_reg_read(bat->da9052, DA9052_CHGBUCK_REG); 466 + if (ret & DA9052_CHG_USB_ILIM_MASK) 467 + return -EPERM; 468 + 469 + if (bat->da9052->chip_id == DA9052) 470 + row = 0; 471 + else 472 + row = 1; 473 + 474 + if (*current_mA < da9052_chg_current_lim[row][0] || 475 + *current_mA > da9052_chg_current_lim[row][DA9052_CHG_LIM_COLS - 1]) 476 + return -EINVAL; 477 + 478 + for (col = 0; col <= DA9052_CHG_LIM_COLS - 1 ; col++) { 479 + if (*current_mA <= da9052_chg_current_lim[row][col]) 480 + break; 481 + } 482 + 483 + return da9052_reg_update(bat->da9052, DA9052_ISET_REG, 484 + DA9052_ISET_USB_MASK, col); 485 + } 486 + 487 + static int da9052_bat_get_property(struct power_supply *psy, 488 + enum power_supply_property psp, 489 + union power_supply_propval *val) 490 + { 491 + int ret; 492 + int illegal; 493 + struct da9052_battery *bat = container_of(psy, struct da9052_battery, 494 + psy); 495 + 496 + ret = da9052_bat_check_presence(bat, &illegal); 497 + if (ret < 0) 498 + return ret; 499 + 500 + if (illegal && psp != POWER_SUPPLY_PROP_PRESENT) 501 + return -ENODEV; 502 + 503 + switch (psp) { 504 + case POWER_SUPPLY_PROP_STATUS: 505 + ret = da9052_bat_check_status(bat, &val->intval); 506 + break; 507 + case POWER_SUPPLY_PROP_ONLINE: 508 + val->intval = 509 + (bat->charger_type == DA9052_NOCHARGER) ? 0 : 1; 510 + break; 511 + case POWER_SUPPLY_PROP_PRESENT: 512 + ret = da9052_bat_check_presence(bat, &val->intval); 513 + break; 514 + case POWER_SUPPLY_PROP_HEALTH: 515 + ret = da9052_bat_check_health(bat, &val->intval); 516 + break; 517 + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 518 + val->intval = DA9052_BAT_CUTOFF_VOLT * 1000; 519 + break; 520 + case POWER_SUPPLY_PROP_VOLTAGE_AVG: 521 + ret = da9052_bat_read_volt(bat, &val->intval); 522 + break; 523 + case POWER_SUPPLY_PROP_CURRENT_AVG: 524 + ret = da9052_read_chg_current(bat, &val->intval); 525 + break; 526 + case POWER_SUPPLY_PROP_CAPACITY: 527 + ret = da9052_bat_read_capacity(bat, &val->intval); 528 + break; 529 + case POWER_SUPPLY_PROP_TEMP: 530 + val->intval = da9052_adc_read_temp(bat->da9052); 531 + ret = val->intval; 532 + break; 533 + case POWER_SUPPLY_PROP_TECHNOLOGY: 534 + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 535 + break; 536 + default: 537 + return -EINVAL; 538 + } 539 + return ret; 540 + } 541 + 542 + static enum power_supply_property da9052_bat_props[] = { 543 + POWER_SUPPLY_PROP_STATUS, 544 + POWER_SUPPLY_PROP_ONLINE, 545 + POWER_SUPPLY_PROP_PRESENT, 546 + POWER_SUPPLY_PROP_HEALTH, 547 + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 548 + POWER_SUPPLY_PROP_VOLTAGE_AVG, 549 + POWER_SUPPLY_PROP_CURRENT_AVG, 550 + POWER_SUPPLY_PROP_CAPACITY, 551 + POWER_SUPPLY_PROP_TEMP, 552 + POWER_SUPPLY_PROP_TECHNOLOGY, 553 + }; 554 + 555 + static struct power_supply template_battery = { 556 + .name = "da9052-bat", 557 + .type = POWER_SUPPLY_TYPE_BATTERY, 558 + .properties = da9052_bat_props, 559 + .num_properties = ARRAY_SIZE(da9052_bat_props), 560 + .get_property = da9052_bat_get_property, 561 + }; 562 + 563 + static const char *const da9052_bat_irqs[] = { 564 + "BATT TEMP", 565 + "DCIN DET", 566 + "DCIN REM", 567 + "VBUS DET", 568 + "VBUS REM", 569 + "CHG END", 570 + }; 571 + 572 + static s32 __devinit da9052_bat_probe(struct platform_device *pdev) 573 + { 574 + struct da9052_pdata *pdata; 575 + struct da9052_battery *bat; 576 + int ret; 577 + int irq; 578 + int i; 579 + 580 + bat = kzalloc(sizeof(struct da9052_battery), GFP_KERNEL); 581 + if (!bat) 582 + return -ENOMEM; 583 + 584 + bat->da9052 = dev_get_drvdata(pdev->dev.parent); 585 + bat->psy = template_battery; 586 + bat->charger_type = DA9052_NOCHARGER; 587 + bat->status = POWER_SUPPLY_STATUS_UNKNOWN; 588 + bat->health = POWER_SUPPLY_HEALTH_UNKNOWN; 589 + bat->nb.notifier_call = da9052_USB_current_notifier; 590 + 591 + pdata = bat->da9052->dev->platform_data; 592 + if (pdata != NULL && pdata->use_for_apm) 593 + bat->psy.use_for_apm = pdata->use_for_apm; 594 + else 595 + bat->psy.use_for_apm = 1; 596 + 597 + for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) { 598 + irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); 599 + ret = request_threaded_irq(bat->da9052->irq_base + irq, 600 + NULL, da9052_bat_irq, 601 + IRQF_TRIGGER_LOW | IRQF_ONESHOT, 602 + da9052_bat_irqs[i], bat); 603 + if (ret != 0) { 604 + dev_err(bat->da9052->dev, 605 + "DA9052 failed to request %s IRQ %d: %d\n", 606 + da9052_bat_irqs[i], irq, ret); 607 + goto err; 608 + } 609 + } 610 + 611 + ret = power_supply_register(&pdev->dev, &bat->psy); 612 + if (ret) 613 + goto err; 614 + 615 + return 0; 616 + 617 + err: 618 + for (; i >= 0; i--) { 619 + irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); 620 + free_irq(bat->da9052->irq_base + irq, bat); 621 + } 622 + kfree(bat); 623 + return ret; 624 + } 625 + static int __devexit da9052_bat_remove(struct platform_device *pdev) 626 + { 627 + int i; 628 + int irq; 629 + struct da9052_battery *bat = platform_get_drvdata(pdev); 630 + 631 + for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) { 632 + irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); 633 + free_irq(bat->da9052->irq_base + irq, bat); 634 + } 635 + power_supply_unregister(&bat->psy); 636 + 637 + return 0; 638 + } 639 + 640 + static struct platform_driver da9052_bat_driver = { 641 + .probe = da9052_bat_probe, 642 + .remove = __devexit_p(da9052_bat_remove), 643 + .driver = { 644 + .name = "da9052-bat", 645 + .owner = THIS_MODULE, 646 + }, 647 + }; 648 + 649 + static int __init da9052_bat_init(void) 650 + { 651 + return platform_driver_register(&da9052_bat_driver); 652 + } 653 + module_init(da9052_bat_init); 654 + 655 + static void __exit da9052_bat_exit(void) 656 + { 657 + platform_driver_unregister(&da9052_bat_driver); 658 + } 659 + module_exit(da9052_bat_exit); 660 + 661 + MODULE_DESCRIPTION("DA9052 BAT Device Driver"); 662 + MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 663 + MODULE_LICENSE("GPL"); 664 + MODULE_ALIAS("platform:da9052-bat");