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