13961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown/* 23961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * PMU driver for Wolfson Microelectronics wm831x PMICs 33961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * 43961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * Copyright 2009 Wolfson Microelectronics PLC. 53961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * 63961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * This program is free software; you can redistribute it and/or modify 73961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * it under the terms of the GNU General Public License version 2 as 83961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * published by the Free Software Foundation. 93961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown */ 103961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 113961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown#include <linux/module.h> 123961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown#include <linux/err.h> 133961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown#include <linux/platform_device.h> 143961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown#include <linux/power_supply.h> 155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 163961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 173961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown#include <linux/mfd/wm831x/core.h> 183961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown#include <linux/mfd/wm831x/auxadc.h> 193961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown#include <linux/mfd/wm831x/pmu.h> 203961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown#include <linux/mfd/wm831x/pdata.h> 213961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 223961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstruct wm831x_power { 233961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x *wm831x; 243961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct power_supply wall; 253961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct power_supply usb; 263961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct power_supply battery; 27ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown char wall_name[20]; 28ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown char usb_name[20]; 29ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown char battery_name[20]; 3035c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown bool have_battery; 313961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 323961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 333961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic int wm831x_power_check_online(struct wm831x *wm831x, int supply, 343961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown union power_supply_propval *val) 353961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 363961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret; 373961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 383961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS); 393961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret < 0) 403961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 413961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 423961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret & supply) 433961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown val->intval = 1; 443961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown else 453961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown val->intval = 0; 463961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 473961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return 0; 483961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 493961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 503961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic int wm831x_power_read_voltage(struct wm831x *wm831x, 513961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown enum wm831x_auxadc src, 523961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown union power_supply_propval *val) 533961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 543961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret; 553961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 563961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_auxadc_read_uv(wm831x, src); 573961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret >= 0) 583961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown val->intval = ret; 593961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 603961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 613961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 623961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 633961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown/********************************************************************* 643961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * WALL Power 653961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *********************************************************************/ 663961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic int wm831x_wall_get_prop(struct power_supply *psy, 673961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown enum power_supply_property psp, 683961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown union power_supply_propval *val) 693961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 703961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev->parent); 713961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x *wm831x = wm831x_power->wm831x; 723961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret = 0; 733961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 743961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown switch (psp) { 753961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case POWER_SUPPLY_PROP_ONLINE: 763961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_power_check_online(wm831x, WM831X_PWR_WALL, val); 773961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 783961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case POWER_SUPPLY_PROP_VOLTAGE_NOW: 793961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_WALL, val); 803961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 813961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown default: 823961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = -EINVAL; 833961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 843961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 853961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 863961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 873961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 883961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 893961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic enum power_supply_property wm831x_wall_props[] = { 903961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown POWER_SUPPLY_PROP_ONLINE, 913961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown POWER_SUPPLY_PROP_VOLTAGE_NOW, 923961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 933961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 943961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown/********************************************************************* 953961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * USB Power 963961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *********************************************************************/ 973961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic int wm831x_usb_get_prop(struct power_supply *psy, 983961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown enum power_supply_property psp, 993961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown union power_supply_propval *val) 1003961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 1013961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev->parent); 1023961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x *wm831x = wm831x_power->wm831x; 1033961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret = 0; 1043961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1053961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown switch (psp) { 1063961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case POWER_SUPPLY_PROP_ONLINE: 1073961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_power_check_online(wm831x, WM831X_PWR_USB, val); 1083961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 1093961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case POWER_SUPPLY_PROP_VOLTAGE_NOW: 1103961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_USB, val); 1113961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 1123961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown default: 1133961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = -EINVAL; 1143961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 1153961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 1163961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1173961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 1183961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 1193961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1203961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic enum power_supply_property wm831x_usb_props[] = { 1213961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown POWER_SUPPLY_PROP_ONLINE, 1223961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown POWER_SUPPLY_PROP_VOLTAGE_NOW, 1233961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 1243961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1253961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown/********************************************************************* 1263961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * Battery properties 1273961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *********************************************************************/ 1283961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1293961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstruct chg_map { 1303961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int val; 1313961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int reg_val; 1323961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 1333961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1343961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic struct chg_map trickle_ilims[] = { 1353961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 50, 0 << WM831X_CHG_TRKL_ILIM_SHIFT }, 1363961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 100, 1 << WM831X_CHG_TRKL_ILIM_SHIFT }, 1373961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 150, 2 << WM831X_CHG_TRKL_ILIM_SHIFT }, 1383961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 200, 3 << WM831X_CHG_TRKL_ILIM_SHIFT }, 1393961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 1403961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1413961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic struct chg_map vsels[] = { 1423961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 4050, 0 << WM831X_CHG_VSEL_SHIFT }, 1433961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 4100, 1 << WM831X_CHG_VSEL_SHIFT }, 1443961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 4150, 2 << WM831X_CHG_VSEL_SHIFT }, 1453961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 4200, 3 << WM831X_CHG_VSEL_SHIFT }, 1463961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 1473961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1483961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic struct chg_map fast_ilims[] = { 1493961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 0, 0 << WM831X_CHG_FAST_ILIM_SHIFT }, 1503961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 50, 1 << WM831X_CHG_FAST_ILIM_SHIFT }, 1513961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 100, 2 << WM831X_CHG_FAST_ILIM_SHIFT }, 1523961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 150, 3 << WM831X_CHG_FAST_ILIM_SHIFT }, 1533961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 200, 4 << WM831X_CHG_FAST_ILIM_SHIFT }, 1543961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 250, 5 << WM831X_CHG_FAST_ILIM_SHIFT }, 1553961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 300, 6 << WM831X_CHG_FAST_ILIM_SHIFT }, 1563961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 350, 7 << WM831X_CHG_FAST_ILIM_SHIFT }, 1573961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 400, 8 << WM831X_CHG_FAST_ILIM_SHIFT }, 1583961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 450, 9 << WM831X_CHG_FAST_ILIM_SHIFT }, 1593961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 500, 10 << WM831X_CHG_FAST_ILIM_SHIFT }, 1603961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 600, 11 << WM831X_CHG_FAST_ILIM_SHIFT }, 1613961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 700, 12 << WM831X_CHG_FAST_ILIM_SHIFT }, 1623961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 800, 13 << WM831X_CHG_FAST_ILIM_SHIFT }, 1633961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 900, 14 << WM831X_CHG_FAST_ILIM_SHIFT }, 1643961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 1000, 15 << WM831X_CHG_FAST_ILIM_SHIFT }, 1653961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 1663961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1673961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic struct chg_map eoc_iterms[] = { 1683961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 20, 0 << WM831X_CHG_ITERM_SHIFT }, 1693961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 30, 1 << WM831X_CHG_ITERM_SHIFT }, 1703961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 40, 2 << WM831X_CHG_ITERM_SHIFT }, 1713961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 50, 3 << WM831X_CHG_ITERM_SHIFT }, 1723961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 60, 4 << WM831X_CHG_ITERM_SHIFT }, 1733961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 70, 5 << WM831X_CHG_ITERM_SHIFT }, 1743961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 80, 6 << WM831X_CHG_ITERM_SHIFT }, 1753961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 90, 7 << WM831X_CHG_ITERM_SHIFT }, 1763961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 1773961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1783961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic struct chg_map chg_times[] = { 1793961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 60, 0 << WM831X_CHG_TIME_SHIFT }, 1803961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 90, 1 << WM831X_CHG_TIME_SHIFT }, 1813961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 120, 2 << WM831X_CHG_TIME_SHIFT }, 1823961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 150, 3 << WM831X_CHG_TIME_SHIFT }, 1833961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 180, 4 << WM831X_CHG_TIME_SHIFT }, 1843961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 210, 5 << WM831X_CHG_TIME_SHIFT }, 1853961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 240, 6 << WM831X_CHG_TIME_SHIFT }, 1863961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 270, 7 << WM831X_CHG_TIME_SHIFT }, 1873961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 300, 8 << WM831X_CHG_TIME_SHIFT }, 1883961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 330, 9 << WM831X_CHG_TIME_SHIFT }, 1893961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 360, 10 << WM831X_CHG_TIME_SHIFT }, 1903961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 390, 11 << WM831X_CHG_TIME_SHIFT }, 1913961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 420, 12 << WM831X_CHG_TIME_SHIFT }, 1923961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 450, 13 << WM831X_CHG_TIME_SHIFT }, 1933961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 480, 14 << WM831X_CHG_TIME_SHIFT }, 1943961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown { 510, 15 << WM831X_CHG_TIME_SHIFT }, 1953961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 1963961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 1973961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic void wm831x_battey_apply_config(struct wm831x *wm831x, 1983961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct chg_map *map, int count, int val, 1993961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int *reg, const char *name, 2003961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown const char *units) 2013961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 2023961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int i; 2033961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2043961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown for (i = 0; i < count; i++) 2053961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (val == map[i].val) 2063961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 2073961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (i == count) { 2083961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_err(wm831x->dev, "Invalid %s %d%s\n", 2093961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown name, val, units); 2103961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } else { 2113961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *reg |= map[i].reg_val; 2123961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_dbg(wm831x->dev, "Set %s of %d%s\n", name, val, units); 2133961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 2143961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 2153961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2163961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic void wm831x_config_battery(struct wm831x *wm831x) 2173961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 2183961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data; 2193961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_battery_pdata *pdata; 2203961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret, reg1, reg2; 2213961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2223961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (!wm831x_pdata || !wm831x_pdata->battery) { 2233961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_warn(wm831x->dev, 2243961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "No battery charger configuration\n"); 2253961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return; 2263961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 2273961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2283961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown pdata = wm831x_pdata->battery; 2293961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2303961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown reg1 = 0; 2313961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown reg2 = 0; 2323961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2333961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (!pdata->enable) { 2343961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_info(wm831x->dev, "Battery charger disabled\n"); 2353961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return; 2363961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 2373961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2383961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown reg1 |= WM831X_CHG_ENA; 2393961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (pdata->off_mask) 2403961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown reg2 |= WM831X_CHG_OFF_MSK; 2413961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (pdata->fast_enable) 2423961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown reg1 |= WM831X_CHG_FAST; 2433961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2443961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wm831x_battey_apply_config(wm831x, trickle_ilims, 2453961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ARRAY_SIZE(trickle_ilims), 2463961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown pdata->trickle_ilim, ®2, 2473961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "trickle charge current limit", "mA"); 2483961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2493961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wm831x_battey_apply_config(wm831x, vsels, ARRAY_SIZE(vsels), 2503961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown pdata->vsel, ®2, 2513961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "target voltage", "mV"); 2523961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2533961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wm831x_battey_apply_config(wm831x, fast_ilims, ARRAY_SIZE(fast_ilims), 2543961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown pdata->fast_ilim, ®2, 2553961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "fast charge current limit", "mA"); 2563961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2573961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wm831x_battey_apply_config(wm831x, eoc_iterms, ARRAY_SIZE(eoc_iterms), 2583961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown pdata->eoc_iterm, ®1, 2593961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "end of charge current threshold", "mA"); 2603961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2613961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wm831x_battey_apply_config(wm831x, chg_times, ARRAY_SIZE(chg_times), 2623961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown pdata->timeout, ®2, 2633961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "charger timeout", "min"); 2643961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2653961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_reg_unlock(wm831x); 2663961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret != 0) { 2673961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret); 2683961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return; 2693961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 2703961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2713961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_1, 2723961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown WM831X_CHG_ENA_MASK | 2733961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown WM831X_CHG_FAST_MASK | 2743961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown WM831X_CHG_ITERM_MASK, 2753961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown reg1); 2763961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret != 0) 2773961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_err(wm831x->dev, "Failed to set charger control 1: %d\n", 2783961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret); 2793961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2803961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_2, 2813961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown WM831X_CHG_OFF_MSK | 2823961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown WM831X_CHG_TIME_MASK | 2833961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown WM831X_CHG_FAST_ILIM_MASK | 2843961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown WM831X_CHG_TRKL_ILIM_MASK | 2853961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown WM831X_CHG_VSEL_MASK, 2863961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown reg2); 2873961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret != 0) 2883961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_err(wm831x->dev, "Failed to set charger control 2: %d\n", 2893961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret); 2903961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2913961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wm831x_reg_lock(wm831x); 2923961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 2933961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2943961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic int wm831x_bat_check_status(struct wm831x *wm831x, int *status) 2953961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 2963961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret; 2973961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 2983961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS); 2993961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret < 0) 3003961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 3013961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3023961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret & WM831X_PWR_SRC_BATT) { 3033961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *status = POWER_SUPPLY_STATUS_DISCHARGING; 3043961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return 0; 3053961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 3063961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3073961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS); 3083961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret < 0) 3093961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 3103961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3113961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown switch (ret & WM831X_CHG_STATE_MASK) { 3123961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_OFF: 3133961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *status = POWER_SUPPLY_STATUS_NOT_CHARGING; 3143961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 3153961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_TRICKLE: 3163961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_FAST: 3173961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *status = POWER_SUPPLY_STATUS_CHARGING; 3183961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 3193961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3203961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown default: 3213961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *status = POWER_SUPPLY_STATUS_UNKNOWN; 3223961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 3233961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 3243961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3253961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return 0; 3263961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 3273961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3283961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic int wm831x_bat_check_type(struct wm831x *wm831x, int *type) 3293961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 3303961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret; 3313961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3323961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS); 3333961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret < 0) 3343961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 3353961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3363961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown switch (ret & WM831X_CHG_STATE_MASK) { 3373961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_TRICKLE: 3383961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_TRICKLE_OT: 3393961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 3403961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 3413961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_FAST: 3423961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_FAST_OT: 3433961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *type = POWER_SUPPLY_CHARGE_TYPE_FAST; 3443961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 3453961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown default: 3463961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *type = POWER_SUPPLY_CHARGE_TYPE_NONE; 3473961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 3483961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 3493961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3503961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return 0; 3513961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 3523961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3533961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic int wm831x_bat_check_health(struct wm831x *wm831x, int *health) 3543961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 3553961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret; 3563961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3573961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS); 3583961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret < 0) 3593961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 3603961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3613961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret & WM831X_BATT_HOT_STS) { 3623961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *health = POWER_SUPPLY_HEALTH_OVERHEAT; 3633961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return 0; 3643961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 3653961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3663961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret & WM831X_BATT_COLD_STS) { 3673961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *health = POWER_SUPPLY_HEALTH_COLD; 3683961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return 0; 3693961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 3703961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3713961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret & WM831X_BATT_OV_STS) { 3723961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 3733961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return 0; 3743961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 3753961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3763961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown switch (ret & WM831X_CHG_STATE_MASK) { 3773961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_TRICKLE_OT: 3783961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_FAST_OT: 3793961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *health = POWER_SUPPLY_HEALTH_OVERHEAT; 3803961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 3813961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case WM831X_CHG_STATE_DEFECTIVE: 3823961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 3833961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 3843961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown default: 3853961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *health = POWER_SUPPLY_HEALTH_GOOD; 3863961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 3873961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 3883961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3893961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return 0; 3903961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 3913961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 3923961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic int wm831x_bat_get_prop(struct power_supply *psy, 3933961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown enum power_supply_property psp, 3943961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown union power_supply_propval *val) 3953961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 3963961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev->parent); 3973961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x *wm831x = wm831x_power->wm831x; 3983961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret = 0; 3993961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4003961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown switch (psp) { 4013961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case POWER_SUPPLY_PROP_STATUS: 4023961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_bat_check_status(wm831x, &val->intval); 4033961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 4043961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case POWER_SUPPLY_PROP_ONLINE: 4053961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_power_check_online(wm831x, WM831X_PWR_SRC_BATT, 4063961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown val); 4073961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 4083961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case POWER_SUPPLY_PROP_VOLTAGE_NOW: 4093961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_BATT, val); 4103961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 4113961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case POWER_SUPPLY_PROP_HEALTH: 4123961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_bat_check_health(wm831x, &val->intval); 4133961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 4143961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown case POWER_SUPPLY_PROP_CHARGE_TYPE: 4153961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = wm831x_bat_check_type(wm831x, &val->intval); 4163961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 4173961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown default: 4183961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = -EINVAL; 4193961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown break; 4203961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 4213961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4223961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 4233961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 4243961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4253961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic enum power_supply_property wm831x_bat_props[] = { 4263961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown POWER_SUPPLY_PROP_STATUS, 4273961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown POWER_SUPPLY_PROP_ONLINE, 4283961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown POWER_SUPPLY_PROP_VOLTAGE_NOW, 4293961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown POWER_SUPPLY_PROP_HEALTH, 4303961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown POWER_SUPPLY_PROP_CHARGE_TYPE, 4313961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 4323961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4333961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic const char *wm831x_bat_irqs[] = { 4343961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "BATT HOT", 4353961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "BATT COLD", 4363961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "BATT FAIL", 4373961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "OV", 4383961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "END", 4393961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "TO", 4403961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "MODE", 4413961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "START", 4423961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 4433961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4443961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic irqreturn_t wm831x_bat_irq(int irq, void *data) 4453961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 4463961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_power *wm831x_power = data; 4473961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x *wm831x = wm831x_power->wm831x; 4483961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4493961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_dbg(wm831x->dev, "Battery status changed: %d\n", irq); 4503961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4513961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown /* The battery charger is autonomous so we don't need to do 4523961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * anything except kick user space */ 45335c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown if (wm831x_power->have_battery) 45435c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown power_supply_changed(&wm831x_power->battery); 4553961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4563961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return IRQ_HANDLED; 4573961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 4583961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4593961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4603961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown/********************************************************************* 4613961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * Initialisation 4623961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown *********************************************************************/ 4633961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4643961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic irqreturn_t wm831x_syslo_irq(int irq, void *data) 4653961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 4663961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_power *wm831x_power = data; 4673961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x *wm831x = wm831x_power->wm831x; 4683961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4693961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown /* Not much we can actually *do* but tell people for 4703961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown * posterity, we're probably about to run out of power. */ 4713961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_crit(wm831x->dev, "SYSVDD under voltage\n"); 4723961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4733961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return IRQ_HANDLED; 4743961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 4753961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4763961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic irqreturn_t wm831x_pwr_src_irq(int irq, void *data) 4773961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 4783961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_power *wm831x_power = data; 4793961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x *wm831x = wm831x_power->wm831x; 4803961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4813961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_dbg(wm831x->dev, "Power source changed\n"); 4823961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 483c26964ead57f0aa1dff4926aae2982b174798e7bMark Brown /* Just notify for everything - little harm in overnotifying. */ 48435c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown if (wm831x_power->have_battery) 48535c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown power_supply_changed(&wm831x_power->battery); 4863961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown power_supply_changed(&wm831x_power->usb); 4873961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown power_supply_changed(&wm831x_power->wall); 4883961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 4893961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return IRQ_HANDLED; 4903961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 4913961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 492c8afa6406e60aec6ff90033e5ffe41a206609296Bill Pembertonstatic int wm831x_power_probe(struct platform_device *pdev) 4933961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 4943961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); 495ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data; 4963961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_power *power; 4973961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct power_supply *usb; 4983961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct power_supply *battery; 4993961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct power_supply *wall; 5003961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int ret, irq, i; 5013961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 5023961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown power = kzalloc(sizeof(struct wm831x_power), GFP_KERNEL); 5033961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (power == NULL) 5043961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return -ENOMEM; 5053961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 5063961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown power->wm831x = wm831x; 5073961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown platform_set_drvdata(pdev, power); 5083961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 5093961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown usb = &power->usb; 5103961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown battery = &power->battery; 5113961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wall = &power->wall; 5123961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 513ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown if (wm831x_pdata && wm831x_pdata->wm831x_num) { 514ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown snprintf(power->wall_name, sizeof(power->wall_name), 515ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown "wm831x-wall.%d", wm831x_pdata->wm831x_num); 516ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown snprintf(power->battery_name, sizeof(power->wall_name), 517ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown "wm831x-battery.%d", wm831x_pdata->wm831x_num); 518ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown snprintf(power->usb_name, sizeof(power->wall_name), 519ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown "wm831x-usb.%d", wm831x_pdata->wm831x_num); 520ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown } else { 521ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown snprintf(power->wall_name, sizeof(power->wall_name), 522ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown "wm831x-wall"); 523ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown snprintf(power->battery_name, sizeof(power->wall_name), 524ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown "wm831x-battery"); 525ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown snprintf(power->usb_name, sizeof(power->wall_name), 526ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown "wm831x-usb"); 527ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown } 528ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown 5293961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown /* We ignore configuration failures since we can still read back 530c26964ead57f0aa1dff4926aae2982b174798e7bMark Brown * the status without enabling the charger. 5313961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown */ 5323961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wm831x_config_battery(wm831x); 5333961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 534ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown wall->name = power->wall_name; 5353961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wall->type = POWER_SUPPLY_TYPE_MAINS; 5363961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wall->properties = wm831x_wall_props; 5373961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wall->num_properties = ARRAY_SIZE(wm831x_wall_props); 5383961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wall->get_property = wm831x_wall_get_prop; 5393961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = power_supply_register(&pdev->dev, wall); 5403961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret) 5413961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown goto err_kmalloc; 5423961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 543ccf8fa2d1b4dd8660aadc830f22645781628b894Mark Brown usb->name = power->usb_name, 5443961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown usb->type = POWER_SUPPLY_TYPE_USB; 5453961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown usb->properties = wm831x_usb_props; 5463961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown usb->num_properties = ARRAY_SIZE(wm831x_usb_props); 5473961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown usb->get_property = wm831x_usb_get_prop; 5483961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown ret = power_supply_register(&pdev->dev, usb); 5493961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret) 55035c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown goto err_wall; 55135c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown 55235c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown ret = wm831x_reg_read(wm831x, WM831X_CHARGER_CONTROL_1); 55335c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown if (ret < 0) 55435c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown goto err_wall; 55535c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown power->have_battery = ret & WM831X_CHG_ENA; 55635c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown 55735c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown if (power->have_battery) { 55835c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown battery->name = power->battery_name; 55935c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown battery->properties = wm831x_bat_props; 56035c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown battery->num_properties = ARRAY_SIZE(wm831x_bat_props); 56135c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown battery->get_property = wm831x_bat_get_prop; 56235c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown battery->use_for_apm = 1; 56335c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown ret = power_supply_register(&pdev->dev, battery); 56435c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown if (ret) 56535c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown goto err_usb; 56635c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown } 5673961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 568cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO")); 569b5874f33bbaf00586d05de37706491ee37057e11Mark Brown ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq, 570b5874f33bbaf00586d05de37706491ee37057e11Mark Brown IRQF_TRIGGER_RISING, "System power low", 571b5874f33bbaf00586d05de37706491ee37057e11Mark Brown power); 5723961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret != 0) { 5733961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n", 5743961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown irq, ret); 57535c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown goto err_battery; 5763961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 5773961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 578cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC")); 579b5874f33bbaf00586d05de37706491ee37057e11Mark Brown ret = request_threaded_irq(irq, NULL, wm831x_pwr_src_irq, 580b5874f33bbaf00586d05de37706491ee37057e11Mark Brown IRQF_TRIGGER_RISING, "Power source", 581b5874f33bbaf00586d05de37706491ee37057e11Mark Brown power); 5823961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret != 0) { 5833961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n", 5843961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown irq, ret); 5853961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown goto err_syslo; 5863961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 5873961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 5883961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { 589cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown irq = wm831x_irq(wm831x, 590cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown platform_get_irq_byname(pdev, 591cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown wm831x_bat_irqs[i])); 592b5874f33bbaf00586d05de37706491ee37057e11Mark Brown ret = request_threaded_irq(irq, NULL, wm831x_bat_irq, 593b5874f33bbaf00586d05de37706491ee37057e11Mark Brown IRQF_TRIGGER_RISING, 594b5874f33bbaf00586d05de37706491ee37057e11Mark Brown wm831x_bat_irqs[i], 595b5874f33bbaf00586d05de37706491ee37057e11Mark Brown power); 5963961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown if (ret != 0) { 5973961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown dev_err(&pdev->dev, 5983961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown "Failed to request %s IRQ %d: %d\n", 5993961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown wm831x_bat_irqs[i], irq, ret); 6003961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown goto err_bat_irq; 6013961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 6023961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 6033961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 6043961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 6053961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 6063961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownerr_bat_irq: 6073961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown for (; i >= 0; i--) { 6083961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]); 609b5874f33bbaf00586d05de37706491ee37057e11Mark Brown free_irq(irq, power); 6103961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 611cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC")); 612b5874f33bbaf00586d05de37706491ee37057e11Mark Brown free_irq(irq, power); 6133961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownerr_syslo: 614cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO")); 615b5874f33bbaf00586d05de37706491ee37057e11Mark Brown free_irq(irq, power); 61635c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brownerr_battery: 61735c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown if (power->have_battery) 61835c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown power_supply_unregister(battery); 6193961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownerr_usb: 6203961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown power_supply_unregister(usb); 6213961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownerr_wall: 6223961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown power_supply_unregister(wall); 6233961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownerr_kmalloc: 6243961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown kfree(power); 6253961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return ret; 6263961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 6273961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 628415ec69fb1861fc377c65cb30ddc76999891b8e1Bill Pembertonstatic int wm831x_power_remove(struct platform_device *pdev) 6293961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown{ 6303961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown struct wm831x_power *wm831x_power = platform_get_drvdata(pdev); 631cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown struct wm831x *wm831x = wm831x_power->wm831x; 6323961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown int irq, i; 6333961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 6343961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { 635cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown irq = wm831x_irq(wm831x, 636cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown platform_get_irq_byname(pdev, 637cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown wm831x_bat_irqs[i])); 638b5874f33bbaf00586d05de37706491ee37057e11Mark Brown free_irq(irq, wm831x_power); 6393961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown } 6403961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 641cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC")); 642b5874f33bbaf00586d05de37706491ee37057e11Mark Brown free_irq(irq, wm831x_power); 6433961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 644cd99758ba3bde64347a8ece381cbae2fb5c745b2Mark Brown irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO")); 645b5874f33bbaf00586d05de37706491ee37057e11Mark Brown free_irq(irq, wm831x_power); 6463961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 64735c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown if (wm831x_power->have_battery) 64835c3ae5eef3fc641c75c5e1e4307835c8efa5f6bMark Brown power_supply_unregister(&wm831x_power->battery); 6493961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown power_supply_unregister(&wm831x_power->wall); 6503961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown power_supply_unregister(&wm831x_power->usb); 6519c99f08991b38bf6ab62ffe9013ee46ff41d66d0Axel Lin kfree(wm831x_power); 6523961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown return 0; 6533961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown} 6543961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 6553961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brownstatic struct platform_driver wm831x_power_driver = { 6563961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown .probe = wm831x_power_probe, 65728ea73f4c67cb3dd8c972b21d9fdf84ea78d6daaBill Pemberton .remove = wm831x_power_remove, 6583961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown .driver = { 6593961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown .name = "wm831x-power", 6603961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown }, 6613961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown}; 6623961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 663300bac7fb85a20b2704dc3645419057992f78565Axel Linmodule_platform_driver(wm831x_power_driver); 6643961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark Brown 6653961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark BrownMODULE_DESCRIPTION("Power supply driver for WM831x PMICs"); 6663961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark BrownMODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 6673961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark BrownMODULE_LICENSE("GPL"); 6683961f7c3cf247eee5df7fabadc7a40f2deeb98f3Mark BrownMODULE_ALIAS("platform:wm831x-power"); 669