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 case WM8350_IRQ_EXT_BAT_FB: /* Fall through */ 234 power_supply_changed(power->battery); 235 power_supply_changed(power->usb); 236 power_supply_changed(power->ac); 237 break; 238 239 default: 240 dev_err(wm8350->dev, "Unknown interrupt %d\n", irq); 241 } 242 243 return IRQ_HANDLED; 244 } 245 246 /********************************************************************* 247 * AC Power 248 *********************************************************************/ 249 static int wm8350_ac_get_prop(struct power_supply *psy, 250 enum power_supply_property psp, 251 union power_supply_propval *val) 252 { 253 struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent); 254 int ret = 0; 255 256 switch (psp) { 257 case POWER_SUPPLY_PROP_ONLINE: 258 val->intval = !!(wm8350_get_supplies(wm8350) & 259 WM8350_LINE_SUPPLY); 260 break; 261 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 262 val->intval = wm8350_read_line_uvolts(wm8350); 263 break; 264 default: 265 ret = -EINVAL; 266 break; 267 } 268 return ret; 269 } 270 271 static enum power_supply_property wm8350_ac_props[] = { 272 POWER_SUPPLY_PROP_ONLINE, 273 POWER_SUPPLY_PROP_VOLTAGE_NOW, 274 }; 275 276 /********************************************************************* 277 * USB Power 278 *********************************************************************/ 279 static int wm8350_usb_get_prop(struct power_supply *psy, 280 enum power_supply_property psp, 281 union power_supply_propval *val) 282 { 283 struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent); 284 int ret = 0; 285 286 switch (psp) { 287 case POWER_SUPPLY_PROP_ONLINE: 288 val->intval = !!(wm8350_get_supplies(wm8350) & 289 WM8350_USB_SUPPLY); 290 break; 291 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 292 val->intval = wm8350_read_usb_uvolts(wm8350); 293 break; 294 default: 295 ret = -EINVAL; 296 break; 297 } 298 return ret; 299 } 300 301 static enum power_supply_property wm8350_usb_props[] = { 302 POWER_SUPPLY_PROP_ONLINE, 303 POWER_SUPPLY_PROP_VOLTAGE_NOW, 304 }; 305 306 /********************************************************************* 307 * Battery properties 308 *********************************************************************/ 309 310 static int wm8350_bat_check_health(struct wm8350 *wm8350) 311 { 312 u16 reg; 313 314 if (wm8350_read_battery_uvolts(wm8350) < 2850000) 315 return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 316 317 reg = wm8350_reg_read(wm8350, WM8350_CHARGER_OVERRIDES); 318 if (reg & WM8350_CHG_BATT_HOT_OVRDE) 319 return POWER_SUPPLY_HEALTH_OVERHEAT; 320 321 if (reg & WM8350_CHG_BATT_COLD_OVRDE) 322 return POWER_SUPPLY_HEALTH_COLD; 323 324 return POWER_SUPPLY_HEALTH_GOOD; 325 } 326 327 static int wm8350_bat_get_charge_type(struct wm8350 *wm8350) 328 { 329 int state; 330 331 state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) & 332 WM8350_CHG_STS_MASK; 333 switch (state) { 334 case WM8350_CHG_STS_OFF: 335 return POWER_SUPPLY_CHARGE_TYPE_NONE; 336 case WM8350_CHG_STS_TRICKLE: 337 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 338 case WM8350_CHG_STS_FAST: 339 return POWER_SUPPLY_CHARGE_TYPE_FAST; 340 default: 341 return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 342 } 343 } 344 345 static int wm8350_bat_get_property(struct power_supply *psy, 346 enum power_supply_property psp, 347 union power_supply_propval *val) 348 { 349 struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent); 350 int ret = 0; 351 352 switch (psp) { 353 case POWER_SUPPLY_PROP_STATUS: 354 val->intval = wm8350_batt_status(wm8350); 355 break; 356 case POWER_SUPPLY_PROP_ONLINE: 357 val->intval = !!(wm8350_get_supplies(wm8350) & 358 WM8350_BATT_SUPPLY); 359 break; 360 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 361 val->intval = wm8350_read_battery_uvolts(wm8350); 362 break; 363 case POWER_SUPPLY_PROP_HEALTH: 364 val->intval = wm8350_bat_check_health(wm8350); 365 break; 366 case POWER_SUPPLY_PROP_CHARGE_TYPE: 367 val->intval = wm8350_bat_get_charge_type(wm8350); 368 break; 369 default: 370 ret = -EINVAL; 371 break; 372 } 373 374 return ret; 375 } 376 377 static enum power_supply_property wm8350_bat_props[] = { 378 POWER_SUPPLY_PROP_STATUS, 379 POWER_SUPPLY_PROP_ONLINE, 380 POWER_SUPPLY_PROP_VOLTAGE_NOW, 381 POWER_SUPPLY_PROP_HEALTH, 382 POWER_SUPPLY_PROP_CHARGE_TYPE, 383 }; 384 385 static const struct power_supply_desc wm8350_ac_desc = { 386 .name = "wm8350-ac", 387 .type = POWER_SUPPLY_TYPE_MAINS, 388 .properties = wm8350_ac_props, 389 .num_properties = ARRAY_SIZE(wm8350_ac_props), 390 .get_property = wm8350_ac_get_prop, 391 }; 392 393 static const struct power_supply_desc wm8350_battery_desc = { 394 .name = "wm8350-battery", 395 .properties = wm8350_bat_props, 396 .num_properties = ARRAY_SIZE(wm8350_bat_props), 397 .get_property = wm8350_bat_get_property, 398 .use_for_apm = 1, 399 }; 400 401 static const struct power_supply_desc wm8350_usb_desc = { 402 .name = "wm8350-usb", 403 .type = POWER_SUPPLY_TYPE_USB, 404 .properties = wm8350_usb_props, 405 .num_properties = ARRAY_SIZE(wm8350_usb_props), 406 .get_property = wm8350_usb_get_prop, 407 }; 408 409 /********************************************************************* 410 * Initialisation 411 *********************************************************************/ 412 413 static void wm8350_init_charger(struct wm8350 *wm8350) 414 { 415 /* register our interest in charger events */ 416 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, 417 wm8350_charger_handler, 0, "Battery hot", wm8350); 418 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, 419 wm8350_charger_handler, 0, "Battery cold", wm8350); 420 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, 421 wm8350_charger_handler, 0, "Battery fail", wm8350); 422 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, 423 wm8350_charger_handler, 0, 424 "Charger timeout", wm8350); 425 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, 426 wm8350_charger_handler, 0, 427 "Charge end", wm8350); 428 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, 429 wm8350_charger_handler, 0, 430 "Charge start", wm8350); 431 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, 432 wm8350_charger_handler, 0, 433 "Fast charge ready", wm8350); 434 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, 435 wm8350_charger_handler, 0, 436 "Battery <3.9V", wm8350); 437 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, 438 wm8350_charger_handler, 0, 439 "Battery <3.1V", wm8350); 440 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, 441 wm8350_charger_handler, 0, 442 "Battery <2.85V", wm8350); 443 444 /* and supply change events */ 445 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, 446 wm8350_charger_handler, 0, "USB", wm8350); 447 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, 448 wm8350_charger_handler, 0, "Wall", wm8350); 449 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, 450 wm8350_charger_handler, 0, "Battery", wm8350); 451 } 452 453 static void free_charger_irq(struct wm8350 *wm8350) 454 { 455 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350); 456 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350); 457 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350); 458 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); 459 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); 460 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); 461 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); 462 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); 463 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); 464 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350); 465 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350); 466 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350); 467 } 468 469 static int wm8350_power_probe(struct platform_device *pdev) 470 { 471 struct wm8350 *wm8350 = platform_get_drvdata(pdev); 472 struct wm8350_power *power = &wm8350->power; 473 struct wm8350_charger_policy *policy = power->policy; 474 int ret; 475 476 power->ac = power_supply_register(&pdev->dev, &wm8350_ac_desc, NULL); 477 if (IS_ERR(power->ac)) 478 return PTR_ERR(power->ac); 479 480 power->battery = power_supply_register(&pdev->dev, &wm8350_battery_desc, 481 NULL); 482 if (IS_ERR(power->battery)) { 483 ret = PTR_ERR(power->battery); 484 goto battery_failed; 485 } 486 487 power->usb = power_supply_register(&pdev->dev, &wm8350_usb_desc, NULL); 488 if (IS_ERR(power->usb)) { 489 ret = PTR_ERR(power->usb); 490 goto usb_failed; 491 } 492 493 ret = device_create_file(&pdev->dev, &dev_attr_charger_state); 494 if (ret < 0) 495 dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret); 496 ret = 0; 497 498 wm8350_init_charger(wm8350); 499 if (wm8350_charger_config(wm8350, policy) == 0) { 500 wm8350_reg_unlock(wm8350); 501 wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA); 502 wm8350_reg_lock(wm8350); 503 } 504 505 return ret; 506 507 usb_failed: 508 power_supply_unregister(power->battery); 509 battery_failed: 510 power_supply_unregister(power->ac); 511 512 return ret; 513 } 514 515 static int wm8350_power_remove(struct platform_device *pdev) 516 { 517 struct wm8350 *wm8350 = platform_get_drvdata(pdev); 518 struct wm8350_power *power = &wm8350->power; 519 520 free_charger_irq(wm8350); 521 device_remove_file(&pdev->dev, &dev_attr_charger_state); 522 power_supply_unregister(power->battery); 523 power_supply_unregister(power->ac); 524 power_supply_unregister(power->usb); 525 return 0; 526 } 527 528 static struct platform_driver wm8350_power_driver = { 529 .probe = wm8350_power_probe, 530 .remove = wm8350_power_remove, 531 .driver = { 532 .name = "wm8350-power", 533 }, 534 }; 535 536 module_platform_driver(wm8350_power_driver); 537 538 MODULE_LICENSE("GPL"); 539 MODULE_DESCRIPTION("Power supply driver for WM8350"); 540 MODULE_ALIAS("platform:wm8350-power"); 541