1 /* $NetBSD: scoop.c,v 1.7 2009/04/18 05:20:21 nonaka 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.7 2009/04/18 05:20:21 nonaka 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 device_t 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(device_t, cfdata_t, void *); 51 static void scoopattach(device_t, device_t, void *); 52 53 CFATTACH_DECL_NEW(scoop, sizeof(struct scoop_softc), 54 scoopmatch, scoopattach, NULL, NULL); 55 56 #if 0 57 static int scoop_gpio_pin_read(struct scoop_softc *, int); 58 #endif 59 static void scoop_gpio_pin_write(struct scoop_softc *, int, int); 60 static void scoop_gpio_pin_ctl(struct scoop_softc *, 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(device_t parent, cfdata_t 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(device_t parent, device_t self, void *aux) 83 { 84 struct scoop_softc *sc = device_private(self); 85 struct pxaip_attach_args *pxa = (struct pxaip_attach_args *)aux; 86 bus_addr_t addr; 87 bus_size_t size; 88 89 sc->sc_dev = self; 90 sc->sc_iot = pxa->pxa_iot; 91 92 aprint_normal(": PCMCIA/GPIO controller\n"); 93 aprint_naive("\n"); 94 95 if (pxa->pxa_addr != -1) 96 addr = pxa->pxa_addr; 97 else if (sc->sc_dev->dv_unit == 0) 98 addr = C3000_SCOOP0_BASE; 99 else 100 addr = C3000_SCOOP1_BASE; 101 102 size = pxa->pxa_size < SCOOP_SIZE ? SCOOP_SIZE : pxa->pxa_size; 103 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"); 106 return; 107 } 108 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); 115 } 116 117 } 118 119 #if 0 120 static int 121 scoop_gpio_pin_read(struct scoop_softc *sc, int pin) 122 { 123 uint16_t bit = (1 << pin); 124 uint16_t rv; 125 126 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR); 127 return (rv & bit) ? 1 : 0; 128 } 129 #endif 130 131 static void 132 scoop_gpio_pin_write(struct scoop_softc *sc, int pin, int level) 133 { 134 uint16_t bit = (1 << pin); 135 uint16_t rv; 136 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)); 140 } 141 142 static void 143 scoop_gpio_pin_ctl(struct scoop_softc *sc, int pin, int flags) 144 { 145 uint16_t bit = (1 << pin); 146 uint16_t rv; 147 148 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR); 149 switch (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 150 case GPIO_PIN_INPUT: 151 rv &= ~bit; 152 break; 153 case GPIO_PIN_OUTPUT: 154 rv |= bit; 155 break; 156 } 157 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR, rv); 158 } 159 160 /* 161 * Turn the LCD background light and contrast signal on or off. 162 */ 163 void 164 scoop_set_backlight(int on, int cont) 165 { 166 struct scoop_softc *sc; 167 #if 0 168 struct scoop_softc *sc0; 169 170 sc0 = device_lookup_private(&scoop_cd, 0); 171 #endif 172 173 sc = device_lookup_private(&scoop_cd, 1); 174 if (sc != NULL) { 175 /* C3000 */ 176 scoop_gpio_pin_write(sc, 177 SCOOP1_BACKLIGHT_CONT, !cont); 178 scoop_gpio_pin_write(sc, 179 SCOOP1_BACKLIGHT_ON, on); 180 } 181 #if 0 182 else if (sc0 != NULL) { 183 scoop_gpio_pin_write(sc0, 184 SCOOP0_BACKLIGHT_CONT, cont); 185 } 186 #endif 187 } 188 189 /* 190 * Turn the infrared LED on or off (must be on while transmitting). 191 */ 192 void 193 scoop_set_irled(int on) 194 { 195 struct scoop_softc *sc; 196 197 sc = device_lookup_private(&scoop_cd, 1); 198 if (sc != NULL) { 199 /* IR_ON is inverted */ 200 scoop_gpio_pin_write(sc, 201 SCOOP1_IR_ON, !on); 202 } 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 struct scoop_softc *sc; 214 215 sc = device_lookup_private(&scoop_cd, 0); 216 if (sc != NULL) { 217 if ((led & SCOOP_LED_GREEN) != 0) { 218 scoop_gpio_pin_write(sc, 219 SCOOP0_LED_GREEN, on); 220 } 221 if (scoop_cd.cd_ndevs > 1 && (led & SCOOP_LED_ORANGE) != 0) { 222 scoop_gpio_pin_write(sc, 223 SCOOP0_LED_ORANGE_C3000, on); 224 } 225 } 226 } 227 228 /* 229 * Enable or disable the headphone output connection. 230 */ 231 void 232 scoop_set_headphone(int on) 233 { 234 struct scoop_softc *sc; 235 236 sc = device_lookup_private(&scoop_cd, 0); 237 if (sc == NULL) 238 return; 239 240 scoop_gpio_pin_ctl(sc, SCOOP0_MUTE_L, 241 GPIO_PIN_OUTPUT); 242 scoop_gpio_pin_ctl(sc, SCOOP0_MUTE_R, 243 GPIO_PIN_OUTPUT); 244 245 if (on) { 246 scoop_gpio_pin_write(sc, SCOOP0_MUTE_L, 247 GPIO_PIN_HIGH); 248 scoop_gpio_pin_write(sc, SCOOP0_MUTE_R, 249 GPIO_PIN_HIGH); 250 } else { 251 scoop_gpio_pin_write(sc, SCOOP0_MUTE_L, 252 GPIO_PIN_LOW); 253 scoop_gpio_pin_write(sc, SCOOP0_MUTE_R, 254 GPIO_PIN_LOW); 255 } 256 } 257 258 /* 259 * Enable or disable the mic bias 260 */ 261 void 262 scoop_set_mic_bias(int onoff) 263 { 264 struct scoop_softc *sc1; 265 266 sc1 = device_lookup_private(&scoop_cd, 1); 267 if (sc1 != NULL) 268 scoop_gpio_pin_write(sc1, SCOOP1_MIC_BIAS, onoff); 269 } 270 271 /* 272 * Turn on pullup resistor while not reading the remote control. 273 */ 274 void 275 scoop_akin_pullup(int enable) 276 { 277 struct scoop_softc *sc0; 278 struct scoop_softc *sc1; 279 280 sc0 = device_lookup_private(&scoop_cd, 0); 281 sc1 = device_lookup_private(&scoop_cd, 1); 282 283 if (sc1 != NULL) { 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); 289 } 290 } 291 292 void 293 scoop_battery_temp_adc(int enable) 294 { 295 struct scoop_softc *sc; 296 297 sc = device_lookup_private(&scoop_cd, 0); 298 299 if (sc != NULL) { 300 scoop_gpio_pin_write(sc, 301 SCOOP0_ADC_TEMP_ON_C3000, enable); 302 } 303 } 304 305 void 306 scoop_charge_battery(int enable, int voltage_high) 307 { 308 struct scoop_softc *sc; 309 310 sc = device_lookup_private(&scoop_cd, 0); 311 312 if (sc != NULL) { 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); 317 } 318 } 319 320 void 321 scoop_discharge_battery(int enable) 322 { 323 struct scoop_softc *sc; 324 325 sc = device_lookup_private(&scoop_cd, 0); 326 327 if (sc != NULL) { 328 scoop_gpio_pin_write(sc, 329 SCOOP0_JK_A_C3000, enable); 330 } 331 } 332 333 /* 334 * Enable or disable 3.3V power to the SD/MMC card slot. 335 */ 336 void 337 scoop_set_sdmmc_power(int on) 338 { 339 340 scoop0_set_card_power(SD_CARD, on ? SCP_CPR_SD_3V : SCP_CPR_OFF); 341 } 342 343 /* 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. 346 */ 347 void 348 scoop0_set_card_power(enum scoop_card card, int new_cpr) 349 { 350 struct scoop_softc *sc; 351 bus_space_tag_t iot; 352 bus_space_handle_t ioh; 353 uint16_t cpr; 354 355 sc = device_lookup_private(&scoop_cd, 0); 356 if (sc == NULL) 357 return; 358 359 iot = sc->sc_iot; 360 ioh = sc->sc_ioh; 361 362 cpr = bus_space_read_2(iot, ioh, SCOOP_CPR); 363 if (new_cpr & SCP_CPR_VOLTAGE_MSK) { 364 if (card == CF_CARD) 365 cpr |= SCP_CPR_5V; 366 else if (card == SD_CARD) 367 cpr |= SCP_CPR_SD_3V; 368 369 scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 1); 370 if (!ISSET(cpr, SCP_CPR_5V) && !ISSET(cpr, SCP_CPR_SD_3V)) 371 delay(5000); 372 bus_space_write_2(iot, ioh, SCOOP_CPR, cpr | new_cpr); 373 } else { 374 if (card == CF_CARD) 375 cpr &= ~SCP_CPR_5V; 376 else if (card == SD_CARD) 377 cpr &= ~SCP_CPR_SD_3V; 378 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); 381 delay(1000); 382 scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 0); 383 } else 384 bus_space_write_2(iot, ioh, SCOOP_CPR, cpr | new_cpr); 385 } 386 } 387 388 void 389 scoop_check_mcr(void) 390 { 391 struct scoop_softc *sc0, *sc1, *sc; 392 uint16_t v; 393 394 sc0 = device_lookup_private(&scoop_cd, 0); 395 sc1 = device_lookup_private(&scoop_cd, 1); 396 397 /* C3000 */ 398 if (sc1 != NULL) { 399 sc = sc0; 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, 403 0x0101); 404 } 405 406 sc = sc1; 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, 410 0x0101); 411 } 412 } 413 } 414 415 void 416 scoop_suspend(void) 417 { 418 struct scoop_softc *sc, *sc0, *sc1; 419 uint32_t rv; 420 421 sc0 = device_lookup_private(&scoop_cd, 0); 422 sc1 = device_lookup_private(&scoop_cd, 1); 423 424 if (sc0 != NULL) { 425 sc = sc0; 426 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 427 SCOOP_GPWR); 428 /* C3000 */ 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))); 433 } 434 435 /* C3000 */ 436 if (sc1 != NULL) { 437 sc = sc1; 438 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 439 SCOOP_GPWR); 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))); 448 } 449 } 450 451 void 452 scoop_resume(void) 453 { 454 struct scoop_softc *sc, *sc0, *sc1; 455 456 sc0 = device_lookup_private(&scoop_cd, 0); 457 sc1 = device_lookup_private(&scoop_cd, 1); 458 459 if (sc0 != NULL) { 460 sc = sc0; 461 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 462 sc->sc_gpwr); 463 } 464 465 if (sc1 != NULL) { 466 sc = sc1; 467 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 468 sc->sc_gpwr); 469 } 470 } 471