1 /* $NetBSD: scoop.c,v 1.9 2011/07/19 15:11:49 dyoung 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.9 2011/07/19 15:11:49 dyoung 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 #include <sys/bus.h> 29 30 #include <arm/xscale/pxa2x0var.h> 31 32 #include <zaurus/zaurus/zaurus_reg.h> 33 #include <zaurus/zaurus/zaurus_var.h> 34 35 #include <zaurus/dev/scoopreg.h> 36 #include <zaurus/dev/scoopvar.h> 37 38 #include "ioconf.h" 39 40 struct scoop_softc { 41 device_t sc_dev; 42 43 bus_space_tag_t sc_iot; 44 bus_space_handle_t sc_ioh; 45 46 uint16_t sc_gpwr; /* GPIO state before suspend */ 47 }; 48 49 static int scoopmatch(device_t, cfdata_t, void *); 50 static void scoopattach(device_t, device_t, void *); 51 52 CFATTACH_DECL_NEW(scoop, sizeof(struct scoop_softc), 53 scoopmatch, scoopattach, NULL, NULL); 54 55 #if 0 56 static int scoop_gpio_pin_read(struct scoop_softc *, int); 57 #endif 58 static void scoop_gpio_pin_write(struct scoop_softc *, int, int); 59 static void scoop_gpio_pin_ctl(struct scoop_softc *, int, int); 60 61 enum scoop_card { 62 SD_CARD, 63 CF_CARD /* socket 0 (external) */ 64 }; 65 66 static void scoop0_set_card_power(enum scoop_card card, int new_cpr); 67 68 static int 69 scoopmatch(device_t parent, cfdata_t cf, void *aux) 70 { 71 72 /* 73 * Only C3000-like models are known to have two SCOOPs. 74 */ 75 if (ZAURUS_ISC3000) 76 return (cf->cf_unit < 2); 77 return (cf->cf_unit == 0); 78 } 79 80 static void 81 scoopattach(device_t parent, device_t self, void *aux) 82 { 83 struct scoop_softc *sc = device_private(self); 84 struct pxaip_attach_args *pxa = (struct pxaip_attach_args *)aux; 85 bus_addr_t addr; 86 bus_size_t size; 87 88 sc->sc_dev = self; 89 sc->sc_iot = pxa->pxa_iot; 90 91 aprint_normal(": PCMCIA/GPIO controller\n"); 92 aprint_naive("\n"); 93 94 if (pxa->pxa_addr != -1) 95 addr = pxa->pxa_addr; 96 else if (sc->sc_dev->dv_unit == 0) 97 addr = C3000_SCOOP0_BASE; 98 else 99 addr = C3000_SCOOP1_BASE; 100 101 size = pxa->pxa_size < SCOOP_SIZE ? SCOOP_SIZE : pxa->pxa_size; 102 103 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) { 104 aprint_error_dev(sc->sc_dev, "couldn't map registers\n"); 105 return; 106 } 107 108 if (ZAURUS_ISC3000 && sc->sc_dev->dv_unit == 1) { 109 scoop_gpio_pin_ctl(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_OUTPUT); 110 scoop_gpio_pin_write(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_LOW); 111 } else if (ZAURUS_ISC860) { 112 scoop_gpio_pin_ctl(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_OUTPUT); 113 scoop_gpio_pin_write(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_LOW); 114 } 115 } 116 117 #if 0 118 static int 119 scoop_gpio_pin_read(struct scoop_softc *sc, int pin) 120 { 121 uint16_t bit = (1 << pin); 122 uint16_t rv; 123 124 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR); 125 return (rv & bit) ? 1 : 0; 126 } 127 #endif 128 129 static void 130 scoop_gpio_pin_write(struct scoop_softc *sc, int pin, int level) 131 { 132 uint16_t bit = (1 << pin); 133 uint16_t rv; 134 135 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR); 136 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 137 (level == GPIO_PIN_LOW) ? (rv & ~bit) : (rv | bit)); 138 } 139 140 static void 141 scoop_gpio_pin_ctl(struct scoop_softc *sc, int pin, int flags) 142 { 143 uint16_t bit = (1 << pin); 144 uint16_t rv; 145 146 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR); 147 switch (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 148 case GPIO_PIN_INPUT: 149 rv &= ~bit; 150 break; 151 case GPIO_PIN_OUTPUT: 152 rv |= bit; 153 break; 154 } 155 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR, rv); 156 } 157 158 /* 159 * Turn the LCD background light and contrast signal on or off. 160 */ 161 void 162 scoop_set_backlight(int on, int cont) 163 { 164 struct scoop_softc *sc; 165 #if 0 166 struct scoop_softc *sc0; 167 168 sc0 = device_lookup_private(&scoop_cd, 0); 169 #endif 170 171 sc = device_lookup_private(&scoop_cd, 1); 172 if (sc != NULL) { 173 /* C3000 */ 174 scoop_gpio_pin_write(sc, SCOOP1_BACKLIGHT_CONT, !cont); 175 scoop_gpio_pin_write(sc, SCOOP1_BACKLIGHT_ON, on); 176 } 177 #if 0 178 else if (sc0 != NULL) { 179 scoop_gpio_pin_write(sc0, 180 SCOOP0_BACKLIGHT_CONT, cont); 181 } 182 #endif 183 } 184 185 /* 186 * Turn the infrared LED on or off (must be on while transmitting). 187 */ 188 void 189 scoop_set_irled(int on) 190 { 191 struct scoop_softc *sc; 192 193 sc = device_lookup_private(&scoop_cd, 1); 194 if (sc != NULL) { 195 /* IR_ON is inverted */ 196 scoop_gpio_pin_write(sc, SCOOP1_IR_ON, !on); 197 } 198 } 199 200 /* 201 * Turn the green and orange LEDs on or off. If the orange LED is on, 202 * then it is wired to indicate if A/C is connected. The green LED has 203 * no such predefined function. 204 */ 205 void 206 scoop_led_set(int led, int on) 207 { 208 struct scoop_softc *sc; 209 210 sc = device_lookup_private(&scoop_cd, 0); 211 if (sc != NULL) { 212 if ((led & SCOOP_LED_GREEN) != 0) { 213 scoop_gpio_pin_write(sc, SCOOP0_LED_GREEN, on); 214 } 215 if (scoop_cd.cd_ndevs > 1 && (led & SCOOP_LED_ORANGE) != 0) { 216 scoop_gpio_pin_write(sc, SCOOP0_LED_ORANGE_C3000, on); 217 } 218 } 219 } 220 221 /* 222 * Enable or disable the headphone output connection. 223 */ 224 void 225 scoop_set_headphone(int on) 226 { 227 struct scoop_softc *sc; 228 229 sc = device_lookup_private(&scoop_cd, 0); 230 if (sc == NULL) 231 return; 232 233 scoop_gpio_pin_ctl(sc, SCOOP0_MUTE_L, GPIO_PIN_OUTPUT); 234 scoop_gpio_pin_ctl(sc, SCOOP0_MUTE_R, GPIO_PIN_OUTPUT); 235 236 if (on) { 237 scoop_gpio_pin_write(sc, SCOOP0_MUTE_L, GPIO_PIN_HIGH); 238 scoop_gpio_pin_write(sc, SCOOP0_MUTE_R, GPIO_PIN_HIGH); 239 } else { 240 scoop_gpio_pin_write(sc, SCOOP0_MUTE_L, GPIO_PIN_LOW); 241 scoop_gpio_pin_write(sc, SCOOP0_MUTE_R, GPIO_PIN_LOW); 242 } 243 } 244 245 /* 246 * Enable or disable the mic bias 247 */ 248 void 249 scoop_set_mic_bias(int onoff) 250 { 251 struct scoop_softc *sc1; 252 253 sc1 = device_lookup_private(&scoop_cd, 1); 254 if (sc1 != NULL) 255 scoop_gpio_pin_write(sc1, SCOOP1_MIC_BIAS, onoff); 256 } 257 258 /* 259 * Turn on pullup resistor while not reading the remote control. 260 */ 261 void 262 scoop_akin_pullup(int enable) 263 { 264 struct scoop_softc *sc0; 265 struct scoop_softc *sc1; 266 267 sc0 = device_lookup_private(&scoop_cd, 0); 268 sc1 = device_lookup_private(&scoop_cd, 1); 269 270 if (sc1 != NULL) { 271 scoop_gpio_pin_write(sc1, SCOOP1_AKIN_PULLUP, enable); 272 } else if (sc0 != NULL) { 273 scoop_gpio_pin_write(sc0, SCOOP0_AKIN_PULLUP, enable); 274 } 275 } 276 277 void 278 scoop_battery_temp_adc(int enable) 279 { 280 struct scoop_softc *sc; 281 282 sc = device_lookup_private(&scoop_cd, 0); 283 284 if (sc != NULL) { 285 scoop_gpio_pin_write(sc, 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, SCOOP0_JK_B_C3000, voltage_high); 298 scoop_gpio_pin_write(sc, SCOOP0_CHARGE_OFF_C3000, !enable); 299 } 300 } 301 302 void 303 scoop_discharge_battery(int enable) 304 { 305 struct scoop_softc *sc; 306 307 sc = device_lookup_private(&scoop_cd, 0); 308 309 if (sc != NULL) { 310 scoop_gpio_pin_write(sc, SCOOP0_JK_A_C3000, enable); 311 } 312 } 313 314 /* 315 * Enable or disable 3.3V power to the SD/MMC card slot. 316 */ 317 void 318 scoop_set_sdmmc_power(int on) 319 { 320 321 scoop0_set_card_power(SD_CARD, on ? SCP_CPR_SD_3V : SCP_CPR_OFF); 322 } 323 324 /* 325 * The Card Power Register of the first SCOOP unit controls the power 326 * for the first CompactFlash slot and the SD/MMC card slot as well. 327 */ 328 void 329 scoop0_set_card_power(enum scoop_card card, int new_cpr) 330 { 331 struct scoop_softc *sc; 332 bus_space_tag_t iot; 333 bus_space_handle_t ioh; 334 uint16_t cpr; 335 336 sc = device_lookup_private(&scoop_cd, 0); 337 if (sc == NULL) 338 return; 339 340 iot = sc->sc_iot; 341 ioh = sc->sc_ioh; 342 343 cpr = bus_space_read_2(iot, ioh, SCOOP_CPR); 344 if (new_cpr & SCP_CPR_VOLTAGE_MSK) { 345 if (card == CF_CARD) 346 cpr |= SCP_CPR_5V; 347 else if (card == SD_CARD) 348 cpr |= SCP_CPR_SD_3V; 349 350 scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 1); 351 if (!ISSET(cpr, SCP_CPR_5V) && !ISSET(cpr, SCP_CPR_SD_3V)) 352 delay(5000); 353 bus_space_write_2(iot, ioh, SCOOP_CPR, cpr | new_cpr); 354 } else { 355 if (card == CF_CARD) 356 cpr &= ~SCP_CPR_5V; 357 else if (card == SD_CARD) 358 cpr &= ~SCP_CPR_SD_3V; 359 360 if (!ISSET(cpr, SCP_CPR_5V) && !ISSET(cpr, SCP_CPR_SD_3V)) { 361 bus_space_write_2(iot, ioh, SCOOP_CPR, SCP_CPR_OFF); 362 delay(1000); 363 scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 0); 364 } else 365 bus_space_write_2(iot, ioh, SCOOP_CPR, cpr | new_cpr); 366 } 367 } 368 369 void 370 scoop_check_mcr(void) 371 { 372 struct scoop_softc *sc0, *sc1, *sc; 373 uint16_t v; 374 375 sc0 = device_lookup_private(&scoop_cd, 0); 376 sc1 = device_lookup_private(&scoop_cd, 1); 377 378 /* C3000 */ 379 if (sc1 != NULL) { 380 sc = sc0; 381 v = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR); 382 if ((v & 0x100) == 0) { 383 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR, 384 0x0101); 385 } 386 387 sc = sc1; 388 v = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR); 389 if ((v & 0x100) == 0) { 390 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR, 391 0x0101); 392 } 393 } 394 } 395 396 void 397 scoop_suspend(void) 398 { 399 struct scoop_softc *sc, *sc0, *sc1; 400 uint32_t rv; 401 402 sc0 = device_lookup_private(&scoop_cd, 0); 403 sc1 = device_lookup_private(&scoop_cd, 1); 404 405 if (sc0 != NULL) { 406 sc = sc0; 407 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 408 SCOOP_GPWR); 409 /* C3000 */ 410 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 411 sc->sc_gpwr & ~((1<<SCOOP0_MUTE_L) | (1<<SCOOP0_MUTE_R) | 412 (1<<SCOOP0_JK_A_C3000) | (1<<SCOOP0_ADC_TEMP_ON_C3000) | 413 (1<<SCOOP0_LED_GREEN))); 414 } 415 416 /* C3000 */ 417 if (sc1 != NULL) { 418 sc = sc1; 419 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 420 SCOOP_GPWR); 421 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 422 sc->sc_gpwr & ~((1<<SCOOP1_RESERVED_4) | 423 (1<<SCOOP1_RESERVED_5) | (1<<SCOOP1_RESERVED_6) | 424 (1<<SCOOP1_BACKLIGHT_CONT) | (1<<SCOOP1_BACKLIGHT_ON) | 425 (1<<SCOOP1_MIC_BIAS))); 426 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR); 427 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 428 rv | ((1<<SCOOP1_IR_ON) | (1<<SCOOP1_RESERVED_3))); 429 } 430 } 431 432 void 433 scoop_resume(void) 434 { 435 struct scoop_softc *sc, *sc0, *sc1; 436 437 sc0 = device_lookup_private(&scoop_cd, 0); 438 sc1 = device_lookup_private(&scoop_cd, 1); 439 440 if (sc0 != NULL) { 441 sc = sc0; 442 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 443 sc->sc_gpwr); 444 } 445 446 if (sc1 != NULL) { 447 sc = sc1; 448 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 449 sc->sc_gpwr); 450 } 451 } 452