summaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorAntony Pavlov <antonynpavlov@gmail.com>2014-06-24 01:21:07 +0400
committerSascha Hauer <s.hauer@pengutronix.de>2014-06-24 09:07:06 +0200
commiteb58282ee448d1fb7b92a35f2e4eaf9607b8e8fe (patch)
tree9ed7b09a69ca9a897b99f727ba93546fc8d21f5c /drivers/gpio
parent40d89c49777081ea88818610a575813d8a08e5c5 (diff)
downloadbarebox-eb58282ee448d1fb7b92a35f2e4eaf9607b8e8fe.tar.gz
barebox-eb58282ee448d1fb7b92a35f2e4eaf9607b8e8fe.tar.xz
gpio: add Malta CBUS FPGA I2C driver
This driver provides common support for accessing the CBUS FPGA I2C lines through the gpio library. Additional i2c bitbang driver must be enabled in order to use the functionality of the i2c controller. Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig10
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-malta-fpga-i2c.c186
3 files changed, 197 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 7302955d87..45b8c53fd5 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -37,6 +37,16 @@ config GPIO_GENERIC_PLATFORM
config GPIO_IMX
def_bool ARCH_IMX
+config GPIO_MALTA_FPGA_I2C
+ bool "Malta CBUS FPGA I2C GPIO"
+ depends on MACH_MIPS_MALTA
+ help
+ Support access to the CBUS FPGA I2C lines through the gpio library.
+
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
config GPIO_OMAP
def_bool ARCH_OMAP
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 68a76a3745..add6ffc1da 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
obj-$(CONFIG_GPIO_IMX) += gpio-imx.o
+obj-$(CONFIG_GPIO_MALTA_FPGA_I2C) += gpio-malta-fpga-i2c.o
obj-$(CONFIG_GPIO_ORION) += gpio-orion.o
obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
diff --git a/drivers/gpio/gpio-malta-fpga-i2c.c b/drivers/gpio/gpio-malta-fpga-i2c.c
new file mode 100644
index 0000000000..d6995aad81
--- /dev/null
+++ b/drivers/gpio/gpio-malta-fpga-i2c.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This file is part of barebox.
+ * See file CREDITS for list of people who contributed to this project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <gpio.h>
+#include <linux/err.h>
+#include <malloc.h>
+
+struct malta_i2c_gpio {
+ void __iomem *base;
+ struct gpio_chip chip;
+};
+
+#define MALTA_I2CINP 0
+#define MALTA_I2COE 0x8
+#define MALTA_I2COUT 0x10
+#define MALTA_I2CSEL 0x18
+
+static inline struct malta_i2c_gpio *chip_to_malta_i2c_gpio(struct gpio_chip *c)
+{
+ return container_of(c, struct malta_i2c_gpio, chip);
+}
+
+static inline void malta_i2c_gpio_write(struct malta_i2c_gpio *sc,
+ u32 v, int reg)
+{
+ __raw_writel(v, sc->base + reg);
+}
+
+static inline u32 malta_i2c_gpio_read(struct malta_i2c_gpio *sc, int reg)
+{
+ return __raw_readl(sc->base + reg);
+}
+
+static inline int malta_i2c_gpio_get_bit(struct malta_i2c_gpio *sc,
+ int reg, int bit)
+{
+ return !!(malta_i2c_gpio_read(sc, reg) & BIT(bit));
+}
+
+static inline void malta_i2c_gpio_set_bit(struct malta_i2c_gpio *sc,
+ int reg, int bit, int v)
+{
+ u32 t;
+
+ t = malta_i2c_gpio_read(sc, reg);
+ if (v)
+ t |= BIT(bit);
+ else
+ t &= ~BIT(bit);
+
+ malta_i2c_gpio_write(sc, t, reg);
+}
+
+static int malta_i2c_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct malta_i2c_gpio *sc = chip_to_malta_i2c_gpio(chip);
+
+ malta_i2c_gpio_set_bit(sc, MALTA_I2COE, gpio, 0);
+
+ return 0;
+}
+
+static int malta_i2c_gpio_direction_output(struct gpio_chip *chip,
+ unsigned gpio, int v)
+{
+ struct malta_i2c_gpio *sc = chip_to_malta_i2c_gpio(chip);
+
+ malta_i2c_gpio_set_bit(sc, MALTA_I2COUT, gpio, v);
+ malta_i2c_gpio_set_bit(sc, MALTA_I2COE, gpio, 1);
+
+ return 0;
+}
+
+static int malta_i2c_gpio_get_direction(struct gpio_chip *chip, unsigned gpio)
+{
+ struct malta_i2c_gpio *sc = chip_to_malta_i2c_gpio(chip);
+
+ if (malta_i2c_gpio_get_bit(sc, MALTA_I2COE, gpio))
+ return GPIOF_DIR_OUT;
+
+ return GPIOF_DIR_IN;
+}
+
+static int malta_i2c_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ struct malta_i2c_gpio *sc = chip_to_malta_i2c_gpio(chip);
+ int v;
+
+ v = malta_i2c_gpio_get_bit(sc, MALTA_I2CINP, gpio);
+
+ pr_debug("%s: gpio_chip=%p gpio=%d value=%d\n",
+ __func__, chip, gpio, v);
+
+ return v;
+}
+
+static void malta_i2c_gpio_set_value(struct gpio_chip *chip,
+ unsigned gpio, int v)
+{
+ struct malta_i2c_gpio *sc = chip_to_malta_i2c_gpio(chip);
+
+ pr_debug("%s: gpio_chip=%p gpio=%d value=%d\n",
+ __func__, chip, gpio, v);
+
+ malta_i2c_gpio_set_bit(sc, MALTA_I2COUT, gpio, v);
+}
+
+static struct gpio_ops malta_i2c_gpio_ops = {
+ .direction_input = malta_i2c_gpio_direction_input,
+ .direction_output = malta_i2c_gpio_direction_output,
+ .get_direction = malta_i2c_gpio_get_direction,
+ .get = malta_i2c_gpio_get_value,
+ .set = malta_i2c_gpio_set_value,
+};
+
+static int malta_i2c_gpio_probe(struct device_d *dev)
+{
+ void __iomem *gpio_base;
+ struct malta_i2c_gpio *sc;
+ int ret;
+
+ gpio_base = dev_request_mem_region(dev, 0);
+ if (!gpio_base) {
+ dev_err(dev, "could not get memory region\n");
+ return -ENODEV;
+ }
+
+ sc = xzalloc(sizeof(*sc));
+ sc->base = gpio_base;
+ sc->chip.ops = &malta_i2c_gpio_ops;
+ sc->chip.base = -1;
+ sc->chip.ngpio = 2;
+ sc->chip.dev = dev;
+
+ ret = gpiochip_add(&sc->chip);
+ if (ret) {
+ dev_err(dev, "couldn't add gpiochip\n");
+ free(sc);
+ return ret;
+ }
+
+ malta_i2c_gpio_write(sc, 1, MALTA_I2CSEL);
+
+ dev_info(dev, "probed gpiochip%d with base %d\n",
+ dev->id, sc->chip.base);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id malta_i2c_gpio_dt_ids[] = {
+ {
+ .compatible = "mti,malta-fpga-i2c-gpio",
+ }, {
+ /* sentinel */
+ },
+};
+
+static struct driver_d malta_i2c_gpio_driver = {
+ .name = "malta-fpga-i2c-gpio",
+ .probe = malta_i2c_gpio_probe,
+ .of_compatible = DRV_OF_COMPAT(malta_i2c_gpio_dt_ids),
+};
+
+static int malta_i2c_gpio_driver_init(void)
+{
+ return platform_driver_register(&malta_i2c_gpio_driver);
+}
+coredevice_initcall(malta_i2c_gpio_driver_init);