Commit | Line | Data |
---|---|---|
48a03ae8 PM |
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. | |
3821589c PM |
12 | * |
13 | * Actually, this should be quite safe, it seems sharp leaves charger enabled by default, | |
14 | * and my collie did not explode (yet). | |
48a03ae8 PM |
15 | */ |
16 | ||
17 | #include <linux/module.h> | |
18 | #include <linux/stat.h> | |
19 | #include <linux/init.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <linux/delay.h> | |
22 | #include <linux/interrupt.h> | |
23 | #include <linux/device.h> | |
24 | #include <linux/platform_device.h> | |
25 | ||
26 | #include <asm/irq.h> | |
a09e64fb | 27 | #include <mach/hardware.h> |
48a03ae8 | 28 | #include <asm/hardware/scoop.h> |
dcea83ad | 29 | #include <mach/dma.h> |
a09e64fb | 30 | #include <mach/collie.h> |
48a03ae8 PM |
31 | #include <asm/mach/sharpsl_param.h> |
32 | #include <asm/hardware/sharpsl_pm.h> | |
33 | ||
34 | #include "../drivers/mfd/ucb1x00.h" | |
35 | ||
36 | static struct ucb1x00 *ucb; | |
37 | static int ad_revise; | |
38 | ||
39 | #define ADCtoPower(x) ((330 * x * 2) / 1024) | |
40 | ||
41 | static void collie_charger_init(void) | |
42 | { | |
43 | int err; | |
44 | ||
3821589c | 45 | if (sharpsl_param.adadj != -1) |
48a03ae8 | 46 | ad_revise = sharpsl_param.adadj; |
48a03ae8 PM |
47 | |
48 | /* Register interrupt handler. */ | |
52e405ea | 49 | if ((err = request_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr, IRQF_DISABLED, |
48a03ae8 PM |
50 | "ACIN", sharpsl_ac_isr))) { |
51 | printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_AC_IN); | |
52 | return; | |
53 | } | |
52e405ea | 54 | if ((err = request_irq(COLLIE_IRQ_GPIO_CO, sharpsl_chrg_full_isr, IRQF_DISABLED, |
48a03ae8 PM |
55 | "CO", sharpsl_chrg_full_isr))) { |
56 | free_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr); | |
57 | printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_CO); | |
58 | return; | |
59 | } | |
60 | ||
61 | ucb1x00_io_set_dir(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON | COLLIE_TC35143_GPIO_TMP_ON | | |
62 | COLLIE_TC35143_GPIO_BBAT_ON); | |
63 | return; | |
64 | } | |
65 | ||
66 | static void collie_measure_temp(int on) | |
67 | { | |
68 | if (on) | |
69 | ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0); | |
70 | else | |
71 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON); | |
72 | } | |
73 | ||
74 | static void collie_charge(int on) | |
75 | { | |
3821589c | 76 | extern struct platform_device colliescoop_device; |
48a03ae8 | 77 | |
3821589c | 78 | /* Zaurus seems to contain LTC1731; it should know when to |
48a03ae8 PM |
79 | * stop charging itself, so setting charge on should be |
80 | * relatively harmless (as long as it is not done too often). | |
81 | */ | |
48a03ae8 PM |
82 | if (on) { |
83 | set_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON); | |
84 | } else { | |
85 | reset_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON); | |
86 | } | |
48a03ae8 PM |
87 | } |
88 | ||
89 | static void collie_discharge(int on) | |
90 | { | |
91 | } | |
92 | ||
93 | static void collie_discharge1(int on) | |
94 | { | |
95 | } | |
96 | ||
97 | static void collie_presuspend(void) | |
98 | { | |
99 | } | |
100 | ||
101 | static void collie_postsuspend(void) | |
102 | { | |
103 | } | |
104 | ||
105 | static int collie_should_wakeup(unsigned int resume_on_alarm) | |
106 | { | |
107 | return 0; | |
108 | } | |
109 | ||
110 | static unsigned long collie_charger_wakeup(void) | |
111 | { | |
112 | return 0; | |
113 | } | |
114 | ||
115 | int collie_read_backup_battery(void) | |
116 | { | |
117 | int voltage; | |
118 | ||
119 | ucb1x00_adc_enable(ucb); | |
120 | ||
48a03ae8 PM |
121 | ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_BBAT_ON, 0); |
122 | voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC); | |
123 | ||
124 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON); | |
125 | ucb1x00_adc_disable(ucb); | |
126 | ||
127 | printk("Backup battery = %d(%d)\n", ADCtoPower(voltage), voltage); | |
128 | ||
129 | return ADCtoPower(voltage); | |
130 | } | |
131 | ||
132 | int collie_read_main_battery(void) | |
133 | { | |
134 | int voltage, voltage_rev, voltage_volts; | |
135 | ||
136 | ucb1x00_adc_enable(ucb); | |
137 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON); | |
138 | ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_MBAT_ON, 0); | |
3821589c PM |
139 | |
140 | mdelay(1); | |
48a03ae8 PM |
141 | voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC); |
142 | ||
143 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON); | |
144 | ucb1x00_adc_disable(ucb); | |
145 | ||
146 | voltage_rev = voltage + ((ad_revise * voltage) / 652); | |
147 | voltage_volts = ADCtoPower(voltage_rev); | |
148 | ||
149 | printk("Main battery = %d(%d)\n", voltage_volts, voltage); | |
150 | ||
151 | if (voltage != -1) | |
152 | return voltage_volts; | |
153 | else | |
154 | return voltage; | |
155 | } | |
156 | ||
157 | int collie_read_temp(void) | |
158 | { | |
159 | int voltage; | |
160 | ||
161 | /* According to Sharp, temp must be > 973, main battery must be < 465, | |
162 | FIXME: sharpsl_pm.c has both conditions negated? FIXME: values | |
163 | are way out of range? */ | |
164 | ||
165 | ucb1x00_adc_enable(ucb); | |
166 | ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0); | |
87b9bcd5 | 167 | /* >1010 = battery removed, 460 = 22C ?, higher = lower temp ? */ |
48a03ae8 PM |
168 | voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC); |
169 | ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON); | |
170 | ucb1x00_adc_disable(ucb); | |
171 | ||
172 | printk("Battery temp = %d\n", voltage); | |
173 | return voltage; | |
174 | } | |
175 | ||
176 | static unsigned long read_devdata(int which) | |
177 | { | |
178 | switch (which) { | |
179 | case SHARPSL_BATT_VOLT: | |
180 | return collie_read_main_battery(); | |
181 | case SHARPSL_BATT_TEMP: | |
182 | return collie_read_temp(); | |
183 | case SHARPSL_ACIN_VOLT: | |
3821589c | 184 | return 500; |
48a03ae8 PM |
185 | case SHARPSL_STATUS_ACIN: { |
186 | int ret = GPLR & COLLIE_GPIO_AC_IN; | |
187 | printk("AC status = %d\n", ret); | |
188 | return ret; | |
189 | } | |
190 | case SHARPSL_STATUS_FATAL: { | |
191 | int ret = GPLR & COLLIE_GPIO_MAIN_BAT_LOW; | |
192 | printk("Fatal bat = %d\n", ret); | |
193 | return ret; | |
194 | } | |
195 | default: | |
196 | return ~0; | |
197 | } | |
198 | } | |
199 | ||
3821589c PM |
200 | struct battery_thresh collie_battery_levels_acin[] = { |
201 | { 420, 100}, | |
202 | { 417, 95}, | |
203 | { 415, 90}, | |
204 | { 413, 80}, | |
205 | { 411, 75}, | |
206 | { 408, 70}, | |
207 | { 406, 60}, | |
208 | { 403, 50}, | |
209 | { 398, 40}, | |
210 | { 391, 25}, | |
211 | { 10, 5}, | |
212 | { 0, 0}, | |
213 | }; | |
214 | ||
48a03ae8 | 215 | struct battery_thresh collie_battery_levels[] = { |
3821589c PM |
216 | { 394, 100}, |
217 | { 390, 95}, | |
218 | { 380, 90}, | |
219 | { 370, 80}, | |
220 | { 368, 75}, /* From sharp code: battery high with frontlight */ | |
221 | { 366, 70}, /* 60..90 -- fake values invented by me for testing */ | |
222 | { 364, 60}, | |
223 | { 362, 50}, | |
224 | { 360, 40}, | |
225 | { 358, 25}, /* From sharp code: battery low with frontlight */ | |
226 | { 356, 5}, /* From sharp code: battery verylow with frontlight */ | |
48a03ae8 PM |
227 | { 0, 0}, |
228 | }; | |
229 | ||
230 | struct sharpsl_charger_machinfo collie_pm_machinfo = { | |
231 | .init = collie_charger_init, | |
232 | .read_devdata = read_devdata, | |
233 | .discharge = collie_discharge, | |
234 | .discharge1 = collie_discharge1, | |
235 | .charge = collie_charge, | |
236 | .measure_temp = collie_measure_temp, | |
237 | .presuspend = collie_presuspend, | |
238 | .postsuspend = collie_postsuspend, | |
239 | .charger_wakeup = collie_charger_wakeup, | |
240 | .should_wakeup = collie_should_wakeup, | |
3821589c | 241 | .bat_levels = 12, |
48a03ae8 | 242 | .bat_levels_noac = collie_battery_levels, |
3821589c | 243 | .bat_levels_acin = collie_battery_levels_acin, |
48a03ae8 PM |
244 | .status_high_acin = 368, |
245 | .status_low_acin = 358, | |
246 | .status_high_noac = 368, | |
247 | .status_low_noac = 358, | |
3821589c PM |
248 | .charge_on_volt = 350, /* spitz uses 2.90V, but lets play it safe. */ |
249 | .charge_on_temp = 550, | |
250 | .charge_acin_high = 550, /* collie does not seem to have sensor for this, anyway */ | |
251 | .charge_acin_low = 450, /* ignored, too */ | |
252 | .fatal_acin_volt = 356, | |
253 | .fatal_noacin_volt = 356, | |
254 | ||
255 | .batfull_irq = 1, /* We do not want periodical charge restarts */ | |
48a03ae8 PM |
256 | }; |
257 | ||
258 | static int __init collie_pm_ucb_add(struct ucb1x00_dev *pdev) | |
259 | { | |
260 | sharpsl_pm.machinfo = &collie_pm_machinfo; | |
261 | ucb = pdev->ucb; | |
262 | return 0; | |
263 | } | |
264 | ||
265 | static struct ucb1x00_driver collie_pm_ucb_driver = { | |
93982535 | 266 | .add = collie_pm_ucb_add, |
48a03ae8 PM |
267 | }; |
268 | ||
269 | static struct platform_device *collie_pm_device; | |
270 | ||
271 | static int __init collie_pm_init(void) | |
272 | { | |
93982535 | 273 | int ret; |
48a03ae8 | 274 | |
93982535 KE |
275 | collie_pm_device = platform_device_alloc("sharpsl-pm", -1); |
276 | if (!collie_pm_device) | |
277 | return -ENOMEM; | |
48a03ae8 | 278 | |
93982535 KE |
279 | collie_pm_device->dev.platform_data = &collie_pm_machinfo; |
280 | ret = platform_device_add(collie_pm_device); | |
48a03ae8 | 281 | |
93982535 KE |
282 | if (ret) |
283 | platform_device_put(collie_pm_device); | |
48a03ae8 PM |
284 | |
285 | if (!ret) | |
286 | ret = ucb1x00_register_driver(&collie_pm_ucb_driver); | |
287 | ||
288 | return ret; | |
289 | } | |
290 | ||
291 | static void __exit collie_pm_exit(void) | |
292 | { | |
293 | ucb1x00_unregister_driver(&collie_pm_ucb_driver); | |
93982535 | 294 | platform_device_unregister(collie_pm_device); |
48a03ae8 PM |
295 | } |
296 | ||
297 | module_init(collie_pm_init); | |
298 | module_exit(collie_pm_exit); |