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