summaryrefslogtreecommitdiff
path: root/sys/arch/armv7/imx/imxgpio.c
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2013-09-06 20:45:55 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2013-09-06 20:45:55 +0000
commitcbccf2bd320a00fd2d28064002c74254167e613c (patch)
tree323c94f9972ad75f3f2318d9cac70847e3400a66 /sys/arch/armv7/imx/imxgpio.c
parentaba4f7ffe403094c2f9d96695a052a49d4a82890 (diff)
Support for FreeScale's i.MX6 SoC.
Diffstat (limited to 'sys/arch/armv7/imx/imxgpio.c')
-rw-r--r--sys/arch/armv7/imx/imxgpio.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/sys/arch/armv7/imx/imxgpio.c b/sys/arch/armv7/imx/imxgpio.c
new file mode 100644
index 00000000000..fbaf91a8f85
--- /dev/null
+++ b/sys/arch/armv7/imx/imxgpio.c
@@ -0,0 +1,241 @@
+/* $OpenBSD: imxgpio.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/evcount.h>
+
+#include <arm/cpufunc.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <armv7/imx/imxvar.h>
+#include <armv7/imx/imxgpiovar.h>
+
+/* iMX6 registers */
+#define GPIO_DR 0x00
+#define GPIO_GDIR 0x04
+#define GPIO_PSR 0x08
+#define GPIO_ICR1 0x0C
+#define GPIO_ICR2 0x10
+#define GPIO_IMR 0x14
+#define GPIO_ISR 0x18
+#define GPIO_EDGE_SEL 0x1C
+
+#define GPIO_NUM_PINS 32
+
+struct intrhand {
+ int (*ih_func)(void *); /* handler */
+ void *ih_arg; /* arg for handler */
+ int ih_ipl; /* IPL_* */
+ int ih_irq; /* IRQ number */
+ int ih_gpio; /* gpio pin */
+ struct evcount ih_count;
+ char *ih_name;
+};
+
+struct imxgpio_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ void *sc_ih_h;
+ void *sc_ih_l;
+ int sc_max_il;
+ int sc_min_il;
+ int sc_irq;
+ struct intrhand *sc_handlers[GPIO_NUM_PINS];
+ unsigned int (*sc_get_bit)(struct imxgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_set_bit)(struct imxgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_clear_bit)(struct imxgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_set_dir)(struct imxgpio_softc *sc,
+ unsigned int gpio, unsigned int dir);
+};
+
+#define GPIO_PIN_TO_INST(x) ((x) >> 5)
+#define GPIO_PIN_TO_OFFSET(x) ((x) & 0x1f)
+
+int imxgpio_match(struct device *parent, void *v, void *aux);
+void imxgpio_attach(struct device *parent, struct device *self, void *args);
+void imxgpio_recalc_interrupts(struct imxgpio_softc *sc);
+int imxgpio_irq(void *);
+int imxgpio_irq_dummy(void *);
+
+unsigned int imxgpio_v6_get_bit(struct imxgpio_softc *, unsigned int);
+void imxgpio_v6_set_bit(struct imxgpio_softc *, unsigned int);
+void imxgpio_v6_clear_bit(struct imxgpio_softc *, unsigned int);
+void imxgpio_v6_set_dir(struct imxgpio_softc *, unsigned int, unsigned int);
+unsigned int imxgpio_v6_get_dir(struct imxgpio_softc *, unsigned int);
+
+
+struct cfattach imxgpio_ca = {
+ sizeof (struct imxgpio_softc), imxgpio_match, imxgpio_attach
+};
+
+struct cfdriver imxgpio_cd = {
+ NULL, "imxgpio", DV_DULL
+};
+
+int
+imxgpio_match(struct device *parent, void *v, void *aux)
+{
+ switch (board_id) {
+ case BOARD_ID_IMX6_PHYFLEX:
+ case BOARD_ID_IMX6_SABRELITE:
+ break; /* continue trying */
+ default:
+ return 0; /* unknown */
+ }
+ return (1);
+}
+
+void
+imxgpio_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imx_attach_args *ia = args;
+ struct imxgpio_softc *sc = (struct imxgpio_softc *) self;
+
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxgpio_attach: bus_space_map failed!");
+
+
+ switch (board_id) {
+ case BOARD_ID_IMX6_PHYFLEX:
+ case BOARD_ID_IMX6_SABRELITE:
+ sc->sc_get_bit = imxgpio_v6_get_bit;
+ sc->sc_set_bit = imxgpio_v6_set_bit;
+ sc->sc_clear_bit = imxgpio_v6_clear_bit;
+ sc->sc_set_dir = imxgpio_v6_set_dir;
+ break;
+ }
+
+ printf("\n");
+
+ /* XXX - IRQ */
+ /* XXX - SYSCONFIG */
+ /* XXX - CTRL */
+ /* XXX - DEBOUNCE */
+}
+
+unsigned int
+imxgpio_get_bit(unsigned int gpio)
+{
+ struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ return sc->sc_get_bit(sc, gpio);
+
+}
+
+void
+imxgpio_set_bit(unsigned int gpio)
+{
+ struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ sc->sc_set_bit(sc, gpio);
+}
+
+void
+imxgpio_clear_bit(unsigned int gpio)
+{
+ struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ sc->sc_clear_bit(sc, gpio);
+}
+void
+imxgpio_set_dir(unsigned int gpio, unsigned int dir)
+{
+ struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ sc->sc_set_dir(sc, gpio, dir);
+}
+
+unsigned int
+imxgpio_v6_get_bit(struct imxgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t val;
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
+
+ return (val >> GPIO_PIN_TO_OFFSET(gpio)) & 0x1;
+}
+
+void
+imxgpio_v6_set_bit(struct imxgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t val;
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR,
+ val | (1 << GPIO_PIN_TO_OFFSET(gpio)));
+}
+
+void
+imxgpio_v6_clear_bit(struct imxgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t val;
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR,
+ val & ~(1 << GPIO_PIN_TO_OFFSET(gpio)));
+}
+
+void
+imxgpio_v6_set_dir(struct imxgpio_softc *sc, unsigned int gpio, unsigned int dir)
+{
+ int s;
+ u_int32_t val;
+
+ s = splhigh();
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR);
+ if (dir == IMXGPIO_DIR_OUT)
+ val |= 1 << GPIO_PIN_TO_OFFSET(gpio);
+ else
+ val &= ~(1 << GPIO_PIN_TO_OFFSET(gpio));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR, val);
+
+ splx(s);
+}
+
+unsigned int
+imxgpio_v6_get_dir(struct imxgpio_softc *sc, unsigned int gpio)
+{
+ int s;
+ u_int32_t val;
+
+ s = splhigh();
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR);
+ if (val & (1 << GPIO_PIN_TO_OFFSET(gpio)))
+ val = IMXGPIO_DIR_OUT;
+ else
+ val = IMXGPIO_DIR_IN;
+
+ splx(s);
+ return val;
+}