1 /* $NetBSD: scoop.c,v 1.6 2009/01/29 12:28:15 nonaka Exp $ */
2 /* $OpenBSD: zaurus_scoop.c,v 1.12 2005/11/17 05:26:31 uwe Exp $ */
5 * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
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.
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.
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: scoop.c,v 1.6 2009/01/29 12:28:15 nonaka Exp $");
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
29 #include <machine/bus.h>
31 #include <arm/xscale/pxa2x0var.h>
33 #include <zaurus/zaurus/zaurus_reg.h>
34 #include <zaurus/zaurus/zaurus_var.h>
36 #include <zaurus/dev/scoopreg.h>
37 #include <zaurus/dev/scoopvar.h>
44 bus_space_tag_t sc_iot
;
45 bus_space_handle_t sc_ioh
;
47 uint16_t sc_gpwr
; /* GPIO state before suspend */
50 static int scoopmatch(device_t
, cfdata_t
, void *);
51 static void scoopattach(device_t
, device_t
, void *);
53 CFATTACH_DECL_NEW(scoop
, sizeof(struct scoop_softc
),
54 scoopmatch
, scoopattach
, NULL
, NULL
);
57 static int scoop_gpio_pin_read(struct scoop_softc
*, int);
59 static void scoop_gpio_pin_write(struct scoop_softc
*, int, int);
60 static void scoop_gpio_pin_ctl(struct scoop_softc
*, int, int);
64 CF_CARD
/* socket 0 (external) */
67 static void scoop0_set_card_power(enum scoop_card card
, int new_cpr
);
70 scoopmatch(device_t parent
, cfdata_t cf
, void *aux
)
74 * Only C3000-like models are known to have two SCOOPs.
77 return (cf
->cf_unit
< 2);
78 return (cf
->cf_unit
== 0);
82 scoopattach(device_t parent
, device_t self
, void *aux
)
84 struct scoop_softc
*sc
= device_private(self
);
85 struct pxaip_attach_args
*pxa
= (struct pxaip_attach_args
*)aux
;
90 sc
->sc_iot
= pxa
->pxa_iot
;
92 aprint_normal(": PCMCIA/GPIO controller\n");
95 if (pxa
->pxa_addr
!= -1)
97 else if (sc
->sc_dev
->dv_unit
== 0)
98 addr
= C3000_SCOOP0_BASE
;
100 addr
= C3000_SCOOP1_BASE
;
102 size
= pxa
->pxa_size
< SCOOP_SIZE
? SCOOP_SIZE
: pxa
->pxa_size
;
104 if (bus_space_map(sc
->sc_iot
, addr
, size
, 0, &sc
->sc_ioh
) != 0) {
105 aprint_error_dev(sc
->sc_dev
, "couldn't map registers\n");
109 if (ZAURUS_ISC3000
&& sc
->sc_dev
->dv_unit
== 1) {
110 scoop_gpio_pin_ctl(sc
, SCOOP1_AKIN_PULLUP
, GPIO_PIN_OUTPUT
);
111 scoop_gpio_pin_write(sc
, SCOOP1_AKIN_PULLUP
, GPIO_PIN_LOW
);
112 } else if (!ZAURUS_ISC3000
) {
113 scoop_gpio_pin_ctl(sc
, SCOOP0_AKIN_PULLUP
, GPIO_PIN_OUTPUT
);
114 scoop_gpio_pin_write(sc
, SCOOP0_AKIN_PULLUP
, GPIO_PIN_LOW
);
121 scoop_gpio_pin_read(struct scoop_softc
*sc
, int pin
)
123 uint16_t bit
= (1 << pin
);
126 rv
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPWR
);
127 return (rv
& bit
) ? 1 : 0;
132 scoop_gpio_pin_write(struct scoop_softc
*sc
, int pin
, int level
)
134 uint16_t bit
= (1 << pin
);
137 rv
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPWR
);
138 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPWR
,
139 (level
== GPIO_PIN_LOW
) ? (rv
& ~bit
) : (rv
| bit
));
143 scoop_gpio_pin_ctl(struct scoop_softc
*sc
, int pin
, int flags
)
145 uint16_t bit
= (1 << pin
);
148 rv
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPCR
);
149 switch (flags
& (GPIO_PIN_INPUT
|GPIO_PIN_OUTPUT
)) {
153 case GPIO_PIN_OUTPUT
:
157 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPCR
, rv
);
161 * Turn the LCD background light and contrast signal on or off.
164 scoop_set_backlight(int on
, int cont
)
166 struct scoop_softc
*sc
;
168 struct scoop_softc
*sc0
;
170 sc0
= device_lookup_private(&scoop_cd
, 0);
173 sc
= device_lookup_private(&scoop_cd
, 1);
176 scoop_gpio_pin_write(sc
,
177 SCOOP1_BACKLIGHT_CONT
, !cont
);
178 scoop_gpio_pin_write(sc
,
179 SCOOP1_BACKLIGHT_ON
, on
);
182 else if (sc0
!= NULL
) {
183 scoop_gpio_pin_write(sc0
,
184 SCOOP0_BACKLIGHT_CONT
, cont
);
190 * Turn the infrared LED on or off (must be on while transmitting).
193 scoop_set_irled(int on
)
195 struct scoop_softc
*sc
;
197 sc
= device_lookup_private(&scoop_cd
, 1);
199 /* IR_ON is inverted */
200 scoop_gpio_pin_write(sc
,
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.
211 scoop_led_set(int led
, int on
)
213 struct scoop_softc
*sc
;
215 sc
= device_lookup_private(&scoop_cd
, 0);
217 if ((led
& SCOOP_LED_GREEN
) != 0) {
218 scoop_gpio_pin_write(sc
,
219 SCOOP0_LED_GREEN
, on
);
221 if (scoop_cd
.cd_ndevs
> 1 && (led
& SCOOP_LED_ORANGE
) != 0) {
222 scoop_gpio_pin_write(sc
,
223 SCOOP0_LED_ORANGE_C3000
, on
);
229 * Enable or disable the headphone output connection.
232 scoop_set_headphone(int on
)
234 struct scoop_softc
*sc
;
236 sc
= device_lookup_private(&scoop_cd
, 0);
240 scoop_gpio_pin_ctl(sc
, SCOOP0_MUTE_L
,
242 scoop_gpio_pin_ctl(sc
, SCOOP0_MUTE_R
,
246 scoop_gpio_pin_write(sc
, SCOOP0_MUTE_L
,
248 scoop_gpio_pin_write(sc
, SCOOP0_MUTE_R
,
251 scoop_gpio_pin_write(sc
, SCOOP0_MUTE_L
,
253 scoop_gpio_pin_write(sc
, SCOOP0_MUTE_R
,
259 * Enable or disable the mic bias
262 scoop_set_mic_bias(int onoff
)
264 struct scoop_softc
*sc1
;
266 sc1
= device_lookup_private(&scoop_cd
, 1);
268 scoop_gpio_pin_write(sc1
, SCOOP1_MIC_BIAS
, onoff
);
272 * Turn on pullup resistor while not reading the remote control.
275 scoop_akin_pullup(int enable
)
277 struct scoop_softc
*sc0
;
278 struct scoop_softc
*sc1
;
280 sc0
= device_lookup_private(&scoop_cd
, 0);
281 sc1
= device_lookup_private(&scoop_cd
, 1);
284 scoop_gpio_pin_write(sc1
,
285 SCOOP1_AKIN_PULLUP
, enable
);
286 } else if (sc0
!= NULL
) {
287 scoop_gpio_pin_write(sc0
,
288 SCOOP0_AKIN_PULLUP
, enable
);
293 scoop_battery_temp_adc(int enable
)
295 struct scoop_softc
*sc
;
297 sc
= device_lookup_private(&scoop_cd
, 0);
300 scoop_gpio_pin_write(sc
,
301 SCOOP0_ADC_TEMP_ON_C3000
, enable
);
306 scoop_charge_battery(int enable
, int voltage_high
)
308 struct scoop_softc
*sc
;
310 sc
= device_lookup_private(&scoop_cd
, 0);
313 scoop_gpio_pin_write(sc
,
314 SCOOP0_JK_B_C3000
, voltage_high
);
315 scoop_gpio_pin_write(sc
,
316 SCOOP0_CHARGE_OFF_C3000
, !enable
);
321 scoop_discharge_battery(int enable
)
323 struct scoop_softc
*sc
;
325 sc
= device_lookup_private(&scoop_cd
, 0);
328 scoop_gpio_pin_write(sc
,
329 SCOOP0_JK_A_C3000
, enable
);
334 * Enable or disable 3.3V power to the SD/MMC card slot.
337 scoop_set_sdmmc_power(int on
)
340 scoop0_set_card_power(SD_CARD
, on
? SCP_CPR_SD_3V
: SCP_CPR_OFF
);
344 * The Card Power Register of the first SCOOP unit controls the power
345 * for the first CompactFlash slot and the SD/MMC card slot as well.
348 scoop0_set_card_power(enum scoop_card card
, int new_cpr
)
350 struct scoop_softc
*sc
;
352 bus_space_handle_t ioh
;
355 sc
= device_lookup_private(&scoop_cd
, 0);
362 cpr
= bus_space_read_2(iot
, ioh
, SCOOP_CPR
);
363 if (new_cpr
& SCP_CPR_VOLTAGE_MSK
) {
366 else if (card
== SD_CARD
)
367 cpr
|= SCP_CPR_SD_3V
;
369 scoop_gpio_pin_write(sc
, SCOOP0_CF_POWER_C3000
, 1);
370 if (!ISSET(cpr
, SCP_CPR_5V
) && !ISSET(cpr
, SCP_CPR_SD_3V
))
372 bus_space_write_2(iot
, ioh
, SCOOP_CPR
, cpr
| new_cpr
);
376 else if (card
== SD_CARD
)
377 cpr
&= ~SCP_CPR_SD_3V
;
379 if (!ISSET(cpr
, SCP_CPR_5V
) && !ISSET(cpr
, SCP_CPR_SD_3V
)) {
380 bus_space_write_2(iot
, ioh
, SCOOP_CPR
, SCP_CPR_OFF
);
382 scoop_gpio_pin_write(sc
, SCOOP0_CF_POWER_C3000
, 0);
384 bus_space_write_2(iot
, ioh
, SCOOP_CPR
, cpr
| new_cpr
);
389 scoop_check_mcr(void)
391 struct scoop_softc
*sc0
, *sc1
, *sc
;
394 sc0
= device_lookup_private(&scoop_cd
, 0);
395 sc1
= device_lookup_private(&scoop_cd
, 1);
400 v
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_MCR
);
401 if ((v
& 0x100) == 0) {
402 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_MCR
,
407 v
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_MCR
);
408 if ((v
& 0x100) == 0) {
409 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_MCR
,
418 struct scoop_softc
*sc
, *sc0
, *sc1
;
421 sc0
= device_lookup_private(&scoop_cd
, 0);
422 sc1
= device_lookup_private(&scoop_cd
, 1);
426 sc
->sc_gpwr
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
,
429 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPWR
,
430 sc
->sc_gpwr
& ~((1<<SCOOP0_MUTE_L
) | (1<<SCOOP0_MUTE_R
) |
431 (1<<SCOOP0_JK_A_C3000
) | (1<<SCOOP0_ADC_TEMP_ON_C3000
) |
432 (1<<SCOOP0_LED_GREEN
)));
438 sc
->sc_gpwr
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
,
440 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPWR
,
441 sc
->sc_gpwr
& ~((1<<SCOOP1_RESERVED_4
) |
442 (1<<SCOOP1_RESERVED_5
) | (1<<SCOOP1_RESERVED_6
) |
443 (1<<SCOOP1_BACKLIGHT_CONT
) | (1<<SCOOP1_BACKLIGHT_ON
) |
444 (1<<SCOOP1_MIC_BIAS
)));
445 rv
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPWR
);
446 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPWR
,
447 rv
| ((1<<SCOOP1_IR_ON
) | (1<<SCOOP1_RESERVED_3
)));
454 struct scoop_softc
*sc
, *sc0
, *sc1
;
456 sc0
= device_lookup_private(&scoop_cd
, 0);
457 sc1
= device_lookup_private(&scoop_cd
, 1);
461 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPWR
,
467 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, SCOOP_GPWR
,