diff options
author | Pavel Machek <pavel@ucw.cz> | 2006-03-25 16:57:57 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-03-25 16:57:57 -0500 |
commit | 48a03ae863e0031def037fc828d7ea1a29b6fb7b (patch) | |
tree | 19fdc75a33256cf4ec1f68b8de6c4e98546d273f | |
parent | 091c539f08a6700e0cca8cd620c3d72dd9f9e2bb (diff) |
[ARM] 3385/1: Battery support for sharp zaurus sl-5500 (collie)
Patch from Pavel Machek
This adds support for battery reading on collie. Collie slowly charges
battery even with charging disabled, so I did not yet enable fast
charge.
Signed-off-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/mach-sa1100/collie_pm.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/arch/arm/mach-sa1100/collie_pm.c b/arch/arm/mach-sa1100/collie_pm.c new file mode 100644 index 000000000000..696d7d29c8a5 --- /dev/null +++ b/arch/arm/mach-sa1100/collie_pm.c | |||
@@ -0,0 +1,278 @@ | |||
1 | /* | ||
2 | * Based on spitz_pm.c and sharp code. | ||
3 | * | ||
4 | * Copyright (C) 2001 SHARP | ||
5 | * Copyright 2005 Pavel Machek <pavel@suse.cz> | ||
6 | * | ||
7 | * Distribute under GPLv2. | ||
8 | * | ||
9 | * Li-ion batteries are angry beasts, and they like to explode. This driver is not finished, | ||
10 | * and sometimes charges them when it should not. If it makes angry lithium to come your way... | ||
11 | * ...well, you have been warned. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/stat.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include <asm/irq.h> | ||
24 | #include <asm/mach-types.h> | ||
25 | #include <asm/hardware.h> | ||
26 | #include <asm/hardware/scoop.h> | ||
27 | #include <asm/dma.h> | ||
28 | #include <asm/arch/collie.h> | ||
29 | #include <asm/mach/sharpsl_param.h> | ||
30 | #include <asm/hardware/sharpsl_pm.h> | ||
31 | |||
32 | #include "../drivers/mfd/ucb1x00.h" | ||
33 | |||
34 | static struct ucb1x00 *ucb; | ||
35 | static int ad_revise; | ||
36 | |||
37 | #define ADCtoPower(x) ((330 * x * 2) / 1024) | ||
38 | |||
39 | static void collie_charger_init(void) | ||
40 | { | ||
41 | int err; | ||
42 | |||
43 | if (sharpsl_param.adadj != -1) { | ||
44 | ad_revise = sharpsl_param.adadj; | ||
45 | } | ||
46 | |||
47 | /* Register interrupt handler. */ | ||
48 | if ((err = request_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr, SA_INTERRUPT, | ||
49 | "ACIN", sharpsl_ac_isr))) { | ||
50 | printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_AC_IN); | ||
51 | return; | ||
52 | } | ||
53 | if ((err = request_irq(COLLIE_IRQ_GPIO_CO, sharpsl_chrg_full_isr, SA_INTERRUPT, | ||
54 | "CO", sharpsl_chrg_full_isr))) { | ||
55 | free_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr); | ||
56 | printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_CO); | ||
57 | return; | ||
58 | } | ||
59 | |||
60 | ucb1x00_io_set_dir(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON | COLLIE_TC35143_GPIO_TMP_ON | | ||
61 | COLLIE_TC35143_GPIO_BBAT_ON); | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | static void collie_measure_temp(int on) | ||
66 | { | ||
67 | if (on) | ||
68 | ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0); | ||
69 | else | ||
70 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON); | ||
71 | } | ||
72 | |||
73 | static void collie_charge(int on) | ||
74 | { | ||
75 | if (on) { | ||
76 | printk("Should start charger\n"); | ||
77 | } else { | ||
78 | printk("Should stop charger\n"); | ||
79 | } | ||
80 | #ifdef I_AM_SURE | ||
81 | |||
82 | /* Zaurus seems to contain LTC1731 ; it should know when to | ||
83 | * stop charging itself, so setting charge on should be | ||
84 | * relatively harmless (as long as it is not done too often). | ||
85 | */ | ||
86 | #define CF_BUF_CTRL_BASE 0xF0800000 | ||
87 | #define SCOOP_REG(adr) (*(volatile unsigned short*)(CF_BUF_CTRL_BASE+(adr))) | ||
88 | #define SCOOP_REG_GPWR SCOOP_REG(SCOOP_GPWR) | ||
89 | |||
90 | if (on) { | ||
91 | set_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON); | ||
92 | } else { | ||
93 | reset_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON); | ||
94 | } | ||
95 | #endif | ||
96 | } | ||
97 | |||
98 | static void collie_discharge(int on) | ||
99 | { | ||
100 | } | ||
101 | |||
102 | static void collie_discharge1(int on) | ||
103 | { | ||
104 | } | ||
105 | |||
106 | static void collie_presuspend(void) | ||
107 | { | ||
108 | } | ||
109 | |||
110 | static void collie_postsuspend(void) | ||
111 | { | ||
112 | } | ||
113 | |||
114 | static int collie_should_wakeup(unsigned int resume_on_alarm) | ||
115 | { | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static unsigned long collie_charger_wakeup(void) | ||
120 | { | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | int collie_read_backup_battery(void) | ||
125 | { | ||
126 | int voltage; | ||
127 | |||
128 | ucb1x00_adc_enable(ucb); | ||
129 | |||
130 | /* Gives 75..130 */ | ||
131 | ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_BBAT_ON, 0); | ||
132 | voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC); | ||
133 | |||
134 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON); | ||
135 | ucb1x00_adc_disable(ucb); | ||
136 | |||
137 | printk("Backup battery = %d(%d)\n", ADCtoPower(voltage), voltage); | ||
138 | |||
139 | return ADCtoPower(voltage); | ||
140 | } | ||
141 | |||
142 | int collie_read_main_battery(void) | ||
143 | { | ||
144 | int voltage, voltage_rev, voltage_volts; | ||
145 | |||
146 | ucb1x00_adc_enable(ucb); | ||
147 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON); | ||
148 | ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_MBAT_ON, 0); | ||
149 | /* gives values 160..255 with battery removed... and | ||
150 | 145..255 with battery inserted. (on AC), goes as low as | ||
151 | 80 on DC. */ | ||
152 | voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC); | ||
153 | |||
154 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON); | ||
155 | ucb1x00_adc_disable(ucb); | ||
156 | |||
157 | voltage_rev = voltage + ((ad_revise * voltage) / 652); | ||
158 | voltage_volts = ADCtoPower(voltage_rev); | ||
159 | |||
160 | printk("Main battery = %d(%d)\n", voltage_volts, voltage); | ||
161 | |||
162 | if (voltage != -1) | ||
163 | return voltage_volts; | ||
164 | else | ||
165 | return voltage; | ||
166 | } | ||
167 | |||
168 | int collie_read_temp(void) | ||
169 | { | ||
170 | int voltage; | ||
171 | |||
172 | /* According to Sharp, temp must be > 973, main battery must be < 465, | ||
173 | FIXME: sharpsl_pm.c has both conditions negated? FIXME: values | ||
174 | are way out of range? */ | ||
175 | |||
176 | ucb1x00_adc_enable(ucb); | ||
177 | ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0); | ||
178 | /* >1010 = battery removed, 460 = 22C ?, higer = lower temp ? */ | ||
179 | voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC); | ||
180 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON); | ||
181 | ucb1x00_adc_disable(ucb); | ||
182 | |||
183 | printk("Battery temp = %d\n", voltage); | ||
184 | return voltage; | ||
185 | } | ||
186 | |||
187 | static unsigned long read_devdata(int which) | ||
188 | { | ||
189 | switch (which) { | ||
190 | case SHARPSL_BATT_VOLT: | ||
191 | return collie_read_main_battery(); | ||
192 | case SHARPSL_BATT_TEMP: | ||
193 | return collie_read_temp(); | ||
194 | case SHARPSL_ACIN_VOLT: | ||
195 | return 0x1; | ||
196 | case SHARPSL_STATUS_ACIN: { | ||
197 | int ret = GPLR & COLLIE_GPIO_AC_IN; | ||
198 | printk("AC status = %d\n", ret); | ||
199 | return ret; | ||
200 | } | ||
201 | case SHARPSL_STATUS_FATAL: { | ||
202 | int ret = GPLR & COLLIE_GPIO_MAIN_BAT_LOW; | ||
203 | printk("Fatal bat = %d\n", ret); | ||
204 | return ret; | ||
205 | } | ||
206 | default: | ||
207 | return ~0; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | struct battery_thresh collie_battery_levels[] = { | ||
212 | { 368, 100}, | ||
213 | { 358, 25}, | ||
214 | { 356, 5}, | ||
215 | { 0, 0}, | ||
216 | }; | ||
217 | |||
218 | struct sharpsl_charger_machinfo collie_pm_machinfo = { | ||
219 | .init = collie_charger_init, | ||
220 | .read_devdata = read_devdata, | ||
221 | .discharge = collie_discharge, | ||
222 | .discharge1 = collie_discharge1, | ||
223 | .charge = collie_charge, | ||
224 | .measure_temp = collie_measure_temp, | ||
225 | .presuspend = collie_presuspend, | ||
226 | .postsuspend = collie_postsuspend, | ||
227 | .charger_wakeup = collie_charger_wakeup, | ||
228 | .should_wakeup = collie_should_wakeup, | ||
229 | .bat_levels = 3, | ||
230 | .bat_levels_noac = collie_battery_levels, | ||
231 | .bat_levels_acin = collie_battery_levels, | ||
232 | .status_high_acin = 368, | ||
233 | .status_low_acin = 358, | ||
234 | .status_high_noac = 368, | ||
235 | .status_low_noac = 358, | ||
236 | }; | ||
237 | |||
238 | static int __init collie_pm_ucb_add(struct ucb1x00_dev *pdev) | ||
239 | { | ||
240 | sharpsl_pm.machinfo = &collie_pm_machinfo; | ||
241 | ucb = pdev->ucb; | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static struct ucb1x00_driver collie_pm_ucb_driver = { | ||
246 | .add = collie_pm_ucb_add, | ||
247 | }; | ||
248 | |||
249 | static struct platform_device *collie_pm_device; | ||
250 | |||
251 | static int __init collie_pm_init(void) | ||
252 | { | ||
253 | int ret; | ||
254 | |||
255 | collie_pm_device = platform_device_alloc("sharpsl-pm", -1); | ||
256 | if (!collie_pm_device) | ||
257 | return -ENOMEM; | ||
258 | |||
259 | collie_pm_device->dev.platform_data = &collie_pm_machinfo; | ||
260 | ret = platform_device_add(collie_pm_device); | ||
261 | |||
262 | if (ret) | ||
263 | platform_device_put(collie_pm_device); | ||
264 | |||
265 | if (!ret) | ||
266 | ret = ucb1x00_register_driver(&collie_pm_ucb_driver); | ||
267 | |||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | static void __exit collie_pm_exit(void) | ||
272 | { | ||
273 | ucb1x00_unregister_driver(&collie_pm_ucb_driver); | ||
274 | platform_device_unregister(collie_pm_device); | ||
275 | } | ||
276 | |||
277 | module_init(collie_pm_init); | ||
278 | module_exit(collie_pm_exit); | ||