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