scoop.c revision 1.1 1 /* $NetBSD: scoop.c,v 1.1 2006/12/16 05:15:16 ober 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.1 2006/12/16 05:15:16 ober 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 bus_space_tag_t sc_iot;
44 bus_space_handle_t sc_ioh;
45 uint16_t sc_gpwr; /* GPIO state before suspend */
46 };
47
48 static int scoopmatch(struct device *, struct cfdata *, void *);
49 static void scoopattach(struct device *, struct device *, void *);
50
51 CFATTACH_DECL(scoop, sizeof(struct scoop_softc),
52 scoopmatch, scoopattach, NULL, NULL);
53
54 int scoop_gpio_pin_read(struct scoop_softc *sc, int);
55 void scoop_gpio_pin_write(struct scoop_softc *sc, int, int);
56 void scoop_gpio_pin_ctl(struct scoop_softc *sc, int, int);
57
58 static int
59 scoopmatch(struct device *parent, struct cfdata *cf, void *aux)
60 {
61
62 /*
63 * Only C3000-like models are known to have two SCOOPs.
64 */
65 if (ZAURUS_ISC3000)
66 return (cf->cf_unit < 2);
67 return (cf->cf_unit == 0);
68 }
69
70 static void
71 scoopattach(struct device *parent, struct device *self, void *aux)
72 {
73 struct pxaip_attach_args *pxa = (struct pxaip_attach_args *)aux;
74 struct scoop_softc *sc = (struct scoop_softc *)self;
75 bus_addr_t addr;
76 bus_size_t size;
77
78 sc->sc_iot = pxa->pxa_iot;
79
80 if (pxa->pxa_addr != -1)
81 addr = pxa->pxa_addr;
82 else if (sc->sc_dev.dv_unit == 0)
83 addr = C3000_SCOOP0_BASE;
84 else
85 addr = C3000_SCOOP1_BASE;
86
87 size = pxa->pxa_size < SCOOP_SIZE ? SCOOP_SIZE : pxa->pxa_size;
88
89 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
90 printf(": failed to map %s\n", sc->sc_dev.dv_xname);
91 return;
92 }
93
94 if (ZAURUS_ISC3000 && sc->sc_dev.dv_unit == 1) {
95 scoop_gpio_pin_ctl(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_OUTPUT);
96 scoop_gpio_pin_write(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_LOW);
97 } else if (!ZAURUS_ISC3000) {
98 scoop_gpio_pin_ctl(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_OUTPUT);
99 scoop_gpio_pin_write(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_LOW);
100 }
101
102 printf(": PCMCIA/GPIO controller\n");
103 }
104
105 int
106 scoop_gpio_pin_read(struct scoop_softc *sc, int pin)
107 {
108 uint16_t bit = (1 << pin);
109 uint16_t rv;
110
111 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR);
112 return (rv & bit) != 0 ? 1 : 0;
113 }
114
115 void
116 scoop_gpio_pin_write(struct scoop_softc *sc, int pin, int level)
117 {
118 uint16_t bit = (1 << pin);
119 uint16_t rv;
120
121 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR);
122 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
123 level == GPIO_PIN_LOW ? (rv & ~bit) : (rv | bit));
124 }
125
126 void
127 scoop_gpio_pin_ctl(struct scoop_softc *sc, int pin, int flags)
128 {
129 uint16_t bit = (1 << pin);
130 uint16_t rv;
131
132 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR);
133 switch (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
134 case GPIO_PIN_INPUT:
135 rv &= ~bit;
136 break;
137 case GPIO_PIN_OUTPUT:
138 rv |= bit;
139 break;
140 }
141 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR, rv);
142 }
143
144 /*
145 * Turn the LCD background light and contrast signal on or off.
146 */
147 void
148 scoop_set_backlight(int on, int cont)
149 {
150
151 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) {
152 /* C3000 */
153 scoop_gpio_pin_write(scoop_cd.cd_devs[1],
154 SCOOP1_BACKLIGHT_CONT, !cont);
155 scoop_gpio_pin_write(scoop_cd.cd_devs[1],
156 SCOOP1_BACKLIGHT_ON, on);
157 }
158 #if 0
159 else if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
160 scoop_gpio_pin_write(scoop_cd.cd_devs[0],
161 SCOOP0_BACKLIGHT_CONT, cont);
162 }
163 #endif
164 }
165
166 /*
167 * Turn the infrared LED on or off (must be on while transmitting).
168 */
169 void
170 scoop_set_irled(int on)
171 {
172 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL)
173 /* IR_ON is inverted */
174 scoop_gpio_pin_write(scoop_cd.cd_devs[1],
175 SCOOP1_IR_ON, !on);
176 }
177
178 /*
179 * Turn the green and orange LEDs on or off. If the orange LED is on,
180 * then it is wired to indicate if A/C is connected. The green LED has
181 * no such predefined function.
182 */
183 void
184 scoop_led_set(int led, int on)
185 {
186
187 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
188 if ((led & SCOOP_LED_GREEN) != 0) {
189 scoop_gpio_pin_write(scoop_cd.cd_devs[0],
190 SCOOP0_LED_GREEN, on);
191 }
192 if (scoop_cd.cd_ndevs > 1 && (led & SCOOP_LED_ORANGE) != 0) {
193 scoop_gpio_pin_write(scoop_cd.cd_devs[0],
194 SCOOP0_LED_ORANGE_C3000, on);
195 }
196 }
197 }
198
199 /*
200 * Enable or disable the headphone output connection.
201 */
202 void
203 scoop_set_headphone(int on)
204 {
205
206 if (scoop_cd.cd_ndevs < 1 || scoop_cd.cd_devs[0] == NULL)
207 return;
208
209 scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_L,
210 GPIO_PIN_OUTPUT);
211 scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_R,
212 GPIO_PIN_OUTPUT);
213
214 if (on) {
215 scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_L,
216 GPIO_PIN_HIGH);
217 scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R,
218 GPIO_PIN_HIGH);
219 } else {
220 scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_L,
221 GPIO_PIN_LOW);
222 scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R,
223 GPIO_PIN_LOW);
224 }
225 }
226
227 /*
228 * Turn on pullup resistor while not reading the remote control.
229 */
230 void
231 scoop_akin_pullup(int enable)
232 {
233
234 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) {
235 scoop_gpio_pin_write(scoop_cd.cd_devs[1],
236 SCOOP1_AKIN_PULLUP, enable);
237 } else {
238 scoop_gpio_pin_write(scoop_cd.cd_devs[0],
239 SCOOP0_AKIN_PULLUP, enable);
240 }
241 }
242
243 void
244 scoop_battery_temp_adc(int enable)
245 {
246
247 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
248 scoop_gpio_pin_write(scoop_cd.cd_devs[0],
249 SCOOP0_ADC_TEMP_ON_C3000, enable);
250 }
251 }
252
253 void
254 scoop_charge_battery(int enable, int voltage_high)
255 {
256
257 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
258 scoop_gpio_pin_write(scoop_cd.cd_devs[0],
259 SCOOP0_JK_B_C3000, voltage_high);
260 scoop_gpio_pin_write(scoop_cd.cd_devs[0],
261 SCOOP0_CHARGE_OFF_C3000, !enable);
262 }
263 }
264
265 void
266 scoop_discharge_battery(int enable)
267 {
268
269 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
270 scoop_gpio_pin_write(scoop_cd.cd_devs[0],
271 SCOOP0_JK_A_C3000, enable);
272 }
273 }
274
275 /* XXX */
276 void scoop_check_mcr(void);
277 void
278 scoop_check_mcr(void)
279 {
280 struct scoop_softc *sc;
281 uint16_t v;
282
283 /* C3000 */
284 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) {
285 sc = scoop_cd.cd_devs[0];
286 v = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR);
287 if ((v & 0x100) == 0) {
288 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR,
289 0x0101);
290 }
291
292 sc = scoop_cd.cd_devs[1];
293 v = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR);
294 if ((v & 0x100) == 0) {
295 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR,
296 0x0101);
297 }
298 }
299 }
300
301 void
302 scoop_suspend(void)
303 {
304 struct scoop_softc *sc;
305 uint32_t rv;
306
307 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
308 sc = scoop_cd.cd_devs[0];
309 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
310 SCOOP_GPWR);
311 /* C3000 */
312 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
313 sc->sc_gpwr & ~((1<<SCOOP0_MUTE_L) | (1<<SCOOP0_MUTE_R) |
314 (1<<SCOOP0_JK_A_C3000) | (1<<SCOOP0_ADC_TEMP_ON_C3000) |
315 (1<<SCOOP0_LED_GREEN)));
316 }
317
318 /* C3000 */
319 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) {
320 sc = scoop_cd.cd_devs[1];
321 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
322 SCOOP_GPWR);
323 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
324 sc->sc_gpwr & ~((1<<SCOOP1_RESERVED_4) |
325 (1<<SCOOP1_RESERVED_5) | (1<<SCOOP1_RESERVED_6) |
326 (1<<SCOOP1_BACKLIGHT_CONT) | (1<<SCOOP1_BACKLIGHT_ON) |
327 (1<<SCOOP1_MIC_BIAS)));
328 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR);
329 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
330 rv | ((1<<SCOOP1_IR_ON) | (1<<SCOOP1_RESERVED_3)));
331 }
332 }
333
334 void
335 scoop_resume(void)
336 {
337 struct scoop_softc *sc;
338
339 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
340 sc = scoop_cd.cd_devs[0];
341 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
342 sc->sc_gpwr);
343 }
344
345 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) {
346 sc = scoop_cd.cd_devs[1];
347 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
348 sc->sc_gpwr);
349 }
350 }
351