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