aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/Kconfig14
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/da9030_battery.c600
-rw-r--r--drivers/power/power_supply_sysfs.c2
-rw-r--r--drivers/power/wm8350_power.c532
5 files changed, 1149 insertions, 1 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 8e0c2b47803c..668472405a57 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -29,6 +29,13 @@ config APM_POWER
29 Say Y here to enable support APM status emulation using 29 Say Y here to enable support APM status emulation using
30 battery class devices. 30 battery class devices.
31 31
32config WM8350_POWER
33 tristate "WM8350 PMU support"
34 depends on MFD_WM8350
35 help
36 Say Y here to enable support for the power management unit
37 provided by the Wolfson Microelectronics WM8350 PMIC.
38
32config BATTERY_DS2760 39config BATTERY_DS2760
33 tristate "DS2760 battery driver (HP iPAQ & others)" 40 tristate "DS2760 battery driver (HP iPAQ & others)"
34 select W1 41 select W1
@@ -68,4 +75,11 @@ config BATTERY_BQ27x00
68 help 75 help
69 Say Y here to enable support for batteries with BQ27200(I2C) chip. 76 Say Y here to enable support for batteries with BQ27200(I2C) chip.
70 77
78config BATTERY_DA9030
79 tristate "DA9030 battery driver"
80 depends on PMIC_DA903X
81 help
82 Say Y here to enable support for batteries charger integrated into
83 DA9030 PMIC.
84
71endif # POWER_SUPPLY 85endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index e8f1ecec5d8f..eebb15505a40 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
16 16
17obj-$(CONFIG_PDA_POWER) += pda_power.o 17obj-$(CONFIG_PDA_POWER) += pda_power.o
18obj-$(CONFIG_APM_POWER) += apm_power.o 18obj-$(CONFIG_APM_POWER) += apm_power.o
19obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
19 20
20obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o 21obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
21obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o 22obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
@@ -23,3 +24,4 @@ obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
23obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o 24obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
24obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o 25obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
25obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o 26obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
27obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c
new file mode 100644
index 000000000000..1662bb0f23a5
--- /dev/null
+++ b/drivers/power/da9030_battery.c
@@ -0,0 +1,600 @@
1/*
2 * Battery charger driver for Dialog Semiconductor DA9030
3 *
4 * Copyright (C) 2008 Compulab, Ltd.
5 * Mike Rapoport <mike@compulab.co.il>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/types.h>
15#include <linux/device.h>
16#include <linux/workqueue.h>
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <linux/power_supply.h>
20#include <linux/mfd/da903x.h>
21
22#include <linux/debugfs.h>
23#include <linux/seq_file.h>
24
25#define DA9030_STATUS_CHDET (1 << 3)
26
27#define DA9030_FAULT_LOG 0x0a
28#define DA9030_FAULT_LOG_OVER_TEMP (1 << 7)
29#define DA9030_FAULT_LOG_VBAT_OVER (1 << 4)
30
31#define DA9030_CHARGE_CONTROL 0x28
32#define DA9030_CHRG_CHARGER_ENABLE (1 << 7)
33
34#define DA9030_ADC_MAN_CONTROL 0x30
35#define DA9030_ADC_TBATREF_ENABLE (1 << 5)
36#define DA9030_ADC_LDO_INT_ENABLE (1 << 4)
37
38#define DA9030_ADC_AUTO_CONTROL 0x31
39#define DA9030_ADC_TBAT_ENABLE (1 << 5)
40#define DA9030_ADC_VBAT_IN_TXON (1 << 4)
41#define DA9030_ADC_VCH_ENABLE (1 << 3)
42#define DA9030_ADC_ICH_ENABLE (1 << 2)
43#define DA9030_ADC_VBAT_ENABLE (1 << 1)
44#define DA9030_ADC_AUTO_SLEEP_ENABLE (1 << 0)
45
46#define DA9030_VBATMON 0x32
47#define DA9030_VBATMONTXON 0x33
48#define DA9030_TBATHIGHP 0x34
49#define DA9030_TBATHIGHN 0x35
50#define DA9030_TBATLOW 0x36
51
52#define DA9030_VBAT_RES 0x41
53#define DA9030_VBATMIN_RES 0x42
54#define DA9030_VBATMINTXON_RES 0x43
55#define DA9030_ICHMAX_RES 0x44
56#define DA9030_ICHMIN_RES 0x45
57#define DA9030_ICHAVERAGE_RES 0x46
58#define DA9030_VCHMAX_RES 0x47
59#define DA9030_VCHMIN_RES 0x48
60#define DA9030_TBAT_RES 0x49
61
62struct da9030_adc_res {
63 uint8_t vbat_res;
64 uint8_t vbatmin_res;
65 uint8_t vbatmintxon;
66 uint8_t ichmax_res;
67 uint8_t ichmin_res;
68 uint8_t ichaverage_res;
69 uint8_t vchmax_res;
70 uint8_t vchmin_res;
71 uint8_t tbat_res;
72 uint8_t adc_in4_res;
73 uint8_t adc_in5_res;
74};
75
76struct da9030_battery_thresholds {
77 int tbat_low;
78 int tbat_high;
79 int tbat_restart;
80
81 int vbat_low;
82 int vbat_crit;
83 int vbat_charge_start;
84 int vbat_charge_stop;
85 int vbat_charge_restart;
86
87 int vcharge_min;
88 int vcharge_max;
89};
90
91struct da9030_charger {
92 struct power_supply psy;
93
94 struct device *master;
95
96 struct da9030_adc_res adc;
97 struct delayed_work work;
98 unsigned int interval;
99
100 struct power_supply_info *battery_info;
101
102 struct da9030_battery_thresholds thresholds;
103
104 unsigned int charge_milliamp;
105 unsigned int charge_millivolt;
106
107 /* charger status */
108 bool chdet;
109 uint8_t fault;
110 int mA;
111 int mV;
112 bool is_on;
113
114 struct notifier_block nb;
115
116 /* platform callbacks for battery low and critical events */
117 void (*battery_low)(void);
118 void (*battery_critical)(void);
119
120 struct dentry *debug_file;
121};
122
123static inline int da9030_reg_to_mV(int reg)
124{
125 return ((reg * 2650) >> 8) + 2650;
126}
127
128static inline int da9030_millivolt_to_reg(int mV)
129{
130 return ((mV - 2650) << 8) / 2650;
131}
132
133static inline int da9030_reg_to_mA(int reg)
134{
135 return ((reg * 24000) >> 8) / 15;
136}
137
138#ifdef CONFIG_DEBUG_FS
139static int bat_debug_show(struct seq_file *s, void *data)
140{
141 struct da9030_charger *charger = s->private;
142
143 seq_printf(s, "charger is %s\n", charger->is_on ? "on" : "off");
144 if (charger->chdet) {
145 seq_printf(s, "iset = %dmA, vset = %dmV\n",
146 charger->mA, charger->mV);
147 }
148
149 seq_printf(s, "vbat_res = %d (%dmV)\n",
150 charger->adc.vbat_res,
151 da9030_reg_to_mV(charger->adc.vbat_res));
152 seq_printf(s, "vbatmin_res = %d (%dmV)\n",
153 charger->adc.vbatmin_res,
154 da9030_reg_to_mV(charger->adc.vbatmin_res));
155 seq_printf(s, "vbatmintxon = %d (%dmV)\n",
156 charger->adc.vbatmintxon,
157 da9030_reg_to_mV(charger->adc.vbatmintxon));
158 seq_printf(s, "ichmax_res = %d (%dmA)\n",
159 charger->adc.ichmax_res,
160 da9030_reg_to_mV(charger->adc.ichmax_res));
161 seq_printf(s, "ichmin_res = %d (%dmA)\n",
162 charger->adc.ichmin_res,
163 da9030_reg_to_mA(charger->adc.ichmin_res));
164 seq_printf(s, "ichaverage_res = %d (%dmA)\n",
165 charger->adc.ichaverage_res,
166 da9030_reg_to_mA(charger->adc.ichaverage_res));
167 seq_printf(s, "vchmax_res = %d (%dmV)\n",
168 charger->adc.vchmax_res,
169 da9030_reg_to_mA(charger->adc.vchmax_res));
170 seq_printf(s, "vchmin_res = %d (%dmV)\n",
171 charger->adc.vchmin_res,
172 da9030_reg_to_mV(charger->adc.vchmin_res));
173
174 return 0;
175}
176
177static int debug_open(struct inode *inode, struct file *file)
178{
179 return single_open(file, bat_debug_show, inode->i_private);
180}
181
182static const struct file_operations bat_debug_fops = {
183 .open = debug_open,
184 .read = seq_read,
185 .llseek = seq_lseek,
186 .release = single_release,
187};
188
189static struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
190{
191 charger->debug_file = debugfs_create_file("charger", 0666, 0, charger,
192 &bat_debug_fops);
193 return charger->debug_file;
194}
195
196static void da9030_bat_remove_debugfs(struct da9030_charger *charger)
197{
198 debugfs_remove(charger->debug_file);
199}
200#else
201static inline struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
202{
203 return NULL;
204}
205static inline void da9030_bat_remove_debugfs(struct da9030_charger *charger)
206{
207}
208#endif
209
210static inline void da9030_read_adc(struct da9030_charger *charger,
211 struct da9030_adc_res *adc)
212{
213 da903x_reads(charger->master, DA9030_VBAT_RES,
214 sizeof(*adc), (uint8_t *)adc);
215}
216
217static void da9030_charger_update_state(struct da9030_charger *charger)
218{
219 uint8_t val;
220
221 da903x_read(charger->master, DA9030_CHARGE_CONTROL, &val);
222 charger->is_on = (val & DA9030_CHRG_CHARGER_ENABLE) ? 1 : 0;
223 charger->mA = ((val >> 3) & 0xf) * 100;
224 charger->mV = (val & 0x7) * 50 + 4000;
225
226 da9030_read_adc(charger, &charger->adc);
227 da903x_read(charger->master, DA9030_FAULT_LOG, &charger->fault);
228 charger->chdet = da903x_query_status(charger->master,
229 DA9030_STATUS_CHDET);
230}
231
232static void da9030_set_charge(struct da9030_charger *charger, int on)
233{
234 uint8_t val;
235
236 if (on) {
237 val = DA9030_CHRG_CHARGER_ENABLE;
238 val |= (charger->charge_milliamp / 100) << 3;
239 val |= (charger->charge_millivolt - 4000) / 50;
240 charger->is_on = 1;
241 } else {
242 val = 0;
243 charger->is_on = 0;
244 }
245
246 da903x_write(charger->master, DA9030_CHARGE_CONTROL, val);
247}
248
249static void da9030_charger_check_state(struct da9030_charger *charger)
250{
251 da9030_charger_update_state(charger);
252
253 /* we wake or boot with external power on */
254 if (!charger->is_on) {
255 if ((charger->chdet) &&
256 (charger->adc.vbat_res <
257 charger->thresholds.vbat_charge_start)) {
258 da9030_set_charge(charger, 1);
259 }
260 } else {
261 if (charger->adc.vbat_res >=
262 charger->thresholds.vbat_charge_stop) {
263 da9030_set_charge(charger, 0);
264 da903x_write(charger->master, DA9030_VBATMON,
265 charger->thresholds.vbat_charge_restart);
266 } else if (charger->adc.vbat_res >
267 charger->thresholds.vbat_low) {
268 /* we are charging and passed LOW_THRESH,
269 so upate DA9030 VBAT threshold
270 */
271 da903x_write(charger->master, DA9030_VBATMON,
272 charger->thresholds.vbat_low);
273 }
274 if (charger->adc.vchmax_res > charger->thresholds.vcharge_max ||
275 charger->adc.vchmin_res < charger->thresholds.vcharge_min ||
276 /* Tempreture readings are negative */
277 charger->adc.tbat_res < charger->thresholds.tbat_high ||
278 charger->adc.tbat_res > charger->thresholds.tbat_low) {
279 /* disable charger */
280 da9030_set_charge(charger, 0);
281 }
282 }
283}
284
285static void da9030_charging_monitor(struct work_struct *work)
286{
287 struct da9030_charger *charger;
288
289 charger = container_of(work, struct da9030_charger, work.work);
290
291 da9030_charger_check_state(charger);
292
293 /* reschedule for the next time */
294 schedule_delayed_work(&charger->work, charger->interval);
295}
296
297static enum power_supply_property da9030_battery_props[] = {
298 POWER_SUPPLY_PROP_MODEL_NAME,
299 POWER_SUPPLY_PROP_STATUS,
300 POWER_SUPPLY_PROP_HEALTH,
301 POWER_SUPPLY_PROP_TECHNOLOGY,
302 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
303 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
304 POWER_SUPPLY_PROP_VOLTAGE_NOW,
305 POWER_SUPPLY_PROP_CURRENT_AVG,
306};
307
308static void da9030_battery_check_status(struct da9030_charger *charger,
309 union power_supply_propval *val)
310{
311 if (charger->chdet) {
312 if (charger->is_on)
313 val->intval = POWER_SUPPLY_STATUS_CHARGING;
314 else
315 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
316 } else {
317 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
318 }
319}
320
321static void da9030_battery_check_health(struct da9030_charger *charger,
322 union power_supply_propval *val)
323{
324 if (charger->fault & DA9030_FAULT_LOG_OVER_TEMP)
325 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
326 else if (charger->fault & DA9030_FAULT_LOG_VBAT_OVER)
327 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
328 else
329 val->intval = POWER_SUPPLY_HEALTH_GOOD;
330}
331
332static int da9030_battery_get_property(struct power_supply *psy,
333 enum power_supply_property psp,
334 union power_supply_propval *val)
335{
336 struct da9030_charger *charger;
337 charger = container_of(psy, struct da9030_charger, psy);
338
339 switch (psp) {
340 case POWER_SUPPLY_PROP_STATUS:
341 da9030_battery_check_status(charger, val);
342 break;
343 case POWER_SUPPLY_PROP_HEALTH:
344 da9030_battery_check_health(charger, val);
345 break;
346 case POWER_SUPPLY_PROP_TECHNOLOGY:
347 val->intval = charger->battery_info->technology;
348 break;
349 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
350 val->intval = charger->battery_info->voltage_max_design;
351 break;
352 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
353 val->intval = charger->battery_info->voltage_min_design;
354 break;
355 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
356 val->intval = da9030_reg_to_mV(charger->adc.vbat_res) * 1000;
357 break;
358 case POWER_SUPPLY_PROP_CURRENT_AVG:
359 val->intval =
360 da9030_reg_to_mA(charger->adc.ichaverage_res) * 1000;
361 break;
362 case POWER_SUPPLY_PROP_MODEL_NAME:
363 val->strval = charger->battery_info->name;
364 break;
365 default:
366 break;
367 }
368
369 return 0;
370}
371
372static void da9030_battery_vbat_event(struct da9030_charger *charger)
373{
374 da9030_read_adc(charger, &charger->adc);
375
376 if (charger->is_on)
377 return;
378
379 if (charger->adc.vbat_res < charger->thresholds.vbat_low) {
380 /* set VBAT threshold for critical */
381 da903x_write(charger->master, DA9030_VBATMON,
382 charger->thresholds.vbat_crit);
383 if (charger->battery_low)
384 charger->battery_low();
385 } else if (charger->adc.vbat_res <
386 charger->thresholds.vbat_crit) {
387 /* notify the system of battery critical */
388 if (charger->battery_critical)
389 charger->battery_critical();
390 }
391}
392
393static int da9030_battery_event(struct notifier_block *nb, unsigned long event,
394 void *data)
395{
396 struct da9030_charger *charger =
397 container_of(nb, struct da9030_charger, nb);
398 int status;
399
400 switch (event) {
401 case DA9030_EVENT_CHDET:
402 status = da903x_query_status(charger->master,
403 DA9030_STATUS_CHDET);
404 da9030_set_charge(charger, status);
405 break;
406 case DA9030_EVENT_VBATMON:
407 da9030_battery_vbat_event(charger);
408 break;
409 case DA9030_EVENT_CHIOVER:
410 case DA9030_EVENT_TBAT:
411 da9030_set_charge(charger, 0);
412 break;
413 }
414
415 return 0;
416}
417
418static void da9030_battery_convert_thresholds(struct da9030_charger *charger,
419 struct da9030_battery_info *pdata)
420{
421 charger->thresholds.tbat_low = pdata->tbat_low;
422 charger->thresholds.tbat_high = pdata->tbat_high;
423 charger->thresholds.tbat_restart = pdata->tbat_restart;
424
425 charger->thresholds.vbat_low =
426 da9030_millivolt_to_reg(pdata->vbat_low);
427 charger->thresholds.vbat_crit =
428 da9030_millivolt_to_reg(pdata->vbat_crit);
429 charger->thresholds.vbat_charge_start =
430 da9030_millivolt_to_reg(pdata->vbat_charge_start);
431 charger->thresholds.vbat_charge_stop =
432 da9030_millivolt_to_reg(pdata->vbat_charge_stop);
433 charger->thresholds.vbat_charge_restart =
434 da9030_millivolt_to_reg(pdata->vbat_charge_restart);
435
436 charger->thresholds.vcharge_min =
437 da9030_millivolt_to_reg(pdata->vcharge_min);
438 charger->thresholds.vcharge_max =
439 da9030_millivolt_to_reg(pdata->vcharge_max);
440}
441
442static void da9030_battery_setup_psy(struct da9030_charger *charger)
443{
444 struct power_supply *psy = &charger->psy;
445 struct power_supply_info *info = charger->battery_info;
446
447 psy->name = info->name;
448 psy->use_for_apm = info->use_for_apm;
449 psy->type = POWER_SUPPLY_TYPE_BATTERY;
450 psy->get_property = da9030_battery_get_property;
451
452 psy->properties = da9030_battery_props;
453 psy->num_properties = ARRAY_SIZE(da9030_battery_props);
454};
455
456static int da9030_battery_charger_init(struct da9030_charger *charger)
457{
458 char v[5];
459 int ret;
460
461 v[0] = v[1] = charger->thresholds.vbat_low;
462 v[2] = charger->thresholds.tbat_high;
463 v[3] = charger->thresholds.tbat_restart;
464 v[4] = charger->thresholds.tbat_low;
465
466 ret = da903x_writes(charger->master, DA9030_VBATMON, 5, v);
467 if (ret)
468 return ret;
469
470 /*
471 * Enable reference voltage supply for ADC from the LDO_INTERNAL
472 * regulator. Must be set before ADC measurements can be made.
473 */
474 ret = da903x_write(charger->master, DA9030_ADC_MAN_CONTROL,
475 DA9030_ADC_LDO_INT_ENABLE |
476 DA9030_ADC_TBATREF_ENABLE);
477 if (ret)
478 return ret;
479
480 /* enable auto ADC measuremnts */
481 return da903x_write(charger->master, DA9030_ADC_AUTO_CONTROL,
482 DA9030_ADC_TBAT_ENABLE | DA9030_ADC_VBAT_IN_TXON |
483 DA9030_ADC_VCH_ENABLE | DA9030_ADC_ICH_ENABLE |
484 DA9030_ADC_VBAT_ENABLE |
485 DA9030_ADC_AUTO_SLEEP_ENABLE);
486}
487
488static int da9030_battery_probe(struct platform_device *pdev)
489{
490 struct da9030_charger *charger;
491 struct da9030_battery_info *pdata = pdev->dev.platform_data;
492 int ret;
493
494 if (pdata == NULL)
495 return -EINVAL;
496
497 if (pdata->charge_milliamp >= 1500 ||
498 pdata->charge_millivolt < 4000 ||
499 pdata->charge_millivolt > 4350)
500 return -EINVAL;
501
502 charger = kzalloc(sizeof(*charger), GFP_KERNEL);
503 if (charger == NULL)
504 return -ENOMEM;
505
506 charger->master = pdev->dev.parent;
507
508 /* 10 seconds between monotor runs unless platfrom defines other
509 interval */
510 charger->interval = msecs_to_jiffies(
511 (pdata->batmon_interval ? : 10) * 1000);
512
513 charger->charge_milliamp = pdata->charge_milliamp;
514 charger->charge_millivolt = pdata->charge_millivolt;
515 charger->battery_info = pdata->battery_info;
516 charger->battery_low = pdata->battery_low;
517 charger->battery_critical = pdata->battery_critical;
518
519 da9030_battery_convert_thresholds(charger, pdata);
520
521 ret = da9030_battery_charger_init(charger);
522 if (ret)
523 goto err_charger_init;
524
525 INIT_DELAYED_WORK(&charger->work, da9030_charging_monitor);
526 schedule_delayed_work(&charger->work, charger->interval);
527
528 charger->nb.notifier_call = da9030_battery_event;
529 ret = da903x_register_notifier(charger->master, &charger->nb,
530 DA9030_EVENT_CHDET |
531 DA9030_EVENT_VBATMON |
532 DA9030_EVENT_CHIOVER |
533 DA9030_EVENT_TBAT);
534 if (ret)
535 goto err_notifier;
536
537 da9030_battery_setup_psy(charger);
538 ret = power_supply_register(&pdev->dev, &charger->psy);
539 if (ret)
540 goto err_ps_register;
541
542 charger->debug_file = da9030_bat_create_debugfs(charger);
543 platform_set_drvdata(pdev, charger);
544 return 0;
545
546err_ps_register:
547 da903x_unregister_notifier(charger->master, &charger->nb,
548 DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
549 DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
550err_notifier:
551 cancel_delayed_work(&charger->work);
552
553err_charger_init:
554 kfree(charger);
555
556 return ret;
557}
558
559static int da9030_battery_remove(struct platform_device *dev)
560{
561 struct da9030_charger *charger = platform_get_drvdata(dev);
562
563 da9030_bat_remove_debugfs(charger);
564
565 da903x_unregister_notifier(charger->master, &charger->nb,
566 DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
567 DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
568 cancel_delayed_work(&charger->work);
569 power_supply_unregister(&charger->psy);
570
571 kfree(charger);
572
573 return 0;
574}
575
576static struct platform_driver da903x_battery_driver = {
577 .driver = {
578 .name = "da903x-battery",
579 .owner = THIS_MODULE,
580 },
581 .probe = da9030_battery_probe,
582 .remove = da9030_battery_remove,
583};
584
585static int da903x_battery_init(void)
586{
587 return platform_driver_register(&da903x_battery_driver);
588}
589
590static void da903x_battery_exit(void)
591{
592 platform_driver_unregister(&da903x_battery_driver);
593}
594
595module_init(da903x_battery_init);
596module_exit(da903x_battery_exit);
597
598MODULE_DESCRIPTION("DA9030 battery charger driver");
599MODULE_AUTHOR("Mike Rapoport, CompuLab");
600MODULE_LICENSE("GPL");
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 23ae8460f5c1..ac01e06817fb 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -45,7 +45,7 @@ static ssize_t power_supply_show_property(struct device *dev,
45 }; 45 };
46 static char *health_text[] = { 46 static char *health_text[] = {
47 "Unknown", "Good", "Overheat", "Dead", "Over voltage", 47 "Unknown", "Good", "Overheat", "Dead", "Over voltage",
48 "Unspecified failure" 48 "Unspecified failure", "Cold",
49 }; 49 };
50 static char *technology_text[] = { 50 static char *technology_text[] = {
51 "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd", 51 "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c
new file mode 100644
index 000000000000..1b16bf343f2f
--- /dev/null
+++ b/drivers/power/wm8350_power.c
@@ -0,0 +1,532 @@
1/*
2 * Battery driver for wm8350 PMIC
3 *
4 * Copyright 2007, 2008 Wolfson Microelectronics PLC.
5 *
6 * Based on OLPC Battery Driver
7 *
8 * Copyright 2006 David Woodhouse <dwmw2@infradead.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/module.h>
16#include <linux/err.h>
17#include <linux/platform_device.h>
18#include <linux/power_supply.h>
19#include <linux/mfd/wm8350/supply.h>
20#include <linux/mfd/wm8350/core.h>
21#include <linux/mfd/wm8350/comparator.h>
22
23static int wm8350_read_battery_uvolts(struct wm8350 *wm8350)
24{
25 return wm8350_read_auxadc(wm8350, WM8350_AUXADC_BATT, 0, 0)
26 * WM8350_AUX_COEFF;
27}
28
29static int wm8350_read_line_uvolts(struct wm8350 *wm8350)
30{
31 return wm8350_read_auxadc(wm8350, WM8350_AUXADC_LINE, 0, 0)
32 * WM8350_AUX_COEFF;
33}
34
35static int wm8350_read_usb_uvolts(struct wm8350 *wm8350)
36{
37 return wm8350_read_auxadc(wm8350, WM8350_AUXADC_USB, 0, 0)
38 * WM8350_AUX_COEFF;
39}
40
41#define WM8350_BATT_SUPPLY 1
42#define WM8350_USB_SUPPLY 2
43#define WM8350_LINE_SUPPLY 4
44
45static inline int wm8350_charge_time_min(struct wm8350 *wm8350, int min)
46{
47 if (!wm8350->power.rev_g_coeff)
48 return (((min - 30) / 15) & 0xf) << 8;
49 else
50 return (((min - 30) / 30) & 0xf) << 8;
51}
52
53static int wm8350_get_supplies(struct wm8350 *wm8350)
54{
55 u16 sm, ov, co, chrg;
56 int supplies = 0;
57
58 sm = wm8350_reg_read(wm8350, WM8350_STATE_MACHINE_STATUS);
59 ov = wm8350_reg_read(wm8350, WM8350_MISC_OVERRIDES);
60 co = wm8350_reg_read(wm8350, WM8350_COMPARATOR_OVERRIDES);
61 chrg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
62
63 /* USB_SM */
64 sm = (sm & WM8350_USB_SM_MASK) >> WM8350_USB_SM_SHIFT;
65
66 /* CHG_ISEL */
67 chrg &= WM8350_CHG_ISEL_MASK;
68
69 /* If the USB state machine is active then we're using that with or
70 * without battery, otherwise check for wall supply */
71 if (((sm == WM8350_USB_SM_100_SLV) ||
72 (sm == WM8350_USB_SM_500_SLV) ||
73 (sm == WM8350_USB_SM_STDBY_SLV))
74 && !(ov & WM8350_USB_LIMIT_OVRDE))
75 supplies = WM8350_USB_SUPPLY;
76 else if (((sm == WM8350_USB_SM_100_SLV) ||
77 (sm == WM8350_USB_SM_500_SLV) ||
78 (sm == WM8350_USB_SM_STDBY_SLV))
79 && (ov & WM8350_USB_LIMIT_OVRDE) && (chrg == 0))
80 supplies = WM8350_USB_SUPPLY | WM8350_BATT_SUPPLY;
81 else if (co & WM8350_WALL_FB_OVRDE)
82 supplies = WM8350_LINE_SUPPLY;
83 else
84 supplies = WM8350_BATT_SUPPLY;
85
86 return supplies;
87}
88
89static int wm8350_charger_config(struct wm8350 *wm8350,
90 struct wm8350_charger_policy *policy)
91{
92 u16 reg, eoc_mA, fast_limit_mA;
93
94 if (!policy) {
95 dev_warn(wm8350->dev,
96 "No charger policy, charger not configured.\n");
97 return -EINVAL;
98 }
99
100 /* make sure USB fast charge current is not > 500mA */
101 if (policy->fast_limit_USB_mA > 500) {
102 dev_err(wm8350->dev, "USB fast charge > 500mA\n");
103 return -EINVAL;
104 }
105
106 eoc_mA = WM8350_CHG_EOC_mA(policy->eoc_mA);
107
108 wm8350_reg_unlock(wm8350);
109
110 reg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1)
111 & WM8350_CHG_ENA_R168;
112 wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
113 reg | eoc_mA | policy->trickle_start_mV |
114 WM8350_CHG_TRICKLE_TEMP_CHOKE |
115 WM8350_CHG_TRICKLE_USB_CHOKE |
116 WM8350_CHG_FAST_USB_THROTTLE);
117
118 if (wm8350_get_supplies(wm8350) & WM8350_USB_SUPPLY) {
119 fast_limit_mA =
120 WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_USB_mA);
121 wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
122 policy->charge_mV | policy->trickle_charge_USB_mA |
123 fast_limit_mA | wm8350_charge_time_min(wm8350,
124 policy->charge_timeout));
125
126 } else {
127 fast_limit_mA =
128 WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_mA);
129 wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
130 policy->charge_mV | policy->trickle_charge_mA |
131 fast_limit_mA | wm8350_charge_time_min(wm8350,
132 policy->charge_timeout));
133 }
134
135 wm8350_reg_lock(wm8350);
136 return 0;
137}
138
139static int wm8350_batt_status(struct wm8350 *wm8350)
140{
141 u16 state;
142
143 state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
144 state &= WM8350_CHG_STS_MASK;
145
146 switch (state) {
147 case WM8350_CHG_STS_OFF:
148 return POWER_SUPPLY_STATUS_DISCHARGING;
149
150 case WM8350_CHG_STS_TRICKLE:
151 case WM8350_CHG_STS_FAST:
152 return POWER_SUPPLY_STATUS_CHARGING;
153
154 default:
155 return POWER_SUPPLY_STATUS_UNKNOWN;
156 }
157}
158
159static ssize_t charger_state_show(struct device *dev,
160 struct device_attribute *attr, char *buf)
161{
162 struct wm8350 *wm8350 = dev_get_drvdata(dev);
163 char *charge;
164 int state;
165
166 state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) &
167 WM8350_CHG_STS_MASK;
168 switch (state) {
169 case WM8350_CHG_STS_OFF:
170 charge = "Charger Off";
171 break;
172 case WM8350_CHG_STS_TRICKLE:
173 charge = "Trickle Charging";
174 break;
175 case WM8350_CHG_STS_FAST:
176 charge = "Fast Charging";
177 break;
178 default:
179 return 0;
180 }
181
182 return sprintf(buf, "%s\n", charge);
183}
184
185static DEVICE_ATTR(charger_state, 0444, charger_state_show, NULL);
186
187static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data)
188{
189 struct wm8350_power *power = &wm8350->power;
190 struct wm8350_charger_policy *policy = power->policy;
191
192 switch (irq) {
193 case WM8350_IRQ_CHG_BAT_FAIL:
194 dev_err(wm8350->dev, "battery failed\n");
195 break;
196 case WM8350_IRQ_CHG_TO:
197 dev_err(wm8350->dev, "charger timeout\n");
198 power_supply_changed(&power->battery);
199 break;
200
201 case WM8350_IRQ_CHG_BAT_HOT:
202 case WM8350_IRQ_CHG_BAT_COLD:
203 case WM8350_IRQ_CHG_START:
204 case WM8350_IRQ_CHG_END:
205 power_supply_changed(&power->battery);
206 break;
207
208 case WM8350_IRQ_CHG_FAST_RDY:
209 dev_dbg(wm8350->dev, "fast charger ready\n");
210 wm8350_charger_config(wm8350, policy);
211 wm8350_reg_unlock(wm8350);
212 wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
213 WM8350_CHG_FAST);
214 wm8350_reg_lock(wm8350);
215 break;
216
217 case WM8350_IRQ_CHG_VBATT_LT_3P9:
218 dev_warn(wm8350->dev, "battery < 3.9V\n");
219 break;
220 case WM8350_IRQ_CHG_VBATT_LT_3P1:
221 dev_warn(wm8350->dev, "battery < 3.1V\n");
222 break;
223 case WM8350_IRQ_CHG_VBATT_LT_2P85:
224 dev_warn(wm8350->dev, "battery < 2.85V\n");
225 break;
226
227 /* Supply change. We will overnotify but it should do
228 * no harm. */
229 case WM8350_IRQ_EXT_USB_FB:
230 case WM8350_IRQ_EXT_WALL_FB:
231 wm8350_charger_config(wm8350, policy);
232 case WM8350_IRQ_EXT_BAT_FB: /* Fall through */
233 power_supply_changed(&power->battery);
234 power_supply_changed(&power->usb);
235 power_supply_changed(&power->ac);
236 break;
237
238 default:
239 dev_err(wm8350->dev, "Unknown interrupt %d\n", irq);
240 }
241}
242
243/*********************************************************************
244 * AC Power
245 *********************************************************************/
246static int wm8350_ac_get_prop(struct power_supply *psy,
247 enum power_supply_property psp,
248 union power_supply_propval *val)
249{
250 struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent);
251 int ret = 0;
252
253 switch (psp) {
254 case POWER_SUPPLY_PROP_ONLINE:
255 val->intval = !!(wm8350_get_supplies(wm8350) &
256 WM8350_LINE_SUPPLY);
257 break;
258 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
259 val->intval = wm8350_read_line_uvolts(wm8350);
260 break;
261 default:
262 ret = -EINVAL;
263 break;
264 }
265 return ret;
266}
267
268static enum power_supply_property wm8350_ac_props[] = {
269 POWER_SUPPLY_PROP_ONLINE,
270 POWER_SUPPLY_PROP_VOLTAGE_NOW,
271};
272
273/*********************************************************************
274 * USB Power
275 *********************************************************************/
276static int wm8350_usb_get_prop(struct power_supply *psy,
277 enum power_supply_property psp,
278 union power_supply_propval *val)
279{
280 struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent);
281 int ret = 0;
282
283 switch (psp) {
284 case POWER_SUPPLY_PROP_ONLINE:
285 val->intval = !!(wm8350_get_supplies(wm8350) &
286 WM8350_USB_SUPPLY);
287 break;
288 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
289 val->intval = wm8350_read_usb_uvolts(wm8350);
290 break;
291 default:
292 ret = -EINVAL;
293 break;
294 }
295 return ret;
296}
297
298static enum power_supply_property wm8350_usb_props[] = {
299 POWER_SUPPLY_PROP_ONLINE,
300 POWER_SUPPLY_PROP_VOLTAGE_NOW,
301};
302
303/*********************************************************************
304 * Battery properties
305 *********************************************************************/
306
307static int wm8350_bat_check_health(struct wm8350 *wm8350)
308{
309 u16 reg;
310
311 if (wm8350_read_battery_uvolts(wm8350) < 2850000)
312 return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
313
314 reg = wm8350_reg_read(wm8350, WM8350_CHARGER_OVERRIDES);
315 if (reg & WM8350_CHG_BATT_HOT_OVRDE)
316 return POWER_SUPPLY_HEALTH_OVERHEAT;
317
318 if (reg & WM8350_CHG_BATT_COLD_OVRDE)
319 return POWER_SUPPLY_HEALTH_COLD;
320
321 return POWER_SUPPLY_HEALTH_GOOD;
322}
323
324static int wm8350_bat_get_property(struct power_supply *psy,
325 enum power_supply_property psp,
326 union power_supply_propval *val)
327{
328 struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent);
329 int ret = 0;
330
331 switch (psp) {
332 case POWER_SUPPLY_PROP_STATUS:
333 val->intval = wm8350_batt_status(wm8350);
334 break;
335 case POWER_SUPPLY_PROP_ONLINE:
336 val->intval = !!(wm8350_get_supplies(wm8350) &
337 WM8350_BATT_SUPPLY);
338 break;
339 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
340 val->intval = wm8350_read_battery_uvolts(wm8350);
341 break;
342 case POWER_SUPPLY_PROP_HEALTH:
343 val->intval = wm8350_bat_check_health(wm8350);
344 break;
345 default:
346 ret = -EINVAL;
347 break;
348 }
349
350 return ret;
351}
352
353static enum power_supply_property wm8350_bat_props[] = {
354 POWER_SUPPLY_PROP_STATUS,
355 POWER_SUPPLY_PROP_ONLINE,
356 POWER_SUPPLY_PROP_VOLTAGE_NOW,
357 POWER_SUPPLY_PROP_HEALTH,
358};
359
360/*********************************************************************
361 * Initialisation
362 *********************************************************************/
363
364static void wm8350_init_charger(struct wm8350 *wm8350)
365{
366 /* register our interest in charger events */
367 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT,
368 wm8350_charger_handler, NULL);
369 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
370 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD,
371 wm8350_charger_handler, NULL);
372 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
373 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL,
374 wm8350_charger_handler, NULL);
375 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
376 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO,
377 wm8350_charger_handler, NULL);
378 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_TO);
379 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END,
380 wm8350_charger_handler, NULL);
381 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_END);
382 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START,
383 wm8350_charger_handler, NULL);
384 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_START);
385 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY,
386 wm8350_charger_handler, NULL);
387 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY);
388 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9,
389 wm8350_charger_handler, NULL);
390 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
391 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1,
392 wm8350_charger_handler, NULL);
393 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
394 wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85,
395 wm8350_charger_handler, NULL);
396 wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
397
398 /* and supply change events */
399 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB,
400 wm8350_charger_handler, NULL);
401 wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
402 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB,
403 wm8350_charger_handler, NULL);
404 wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
405 wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB,
406 wm8350_charger_handler, NULL);
407 wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
408}
409
410static void free_charger_irq(struct wm8350 *wm8350)
411{
412 wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
413 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
414 wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
415 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
416 wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
417 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
418 wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_TO);
419 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO);
420 wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_END);
421 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END);
422 wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_START);
423 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START);
424 wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
425 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
426 wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
427 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
428 wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
429 wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
430 wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
431 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
432 wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
433 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
434 wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
435 wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
436}
437
438static __devinit int wm8350_power_probe(struct platform_device *pdev)
439{
440 struct wm8350 *wm8350 = platform_get_drvdata(pdev);
441 struct wm8350_power *power = &wm8350->power;
442 struct wm8350_charger_policy *policy = power->policy;
443 struct power_supply *usb = &power->usb;
444 struct power_supply *battery = &power->battery;
445 struct power_supply *ac = &power->ac;
446 int ret;
447
448 ac->name = "wm8350-ac";
449 ac->type = POWER_SUPPLY_TYPE_MAINS;
450 ac->properties = wm8350_ac_props;
451 ac->num_properties = ARRAY_SIZE(wm8350_ac_props);
452 ac->get_property = wm8350_ac_get_prop;
453 ret = power_supply_register(&pdev->dev, ac);
454 if (ret)
455 return ret;
456
457 battery->name = "wm8350-battery";
458 battery->properties = wm8350_bat_props;
459 battery->num_properties = ARRAY_SIZE(wm8350_bat_props);
460 battery->get_property = wm8350_bat_get_property;
461 battery->use_for_apm = 1;
462 ret = power_supply_register(&pdev->dev, battery);
463 if (ret)
464 goto battery_failed;
465
466 usb->name = "wm8350-usb",
467 usb->type = POWER_SUPPLY_TYPE_USB;
468 usb->properties = wm8350_usb_props;
469 usb->num_properties = ARRAY_SIZE(wm8350_usb_props);
470 usb->get_property = wm8350_usb_get_prop;
471 ret = power_supply_register(&pdev->dev, usb);
472 if (ret)
473 goto usb_failed;
474
475 ret = device_create_file(&pdev->dev, &dev_attr_charger_state);
476 if (ret < 0)
477 dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret);
478 ret = 0;
479
480 wm8350_init_charger(wm8350);
481 if (wm8350_charger_config(wm8350, policy) == 0) {
482 wm8350_reg_unlock(wm8350);
483 wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA);
484 wm8350_reg_lock(wm8350);
485 }
486
487 return ret;
488
489usb_failed:
490 power_supply_unregister(battery);
491battery_failed:
492 power_supply_unregister(ac);
493
494 return ret;
495}
496
497static __devexit int wm8350_power_remove(struct platform_device *pdev)
498{
499 struct wm8350 *wm8350 = platform_get_drvdata(pdev);
500 struct wm8350_power *power = &wm8350->power;
501
502 free_charger_irq(wm8350);
503 device_remove_file(&pdev->dev, &dev_attr_charger_state);
504 power_supply_unregister(&power->battery);
505 power_supply_unregister(&power->ac);
506 power_supply_unregister(&power->usb);
507 return 0;
508}
509
510static struct platform_driver wm8350_power_driver = {
511 .probe = wm8350_power_probe,
512 .remove = __devexit_p(wm8350_power_remove),
513 .driver = {
514 .name = "wm8350-power",
515 },
516};
517
518static int __init wm8350_power_init(void)
519{
520 return platform_driver_register(&wm8350_power_driver);
521}
522module_init(wm8350_power_init);
523
524static void __exit wm8350_power_exit(void)
525{
526 platform_driver_unregister(&wm8350_power_driver);
527}
528module_exit(wm8350_power_exit);
529
530MODULE_LICENSE("GPL");
531MODULE_DESCRIPTION("Power supply driver for WM8350");
532MODULE_ALIAS("platform:wm8350-power");