This patch adds support for the synchronous FIFO mode of the FT232H serial converter chip. This might also be extended to be usable with other FTDI chips. Signed-off-by: Philipp Hachtmann <hachti@xxxxxxxxx> --- drivers/usb/serial/ftdi_sio.c | 65 +++++++++++++++++++++++++++++++++++++++++-- drivers/usb/serial/ftdi_sio.h | 15 ++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 7c6e1de..cacba4a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -73,7 +73,7 @@ struct ftdi_private { this value */ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ - + int syncmode; /* FIFO device in synchronous 245 mode */ unsigned int latency; /* latency setting in use */ unsigned short max_packet_size; struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */ @@ -1327,6 +1327,36 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) return rv; } +static int set_syncmode(struct usb_serial_port *port, int enable) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + + __u16 urb_value = 0; + int rv = 0; + + enable = enable ? 1 : 0; + if (enable == priv->syncmode) + return 0; + + priv->syncmode = enable; + + /* FTDI seems to say that the urb_value should be or'ed with 0xff. But + * when done this way the port gets quite slow. 0x00 seems to work much + * better. + */ + if (enable) + urb_value = FTDI_BITMODE_SYNCFIFO << 8 | 0x00; + + rv = usb_control_msg(port->serial->dev, + usb_sndctrlpipe(port->serial->dev, 0), + FTDI_SIO_SET_BITBANG_REQUEST, + FTDI_SIO_SET_BITBANG_REQUEST_TYPE, + urb_value, priv->interface, + NULL, 0, WDR_SHORT_TIMEOUT); + + return rv; +} + static int write_latency_timer(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); @@ -1628,6 +1658,32 @@ static ssize_t latency_timer_store(struct device *dev, } static DEVICE_ATTR_RW(latency_timer); +static ssize_t syncmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_serial_port *port = to_usb_serial_port(dev); + struct ftdi_private *priv = usb_get_serial_port_data(port); + return sprintf(buf, "%i\n", priv->syncmode); +} + +static ssize_t syncmode_store(struct device *dev, + struct device_attribute *attr, + const char *valbuf, size_t count) +{ + unsigned long value; + int rv; + struct usb_serial_port *port = to_usb_serial_port(dev); + int ret = kstrtoul(valbuf, 0, &value); + if (ret) + return -EINVAL; + + rv = set_syncmode(port, value); + if (rv < 0) + return -EIO; + return count; +} +static DEVICE_ATTR_RW(syncmode); + /* Write an event character directly to the FTDI register. The ASCII value is in the low 8 bits, with the enable bit in the 9th bit. */ static ssize_t store_event_char(struct device *dev, @@ -1678,6 +1734,10 @@ static int create_sysfs_attrs(struct usb_serial_port *port) &dev_attr_latency_timer); } } + if ((!retval) && priv->chip_type == FT232H) { + retval = device_create_file(&port->dev, + &dev_attr_syncmode); + } return retval; } @@ -1698,7 +1758,8 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) device_remove_file(&port->dev, &dev_attr_latency_timer); } } - + if (priv->chip_type == FT232H) + device_remove_file(&port->dev, &dev_attr_syncmode); } /* diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index ed58c6f..04a29f8 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -35,6 +35,7 @@ #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_BITBANG 11 /* Set the bitbang mode */ /* Interface indices for FT2232, FT2232H and FT4232H devices */ #define INTERFACE_A 1 @@ -345,6 +346,20 @@ enum ftdi_sio_baudrate { */ /* + * FTDI_SIO_SET_BITBANG + * + * Set the chip's bitbang mode. Used to switch FT232H (which else?) into + * synchronous FIFO mode which cannot be configured in the eeprom. + * + */ + +#define FTDI_SIO_SET_BITBANG_REQUEST FTDI_SIO_SET_BITBANG +#define FTDI_SIO_SET_BITBANG_REQUEST_TYPE 0x40 + +#define FTDI_BITMODE_RESET 0x00 /* Switch back to normal operation */ +#define FTDI_BITMODE_SYNCFIFO 0x40 /* Switch to syncronous FIFO mode */ + +/* * FTDI_SIO_SET_EVENT_CHAR * * Set the special event character for the specified communications port. -- 2.0.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html