Merge branch 'x86/auditsc' of git://git.kernel.org/pub/scm/linux/kernel/git/frob...
[linux-2.6] / drivers / power / palmtx_battery.c
1 /*
2  * linux/drivers/power/palmtx_battery.c
3  *
4  * Battery measurement code for Palm T|X Handheld computer
5  *
6  * based on tosa_battery.c
7  *
8  * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com>
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/kernel.h>
16 #include <linux/module.h>
17 #include <linux/power_supply.h>
18 #include <linux/wm97xx.h>
19 #include <linux/delay.h>
20 #include <linux/spinlock.h>
21 #include <linux/interrupt.h>
22 #include <linux/gpio.h>
23
24 #include <asm/mach-types.h>
25 #include <asm/arch/palmtx.h>
26
27 static DEFINE_MUTEX(bat_lock);
28 static struct work_struct bat_work;
29 struct mutex work_lock;
30 int bat_status = POWER_SUPPLY_STATUS_DISCHARGING;
31
32 static unsigned long palmtx_read_bat(struct power_supply *bat_ps)
33 {
34         return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
35                                     WM97XX_AUX_ID3) * 1000 / 414;
36 }
37
38 static unsigned long palmtx_read_temp(struct power_supply *bat_ps)
39 {
40         return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data,
41                                     WM97XX_AUX_ID2);
42 }
43
44 static int palmtx_bat_get_property(struct power_supply *bat_ps,
45                             enum power_supply_property psp,
46                             union power_supply_propval *val)
47 {
48         switch (psp) {
49         case POWER_SUPPLY_PROP_STATUS:
50                 val->intval = bat_status;
51                 break;
52         case POWER_SUPPLY_PROP_TECHNOLOGY:
53                 val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
54                 break;
55         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
56                 val->intval = palmtx_read_bat(bat_ps);
57                 break;
58         case POWER_SUPPLY_PROP_VOLTAGE_MAX:
59         case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
60                 val->intval = PALMTX_BAT_MAX_VOLTAGE;
61                 break;
62         case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
63                 val->intval = PALMTX_BAT_MIN_VOLTAGE;
64                 break;
65         case POWER_SUPPLY_PROP_TEMP:
66                 val->intval = palmtx_read_temp(bat_ps);
67                 break;
68         case POWER_SUPPLY_PROP_PRESENT:
69                 val->intval = 1;
70                 break;
71         default:
72                 return -EINVAL;
73         }
74         return 0;
75 }
76
77 static void palmtx_bat_external_power_changed(struct power_supply *bat_ps)
78 {
79         schedule_work(&bat_work);
80 }
81
82 static char *status_text[] = {
83         [POWER_SUPPLY_STATUS_UNKNOWN] =         "Unknown",
84         [POWER_SUPPLY_STATUS_CHARGING] =        "Charging",
85         [POWER_SUPPLY_STATUS_DISCHARGING] =     "Discharging",
86 };
87
88 static void palmtx_bat_update(struct power_supply *bat_ps)
89 {
90         int old_status = bat_status;
91
92         mutex_lock(&work_lock);
93
94         bat_status = gpio_get_value(GPIO_NR_PALMTX_POWER_DETECT) ?
95                                     POWER_SUPPLY_STATUS_CHARGING :
96                                     POWER_SUPPLY_STATUS_DISCHARGING;
97
98         if (old_status != bat_status) {
99                 pr_debug("%s %s -> %s\n", bat_ps->name,
100                                 status_text[old_status],
101                                 status_text[bat_status]);
102                 power_supply_changed(bat_ps);
103         }
104
105         mutex_unlock(&work_lock);
106 }
107
108 static enum power_supply_property palmtx_bat_main_props[] = {
109         POWER_SUPPLY_PROP_STATUS,
110         POWER_SUPPLY_PROP_TECHNOLOGY,
111         POWER_SUPPLY_PROP_VOLTAGE_NOW,
112         POWER_SUPPLY_PROP_VOLTAGE_MAX,
113         POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
114         POWER_SUPPLY_PROP_TEMP,
115         POWER_SUPPLY_PROP_PRESENT,
116 };
117
118 struct power_supply bat_ps = {
119         .name                   = "main-battery",
120         .type                   = POWER_SUPPLY_TYPE_BATTERY,
121         .properties             = palmtx_bat_main_props,
122         .num_properties         = ARRAY_SIZE(palmtx_bat_main_props),
123         .get_property           = palmtx_bat_get_property,
124         .external_power_changed = palmtx_bat_external_power_changed,
125         .use_for_apm            = 1,
126 };
127
128 static void palmtx_bat_work(struct work_struct *work)
129 {
130         palmtx_bat_update(&bat_ps);
131 }
132
133 #ifdef CONFIG_PM
134 static int palmtx_bat_suspend(struct platform_device *dev, pm_message_t state)
135 {
136         flush_scheduled_work();
137         return 0;
138 }
139
140 static int palmtx_bat_resume(struct platform_device *dev)
141 {
142         schedule_work(&bat_work);
143         return 0;
144 }
145 #else
146 #define palmtx_bat_suspend NULL
147 #define palmtx_bat_resume NULL
148 #endif
149
150 static int __devinit palmtx_bat_probe(struct platform_device *dev)
151 {
152         int ret = 0;
153
154         if (!machine_is_palmtx())
155                 return -ENODEV;
156
157         mutex_init(&work_lock);
158
159         INIT_WORK(&bat_work, palmtx_bat_work);
160
161         ret = power_supply_register(&dev->dev, &bat_ps);
162         if (!ret)
163                 schedule_work(&bat_work);
164
165         return ret;
166 }
167
168 static int __devexit palmtx_bat_remove(struct platform_device *dev)
169 {
170         power_supply_unregister(&bat_ps);
171         return 0;
172 }
173
174 static struct platform_driver palmtx_bat_driver = {
175         .driver.name    = "wm97xx-battery",
176         .driver.owner   = THIS_MODULE,
177         .probe          = palmtx_bat_probe,
178         .remove         = __devexit_p(palmtx_bat_remove),
179         .suspend        = palmtx_bat_suspend,
180         .resume         = palmtx_bat_resume,
181 };
182
183 static int __init palmtx_bat_init(void)
184 {
185         return platform_driver_register(&palmtx_bat_driver);
186 }
187
188 static void __exit palmtx_bat_exit(void)
189 {
190         platform_driver_unregister(&palmtx_bat_driver);
191 }
192
193 module_init(palmtx_bat_init);
194 module_exit(palmtx_bat_exit);
195
196 MODULE_LICENSE("GPL");
197 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
198 MODULE_DESCRIPTION("Palm T|X battery driver");