aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/serial/ftdi_sio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r--drivers/usb/serial/ftdi_sio.c90
1 files changed, 80 insertions, 10 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 59c7501840c..80ccfa13e0b 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -47,7 +47,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.4.3"
+#define DRIVER_VERSION "v1.5.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
@@ -82,7 +82,8 @@ struct ftdi_private {
int rx_processed;
unsigned long rx_bytes;
- __u16 interface; /* FT2232C port interface (0 for FT232/245) */
+ __u16 interface; /* FT2232C, FT2232H or FT4232H port interface
+ (0 for FT232/245) */
speed_t force_baud; /* if non-zero, force the baud rate to
this value */
@@ -164,6 +165,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
@@ -694,6 +696,8 @@ static const char *ftdi_chip_name[] = {
[FT232BM] = "FT232BM",
[FT2232C] = "FT2232C",
[FT232RL] = "FT232RL",
+ [FT2232H] = "FT2232H",
+ [FT4232H] = "FT4232H"
};
@@ -745,6 +749,8 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base);
static unsigned short int ftdi_232am_baud_to_divisor(int baud);
static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base);
static __u32 ftdi_232bm_baud_to_divisor(int baud);
+static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base);
+static __u32 ftdi_2232h_baud_to_divisor(int baud);
static struct usb_serial_driver ftdi_sio_device = {
.driver = {
@@ -839,6 +845,36 @@ static __u32 ftdi_232bm_baud_to_divisor(int baud)
return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
}
+static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
+{
+ static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
+ __u32 divisor;
+ int divisor3;
+
+ /* hi-speed baud rate is 10-bit sampling instead of 16-bit */
+ divisor3 = (base / 10 / baud) * 8;
+
+ divisor = divisor3 >> 3;
+ divisor |= (__u32)divfrac[divisor3 & 0x7] << 14;
+ /* Deal with special cases for highest baud rates. */
+ if (divisor == 1)
+ divisor = 0;
+ else if (divisor == 0x4001)
+ divisor = 1;
+ /*
+ * Set this bit to turn off a divide by 2.5 on baud rate generator
+ * This enables baud rates up to 12Mbaud but cannot reach below 1200
+ * baud with this bit set
+ */
+ divisor |= 0x00020000;
+ return divisor;
+}
+
+static __u32 ftdi_2232h_baud_to_divisor(int baud)
+{
+ return ftdi_2232h_baud_base_to_divisor(baud, 120000000);
+}
+
#define set_mctrl(port, set) update_mctrl((port), (set), 0)
#define clear_mctrl(port, clear) update_mctrl((port), 0, (clear))
@@ -997,6 +1033,19 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
baud = 9600;
}
break;
+ case FT2232H: /* FT2232H chip */
+ case FT4232H: /* FT4232H chip */
+ if ((baud <= 12000000) & (baud >= 1200)) {
+ div_value = ftdi_2232h_baud_to_divisor(baud);
+ } else if (baud < 1200) {
+ div_value = ftdi_232bm_baud_to_divisor(baud);
+ } else {
+ dbg("%s - Baud rate too high!", __func__);
+ div_value = ftdi_232bm_baud_to_divisor(9600);
+ div_okay = 0;
+ baud = 9600;
+ }
+ break;
} /* priv->chip_type */
if (div_okay) {
@@ -1197,14 +1246,29 @@ static void ftdi_determine_type(struct usb_serial_port *port)
if (interfaces > 1) {
int inter;
- /* Multiple interfaces. Assume FT2232C. */
- priv->chip_type = FT2232C;
+ /* Multiple interfaces.*/
+ if (version == 0x0800) {
+ priv->chip_type = FT4232H;
+ /* Hi-speed - baud clock runs at 120MHz */
+ priv->baud_base = 120000000 / 2;
+ } else if (version == 0x0700) {
+ priv->chip_type = FT2232H;
+ /* Hi-speed - baud clock runs at 120MHz */
+ priv->baud_base = 120000000 / 2;
+ } else
+ priv->chip_type = FT2232C;
+
/* Determine interface code. */
inter = serial->interface->altsetting->desc.bInterfaceNumber;
- if (inter == 0)
- priv->interface = PIT_SIOA;
- else
- priv->interface = PIT_SIOB;
+ if (inter == 0) {
+ priv->interface = INTERFACE_A;
+ } else if (inter == 1) {
+ priv->interface = INTERFACE_B;
+ } else if (inter == 2) {
+ priv->interface = INTERFACE_C;
+ } else if (inter == 3) {
+ priv->interface = INTERFACE_D;
+ }
/* BM-type devices have a bug where bcdDevice gets set
* to 0x200 when iSerialNumber is 0. */
if (version < 0x500) {
@@ -1315,7 +1379,9 @@ static int create_sysfs_attrs(struct usb_serial_port *port)
if ((!retval) &&
(priv->chip_type == FT232BM ||
priv->chip_type == FT2232C ||
- priv->chip_type == FT232RL)) {
+ priv->chip_type == FT232RL ||
+ priv->chip_type == FT2232H ||
+ priv->chip_type == FT4232H)) {
retval = device_create_file(&port->dev,
&dev_attr_latency_timer);
}
@@ -1334,7 +1400,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
device_remove_file(&port->dev, &dev_attr_event_char);
if (priv->chip_type == FT232BM ||
priv->chip_type == FT2232C ||
- priv->chip_type == FT232RL) {
+ priv->chip_type == FT232RL ||
+ priv->chip_type == FT2232H ||
+ priv->chip_type == FT4232H) {
device_remove_file(&port->dev, &dev_attr_latency_timer);
}
}
@@ -2333,6 +2401,8 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
case FT232BM:
case FT2232C:
case FT232RL:
+ case FT2232H:
+ case FT4232H:
/* the 8U232AM returns a two byte value (the sio is a 1 byte
value) - in the same format as the data returned from the in
point */