/* $Id: sa1111_gpio.c,v 1.1 2008/03/05 13:34:26 nbrk Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * SA-1111 GPIO controller. * It featurs three blocks: * - GPIO_A[0:3] * - GPIO_B[0:5] * - GPIO_C[0:7] * We can control data value (level) and direction individually for each pin. */ struct sacgpio_softc { struct device sc_dev; bus_space_tag_t sc_bust; bus_space_handle_t sc_bush; }; /* autoconf glue */ int sacgpio_match(struct device *parent, void *cf, void *aux); void sacgpio_attach(struct device *parent, struct device *self, void *aux); struct cfattach sacgpio_ca = { sizeof(struct sacgpio_softc), sacgpio_match, sacgpio_attach, NULL, NULL }; struct cfdriver sacgpio_cd = { NULL, "sacgpio", DV_DULL }; struct sacgpio_softc *sacgpio_sc; int sacgpio_match(struct device *parent, void *cf, void *aux) { struct sacc_attach_args *saa = aux; if (saa->sac_typecookie == SACC_TYPE_GPIO && sacgpio_sc == NULL) return(1); return(0); } void sacgpio_attach(struct device *parent, struct device *self, void *aux) { struct sacgpio_softc *sc = (struct sacgpio_softc*)self; struct sacc_attach_args *saa = aux; sc->sc_bust = saa->sac_iot; sc->sc_bush = saa->sac_bush; /* * Nothing to do. Just register default sc and return. */ printf(": SA-1111 GPIO controller\n"); sacgpio_sc = sc; } /* * Read value of port x. */ int sa1111_gpio_get_bit(int gpiobank, uint8_t gpio) { struct sacgpio_softc *sc = sacgpio_sc; bus_addr_t reg; if (sc == NULL) panic("sa1111_gpio_get_bit: sacgpio not configured"); /* select bank */ switch (gpiobank) { case SACGPIO_BANKA: /* block A has only 4 pins */ if (gpio > 3) panic("%s: sa1111_gpio_get_bit: bogus gpio %d in bank A", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOA_DVR; break; case SACGPIO_BANKB: /* block B has only 6 pins */ if (gpio > 5) panic("%s: sa1111_gpio_get_bit: bogus gpio %d in bank B", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOB_DVR; break; case SACGPIO_BANKC: reg = SACCGPIOC_DVR; break; default: panic("%s: sa1111_gpio_get_bit: bogus gpio bank 0x%x", sc->sc_dev.dv_xname, gpiobank); } return( bus_space_read_4(sc->sc_bust, sc->sc_bush, reg) & (1 << gpio) ); } /* * Set value of port x to 1. */ void sa1111_gpio_set_bit(int gpiobank, uint8_t gpio) { struct sacgpio_softc *sc = sacgpio_sc; bus_addr_t reg; uint32_t oldval; if (sc == NULL) panic("sa1111_gpio_set_bit: sacgpio not configured"); /* select bank */ switch (gpiobank) { case SACGPIO_BANKA: /* block A has only 4 pins */ if (gpio > 3) panic("%s: sa1111_gpio_set_bit: bogus gpio %d in bank A", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOA_DVR; break; case SACGPIO_BANKB: /* block B has only 6 pins */ if (gpio > 5) panic("%s: sa1111_gpio_set_bit: bogus gpio %d in bank B", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOB_DVR; break; case SACGPIO_BANKC: reg = SACCGPIOC_DVR; break; default: panic("%s: sa1111_gpio_set_bit: bogus gpio bank 0x%x", sc->sc_dev.dv_xname, gpiobank); } oldval = bus_space_read_4(sc->sc_bust, sc->sc_bush, reg); bus_space_write_4(sc->sc_bust, sc->sc_bush, reg, oldval | 1 << gpio); } /* * Set value of port x to 0. */ void sa1111_gpio_clear_bit(int gpiobank, uint8_t gpio) { struct sacgpio_softc *sc = sacgpio_sc; bus_addr_t reg; uint32_t oldval; if (sc == NULL) panic("sa1111_gpio_glear_bit: sacgpio not configured"); /* select bank */ switch (gpiobank) { case SACGPIO_BANKA: /* block A has only 4 pins */ if (gpio > 3) panic("%s: sa1111_gpio_clear_bit: bogus gpio %d in bank A", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOA_DVR; break; case SACGPIO_BANKB: /* block B has only 6 pins */ if (gpio > 5) panic("%s: sa1111_gpio_clear_bit: bogus gpio %d in bank B", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOB_DVR; break; case SACGPIO_BANKC: reg = SACCGPIOC_DVR; break; default: panic("%s: sa1111_gpio_clear_sit: bogus gpio bank 0x%x", sc->sc_dev.dv_xname, gpiobank); } oldval = bus_space_read_4(sc->sc_bust, sc->sc_bush, reg); bus_space_write_4(sc->sc_bust, sc->sc_bush, reg, oldval & ~(1 << gpio)); } /* * Set port direction. */ void sa1111_gpio_set_dir(int gpiobank, uint8_t gpio, int dir) { struct sacgpio_softc *sc = sacgpio_sc; bus_addr_t reg; uint32_t olddir; if (sc == NULL) panic("sa1111_gpio_set_dir: sacgpio not configured"); /* select bank */ switch (gpiobank) { case SACGPIO_BANKA: /* block A has only 4 pins */ if (gpio > 3) panic("%s: sa1111_gpio_set_dir: bogus gpio %d in bank A", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOA_DDR; break; case SACGPIO_BANKB: /* block B has only 6 pins */ if (gpio > 5) panic("%s: sa1111_gpio_set_dir: bogus gpio %d in bank B", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOB_DDR; break; case SACGPIO_BANKC: reg = SACCGPIOC_DDR; break; default: panic("%s: sa1111_gpio_set_dir: bogus gpio bank 0x%x", sc->sc_dev.dv_xname, gpiobank); } /* direction */ olddir = bus_space_read_4(sc->sc_bust, sc->sc_bush, reg); switch (dir) { case SACGPIO_DIR_INPUT: olddir |= 1 << gpio; break; case SACGPIO_DIR_OUTPUT: olddir &= ~(1 << gpio); break; default: panic("%s: sa1111_gpio_set_dir: bogus direction 0x%x", sc->sc_dev.dv_xname, dir); } bus_space_write_4(sc->sc_bust, sc->sc_bush, reg, olddir); } /* * Get port direction. */ u_int sa1111_gpio_get_dir(int gpiobank, uint8_t gpio) { struct sacgpio_softc *sc = sacgpio_sc; bus_addr_t reg; int dir; if (sc == NULL) panic("sa1111_gpio_get_dir: sacgpio not configured"); /* select bank */ switch (gpiobank) { case SACGPIO_BANKA: /* block A has only 4 pins */ if (gpio > 3) panic("%s: sa1111_gpio_get_dir: bogus gpio %d in bank A", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOA_DDR; break; case SACGPIO_BANKB: /* block B has only 6 pins */ if (gpio > 5) panic("%s: sa1111_gpio_get_dir: bogus gpio %d in bank B", sc->sc_dev.dv_xname, gpio); reg = SACCGPIOB_DDR; break; case SACGPIO_BANKC: reg = SACCGPIOC_DDR; break; default: panic("%s: sa1111_gpio_get_dir: bogus gpio bank 0x%x", sc->sc_dev.dv_xname, gpiobank); } dir = bus_space_read_4(sc->sc_bust, sc->sc_bush, reg) & ~(1 << gpio); return (dir ? SACGPIO_DIR_INPUT : SACGPIO_DIR_OUTPUT); }