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 v2.6.32-rc3 605 lines 16 kB view raw
1/* 2 * Battery charger driver for Dialog Semiconductor DA9030 3 * 4 * Copyright (C) 2008 Compulab, Ltd. 5 * Mike Rapoport <mike@compulab.co.il> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#include <linux/kernel.h> 13#include <linux/init.h> 14#include <linux/types.h> 15#include <linux/device.h> 16#include <linux/workqueue.h> 17#include <linux/module.h> 18#include <linux/platform_device.h> 19#include <linux/power_supply.h> 20#include <linux/mfd/da903x.h> 21 22#include <linux/debugfs.h> 23#include <linux/seq_file.h> 24 25#define DA9030_FAULT_LOG 0x0a 26#define DA9030_FAULT_LOG_OVER_TEMP (1 << 7) 27#define DA9030_FAULT_LOG_VBAT_OVER (1 << 4) 28 29#define DA9030_CHARGE_CONTROL 0x28 30#define DA9030_CHRG_CHARGER_ENABLE (1 << 7) 31 32#define DA9030_ADC_MAN_CONTROL 0x30 33#define DA9030_ADC_TBATREF_ENABLE (1 << 5) 34#define DA9030_ADC_LDO_INT_ENABLE (1 << 4) 35 36#define DA9030_ADC_AUTO_CONTROL 0x31 37#define DA9030_ADC_TBAT_ENABLE (1 << 5) 38#define DA9030_ADC_VBAT_IN_TXON (1 << 4) 39#define DA9030_ADC_VCH_ENABLE (1 << 3) 40#define DA9030_ADC_ICH_ENABLE (1 << 2) 41#define DA9030_ADC_VBAT_ENABLE (1 << 1) 42#define DA9030_ADC_AUTO_SLEEP_ENABLE (1 << 0) 43 44#define DA9030_VBATMON 0x32 45#define DA9030_VBATMONTXON 0x33 46#define DA9030_TBATHIGHP 0x34 47#define DA9030_TBATHIGHN 0x35 48#define DA9030_TBATLOW 0x36 49 50#define DA9030_VBAT_RES 0x41 51#define DA9030_VBATMIN_RES 0x42 52#define DA9030_VBATMINTXON_RES 0x43 53#define DA9030_ICHMAX_RES 0x44 54#define DA9030_ICHMIN_RES 0x45 55#define DA9030_ICHAVERAGE_RES 0x46 56#define DA9030_VCHMAX_RES 0x47 57#define DA9030_VCHMIN_RES 0x48 58#define DA9030_TBAT_RES 0x49 59 60struct da9030_adc_res { 61 uint8_t vbat_res; 62 uint8_t vbatmin_res; 63 uint8_t vbatmintxon; 64 uint8_t ichmax_res; 65 uint8_t ichmin_res; 66 uint8_t ichaverage_res; 67 uint8_t vchmax_res; 68 uint8_t vchmin_res; 69 uint8_t tbat_res; 70 uint8_t adc_in4_res; 71 uint8_t adc_in5_res; 72}; 73 74struct da9030_battery_thresholds { 75 int tbat_low; 76 int tbat_high; 77 int tbat_restart; 78 79 int vbat_low; 80 int vbat_crit; 81 int vbat_charge_start; 82 int vbat_charge_stop; 83 int vbat_charge_restart; 84 85 int vcharge_min; 86 int vcharge_max; 87}; 88 89struct da9030_charger { 90 struct power_supply psy; 91 92 struct device *master; 93 94 struct da9030_adc_res adc; 95 struct delayed_work work; 96 unsigned int interval; 97 98 struct power_supply_info *battery_info; 99 100 struct da9030_battery_thresholds thresholds; 101 102 unsigned int charge_milliamp; 103 unsigned int charge_millivolt; 104 105 /* charger status */ 106 bool chdet; 107 uint8_t fault; 108 int mA; 109 int mV; 110 bool is_on; 111 112 struct notifier_block nb; 113 114 /* platform callbacks for battery low and critical events */ 115 void (*battery_low)(void); 116 void (*battery_critical)(void); 117 118 struct dentry *debug_file; 119}; 120 121static inline int da9030_reg_to_mV(int reg) 122{ 123 return ((reg * 2650) >> 8) + 2650; 124} 125 126static inline int da9030_millivolt_to_reg(int mV) 127{ 128 return ((mV - 2650) << 8) / 2650; 129} 130 131static inline int da9030_reg_to_mA(int reg) 132{ 133 return ((reg * 24000) >> 8) / 15; 134} 135 136#ifdef CONFIG_DEBUG_FS 137static int bat_debug_show(struct seq_file *s, void *data) 138{ 139 struct da9030_charger *charger = s->private; 140 141 seq_printf(s, "charger is %s\n", charger->is_on ? "on" : "off"); 142 if (charger->chdet) { 143 seq_printf(s, "iset = %dmA, vset = %dmV\n", 144 charger->mA, charger->mV); 145 } 146 147 seq_printf(s, "vbat_res = %d (%dmV)\n", 148 charger->adc.vbat_res, 149 da9030_reg_to_mV(charger->adc.vbat_res)); 150 seq_printf(s, "vbatmin_res = %d (%dmV)\n", 151 charger->adc.vbatmin_res, 152 da9030_reg_to_mV(charger->adc.vbatmin_res)); 153 seq_printf(s, "vbatmintxon = %d (%dmV)\n", 154 charger->adc.vbatmintxon, 155 da9030_reg_to_mV(charger->adc.vbatmintxon)); 156 seq_printf(s, "ichmax_res = %d (%dmA)\n", 157 charger->adc.ichmax_res, 158 da9030_reg_to_mV(charger->adc.ichmax_res)); 159 seq_printf(s, "ichmin_res = %d (%dmA)\n", 160 charger->adc.ichmin_res, 161 da9030_reg_to_mA(charger->adc.ichmin_res)); 162 seq_printf(s, "ichaverage_res = %d (%dmA)\n", 163 charger->adc.ichaverage_res, 164 da9030_reg_to_mA(charger->adc.ichaverage_res)); 165 seq_printf(s, "vchmax_res = %d (%dmV)\n", 166 charger->adc.vchmax_res, 167 da9030_reg_to_mA(charger->adc.vchmax_res)); 168 seq_printf(s, "vchmin_res = %d (%dmV)\n", 169 charger->adc.vchmin_res, 170 da9030_reg_to_mV(charger->adc.vchmin_res)); 171 172 return 0; 173} 174 175static int debug_open(struct inode *inode, struct file *file) 176{ 177 return single_open(file, bat_debug_show, inode->i_private); 178} 179 180static const struct file_operations bat_debug_fops = { 181 .open = debug_open, 182 .read = seq_read, 183 .llseek = seq_lseek, 184 .release = single_release, 185}; 186 187static struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger) 188{ 189 charger->debug_file = debugfs_create_file("charger", 0666, 0, charger, 190 &bat_debug_fops); 191 return charger->debug_file; 192} 193 194static void da9030_bat_remove_debugfs(struct da9030_charger *charger) 195{ 196 debugfs_remove(charger->debug_file); 197} 198#else 199static inline struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger) 200{ 201 return NULL; 202} 203static inline void da9030_bat_remove_debugfs(struct da9030_charger *charger) 204{ 205} 206#endif 207 208static inline void da9030_read_adc(struct da9030_charger *charger, 209 struct da9030_adc_res *adc) 210{ 211 da903x_reads(charger->master, DA9030_VBAT_RES, 212 sizeof(*adc), (uint8_t *)adc); 213} 214 215static void da9030_charger_update_state(struct da9030_charger *charger) 216{ 217 uint8_t val; 218 219 da903x_read(charger->master, DA9030_CHARGE_CONTROL, &val); 220 charger->is_on = (val & DA9030_CHRG_CHARGER_ENABLE) ? 1 : 0; 221 charger->mA = ((val >> 3) & 0xf) * 100; 222 charger->mV = (val & 0x7) * 50 + 4000; 223 224 da9030_read_adc(charger, &charger->adc); 225 da903x_read(charger->master, DA9030_FAULT_LOG, &charger->fault); 226 charger->chdet = da903x_query_status(charger->master, 227 DA9030_STATUS_CHDET); 228} 229 230static void da9030_set_charge(struct da9030_charger *charger, int on) 231{ 232 uint8_t val; 233 234 if (on) { 235 val = DA9030_CHRG_CHARGER_ENABLE; 236 val |= (charger->charge_milliamp / 100) << 3; 237 val |= (charger->charge_millivolt - 4000) / 50; 238 charger->is_on = 1; 239 } else { 240 val = 0; 241 charger->is_on = 0; 242 } 243 244 da903x_write(charger->master, DA9030_CHARGE_CONTROL, val); 245 246 power_supply_changed(&charger->psy); 247} 248 249static void da9030_charger_check_state(struct da9030_charger *charger) 250{ 251 da9030_charger_update_state(charger); 252 253 /* we wake or boot with external power on */ 254 if (!charger->is_on) { 255 if ((charger->chdet) && 256 (charger->adc.vbat_res < 257 charger->thresholds.vbat_charge_start)) { 258 da9030_set_charge(charger, 1); 259 } 260 } else { 261 /* Charger has been pulled out */ 262 if (!charger->chdet) { 263 da9030_set_charge(charger, 0); 264 return; 265 } 266 267 if (charger->adc.vbat_res >= 268 charger->thresholds.vbat_charge_stop) { 269 da9030_set_charge(charger, 0); 270 da903x_write(charger->master, DA9030_VBATMON, 271 charger->thresholds.vbat_charge_restart); 272 } else if (charger->adc.vbat_res > 273 charger->thresholds.vbat_low) { 274 /* we are charging and passed LOW_THRESH, 275 so upate DA9030 VBAT threshold 276 */ 277 da903x_write(charger->master, DA9030_VBATMON, 278 charger->thresholds.vbat_low); 279 } 280 if (charger->adc.vchmax_res > charger->thresholds.vcharge_max || 281 charger->adc.vchmin_res < charger->thresholds.vcharge_min || 282 /* Tempreture readings are negative */ 283 charger->adc.tbat_res < charger->thresholds.tbat_high || 284 charger->adc.tbat_res > charger->thresholds.tbat_low) { 285 /* disable charger */ 286 da9030_set_charge(charger, 0); 287 } 288 } 289} 290 291static void da9030_charging_monitor(struct work_struct *work) 292{ 293 struct da9030_charger *charger; 294 295 charger = container_of(work, struct da9030_charger, work.work); 296 297 da9030_charger_check_state(charger); 298 299 /* reschedule for the next time */ 300 schedule_delayed_work(&charger->work, charger->interval); 301} 302 303static enum power_supply_property da9030_battery_props[] = { 304 POWER_SUPPLY_PROP_MODEL_NAME, 305 POWER_SUPPLY_PROP_STATUS, 306 POWER_SUPPLY_PROP_HEALTH, 307 POWER_SUPPLY_PROP_TECHNOLOGY, 308 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 309 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 310 POWER_SUPPLY_PROP_VOLTAGE_NOW, 311 POWER_SUPPLY_PROP_CURRENT_AVG, 312}; 313 314static void da9030_battery_check_status(struct da9030_charger *charger, 315 union power_supply_propval *val) 316{ 317 if (charger->chdet) { 318 if (charger->is_on) 319 val->intval = POWER_SUPPLY_STATUS_CHARGING; 320 else 321 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 322 } else { 323 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 324 } 325} 326 327static void da9030_battery_check_health(struct da9030_charger *charger, 328 union power_supply_propval *val) 329{ 330 if (charger->fault & DA9030_FAULT_LOG_OVER_TEMP) 331 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 332 else if (charger->fault & DA9030_FAULT_LOG_VBAT_OVER) 333 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 334 else 335 val->intval = POWER_SUPPLY_HEALTH_GOOD; 336} 337 338static int da9030_battery_get_property(struct power_supply *psy, 339 enum power_supply_property psp, 340 union power_supply_propval *val) 341{ 342 struct da9030_charger *charger; 343 charger = container_of(psy, struct da9030_charger, psy); 344 345 switch (psp) { 346 case POWER_SUPPLY_PROP_STATUS: 347 da9030_battery_check_status(charger, val); 348 break; 349 case POWER_SUPPLY_PROP_HEALTH: 350 da9030_battery_check_health(charger, val); 351 break; 352 case POWER_SUPPLY_PROP_TECHNOLOGY: 353 val->intval = charger->battery_info->technology; 354 break; 355 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 356 val->intval = charger->battery_info->voltage_max_design; 357 break; 358 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 359 val->intval = charger->battery_info->voltage_min_design; 360 break; 361 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 362 val->intval = da9030_reg_to_mV(charger->adc.vbat_res) * 1000; 363 break; 364 case POWER_SUPPLY_PROP_CURRENT_AVG: 365 val->intval = 366 da9030_reg_to_mA(charger->adc.ichaverage_res) * 1000; 367 break; 368 case POWER_SUPPLY_PROP_MODEL_NAME: 369 val->strval = charger->battery_info->name; 370 break; 371 default: 372 break; 373 } 374 375 return 0; 376} 377 378static void da9030_battery_vbat_event(struct da9030_charger *charger) 379{ 380 da9030_read_adc(charger, &charger->adc); 381 382 if (charger->is_on) 383 return; 384 385 if (charger->adc.vbat_res < charger->thresholds.vbat_low) { 386 /* set VBAT threshold for critical */ 387 da903x_write(charger->master, DA9030_VBATMON, 388 charger->thresholds.vbat_crit); 389 if (charger->battery_low) 390 charger->battery_low(); 391 } else if (charger->adc.vbat_res < 392 charger->thresholds.vbat_crit) { 393 /* notify the system of battery critical */ 394 if (charger->battery_critical) 395 charger->battery_critical(); 396 } 397} 398 399static int da9030_battery_event(struct notifier_block *nb, unsigned long event, 400 void *data) 401{ 402 struct da9030_charger *charger = 403 container_of(nb, struct da9030_charger, nb); 404 405 switch (event) { 406 case DA9030_EVENT_CHDET: 407 cancel_delayed_work_sync(&charger->work); 408 schedule_work(&charger->work.work); 409 break; 410 case DA9030_EVENT_VBATMON: 411 da9030_battery_vbat_event(charger); 412 break; 413 case DA9030_EVENT_CHIOVER: 414 case DA9030_EVENT_TBAT: 415 da9030_set_charge(charger, 0); 416 break; 417 } 418 419 return 0; 420} 421 422static void da9030_battery_convert_thresholds(struct da9030_charger *charger, 423 struct da9030_battery_info *pdata) 424{ 425 charger->thresholds.tbat_low = pdata->tbat_low; 426 charger->thresholds.tbat_high = pdata->tbat_high; 427 charger->thresholds.tbat_restart = pdata->tbat_restart; 428 429 charger->thresholds.vbat_low = 430 da9030_millivolt_to_reg(pdata->vbat_low); 431 charger->thresholds.vbat_crit = 432 da9030_millivolt_to_reg(pdata->vbat_crit); 433 charger->thresholds.vbat_charge_start = 434 da9030_millivolt_to_reg(pdata->vbat_charge_start); 435 charger->thresholds.vbat_charge_stop = 436 da9030_millivolt_to_reg(pdata->vbat_charge_stop); 437 charger->thresholds.vbat_charge_restart = 438 da9030_millivolt_to_reg(pdata->vbat_charge_restart); 439 440 charger->thresholds.vcharge_min = 441 da9030_millivolt_to_reg(pdata->vcharge_min); 442 charger->thresholds.vcharge_max = 443 da9030_millivolt_to_reg(pdata->vcharge_max); 444} 445 446static void da9030_battery_setup_psy(struct da9030_charger *charger) 447{ 448 struct power_supply *psy = &charger->psy; 449 struct power_supply_info *info = charger->battery_info; 450 451 psy->name = info->name; 452 psy->use_for_apm = info->use_for_apm; 453 psy->type = POWER_SUPPLY_TYPE_BATTERY; 454 psy->get_property = da9030_battery_get_property; 455 456 psy->properties = da9030_battery_props; 457 psy->num_properties = ARRAY_SIZE(da9030_battery_props); 458}; 459 460static int da9030_battery_charger_init(struct da9030_charger *charger) 461{ 462 char v[5]; 463 int ret; 464 465 v[0] = v[1] = charger->thresholds.vbat_low; 466 v[2] = charger->thresholds.tbat_high; 467 v[3] = charger->thresholds.tbat_restart; 468 v[4] = charger->thresholds.tbat_low; 469 470 ret = da903x_writes(charger->master, DA9030_VBATMON, 5, v); 471 if (ret) 472 return ret; 473 474 /* 475 * Enable reference voltage supply for ADC from the LDO_INTERNAL 476 * regulator. Must be set before ADC measurements can be made. 477 */ 478 ret = da903x_write(charger->master, DA9030_ADC_MAN_CONTROL, 479 DA9030_ADC_LDO_INT_ENABLE | 480 DA9030_ADC_TBATREF_ENABLE); 481 if (ret) 482 return ret; 483 484 /* enable auto ADC measuremnts */ 485 return da903x_write(charger->master, DA9030_ADC_AUTO_CONTROL, 486 DA9030_ADC_TBAT_ENABLE | DA9030_ADC_VBAT_IN_TXON | 487 DA9030_ADC_VCH_ENABLE | DA9030_ADC_ICH_ENABLE | 488 DA9030_ADC_VBAT_ENABLE | 489 DA9030_ADC_AUTO_SLEEP_ENABLE); 490} 491 492static int da9030_battery_probe(struct platform_device *pdev) 493{ 494 struct da9030_charger *charger; 495 struct da9030_battery_info *pdata = pdev->dev.platform_data; 496 int ret; 497 498 if (pdata == NULL) 499 return -EINVAL; 500 501 if (pdata->charge_milliamp >= 1500 || 502 pdata->charge_millivolt < 4000 || 503 pdata->charge_millivolt > 4350) 504 return -EINVAL; 505 506 charger = kzalloc(sizeof(*charger), GFP_KERNEL); 507 if (charger == NULL) 508 return -ENOMEM; 509 510 charger->master = pdev->dev.parent; 511 512 /* 10 seconds between monotor runs unless platfrom defines other 513 interval */ 514 charger->interval = msecs_to_jiffies( 515 (pdata->batmon_interval ? : 10) * 1000); 516 517 charger->charge_milliamp = pdata->charge_milliamp; 518 charger->charge_millivolt = pdata->charge_millivolt; 519 charger->battery_info = pdata->battery_info; 520 charger->battery_low = pdata->battery_low; 521 charger->battery_critical = pdata->battery_critical; 522 523 da9030_battery_convert_thresholds(charger, pdata); 524 525 ret = da9030_battery_charger_init(charger); 526 if (ret) 527 goto err_charger_init; 528 529 INIT_DELAYED_WORK(&charger->work, da9030_charging_monitor); 530 schedule_delayed_work(&charger->work, charger->interval); 531 532 charger->nb.notifier_call = da9030_battery_event; 533 ret = da903x_register_notifier(charger->master, &charger->nb, 534 DA9030_EVENT_CHDET | 535 DA9030_EVENT_VBATMON | 536 DA9030_EVENT_CHIOVER | 537 DA9030_EVENT_TBAT); 538 if (ret) 539 goto err_notifier; 540 541 da9030_battery_setup_psy(charger); 542 ret = power_supply_register(&pdev->dev, &charger->psy); 543 if (ret) 544 goto err_ps_register; 545 546 charger->debug_file = da9030_bat_create_debugfs(charger); 547 platform_set_drvdata(pdev, charger); 548 return 0; 549 550err_ps_register: 551 da903x_unregister_notifier(charger->master, &charger->nb, 552 DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON | 553 DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT); 554err_notifier: 555 cancel_delayed_work(&charger->work); 556 557err_charger_init: 558 kfree(charger); 559 560 return ret; 561} 562 563static int da9030_battery_remove(struct platform_device *dev) 564{ 565 struct da9030_charger *charger = platform_get_drvdata(dev); 566 567 da9030_bat_remove_debugfs(charger); 568 569 da903x_unregister_notifier(charger->master, &charger->nb, 570 DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON | 571 DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT); 572 cancel_delayed_work_sync(&charger->work); 573 da9030_set_charge(charger, 0); 574 power_supply_unregister(&charger->psy); 575 576 kfree(charger); 577 578 return 0; 579} 580 581static struct platform_driver da903x_battery_driver = { 582 .driver = { 583 .name = "da903x-battery", 584 .owner = THIS_MODULE, 585 }, 586 .probe = da9030_battery_probe, 587 .remove = da9030_battery_remove, 588}; 589 590static int da903x_battery_init(void) 591{ 592 return platform_driver_register(&da903x_battery_driver); 593} 594 595static void da903x_battery_exit(void) 596{ 597 platform_driver_unregister(&da903x_battery_driver); 598} 599 600module_init(da903x_battery_init); 601module_exit(da903x_battery_exit); 602 603MODULE_DESCRIPTION("DA9030 battery charger driver"); 604MODULE_AUTHOR("Mike Rapoport, CompuLab"); 605MODULE_LICENSE("GPL");