[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     ! 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