]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - drivers/power/wm831x_power.c
arm: tegra: enterprise: Filling regulator supply info
[linux-2.6.git] / drivers / power / wm831x_power.c
1 /*
2  * PMU driver for Wolfson Microelectronics wm831x PMICs
3  *
4  * Copyright 2009 Wolfson Microelectronics PLC.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <linux/module.h>
12 #include <linux/err.h>
13 #include <linux/platform_device.h>
14 #include <linux/power_supply.h>
15 #include <linux/slab.h>
16
17 #include <linux/mfd/wm831x/core.h>
18 #include <linux/mfd/wm831x/auxadc.h>
19 #include <linux/mfd/wm831x/pmu.h>
20 #include <linux/mfd/wm831x/pdata.h>
21
22 struct wm831x_power {
23         struct wm831x *wm831x;
24         struct power_supply wall;
25         struct power_supply usb;
26         struct power_supply battery;
27         char wall_name[20];
28         char usb_name[20];
29         char battery_name[20];
30 };
31
32 static int wm831x_power_check_online(struct wm831x *wm831x, int supply,
33                                      union power_supply_propval *val)
34 {
35         int ret;
36
37         ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS);
38         if (ret < 0)
39                 return ret;
40
41         if (ret & supply)
42                 val->intval = 1;
43         else
44                 val->intval = 0;
45
46         return 0;
47 }
48
49 static int wm831x_power_read_voltage(struct wm831x *wm831x,
50                                      enum wm831x_auxadc src,
51                                      union power_supply_propval *val)
52 {
53         int ret;
54
55         ret = wm831x_auxadc_read_uv(wm831x, src);
56         if (ret >= 0)
57                 val->intval = ret;
58
59         return ret;
60 }
61
62 /*********************************************************************
63  *              WALL Power
64  *********************************************************************/
65 static int wm831x_wall_get_prop(struct power_supply *psy,
66                                 enum power_supply_property psp,
67                                 union power_supply_propval *val)
68 {
69         struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev->parent);
70         struct wm831x *wm831x = wm831x_power->wm831x;
71         int ret = 0;
72
73         switch (psp) {
74         case POWER_SUPPLY_PROP_ONLINE:
75                 ret = wm831x_power_check_online(wm831x, WM831X_PWR_WALL, val);
76                 break;
77         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
78                 ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_WALL, val);
79                 break;
80         default:
81                 ret = -EINVAL;
82                 break;
83         }
84
85         return ret;
86 }
87
88 static enum power_supply_property wm831x_wall_props[] = {
89         POWER_SUPPLY_PROP_ONLINE,
90         POWER_SUPPLY_PROP_VOLTAGE_NOW,
91 };
92
93 /*********************************************************************
94  *              USB Power
95  *********************************************************************/
96 static int wm831x_usb_get_prop(struct power_supply *psy,
97                                enum power_supply_property psp,
98                                union power_supply_propval *val)
99 {
100         struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev->parent);
101         struct wm831x *wm831x = wm831x_power->wm831x;
102         int ret = 0;
103
104         switch (psp) {
105         case POWER_SUPPLY_PROP_ONLINE:
106                 ret = wm831x_power_check_online(wm831x, WM831X_PWR_USB, val);
107                 break;
108         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
109                 ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_USB, val);
110                 break;
111         default:
112                 ret = -EINVAL;
113                 break;
114         }
115
116         return ret;
117 }
118
119 static enum power_supply_property wm831x_usb_props[] = {
120         POWER_SUPPLY_PROP_ONLINE,
121         POWER_SUPPLY_PROP_VOLTAGE_NOW,
122 };
123
124 /*********************************************************************
125  *              Battery properties
126  *********************************************************************/
127
128 struct chg_map {
129         int val;
130         int reg_val;
131 };
132
133 static struct chg_map trickle_ilims[] = {
134         {  50, 0 << WM831X_CHG_TRKL_ILIM_SHIFT },
135         { 100, 1 << WM831X_CHG_TRKL_ILIM_SHIFT },
136         { 150, 2 << WM831X_CHG_TRKL_ILIM_SHIFT },
137         { 200, 3 << WM831X_CHG_TRKL_ILIM_SHIFT },
138 };
139
140 static struct chg_map vsels[] = {
141         { 4050, 0 << WM831X_CHG_VSEL_SHIFT },
142         { 4100, 1 << WM831X_CHG_VSEL_SHIFT },
143         { 4150, 2 << WM831X_CHG_VSEL_SHIFT },
144         { 4200, 3 << WM831X_CHG_VSEL_SHIFT },
145 };
146
147 static struct chg_map fast_ilims[] = {
148         {    0,  0 << WM831X_CHG_FAST_ILIM_SHIFT },
149         {   50,  1 << WM831X_CHG_FAST_ILIM_SHIFT },
150         {  100,  2 << WM831X_CHG_FAST_ILIM_SHIFT },
151         {  150,  3 << WM831X_CHG_FAST_ILIM_SHIFT },
152         {  200,  4 << WM831X_CHG_FAST_ILIM_SHIFT },
153         {  250,  5 << WM831X_CHG_FAST_ILIM_SHIFT },
154         {  300,  6 << WM831X_CHG_FAST_ILIM_SHIFT },
155         {  350,  7 << WM831X_CHG_FAST_ILIM_SHIFT },
156         {  400,  8 << WM831X_CHG_FAST_ILIM_SHIFT },
157         {  450,  9 << WM831X_CHG_FAST_ILIM_SHIFT },
158         {  500, 10 << WM831X_CHG_FAST_ILIM_SHIFT },
159         {  600, 11 << WM831X_CHG_FAST_ILIM_SHIFT },
160         {  700, 12 << WM831X_CHG_FAST_ILIM_SHIFT },
161         {  800, 13 << WM831X_CHG_FAST_ILIM_SHIFT },
162         {  900, 14 << WM831X_CHG_FAST_ILIM_SHIFT },
163         { 1000, 15 << WM831X_CHG_FAST_ILIM_SHIFT },
164 };
165
166 static struct chg_map eoc_iterms[] = {
167         { 20, 0 << WM831X_CHG_ITERM_SHIFT },
168         { 30, 1 << WM831X_CHG_ITERM_SHIFT },
169         { 40, 2 << WM831X_CHG_ITERM_SHIFT },
170         { 50, 3 << WM831X_CHG_ITERM_SHIFT },
171         { 60, 4 << WM831X_CHG_ITERM_SHIFT },
172         { 70, 5 << WM831X_CHG_ITERM_SHIFT },
173         { 80, 6 << WM831X_CHG_ITERM_SHIFT },
174         { 90, 7 << WM831X_CHG_ITERM_SHIFT },
175 };
176
177 static struct chg_map chg_times[] = {
178         {  60,  0 << WM831X_CHG_TIME_SHIFT },
179         {  90,  1 << WM831X_CHG_TIME_SHIFT },
180         { 120,  2 << WM831X_CHG_TIME_SHIFT },
181         { 150,  3 << WM831X_CHG_TIME_SHIFT },
182         { 180,  4 << WM831X_CHG_TIME_SHIFT },
183         { 210,  5 << WM831X_CHG_TIME_SHIFT },
184         { 240,  6 << WM831X_CHG_TIME_SHIFT },
185         { 270,  7 << WM831X_CHG_TIME_SHIFT },
186         { 300,  8 << WM831X_CHG_TIME_SHIFT },
187         { 330,  9 << WM831X_CHG_TIME_SHIFT },
188         { 360, 10 << WM831X_CHG_TIME_SHIFT },
189         { 390, 11 << WM831X_CHG_TIME_SHIFT },
190         { 420, 12 << WM831X_CHG_TIME_SHIFT },
191         { 450, 13 << WM831X_CHG_TIME_SHIFT },
192         { 480, 14 << WM831X_CHG_TIME_SHIFT },
193         { 510, 15 << WM831X_CHG_TIME_SHIFT },
194 };
195
196 static void wm831x_battey_apply_config(struct wm831x *wm831x,
197                                        struct chg_map *map, int count, int val,
198                                        int *reg, const char *name,
199                                        const char *units)
200 {
201         int i;
202
203         for (i = 0; i < count; i++)
204                 if (val == map[i].val)
205                         break;
206         if (i == count) {
207                 dev_err(wm831x->dev, "Invalid %s %d%s\n",
208                         name, val, units);
209         } else {
210                 *reg |= map[i].reg_val;
211                 dev_dbg(wm831x->dev, "Set %s of %d%s\n", name, val, units);
212         }
213 }
214
215 static void wm831x_config_battery(struct wm831x *wm831x)
216 {
217         struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
218         struct wm831x_battery_pdata *pdata;
219         int ret, reg1, reg2;
220
221         if (!wm831x_pdata || !wm831x_pdata->battery) {
222                 dev_warn(wm831x->dev,
223                          "No battery charger configuration\n");
224                 return;
225         }
226
227         pdata = wm831x_pdata->battery;
228
229         reg1 = 0;
230         reg2 = 0;
231
232         if (!pdata->enable) {
233                 dev_info(wm831x->dev, "Battery charger disabled\n");
234                 return;
235         }
236
237         reg1 |= WM831X_CHG_ENA;
238         if (pdata->off_mask)
239                 reg2 |= WM831X_CHG_OFF_MSK;
240         if (pdata->fast_enable)
241                 reg1 |= WM831X_CHG_FAST;
242
243         wm831x_battey_apply_config(wm831x, trickle_ilims,
244                                    ARRAY_SIZE(trickle_ilims),
245                                    pdata->trickle_ilim, &reg2,
246                                    "trickle charge current limit", "mA");
247
248         wm831x_battey_apply_config(wm831x, vsels, ARRAY_SIZE(vsels),
249                                    pdata->vsel, &reg2,
250                                    "target voltage", "mV");
251
252         wm831x_battey_apply_config(wm831x, fast_ilims, ARRAY_SIZE(fast_ilims),
253                                    pdata->fast_ilim, &reg2,
254                                    "fast charge current limit", "mA");
255
256         wm831x_battey_apply_config(wm831x, eoc_iterms, ARRAY_SIZE(eoc_iterms),
257                                    pdata->eoc_iterm, &reg1,
258                                    "end of charge current threshold", "mA");
259
260         wm831x_battey_apply_config(wm831x, chg_times, ARRAY_SIZE(chg_times),
261                                    pdata->timeout, &reg2,
262                                    "charger timeout", "min");
263
264         ret = wm831x_reg_unlock(wm831x);
265         if (ret != 0) {
266                 dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret);
267                 return;
268         }
269
270         ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_1,
271                               WM831X_CHG_ENA_MASK |
272                               WM831X_CHG_FAST_MASK |
273                               WM831X_CHG_ITERM_MASK,
274                               reg1);
275         if (ret != 0)
276                 dev_err(wm831x->dev, "Failed to set charger control 1: %d\n",
277                         ret);
278
279         ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_2,
280                               WM831X_CHG_OFF_MSK |
281                               WM831X_CHG_TIME_MASK |
282                               WM831X_CHG_FAST_ILIM_MASK |
283                               WM831X_CHG_TRKL_ILIM_MASK |
284                               WM831X_CHG_VSEL_MASK,
285                               reg2);
286         if (ret != 0)
287                 dev_err(wm831x->dev, "Failed to set charger control 2: %d\n",
288                         ret);
289
290         wm831x_reg_lock(wm831x);
291 }
292
293 static int wm831x_bat_check_status(struct wm831x *wm831x, int *status)
294 {
295         int ret;
296
297         ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS);
298         if (ret < 0)
299                 return ret;
300
301         if (ret & WM831X_PWR_SRC_BATT) {
302                 *status = POWER_SUPPLY_STATUS_DISCHARGING;
303                 return 0;
304         }
305
306         ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
307         if (ret < 0)
308                 return ret;
309
310         switch (ret & WM831X_CHG_STATE_MASK) {
311         case WM831X_CHG_STATE_OFF:
312                 *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
313                 break;
314         case WM831X_CHG_STATE_TRICKLE:
315         case WM831X_CHG_STATE_FAST:
316                 *status = POWER_SUPPLY_STATUS_CHARGING;
317                 break;
318
319         default:
320                 *status = POWER_SUPPLY_STATUS_UNKNOWN;
321                 break;
322         }
323
324         return 0;
325 }
326
327 static int wm831x_bat_check_type(struct wm831x *wm831x, int *type)
328 {
329         int ret;
330
331         ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
332         if (ret < 0)
333                 return ret;
334
335         switch (ret & WM831X_CHG_STATE_MASK) {
336         case WM831X_CHG_STATE_TRICKLE:
337         case WM831X_CHG_STATE_TRICKLE_OT:
338                 *type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
339                 break;
340         case WM831X_CHG_STATE_FAST:
341         case WM831X_CHG_STATE_FAST_OT:
342                 *type = POWER_SUPPLY_CHARGE_TYPE_FAST;
343                 break;
344         default:
345                 *type = POWER_SUPPLY_CHARGE_TYPE_NONE;
346                 break;
347         }
348
349         return 0;
350 }
351
352 static int wm831x_bat_check_health(struct wm831x *wm831x, int *health)
353 {
354         int ret;
355
356         ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
357         if (ret < 0)
358                 return ret;
359
360         if (ret & WM831X_BATT_HOT_STS) {
361                 *health = POWER_SUPPLY_HEALTH_OVERHEAT;
362                 return 0;
363         }
364
365         if (ret & WM831X_BATT_COLD_STS) {
366                 *health = POWER_SUPPLY_HEALTH_COLD;
367                 return 0;
368         }
369
370         if (ret & WM831X_BATT_OV_STS) {
371                 *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
372                 return 0;
373         }
374
375         switch (ret & WM831X_CHG_STATE_MASK) {
376         case WM831X_CHG_STATE_TRICKLE_OT:
377         case WM831X_CHG_STATE_FAST_OT:
378                 *health = POWER_SUPPLY_HEALTH_OVERHEAT;
379                 break;
380         case WM831X_CHG_STATE_DEFECTIVE:
381                 *health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
382                 break;
383         default:
384                 *health = POWER_SUPPLY_HEALTH_GOOD;
385                 break;
386         }
387
388         return 0;
389 }
390
391 static int wm831x_bat_get_prop(struct power_supply *psy,
392                                enum power_supply_property psp,
393                                union power_supply_propval *val)
394 {
395         struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev->parent);
396         struct wm831x *wm831x = wm831x_power->wm831x;
397         int ret = 0;
398
399         switch (psp) {
400         case POWER_SUPPLY_PROP_STATUS:
401                 ret = wm831x_bat_check_status(wm831x, &val->intval);
402                 break;
403         case POWER_SUPPLY_PROP_ONLINE:
404                 ret = wm831x_power_check_online(wm831x, WM831X_PWR_SRC_BATT,
405                                                 val);
406                 break;
407         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
408                 ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_BATT, val);
409                 break;
410         case POWER_SUPPLY_PROP_HEALTH:
411                 ret = wm831x_bat_check_health(wm831x, &val->intval);
412                 break;
413         case POWER_SUPPLY_PROP_CHARGE_TYPE:
414                 ret = wm831x_bat_check_type(wm831x, &val->intval);
415                 break;
416         default:
417                 ret = -EINVAL;
418                 break;
419         }
420
421         return ret;
422 }
423
424 static enum power_supply_property wm831x_bat_props[] = {
425         POWER_SUPPLY_PROP_STATUS,
426         POWER_SUPPLY_PROP_ONLINE,
427         POWER_SUPPLY_PROP_VOLTAGE_NOW,
428         POWER_SUPPLY_PROP_HEALTH,
429         POWER_SUPPLY_PROP_CHARGE_TYPE,
430 };
431
432 static const char *wm831x_bat_irqs[] = {
433         "BATT HOT",
434         "BATT COLD",
435         "BATT FAIL",
436         "OV",
437         "END",
438         "TO",
439         "MODE",
440         "START",
441 };
442
443 static irqreturn_t wm831x_bat_irq(int irq, void *data)
444 {
445         struct wm831x_power *wm831x_power = data;
446         struct wm831x *wm831x = wm831x_power->wm831x;
447
448         dev_dbg(wm831x->dev, "Battery status changed: %d\n", irq);
449
450         /* The battery charger is autonomous so we don't need to do
451          * anything except kick user space */
452         power_supply_changed(&wm831x_power->battery);
453
454         return IRQ_HANDLED;
455 }
456
457
458 /*********************************************************************
459  *              Initialisation
460  *********************************************************************/
461
462 static irqreturn_t wm831x_syslo_irq(int irq, void *data)
463 {
464         struct wm831x_power *wm831x_power = data;
465         struct wm831x *wm831x = wm831x_power->wm831x;
466
467         /* Not much we can actually *do* but tell people for
468          * posterity, we're probably about to run out of power. */
469         dev_crit(wm831x->dev, "SYSVDD under voltage\n");
470
471         return IRQ_HANDLED;
472 }
473
474 static irqreturn_t wm831x_pwr_src_irq(int irq, void *data)
475 {
476         struct wm831x_power *wm831x_power = data;
477         struct wm831x *wm831x = wm831x_power->wm831x;
478
479         dev_dbg(wm831x->dev, "Power source changed\n");
480
481         /* Just notify for everything - little harm in overnotifying. */
482         power_supply_changed(&wm831x_power->battery);
483         power_supply_changed(&wm831x_power->usb);
484         power_supply_changed(&wm831x_power->wall);
485
486         return IRQ_HANDLED;
487 }
488
489 static __devinit int wm831x_power_probe(struct platform_device *pdev)
490 {
491         struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
492         struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
493         struct wm831x_power *power;
494         struct power_supply *usb;
495         struct power_supply *battery;
496         struct power_supply *wall;
497         int ret, irq, i;
498
499         power = kzalloc(sizeof(struct wm831x_power), GFP_KERNEL);
500         if (power == NULL)
501                 return -ENOMEM;
502
503         power->wm831x = wm831x;
504         platform_set_drvdata(pdev, power);
505
506         usb = &power->usb;
507         battery = &power->battery;
508         wall = &power->wall;
509
510         if (wm831x_pdata && wm831x_pdata->wm831x_num) {
511                 snprintf(power->wall_name, sizeof(power->wall_name),
512                          "wm831x-wall.%d", wm831x_pdata->wm831x_num);
513                 snprintf(power->battery_name, sizeof(power->wall_name),
514                          "wm831x-battery.%d", wm831x_pdata->wm831x_num);
515                 snprintf(power->usb_name, sizeof(power->wall_name),
516                          "wm831x-usb.%d", wm831x_pdata->wm831x_num);
517         } else {
518                 snprintf(power->wall_name, sizeof(power->wall_name),
519                          "wm831x-wall");
520                 snprintf(power->battery_name, sizeof(power->wall_name),
521                          "wm831x-battery");
522                 snprintf(power->usb_name, sizeof(power->wall_name),
523                          "wm831x-usb");
524         }
525
526         /* We ignore configuration failures since we can still read back
527          * the status without enabling the charger.
528          */
529         wm831x_config_battery(wm831x);
530
531         wall->name = power->wall_name;
532         wall->type = POWER_SUPPLY_TYPE_MAINS;
533         wall->properties = wm831x_wall_props;
534         wall->num_properties = ARRAY_SIZE(wm831x_wall_props);
535         wall->get_property = wm831x_wall_get_prop;
536         ret = power_supply_register(&pdev->dev, wall);
537         if (ret)
538                 goto err_kmalloc;
539
540         battery->name = power->battery_name;
541         battery->properties = wm831x_bat_props;
542         battery->num_properties = ARRAY_SIZE(wm831x_bat_props);
543         battery->get_property = wm831x_bat_get_prop;
544         battery->use_for_apm = 1;
545         ret = power_supply_register(&pdev->dev, battery);
546         if (ret)
547                 goto err_wall;
548
549         usb->name = power->usb_name,
550         usb->type = POWER_SUPPLY_TYPE_USB;
551         usb->properties = wm831x_usb_props;
552         usb->num_properties = ARRAY_SIZE(wm831x_usb_props);
553         usb->get_property = wm831x_usb_get_prop;
554         ret = power_supply_register(&pdev->dev, usb);
555         if (ret)
556                 goto err_battery;
557
558         irq = platform_get_irq_byname(pdev, "SYSLO");
559         ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq,
560                                    IRQF_TRIGGER_RISING, "System power low",
561                                    power);
562         if (ret != 0) {
563                 dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n",
564                         irq, ret);
565                 goto err_usb;
566         }
567
568         irq = platform_get_irq_byname(pdev, "PWR SRC");
569         ret = request_threaded_irq(irq, NULL, wm831x_pwr_src_irq,
570                                    IRQF_TRIGGER_RISING, "Power source",
571                                    power);
572         if (ret != 0) {
573                 dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n",
574                         irq, ret);
575                 goto err_syslo;
576         }
577
578         for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
579                 irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
580                 ret = request_threaded_irq(irq, NULL, wm831x_bat_irq,
581                                            IRQF_TRIGGER_RISING,
582                                            wm831x_bat_irqs[i],
583                                            power);
584                 if (ret != 0) {
585                         dev_err(&pdev->dev,
586                                 "Failed to request %s IRQ %d: %d\n",
587                                 wm831x_bat_irqs[i], irq, ret);
588                         goto err_bat_irq;
589                 }
590         }
591
592         return ret;
593
594 err_bat_irq:
595         for (; i >= 0; i--) {
596                 irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
597                 free_irq(irq, power);
598         }
599         irq = platform_get_irq_byname(pdev, "PWR SRC");
600         free_irq(irq, power);
601 err_syslo:
602         irq = platform_get_irq_byname(pdev, "SYSLO");
603         free_irq(irq, power);
604 err_usb:
605         power_supply_unregister(usb);
606 err_battery:
607         power_supply_unregister(battery);
608 err_wall:
609         power_supply_unregister(wall);
610 err_kmalloc:
611         kfree(power);
612         return ret;
613 }
614
615 static __devexit int wm831x_power_remove(struct platform_device *pdev)
616 {
617         struct wm831x_power *wm831x_power = platform_get_drvdata(pdev);
618         int irq, i;
619
620         for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
621                 irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
622                 free_irq(irq, wm831x_power);
623         }
624
625         irq = platform_get_irq_byname(pdev, "PWR SRC");
626         free_irq(irq, wm831x_power);
627
628         irq = platform_get_irq_byname(pdev, "SYSLO");
629         free_irq(irq, wm831x_power);
630
631         power_supply_unregister(&wm831x_power->battery);
632         power_supply_unregister(&wm831x_power->wall);
633         power_supply_unregister(&wm831x_power->usb);
634         kfree(wm831x_power);
635         return 0;
636 }
637
638 static struct platform_driver wm831x_power_driver = {
639         .probe = wm831x_power_probe,
640         .remove = __devexit_p(wm831x_power_remove),
641         .driver = {
642                 .name = "wm831x-power",
643         },
644 };
645
646 static int __init wm831x_power_init(void)
647 {
648         return platform_driver_register(&wm831x_power_driver);
649 }
650 module_init(wm831x_power_init);
651
652 static void __exit wm831x_power_exit(void)
653 {
654         platform_driver_unregister(&wm831x_power_driver);
655 }
656 module_exit(wm831x_power_exit);
657
658 MODULE_DESCRIPTION("Power supply driver for WM831x PMICs");
659 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
660 MODULE_LICENSE("GPL");
661 MODULE_ALIAS("platform:wm831x-power");