1 /* 2 * Battery driver for wm8350 PMIC 3 * 4 * Copyright 2007, 2008 Wolfson Microelectronics PLC. 5 * 6 * Based on OLPC Battery Driver 7 * 8 * Copyright 2006 David Woodhouse <dwmw2@infradead.org> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15 #include <linux/module.h> 16 #include <linux/err.h> 17 #include <linux/platform_device.h> 18 #include <linux/power_supply.h> 19 #include <linux/mfd/wm8350/supply.h> 20 #include <linux/mfd/wm8350/core.h> 21 #include <linux/mfd/wm8350/comparator.h> 22 23 static int wm8350_read_battery_uvolts(struct wm8350 *wm8350) 24 { 25 return wm8350_read_auxadc(wm8350, WM8350_AUXADC_BATT, 0, 0) 26 * WM8350_AUX_COEFF; 27 } 28 29 static int wm8350_read_line_uvolts(struct wm8350 *wm8350) 30 { 31 return wm8350_read_auxadc(wm8350, WM8350_AUXADC_LINE, 0, 0) 32 * WM8350_AUX_COEFF; 33 } 34 35 static int wm8350_read_usb_uvolts(struct wm8350 *wm8350) 36 { 37 return wm8350_read_auxadc(wm8350, WM8350_AUXADC_USB, 0, 0) 38 * WM8350_AUX_COEFF; 39 } 40 41 #define WM8350_BATT_SUPPLY 1 42 #define WM8350_USB_SUPPLY 2 43 #define WM8350_LINE_SUPPLY 4 44 45 static inline int wm8350_charge_time_min(struct wm8350 *wm8350, int min) 46 { 47 if (!wm8350->power.rev_g_coeff) 48 return (((min - 30) / 15) & 0xf) << 8; 49 else 50 return (((min - 30) / 30) & 0xf) << 8; 51 } 52 53 static int wm8350_get_supplies(struct wm8350 *wm8350) 54 { 55 u16 sm, ov, co, chrg; 56 int supplies = 0; 57 58 sm = wm8350_reg_read(wm8350, WM8350_STATE_MACHINE_STATUS); 59 ov = wm8350_reg_read(wm8350, WM8350_MISC_OVERRIDES); 60 co = wm8350_reg_read(wm8350, WM8350_COMPARATOR_OVERRIDES); 61 chrg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2); 62 63 /* USB_SM */ 64 sm = (sm & WM8350_USB_SM_MASK) >> WM8350_USB_SM_SHIFT; 65 66 /* CHG_ISEL */ 67 chrg &= WM8350_CHG_ISEL_MASK; 68 69 /* If the USB state machine is active then we're using that with or 70 * without battery, otherwise check for wall supply */ 71 if (((sm == WM8350_USB_SM_100_SLV) || 72 (sm == WM8350_USB_SM_500_SLV) || 73 (sm == WM8350_USB_SM_STDBY_SLV)) 74 && !(ov & WM8350_USB_LIMIT_OVRDE)) 75 supplies = WM8350_USB_SUPPLY; 76 else if (((sm == WM8350_USB_SM_100_SLV) || 77 (sm == WM8350_USB_SM_500_SLV) || 78 (sm == WM8350_USB_SM_STDBY_SLV)) 79 && (ov & WM8350_USB_LIMIT_OVRDE) && (chrg == 0)) 80 supplies = WM8350_USB_SUPPLY | WM8350_BATT_SUPPLY; 81 else if (co & WM8350_WALL_FB_OVRDE) 82 supplies = WM8350_LINE_SUPPLY; 83 else 84 supplies = WM8350_BATT_SUPPLY; 85 86 return supplies; 87 } 88 89 static int wm8350_charger_config(struct wm8350 *wm8350, 90 struct wm8350_charger_policy *policy) 91 { 92 u16 reg, eoc_mA, fast_limit_mA; 93 94 if (!policy) { 95 dev_warn(wm8350->dev, 96 "No charger policy, charger not configured.\n"); 97 return -EINVAL; 98 } 99 100 /* make sure USB fast charge current is not > 500mA */ 101 if (policy->fast_limit_USB_mA > 500) { 102 dev_err(wm8350->dev, "USB fast charge > 500mA\n"); 103 return -EINVAL; 104 } 105 106 eoc_mA = WM8350_CHG_EOC_mA(policy->eoc_mA); 107 108 wm8350_reg_unlock(wm8350); 109 110 reg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1) 111 & WM8350_CHG_ENA_R168; 112 wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1, 113 reg | eoc_mA | policy->trickle_start_mV | 114 WM8350_CHG_TRICKLE_TEMP_CHOKE | 115 WM8350_CHG_TRICKLE_USB_CHOKE | 116 WM8350_CHG_FAST_USB_THROTTLE); 117 118 if (wm8350_get_supplies(wm8350) & WM8350_USB_SUPPLY) { 119 fast_limit_mA = 120 WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_USB_mA); 121 wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2, 122 policy->charge_mV | policy->trickle_charge_USB_mA | 123 fast_limit_mA | wm8350_charge_time_min(wm8350, 124 policy->charge_timeout)); 125 126 } else { 127 fast_limit_mA = 128 WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_mA); 129 wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2, 130 policy->charge_mV | policy->trickle_charge_mA | 131 fast_limit_mA | wm8350_charge_time_min(wm8350, 132 policy->charge_timeout)); 133 } 134 135 wm8350_reg_lock(wm8350); 136 return 0; 137 } 138 139 static int wm8350_batt_status(struct wm8350 *wm8350) 140 { 141 u16 state; 142 143 state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2); 144 state &= WM8350_CHG_STS_MASK; 145 146 switch (state) { 147 case WM8350_CHG_STS_OFF: 148 return POWER_SUPPLY_STATUS_DISCHARGING; 149 150 case WM8350_CHG_STS_TRICKLE: 151 case WM8350_CHG_STS_FAST: 152 return POWER_SUPPLY_STATUS_CHARGING; 153 154 default: 155 return POWER_SUPPLY_STATUS_UNKNOWN; 156 } 157 } 158 159 static ssize_t charger_state_show(struct device *dev, 160 struct device_attribute *attr, char *buf) 161 { 162 struct wm8350 *wm8350 = dev_get_drvdata(dev); 163 char *charge; 164 int state; 165 166 state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) & 167 WM8350_CHG_STS_MASK; 168 switch (state) { 169 case WM8350_CHG_STS_OFF: 170 charge = "Charger Off"; 171 break; 172 case WM8350_CHG_STS_TRICKLE: 173 charge = "Trickle Charging"; 174 break; 175 case WM8350_CHG_STS_FAST: 176 charge = "Fast Charging"; 177 break; 178 default: 179 return 0; 180 } 181 182 return sprintf(buf, "%s\n", charge); 183 } 184 185 static DEVICE_ATTR_RO(charger_state); 186 187 static irqreturn_t wm8350_charger_handler(int irq, void *data) 188 { 189 struct wm8350 *wm8350 = data; 190 struct wm8350_power *power = &wm8350->power; 191 struct wm8350_charger_policy *policy = power->policy; 192 193 switch (irq - wm8350->irq_base) { 194 case WM8350_IRQ_CHG_BAT_FAIL: 195 dev_err(wm8350->dev, "battery failed\n"); 196 break; 197 case WM8350_IRQ_CHG_TO: 198 dev_err(wm8350->dev, "charger timeout\n"); 199 power_supply_changed(power->battery); 200 break; 201 202 case WM8350_IRQ_CHG_BAT_HOT: 203 case WM8350_IRQ_CHG_BAT_COLD: 204 case WM8350_IRQ_CHG_START: 205 case WM8350_IRQ_CHG_END: 206 power_supply_changed(power->battery); 207 break; 208 209 case WM8350_IRQ_CHG_FAST_RDY: 210 dev_dbg(wm8350->dev, "fast charger ready\n"); 211 wm8350_charger_config(wm8350, policy); 212 wm8350_reg_unlock(wm8350); 213 wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1, 214 WM8350_CHG_FAST); 215 wm8350_reg_lock(wm8350); 216 break; 217 218 case WM8350_IRQ_CHG_VBATT_LT_3P9: 219 dev_warn(wm8350->dev, "battery < 3.9V\n"); 220 break; 221 case WM8350_IRQ_CHG_VBATT_LT_3P1: 222 dev_warn(wm8350->dev, "battery < 3.1V\n"); 223 break; 224 case WM8350_IRQ_CHG_VBATT_LT_2P85: 225 dev_warn(wm8350->dev, "battery < 2.85V\n"); 226 break; 227 228 /* Supply change. We will overnotify but it should do 229 * no harm. */ 230 case WM8350_IRQ_EXT_USB_FB: 231 case WM8350_IRQ_EXT_WALL_FB: 232 wm8350_charger_config(wm8350, policy); 233 /* Fall through */ 234 case WM8350_IRQ_EXT_BAT_FB: 235 power_supply_changed(power->battery); 236 power_supply_changed(power->usb); 237 power_supply_changed(power->ac); 238 break; 239 240 default: 241 dev_err(wm8350->dev, "Unknown interrupt %d\n", irq); 242 } 243 244 return IRQ_HANDLED; 245 } 246 247 /********************************************************************* 248 * AC Power 249 *********************************************************************/ 250 static int wm8350_ac_get_prop(struct power_supply *psy, 251 enum power_supply_property psp, 252 union power_supply_propval *val) 253 { 254 struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent); 255 int ret = 0; 256 257 switch (psp) { 258 case POWER_SUPPLY_PROP_ONLINE: 259 val->intval = !!(wm8350_get_supplies(wm8350) & 260 WM8350_LINE_SUPPLY); 261 break; 262 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 263 val->intval = wm8350_read_line_uvolts(wm8350); 264 break; 265 default: 266 ret = -EINVAL; 267 break; 268 } 269 return ret; 270 } 271 272 static enum power_supply_property wm8350_ac_props[] = { 273 POWER_SUPPLY_PROP_ONLINE, 274 POWER_SUPPLY_PROP_VOLTAGE_NOW, 275 }; 276 277 /********************************************************************* 278 * USB Power 279 *********************************************************************/ 280 static int wm8350_usb_get_prop(struct power_supply *psy, 281 enum power_supply_property psp, 282 union power_supply_propval *val) 283 { 284 struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent); 285 int ret = 0; 286 287 switch (psp) { 288 case POWER_SUPPLY_PROP_ONLINE: 289 val->intval = !!(wm8350_get_supplies(wm8350) & 290 WM8350_USB_SUPPLY); 291 break; 292 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 293 val->intval = wm8350_read_usb_uvolts(wm8350); 294 break; 295 default: 296 ret = -EINVAL; 297 break; 298 } 299 return ret; 300 } 301 302 static enum power_supply_property wm8350_usb_props[] = { 303 POWER_SUPPLY_PROP_ONLINE, 304 POWER_SUPPLY_PROP_VOLTAGE_NOW, 305 }; 306 307 /********************************************************************* 308 * Battery properties 309 *********************************************************************/ 310 311 static int wm8350_bat_check_health(struct wm8350 *wm8350) 312 { 313 u16 reg; 314 315 if (wm8350_read_battery_uvolts(wm8350) < 2850000) 316 return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 317 318 reg = wm8350_reg_read(wm8350, WM8350_CHARGER_OVERRIDES); 319 if (reg & WM8350_CHG_BATT_HOT_OVRDE) 320 return POWER_SUPPLY_HEALTH_OVERHEAT; 321 322 if (reg & WM8350_CHG_BATT_COLD_OVRDE) 323 return POWER_SUPPLY_HEALTH_COLD; 324 325 return POWER_SUPPLY_HEALTH_GOOD; 326 } 327 328 static int wm8350_bat_get_charge_type(struct wm8350 *wm8350) 329 { 330 int state; 331 332 state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) & 333 WM8350_CHG_STS_MASK; 334 switch (state) { 335 case WM8350_CHG_STS_OFF: 336 return POWER_SUPPLY_CHARGE_TYPE_NONE; 337 case WM8350_CHG_STS_TRICKLE: 338 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 339 case WM8350_CHG_STS_FAST: 340 return POWER_SUPPLY_CHARGE_TYPE_FAST; 341 default: 342 return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 343 } 344 } 345 346 static int wm8350_bat_get_property(struct power_supply *psy, 347 enum power_supply_property psp, 348 union power_supply_propval *val) 349 { 350 struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent); 351 int ret = 0; 352 353 switch (psp) { 354 case POWER_SUPPLY_PROP_STATUS: 355 val->intval = wm8350_batt_status(wm8350); 356 break; 357 case POWER_SUPPLY_PROP_ONLINE: 358 val->intval = !!(wm8350_get_supplies(wm8350) & 359 WM8350_BATT_SUPPLY); 360 break; 361 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 362 val->intval = wm8350_read_battery_uvolts(wm8350); 363 break; 364 case POWER_SUPPLY_PROP_HEALTH: 365 val->intval = wm8350_bat_check_health(wm8350); 366 break; 367 case POWER_SUPPLY_PROP_CHARGE_TYPE: 368 val->intval = wm8350_bat_get_charge_type(wm8350); 369 break; 370 default: 371 ret = -EINVAL; 372 break; 373 } 374 375 return ret; 376 } 377 378 static enum power_supply_property wm8350_bat_props[] = { 379 POWER_SUPPLY_PROP_STATUS, 380 POWER_SUPPLY_PROP_ONLINE, 381 POWER_SUPPLY_PROP_VOLTAGE_NOW, 382 POWER_SUPPLY_PROP_HEALTH, 383 POWER_SUPPLY_PROP_CHARGE_TYPE, 384 }; 385 386 static const struct power_supply_desc wm8350_ac_desc = { 387 .name = "wm8350-ac", 388 .type = POWER_SUPPLY_TYPE_MAINS, 389 .properties = wm8350_ac_props, 390 .num_properties = ARRAY_SIZE(wm8350_ac_props), 391 .get_property = wm8350_ac_get_prop, 392 }; 393 394 static const struct power_supply_desc wm8350_battery_desc = { 395 .name = "wm8350-battery", 396 .properties = wm8350_bat_props, 397 .num_properties = ARRAY_SIZE(wm8350_bat_props), 398 .get_property = wm8350_bat_get_property, 399 .use_for_apm = 1, 400 }; 401 402 static const struct power_supply_desc wm8350_usb_desc = { 403 .name = "wm8350-usb", 404 .type = POWER_SUPPLY_TYPE_USB, 405 .properties = wm8350_usb_props, 406 .num_properties = ARRAY_SIZE(wm8350_usb_props), 407 .get_property = wm8350_usb_get_prop, 408 }; 409 410 /********************************************************************* 411 * Initialisation 412 *********************************************************************/ 413 414 static void wm8350_init_charger(struct wm8350 *wm8350) 415 { 416 /* register our interest in charger events */ 417 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, 418 wm8350_charger_handler, 0, "Battery hot", wm8350); 419 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, 420 wm8350_charger_handler, 0, "Battery cold", wm8350); 421 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, 422 wm8350_charger_handler, 0, "Battery fail", wm8350); 423 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, 424 wm8350_charger_handler, 0, 425 "Charger timeout", wm8350); 426 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, 427 wm8350_charger_handler, 0, 428 "Charge end", wm8350); 429 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, 430 wm8350_charger_handler, 0, 431 "Charge start", wm8350); 432 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, 433 wm8350_charger_handler, 0, 434 "Fast charge ready", wm8350); 435 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, 436 wm8350_charger_handler, 0, 437 "Battery <3.9V", wm8350); 438 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, 439 wm8350_charger_handler, 0, 440 "Battery <3.1V", wm8350); 441 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, 442 wm8350_charger_handler, 0, 443 "Battery <2.85V", wm8350); 444 445 /* and supply change events */ 446 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, 447 wm8350_charger_handler, 0, "USB", wm8350); 448 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, 449 wm8350_charger_handler, 0, "Wall", wm8350); 450 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, 451 wm8350_charger_handler, 0, "Battery", wm8350); 452 } 453 454 static void free_charger_irq(struct wm8350 *wm8350) 455 { 456 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350); 457 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350); 458 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350); 459 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); 460 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); 461 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); 462 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); 463 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); 464 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); 465 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350); 466 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350); 467 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350); 468 } 469 470 static int wm8350_power_probe(struct platform_device *pdev) 471 { 472 struct wm8350 *wm8350 = platform_get_drvdata(pdev); 473 struct wm8350_power *power = &wm8350->power; 474 struct wm8350_charger_policy *policy = power->policy; 475 int ret; 476 477 power->ac = power_supply_register(&pdev->dev, &wm8350_ac_desc, NULL); 478 if (IS_ERR(power->ac)) 479 return PTR_ERR(power->ac); 480 481 power->battery = power_supply_register(&pdev->dev, &wm8350_battery_desc, 482 NULL); 483 if (IS_ERR(power->battery)) { 484 ret = PTR_ERR(power->battery); 485 goto battery_failed; 486 } 487 488 power->usb = power_supply_register(&pdev->dev, &wm8350_usb_desc, NULL); 489 if (IS_ERR(power->usb)) { 490 ret = PTR_ERR(power->usb); 491 goto usb_failed; 492 } 493 494 ret = device_create_file(&pdev->dev, &dev_attr_charger_state); 495 if (ret < 0) 496 dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret); 497 ret = 0; 498 499 wm8350_init_charger(wm8350); 500 if (wm8350_charger_config(wm8350, policy) == 0) { 501 wm8350_reg_unlock(wm8350); 502 wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA); 503 wm8350_reg_lock(wm8350); 504 } 505 506 return ret; 507 508 usb_failed: 509 power_supply_unregister(power->battery); 510 battery_failed: 511 power_supply_unregister(power->ac); 512 513 return ret; 514 } 515 516 static int wm8350_power_remove(struct platform_device *pdev) 517 { 518 struct wm8350 *wm8350 = platform_get_drvdata(pdev); 519 struct wm8350_power *power = &wm8350->power; 520 521 free_charger_irq(wm8350); 522 device_remove_file(&pdev->dev, &dev_attr_charger_state); 523 power_supply_unregister(power->battery); 524 power_supply_unregister(power->ac); 525 power_supply_unregister(power->usb); 526 return 0; 527 } 528 529 static struct platform_driver wm8350_power_driver = { 530 .probe = wm8350_power_probe, 531 .remove = wm8350_power_remove, 532 .driver = { 533 .name = "wm8350-power", 534 }, 535 }; 536 537 module_platform_driver(wm8350_power_driver); 538 539 MODULE_LICENSE("GPL"); 540 MODULE_DESCRIPTION("Power supply driver for WM8350"); 541 MODULE_ALIAS("platform:wm8350-power"); 542