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
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.
11 Signed-off-by: Mike Westerhof <mwester@dls.net>
13 arch/arm/configs/gta02-moredrivers-defconfig | 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
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
30 # CONFIG_BATTERY_DS2760 is not set
31 +# CONFIG_BATTERY_GTA01 is not set
32 CONFIG_BATTERY_BQ27000_HDQ=y
35 diff --git a/defconfig-gta01 b/defconfig-gta01
36 index cecb57f..e2e4330 100644
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
46 # CONFIG_HWMON is not set
47 diff --git a/defconfig-gta02 b/defconfig-gta02
48 index 619f7f2..2a6e398 100644
51 @@ -1021,6 +1021,7 @@ CONFIG_POWER_SUPPLY=y
52 # CONFIG_PDA_POWER is not set
54 # CONFIG_BATTERY_DS2760 is not set
55 +# CONFIG_BATTERY_GTA01 is not set
56 CONFIG_BATTERY_BQ27000_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
64 #include <linux/platform_device.h>
65 #include <linux/pcf50606.h>
66 #include <linux/apm-emulation.h>
67 +#include <linux/power_supply.h>
69 #include <asm/mach-types.h>
70 #include <asm/arch/gta01.h>
71 @@ -141,6 +142,12 @@ struct pcf50606_data {
73 static struct i2c_driver pcf50606_driver;
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);
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)
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)
94 + u_int16_t adc, adc_adcin1;
95 + u_int8_t mbcc1, chgmod;
96 + struct pcf50606_data *pcf = pcf50606_global;
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;
107 + /* We have a charger present, get charge mode */
108 + mbcc1 = reg_read(pcf, PCF50606_REG_MBCC1);
109 + chgmod = (mbcc1 & PCF50606_MBCC1_CHGMOD_MASK);
112 + /* TODO: How to determine POWER_SUPPLY_STATUS_FULL? */
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;
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;
129 + val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
135 + case POWER_SUPPLY_PROP_PRESENT:
136 + val->intval = 1; /* Must be, or the magic smoke comes out */
139 + case POWER_SUPPLY_PROP_ONLINE:
140 + val->intval = !!(reg_read(pcf, PCF50606_REG_OOCS) &
141 + PCF50606_OOCS_EXTON);
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;
150 + case POWER_SUPPLY_PROP_CURRENT_NOW:
151 + adc = adc_read(pcf, PCF50606_ADCMUX_BATVOLT_ADCIN1,
153 + val->intval = adc_to_chg_milliamps(pcf, adc_adcin1, adc) * 1000;
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;
161 + case POWER_SUPPLY_PROP_CAPACITY:
162 + val->intval = battvolt_scale(pcf50606_battvolt(pcf));
173 +/***********************************************************************
175 ***********************************************************************/
177 @@ -1900,6 +1993,7 @@ static int pcf50606_detect(struct i2c_adapter *adapter, int address, int kind)
180 apm_get_power_status = pcf50606_get_power_status;
181 + pmu_bat_get_property = pcf50606_bat_get_property;
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);
188 apm_get_power_status = NULL;
189 + pmu_bat_get_property = NULL;
191 input_unregister_device(pcf->input_dev);
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
202 +config BATTERY_GTA01
203 + tristate "Neo GTA01 battery"
204 + depends on MACH_NEO1973_GTA01
206 + Say Y to enable support for the battery on the Neo GTA01
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
220 obj-$(CONFIG_GTA02_HDQ) += gta02_hdq.o
221 diff --git a/drivers/power/gta01_battery.c b/drivers/power/gta01_battery.c
223 index 0000000..5acb45c
225 +++ b/drivers/power/gta01_battery.c
228 + * Battery driver for the Openmoko GTA01 device, using the pcf50606 chip.
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>
235 + * Portions liberally borrowed from olpc_battery.c, copyright below:
236 + * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
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.
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>
250 +/*********************************************************************
251 + * This global is set by the pcf50606 driver to the correct callback
252 + *********************************************************************/
254 +extern int (*pmu_bat_get_property)(struct power_supply *,
255 + enum power_supply_property,
256 + union power_supply_propval *);
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)
266 + if (pmu_bat_get_property)
267 + return (pmu_bat_get_property)(psy, psp, val);
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,
282 +/*********************************************************************
284 + *********************************************************************/
286 +static struct platform_device *bat_pdev;
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 */
295 +static int __init gta01_bat_init(void)
299 + bat_pdev = platform_device_register_simple("gta01-battery", 0, NULL, 0);
300 + if (IS_ERR(bat_pdev))
301 + return PTR_ERR(bat_pdev);
303 + gta01_bat.name = bat_pdev->name;
305 + ret = power_supply_register(&bat_pdev->dev, >a01_bat);
307 + platform_device_unregister(bat_pdev);
312 +static void __exit gta01_bat_exit(void)
314 + power_supply_unregister(>a01_bat);
315 + platform_device_unregister(bat_pdev);
318 +module_init(gta01_bat_init);
319 +module_exit(gta01_bat_exit);
321 +MODULE_AUTHOR("Mike Westerhof <mwester@dls.net>");
322 +MODULE_LICENSE("GPL");
323 +MODULE_DESCRIPTION("Battery driver for GTA01");