1 /* $NetBSD: scoop.c,v 1.4 2007/10/17 19:58:34 garbled 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.4 2007/10/17 19:58:34 garbled 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 164 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) { 165 /* C3000 */ 166 scoop_gpio_pin_write(scoop_cd.cd_devs[1], 167 SCOOP1_BACKLIGHT_CONT, !cont); 168 scoop_gpio_pin_write(scoop_cd.cd_devs[1], 169 SCOOP1_BACKLIGHT_ON, on); 170 } 171 #if 0 172 else if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) { 173 scoop_gpio_pin_write(scoop_cd.cd_devs[0], 174 SCOOP0_BACKLIGHT_CONT, cont); 175 } 176 #endif 177 } 178 179 /* 180 * Turn the infrared LED on or off (must be on while transmitting). 181 */ 182 void 183 scoop_set_irled(int on) 184 { 185 186 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) { 187 /* IR_ON is inverted */ 188 scoop_gpio_pin_write(scoop_cd.cd_devs[1], 189 SCOOP1_IR_ON, !on); 190 } 191 } 192 193 /* 194 * Turn the green and orange LEDs on or off. If the orange LED is on, 195 * then it is wired to indicate if A/C is connected. The green LED has 196 * no such predefined function. 197 */ 198 void 199 scoop_led_set(int led, int on) 200 { 201 202 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) { 203 if ((led & SCOOP_LED_GREEN) != 0) { 204 scoop_gpio_pin_write(scoop_cd.cd_devs[0], 205 SCOOP0_LED_GREEN, on); 206 } 207 if (scoop_cd.cd_ndevs > 1 && (led & SCOOP_LED_ORANGE) != 0) { 208 scoop_gpio_pin_write(scoop_cd.cd_devs[0], 209 SCOOP0_LED_ORANGE_C3000, on); 210 } 211 } 212 } 213 214 /* 215 * Enable or disable the headphone output connection. 216 */ 217 void 218 scoop_set_headphone(int on) 219 { 220 221 if (scoop_cd.cd_ndevs < 1 || scoop_cd.cd_devs[0] == NULL) 222 return; 223 224 scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_L, 225 GPIO_PIN_OUTPUT); 226 scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_R, 227 GPIO_PIN_OUTPUT); 228 229 if (on) { 230 scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_L, 231 GPIO_PIN_HIGH); 232 scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R, 233 GPIO_PIN_HIGH); 234 } else { 235 scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_L, 236 GPIO_PIN_LOW); 237 scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R, 238 GPIO_PIN_LOW); 239 } 240 } 241 242 /* 243 * Turn on pullup resistor while not reading the remote control. 244 */ 245 void 246 scoop_akin_pullup(int enable) 247 { 248 249 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) { 250 scoop_gpio_pin_write(scoop_cd.cd_devs[1], 251 SCOOP1_AKIN_PULLUP, enable); 252 } else { 253 scoop_gpio_pin_write(scoop_cd.cd_devs[0], 254 SCOOP0_AKIN_PULLUP, enable); 255 } 256 } 257 258 void 259 scoop_battery_temp_adc(int enable) 260 { 261 262 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) { 263 scoop_gpio_pin_write(scoop_cd.cd_devs[0], 264 SCOOP0_ADC_TEMP_ON_C3000, enable); 265 } 266 } 267 268 void 269 scoop_charge_battery(int enable, int voltage_high) 270 { 271 272 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) { 273 scoop_gpio_pin_write(scoop_cd.cd_devs[0], 274 SCOOP0_JK_B_C3000, voltage_high); 275 scoop_gpio_pin_write(scoop_cd.cd_devs[0], 276 SCOOP0_CHARGE_OFF_C3000, !enable); 277 } 278 } 279 280 void 281 scoop_discharge_battery(int enable) 282 { 283 284 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) { 285 scoop_gpio_pin_write(scoop_cd.cd_devs[0], 286 SCOOP0_JK_A_C3000, enable); 287 } 288 } 289 290 /* 291 * Enable or disable 3.3V power to the SD/MMC card slot. 292 */ 293 void 294 scoop_set_sdmmc_power(int on) 295 { 296 297 scoop0_set_card_power(SD_CARD, on ? SCP_CPR_SD_3V : SCP_CPR_OFF); 298 } 299 300 /* 301 * The Card Power Register of the first SCOOP unit controls the power 302 * for the first CompactFlash slot and the SD/MMC card slot as well. 303 */ 304 void 305 scoop0_set_card_power(enum scoop_card card, int new_cpr) 306 { 307 struct scoop_softc *sc; 308 bus_space_tag_t iot; 309 bus_space_handle_t ioh; 310 uint16_t cpr; 311 312 if (scoop_cd.cd_ndevs <= 0 || scoop_cd.cd_devs[0] == NULL) 313 return; 314 315 sc = scoop_cd.cd_devs[0]; 316 iot = sc->sc_iot; 317 ioh = sc->sc_ioh; 318 319 cpr = bus_space_read_2(iot, ioh, SCOOP_CPR); 320 if (new_cpr & SCP_CPR_VOLTAGE_MSK) { 321 if (card == CF_CARD) 322 cpr |= SCP_CPR_5V; 323 else if (card == SD_CARD) 324 cpr |= SCP_CPR_SD_3V; 325 326 scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 1); 327 if (!ISSET(cpr, SCP_CPR_5V) && !ISSET(cpr, SCP_CPR_SD_3V)) 328 delay(5000); 329 bus_space_write_2(iot, ioh, SCOOP_CPR, cpr | new_cpr); 330 } else { 331 if (card == CF_CARD) 332 cpr &= ~SCP_CPR_5V; 333 else if (card == SD_CARD) 334 cpr &= ~SCP_CPR_SD_3V; 335 336 if (!ISSET(cpr, SCP_CPR_5V) && !ISSET(cpr, SCP_CPR_SD_3V)) { 337 bus_space_write_2(iot, ioh, SCOOP_CPR, SCP_CPR_OFF); 338 delay(1000); 339 scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 0); 340 } else 341 bus_space_write_2(iot, ioh, SCOOP_CPR, cpr | new_cpr); 342 } 343 } 344 345 void 346 scoop_check_mcr(void) 347 { 348 struct scoop_softc *sc; 349 uint16_t v; 350 351 /* C3000 */ 352 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) { 353 sc = scoop_cd.cd_devs[0]; 354 v = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR); 355 if ((v & 0x100) == 0) { 356 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR, 357 0x0101); 358 } 359 360 sc = scoop_cd.cd_devs[1]; 361 v = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR); 362 if ((v & 0x100) == 0) { 363 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR, 364 0x0101); 365 } 366 } 367 } 368 369 void 370 scoop_suspend(void) 371 { 372 struct scoop_softc *sc; 373 uint32_t rv; 374 375 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) { 376 sc = scoop_cd.cd_devs[0]; 377 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 378 SCOOP_GPWR); 379 /* C3000 */ 380 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 381 sc->sc_gpwr & ~((1<<SCOOP0_MUTE_L) | (1<<SCOOP0_MUTE_R) | 382 (1<<SCOOP0_JK_A_C3000) | (1<<SCOOP0_ADC_TEMP_ON_C3000) | 383 (1<<SCOOP0_LED_GREEN))); 384 } 385 386 /* C3000 */ 387 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) { 388 sc = scoop_cd.cd_devs[1]; 389 sc->sc_gpwr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 390 SCOOP_GPWR); 391 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 392 sc->sc_gpwr & ~((1<<SCOOP1_RESERVED_4) | 393 (1<<SCOOP1_RESERVED_5) | (1<<SCOOP1_RESERVED_6) | 394 (1<<SCOOP1_BACKLIGHT_CONT) | (1<<SCOOP1_BACKLIGHT_ON) | 395 (1<<SCOOP1_MIC_BIAS))); 396 rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR); 397 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 398 rv | ((1<<SCOOP1_IR_ON) | (1<<SCOOP1_RESERVED_3))); 399 } 400 } 401 402 void 403 scoop_resume(void) 404 { 405 struct scoop_softc *sc; 406 407 if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) { 408 sc = scoop_cd.cd_devs[0]; 409 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 410 sc->sc_gpwr); 411 } 412 413 if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) { 414 sc = scoop_cd.cd_devs[1]; 415 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR, 416 sc->sc_gpwr); 417 } 418 } 419