[BACK]Return to zaurus_scoop.c CVS log [TXT][DIR] Up to [local] / sys / arch / zaurus / dev

Annotation of sys/arch/zaurus/dev/zaurus_scoop.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: zaurus_scoop.c,v 1.16 2007/03/29 18:42:38 uwe Exp $   */
                      2:
                      3: /*
                      4:  * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/param.h>
                     20: #include <sys/device.h>
                     21: #include <sys/kernel.h>
                     22: #include <sys/systm.h>
                     23: #include <sys/conf.h>
                     24: #include <sys/disk.h>
                     25: #include <sys/timeout.h>
                     26: #include <sys/gpio.h>
                     27:
                     28: #include <machine/bus.h>
                     29:
                     30: #include <arm/xscale/pxa2x0var.h>
                     31:
                     32: #include <machine/zaurus_reg.h>
                     33: #include <machine/zaurus_var.h>
                     34:
                     35: #include <zaurus/dev/zaurus_scoopreg.h>
                     36: #include <zaurus/dev/zaurus_scoopvar.h>
                     37:
                     38: struct scoop_softc {
                     39:        struct device sc_dev;
                     40:        bus_space_tag_t sc_iot;
                     41:        bus_space_handle_t sc_ioh;
                     42:        u_int16_t sc_gpwr;      /* GPIO state before suspend */
                     43:        void *sc_powerhook;
                     44:        int sc_suspended;
                     45: };
                     46:
                     47: int    scoopmatch(struct device *, void *, void *);
                     48: void   scoopattach(struct device *, struct device *, void *);
                     49:
                     50: struct cfattach scoop_ca = {
                     51:        sizeof (struct scoop_softc), scoopmatch, scoopattach
                     52: };
                     53:
                     54: struct cfdriver scoop_cd = {
                     55:        NULL, "scoop", DV_DULL
                     56: };
                     57:
                     58: enum card {
                     59:        SD_CARD,
                     60:        CF_CARD                 /* socket 0 (external) */
                     61: };
                     62:
                     63: int    scoop_gpio_pin_read(struct scoop_softc *sc, int);
                     64: void   scoop_gpio_pin_write(struct scoop_softc *sc, int, int);
                     65: void   scoop_gpio_pin_ctl(struct scoop_softc *sc, int, int);
                     66: void   scoop0_set_card_power(enum card, int);
                     67:
                     68: struct timeout scoop_checkdisk;
                     69: void   scoop_timeout(void *);
                     70: void   scoop_power(int, void *);
                     71:
                     72: int
                     73: scoopmatch(struct device *parent, void *match, void *aux)
                     74: {
                     75:        struct cfdata *cf = match;
                     76:
                     77:        /*
                     78:         * Only C3000-like models are known to have two SCOOPs.
                     79:         */
                     80:         if (ZAURUS_ISC3000)
                     81:                return (cf->cf_unit < 2);
                     82:
                     83:        return (cf->cf_unit == 0);
                     84: }
                     85:
                     86: void
                     87: scoopattach(struct device *parent, struct device *self, void *aux)
                     88: {
                     89:        struct pxaip_attach_args *pxa = aux;
                     90:        struct scoop_softc *sc = (struct scoop_softc *)self;
                     91:        bus_addr_t addr;
                     92:        bus_size_t size;
                     93:
                     94:        sc->sc_iot = pxa->pxa_iot;
                     95:
                     96:        if (pxa->pxa_addr != -1)
                     97:                addr = pxa->pxa_addr;
                     98:        else if (sc->sc_dev.dv_unit == 0)
                     99:                addr = C3000_SCOOP0_BASE;
                    100:        else
                    101:                addr = C3000_SCOOP1_BASE;
                    102:
                    103:        size = pxa->pxa_size < SCOOP_SIZE ? SCOOP_SIZE : pxa->pxa_size;
                    104:
                    105:        if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
                    106:                printf(": failed to map %s\n", sc->sc_dev.dv_xname);
                    107:                return;
                    108:        }
                    109:
                    110:        if (ZAURUS_ISC3000 && sc->sc_dev.dv_unit == 1) {
                    111:                scoop_gpio_pin_ctl(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_OUTPUT);
                    112:                scoop_gpio_pin_write(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_LOW);
                    113:        } else if (!ZAURUS_ISC3000) {
                    114:                scoop_gpio_pin_ctl(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_OUTPUT);
                    115:                scoop_gpio_pin_write(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_LOW);
                    116:        }
                    117:
                    118:        if (sc->sc_dev.dv_unit == 0)
                    119:                timeout_set(&scoop_checkdisk, scoop_timeout, sc);
                    120:
                    121:        printf(": PCMCIA/GPIO controller\n");
                    122:
                    123:        sc->sc_powerhook = powerhook_establish(scoop_power, sc);
                    124:        if (sc->sc_powerhook == NULL)
                    125:                panic("Unable to establish %s powerhook",
                    126:                    sc->sc_dev.dv_xname);
                    127: }
                    128:
                    129: int
                    130: scoop_gpio_pin_read(struct scoop_softc *sc, int pin)
                    131: {
                    132:        u_int16_t rv;
                    133:        u_int16_t bit = (1 << pin);
                    134:
                    135:        rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR);
                    136:        return (rv & bit) != 0 ? 1 : 0;
                    137: }
                    138:
                    139: void
                    140: scoop_gpio_pin_write(struct scoop_softc *sc, int pin, int level)
                    141: {
                    142:        u_int16_t rv;
                    143:        u_int16_t bit = (1 << pin);
                    144:        int s;
                    145:
                    146:        s = splhigh();
                    147:        rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR);
                    148:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
                    149:            level == GPIO_PIN_LOW ? (rv & ~bit) : (rv | bit));
                    150:        splx(s);
                    151: }
                    152:
                    153: void
                    154: scoop_gpio_pin_ctl(struct scoop_softc *sc, int pin, int flags)
                    155: {
                    156:        u_int16_t rv;
                    157:        u_int16_t bit = (1 << pin);
                    158:
                    159:        rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR);
                    160:        switch (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
                    161:        case GPIO_PIN_INPUT:
                    162:                rv &= ~bit;
                    163:                break;
                    164:        case GPIO_PIN_OUTPUT:
                    165:                rv |= bit;
                    166:                break;
                    167:        }
                    168:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPCR, rv);
                    169: }
                    170:
                    171: /*
                    172:  * Turn the LCD background light and contrast signal on or off.
                    173:  */
                    174: void
                    175: scoop_set_backlight(int on, int cont)
                    176: {
                    177:
                    178:        if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) {
                    179:                /* C3000 */
                    180:                scoop_gpio_pin_write(scoop_cd.cd_devs[1],
                    181:                    SCOOP1_BACKLIGHT_CONT, !cont);
                    182:                scoop_gpio_pin_write(scoop_cd.cd_devs[1],
                    183:                    SCOOP1_BACKLIGHT_ON, on);
                    184:        }
                    185: #if 0
                    186:        else if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
                    187:                scoop_gpio_pin_write(scoop_cd.cd_devs[0],
                    188:                    SCOOP0_BACKLIGHT_CONT, cont);
                    189:        }
                    190: #endif
                    191: }
                    192:
                    193: /*
                    194:  * Turn the infrared LED on or off (must be on while transmitting).
                    195:  */
                    196: void
                    197: scoop_set_irled(int on)
                    198: {
                    199:        if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL)
                    200:                /* IR_ON is inverted */
                    201:                scoop_gpio_pin_write(scoop_cd.cd_devs[1],
                    202:                    SCOOP1_IR_ON, !on);
                    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:
                    214:        if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
                    215:                if ((led & SCOOP_LED_GREEN) != 0)
                    216:                        scoop_gpio_pin_write(scoop_cd.cd_devs[0],
                    217:                            SCOOP0_LED_GREEN, on);
                    218:                if (scoop_cd.cd_ndevs > 1 && (led & SCOOP_LED_ORANGE) != 0)
                    219:                        scoop_gpio_pin_write(scoop_cd.cd_devs[0],
                    220:                            SCOOP0_LED_ORANGE_C3000, on);
                    221:        }
                    222: }
                    223:
                    224: /*
                    225:  * Enable or disable the headphone output connection.
                    226:  */
                    227: void
                    228: scoop_set_headphone(int on)
                    229: {
                    230:        if (scoop_cd.cd_ndevs < 1 || scoop_cd.cd_devs[0] == NULL)
                    231:                return;
                    232:
                    233:        scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_L,
                    234:            GPIO_PIN_OUTPUT);
                    235:        scoop_gpio_pin_ctl(scoop_cd.cd_devs[0], SCOOP0_MUTE_R,
                    236:            GPIO_PIN_OUTPUT);
                    237:
                    238:        if (on) {
                    239:                scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_L,
                    240:                    GPIO_PIN_HIGH);
                    241:                scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R,
                    242:                    GPIO_PIN_HIGH);
                    243:        } else {
                    244:                scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_L,
                    245:                    GPIO_PIN_LOW);
                    246:                scoop_gpio_pin_write(scoop_cd.cd_devs[0], SCOOP0_MUTE_R,
                    247:                    GPIO_PIN_LOW);
                    248:        }
                    249: }
                    250:
                    251: /*
                    252:  * Enable or disable 3.3V power to the SD/MMC card slot.
                    253:  */
                    254: void
                    255: scoop_set_sdmmc_power(int on)
                    256: {
                    257:        scoop0_set_card_power(SD_CARD, on ? SCP_CPR_SD_3V : SCP_CPR_OFF);
                    258: }
                    259:
                    260: /*
                    261:  * The Card Power Register of the first SCOOP unit controls the power
                    262:  * for the first CompactFlash slot and the SD/MMC card slot as well.
                    263:  */
                    264: void
                    265: scoop0_set_card_power(enum card slot, int new_cpr)
                    266: {
                    267:        struct scoop_softc *sc = scoop_cd.cd_devs[0];
                    268:        u_int16_t cpr;
                    269:
                    270:        cpr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_CPR);
                    271:        if (new_cpr & SCP_CPR_VOLTAGE_MSK) {
                    272:                if (slot == CF_CARD)
                    273:                        cpr |= SCP_CPR_5V;
                    274:                else if (slot == SD_CARD)
                    275:                        cpr |= SCP_CPR_SD_3V;
                    276:
                    277:                scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 1);
                    278:                if (!ISSET(cpr, SCP_CPR_5V) && !ISSET(cpr, SCP_CPR_SD_3V))
                    279:                        delay(5000);
                    280:                bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_CPR,
                    281:                    cpr | new_cpr);
                    282:        } else {
                    283:                if (slot == CF_CARD)
                    284:                        cpr &= ~SCP_CPR_5V;
                    285:                else if (slot == SD_CARD)
                    286:                        cpr &= ~SCP_CPR_SD_3V;
                    287:
                    288:                if (!ISSET(cpr, SCP_CPR_5V) && !ISSET(cpr, SCP_CPR_SD_3V)) {
                    289:                        bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_CPR,
                    290:                            SCP_CPR_OFF);
                    291:                        delay(1000);
                    292:                        scoop_gpio_pin_write(sc, SCOOP0_CF_POWER_C3000, 0);
                    293:                } else
                    294:                        bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_CPR,
                    295:                            cpr | new_cpr);
                    296:        }
                    297: }
                    298:
                    299: /*
                    300:  * Turn on pullup resistor while not reading the remote control.
                    301:  */
                    302: void
                    303: scoop_akin_pullup(int enable)
                    304: {
                    305:        if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL)
                    306:                scoop_gpio_pin_write(scoop_cd.cd_devs[1],
                    307:                    SCOOP1_AKIN_PULLUP, enable);
                    308:        else
                    309:                scoop_gpio_pin_write(scoop_cd.cd_devs[0],
                    310:                    SCOOP0_AKIN_PULLUP, enable);
                    311: }
                    312:
                    313: void
                    314: scoop_battery_temp_adc(int enable)
                    315: {
                    316:
                    317:        if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL)
                    318:                scoop_gpio_pin_write(scoop_cd.cd_devs[0],
                    319:                    SCOOP0_ADC_TEMP_ON_C3000, enable);
                    320: }
                    321:
                    322: void
                    323: scoop_charge_battery(int enable, int voltage_high)
                    324: {
                    325:
                    326:        if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
                    327:                scoop_gpio_pin_write(scoop_cd.cd_devs[0],
                    328:                    SCOOP0_JK_B_C3000, voltage_high);
                    329:                scoop_gpio_pin_write(scoop_cd.cd_devs[0],
                    330:                    SCOOP0_CHARGE_OFF_C3000, !enable);
                    331:        }
                    332: }
                    333:
                    334: void
                    335: scoop_discharge_battery(int enable)
                    336: {
                    337:
                    338:        if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL)
                    339:                scoop_gpio_pin_write(scoop_cd.cd_devs[0],
                    340:                    SCOOP0_JK_A_C3000, enable);
                    341: }
                    342:
                    343: /* XXX */
                    344: void scoop_check_mcr(void);
                    345: void
                    346: scoop_check_mcr(void)
                    347: {
                    348:        struct  scoop_softc *sc;
                    349:
                    350:        /* C3000 */
                    351:        if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) {
                    352:
                    353:                sc = scoop_cd.cd_devs[0];
                    354:                if ((bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR) &
                    355:                    0x100) == 0)
                    356:                        bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR,
                    357:                            0x0101);
                    358:
                    359:                sc = scoop_cd.cd_devs[1];
                    360:                if ((bus_space_read_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR) &
                    361:                    0x100) == 0)
                    362:                        bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_MCR,
                    363:                            0x0101);
                    364:        }
                    365: }
                    366:
                    367: void
                    368: scoop_suspend(void)
                    369: {
                    370:        struct scoop_softc *sc;
                    371:        u_int32_t rv;
                    372:
                    373:        scoop_check_mcr();
                    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:        scoop_check_mcr();
                    408:
                    409:        if (scoop_cd.cd_ndevs > 0 && scoop_cd.cd_devs[0] != NULL) {
                    410:                sc = scoop_cd.cd_devs[0];
                    411:                bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
                    412:                    sc->sc_gpwr);
                    413:        }
                    414:
                    415:        if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) {
                    416:                sc = scoop_cd.cd_devs[1];
                    417:                bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCOOP_GPWR,
                    418:                    sc->sc_gpwr);
                    419:        }
                    420: }
                    421:
                    422: void
                    423: scoop_timeout(void *v)
                    424: {
                    425:        extern struct disklist_head disklist;
                    426:        struct scoop_softc *sc = v;
                    427:        static struct disk *dk;
                    428:        static int state = 0;
                    429:
                    430:        if (dk == NULL) {
                    431:                for (dk = TAILQ_FIRST(&disklist); dk;
                    432:                    dk = TAILQ_NEXT(dk, dk_link))
                    433:                        if (dk->dk_name &&
                    434:                            strcmp(dk->dk_name, "wd0") == 0)
                    435:                                break;
                    436:        }
                    437:
                    438:        if (sc->sc_suspended)
                    439:                state = -1;
                    440:        else if (dk) {
                    441:                int newstate = (dk->dk_busy ? 1 : 0);
                    442:
                    443:                if (newstate != state) {
                    444:                        state = newstate;
                    445:                        scoop_led_set(SCOOP_LED_GREEN, newstate);
                    446:                }
                    447:        }
                    448:        timeout_add(&scoop_checkdisk, hz/25);
                    449: }
                    450:
                    451: void
                    452: scoop_power(int why, void *arg)
                    453: {
                    454:        struct scoop_softc *sc = arg;
                    455:
                    456:        switch (why) {
                    457:        case PWR_STANDBY:
                    458:        case PWR_SUSPEND:
                    459:                /*
                    460:                 * Nothing should use the scoop from this point on.
                    461:                 * No timeouts, no interrupts (even though interrupts
                    462:                 * are still enabled).  scoop_timeout() respects the
                    463:                 * sc_suspended flag.
                    464:                 */
                    465:                if (sc->sc_dev.dv_unit == 0) {
                    466:                        sc->sc_suspended = 1;
                    467:                        scoop_suspend();
                    468:                }
                    469:                break;
                    470:        case PWR_RESUME:
                    471:                if (sc->sc_dev.dv_unit == 0) {
                    472:                        scoop_resume();
                    473:                        sc->sc_suspended = 0;
                    474:                }
                    475:                break;
                    476:        }
                    477: }

CVSweb