#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/proc.h>
#include <sys/rman.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/gpio.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <machine/intr.h>
#include <dev/gpio/gpiobusvar.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/clk/clk.h>
#include "gpio_if.h"
#include "pic_if.h"
#include "fdt_pinctrl_if.h"
enum gpio_regs {
RK_GPIO_SWPORTA_DR = 1,
RK_GPIO_SWPORTA_DDR,
RK_GPIO_INTEN,
RK_GPIO_INTMASK,
RK_GPIO_INTTYPE_LEVEL,
RK_GPIO_INTTYPE_BOTH,
RK_GPIO_INT_POLARITY,
RK_GPIO_INT_STATUS,
RK_GPIO_INT_RAWSTATUS,
RK_GPIO_DEBOUNCE,
RK_GPIO_PORTA_EOI,
RK_GPIO_EXT_PORTA,
RK_GPIO_REGNUM
};
#define RK_GPIO_LS_SYNC 0x60
#define RK_GPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_INTR_EDGE_BOTH | \
GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING | \
GPIO_INTR_LEVEL_HIGH | GPIO_INTR_LEVEL_LOW)
#define GPIO_FLAGS_PINCTRL (GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)
#define RK_GPIO_MAX_PINS 32
struct pin_cached {
uint8_t is_gpio;
uint32_t flags;
};
struct rk_pin_irqsrc {
struct intr_irqsrc isrc;
uint32_t irq;
uint32_t mode;
};
struct rk_gpio_reg {
uint8_t single;
uint8_t offset;
};
struct rk_gpio_softc {
device_t sc_dev;
device_t sc_busdev;
struct mtx sc_mtx;
struct resource *sc_res[2];
bus_space_tag_t sc_bst;
bus_space_handle_t sc_bsh;
clk_t clk;
device_t pinctrl;
uint32_t swporta;
uint32_t swporta_ddr;
uint32_t version;
struct pin_cached pin_cached[RK_GPIO_MAX_PINS];
struct rk_gpio_reg regs[RK_GPIO_REGNUM];
void *ihandle;
struct rk_pin_irqsrc isrcs[RK_GPIO_MAX_PINS];
};
static struct ofw_compat_data compat_data[] = {
{"rockchip,gpio-bank", 1},
{NULL, 0}
};
static struct resource_spec rk_gpio_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ -1, 0 }
};
#define RK_GPIO_VERSION 0x78
#define RK_GPIO_TYPE_V1 0x00000000
#define RK_GPIO_TYPE_V2 0x01000c2b
#define RK_GPIO_ISRC(sc, irq) (&(sc->isrcs[irq].isrc))
static int rk_gpio_detach(device_t dev);
#define RK_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx)
#define RK_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx)
#define RK_GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
#define RK_GPIO_WRITE(_sc, _off, _val) \
bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
#define RK_GPIO_READ(_sc, _off) \
bus_space_read_4(_sc->sc_bst, _sc->sc_bsh, _off)
static int
rk_gpio_read_bit(struct rk_gpio_softc *sc, int reg, int bit)
{
struct rk_gpio_reg *rk_reg = &sc->regs[reg];
uint32_t value;
if (rk_reg->single) {
value = RK_GPIO_READ(sc, rk_reg->offset);
value >>= bit;
} else {
value = RK_GPIO_READ(sc, bit > 15 ?
rk_reg->offset + 4 : rk_reg->offset);
value >>= (bit % 16);
}
return (value & 1);
}
static void
rk_gpio_write_bit(struct rk_gpio_softc *sc, int reg, int bit, int data)
{
struct rk_gpio_reg *rk_reg = &sc->regs[reg];
uint32_t value;
if (rk_reg->single) {
value = RK_GPIO_READ(sc, rk_reg->offset);
if (data)
value |= (1 << bit);
else
value &= ~(1 << bit);
RK_GPIO_WRITE(sc, rk_reg->offset, value);
} else {
if (data)
value = (1 << (bit % 16));
else
value = 0;
value |= (1 << ((bit % 16) + 16));
RK_GPIO_WRITE(sc, bit > 15 ?
rk_reg->offset + 4 : rk_reg->offset, value);
}
}
static uint32_t
rk_gpio_read_4(struct rk_gpio_softc *sc, int reg)
{
struct rk_gpio_reg *rk_reg = &sc->regs[reg];
uint32_t value;
if (rk_reg->single)
value = RK_GPIO_READ(sc, rk_reg->offset);
else
value = (RK_GPIO_READ(sc, rk_reg->offset) & 0xffff) |
(RK_GPIO_READ(sc, rk_reg->offset + 4) << 16);
return (value);
}
static void
rk_gpio_write_4(struct rk_gpio_softc *sc, int reg, uint32_t value)
{
struct rk_gpio_reg *rk_reg = &sc->regs[reg];
if (rk_reg->single)
RK_GPIO_WRITE(sc, rk_reg->offset, value);
else {
RK_GPIO_WRITE(sc, rk_reg->offset,
(value & 0xffff) | 0xffff0000);
RK_GPIO_WRITE(sc, rk_reg->offset + 4,
(value >> 16) | 0xffff0000);
}
}
static int
rk_gpio_intr(void *arg)
{
struct rk_gpio_softc *sc = (struct rk_gpio_softc *)arg;
struct trapframe *tf = curthread->td_intr_frame;
uint32_t status;
RK_GPIO_LOCK(sc);
status = rk_gpio_read_4(sc, RK_GPIO_INT_STATUS);
rk_gpio_write_4(sc, RK_GPIO_PORTA_EOI, status);
RK_GPIO_UNLOCK(sc);
while (status) {
int pin = ffs(status) - 1;
status &= ~(1 << pin);
if (intr_isrc_dispatch(RK_GPIO_ISRC(sc, pin), tf)) {
device_printf(sc->sc_dev, "Interrupt pin=%d unhandled\n",
pin);
continue;
}
if ((sc->version == RK_GPIO_TYPE_V1) &&
(sc->isrcs[pin].mode & GPIO_INTR_EDGE_BOTH)) {
RK_GPIO_LOCK(sc);
if (rk_gpio_read_bit(sc, RK_GPIO_EXT_PORTA, pin))
rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,
(1 << pin), 0);
else
rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,
(1 << pin), 1);
RK_GPIO_UNLOCK(sc);
}
}
return (FILTER_HANDLED);
}
static int
rk_gpio_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
return (ENXIO);
device_set_desc(dev, "RockChip GPIO Bank controller");
return (BUS_PROBE_DEFAULT);
}
static int
rk_gpio_attach(device_t dev)
{
struct rk_gpio_softc *sc;
phandle_t parent_node, node;
int err, i;
sc = device_get_softc(dev);
sc->sc_dev = dev;
sc->pinctrl = device_get_parent(dev);
parent_node = ofw_bus_get_node(sc->pinctrl);
node = ofw_bus_get_node(sc->sc_dev);
if (!OF_hasprop(node, "gpio-controller"))
return (ENXIO);
mtx_init(&sc->sc_mtx, "rk gpio", "gpio", MTX_SPIN);
if (bus_alloc_resources(dev, rk_gpio_spec, sc->sc_res)) {
device_printf(dev, "could not allocate resources\n");
bus_release_resources(dev, rk_gpio_spec, sc->sc_res);
mtx_destroy(&sc->sc_mtx);
return (ENXIO);
}
sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
if (clk_get_by_ofw_index(dev, 0, 0, &sc->clk) != 0) {
device_printf(dev, "Cannot get clock\n");
rk_gpio_detach(dev);
return (ENXIO);
}
err = clk_enable(sc->clk);
if (err != 0) {
device_printf(dev, "Could not enable clock %s\n",
clk_get_name(sc->clk));
rk_gpio_detach(dev);
return (ENXIO);
}
if ((err = bus_setup_intr(dev, sc->sc_res[1],
INTR_TYPE_MISC | INTR_MPSAFE, rk_gpio_intr, NULL,
sc, &sc->ihandle))) {
device_printf(dev, "Can not setup IRQ\n");
rk_gpio_detach(dev);
return (ENXIO);
}
if (ofw_bus_node_is_compatible(parent_node, "rockchip,rk3568-pinctrl"))
sc->version = RK_GPIO_TYPE_V2;
else
sc->version = RK_GPIO_TYPE_V1;
switch (sc->version) {
case RK_GPIO_TYPE_V1:
sc->regs[RK_GPIO_SWPORTA_DR] = (struct rk_gpio_reg){ 1, 0x00 };
sc->regs[RK_GPIO_SWPORTA_DDR] = (struct rk_gpio_reg){ 1, 0x04 };
sc->regs[RK_GPIO_INTEN] = (struct rk_gpio_reg){ 1, 0x30 };
sc->regs[RK_GPIO_INTMASK] = (struct rk_gpio_reg){ 1, 0x34 };
sc->regs[RK_GPIO_INTTYPE_LEVEL] = (struct rk_gpio_reg){ 1, 0x38 };
sc->regs[RK_GPIO_INT_POLARITY] = (struct rk_gpio_reg){ 1, 0x3c };
sc->regs[RK_GPIO_INT_STATUS] = (struct rk_gpio_reg){ 1, 0x40 };
sc->regs[RK_GPIO_INT_RAWSTATUS] = (struct rk_gpio_reg){ 1, 0x44 };
sc->regs[RK_GPIO_DEBOUNCE] = (struct rk_gpio_reg){ 1, 0x48 };
sc->regs[RK_GPIO_PORTA_EOI] = (struct rk_gpio_reg){ 1, 0x4c };
sc->regs[RK_GPIO_EXT_PORTA] = (struct rk_gpio_reg){ 1, 0x50 };
break;
case RK_GPIO_TYPE_V2:
sc->regs[RK_GPIO_SWPORTA_DR] = (struct rk_gpio_reg){ 0, 0x00 };
sc->regs[RK_GPIO_SWPORTA_DDR] = (struct rk_gpio_reg){ 0, 0x08 };
sc->regs[RK_GPIO_INTEN] = (struct rk_gpio_reg){ 0, 0x10 };
sc->regs[RK_GPIO_INTMASK] = (struct rk_gpio_reg){ 0, 0x18 };
sc->regs[RK_GPIO_INTTYPE_LEVEL] = (struct rk_gpio_reg){ 0, 0x20 };
sc->regs[RK_GPIO_INTTYPE_BOTH] = (struct rk_gpio_reg){ 0, 0x30 };
sc->regs[RK_GPIO_INT_POLARITY] = (struct rk_gpio_reg){ 0, 0x28 };
sc->regs[RK_GPIO_INT_STATUS] = (struct rk_gpio_reg){ 1, 0x50 };
sc->regs[RK_GPIO_INT_RAWSTATUS] = (struct rk_gpio_reg){ 1, 0x58 };
sc->regs[RK_GPIO_DEBOUNCE] = (struct rk_gpio_reg){ 0, 0x38 };
sc->regs[RK_GPIO_PORTA_EOI] = (struct rk_gpio_reg){ 0, 0x60 };
sc->regs[RK_GPIO_EXT_PORTA] = (struct rk_gpio_reg){ 1, 0x70 };
break;
default:
device_printf(dev, "Unknown gpio version %08x\n", sc->version);
rk_gpio_detach(dev);
return (ENXIO);
}
for (i = 0; i < RK_GPIO_MAX_PINS; i++) {
sc->isrcs[i].irq = i;
sc->isrcs[i].mode = GPIO_INTR_CONFORM;
if ((err = intr_isrc_register(RK_GPIO_ISRC(sc, i),
dev, 0, "%s", device_get_nameunit(dev)))) {
device_printf(dev, "Can not register isrc %d\n", err);
rk_gpio_detach(dev);
return (ENXIO);
}
}
if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
device_printf(dev, "Can not register pic\n");
rk_gpio_detach(dev);
return (ENXIO);
}
for (i = 0; i < RK_GPIO_MAX_PINS; i++)
sc->pin_cached[i].is_gpio = 2;
RK_GPIO_LOCK(sc);
sc->swporta = rk_gpio_read_4(sc, RK_GPIO_SWPORTA_DR);
sc->swporta_ddr = rk_gpio_read_4(sc, RK_GPIO_SWPORTA_DDR);
RK_GPIO_UNLOCK(sc);
sc->sc_busdev = gpiobus_add_bus(dev);
if (sc->sc_busdev == NULL) {
rk_gpio_detach(dev);
return (ENXIO);
}
bus_attach_children(dev);
return (0);
}
static int
rk_gpio_detach(device_t dev)
{
struct rk_gpio_softc *sc;
sc = device_get_softc(dev);
if (sc->sc_busdev)
gpiobus_detach_bus(dev);
bus_release_resources(dev, rk_gpio_spec, sc->sc_res);
mtx_destroy(&sc->sc_mtx);
clk_disable(sc->clk);
return (0);
}
static device_t
rk_gpio_get_bus(device_t dev)
{
struct rk_gpio_softc *sc;
sc = device_get_softc(dev);
return (sc->sc_busdev);
}
static int
rk_gpio_pin_max(device_t dev, int *maxpin)
{
*maxpin = 31;
return (0);
}
static int
rk_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
{
struct rk_gpio_softc *sc;
uint32_t bank;
sc = device_get_softc(dev);
if (pin >= 32)
return (EINVAL);
bank = pin / 8;
pin = pin - (bank * 8);
RK_GPIO_LOCK(sc);
snprintf(name, GPIOMAXNAME, "P%c%d", bank + 'A', pin);
RK_GPIO_UNLOCK(sc);
return (0);
}
static int
rk_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
{
struct rk_gpio_softc *sc;
int rv;
sc = device_get_softc(dev);
if (__predict_false(sc->pin_cached[pin].is_gpio != 1)) {
rv = FDT_PINCTRL_IS_GPIO(sc->pinctrl, dev, pin, (bool *)&sc->pin_cached[pin].is_gpio);
if (rv != 0)
return (rv);
if (sc->pin_cached[pin].is_gpio == 0)
return (EINVAL);
}
*flags = 0;
rv = FDT_PINCTRL_GET_FLAGS(sc->pinctrl, dev, pin, flags);
if (rv != 0)
return (rv);
sc->pin_cached[pin].flags = *flags;
if (sc->swporta_ddr & (1 << pin))
*flags |= GPIO_PIN_OUTPUT;
else
*flags |= GPIO_PIN_INPUT;
return (0);
}
static int
rk_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
{
if (pin >= RK_GPIO_MAX_PINS)
return (EINVAL);
*caps = RK_GPIO_DEFAULT_CAPS;
return (0);
}
static int
rk_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
{
struct rk_gpio_softc *sc;
int rv;
sc = device_get_softc(dev);
if (pin >= RK_GPIO_MAX_PINS)
return (EINVAL);
if (__predict_false(sc->pin_cached[pin].is_gpio != 1)) {
rv = FDT_PINCTRL_IS_GPIO(sc->pinctrl, dev, pin, (bool *)&sc->pin_cached[pin].is_gpio);
if (rv != 0)
return (rv);
if (sc->pin_cached[pin].is_gpio == 0)
return (EINVAL);
}
if (__predict_false((flags & GPIO_PIN_INPUT) && ((flags & GPIO_FLAGS_PINCTRL) != sc->pin_cached[pin].flags))) {
rv = FDT_PINCTRL_SET_FLAGS(sc->pinctrl, dev, pin, flags);
sc->pin_cached[pin].flags = flags & GPIO_FLAGS_PINCTRL;
if (rv != 0)
return (rv);
}
RK_GPIO_LOCK(sc);
if (flags & GPIO_PIN_INPUT)
sc->swporta_ddr &= ~(1 << pin);
else if (flags & GPIO_PIN_OUTPUT)
sc->swporta_ddr |= (1 << pin);
rk_gpio_write_4(sc, RK_GPIO_SWPORTA_DDR, sc->swporta_ddr);
RK_GPIO_UNLOCK(sc);
return (0);
}
static int
rk_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
{
struct rk_gpio_softc *sc;
sc = device_get_softc(dev);
if (pin >= RK_GPIO_MAX_PINS)
return (EINVAL);
RK_GPIO_LOCK(sc);
*val = rk_gpio_read_bit(sc, RK_GPIO_EXT_PORTA, pin);
RK_GPIO_UNLOCK(sc);
return (0);
}
static int
rk_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
{
struct rk_gpio_softc *sc;
sc = device_get_softc(dev);
if (pin >= RK_GPIO_MAX_PINS)
return (EINVAL);
RK_GPIO_LOCK(sc);
if (value)
sc->swporta |= (1 << pin);
else
sc->swporta &= ~(1 << pin);
rk_gpio_write_4(sc, RK_GPIO_SWPORTA_DR, sc->swporta);
RK_GPIO_UNLOCK(sc);
return (0);
}
static int
rk_gpio_pin_toggle(device_t dev, uint32_t pin)
{
struct rk_gpio_softc *sc;
sc = device_get_softc(dev);
if (pin >= RK_GPIO_MAX_PINS)
return (EINVAL);
RK_GPIO_LOCK(sc);
if (sc->swporta & (1 << pin))
sc->swporta &= ~(1 << pin);
else
sc->swporta |= (1 << pin);
rk_gpio_write_4(sc, RK_GPIO_SWPORTA_DR, sc->swporta);
RK_GPIO_UNLOCK(sc);
return (0);
}
static int
rk_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins,
uint32_t change_pins, uint32_t *orig_pins)
{
struct rk_gpio_softc *sc;
uint32_t reg;
sc = device_get_softc(dev);
RK_GPIO_LOCK(sc);
reg = rk_gpio_read_4(sc, RK_GPIO_SWPORTA_DR);
if (orig_pins)
*orig_pins = reg;
sc->swporta = reg;
if ((clear_pins | change_pins) != 0) {
reg = (reg & ~clear_pins) ^ change_pins;
rk_gpio_write_4(sc, RK_GPIO_SWPORTA_DR, reg);
}
RK_GPIO_UNLOCK(sc);
return (0);
}
static int
rk_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
uint32_t *pin_flags)
{
struct rk_gpio_softc *sc;
uint32_t reg, set, mask, flags;
int i;
sc = device_get_softc(dev);
if (first_pin != 0 || num_pins > 32)
return (EINVAL);
set = 0;
mask = 0;
for (i = 0; i < num_pins; i++) {
mask = (mask << 1) | 1;
flags = pin_flags[i];
if (flags & GPIO_PIN_INPUT) {
set &= ~(1 << i);
} else if (flags & GPIO_PIN_OUTPUT) {
set |= (1 << i);
}
}
RK_GPIO_LOCK(sc);
reg = rk_gpio_read_4(sc, RK_GPIO_SWPORTA_DDR);
reg &= ~mask;
reg |= set;
rk_gpio_write_4(sc, RK_GPIO_SWPORTA_DDR, reg);
sc->swporta_ddr = reg;
RK_GPIO_UNLOCK(sc);
return (0);
}
static int
rk_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells,
pcell_t *gpios, uint32_t *pin, uint32_t *flags)
{
*pin = gpios[0];
*flags = gpios[1];
return (0);
}
static phandle_t
rk_gpio_get_node(device_t bus, device_t dev)
{
return (ofw_bus_get_node(bus));
}
static int
rk_gpio_pic_map_fdt(struct rk_gpio_softc *sc,
struct intr_map_data_fdt *daf,
u_int *irqp, uint32_t *modep)
{
uint32_t irq;
uint32_t mode;
if (daf->ncells != 2)
return (EINVAL);
irq = daf->cells[0];
if (irq >= RK_GPIO_MAX_PINS)
return (EINVAL);
if (daf->cells[1] == 1)
mode = GPIO_INTR_EDGE_RISING;
else if (daf->cells[1] == 2)
mode = GPIO_INTR_EDGE_FALLING;
else if (daf->cells[1] == 3)
mode = GPIO_INTR_EDGE_BOTH;
else if (daf->cells[1] == 4)
mode = GPIO_INTR_LEVEL_HIGH;
else if (daf->cells[1] == 8)
mode = GPIO_INTR_LEVEL_LOW;
else
return (EINVAL);
*irqp = irq;
if (modep != NULL)
*modep = mode;
return (0);
}
static int
rk_gpio_pic_map_gpio(struct rk_gpio_softc *sc,
struct intr_map_data_gpio *dag,
u_int *irqp, uint32_t *modep)
{
uint32_t irq;
irq = dag->gpio_pin_num;
if (irq >= RK_GPIO_MAX_PINS) {
device_printf(sc->sc_dev, "Invalid interrupt %u\n",
irq);
return (EINVAL);
}
*irqp = irq;
if (modep != NULL)
*modep = dag->gpio_intr_mode;
return (0);
}
static int
rk_gpio_pic_map(struct rk_gpio_softc *sc, struct intr_map_data *data,
u_int *irqp, uint32_t *modep)
{
switch (data->type) {
case INTR_MAP_DATA_FDT:
return (rk_gpio_pic_map_fdt(sc,
(struct intr_map_data_fdt *)data, irqp, modep));
case INTR_MAP_DATA_GPIO:
return (rk_gpio_pic_map_gpio(sc,
(struct intr_map_data_gpio *)data, irqp, modep));
default:
device_printf(sc->sc_dev, "Wrong type\n");
return (ENOTSUP);
}
}
static int
rk_pic_map_intr(device_t dev, struct intr_map_data *data,
struct intr_irqsrc **isrcp)
{
int error;
struct rk_gpio_softc *sc = device_get_softc(dev);
uint32_t irq;
error = rk_gpio_pic_map(sc, data, &irq, NULL);
if (error == 0)
*isrcp = RK_GPIO_ISRC(sc, irq);
return (error);
}
static int
rk_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
struct resource *res, struct intr_map_data *data)
{
struct rk_gpio_softc *sc = device_get_softc(dev);
struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc;
uint32_t mode;
uint32_t pin;
if (!data) {
device_printf(dev, "No map data\n");
return (ENOTSUP);
}
if (rk_gpio_pic_map(sc, data, &pin, &mode) != 0)
return (EINVAL);
if (rkisrc->irq != pin) {
device_printf(dev, "Interrupts don't match\n");
return (EINVAL);
}
if (isrc->isrc_handlers != 0) {
device_printf(dev, "Handler already attached\n");
return (rkisrc->mode == mode ? 0 : EINVAL);
}
rkisrc->mode = mode;
RK_GPIO_LOCK(sc);
switch (mode & GPIO_INTR_MASK) {
case GPIO_INTR_EDGE_RISING:
rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 1);
rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 1);
break;
case GPIO_INTR_EDGE_FALLING:
rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 1);
rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 0);
break;
case GPIO_INTR_EDGE_BOTH:
rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 1);
if (sc->version == RK_GPIO_TYPE_V1) {
if (rk_gpio_read_bit(sc, RK_GPIO_EXT_PORTA, pin))
rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,
pin, 0);
else
rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,
pin, 1);
} else
rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_BOTH, pin, 1);
break;
case GPIO_INTR_LEVEL_HIGH:
rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 0);
rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 1);
break;
case GPIO_INTR_LEVEL_LOW:
rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 0);
rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 0);
break;
default:
rk_gpio_write_bit(sc, RK_GPIO_INTMASK, pin, 1);
rk_gpio_write_bit(sc, RK_GPIO_INTEN, pin, 0);
RK_GPIO_UNLOCK(sc);
return (EINVAL);
}
rk_gpio_write_bit(sc, RK_GPIO_DEBOUNCE, pin, 1);
rk_gpio_write_bit(sc, RK_GPIO_INTMASK, pin, 0);
rk_gpio_write_bit(sc, RK_GPIO_INTEN, pin, 1);
RK_GPIO_UNLOCK(sc);
return (0);
}
static int
rk_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
struct resource *res, struct intr_map_data *data)
{
struct rk_gpio_softc *sc = device_get_softc(dev);
struct rk_pin_irqsrc *irqsrc;
irqsrc = (struct rk_pin_irqsrc *)isrc;
if (isrc->isrc_handlers == 0) {
irqsrc->mode = GPIO_INTR_CONFORM;
RK_GPIO_LOCK(sc);
rk_gpio_write_bit(sc, RK_GPIO_INTEN, irqsrc->irq, 0);
rk_gpio_write_bit(sc, RK_GPIO_INTMASK, irqsrc->irq, 0);
rk_gpio_write_bit(sc, RK_GPIO_DEBOUNCE, irqsrc->irq, 0);
RK_GPIO_UNLOCK(sc);
}
return (0);
}
static device_method_t rk_gpio_methods[] = {
DEVMETHOD(device_probe, rk_gpio_probe),
DEVMETHOD(device_attach, rk_gpio_attach),
DEVMETHOD(device_detach, rk_gpio_detach),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
DEVMETHOD(gpio_get_bus, rk_gpio_get_bus),
DEVMETHOD(gpio_pin_max, rk_gpio_pin_max),
DEVMETHOD(gpio_pin_getname, rk_gpio_pin_getname),
DEVMETHOD(gpio_pin_getflags, rk_gpio_pin_getflags),
DEVMETHOD(gpio_pin_getcaps, rk_gpio_pin_getcaps),
DEVMETHOD(gpio_pin_setflags, rk_gpio_pin_setflags),
DEVMETHOD(gpio_pin_get, rk_gpio_pin_get),
DEVMETHOD(gpio_pin_set, rk_gpio_pin_set),
DEVMETHOD(gpio_pin_toggle, rk_gpio_pin_toggle),
DEVMETHOD(gpio_pin_access_32, rk_gpio_pin_access_32),
DEVMETHOD(gpio_pin_config_32, rk_gpio_pin_config_32),
DEVMETHOD(gpio_map_gpios, rk_gpio_map_gpios),
DEVMETHOD(pic_map_intr, rk_pic_map_intr),
DEVMETHOD(pic_setup_intr, rk_pic_setup_intr),
DEVMETHOD(pic_teardown_intr, rk_pic_teardown_intr),
DEVMETHOD(ofw_bus_get_node, rk_gpio_get_node),
DEVMETHOD_END
};
static driver_t rk_gpio_driver = {
"gpio",
rk_gpio_methods,
sizeof(struct rk_gpio_softc),
};
EARLY_DRIVER_MODULE(rk_gpio, simplebus, rk_gpio_driver, 0, 0,
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);