summaryrefslogtreecommitdiff
path: root/sys/arch/armv7/exynos/exgpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/armv7/exynos/exgpio.c')
-rw-r--r--sys/arch/armv7/exynos/exgpio.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/sys/arch/armv7/exynos/exgpio.c b/sys/arch/armv7/exynos/exgpio.c
new file mode 100644
index 00000000000..fa8bbf377b3
--- /dev/null
+++ b/sys/arch/armv7/exynos/exgpio.c
@@ -0,0 +1,283 @@
+/* $OpenBSD: exgpio.c,v 1.1 2015/01/26 02:48:24 bmercer 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/fdt.h>
+#include <machine/intr.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/exynos/exgpiovar.h>
+
+/* Exynos5 registers */
+#define GPIO_BANK_SIZE 0x20
+#define GPIO_BANK(x) (GPIO_BANK_SIZE * ((x) / 8))
+#define GPIO_CON(x) (GPIO_BANK(x) + 0x00)
+#define GPIO_DAT(x) (GPIO_BANK(x) + 0x04)
+#define GPIO_PULL(x) (GPIO_BANK(x) + 0x08)
+#define GPIO_DRV(x) (GPIO_BANK(x) + 0x0c)
+#define GPIO_PDN_CON(x) (GPIO_BANK(x) + 0x10)
+#define GPIO_PDN_PULL(x) (GPIO_BANK(x) + 0x14)
+
+/* bits and bytes */
+#define GPIO_PIN(x) ((x) % 8)
+#define GPIO_CON_INPUT(x) (0x0 << (GPIO_PIN(x) << 2))
+#define GPIO_CON_OUTPUT(x) (0x1 << (GPIO_PIN(x) << 2))
+#define GPIO_CON_IRQ(x) (0xf << (GPIO_PIN(x) << 2))
+#define GPIO_CON_MASK(x) (0xf << (GPIO_PIN(x) << 2))
+#define GPIO_DAT_SET(x) (0x1 << (GPIO_PIN(x) << 0))
+#define GPIO_DAT_MASK(x) (0x1 << (GPIO_PIN(x) << 0))
+#define GPIO_PULL_NONE(x) (0x0 << (GPIO_PIN(x) << 1))
+#define GPIO_PULL_DOWN(x) (0x1 << (GPIO_PIN(x) << 1))
+#define GPIO_PULL_UP(x) (0x3 << (GPIO_PIN(x) << 1))
+#define GPIO_PULL_MASK(x) (0x3 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_1X(x) (0x0 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_2X(x) (0x1 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_3X(x) (0x2 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_4X(x) (0x3 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_MASK(x) (0x3 << (GPIO_PIN(x) << 1))
+
+#define GPIO_PINS_PER_BANK 8
+
+struct exgpio_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ int sc_ngpio;
+ unsigned int (*sc_get_bit)(struct exgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_set_bit)(struct exgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_clear_bit)(struct exgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_set_dir)(struct exgpio_softc *sc,
+ unsigned int gpio, unsigned int dir);
+};
+
+int exgpio_match(struct device *parent, void *v, void *aux);
+void exgpio_attach(struct device *parent, struct device *self, void *args);
+
+struct exgpio_softc *exgpio_pin_to_inst(unsigned int);
+unsigned int exgpio_pin_to_offset(unsigned int);
+unsigned int exgpio_v5_get_bit(struct exgpio_softc *, unsigned int);
+void exgpio_v5_set_bit(struct exgpio_softc *, unsigned int);
+void exgpio_v5_clear_bit(struct exgpio_softc *, unsigned int);
+void exgpio_v5_set_dir(struct exgpio_softc *, unsigned int, unsigned int);
+unsigned int exgpio_v5_get_dir(struct exgpio_softc *, unsigned int);
+
+
+struct cfattach exgpio_ca = {
+ sizeof (struct exgpio_softc), NULL, exgpio_attach
+};
+struct cfattach exgpio_fdt_ca = {
+ sizeof (struct exgpio_softc), exgpio_match, exgpio_attach
+};
+
+struct cfdriver exgpio_cd = {
+ NULL, "exgpio", DV_DULL
+};
+
+int
+exgpio_match(struct device *parent, void *v, void *aux)
+{
+ struct armv7_attach_args *aa = aux;
+
+ if (fdt_node_compatible("samsung,exynos5250-pinctrl", aa->aa_node))
+ return 1;
+
+ return 0;
+}
+
+void
+exgpio_attach(struct device *parent, struct device *self, void *args)
+{
+ struct armv7_attach_args *aa = args;
+ struct exgpio_softc *sc = (struct exgpio_softc *) self;
+ struct fdt_memory mem;
+
+ sc->sc_iot = aa->aa_iot;
+ if (aa->aa_node) {
+ if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+ panic("%s: could not extract memory data from FDT",
+ __func__);
+ } else {
+ mem.addr = aa->aa_dev->mem[0].addr;
+ mem.size = aa->aa_dev->mem[0].size;
+ }
+ if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+ panic("%s: bus_space_map failed!", __func__);
+
+ sc->sc_ngpio = (mem.size / GPIO_BANK_SIZE) * GPIO_PINS_PER_BANK;
+
+ sc->sc_get_bit = exgpio_v5_get_bit;
+ sc->sc_set_bit = exgpio_v5_set_bit;
+ sc->sc_clear_bit = exgpio_v5_clear_bit;
+ sc->sc_set_dir = exgpio_v5_set_dir;
+
+ printf("\n");
+
+ /* XXX - IRQ */
+ /* XXX - SYSCONFIG */
+ /* XXX - CTRL */
+ /* XXX - DEBOUNCE */
+}
+
+struct exgpio_softc *
+exgpio_pin_to_inst(unsigned int gpio)
+{
+ int i;
+
+ for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
+ {
+ struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
+ if (gpio < sc->sc_ngpio)
+ return sc;
+ else
+ gpio -= sc->sc_ngpio;
+ }
+
+ return NULL;
+}
+
+unsigned int
+exgpio_pin_to_offset(unsigned int gpio)
+{
+ int i;
+
+ for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
+ {
+ struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
+ if (gpio < sc->sc_ngpio)
+ return gpio;
+ else
+ gpio -= sc->sc_ngpio;
+ }
+
+ return 0;
+}
+
+unsigned int
+exgpio_get_bit(unsigned int gpio)
+{
+ struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
+
+ return sc->sc_get_bit(sc, gpio);
+}
+
+void
+exgpio_set_bit(unsigned int gpio)
+{
+ struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
+
+ sc->sc_set_bit(sc, gpio);
+}
+
+void
+exgpio_clear_bit(unsigned int gpio)
+{
+ struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
+
+ sc->sc_clear_bit(sc, gpio);
+}
+void
+exgpio_set_dir(unsigned int gpio, unsigned int dir)
+{
+ struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
+
+ sc->sc_set_dir(sc, gpio, dir);
+}
+
+unsigned int
+exgpio_v5_get_bit(struct exgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t val;
+
+ gpio = exgpio_pin_to_offset(gpio);
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
+
+ return !!(val & GPIO_DAT_SET(gpio));
+}
+
+void
+exgpio_v5_set_bit(struct exgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t val;
+
+ gpio = exgpio_pin_to_offset(gpio);
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
+ val | GPIO_DAT_SET(gpio));
+}
+
+void
+exgpio_v5_clear_bit(struct exgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t val;
+
+ gpio = exgpio_pin_to_offset(gpio);
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
+ val & ~GPIO_DAT_MASK(gpio));
+}
+
+void
+exgpio_v5_set_dir(struct exgpio_softc *sc, unsigned int gpio, unsigned int dir)
+{
+ int s;
+ u_int32_t val;
+
+ gpio = exgpio_pin_to_offset(gpio);
+ s = splhigh();
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
+ val &= ~GPIO_CON_OUTPUT(gpio);
+ if (dir == EXGPIO_DIR_OUT)
+ val |= GPIO_CON_OUTPUT(gpio);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio), val);
+
+ splx(s);
+}
+
+unsigned int
+exgpio_v5_get_dir(struct exgpio_softc *sc, unsigned int gpio)
+{
+ int s;
+ u_int32_t val;
+
+ gpio = exgpio_pin_to_offset(gpio);
+ s = splhigh();
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
+ if (val & GPIO_CON_OUTPUT(gpio))
+ val = EXGPIO_DIR_OUT;
+ else
+ val = EXGPIO_DIR_IN;
+
+ splx(s);
+ return val;
+}