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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.4-rc2 655 lines 16 kB view raw
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 42enum charger_type_enum { 43 DA9052_NOCHARGER = 1, 44 DA9052_CHARGER, 45}; 46 47static 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 54static const u16 vc_tbl_ref[3] = {10, 25, 40}; 55/* Lookup table for voltage vs capacity */ 56static 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 170struct 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 179static inline int volt_reg_to_mV(int value) 180{ 181 return ((value * 1000) / 512) + 2500; 182} 183 184static inline int ichg_reg_to_mA(int value) 185{ 186 return (value * 3900) / 1000; 187} 188 189static 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 206static 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 222static 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 289static 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 302static 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 318static 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 330unsigned 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 350static 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 403static 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 433static 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 452static 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 487static 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 542static 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 555static 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 563static 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 572static 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 platform_set_drvdata(pdev, bat); 616 return 0; 617 618err: 619 for (; i >= 0; i--) { 620 irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); 621 free_irq(bat->da9052->irq_base + irq, bat); 622 } 623 kfree(bat); 624 return ret; 625} 626static int __devexit da9052_bat_remove(struct platform_device *pdev) 627{ 628 int i; 629 int irq; 630 struct da9052_battery *bat = platform_get_drvdata(pdev); 631 632 for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) { 633 irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]); 634 free_irq(bat->da9052->irq_base + irq, bat); 635 } 636 power_supply_unregister(&bat->psy); 637 kfree(bat); 638 639 return 0; 640} 641 642static struct platform_driver da9052_bat_driver = { 643 .probe = da9052_bat_probe, 644 .remove = __devexit_p(da9052_bat_remove), 645 .driver = { 646 .name = "da9052-bat", 647 .owner = THIS_MODULE, 648 }, 649}; 650module_platform_driver(da9052_bat_driver); 651 652MODULE_DESCRIPTION("DA9052 BAT Device Driver"); 653MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 654MODULE_LICENSE("GPL"); 655MODULE_ALIAS("platform:da9052-bat");