[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1401579066-8298-2-git-send-email-hachti@hachti.de>
Date: Sun, 1 Jun 2014 01:31:05 +0200
From: Philipp Hachtmann <hachti@...hti.de>
To: jhovold@...il.com, gregkh@...uxfoundation.org,
linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org
Cc: Philipp Hachtmann <hachti@...hti.de>
Subject: [PATCH 1/2] usb/ftdi_sio: Add synchronous FIFO mode support for FT232H
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@...hti.de>
---
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-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists