Add driver for CBUS pins on FT232H. The driver supports setting
GPIO direction and getting/setting CBUS 0-3 pin value. The CBUS
pins have to be enabled by configuring I/O mode in the FTDI EEPROM.
Signed-off-by: Anatolij Gustschin
---
drivers/gpio/Kconfig | 11 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-ftdi-cbus.c | 251 ++
3 files changed, 263 insertions(+)
create mode 100644 drivers/gpio/gpio-ftdi-cbus.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f235eae..cca784a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -929,6 +929,17 @@ config HTC_EGPIO
several HTC phones. It provides basic support for input
pins, output pins, and irqs.
+config GPIO_FTDI_CBUS
+ tristate "Support for CBUS GPIO pins on FTDI FT232H"
+ depends on MFD_FTDI_FT232H
+ select GPIO_GENERIC
+ help
+ This driver provides basic support for up to four CBUS GPIOs
+ on FT232H. It allows to configure CBUS pins as input or output
+ and to read and write CBUS pin state. You need to enable I/O-mode
+ for ACBUS 5/6/8/9 pins in FTDI EEPROM first. I/O-mode disabled GPIOs
+ will not be used in the driver.
+
config GPIO_JANZ_TTL
tristate "Janz VMOD-TTL Digital IO Module"
depends on MFD_JANZ_CMODIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a9fda6c..c2ab813 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
obj-$(CONFIG_GPIO_EXAR)+= gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
+obj-$(CONFIG_GPIO_FTDI_CBUS) += gpio-ftdi-cbus.o
obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
diff --git a/drivers/gpio/gpio-ftdi-cbus.c b/drivers/gpio/gpio-ftdi-cbus.c
new file mode 100644
index 000..b0adfe3
--- /dev/null
+++ b/drivers/gpio/gpio-ftdi-cbus.c
@@ -0,0 +1,251 @@
+/*
+ * FTDI FT232H CBUS GPIO driver
+ *
+ * Copyright (C) 2017 DENX Software Engineering
+ * Anatolij Gustschin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct ftdi_cbus_gpio {
+ struct platform_device *pdev;
+ struct gpio_chip gpio;
+ const char *gpio_names[4];
+ u8 cbus_pin_offsets[4];
+ u8 cbus_mask;
+ u8 pinbuf[4];
+ u8 eeprom[FTDI_MAX_EEPROM_SIZE];
+};
+
+static const char *ftdi_acbus_names[5] = {
+ "ACBUS5", "ACBUS6", NULL, "ACBUS8", "ACBUS9"
+};
+
+static int ftdi_cbus_gpio_read_pins(struct ftdi_cbus_gpio *priv,
+ unsigned char *pins)
+{
+ struct gpio_chip *chip = >gpio;
+ struct ctrl_desc desc;
+ int ret;
+
+ desc.dir_out = false;
+ desc.request = FTDI_SIO_READ_PINS_REQUEST;
+ desc.requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN;
+ desc.value = 0;
+ desc.index = 1;
+ desc.data = >pinbuf[0];
+ desc.size = 1;
+ desc.timeout = USB_CTRL_GET_TIMEOUT;
+
+ ret = ftdi_ctrl_xfer(priv->pdev, );
+ if (ret < 0) {
+ dev_dbg(chip->parent, "failed to get pin values: %d\n", ret);
+ return ret;
+ }
+
+ *pins = priv->pinbuf[0];
+ return 0;
+}
+
+static inline void ftdi_cbus_init_gpio_data(struct ftdi_cbus_gpio *priv,
+ int gpio_num, int cbus_num)
+{
+ switch (cbus_num) {
+ case 5:
+ case 6:
+ priv->cbus_pin_offsets[gpio_num] = cbus_num - 5;
+ break;
+ case 8:
+ case 9:
+ priv->cbus_pin_offsets[gpio_num] = cbus_num - 6;
+ break;
+ default:
+ return;
+ }
+
+ priv->gpio_names[gpio_num] = ftdi_acbus_names[cbus_num - 5];
+}
+
+static int ftdi_read_eeprom(struct ftdi_cbus_gpio *priv)
+{
+ struct ctrl_desc desc;
+ unsigned int i;
+ int ret;
+
+ desc.dir_out = false;
+ desc.request = FTDI_SIO_READ_EEPROM_REQUEST;
+ desc.requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN;
+ desc.value = 0;
+ desc.size = 2;
+ desc.timeout = USB_CTRL_GET_TIMEOUT;
+
+ for (i = 0; i < FTDI_MAX_EEPROM_SIZE / 2; i++) {
+ desc.index = i;
+ desc.data = >eeprom[i * 2];
+
+ ret = ftdi_ctrl_xfer(priv->pdev, );
+ if (ret < 0) {
+ dev_dbg(>pdev->dev, "EEPROM read failed: %d\n",
+ ret);
+