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