As proposed in
http://mail-index.netbsd.org/tech-kern/2016/04/28/msg020504.html add gpio interrupt support to the gpio framework, and an implementation for the allwinner gpio backend (tested on A20 only). gpio(4) has new public functions: - gpio_intr() called by backends when an interrupt condition for a gpio pin is present - gpio_find_device() and gpio_get_name(), support functions for gpio(4) users, wich respectively returns a void * cookie for a gpio device given its name, and returns the name given the cookie. - gpio_pin_ctl_intr(), which is used to configure interrupts on a gpio pin and registers a callback. - gpio_pin_irqen(), which is used to mask/unmask interrupts on a pin. Nothing in the NetBSD tree uses this yet, but I have a i2c driver (at https://github.com/mbouyer/marine_chartplotter/tree/master/software/NetBSD/driver) which uses it.
This commit is contained in:
parent
9acd6328a2
commit
ba413bf9c2
|
@ -35,7 +35,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__KERNEL_RCSID(1, "$NetBSD: awin_gpio.c,v 1.20 2015/10/02 16:04:40 bouyer Exp $");
|
||||
__KERNEL_RCSID(1, "$NetBSD: awin_gpio.c,v 1.21 2016/05/11 18:33:40 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
|
@ -57,16 +57,7 @@ static void awin_gpio_attach(device_t, device_t, void *);
|
|||
static int awin_gpio_pin_read(void *, int);
|
||||
static void awin_gpio_pin_write(void *, int, int);
|
||||
static void awin_gpio_pin_ctl(void *, int, int);
|
||||
|
||||
#if 0
|
||||
static const int ist_maps[] = {
|
||||
[IST_LEVEL_LOW] = AWIN_PIO_EINT_LOW_LEVEL,
|
||||
[IST_LEVEL_HIGH] = AWIN_PIO_EINT_HIGH_LEVEL,
|
||||
[IST_EDGE_FALLING] = AWIN_PIO_EINT_POSITIVE_EDGE,
|
||||
[IST_EDGE_RISING] = AWIN_PIO_EINT_NEGATIVE_EDGE,
|
||||
[IST_EDGE_BOTH] = AWIN_PIO_EINT_DOUBLE_EDGE,
|
||||
};
|
||||
#endif
|
||||
static void awin_gpio_pin_irqen(void *, int, bool);
|
||||
|
||||
struct awin_gpio_pin_cfg {
|
||||
uint32_t cfg[4];
|
||||
|
@ -77,16 +68,19 @@ struct awin_gpio_pin_cfg {
|
|||
static struct awin_gpio_pin_group {
|
||||
bus_addr_t grp_offset;
|
||||
uint32_t grp_pin_mask;
|
||||
uint32_t grp_pin_intr_mask;
|
||||
uint32_t grp_pin_inuse_mask;
|
||||
bus_space_handle_t grp_bsh;
|
||||
struct awin_gpio_pin_cfg grp_cfg;
|
||||
struct gpio_chipset_tag grp_gc_tag;
|
||||
const int grp_index;
|
||||
const char grp_nc_name[6];
|
||||
device_t grp_gpio_dev;
|
||||
} pin_groups[] = {
|
||||
[0] = {
|
||||
.grp_offset = AWIN_PIO_OFFSET + 0 * AWIN_PIO_GRP_SIZE,
|
||||
.grp_pin_mask = __BIT(AWIN_PIO_PA_PINS) - 1,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_gc_tag = {
|
||||
.gp_cookie = &pin_groups[0],
|
||||
.gp_pin_read = awin_gpio_pin_read,
|
||||
|
@ -99,6 +93,7 @@ static struct awin_gpio_pin_group {
|
|||
[1] = {
|
||||
.grp_offset = AWIN_PIO_OFFSET + 1 * AWIN_PIO_GRP_SIZE,
|
||||
.grp_pin_mask = __BIT(AWIN_PIO_PB_PINS) - 1,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_gc_tag = {
|
||||
.gp_cookie = &pin_groups[1],
|
||||
.gp_pin_read = awin_gpio_pin_read,
|
||||
|
@ -111,6 +106,7 @@ static struct awin_gpio_pin_group {
|
|||
[2] = {
|
||||
.grp_offset = AWIN_PIO_OFFSET + 2 * AWIN_PIO_GRP_SIZE,
|
||||
.grp_pin_mask = __BIT(AWIN_PIO_PC_PINS) - 1,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_gc_tag = {
|
||||
.gp_cookie = &pin_groups[2],
|
||||
.gp_pin_read = awin_gpio_pin_read,
|
||||
|
@ -123,6 +119,7 @@ static struct awin_gpio_pin_group {
|
|||
[3] = {
|
||||
.grp_offset = AWIN_PIO_OFFSET + 3 * AWIN_PIO_GRP_SIZE,
|
||||
.grp_pin_mask = __BIT(AWIN_PIO_PD_PINS) - 1,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_gc_tag = {
|
||||
.gp_cookie = &pin_groups[3],
|
||||
.gp_pin_read = awin_gpio_pin_read,
|
||||
|
@ -135,6 +132,7 @@ static struct awin_gpio_pin_group {
|
|||
[4] = {
|
||||
.grp_offset = AWIN_PIO_OFFSET + 4 * AWIN_PIO_GRP_SIZE,
|
||||
.grp_pin_mask = __BIT(AWIN_PIO_PE_PINS) - 1,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_gc_tag = {
|
||||
.gp_cookie = &pin_groups[4],
|
||||
.gp_pin_read = awin_gpio_pin_read,
|
||||
|
@ -147,6 +145,7 @@ static struct awin_gpio_pin_group {
|
|||
[5] = {
|
||||
.grp_offset = AWIN_PIO_OFFSET + 5 * AWIN_PIO_GRP_SIZE,
|
||||
.grp_pin_mask = __BIT(AWIN_PIO_PF_PINS) - 1,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_gc_tag = {
|
||||
.gp_cookie = &pin_groups[5],
|
||||
.gp_pin_read = awin_gpio_pin_read,
|
||||
|
@ -159,6 +158,7 @@ static struct awin_gpio_pin_group {
|
|||
[6] = {
|
||||
.grp_offset = AWIN_PIO_OFFSET + 6 * AWIN_PIO_GRP_SIZE,
|
||||
.grp_pin_mask = __BIT(AWIN_PIO_PG_PINS) - 1,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_gc_tag = {
|
||||
.gp_cookie = &pin_groups[6],
|
||||
.gp_pin_read = awin_gpio_pin_read,
|
||||
|
@ -171,11 +171,13 @@ static struct awin_gpio_pin_group {
|
|||
[7] = {
|
||||
.grp_offset = AWIN_PIO_OFFSET + 7 * AWIN_PIO_GRP_SIZE,
|
||||
.grp_pin_mask = __BIT(AWIN_PIO_PH_PINS) - 1,
|
||||
.grp_pin_intr_mask = AWIN_PIO_PH_EINT_PINS,
|
||||
.grp_gc_tag = {
|
||||
.gp_cookie = &pin_groups[7],
|
||||
.gp_pin_read = awin_gpio_pin_read,
|
||||
.gp_pin_write = awin_gpio_pin_write,
|
||||
.gp_pin_ctl = awin_gpio_pin_ctl,
|
||||
.gp_pin_irqen = awin_gpio_pin_irqen,
|
||||
},
|
||||
.grp_index = 7,
|
||||
.grp_nc_name = "nc-ph",
|
||||
|
@ -183,6 +185,7 @@ static struct awin_gpio_pin_group {
|
|||
[8] = {
|
||||
.grp_offset = AWIN_PIO_OFFSET + 8 * AWIN_PIO_GRP_SIZE,
|
||||
.grp_pin_mask = __BIT(AWIN_PIO_PI_PINS) - 1,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_gc_tag = {
|
||||
.gp_cookie = &pin_groups[8],
|
||||
.gp_pin_read = awin_gpio_pin_read,
|
||||
|
@ -201,6 +204,7 @@ static struct awin_gpio_pin_group {
|
|||
.gp_pin_ctl = awin_gpio_pin_ctl,
|
||||
},
|
||||
.grp_pin_mask = 0,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_index = 9,
|
||||
.grp_nc_name = "nc-pj",
|
||||
},
|
||||
|
@ -213,6 +217,7 @@ static struct awin_gpio_pin_group {
|
|||
.gp_pin_ctl = awin_gpio_pin_ctl,
|
||||
},
|
||||
.grp_pin_mask = 0,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_index = 10,
|
||||
.grp_nc_name = "nc-pk",
|
||||
},
|
||||
|
@ -225,6 +230,7 @@ static struct awin_gpio_pin_group {
|
|||
.gp_pin_ctl = awin_gpio_pin_ctl,
|
||||
},
|
||||
.grp_pin_mask = 0,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_index = 11,
|
||||
.grp_nc_name = "nc-pl",
|
||||
},
|
||||
|
@ -237,6 +243,7 @@ static struct awin_gpio_pin_group {
|
|||
.gp_pin_ctl = awin_gpio_pin_ctl,
|
||||
},
|
||||
.grp_pin_mask = 0,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_index = 12,
|
||||
.grp_nc_name = "nc-pm",
|
||||
},
|
||||
|
@ -249,6 +256,7 @@ static struct awin_gpio_pin_group {
|
|||
.gp_pin_ctl = awin_gpio_pin_ctl,
|
||||
},
|
||||
.grp_pin_mask = 0,
|
||||
.grp_pin_intr_mask = 0,
|
||||
.grp_nc_name = "nc-pn",
|
||||
},
|
||||
};
|
||||
|
@ -258,13 +266,22 @@ static struct awin_gpio_softc {
|
|||
device_t sc_dev;
|
||||
bus_space_tag_t sc_bst;
|
||||
bus_space_handle_t sc_bsh;
|
||||
bus_space_handle_t sc_eint_bsh;
|
||||
void *sc_ih;
|
||||
kmutex_t sc_intr_lock;
|
||||
uint32_t sc_ecfg[4];
|
||||
uint32_t sc_eintr_configured;
|
||||
} awin_gpio_sc = {
|
||||
.sc_bst = &armv7_generic_bs_tag,
|
||||
};
|
||||
|
||||
#define INT_OFFSET(x) ((x) - AWIN_PIO_INT_CFG0_REG)
|
||||
|
||||
CFATTACH_DECL_NEW(awin_gpio, sizeof(struct awin_gpio_softc),
|
||||
awin_gpio_match, awin_gpio_attach, NULL, NULL);
|
||||
|
||||
static int awin_gpio_intr(void *);
|
||||
|
||||
static int
|
||||
awin_gpio_match(device_t parent, cfdata_t cf, void *aux)
|
||||
{
|
||||
|
@ -345,13 +362,20 @@ awin_gpio_config_pins(device_t self)
|
|||
pin->pin_num = num + (i << 5);
|
||||
pin->pin_caps = pincaps;
|
||||
pin->pin_flags = pincaps;
|
||||
if ((grp->grp_pin_intr_mask & (1 << num)) != 0){
|
||||
pin->pin_caps |=
|
||||
GPIO_PIN_EVENTS |
|
||||
GPIO_PIN_LEVEL |
|
||||
GPIO_PIN_FALLING;
|
||||
}
|
||||
pin->pin_state = (data & 1) != 0;
|
||||
pin++;
|
||||
}
|
||||
}
|
||||
|
||||
gba.gba_npins = pin - gba.gba_pins;
|
||||
config_found_ia(self, "gpiobus", &gba, awin_gpio_cfprint);
|
||||
grp->grp_gpio_dev =
|
||||
config_found_ia(self, "gpiobus", &gba, awin_gpio_cfprint);
|
||||
}
|
||||
}
|
||||
#endif /* NGPIO > 0 */
|
||||
|
@ -372,6 +396,15 @@ awin_gpio_attach(device_t parent, device_t self, void *aux)
|
|||
|
||||
aprint_naive("\n");
|
||||
aprint_normal("\n");
|
||||
sc->sc_ih = intr_establish(loc->loc_intr,
|
||||
IPL_VM, IST_LEVEL | IST_MPSAFE,
|
||||
awin_gpio_intr, &awin_gpio_sc);
|
||||
if (sc->sc_ih == NULL) {
|
||||
aprint_error_dev(self, "failed to establish interrupt %d\n",
|
||||
loc->loc_intr);
|
||||
return;
|
||||
}
|
||||
aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr);
|
||||
|
||||
for (u_int i = 0; i < __arraycount(pin_groups); i++) {
|
||||
struct awin_gpio_pin_group * const grp = &pin_groups[i];
|
||||
|
@ -393,6 +426,32 @@ awin_gpio_attach(device_t parent, device_t self, void *aux)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
awin_gpio_intr(void *a)
|
||||
{
|
||||
struct awin_gpio_softc *sc = a;
|
||||
uint32_t enabled;
|
||||
uint32_t pending;
|
||||
struct awin_gpio_pin_group * const grp = &pin_groups[7]; /* XXX */
|
||||
|
||||
mutex_enter(&sc->sc_intr_lock);
|
||||
enabled = bus_space_read_4(sc->sc_bst, sc->sc_eint_bsh,
|
||||
INT_OFFSET(AWIN_PIO_INT_CTL_REG));
|
||||
pending = bus_space_read_4(sc->sc_bst, sc->sc_eint_bsh,
|
||||
INT_OFFSET(AWIN_PIO_INT_STA_REG));
|
||||
/* keep only enabled interrupts */
|
||||
pending &= enabled;
|
||||
/* mask and ack pending interrupts */
|
||||
enabled &= ~pending;
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh,
|
||||
INT_OFFSET(AWIN_PIO_INT_CTL_REG), enabled);
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh,
|
||||
INT_OFFSET(AWIN_PIO_INT_STA_REG), pending);
|
||||
mutex_exit(&sc->sc_intr_lock);
|
||||
gpio_intr(grp->grp_gpio_dev, pending);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u_int
|
||||
awin_gpio_get_pin_func(const struct awin_gpio_pin_cfg *cfg, u_int pin)
|
||||
{
|
||||
|
@ -457,6 +516,47 @@ awin_gpio_update_cfg_regs(bus_space_tag_t bst, struct awin_gpio_pin_group *grp,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
awin_gpio_set_pin_eint(struct awin_gpio_softc *sc, int pin, uint32_t m)
|
||||
{
|
||||
int g = (pin >> 3);
|
||||
int s = ((pin & 7) * 4);
|
||||
KASSERT(g < 4);
|
||||
sc->sc_ecfg[g] &= ~(0xf << s);
|
||||
sc->sc_ecfg[g] |= ((m & 0xf) << s);
|
||||
}
|
||||
|
||||
static void
|
||||
awin_gpio_update_eint_regs(struct awin_gpio_softc *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
KASSERT(mutex_owned(&sc->sc_intr_lock));
|
||||
for (i = 0; i < 4; i++) {
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh, i * 4,
|
||||
sc->sc_ecfg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
awin_gpio_clear_eint(struct awin_gpio_softc *sc, int pin)
|
||||
{
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh,
|
||||
INT_OFFSET(AWIN_PIO_INT_STA_REG), (1U <<pin));
|
||||
}
|
||||
|
||||
static void
|
||||
awin_gpio_update_eint_mask(struct awin_gpio_softc *sc)
|
||||
{
|
||||
uint32_t enabled;
|
||||
KASSERT(mutex_owned(&sc->sc_intr_lock));
|
||||
enabled = bus_space_read_4(sc->sc_bst, sc->sc_eint_bsh,
|
||||
INT_OFFSET(AWIN_PIO_INT_CTL_REG));
|
||||
enabled &= sc->sc_eintr_configured;
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh,
|
||||
INT_OFFSET(AWIN_PIO_INT_CTL_REG), enabled);
|
||||
}
|
||||
|
||||
void
|
||||
awin_gpio_init(void)
|
||||
{
|
||||
|
@ -465,7 +565,6 @@ awin_gpio_init(void)
|
|||
#ifdef VERBOSE_INIT_ARM
|
||||
printf(" free");
|
||||
#endif
|
||||
|
||||
if (awin_chip_id() == AWIN_CHIP_ID_A31) {
|
||||
pin_groups[0].grp_pin_mask = __BIT(AWIN_A31_PIO_PA_PINS) - 1;
|
||||
pin_groups[1].grp_pin_mask = __BIT(AWIN_A31_PIO_PB_PINS) - 1;
|
||||
|
@ -577,6 +676,15 @@ awin_gpio_init(void)
|
|||
popcount32(grp->grp_pin_mask & ~grp->grp_pin_inuse_mask));
|
||||
#endif
|
||||
}
|
||||
|
||||
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
|
||||
bus_space_subregion(sc->sc_bst, awin_core_bsh,
|
||||
AWIN_PIO_OFFSET + AWIN_PIO_INT_CFG0_REG,
|
||||
AWIN_PIO_INT_SIZE, &sc->sc_eint_bsh);
|
||||
for (u_int i = 0; i < 3; i++) {
|
||||
sc->sc_ecfg[i] = 0;
|
||||
}
|
||||
sc->sc_eintr_configured = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -764,6 +872,7 @@ awin_gpio_pin_ctl(void *cookie, int pin, int flags)
|
|||
{
|
||||
struct awin_gpio_pin_group * const grp = cookie;
|
||||
struct awin_gpio_pin_cfg ncfg = grp->grp_cfg;
|
||||
struct awin_gpio_softc *sc = &awin_gpio_sc;
|
||||
|
||||
u_int pull_value = AWIN_PIO_PULL_NONE;
|
||||
if (flags & GPIO_PIN_PULLUP) {
|
||||
|
@ -773,16 +882,74 @@ awin_gpio_pin_ctl(void *cookie, int pin, int flags)
|
|||
}
|
||||
awin_gpio_set_pin_pull(&ncfg, pin, pull_value);
|
||||
|
||||
if (flags & GPIO_PIN_INPUT) {
|
||||
awin_gpio_set_pin_func(&ncfg, pin, AWIN_PIO_FUNC_INPUT);
|
||||
} else if (flags & GPIO_PIN_OUTPUT) {
|
||||
awin_gpio_set_pin_func(&ncfg, pin, AWIN_PIO_FUNC_OUTPUT);
|
||||
mutex_enter(&sc->sc_intr_lock);
|
||||
if (flags & GPIO_PIN_EVENTS) {
|
||||
KASSERT(awin_chip_id() == AWIN_CHIP_ID_A20);
|
||||
KASSERT(grp->grp_index == 7);
|
||||
KASSERT(pin <= 21);
|
||||
KASSERT((grp->grp_pin_intr_mask & (1 << pin)) != 0);
|
||||
awin_gpio_set_pin_func(&ncfg, pin, AWIN_PIO_PH_EINT_FUNC);
|
||||
if (flags & GPIO_PIN_LEVEL) {
|
||||
if (flags & GPIO_PIN_FALLING) {
|
||||
awin_gpio_set_pin_eint(sc, pin,
|
||||
AWIN_PIO_EINT_LOW_LEVEL);
|
||||
} else {
|
||||
awin_gpio_set_pin_eint(sc, pin,
|
||||
AWIN_PIO_EINT_HIGH_LEVEL);
|
||||
}
|
||||
} else {
|
||||
if (flags & GPIO_PIN_FALLING) {
|
||||
awin_gpio_set_pin_eint(sc, pin,
|
||||
AWIN_PIO_EINT_NEGATIVE_EDGE);
|
||||
} else {
|
||||
awin_gpio_set_pin_eint(sc, pin,
|
||||
AWIN_PIO_EINT_POSITIVE_EDGE);
|
||||
}
|
||||
}
|
||||
awin_gpio_update_eint_regs(sc);
|
||||
sc->sc_eintr_configured |= 1 << pin;
|
||||
awin_gpio_clear_eint(sc, pin);
|
||||
} else {
|
||||
if ((grp->grp_pin_intr_mask & (1 << pin)) != 0) {
|
||||
sc->sc_eintr_configured &= ~(1 << pin);
|
||||
awin_gpio_update_eint_mask(sc);
|
||||
awin_gpio_clear_eint(sc, pin);
|
||||
}
|
||||
if (flags & GPIO_PIN_INPUT) {
|
||||
awin_gpio_set_pin_func(&ncfg, pin,
|
||||
AWIN_PIO_FUNC_INPUT);
|
||||
} else if (flags & GPIO_PIN_OUTPUT) {
|
||||
awin_gpio_set_pin_func(&ncfg, pin,
|
||||
AWIN_PIO_FUNC_OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now update any config register that changed.
|
||||
*/
|
||||
awin_gpio_update_cfg_regs(&armv7_generic_bs_tag, grp, &ncfg);
|
||||
mutex_exit(&sc->sc_intr_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
awin_gpio_pin_irqen(void *cookie, int pin, bool enable)
|
||||
{
|
||||
struct awin_gpio_pin_group * const grp = cookie;
|
||||
uint32_t enabled;
|
||||
struct awin_gpio_softc *sc = &awin_gpio_sc;
|
||||
|
||||
KASSERT(grp->grp_index == 7);
|
||||
mutex_enter(&sc->sc_intr_lock);
|
||||
enabled = bus_space_read_4(sc->sc_bst, sc->sc_eint_bsh,
|
||||
INT_OFFSET(AWIN_PIO_INT_CTL_REG));
|
||||
if (enable)
|
||||
enabled |= (1 << pin);
|
||||
else
|
||||
enabled &= ~(1 << pin);
|
||||
enabled &= sc->sc_eintr_configured;
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh,
|
||||
INT_OFFSET(AWIN_PIO_INT_CTL_REG), enabled);
|
||||
mutex_exit(&sc->sc_intr_lock);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.45 2016/04/25 20:15:46 bouyer Exp $");
|
||||
__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.46 2016/05/11 18:33:40 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
|
@ -97,7 +97,8 @@ awinio_print(void *aux, const char *pnp)
|
|||
|
||||
static const struct awin_locators awin_locators[] = {
|
||||
{ "awinicu", OFFANDSIZE(INTC), NOPORT, NOINTR, A10|REQ },
|
||||
{ "awingpio", OFFANDSIZE(PIO), NOPORT, NOINTR, A10|A20|A31|REQ },
|
||||
{ "awingpio", OFFANDSIZE(PIO), NOPORT, AWIN_IRQ_PIO, A10|A20|REQ },
|
||||
{ "awingpio", OFFANDSIZE(PIO), NOPORT, NOINTR, A31|REQ },
|
||||
{ "awingpio", OFFANDSIZE(A80_PIO), NOPORT, NOINTR, A80|REQ },
|
||||
{ "awindma", OFFANDSIZE(DMA), NOPORT, AWIN_IRQ_DMA, A10|A20 },
|
||||
{ "awindma", OFFANDSIZE(DMA), NOPORT, AWIN_A31_IRQ_DMA, A31 },
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: awin_reg.h,v 1.88 2016/04/25 20:15:46 bouyer Exp $ */
|
||||
/* $NetBSD: awin_reg.h,v 1.89 2016/05/11 18:33:40 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2013 The NetBSD Foundation, Inc.
|
||||
|
@ -1293,6 +1293,7 @@ struct awin_mmc_idma_descriptor {
|
|||
#define AWIN_PIO_INT_DEB_REG 0x0218
|
||||
#define AWIN_PIO_SDR_PAD_DEV_REG 0x0220
|
||||
#define AWIN_PIO_SDR_PAD_PUL_REG 0x0224
|
||||
#define AWIN_PIO_INT_SIZE 0x0028
|
||||
|
||||
#define AWIN_PIO_CFG_PINMASK(pin) (7 << (4*((pin) & 7)))
|
||||
#define AWIN_PIO_DRV_MASK(pin) ((x) << (2*((pin) & 15)))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: gpio.c,v 1.57 2014/07/25 08:10:36 dholland Exp $ */
|
||||
/* $NetBSD: gpio.c,v 1.58 2016/05/11 18:33:40 bouyer Exp $ */
|
||||
/* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -19,7 +19,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.57 2014/07/25 08:10:36 dholland Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.58 2016/05/11 18:33:40 bouyer Exp $");
|
||||
|
||||
/*
|
||||
* General Purpose Input/Output framework.
|
||||
|
@ -298,6 +298,45 @@ gpiobus_print(void *aux, const char *pnp)
|
|||
return UNCONF;
|
||||
}
|
||||
|
||||
/* called from backends when a interrupt even occurs */
|
||||
void
|
||||
gpio_intr(device_t self, uint32_t evts)
|
||||
{
|
||||
struct gpio_softc *sc = device_private(self);
|
||||
void (*callback)(void *);
|
||||
void *callback_arg;
|
||||
|
||||
for (int i = 0; i < sc->sc_npins; i++) {
|
||||
if (evts & (1 << i)) {
|
||||
mutex_enter(&sc->sc_mtx);
|
||||
callback = sc->sc_pins[i].pin_callback;
|
||||
callback_arg = sc->sc_pins[i].pin_callback_arg;
|
||||
DPRINTFN(2, ("gpio pin %d event callback %p\n", i, callback));
|
||||
if (callback != NULL) {
|
||||
callback(callback_arg);
|
||||
}
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
gpio_find_device(const char *name)
|
||||
{
|
||||
device_t gpio_dev;
|
||||
gpio_dev = device_find_by_xname(name);
|
||||
if (gpio_dev == NULL)
|
||||
return NULL;
|
||||
return device_private(gpio_dev);
|
||||
}
|
||||
|
||||
const char *
|
||||
gpio_get_name(void *gpio)
|
||||
{
|
||||
struct gpio_softc *sc = gpio;
|
||||
return device_xname(sc->sc_dev);
|
||||
}
|
||||
|
||||
/* return 1 if all pins can be mapped, 0 if not */
|
||||
int
|
||||
gpio_pin_can_map(void *gpio, int offset, uint32_t mask)
|
||||
|
@ -379,8 +418,42 @@ void
|
|||
gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags)
|
||||
{
|
||||
struct gpio_softc *sc = gpio;
|
||||
struct gpio_pin *pinp = &sc->sc_pins[map->pm_map[pin]];
|
||||
|
||||
return gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags);
|
||||
KASSERT((flags & GPIO_PIN_EVENTS) == 0);
|
||||
mutex_enter(&sc->sc_mtx);
|
||||
gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags);
|
||||
pinp->pin_callback = NULL;
|
||||
pinp->pin_callback_arg = NULL;
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
}
|
||||
|
||||
int
|
||||
gpio_pin_ctl_intr(void *gpio, struct gpio_pinmap *map, int pin, int flags,
|
||||
int ipl, void (*callback)(void *), void *arg)
|
||||
{
|
||||
struct gpio_softc *sc = gpio;
|
||||
struct gpio_pin *pinp = &sc->sc_pins[map->pm_map[pin]];
|
||||
KASSERT((flags & GPIO_PIN_EVENTS) != 0);
|
||||
if (ipl != IPL_VM)
|
||||
return EINVAL;
|
||||
mutex_enter(&sc->sc_mtx);
|
||||
if (pinp->pin_callback != NULL) {
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
return EEXIST;
|
||||
}
|
||||
pinp->pin_callback = callback;
|
||||
pinp->pin_callback_arg = arg;
|
||||
gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags);
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gpio_pin_irqen(void *gpio, struct gpio_pinmap *map, int pin, bool en)
|
||||
{
|
||||
struct gpio_softc *sc = gpio;
|
||||
gpiobus_pin_irqen(sc->sc_gc, map->pm_map[pin], en);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: gpiovar.h,v 1.15 2011/11/13 13:20:02 mbalmer Exp $ */
|
||||
/* $NetBSD: gpiovar.h,v 1.16 2016/05/11 18:33:40 bouyer Exp $ */
|
||||
/* $OpenBSD: gpiovar.h,v 1.3 2006/01/14 12:33:49 grange Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -31,6 +31,7 @@ typedef struct gpio_chipset_tag {
|
|||
int (*gp_pin_read)(void *, int);
|
||||
void (*gp_pin_write)(void *, int, int);
|
||||
void (*gp_pin_ctl)(void *, int, int);
|
||||
void (*gp_pin_irqen)(void *, int, bool);
|
||||
} *gpio_chipset_tag_t;
|
||||
|
||||
/* GPIO pin description */
|
||||
|
@ -41,6 +42,8 @@ typedef struct gpio_pin {
|
|||
int pin_state; /* current state */
|
||||
int pin_mapped; /* is mapped */
|
||||
gpio_chipset_tag_t pin_gc; /* reference the controller */
|
||||
void (*pin_callback)(void *); /* irq callback */
|
||||
void * pin_callback_arg; /* callback arg */
|
||||
} gpio_pin_t;
|
||||
|
||||
/* Attach GPIO framework to the controller */
|
||||
|
@ -63,6 +66,8 @@ int gpiobus_print(void *, const char *);
|
|||
((gc)->gp_pin_write((gc)->gp_cookie, (pin), (value)))
|
||||
#define gpiobus_pin_ctl(gc, pin, flags) \
|
||||
((gc)->gp_pin_ctl((gc)->gp_cookie, (pin), (flags)))
|
||||
#define gpiobus_pin_irqen(gc, pin, en) \
|
||||
((gc)->gp_pin_irqen((gc)->gp_cookie, (pin), (en)))
|
||||
|
||||
/* Attach devices connected to the GPIO pins */
|
||||
struct gpio_attach_args {
|
||||
|
@ -90,16 +95,24 @@ struct gpio_name {
|
|||
LIST_ENTRY(gpio_name) gp_next;
|
||||
};
|
||||
|
||||
void * gpio_find_device(const char *);
|
||||
const char * gpio_get_name(void *gpio);
|
||||
int gpio_pin_can_map(void *, int, uint32_t);
|
||||
int gpio_pin_map(void *, int, uint32_t, struct gpio_pinmap *);
|
||||
void gpio_pin_unmap(void *, struct gpio_pinmap *);
|
||||
int gpio_pin_read(void *, struct gpio_pinmap *, int);
|
||||
void gpio_pin_write(void *, struct gpio_pinmap *, int, int);
|
||||
void gpio_pin_ctl(void *, struct gpio_pinmap *, int, int);
|
||||
int gpio_pin_ctl_intr(void *, struct gpio_pinmap *, int, int,
|
||||
int, void (*)(void *), void *);
|
||||
void gpio_pin_irqen(void *, struct gpio_pinmap *, int, bool);
|
||||
int gpio_pin_caps(void *, struct gpio_pinmap *, int);
|
||||
int gpio_pin_wait(void *, int);
|
||||
int gpio_npins(uint32_t);
|
||||
|
||||
int gpio_lock(void *);
|
||||
void gpio_unlock(void *);
|
||||
|
||||
void gpio_intr(device_t, u_int32_t);
|
||||
|
||||
#endif /* !_DEV_GPIO_GPIOVAR_H_ */
|
||||
|
|
Loading…
Reference in New Issue