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@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