arm: xilinx: gpio: Make the driver more generic
All other Zynq SoCs have the same GPIO controller, the only difference is the number of banks/pins so make this driver more generic to add other SoCs more easily. No functional changes intended. Sponsored by: Beckhoff Automation GmbH & Co. KG MFC after: 2 weeks
This commit is contained in:
+91
-25
@@ -70,16 +70,30 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "gpio_if.h"
|
||||
|
||||
#define NUMBANKS 4
|
||||
#define MAXPIN (32*NUMBANKS)
|
||||
#define ZYNQ_MAX_BANK 4
|
||||
|
||||
#define MIO_PIN 0 /* pins 0-53 go to MIO */
|
||||
#define NUM_MIO_PINS 54
|
||||
#define EMIO_PIN 64 /* pins 64-127 go to PL */
|
||||
#define NUM_EMIO_PINS 64
|
||||
/* Zynq 7000 */
|
||||
#define ZYNQ_BANK0_PIN_MIN 0
|
||||
#define ZYNQ_BANK0_NPIN 32
|
||||
#define ZYNQ_BANK1_PIN_MIN 32
|
||||
#define ZYNQ_BANK1_NPIN 22
|
||||
#define ZYNQ_BANK2_PIN_MIN 64
|
||||
#define ZYNQ_BANK2_NPIN 32
|
||||
#define ZYNQ_BANK3_PIN_MIN 96
|
||||
#define ZYNQ_BANK3_NPIN 32
|
||||
#define ZYNQ_PIN_MIO_MIN 0
|
||||
#define ZYNQ_PIN_MIO_MAX 54
|
||||
#define ZYNQ_PIN_EMIO_MIN 64
|
||||
#define ZYNQ_PIN_EMIO_MAX 118
|
||||
|
||||
#define VALID_PIN(u) (((u) >= MIO_PIN && (u) < MIO_PIN + NUM_MIO_PINS) || \
|
||||
((u) >= EMIO_PIN && (u) < EMIO_PIN + NUM_EMIO_PINS))
|
||||
#define ZYNQ_BANK_NPIN(bank) (ZYNQ_BANK##bank##_NPIN)
|
||||
#define ZYNQ_BANK_PIN_MIN(bank) (ZYNQ_BANK##bank##_PIN_MIN)
|
||||
#define ZYNQ_BANK_PIN_MAX(bank) (ZYNQ_BANK##bank##_PIN_MIN + ZYNQ_BANK##bank##_NPIN - 1)
|
||||
|
||||
#define ZYNQ_PIN_IS_MIO(pin) (pin >= ZYNQ_PIN_MIO_MIN && \
|
||||
pin <= ZYNQ_PIN_MIO_MAX)
|
||||
#define ZYNQ_PIN_IS_EMIO(pin) (pin >= ZYNQ_PIN_EMIO_MIN && \
|
||||
pin <= ZYNQ_PIN_EMIO_MAX)
|
||||
|
||||
#define ZGPIO_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
|
||||
#define ZGPIO_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
|
||||
@@ -88,11 +102,39 @@ __FBSDID("$FreeBSD$");
|
||||
"gpio", MTX_DEF)
|
||||
#define ZGPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
|
||||
|
||||
struct zynq_gpio_conf {
|
||||
char *name;
|
||||
uint32_t nbanks;
|
||||
uint32_t maxpin;
|
||||
uint32_t bank_min[ZYNQ_MAX_BANK];
|
||||
uint32_t bank_max[ZYNQ_MAX_BANK];
|
||||
};
|
||||
|
||||
struct zy7_gpio_softc {
|
||||
device_t dev;
|
||||
device_t busdev;
|
||||
struct mtx sc_mtx;
|
||||
struct resource *mem_res; /* Memory resource */
|
||||
device_t dev;
|
||||
device_t busdev;
|
||||
struct mtx sc_mtx;
|
||||
struct resource *mem_res; /* Memory resource */
|
||||
struct zynq_gpio_conf *conf;
|
||||
};
|
||||
|
||||
static struct zynq_gpio_conf z7_gpio_conf = {
|
||||
.name = "Zynq-7000 GPIO Controller",
|
||||
.nbanks = ZYNQ_MAX_BANK,
|
||||
.maxpin = ZYNQ_PIN_EMIO_MAX,
|
||||
.bank_min[0] = ZYNQ_BANK_PIN_MIN(0),
|
||||
.bank_max[0] = ZYNQ_BANK_PIN_MAX(0),
|
||||
.bank_min[1] = ZYNQ_BANK_PIN_MIN(1),
|
||||
.bank_max[1] = ZYNQ_BANK_PIN_MAX(1),
|
||||
.bank_min[2] = ZYNQ_BANK_PIN_MIN(2),
|
||||
.bank_max[2] = ZYNQ_BANK_PIN_MAX(2),
|
||||
.bank_min[3] = ZYNQ_BANK_PIN_MIN(3),
|
||||
.bank_max[3] = ZYNQ_BANK_PIN_MAX(3),
|
||||
};
|
||||
|
||||
static struct ofw_compat_data compat_data[] = {
|
||||
{"xlnx,zy7_gpio", (uintptr_t)&z7_gpio_conf},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
#define WR4(sc, off, val) bus_write_4((sc)->mem_res, (off), (val))
|
||||
@@ -128,17 +170,37 @@ zy7_gpio_get_bus(device_t dev)
|
||||
static int
|
||||
zy7_gpio_pin_max(device_t dev, int *maxpin)
|
||||
{
|
||||
struct zy7_gpio_softc *sc;
|
||||
|
||||
*maxpin = MAXPIN;
|
||||
sc = device_get_softc(dev);
|
||||
*maxpin = sc->conf->maxpin;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
zy7_pin_valid(device_t dev, uint32_t pin)
|
||||
{
|
||||
struct zy7_gpio_softc *sc;
|
||||
int i;
|
||||
bool found = false;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
for (i = 0; i < sc->conf->nbanks; i++) {
|
||||
if (pin >= sc->conf->bank_min[i] && pin <= sc->conf->bank_max[i]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (found);
|
||||
}
|
||||
|
||||
/* Get a specific pin's capabilities. */
|
||||
static int
|
||||
zy7_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
|
||||
{
|
||||
|
||||
if (!VALID_PIN(pin))
|
||||
if (!zy7_pin_valid(dev, pin))
|
||||
return (EINVAL);
|
||||
|
||||
*caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
|
||||
@@ -151,14 +213,14 @@ static int
|
||||
zy7_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
|
||||
{
|
||||
|
||||
if (!VALID_PIN(pin))
|
||||
if (!zy7_pin_valid(dev, pin))
|
||||
return (EINVAL);
|
||||
|
||||
if (pin < NUM_MIO_PINS) {
|
||||
if (ZYNQ_PIN_IS_MIO(pin)) {
|
||||
snprintf(name, GPIOMAXNAME, "MIO_%d", pin);
|
||||
name[GPIOMAXNAME - 1] = '\0';
|
||||
} else {
|
||||
snprintf(name, GPIOMAXNAME, "EMIO_%d", pin - EMIO_PIN);
|
||||
snprintf(name, GPIOMAXNAME, "EMIO_%d", pin - ZYNQ_PIN_EMIO_MIN);
|
||||
name[GPIOMAXNAME - 1] = '\0';
|
||||
}
|
||||
|
||||
@@ -171,7 +233,7 @@ zy7_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
|
||||
{
|
||||
struct zy7_gpio_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (!VALID_PIN(pin))
|
||||
if (!zy7_pin_valid(dev, pin))
|
||||
return (EINVAL);
|
||||
|
||||
ZGPIO_LOCK(sc);
|
||||
@@ -197,7 +259,7 @@ zy7_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
|
||||
{
|
||||
struct zy7_gpio_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (!VALID_PIN(pin))
|
||||
if (!zy7_pin_valid(dev, pin))
|
||||
return (EINVAL);
|
||||
|
||||
ZGPIO_LOCK(sc);
|
||||
@@ -234,7 +296,7 @@ zy7_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
|
||||
{
|
||||
struct zy7_gpio_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (!VALID_PIN(pin) || value > 1)
|
||||
if (!zy7_pin_valid(dev, pin) || value > 1)
|
||||
return (EINVAL);
|
||||
|
||||
/* Fancy register tricks allow atomic set or reset. */
|
||||
@@ -256,7 +318,7 @@ zy7_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
|
||||
{
|
||||
struct zy7_gpio_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (!VALID_PIN(pin))
|
||||
if (!zy7_pin_valid(dev, pin))
|
||||
return (EINVAL);
|
||||
|
||||
*value = (RD4(sc, ZY7_GPIO_DATA_RO(pin >> 5)) >> (pin & 31)) & 1;
|
||||
@@ -270,7 +332,7 @@ zy7_gpio_pin_toggle(device_t dev, uint32_t pin)
|
||||
{
|
||||
struct zy7_gpio_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (!VALID_PIN(pin))
|
||||
if (!zy7_pin_valid(dev, pin))
|
||||
return (EINVAL);
|
||||
|
||||
ZGPIO_LOCK(sc);
|
||||
@@ -286,14 +348,16 @@ zy7_gpio_pin_toggle(device_t dev, uint32_t pin)
|
||||
static int
|
||||
zy7_gpio_probe(device_t dev)
|
||||
{
|
||||
struct zynq_gpio_conf *conf;
|
||||
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
if (!ofw_bus_is_compatible(dev, "xlnx,zy7_gpio"))
|
||||
conf = (struct zynq_gpio_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
|
||||
if (conf == 0)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "Zynq-7000 GPIO driver");
|
||||
device_set_desc(dev, conf->name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -306,6 +370,7 @@ zy7_gpio_attach(device_t dev)
|
||||
int rid;
|
||||
|
||||
sc->dev = dev;
|
||||
sc->conf = (struct zynq_gpio_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
|
||||
|
||||
ZGPIO_LOCK_INIT(sc);
|
||||
|
||||
@@ -372,4 +437,5 @@ static driver_t zy7_gpio_driver = {
|
||||
sizeof(struct zy7_gpio_softc),
|
||||
};
|
||||
|
||||
DRIVER_MODULE(zy7_gpio, simplebus, zy7_gpio_driver, NULL, NULL);
|
||||
EARLY_DRIVER_MODULE(zy7_gpio, simplebus, zy7_gpio_driver, 0, 0,
|
||||
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
|
||||
|
||||
Reference in New Issue
Block a user