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 23static 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 29static 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 35static 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 45static 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 53static 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 89static 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 139static 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 159static 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 185static DEVICE_ATTR(charger_state, 0444, charger_state_show, NULL); 186 187static 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 *********************************************************************/ 249static 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 271static 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 *********************************************************************/ 279static 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 301static 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 310static 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 327static 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 345static 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 377static 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/********************************************************************* 386 * Initialisation 387 *********************************************************************/ 388 389static void wm8350_init_charger(struct wm8350 *wm8350) 390{ 391 /* register our interest in charger events */ 392 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, 393 wm8350_charger_handler, 0, "Battery hot", wm8350); 394 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, 395 wm8350_charger_handler, 0, "Battery cold", wm8350); 396 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, 397 wm8350_charger_handler, 0, "Battery fail", wm8350); 398 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, 399 wm8350_charger_handler, 0, 400 "Charger timeout", wm8350); 401 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, 402 wm8350_charger_handler, 0, 403 "Charge end", wm8350); 404 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, 405 wm8350_charger_handler, 0, 406 "Charge start", wm8350); 407 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, 408 wm8350_charger_handler, 0, 409 "Fast charge ready", wm8350); 410 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, 411 wm8350_charger_handler, 0, 412 "Battery <3.9V", wm8350); 413 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, 414 wm8350_charger_handler, 0, 415 "Battery <3.1V", wm8350); 416 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, 417 wm8350_charger_handler, 0, 418 "Battery <2.85V", wm8350); 419 420 /* and supply change events */ 421 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, 422 wm8350_charger_handler, 0, "USB", wm8350); 423 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, 424 wm8350_charger_handler, 0, "Wall", wm8350); 425 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, 426 wm8350_charger_handler, 0, "Battery", wm8350); 427} 428 429static void free_charger_irq(struct wm8350 *wm8350) 430{ 431 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350); 432 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350); 433 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350); 434 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); 435 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); 436 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); 437 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); 438 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); 439 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); 440 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350); 441 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350); 442 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350); 443} 444 445static int wm8350_power_probe(struct platform_device *pdev) 446{ 447 struct wm8350 *wm8350 = platform_get_drvdata(pdev); 448 struct wm8350_power *power = &wm8350->power; 449 struct wm8350_charger_policy *policy = power->policy; 450 struct power_supply *usb = &power->usb; 451 struct power_supply *battery = &power->battery; 452 struct power_supply *ac = &power->ac; 453 int ret; 454 455 ac->name = "wm8350-ac"; 456 ac->type = POWER_SUPPLY_TYPE_MAINS; 457 ac->properties = wm8350_ac_props; 458 ac->num_properties = ARRAY_SIZE(wm8350_ac_props); 459 ac->get_property = wm8350_ac_get_prop; 460 ret = power_supply_register(&pdev->dev, ac); 461 if (ret) 462 return ret; 463 464 battery->name = "wm8350-battery"; 465 battery->properties = wm8350_bat_props; 466 battery->num_properties = ARRAY_SIZE(wm8350_bat_props); 467 battery->get_property = wm8350_bat_get_property; 468 battery->use_for_apm = 1; 469 ret = power_supply_register(&pdev->dev, battery); 470 if (ret) 471 goto battery_failed; 472 473 usb->name = "wm8350-usb", 474 usb->type = POWER_SUPPLY_TYPE_USB; 475 usb->properties = wm8350_usb_props; 476 usb->num_properties = ARRAY_SIZE(wm8350_usb_props); 477 usb->get_property = wm8350_usb_get_prop; 478 ret = power_supply_register(&pdev->dev, usb); 479 if (ret) 480 goto usb_failed; 481 482 ret = device_create_file(&pdev->dev, &dev_attr_charger_state); 483 if (ret < 0) 484 dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret); 485 ret = 0; 486 487 wm8350_init_charger(wm8350); 488 if (wm8350_charger_config(wm8350, policy) == 0) { 489 wm8350_reg_unlock(wm8350); 490 wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA); 491 wm8350_reg_lock(wm8350); 492 } 493 494 return ret; 495 496usb_failed: 497 power_supply_unregister(battery); 498battery_failed: 499 power_supply_unregister(ac); 500 501 return ret; 502} 503 504static int wm8350_power_remove(struct platform_device *pdev) 505{ 506 struct wm8350 *wm8350 = platform_get_drvdata(pdev); 507 struct wm8350_power *power = &wm8350->power; 508 509 free_charger_irq(wm8350); 510 device_remove_file(&pdev->dev, &dev_attr_charger_state); 511 power_supply_unregister(&power->battery); 512 power_supply_unregister(&power->ac); 513 power_supply_unregister(&power->usb); 514 return 0; 515} 516 517static struct platform_driver wm8350_power_driver = { 518 .probe = wm8350_power_probe, 519 .remove = wm8350_power_remove, 520 .driver = { 521 .name = "wm8350-power", 522 }, 523}; 524 525module_platform_driver(wm8350_power_driver); 526 527MODULE_LICENSE("GPL"); 528MODULE_DESCRIPTION("Power supply driver for WM8350"); 529MODULE_ALIAS("platform:wm8350-power"); 530