scoop.c revision 1.5 1 /* $NetBSD: scoop.c,v 1.5 2008/06/13 13:58:21 cegger Exp $ */
2 /* $OpenBSD: zaurus_scoop.c,v 1.12 2005/11/17 05:26:31 uwe Exp $ */
3
4 /*
5 * Copyright (c) 2005 Uwe Stuehler <uwe (at) bsdx.de>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: scoop.c,v 1.5 2008/06/13 13:58:21 cegger Exp $");
22
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/conf.h>
27 #include <sys/gpio.h>
28
29 #include <machine/bus.h>
30
31 #include <arm/xscale/pxa2x0var.h>
32
33 #include <zaurus/zaurus/zaurus_reg.h>
34 #include <zaurus/zaurus/zaurus_var.h>
35
36 #include <zaurus/dev/scoopreg.h>
37 #include <zaurus/dev/scoopvar.h>
38
39 #include "ioconf.h"
40
41 struct scoop_softc {
42 struct device sc_dev;
43
44 bus_space_tag_t sc_iot;
45 bus_space_handle_t sc_ioh;
46
47 uint16_t sc_gpwr; /* GPIO state before suspend */
48 };
49
50 static int scoopmatch(struct device *, struct cfdata *, void *);
51 static void scoopattach(struct device *, struct device *, void *);
52
53 CFATTACH_DECL(scoop, sizeof(struct scoop_softc),
54 scoopmatch, scoopattach, NULL, NULL);
55
56 #if 0
57 static int scoop_gpio_pin_read(struct scoop_softc *sc, int);
58 #endif
59 static void scoop_gpio_pin_write(struct scoop_softc *sc, int, int);
60 static void scoop_gpio_pin_ctl(struct scoop_softc *sc, int, int);
61
62 enum scoop_card {
63 SD_CARD,
64 CF_CARD /* socket 0 (external) */
65 };
66
67 static void scoop0_set_card_power(enum scoop_card card, int new_cpr);
68
69 static int
70 scoopmatch(struct device *parent, struct cfdata *cf, void *aux)
71 {
72
73 /*
74 * Only C3000-like models are known to have two SCOOPs.
75 */
76 if (ZAURUS_ISC3000)
77 return (cf->cf_unit < 2);
78 return (cf->cf_unit == 0);
79 }
80
81 static void
82 scoopattach(struct device *parent, struct device *self, void *aux)
83 {
84 struct pxaip_attach_args *pxa = (struct pxaip_attach_args *)aux;
85 struct scoop_softc *sc = (struct scoop_softc *)self;
86 bus_addr_t addr;
87 bus_size_t size;
88
89 sc->sc_iot = pxa->pxa_iot;
90
91 if (pxa->pxa_addr != -1)
92 addr = pxa->pxa_addr;
93 else if (sc->sc_dev.dv_unit == 0)
94 addr = C3000_SCOOP0_BASE;
95 else
96 addr = C3000_SCOOP1_BASE;
97
98 size = pxa->pxa_size < SCOOP_SIZE ? SCOOP_SIZE : pxa->pxa_size;
99
100 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
101 printf(": failed to map %s\n", sc->sc_dev.dv_xname);
102 return;
103 }
104
105 if (ZAURUS_ISC3000 && sc->sc_dev.dv_unit == 1) {
106 scoop_gpio_pin_ctl(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_OUTPUT);
107 scoop_gpio_pin_write(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_LOW);
108 } else if (!ZAURUS_ISC3000) {
109 scoop_gpio_pin_ctl(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_OUTPUT);
110 scoop_gpio_pin_write(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_LOW);
111 }
112
113 printf(": PCMCIA/GPIO controller\n");
114 }
115
116 #if 0
117 static int
118 scoop_gpio_pin_read(struct scoop_softc *sc, int pin)
119 {
120 uint16_t bit = (1 << pin);
121 uint16_t rv;
122
123 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR);
124 return (rv & bit) ? 1 : 0;
125 }
126 #endif
127
128 static void
129 scoop_gpio_pin_write(struct scoop_softc *sc, int pin, int level)
130 {
131 uint16_t bit = (1 << pin);
132 uint16_t rv;
133
134 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR);
135 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
136 (level == GPIO_PIN_LOW) ? (rv & ~bit) : (rv | bit));
137 }
138
139 static void
140 scoop_gpio_pin_ctl(struct scoop_softc *sc, int pin, int flags)
141 {
142 uint16_t bit = (1 << pin);
143 uint16_t rv;
144
145 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR);
146 switch (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
147 case GPIO_PIN_INPUT:
148 rv &= ~bit;
149 break;
150 case GPIO_PIN_OUTPUT:
151 rv |= bit;
152 break;
153 }
154 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR, rv);
155 }
156
157 /*
158 * Turn the LCD background light and contrast signal on or off.
159 */
160 void
161 scoop_set_backlight(int on, int cont)
162 {
163 struct scoop_softc *sc;
164 #if 0
165 struct scoop_softc *sc0;
166
167 sc0 = device_lookup_private(&scoop_cd, 0);
168 #endif
169
170 sc = device_lookup_private(&scoop_cd, 1);
171 if (sc != NULL) {
172 /* C3000 */
173 scoop_gpio_pin_write(sc,
174 SCOOP1_BACKLIGHT_CONT, !cont);
175 scoop_gpio_pin_write(sc,
176 SCOOP1_BACKLIGHT_ON, on);
177 }
178 #if 0
179 else if (sc0 != NULL) {
180 scoop_gpio_pin_write(sc0,
181 SCOOP0_BACKLIGHT_CONT, cont);
182 }
183 #endif
184 }
185
186 /*
187 * Turn the infrared LED on or off (must be on while transmitting).
188 */
189 void
190 scoop_set_irled(int on)
191 {
192 struct scoop_softc *sc;
193
194 sc = device_lookup_private(&scoop_cd, 1);
195 if (sc != NULL) {
196 /* IR_ON is inverted */
197 scoop_gpio_pin_write(sc,
198 SCOOP1_IR_ON, !on);
199 }
200 }
201
202 /*
203 * Turn the green and orange LEDs on or off. If the orange LED is on,
204 * then it is wired to indicate if A/C is connected. The green LED has
205 * no such predefined function.
206 */
207 void
208 scoop_led_set(int led, int on)
209 {
210 struct scoop_softc *sc;
211
212 sc = device_lookup_private(&scoop_cd, 0);
213 if (sc != NULL) {
214 if ((led & SCOOP_LED_GREEN) != 0) {
215 scoop_gpio_pin_write(sc,
216 SCOOP0_LED_GREEN, on);
217 }
218 if (scoop_cd.cd_ndevs > 1 && (led & SCOOP_LED_ORANGE) != 0) {
219 scoop_gpio_pin_write(sc,
220 SCOOP0_LED_ORANGE_C3000, on);
221 }
222 }
223 }
224
225 /*
226 * Enable or disable the headphone output connection.
227 */
228 void
229 scoop_set_headphone(int on)
230 {
231 struct scoop_softc *sc;
232
233 sc = device_lookup_private(&scoop_cd, 0);
234 if (sc == NULL)
235 return;
236
237 scoop_gpio_pin_ctl(sc, SCOOP0_MUTE_L,
238 GPIO_PIN_OUTPUT);
239 scoop_gpio_pin_ctl(sc, SCOOP0_MUTE_R,
240 GPIO_PIN_OUTPUT);
241
242 if (on) {
243 scoop_gpio_pin_write(sc, SCOOP0_MUTE_L,
244 GPIO_PIN_HIGH);
245 scoop_gpio_pin_write(sc, SCOOP0_MUTE_R,
246 GPIO_PIN_HIGH);
247 } else {
248 scoop_gpio_pin_write(sc, SCOOP0_MUTE_L,
249 GPIO_PIN_LOW);
250 scoop_gpio_pin_write(sc, SCOOP0_MUTE_R,
251 GPIO_PIN_LOW);
252 }
253 }
254
255 /*
256 * Turn on pullup resistor while not reading the remote control.
257 */
258 void
259 scoop_akin_pullup(int enable)
260 {
261 struct scoop_softc *sc0;
262 struct scoop_softc *sc1;
263
264 sc0 = device_lookup_private(&scoop_cd, 0);
265 sc1 = device_lookup_private(&scoop_cd, 1);
266
267 if (sc1 != NULL) {
268 scoop_gpio_pin_write(sc1,
269 SCOOP1_AKIN_PULLUP, enable);
270 } else if (sc0 != NULL) {
271 scoop_gpio_pin_write(sc0,
272 SCOOP0_AKIN_PULLUP, enable);
273 }
274 }
275
276 void
277 scoop_battery_temp_adc(int enable)
278 {
279 struct scoop_softc *sc;
280
281 sc = device_lookup_private(&scoop_cd, 0);
282
283 if (sc != NULL) {
284 scoop_gpio_pin_write(sc,
285 SCOOP0_ADC_TEMP_ON_C3000, enable);
286 }
287 }
288
289 void
290 scoop_charge_battery(int enable, int voltage_high)
291 {
292 struct scoop_softc *sc;
293
294 sc = device_lookup_private(&scoop_cd, 0);
295
296 if (sc != NULL) {
297 scoop_gpio_pin_write(sc,
298 SCOOP0_JK_B_C3000, voltage_high);
299 scoop_gpio_pin_write(sc,
300 SCOOP0_CHARGE_OFF_C3000, !enable);
301 }
302 }
303
304 void
305 scoop_discharge_battery(int enable)
306 {
307 struct scoop_softc *sc;
308
309 sc = device_lookup_private(&scoop_cd, 0);
310
311 if (sc != NULL) {
312 scoop_gpio_pin_write(sc,
313 SCOOP0_JK_A_C3000, enable);
314 }
315 }
316
317 /*
318 * Enable or disable 3.3V power to the SD/MMC card slot.
319 */
320 void
321 scoop_set_sdmmc_power(int on)
322 {
323
324 scoop0_set_card_power(SD_CARD, on ? SCP_CPR_SD_3V : SCP_CPR_OFF);
325 }
326
327 /*
328 * The Card Power Register of the first SCOOP unit controls the power
329 * for the first CompactFlash slot and the SD/MMC card slot as well.
330 */
331 void
332 scoop0_set_card_power(enum scoop_card card, int new_cpr)
333 {
334 struct scoop_softc *sc;
335 bus_space_tag_t iot;
336 bus_space_handle_t ioh;
337 uint16_t cpr;
338
339 sc = device_lookup_private(&scoop_cd, 0);
340 if (sc == NULL)
341 return;
342
343 iot = sc->sc_iot;
344 ioh = sc->sc_ioh;
345
346 cpr = bus_space_read_2(iot, ioh, SCOOP_CPR);
347 if (new_cpr & SCP_CPR_VOLTAGE_MSK) {
348 if (card == CF_CARD)
349 cpr |= SCP_CPR_5V;
350 else if (card == SD_CARD)
351 cpr |= SCP_CPR_SD_3V;
352
353 scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 1);
354 if (!ISSET(cpr, SCP_CPR_5V) && !ISSET(cpr, SCP_CPR_SD_3V))
355 delay(5000);
356 bus_space_write_2(iot, ioh, SCOOP_CPR, cpr | new_cpr);
357 } else {
358 if (card == CF_CARD)
359 cpr &= ~SCP_CPR_5V;
360 else if (card == SD_CARD)
361 cpr &= ~SCP_CPR_SD_3V;
362
363 if (!ISSET(cpr, SCP_CPR_5V) && !ISSET(cpr, SCP_CPR_SD_3V)) {
364 bus_space_write_2(iot, ioh, SCOOP_CPR, SCP_CPR_OFF);
365 delay(1000);
366 scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 0);
367 } else
368 bus_space_write_2(iot, ioh, SCOOP_CPR, cpr | new_cpr);
369 }
370 }
371
372 void
373 scoop_check_mcr(void)
374 {
375 struct scoop_softc *sc0, *sc1, *sc;
376 uint16_t v;
377
378 sc0 = device_lookup_private(&scoop_cd, 0);
379 sc1 = device_lookup_private(&scoop_cd, 1);
380
381 /* C3000 */
382 if (sc1 != NULL) {
383 sc = sc0;
384 v = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR);
385 if ((v & 0x100) == 0) {
386 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR,
387 0x0101);
388 }
389
390 sc = sc1;
391 v = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR);
392 if ((v & 0x100) == 0) {
393 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR,
394 0x0101);
395 }
396 }
397 }
398
399 void
400 scoop_suspend(void)
401 {
402 struct scoop_softc *sc, *sc0, *sc1;
403 uint32_t rv;
404
405 sc0 = device_lookup_private(&scoop_cd, 0);
406 sc1 = device_lookup_private(&scoop_cd, 1);
407
408 if (sc0 != NULL) {
409 sc = sc0;
410 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
411 SCOOP_GPWR);
412 /* C3000 */
413 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
414 sc->sc_gpwr & ~((1<<SCOOP0_MUTE_L) | (1<<SCOOP0_MUTE_R) |
415 (1<<SCOOP0_JK_A_C3000) | (1<<SCOOP0_ADC_TEMP_ON_C3000) |
416 (1<<SCOOP0_LED_GREEN)));
417 }
418
419 /* C3000 */
420 if (sc1 != NULL) {
421 sc = sc1;
422 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
423 SCOOP_GPWR);
424 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
425 sc->sc_gpwr & ~((1<<SCOOP1_RESERVED_4) |
426 (1<<SCOOP1_RESERVED_5) | (1<<SCOOP1_RESERVED_6) |
427 (1<<SCOOP1_BACKLIGHT_CONT) | (1<<SCOOP1_BACKLIGHT_ON) |
428 (1<<SCOOP1_MIC_BIAS)));
429 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR);
430 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
431 rv | ((1<<SCOOP1_IR_ON) | (1<<SCOOP1_RESERVED_3)));
432 }
433 }
434
435 void
436 scoop_resume(void)
437 {
438 struct scoop_softc *sc, *sc0, *sc1;
439
440 sc0 = device_lookup_private(&scoop_cd, 0);
441 sc1 = device_lookup_private(&scoop_cd, 1);
442
443 if (sc0 != NULL) {
444 sc = sc0;
445 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
446 sc->sc_gpwr);
447 }
448
449 if (sc1 != NULL) {
450 sc = sc1;
451 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
452 sc->sc_gpwr);
453 }
454 }
455