2015-06-20 22:13:13

by Stefan Agner

[permalink] [raw]
Subject: [PATCH 0/2] FTDI CBUS GPIO support

Yet another FTDI GPIO patchset. Yet somewhat different to previous
implementations...

There are three GPIO modes supported by FTDI devices:
1. Asynchronous Bit Bang Mode (used in Sacha's patch)
2. Synchronous Bit Bang Mode (used in Philipp's patch)
3. CBUS Bit Bang Mode (used in Philipp's patch and this patchset)

Previous implementations:
- Philipp Hachtmann (https://lkml.org/lkml/2014/5/31/181)
- Sascha Silbe (https://lkml.org/lkml/2014/6/9/406)

The first two modes allow to control the serial pins and use the USB
standard data transfer (write/read) to set the GPIO output values. Hence
these modes interference with the standard serial mode of the devices,
but are fast. The third option uses the USB control transfer to set
GPIOs (which makes bit banging slower), and allows to control only 4
pins. The controllable pins are predefined per device type (in FT232R
CBUS0-3, in FT232H ACBUS5-9) and are not required for standard
UART/serial communication. However, the default configuration is set to
auxiliary functions such as TX/RXLED. Hence to make use of them in CBUS
Bit Bang mode, the pins need to be reprogrammed to I/O mode first
(EEPROM). All three modes are supported from userspace by libftdi afaik.

In my use case I would like to use the additional GPIOs to control an
embedded board (power off/reset etc.) and use the serial communication
alongside. Using libftdi to use the CBUS Bit Bang mode is cumbersome,
since libftdi requires to detach the kernel driver to get access to the
device. The user needs then to reconnect the serial terminal every time
a GPIO has been used. Hence, if any of these modes, I see most value in
supporting the CBUS mode through the kernel's gpiolib API. However,
since some functions are shared (e.g. set_bitmode to enable the
different bit modes), this patchset is does some ground work for the
other modes too, in case anybody wants to do further work on them.

This patchset currently supports FT232R type of devices and has been
tested using a FT232RL device. I think the FT232H (and probably later)
types of devices should work too (at least the Table 3.5 in the FT232H
data sheet mentions the ACBUS Signal Option "I/O mode"). However, I
don't have such a device to test at my disposal.

On the implementation side, I created a distinct GPIO driver in
drivers/gpio and create that platform device directly from within the
ftdi_sio driver. I understand that the mfd subsystem would be the way to
go, however it seems to me quite a big change... At least all USB device
IDs would need to be moved to the mfd core device since the mfd device
would be registered as a USB driver. I guess the ftdi_sio driver would
become a platform device and still live under drivers/usb/serial/...?

I just saw that recent discussion by Grant and Linus did not approve
this approach...?

Stefan Agner (2):
USB: ftdi_sio: add CBUS mode for FT232R devices
gpio: gpio-ftdi-cbus: add driver for FTDI CBUS GPIOs

drivers/gpio/Kconfig | 10 +++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-ftdi-cbus.c | 167 ++++++++++++++++++++++++++++++++++++++++++
drivers/usb/serial/ftdi_sio.c | 57 ++++++++++++++
drivers/usb/serial/ftdi_sio.h | 22 ++++++
include/linux/usb/ftdi_sio.h | 32 ++++++++
include/linux/usb/serial.h | 2 +
7 files changed, 291 insertions(+)
create mode 100644 drivers/gpio/gpio-ftdi-cbus.c
create mode 100644 include/linux/usb/ftdi_sio.h

--
2.4.4


2015-06-20 22:13:25

by Stefan Agner

[permalink] [raw]
Subject: [PATCH 1/2] USB: ftdi_sio: add CBUS mode for FT232R devices

Add interface to allow CBUS access. The functions set_bitmode and
read_pins use control transfers only hence should not interfere
with the serial operation mode.

Signed-off-by: Stefan Agner <[email protected]>
---
drivers/usb/serial/ftdi_sio.c | 41 +++++++++++++++++++++++++++++++++++++++++
drivers/usb/serial/ftdi_sio.h | 22 ++++++++++++++++++++++
include/linux/usb/ftdi_sio.h | 32 ++++++++++++++++++++++++++++++++
include/linux/usb/serial.h | 2 ++
4 files changed, 97 insertions(+)
create mode 100644 include/linux/usb/ftdi_sio.h

diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 4c8b3b8..23a3280 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1384,6 +1384,47 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
return rv;
}

+int ftdi_sio_set_bitmode(struct usb_serial_port *port, u8 bitmask, u8 bitmode)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ __u16 urb_value = 0;
+ int rv = 0;
+
+ urb_value = bitmode << 8 | bitmask;
+
+ rv = usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ FTDI_SIO_SET_BITMODE_REQUEST,
+ FTDI_SIO_SET_BITMODE_REQUEST_TYPE,
+ urb_value, priv->interface,
+ NULL, 0, WDR_SHORT_TIMEOUT);
+ return rv;
+}
+EXPORT_SYMBOL(ftdi_sio_set_bitmode);
+
+int ftdi_sio_read_pins(struct usb_serial_port *port, u8 *pins)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int rv;
+ u8 *buf;
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ rv = usb_control_msg(port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+ FTDI_SIO_READ_PINS_REQUEST,
+ FTDI_SIO_READ_PINS_REQUEST_TYPE,
+ 0, priv->interface,
+ buf, 1, WDR_SHORT_TIMEOUT);
+ *pins = *buf;
+ kfree(buf);
+
+ return rv;
+}
+EXPORT_SYMBOL(ftdi_sio_read_pins);
+
static int write_latency_timer(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index ed58c6f..a62eb15 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -35,6 +35,8 @@
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */
#define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */
+#define FTDI_SIO_SET_BITMODE 11 /* Set the bitmode */
+#define FTDI_SIO_READ_PINS 12 /* Read pins in bitmode */

/* Interface indices for FT2232, FT2232H and FT4232H devices */
#define INTERFACE_A 1
@@ -345,6 +347,26 @@ enum ftdi_sio_baudrate {
*/

/*
+ * FTDI_SIO_SET_BITMODE
+ *
+ * Set the chip's bitbang mode. Used to switch FT232R into CBUS mode.
+ * For details see of the bitbang modes supported by FT232R devices
+ * refer to the FTDI Application Note AN_232R-01.
+ */
+
+#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE
+#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40
+
+/*
+ * FTDI_SIO_READ_PINS
+ *
+ * Read the current value of the bit mode.
+ */
+
+#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS
+#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xC0
+
+/*
* FTDI_SIO_SET_EVENT_CHAR
*
* Set the special event character for the specified communications port.
diff --git a/include/linux/usb/ftdi_sio.h b/include/linux/usb/ftdi_sio.h
new file mode 100644
index 0000000..8e1a292
--- /dev/null
+++ b/include/linux/usb/ftdi_sio.h
@@ -0,0 +1,32 @@
+/*
+ * Interface for FTDI SIO driver used by CBUS GPIO driver
+ *
+ * Copyright 2015 Stefan Agner
+ *
+ * Author: Stefan Agner <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_USB_FTDI_SIO_H
+#define __LINUX_USB_FTDI_SIO_H
+
+#include <linux/usb/serial.h>
+
+/* MPSSE bitbang modes */
+enum ftdi_mpsse_mode {
+ /* switch off bitbang mode, back to regular serial/FIFO */
+ BITMODE_RESET = 0x00,
+
+ /* Bitbang on CBUS pins of R-type chips, configure in EEPROM before */
+ BITMODE_CBUS = 0x20,
+};
+
+int ftdi_sio_set_bitmode(struct usb_serial_port *port, u8 bitmask, u8 bitmode);
+int ftdi_sio_read_pins(struct usb_serial_port *port, u8 *pins);
+
+#endif /* __LINUX_USB_FTDI_SIO_H */
+
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 704a1ab..d710656 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -17,6 +17,8 @@
#include <linux/mutex.h>
#include <linux/serial.h>
#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/usb.h>
#include <linux/kfifo.h>

/* The maximum number of ports one device can grab at once */
--
2.4.4

2015-06-20 22:13:34

by Stefan Agner

[permalink] [raw]
Subject: [PATCH 2/2] gpio: gpio-ftdi-cbus: add driver for FTDI CBUS GPIOs

This driver allows to use the CBUS pins, e.g. CBUS 0-3 on FT232R
type of devices. Note that the pins need to be configured first
by using I/O mode signal option in the EEPROM. This is _not_ the
factory default configuration of any of the four pins.

See also FTDI's Application Note AN_232R-01.

Signed-off-by: Stefan Agner <[email protected]>
---
drivers/gpio/Kconfig | 10 +++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-ftdi-cbus.c | 167 ++++++++++++++++++++++++++++++++++++++++++
drivers/usb/serial/ftdi_sio.c | 16 ++++
4 files changed, 194 insertions(+)
create mode 100644 drivers/gpio/gpio-ftdi-cbus.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index caefe80..450ba9f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -975,6 +975,16 @@ endmenu
menu "USB GPIO expanders"
depends on USB

+config GPIO_FTDI_CBUS
+ tristate "FTDI FT232R CBUS bitmode GPIO support"
+ depends on USB_SERIAL_FTDI_SIO
+ help
+ Say yes to use up to four CBUS pins on FT232R type of devices
+ Note that the pins need to be configured in EEPROM using to
+ "I/O mode" signal option first. The factory configuration
+ does not ship with this signal option set for any of the four
+ supported CBUS pins.
+
config GPIO_VIPERBOARD
tristate "Viperboard GPIO a & b support"
depends on MFD_VIPERBOARD && USB
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index f71bb97..a5d661b4 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
+obj-$(CONFIG_GPIO_FTDI_CBUS) += gpio-ftdi-cbus.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
diff --git a/drivers/gpio/gpio-ftdi-cbus.c b/drivers/gpio/gpio-ftdi-cbus.c
new file mode 100644
index 0000000..3a4dc46
--- /dev/null
+++ b/drivers/gpio/gpio-ftdi-cbus.c
@@ -0,0 +1,167 @@
+/*
+ * gpiolib support for FTDI SIO chips supporting CBUS GPIO's (FT232R class)
+ *
+ * Copyright 2015 Stefan Agner
+ *
+ * Author: Stefan Agner <[email protected]>
+ *
+ * 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.
+ *
+ * Note: To use the GPIOs on CBUS the signal option need to be set to
+ * I/O mode in EEPROM!
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/regmap.h>
+
+#include <linux/usb/ftdi_sio.h>
+
+struct ftdi_cbus_gpio {
+ struct usb_serial_port *port;
+ struct gpio_chip gpio_chip;
+ u8 cbus_mask;
+};
+
+static inline struct ftdi_cbus_gpio *to_ftdi_cbus_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct ftdi_cbus_gpio, gpio_chip);
+}
+
+static int ftdi_cbus_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct ftdi_cbus_gpio *fcg = to_ftdi_cbus_gpio(chip);
+
+ fcg->cbus_mask &= ~((1 << offset) << 4);
+
+ return ftdi_sio_set_bitmode(fcg->port, fcg->cbus_mask, BITMODE_CBUS);
+}
+
+static int ftdi_cbus_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct ftdi_cbus_gpio *fcg = to_ftdi_cbus_gpio(chip);
+
+ fcg->cbus_mask |= ((1 << offset) << 4);
+ if (value)
+ fcg->cbus_mask |= (1 << offset);
+ else
+ fcg->cbus_mask &= ~(1 << offset);
+
+ return ftdi_sio_set_bitmode(fcg->port, fcg->cbus_mask, BITMODE_CBUS);
+}
+
+static void ftdi_cbus_gpio_set(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct ftdi_cbus_gpio *fcg = to_ftdi_cbus_gpio(chip);
+ int ret;
+
+ if (value)
+ fcg->cbus_mask |= (1 << offset);
+ else
+ fcg->cbus_mask &= ~(1 << offset);
+
+ ret = ftdi_sio_set_bitmode(fcg->port, fcg->cbus_mask, 0x20);
+ if (ret < 0)
+ dev_warn(chip->dev, "error setting pin value, %d\n", ret);
+}
+
+static int ftdi_cbus_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct ftdi_cbus_gpio *fcg = to_ftdi_cbus_gpio(chip);
+ u8 val;
+ int ret;
+
+ ret = ftdi_sio_read_pins(fcg->port, &val);
+
+ if (ret < 0) {
+ dev_warn(chip->dev, "error getting pin value, %d\n", ret);
+ return 0;
+ }
+
+ if (val & (1 << offset))
+ return 1;
+ else
+ return 0;
+}
+
+static struct gpio_chip ftdi_cbus_gpio_chip = {
+ .label = "ftdi-cbus-gpio",
+ .owner = THIS_MODULE,
+ .direction_input = ftdi_cbus_gpio_direction_input,
+ .direction_output = ftdi_cbus_gpio_direction_output,
+ .get = ftdi_cbus_gpio_get,
+ .set = ftdi_cbus_gpio_set,
+ .can_sleep = true,
+};
+
+static int ftdi_cbus_gpio_probe(struct platform_device *pdev)
+{
+ struct ftdi_cbus_gpio *ftdi_cbus_gpio;
+ int ret = 0;
+
+ ftdi_cbus_gpio = devm_kzalloc(&pdev->dev, sizeof(*ftdi_cbus_gpio),
+ GFP_KERNEL);
+ if (ftdi_cbus_gpio == NULL)
+ return -ENOMEM;
+
+ ftdi_cbus_gpio->port = to_usb_serial_port(pdev->dev.parent);
+ ftdi_cbus_gpio->gpio_chip = ftdi_cbus_gpio_chip;
+ ftdi_cbus_gpio->gpio_chip.base = -1;
+ ftdi_cbus_gpio->gpio_chip.ngpio = 4;
+ ftdi_cbus_gpio->gpio_chip.dev = &pdev->dev;
+
+ ret = gpiochip_add(&ftdi_cbus_gpio->gpio_chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
+ ret);
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, ftdi_cbus_gpio);
+
+err:
+ return ret;
+}
+
+static int ftdi_cbus_gpio_remove(struct platform_device *pdev)
+{
+ struct ftdi_cbus_gpio *fcg = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&fcg->gpio_chip);
+
+ return 0;
+}
+
+static struct platform_driver ftdi_cbus_gpio_driver = {
+ .driver.name = "ftdi-cbus-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = ftdi_cbus_gpio_probe,
+ .remove = ftdi_cbus_gpio_remove,
+};
+
+static int __init ftdi_cbus_gpio_init(void)
+{
+ return platform_driver_register(&ftdi_cbus_gpio_driver);
+}
+subsys_initcall(ftdi_cbus_gpio_init);
+
+static void __exit ftdi_cbus_gpio_exit(void)
+{
+ platform_driver_unregister(&ftdi_cbus_gpio_driver);
+}
+module_exit(ftdi_cbus_gpio_exit);
+
+MODULE_AUTHOR("Stefan Agner <[email protected]>");
+MODULE_DESCRIPTION("GPIO interface for FTDI SIO chips using CBUS bitmode");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ftdi-cbus-gpio");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 23a3280..2711d24 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -33,6 +33,7 @@

#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -1846,6 +1847,21 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
priv->latency = 16;
write_latency_timer(port);
create_sysfs_attrs(port);
+
+ if (priv->chip_type == FT232RL) {
+ struct platform_device *pdev;
+ int ret;
+
+ pdev = platform_device_alloc("ftdi-cbus-gpio", priv->interface);
+ if (!pdev)
+ return -ENOMEM;
+ pdev->dev.parent = &port->dev;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ return ret;
+ }
+
return 0;
}

--
2.4.4

2015-06-20 23:56:47

by Peter Stuge

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

Stefan Agner wrote:
> libftdi requires to detach the kernel driver to get access to the device

Control transfers ought to be possible without a detach.


//Peter

2015-06-21 02:32:59

by Philipp Hachtmann

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

Am 21.06.2015 um 00:12 schrieb Stefan Agner:
> There are three GPIO modes supported by FTDI devices:
> 1. Asynchronous Bit Bang Mode (used in Sacha's patch)
> 2. Synchronous Bit Bang Mode (used in Philipp's patch)
> 3. CBUS Bit Bang Mode (used in Philipp's patch and this patchset)

1. No idea, could be
2. wrong
3. wrong

This is more complicated as I remember. The chip (I speak of FT232H here,
because it's "my" chip) has quite a lot of options.

Reference: http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232H.pdf

I did not use a bit bang mode. My patches were about synchronous FIFO mode and
CBUS control. I'll try to explain.

There are eight data lines called ADBUS[7:0] and ten "other" lines called
ACBUS[9:0].

When the chip is configured (EEPROM!) for UART mode (default), the RX, TX and
modem status lines are assigned to ADBUS[7:0]. ACBUS7 can be used as an USB
voltage detect input (and for nothing else in any case as it looks).
The other ACBUS lines can be configured for several tasks like TXLED, RXLED,
SLEEP, clock output etc.
The ACBUS5, ACBUS6, ACBUS8 and ACBUS9 can also individually be configured to I/O
mode which the datasheet calls "ACBUS BitBang".
These up to four (depending on user's choice) GPIO lines can be accessed from
the host. They're usable for extra control to attached hardware. Controlling
these CBUS lines was the intent of my CBUS patch.

My usblink board (FT232H plus FPGA etc.) makes use of the FT232H's asynchronous
and synchronous FIFO modes. The asynchronous FIFO mode has to be selected by
EEPROM settings. This works out of the box with the ftdi_sio driver. The driver
doesn't notice anything. Just works. Baud rate settings etc. become meaningless,
of course :-)
If you want to get the full USB 2.0 speed you have to use the synchronous FIFO
mode. For this to work the chip has to be eeprom configured to asynchronous FIFO
mode and then the driver has to select synchronous FIFO mode. This was subject
of my other patch.

The chip has some other more or less cool modes but I have no idea if and how
they work with the ftdi_sio driver. Two of them are named asynchronous and
synchronous BitBang mode.

Conclusion:
The FTDI chip has different *modes* of operation which can be selected by eeprom
and/or software. The mode determines the use of the *ADBUS* and some ACBUS pins.
Two of modes are called bit bang modes.

ACBUS bit bang is an additional functionality which is *not to be confused* with
the chip's operation mode!

The confusion comes from things like FTDI_SIO_SET_BITBANG_REQUEST to do anything...

I have not forgotten about the comments on my patches a year ago. I just did not
yet find the time to do add that GPIO stuff.

Two interfaces have to be added to the driver:

- One for setting the mode (here: switch to synchronous FIFO)
I suggest adding a sysfs property here.

- One for the four CBUS bits
I *still* suggest adding a sysfs property *and* adding GPIO support as well.

I will most probably get back to the stuff in July.


Kind regards

Philipp

2015-06-21 19:42:19

by Stefan Agner

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

Hi Philipp,

On 2015-06-21 04:22, Philipp Hachtmann wrote:
> Am 21.06.2015 um 00:12 schrieb Stefan Agner:
>> There are three GPIO modes supported by FTDI devices:
>> 1. Asynchronous Bit Bang Mode (used in Sacha's patch)
>> 2. Synchronous Bit Bang Mode (used in Philipp's patch)
>> 3. CBUS Bit Bang Mode (used in Philipp's patch and this patchset)
>
> 1. No idea, could be
> 2. wrong
> 3. wrong

The list is taken from FTDI's application note AN_232R-01, which mainly
refers to FT232R:
http://www.ftdichip.com/Support/Documents/AppNotes/AN_232R-01_Bit_Bang_Mode_Available_For_FT232R_and_Ft245R.pdf

However, as far as I understand those three bit bang options are also
available on FT232H (maybe there even more on those device?).

FTDI calls all 3 of them modes, but one can argue whether the third
really is an "operation mode" or just a "functionality" to set the CBUS
pins...

However, regarding option 2, I see now, your patch was about introducing
the option to use the Synchronous _FIFO_ mode which is not the same as
the Synchronous Bit Bang mode, hence this is clearly wrong in my list.
Sorry about that.

>
> This is more complicated as I remember. The chip (I speak of FT232H
> here, because it's "my" chip) has quite a lot of options.
>
> Reference:
> http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232H.pdf
>
> I did not use a bit bang mode. My patches were about synchronous FIFO
> mode and CBUS control. I'll try to explain.
>
> There are eight data lines called ADBUS[7:0] and ten "other" lines
> called ACBUS[9:0].

I think we really refer to the same regarding CBUS mode. In the
application note above, this mode is called "CBUS Bit Bang"...

Your patch also uses FTDI_SIO_SET_BITBANG command 11 with the higher
byte set to 0x20 (FTDI_BITMODE_CBUS).


>
> When the chip is configured (EEPROM!) for UART mode (default), the RX,
> TX and modem status lines are assigned to ADBUS[7:0]. ACBUS7 can be
> used as an USB voltage detect input (and for nothing else in any case
> as it looks).
> The other ACBUS lines can be configured for several tasks like TXLED,
> RXLED, SLEEP, clock output etc.
> The ACBUS5, ACBUS6, ACBUS8 and ACBUS9 can also individually be
> configured to I/O mode which the datasheet calls "ACBUS BitBang".
> These up to four (depending on user's choice) GPIO lines can be
> accessed from the host. They're usable for extra control to attached
> hardware. Controlling these CBUS lines was the intent of my CBUS
> patch.

This is the very same for FT232R devices, just that those devices call
the pins CBUS0-3.

>
> My usblink board (FT232H plus FPGA etc.) makes use of the FT232H's
> asynchronous and synchronous FIFO modes. The asynchronous FIFO mode
> has to be selected by EEPROM settings. This works out of the box with
> the ftdi_sio driver. The driver doesn't notice anything. Just works.
> Baud rate settings etc. become meaningless, of course :-)
> If you want to get the full USB 2.0 speed you have to use the
> synchronous FIFO mode. For this to work the chip has to be eeprom
> configured to asynchronous FIFO mode and then the driver has to select
> synchronous FIFO mode. This was subject of my other patch.
>
> The chip has some other more or less cool modes but I have no idea if
> and how they work with the ftdi_sio driver. Two of them are named
> asynchronous and synchronous BitBang mode.
>
> Conclusion:
> The FTDI chip has different *modes* of operation which can be selected
> by eeprom and/or software. The mode determines the use of the *ADBUS*
> and some ACBUS pins. Two of modes are called bit bang modes.
>
> ACBUS bit bang is an additional functionality which is *not to be
> confused* with the chip's operation mode!

I agree, the (A)CBUS bit bang "mode" is somewhat different as it doesn't
alter the functionality of the chip beyond the ability to use the
configured CBUS pins..

>
> The confusion comes from things like FTDI_SIO_SET_BITBANG_REQUEST to
> do anything...
>
> I have not forgotten about the comments on my patches a year ago. I
> just did not yet find the time to do add that GPIO stuff.
>
> Two interfaces have to be added to the driver:
>
> - One for setting the mode (here: switch to synchronous FIFO)
> I suggest adding a sysfs property here.
>
> - One for the four CBUS bits
> I *still* suggest adding a sysfs property *and* adding GPIO support as well.

The only drawback in using gpiolib compared to sysfs is that some USB
control messages could be avoided since one can control the direction
and values of 4 pins using one byte and one USB control transfer.
However, since this mode is anyway not really meant as a high
performance bit bang mode, I think the overhead of gpiolib is
acceptable. It certainly is for my use case.

>
> I will most probably get back to the stuff in July.

Ok cool. If that is ok for you, I will still work on this basic CBUS
mode, I guess your patches could easily be rebased on-top of my work.


--
Stefan

2015-06-21 19:47:06

by Stefan Agner

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

On 2015-06-21 01:49, Peter Stuge wrote:
> Stefan Agner wrote:
>> libftdi requires to detach the kernel driver to get access to the device
>
> Control transfers ought to be possible without a detach.

Good to know, thanks for this input. The detach is probably a default
behavior of libftdi... Will have a look at that.

Having kernel level gpiolib would still have advantages: It would make
the matching of the GPIO's and tty device easier, since with this patch
the gpiolib device is a sub-node of the usb-serial device in sysfs and
the user would have to use kernel interfaces only (no libftdi)...

--
Stefan

2015-06-22 17:26:33

by Johan Hovold

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

On Sun, Jun 21, 2015 at 12:12:55AM +0200, Stefan Agner wrote:
> Yet another FTDI GPIO patchset. Yet somewhat different to previous
> implementations...
>
> There are three GPIO modes supported by FTDI devices:
> 1. Asynchronous Bit Bang Mode (used in Sacha's patch)
> 2. Synchronous Bit Bang Mode (used in Philipp's patch)
> 3. CBUS Bit Bang Mode (used in Philipp's patch and this patchset)
>
> Previous implementations:
> - Philipp Hachtmann (https://lkml.org/lkml/2014/5/31/181)
> - Sascha Silbe (https://lkml.org/lkml/2014/6/9/406)
>
> The first two modes allow to control the serial pins and use the USB
> standard data transfer (write/read) to set the GPIO output values. Hence
> these modes interference with the standard serial mode of the devices,
> but are fast. The third option uses the USB control transfer to set
> GPIOs (which makes bit banging slower), and allows to control only 4
> pins. The controllable pins are predefined per device type (in FT232R
> CBUS0-3, in FT232H ACBUS5-9) and are not required for standard
> UART/serial communication. However, the default configuration is set to
> auxiliary functions such as TX/RXLED. Hence to make use of them in CBUS
> Bit Bang mode, the pins need to be reprogrammed to I/O mode first
> (EEPROM). All three modes are supported from userspace by libftdi afaik.

Is there a way to retrieve the settings from eeprom and only register
the gpio chip based on the configuration?

> In my use case I would like to use the additional GPIOs to control an
> embedded board (power off/reset etc.) and use the serial communication
> alongside. Using libftdi to use the CBUS Bit Bang mode is cumbersome,
> since libftdi requires to detach the kernel driver to get access to the
> device. The user needs then to reconnect the serial terminal every time
> a GPIO has been used. Hence, if any of these modes, I see most value in
> supporting the CBUS mode through the kernel's gpiolib API. However,
> since some functions are shared (e.g. set_bitmode to enable the
> different bit modes), this patchset is does some ground work for the
> other modes too, in case anybody wants to do further work on them.

I agree, the usb-serial driver should only provide access to the four
cbus pins if available (and use gpiolib).

> This patchset currently supports FT232R type of devices and has been
> tested using a FT232RL device. I think the FT232H (and probably later)
> types of devices should work too (at least the Table 3.5 in the FT232H
> data sheet mentions the ACBUS Signal Option "I/O mode"). However, I
> don't have such a device to test at my disposal.
>
> On the implementation side, I created a distinct GPIO driver in
> drivers/gpio and create that platform device directly from within the
> ftdi_sio driver. I understand that the mfd subsystem would be the way to
> go, however it seems to me quite a big change... At least all USB device
> IDs would need to be moved to the mfd core device since the mfd device
> would be registered as a USB driver. I guess the ftdi_sio driver would
> become a platform device and still live under drivers/usb/serial/...?
>
> I just saw that recent discussion by Grant and Linus did not approve
> this approach...?

Using the platform bus -- directly as you do or via MFD -- allows for
some (arguably contrived) abstraction but I think we should avoid it
nonetheless. USB (serial) does not use it as you already noted, and
there's not much to gain from creating a single-cell-mfd child device to
the USB interface.

Instead, hang the gpio chip directly off the usb interface (not the
port), add a new config option, and keep the gpio implementation under
drivers/usb/serial (possibly in its own file ftdi_sio-gpio.c).

Note that your current implementation fails to remove the gpio chip on
device disconnect, leaks resources in error paths, and lacks locking for
the gpio state.

Thanks,
Johan

2015-06-22 20:14:10

by Stefan Agner

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

On 2015-06-22 19:26, Johan Hovold wrote:
> On Sun, Jun 21, 2015 at 12:12:55AM +0200, Stefan Agner wrote:
<snip>
>> Bit Bang mode, the pins need to be reprogrammed to I/O mode first
>> (EEPROM). All three modes are supported from userspace by libftdi afaik.
>
> Is there a way to retrieve the settings from eeprom and only register
> the gpio chip based on the configuration?
>

Afaik, there is. Not sure if that is somewhat standardized between the
different controllers, will have a look at it.

>> In my use case I would like to use the additional GPIOs to control an
>> embedded board (power off/reset etc.) and use the serial communication
>> alongside. Using libftdi to use the CBUS Bit Bang mode is cumbersome,
>> since libftdi requires to detach the kernel driver to get access to the
>> device. The user needs then to reconnect the serial terminal every time
>> a GPIO has been used. Hence, if any of these modes, I see most value in
>> supporting the CBUS mode through the kernel's gpiolib API. However,
>> since some functions are shared (e.g. set_bitmode to enable the
>> different bit modes), this patchset is does some ground work for the
>> other modes too, in case anybody wants to do further work on them.
>
> I agree, the usb-serial driver should only provide access to the four
> cbus pins if available (and use gpiolib).
>
>> This patchset currently supports FT232R type of devices and has been
>> tested using a FT232RL device. I think the FT232H (and probably later)
>> types of devices should work too (at least the Table 3.5 in the FT232H
>> data sheet mentions the ACBUS Signal Option "I/O mode"). However, I
>> don't have such a device to test at my disposal.
>>
>> On the implementation side, I created a distinct GPIO driver in
>> drivers/gpio and create that platform device directly from within the
>> ftdi_sio driver. I understand that the mfd subsystem would be the way to
>> go, however it seems to me quite a big change... At least all USB device
>> IDs would need to be moved to the mfd core device since the mfd device
>> would be registered as a USB driver. I guess the ftdi_sio driver would
>> become a platform device and still live under drivers/usb/serial/...?
>>
>> I just saw that recent discussion by Grant and Linus did not approve
>> this approach...?
>
> Using the platform bus -- directly as you do or via MFD -- allows for
> some (arguably contrived) abstraction but I think we should avoid it
> nonetheless. USB (serial) does not use it as you already noted, and
> there's not much to gain from creating a single-cell-mfd child device to
> the USB interface.
>
> Instead, hang the gpio chip directly off the usb interface (not the
> port), add a new config option, and keep the gpio implementation under
> drivers/usb/serial (possibly in its own file ftdi_sio-gpio.c).

Agreed sounds like a good plan. Will try this approach in v2.

Except I don't think hanging it directly to the USB interface is the
right thing to do.

Looking at the block diagram of FT232R or FT232H, the CBUS pins seem to
be part of the UART/FIFO controller. And I think the dual UART FT2232D
actually supports controlling the CBUS pins of the two UART controllers
individually, at least the block diagram thereof suggests so.


> Note that your current implementation fails to remove the gpio chip on
> device disconnect, leaks resources in error paths, and lacks locking for
> the gpio state.

Oh true. I was aware that it is somewhat rough, should probably have
sent the patch as RFC...

--
Stefan

2015-06-23 09:22:31

by Johan Hovold

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

On Mon, Jun 22, 2015 at 10:11:35PM +0200, Stefan Agner wrote:
> On 2015-06-22 19:26, Johan Hovold wrote:

> > Instead, hang the gpio chip directly off the usb interface (not the
> > port), add a new config option, and keep the gpio implementation under
> > drivers/usb/serial (possibly in its own file ftdi_sio-gpio.c).
>
> Agreed sounds like a good plan. Will try this approach in v2.
>
> Except I don't think hanging it directly to the USB interface is the
> right thing to do.
>
> Looking at the block diagram of FT232R or FT232H, the CBUS pins seem to
> be part of the UART/FIFO controller. And I think the dual UART FT2232D
> actually supports controlling the CBUS pins of the two UART controllers
> individually, at least the block diagram thereof suggests so.

The port is a Linux abstraction, and for FTDI we happen to have exactly
one port child device per USB interface. As I see it, the gpio
controller for the CBUS pins should be a sibling rather than a child
device to the port.

Note that we'd still have two gpio-controllers on FT2232D (one per USB
interface).

I'm aware that this requires some restructuring of the ftdi_sio-driver
(e.g. the device type and ftdi-interface number should be a feature of
the usb-serial rather than usb-serial-port device).

Thanks,
Johan

2015-06-23 22:11:28

by Stefan Agner

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

On 2015-06-23 11:22, Johan Hovold wrote:
> On Mon, Jun 22, 2015 at 10:11:35PM +0200, Stefan Agner wrote:
>> On 2015-06-22 19:26, Johan Hovold wrote:
>
>> > Instead, hang the gpio chip directly off the usb interface (not the
>> > port), add a new config option, and keep the gpio implementation under
>> > drivers/usb/serial (possibly in its own file ftdi_sio-gpio.c).
>>
>> Agreed sounds like a good plan. Will try this approach in v2.
>>
>> Except I don't think hanging it directly to the USB interface is the
>> right thing to do.
>>
>> Looking at the block diagram of FT232R or FT232H, the CBUS pins seem to
>> be part of the UART/FIFO controller. And I think the dual UART FT2232D
>> actually supports controlling the CBUS pins of the two UART controllers
>> individually, at least the block diagram thereof suggests so.
>
> The port is a Linux abstraction, and for FTDI we happen to have exactly
> one port child device per USB interface. As I see it, the gpio
> controller for the CBUS pins should be a sibling rather than a child
> device to the port.
>
> Note that we'd still have two gpio-controllers on FT2232D (one per USB
> interface).

I did some research. I think the FT2232D or FT2232H devices do not
support the CBUS Bit Bang mode. For instance the D2XX Programmer's Guide
indicates that on page 69 (CBUS Bit Bang Mode (FT232R and FT232H devices
only)) as well as the AN_184 "FTDI Device Input Output Pin States", does
not mention that the CBUS pins as EEPROM selectable (the same document
does so for FT232R/FT232H devices)...

I don't have such a device, hence I can't try it out...

> I'm aware that this requires some restructuring of the ftdi_sio-driver
> (e.g. the device type and ftdi-interface number should be a feature of
> the usb-serial rather than usb-serial-port device).

The findings above probably do not change the fact that we should not
use the Linux port abstraction to attach the GPIO controller...

I looked into that a bit more in depth. Do I see things right that the
multi-port devices have multiple USB interfaces, which leads to
usb_serial_probe and in turn ftdi_sio_probe getting called multiple
times by the USB stack? If yes, I think I have the bigger picture to go
ahead and try to implement it accordingly.

--
Stefan



2015-06-24 07:56:55

by Johan Hovold

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

On Wed, Jun 24, 2015 at 12:08:50AM +0200, Stefan Agner wrote:
> On 2015-06-23 11:22, Johan Hovold wrote:
> > On Mon, Jun 22, 2015 at 10:11:35PM +0200, Stefan Agner wrote:
> >> On 2015-06-22 19:26, Johan Hovold wrote:
> >
> >> > Instead, hang the gpio chip directly off the usb interface (not the
> >> > port), add a new config option, and keep the gpio implementation under
> >> > drivers/usb/serial (possibly in its own file ftdi_sio-gpio.c).
> >>
> >> Agreed sounds like a good plan. Will try this approach in v2.
> >>
> >> Except I don't think hanging it directly to the USB interface is the
> >> right thing to do.
> >>
> >> Looking at the block diagram of FT232R or FT232H, the CBUS pins seem to
> >> be part of the UART/FIFO controller. And I think the dual UART FT2232D
> >> actually supports controlling the CBUS pins of the two UART controllers
> >> individually, at least the block diagram thereof suggests so.
> >
> > The port is a Linux abstraction, and for FTDI we happen to have exactly
> > one port child device per USB interface. As I see it, the gpio
> > controller for the CBUS pins should be a sibling rather than a child
> > device to the port.
> >
> > Note that we'd still have two gpio-controllers on FT2232D (one per USB
> > interface).
>
> I did some research. I think the FT2232D or FT2232H devices do not
> support the CBUS Bit Bang mode. For instance the D2XX Programmer's Guide
> indicates that on page 69 (CBUS Bit Bang Mode (FT232R and FT232H devices
> only)) as well as the AN_184 "FTDI Device Input Output Pin States", does
> not mention that the CBUS pins as EEPROM selectable (the same document
> does so for FT232R/FT232H devices)...
>
> I don't have such a device, hence I can't try it out...

Just make sure to only register the gpio chip for device types that
support it (and devices that are configured for it...).

> > I'm aware that this requires some restructuring of the ftdi_sio-driver
> > (e.g. the device type and ftdi-interface number should be a feature of
> > the usb-serial rather than usb-serial-port device).
>
> The findings above probably do not change the fact that we should not
> use the Linux port abstraction to attach the GPIO controller...
>
> I looked into that a bit more in depth. Do I see things right that the
> multi-port devices have multiple USB interfaces, which leads to
> usb_serial_probe and in turn ftdi_sio_probe getting called multiple
> times by the USB stack? If yes, I think I have the bigger picture to go
> ahead and try to implement it accordingly.

Yes, that is correct.

Johan

2015-06-30 06:47:02

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 1/2] USB: ftdi_sio: add CBUS mode for FT232R devices

On Sun, Jun 21, 2015 at 12:12 AM, Stefan Agner <[email protected]> wrote:

> Add interface to allow CBUS access. The functions set_bitmode and
> read_pins use control transfers only hence should not interfere
> with the serial operation mode.
>
> Signed-off-by: Stefan Agner <[email protected]>

Interesting. Waiting for Johan's review on both patches.

Need his or Greg's ACK on patch 1 if I should merge through the GPIO
tree.

Yours,
Linus Walleij

2015-06-30 06:54:11

by Johan Hovold

[permalink] [raw]
Subject: Re: [PATCH 1/2] USB: ftdi_sio: add CBUS mode for FT232R devices

On Tue, Jun 30, 2015 at 08:46:51AM +0200, Linus Walleij wrote:
> On Sun, Jun 21, 2015 at 12:12 AM, Stefan Agner <[email protected]> wrote:
>
> > Add interface to allow CBUS access. The functions set_bitmode and
> > read_pins use control transfers only hence should not interfere
> > with the serial operation mode.
> >
> > Signed-off-by: Stefan Agner <[email protected]>
>
> Interesting. Waiting for Johan's review on both patches.

See the discussion in the cover letter thread.

https://lkml.org/lkml/2015/6/20/205

Johan

2015-07-15 07:42:06

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 2/2] gpio: gpio-ftdi-cbus: add driver for FTDI CBUS GPIOs

On Sun, Jun 21, 2015 at 12:12 AM, Stefan Agner <[email protected]> wrote:

> This driver allows to use the CBUS pins, e.g. CBUS 0-3 on FT232R
> type of devices. Note that the pins need to be configured first
> by using I/O mode signal option in the EEPROM. This is _not_ the
> factory default configuration of any of the four pins.
>
> See also FTDI's Application Note AN_232R-01.
>
> Signed-off-by: Stefan Agner <[email protected]>

I see no big problems with this driver but I guess the serial portions
are the controversial parts.

> +++ b/drivers/gpio/gpio-ftdi-cbus.c
> @@ -0,0 +1,167 @@
> +/*
> + * gpiolib support for FTDI SIO chips supporting CBUS GPIO's (FT232R class)
> + *
> + * Copyright 2015 Stefan Agner
> + *
> + * Author: Stefan Agner <[email protected]>
> + *
> + * 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.
> + *
> + * Note: To use the GPIOs on CBUS the signal option need to be set to
> + * I/O mode in EEPROM!
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/gpio.h>

#include <linux/gpio/driver.h>

should be enough.

> +static int ftdi_cbus_gpio_direction_input(struct gpio_chip *chip,
> + unsigned offset)
> +{
> + struct ftdi_cbus_gpio *fcg = to_ftdi_cbus_gpio(chip);
> +
> + fcg->cbus_mask &= ~((1 << offset) << 4);

I usually replace:

(1 << offset)

with

#include <linux/bitops.h>

BIT(offset)

so it's clear what is happening.

Yours,
Linus Walleij

2015-08-23 20:22:18

by Grant Likely

[permalink] [raw]
Subject: Re: [PATCH 0/2] FTDI CBUS GPIO support

On Sun, 21 Jun 2015 21:44:30 +0200
, Stefan Agner <[email protected]>
wrote:
> On 2015-06-21 01:49, Peter Stuge wrote:
> > Stefan Agner wrote:
> >> libftdi requires to detach the kernel driver to get access to the device
> >
> > Control transfers ought to be possible without a detach.
>
> Good to know, thanks for this input. The detach is probably a default
> behavior of libftdi... Will have a look at that.

libftdi is built on libusb. libusb detaches the device from ftdi_sio and
binds it to a special driver for userspace access. There may indeed be
another way to do it, but libusb doesn't know how to do it AFAIKS.

We can't avoid the detach on current libftdi, but I do have a patch to
libftdi that will at least reconnect the ftdi_sio driver after userspace
has finished. I'll be posting it to the libftdi list in the next week,
but I've attached it below for anyone who wants to play.

> Having kernel level gpiolib would still have advantages: It would make
> the matching of the GPIO's and tty device easier, since with this patch
> the gpiolib device is a sub-node of the usb-serial device in sysfs and
> the user would have to use kernel interfaces only (no libftdi)...

NAK on the sysfs interface. Don't add a new ABI. gpiolib is the right
way to expose these pins.

g.

---
Subject: [PATCH] Automatically reattach kernel driver on close

The built-in libusb auto detach feature supports automatically
reattaching the kernel driver when the device is closed. Switch libftdi
to use the libusb auto-detach code so that we can get the Linux ftdi_sio
driver reattached automatically when finished with the device.
---
src/ftdi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/ftdi.c b/src/ftdi.c
index 68489ea096be..0d043690aeca 100644
--- a/src/ftdi.c
+++ b/src/ftdi.c
@@ -548,7 +548,7 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
// Likely scenario is a static ftdi_sio kernel module.
if (ftdi->module_detach_mode == AUTO_DETACH_SIO_MODULE)
{
- if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0)
+ if (libusb_set_auto_detach_kernel_driver(ftdi->usb_dev, 1))
detach_errno = errno;
}

--
2.1.4