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