[ar71xx] create firmware image for the Ubiquiti LS-SR71 board
[openwrt/svn-archive/archive.git] / target / linux / s3c24xx / patches-2.6.24 / 1324-gta01-battery-driver.patch.patch
1 From 8aefbe43a7864e611dca9821daec3e10009e7171 Mon Sep 17 00:00:00 2001
2 From: Mike Westerhof <mwester@dls.net>
3 Date: Thu, 13 Nov 2008 20:50:55 +0000
4 Subject: [PATCH] gta01-battery-driver.patch
5
6 Adds a simple pass-through battery driver module for the GTA01.
7 This will simplify user-space by providing the same sysfs API
8 on both GTA01 and GTA02, and is a first step towards eliminating
9 the need for APM emulation.
10
11 Signed-off-by: Mike Westerhof <mwester@dls.net>
12 ---
13 arch/arm/configs/gta02-moredrivers-defconfig | 1 +
14 defconfig-gta01 | 1 +
15 defconfig-gta02 | 1 +
16 drivers/i2c/chips/pcf50606.c | 96 +++++++++++++++++++++++++
17 drivers/power/Kconfig | 6 ++
18 drivers/power/Makefile | 1 +
19 drivers/power/gta01_battery.c | 97 ++++++++++++++++++++++++++
20 7 files changed, 203 insertions(+), 0 deletions(-)
21 create mode 100644 drivers/power/gta01_battery.c
22
23 diff --git a/arch/arm/configs/gta02-moredrivers-defconfig b/arch/arm/configs/gta02-moredrivers-defconfig
24 index 113eaec..5e1547e 100644
25 --- a/arch/arm/configs/gta02-moredrivers-defconfig
26 +++ b/arch/arm/configs/gta02-moredrivers-defconfig
27 @@ -1060,6 +1060,7 @@ CONFIG_POWER_SUPPLY_DEBUG=y
28 CONFIG_PDA_POWER=y
29 CONFIG_APM_POWER=y
30 # CONFIG_BATTERY_DS2760 is not set
31 +# CONFIG_BATTERY_GTA01 is not set
32 CONFIG_BATTERY_BQ27000_HDQ=y
33 CONFIG_GTA02_HDQ=y
34 CONFIG_HWMON=y
35 diff --git a/defconfig-gta01 b/defconfig-gta01
36 index cecb57f..e2e4330 100644
37 --- a/defconfig-gta01
38 +++ b/defconfig-gta01
39 @@ -1021,6 +1021,7 @@ CONFIG_POWER_SUPPLY=y
40 # CONFIG_PDA_POWER is not set
41 # CONFIG_APM_POWER is not set
42 # CONFIG_BATTERY_DS2760 is not set
43 +CONFIG_BATTERY_GTA01=y
44 CONFIG_BATTERY_BQ27000_HDQ=y
45 CONFIG_GTA02_HDQ=y
46 # CONFIG_HWMON is not set
47 diff --git a/defconfig-gta02 b/defconfig-gta02
48 index 619f7f2..2a6e398 100644
49 --- a/defconfig-gta02
50 +++ b/defconfig-gta02
51 @@ -1021,6 +1021,7 @@ CONFIG_POWER_SUPPLY=y
52 # CONFIG_PDA_POWER is not set
53 CONFIG_APM_POWER=y
54 # CONFIG_BATTERY_DS2760 is not set
55 +# CONFIG_BATTERY_GTA01 is not set
56 CONFIG_BATTERY_BQ27000_HDQ=y
57 CONFIG_GTA02_HDQ=y
58 # CONFIG_HWMON is not set
59 diff --git a/drivers/i2c/chips/pcf50606.c b/drivers/i2c/chips/pcf50606.c
60 index 706ce6d..f585013 100644
61 --- a/drivers/i2c/chips/pcf50606.c
62 +++ b/drivers/i2c/chips/pcf50606.c
63 @@ -50,6 +50,7 @@
64 #include <linux/platform_device.h>
65 #include <linux/pcf50606.h>
66 #include <linux/apm-emulation.h>
67 +#include <linux/power_supply.h>
68
69 #include <asm/mach-types.h>
70 #include <asm/arch/gta01.h>
71 @@ -141,6 +142,12 @@ struct pcf50606_data {
72
73 static struct i2c_driver pcf50606_driver;
74
75 +/* This global is set by the pcf50606 driver to the correct callback
76 + * for the gta01 battery driver. */
77 +int (*pmu_bat_get_property)(struct power_supply *, enum power_supply_property,
78 + union power_supply_propval *);
79 +EXPORT_SYMBOL(pmu_bat_get_property);
80 +
81 /* This is an ugly construct on how to access the (currently single/global)
82 * pcf50606 handle from other code in the kernel. I didn't really come up with
83 * a more decent method of dynamically resolving this */
84 @@ -1270,6 +1277,92 @@ static void pcf50606_get_power_status(struct apm_power_info *info)
85 }
86
87 /***********************************************************************
88 + * Battery driver interface
89 + ***********************************************************************/
90 +static int pcf50606_bat_get_property(struct power_supply *psy,
91 + enum power_supply_property psp,
92 + union power_supply_propval *val)
93 +{
94 + u_int16_t adc, adc_adcin1;
95 + u_int8_t mbcc1, chgmod;
96 + struct pcf50606_data *pcf = pcf50606_global;
97 + int ret = 0;
98 +
99 + switch (psp) {
100 +
101 + case POWER_SUPPLY_PROP_STATUS:
102 + if (!(reg_read(pcf, PCF50606_REG_OOCS) & PCF50606_OOCS_EXTON)) {
103 + /* No charger, clearly we're discharging then */
104 + val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
105 + } else {
106 +
107 + /* We have a charger present, get charge mode */
108 + mbcc1 = reg_read(pcf, PCF50606_REG_MBCC1);
109 + chgmod = (mbcc1 & PCF50606_MBCC1_CHGMOD_MASK);
110 + switch (chgmod) {
111 +
112 + /* TODO: How to determine POWER_SUPPLY_STATUS_FULL? */
113 +
114 + case PCF50606_MBCC1_CHGMOD_QUAL:
115 + case PCF50606_MBCC1_CHGMOD_PRE:
116 + case PCF50606_MBCC1_CHGMOD_IDLE:
117 + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
118 + break;
119 +
120 + case PCF50606_MBCC1_CHGMOD_TRICKLE:
121 + case PCF50606_MBCC1_CHGMOD_FAST_CCCV:
122 + case PCF50606_MBCC1_CHGMOD_FAST_NOCC:
123 + case PCF50606_MBCC1_CHGMOD_FAST_NOCV:
124 + case PCF50606_MBCC1_CHGMOD_FAST_SW:
125 + val->intval = POWER_SUPPLY_STATUS_CHARGING;
126 + break;
127 +
128 + default:
129 + val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
130 + break;
131 +
132 + }
133 + }
134 +
135 + case POWER_SUPPLY_PROP_PRESENT:
136 + val->intval = 1; /* Must be, or the magic smoke comes out */
137 + break;
138 +
139 + case POWER_SUPPLY_PROP_ONLINE:
140 + val->intval = !!(reg_read(pcf, PCF50606_REG_OOCS) &
141 + PCF50606_OOCS_EXTON);
142 + break;
143 +
144 + case POWER_SUPPLY_PROP_VOLTAGE_NOW:
145 + adc = adc_read(pcf, PCF50606_ADCMUX_BATVOLT_RES, NULL);
146 + /* (adc * 6000000) / 1024 == (adc * 46875) / 8 */
147 + val->intval = (adc * 46875) / 8;
148 + break;
149 +
150 + case POWER_SUPPLY_PROP_CURRENT_NOW:
151 + adc = adc_read(pcf, PCF50606_ADCMUX_BATVOLT_ADCIN1,
152 + &adc_adcin1);
153 + val->intval = adc_to_chg_milliamps(pcf, adc_adcin1, adc) * 1000;
154 + break;
155 +
156 + case POWER_SUPPLY_PROP_TEMP:
157 + adc = adc_read(pcf, PCF50606_ADCMUX_BATTEMP, NULL);
158 + val->intval = rntc_to_temp(adc_to_rntc(pcf, adc)) * 10;
159 + break;
160 +
161 + case POWER_SUPPLY_PROP_CAPACITY:
162 + val->intval = battvolt_scale(pcf50606_battvolt(pcf));
163 + break;
164 +
165 + default:
166 + ret = -EINVAL;
167 + break;
168 + }
169 +
170 + return ret;
171 +}
172 +
173 +/***********************************************************************
174 * RTC
175 ***********************************************************************/
176
177 @@ -1900,6 +1993,7 @@ static int pcf50606_detect(struct i2c_adapter *adapter, int address, int kind)
178 }
179
180 apm_get_power_status = pcf50606_get_power_status;
181 + pmu_bat_get_property = pcf50606_bat_get_property;
182
183 #ifdef CONFIG_MACH_NEO1973_GTA01
184 if (machine_is_neo1973_gta01()) {
185 @@ -1962,6 +2056,8 @@ static int pcf50606_detach_client(struct i2c_client *client)
186 struct pcf50606_data *pcf = i2c_get_clientdata(client);
187
188 apm_get_power_status = NULL;
189 + pmu_bat_get_property = NULL;
190 +
191 input_unregister_device(pcf->input_dev);
192
193 if (pcf->pdata->used_features & PCF50606_FEAT_PWM_BL)
194 diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
195 index 8c50ecb..470e08c 100644
196 --- a/drivers/power/Kconfig
197 +++ b/drivers/power/Kconfig
198 @@ -62,5 +62,11 @@ config GTA02_HDQ
199 on the Neo Freerunner. You probably want to select
200 at least BATTERY_BQ27000_HDQ as well
201
202 +config BATTERY_GTA01
203 + tristate "Neo GTA01 battery"
204 + depends on MACH_NEO1973_GTA01
205 + help
206 + Say Y to enable support for the battery on the Neo GTA01
207 +
208 endif # POWER_SUPPLY
209
210 diff --git a/drivers/power/Makefile b/drivers/power/Makefile
211 index d7e87ad..2013e89 100644
212 --- a/drivers/power/Makefile
213 +++ b/drivers/power/Makefile
214 @@ -21,5 +21,6 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
215 obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
216 obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
217 obj-$(CONFIG_BATTERY_BQ27000_HDQ) += bq27000_battery.o
218 +obj-$(CONFIG_BATTERY_GTA01) += gta01_battery.o
219
220 obj-$(CONFIG_GTA02_HDQ) += gta02_hdq.o
221 diff --git a/drivers/power/gta01_battery.c b/drivers/power/gta01_battery.c
222 new file mode 100644
223 index 0000000..5acb45c
224 --- /dev/null
225 +++ b/drivers/power/gta01_battery.c
226 @@ -0,0 +1,97 @@
227 +/*
228 + * Battery driver for the Openmoko GTA01 device, using the pcf50606 chip.
229 + *
230 + * This is nothing more than a write-thru interface to the real logic,
231 + * which is part of the pcf50606.c multifunction chip driver.
232 + * Copyright © 2008 Mike Westerhof <mwester@dls.net>
233 + *
234 + *
235 + * Portions liberally borrowed from olpc_battery.c, copyright below:
236 + * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
237 + *
238 + * This program is free software; you can redistribute it and/or modify
239 + * it under the terms of the GNU General Public License version 2 as
240 + * published by the Free Software Foundation.
241 + */
242 +
243 +#include <linux/module.h>
244 +#include <linux/err.h>
245 +#include <linux/platform_device.h>
246 +#include <linux/power_supply.h>
247 +#include <linux/jiffies.h>
248 +#include <linux/sched.h>
249 +
250 +/*********************************************************************
251 + * This global is set by the pcf50606 driver to the correct callback
252 + *********************************************************************/
253 +
254 +extern int (*pmu_bat_get_property)(struct power_supply *,
255 + enum power_supply_property,
256 + union power_supply_propval *);
257 +
258 +
259 +/*********************************************************************
260 + * Battery properties
261 + *********************************************************************/
262 +static int gta01_bat_get_property(struct power_supply *psy,
263 + enum power_supply_property psp,
264 + union power_supply_propval *val)
265 +{
266 + if (pmu_bat_get_property)
267 + return (pmu_bat_get_property)(psy, psp, val);
268 + else
269 + return -ENODEV;
270 +}
271 +
272 +static enum power_supply_property gta01_bat_props[] = {
273 + POWER_SUPPLY_PROP_STATUS,
274 + POWER_SUPPLY_PROP_PRESENT,
275 + POWER_SUPPLY_PROP_ONLINE,
276 + POWER_SUPPLY_PROP_VOLTAGE_NOW,
277 + POWER_SUPPLY_PROP_CURRENT_NOW,
278 + POWER_SUPPLY_PROP_TEMP,
279 + POWER_SUPPLY_PROP_CAPACITY,
280 +};
281 +
282 +/*********************************************************************
283 + * Initialisation
284 + *********************************************************************/
285 +
286 +static struct platform_device *bat_pdev;
287 +
288 +static struct power_supply gta01_bat = {
289 + .properties = gta01_bat_props,
290 + .num_properties = ARRAY_SIZE(gta01_bat_props),
291 + .get_property = gta01_bat_get_property,
292 + .use_for_apm = 0, /* pcf50606 driver has its own apm driver */
293 +};
294 +
295 +static int __init gta01_bat_init(void)
296 +{
297 + int ret;
298 +
299 + bat_pdev = platform_device_register_simple("gta01-battery", 0, NULL, 0);
300 + if (IS_ERR(bat_pdev))
301 + return PTR_ERR(bat_pdev);
302 +
303 + gta01_bat.name = bat_pdev->name;
304 +
305 + ret = power_supply_register(&bat_pdev->dev, &gta01_bat);
306 + if (ret)
307 + platform_device_unregister(bat_pdev);
308 +
309 + return ret;
310 +}
311 +
312 +static void __exit gta01_bat_exit(void)
313 +{
314 + power_supply_unregister(&gta01_bat);
315 + platform_device_unregister(bat_pdev);
316 +}
317 +
318 +module_init(gta01_bat_init);
319 +module_exit(gta01_bat_exit);
320 +
321 +MODULE_AUTHOR("Mike Westerhof <mwester@dls.net>");
322 +MODULE_LICENSE("GPL");
323 +MODULE_DESCRIPTION("Battery driver for GTA01");
324 --
325 1.5.6.5
326