File: [local] / sys / arch / arm / sa11x0 / sa1111_gpio.c (download)
Revision 1.1, Wed Mar 5 13:34:26 2008 UTC (16 years, 3 months ago) by nbrk
Branch: MAIN
CVS Tags: HEAD
driver for SA-1111 GPIO controller;
it has three GPIO banks (GPIO_A, B, C):
bank A controls 4 i/o lines;
bank B controls 6 lines;
bank C controls 8 lines;
Implemented functions for value (level) and direction changes.
|
/* $Id: sa1111_gpio.c,v 1.1 2008/03/05 13:34:26 nbrk Exp $ */
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/evcount.h>
#include <sys/queue.h>
#include <uvm/uvm_extern.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/lock.h>
#include <arm/sa11x0/sa11x1_var.h>
#include <arm/sa11x0/sa1111_reg.h>
#include <arm/sa11x0/sa1111_intr.h>
#include <arm/sa11x0/sa1111_gpiovar.h>
/*
* 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);
}