[PATCH 2/2] gpio: add driver for stmpe io-expander
Steffen Trumtrar
s.trumtrar at pengutronix.de
Fri Aug 31 05:14:07 EDT 2012
Add a driver for the stmpe1601 gpio block. The stmpe io-expanders have multiple
blocks (keypad, gpio...) that can be enabled and used. Only gpio is supported atm.
This was only tested on a stmpe connected via i2c. It is also possible to connect
via spi.
Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
drivers/Kconfig | 1 +
drivers/gpio/Kconfig | 8 +++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-stmpe.c | 155 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 165 insertions(+)
create mode 100644 drivers/gpio/Kconfig
create mode 100644 drivers/gpio/gpio-stmpe.c
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 883b0e7..adf8fcd 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -18,5 +18,6 @@ source "drivers/input/Kconfig"
source "drivers/watchdog/Kconfig"
source "drivers/pwm/Kconfig"
source "drivers/dma/Kconfig"
+source "drivers/gpio/Kconfig"
endmenu
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
new file mode 100644
index 0000000..939cda8
--- /dev/null
+++ b/drivers/gpio/Kconfig
@@ -0,0 +1,8 @@
+menu "GPIO "
+
+config STMPE_GPIO
+ depends on I2C
+ select I2C_STMPE
+ bool "STMPE GPIO Expander"
+
+endmenu
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 7837966..da1bc21 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -1 +1,2 @@
obj-y += gpio.o
+obj-$(CONFIG_STMPE_GPIO) += gpio-stmpe.o
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
new file mode 100644
index 0000000..44e7ae6
--- /dev/null
+++ b/drivers/gpio/gpio-stmpe.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 Pengutronix
+ * Steffen Trumtrar <s.trumtrar at pengutronix.de>
+ *
+ * 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 <errno.h>
+#include <io.h>
+#include <gpio.h>
+#include <init.h>
+#include <mfd/stmpe-i2c.h>
+
+#define GPIO_BASE 0x80
+#define GPIO_SET (GPIO_BASE + 0x02)
+#define GPIO_CLR (GPIO_BASE + 0x04)
+#define GPIO_MP (GPIO_BASE + 0x06)
+#define GPIO_SET_DIR (GPIO_BASE + 0x08)
+#define GPIO_ED (GPIO_BASE + 0x0a)
+#define GPIO_RE (GPIO_BASE + 0x0c)
+#define GPIO_FE (GPIO_BASE + 0x0e)
+#define GPIO_PULL_UP (GPIO_BASE + 0x10)
+#define GPIO_AF (GPIO_BASE + 0x12)
+#define GPIO_LT (GPIO_BASE + 0x16)
+
+#define OFFSET(gpio) (0xff & (1 << (gpio)) ? 1 : 0)
+
+extern void __iomem *stmpe_gpio_base[];
+extern int stmpe_gpio_count;
+
+struct stmpe_gpio_chip {
+ void __iomem *base;
+ struct gpio_chip chip;
+ void *ci;
+};
+
+static void stmpe_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
+ struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
+ int ret;
+ u8 val;
+
+ ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val);
+
+ val |= 1 << (gpio % 8);
+
+ if (value)
+ ret = ci->write_reg(ci->stmpe, GPIO_SET + OFFSET(gpio), val);
+ else
+ ret = ci->write_reg(ci->stmpe, GPIO_CLR + OFFSET(gpio), val);
+
+ if (ret)
+ dev_err(chip->dev, "write failed!\n");
+}
+
+static int stmpe_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
+ struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
+ int ret;
+ u8 val;
+
+ ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val);
+ val &= ~(1 << (gpio % 8));
+ ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val);
+
+ if (ret)
+ dev_err(chip->dev, "couldn't change direction. Write failed!\n");
+
+ return 0;
+}
+
+static int stmpe_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
+ struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
+ int ret;
+ u8 val;
+
+ ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val);
+ val |= 1 << (gpio % 8);
+ ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val);
+
+ stmpe_gpio_set_value(chip, gpio, value);
+
+ if (ret)
+ dev_err(chip->dev, "couldn't change direction. Write failed!\n");
+
+ return 0;
+}
+
+static int stmpe_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
+ struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
+ u8 val;
+ int ret;
+
+ ret = ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val);
+
+ if (ret)
+ dev_err(chip->dev, "read failed\n");
+
+ return val & (1 << (gpio % 8)) ? 1 : 0;
+}
+
+static struct gpio_ops stmpe_gpio_ops = {
+ .direction_input = stmpe_gpio_direction_input,
+ .direction_output = stmpe_gpio_direction_output,
+ .get = stmpe_gpio_get_value,
+ .set = stmpe_gpio_set_value,
+};
+
+static int stmpe_gpio_probe(struct device_d *dev)
+{
+ struct stmpe_gpio_chip *stmpegpio;
+
+ stmpegpio = xzalloc(sizeof(*stmpegpio));
+
+ stmpegpio->base = dev_request_mem_region(dev, 0);
+ stmpegpio->chip.ops = &stmpe_gpio_ops;
+ stmpegpio->chip.base = 224;
+ stmpegpio->chip.ngpio = 16;
+ stmpegpio->chip.dev = dev;
+
+ stmpegpio->ci = dev->platform_data;
+
+ gpiochip_add(&stmpegpio->chip);
+
+ dev_info(dev, "probed stmpe gpiochip%d with base %d\n", dev->id, stmpegpio->chip.base);
+ return 0;
+}
+
+static struct driver_d stmpe_gpio_driver = {
+ .name = "stmpe-gpio",
+ .probe = stmpe_gpio_probe,
+};
+
+static int stmpe_gpio_add(void)
+{
+ register_driver(&stmpe_gpio_driver);
+ return 0;
+}
+coredevice_initcall(stmpe_gpio_add);
--
1.7.10.4
More information about the barebox
mailing list