diff options
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/serial/cp210x.c | 130 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 17 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio_ids.h | 6 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan_usa26msg.h | 1 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan_usa28msg.h | 1 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan_usa49msg.h | 1 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan_usa67msg.h | 1 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan_usa90msg.h | 1 | ||||
-rw-r--r-- | drivers/usb/serial/option.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/pl2303.c | 1 | ||||
-rw-r--r-- | drivers/usb/serial/pl2303.h | 2 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial-simple.c | 3 |
13 files changed, 146 insertions, 21 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 533f127c30ad..7d031911d04e 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Serial device configuration # diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index c0777a374a88..fffe23ab0189 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -61,6 +61,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */ + { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */ { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ @@ -245,6 +246,7 @@ struct cp210x_serial_private { u8 gpio_input; #endif u8 partnum; + speed_t min_speed; speed_t max_speed; bool use_actual_rate; }; @@ -443,10 +445,10 @@ struct cp210x_pin_mode { #define CP210X_PIN_MODE_GPIO BIT(0) /* - * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes. - * Structure needs padding due to unused/unspecified bytes. + * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes + * on a CP2105 chip. Structure needs padding due to unused/unspecified bytes. */ -struct cp210x_config { +struct cp210x_dual_port_config { __le16 gpio_mode; u8 __pad0[2]; __le16 reset_state; @@ -457,6 +459,19 @@ struct cp210x_config { u8 device_cfg; } __packed; +/* + * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xd bytes + * on a CP2104 chip. Structure needs padding due to unused/unspecified bytes. + */ +struct cp210x_single_port_config { + __le16 gpio_mode; + u8 __pad0[2]; + __le16 reset_state; + u8 __pad1[4]; + __le16 suspend_state; + u8 device_cfg; +} __packed; + /* GPIO modes */ #define CP210X_SCI_GPIO_MODE_OFFSET 9 #define CP210X_SCI_GPIO_MODE_MASK GENMASK(11, 9) @@ -464,11 +479,19 @@ struct cp210x_config { #define CP210X_ECI_GPIO_MODE_OFFSET 2 #define CP210X_ECI_GPIO_MODE_MASK GENMASK(3, 2) +#define CP210X_GPIO_MODE_OFFSET 8 +#define CP210X_GPIO_MODE_MASK GENMASK(11, 8) + /* CP2105 port configuration values */ #define CP2105_GPIO0_TXLED_MODE BIT(0) #define CP2105_GPIO1_RXLED_MODE BIT(1) #define CP2105_GPIO1_RS485_MODE BIT(2) +/* CP2104 port configuration values */ +#define CP2104_GPIO0_TXLED_MODE BIT(0) +#define CP2104_GPIO1_RXLED_MODE BIT(1) +#define CP2104_GPIO2_RS485_MODE BIT(2) + /* CP2102N configuration array indices */ #define CP210X_2NCONFIG_CONFIG_VERSION_IDX 2 #define CP210X_2NCONFIG_GPIO_MODE_IDX 581 @@ -1051,14 +1074,11 @@ static speed_t cp210x_get_an205_rate(speed_t baud) return cp210x_an205_table1[i].rate; } -static speed_t cp210x_get_actual_rate(struct usb_serial *serial, speed_t baud) +static speed_t cp210x_get_actual_rate(speed_t baud) { - struct cp210x_serial_private *priv = usb_get_serial_data(serial); unsigned int prescale = 1; unsigned int div; - baud = clamp(baud, 300u, priv->max_speed); - if (baud <= 365) prescale = 4; @@ -1101,20 +1121,18 @@ static void cp210x_change_speed(struct tty_struct *tty, struct cp210x_serial_private *priv = usb_get_serial_data(serial); u32 baud; - baud = tty->termios.c_ospeed; - /* * This maps the requested rate to the actual rate, a valid rate on * cp2102 or cp2103, or to an arbitrary rate in [1M, max_speed]. * * NOTE: B0 is not implemented. */ + baud = clamp(tty->termios.c_ospeed, priv->min_speed, priv->max_speed); + if (priv->use_actual_rate) - baud = cp210x_get_actual_rate(serial, baud); + baud = cp210x_get_actual_rate(baud); else if (baud < 1000000) baud = cp210x_get_an205_rate(baud); - else if (baud > priv->max_speed) - baud = priv->max_speed; dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud); if (cp210x_write_u32_reg(port, CP210X_SET_BAUDRATE, baud)) { @@ -1353,8 +1371,13 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio) if (priv->partnum == CP210X_PARTNUM_CP2105) req_type = REQTYPE_INTERFACE_TO_HOST; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + result = cp210x_read_vendor_block(serial, req_type, CP210X_READ_LATCH, &buf, sizeof(buf)); + usb_autopm_put_interface(serial->interface); if (result < 0) return result; @@ -1375,6 +1398,10 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) buf.mask = BIT(gpio); + result = usb_autopm_get_interface(serial->interface); + if (result) + goto out; + if (priv->partnum == CP210X_PARTNUM_CP2105) { result = cp210x_write_vendor_block(serial, REQTYPE_HOST_TO_INTERFACE, @@ -1392,6 +1419,8 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) NULL, 0, USB_CTRL_SET_TIMEOUT); } + usb_autopm_put_interface(serial->interface); +out: if (result < 0) { dev_err(&serial->interface->dev, "failed to set GPIO value: %d\n", result); @@ -1470,7 +1499,7 @@ static int cp2105_gpioconf_init(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); struct cp210x_pin_mode mode; - struct cp210x_config config; + struct cp210x_dual_port_config config; u8 intf_num = cp210x_interface_num(serial); u8 iface_config; int result; @@ -1529,6 +1558,56 @@ static int cp2105_gpioconf_init(struct usb_serial *serial) return 0; } +static int cp2104_gpioconf_init(struct usb_serial *serial) +{ + struct cp210x_serial_private *priv = usb_get_serial_data(serial); + struct cp210x_single_port_config config; + u8 iface_config; + u8 gpio_latch; + int result; + u8 i; + + result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST, + CP210X_GET_PORTCONFIG, &config, + sizeof(config)); + if (result < 0) + return result; + + priv->gc.ngpio = 4; + + iface_config = config.device_cfg; + priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) & + CP210X_GPIO_MODE_MASK) >> + CP210X_GPIO_MODE_OFFSET); + gpio_latch = (u8)((le16_to_cpu(config.reset_state) & + CP210X_GPIO_MODE_MASK) >> + CP210X_GPIO_MODE_OFFSET); + + /* mark all pins which are not in GPIO mode */ + if (iface_config & CP2104_GPIO0_TXLED_MODE) /* GPIO 0 */ + priv->gpio_altfunc |= BIT(0); + if (iface_config & CP2104_GPIO1_RXLED_MODE) /* GPIO 1 */ + priv->gpio_altfunc |= BIT(1); + if (iface_config & CP2104_GPIO2_RS485_MODE) /* GPIO 2 */ + priv->gpio_altfunc |= BIT(2); + + /* + * Like CP2102N, CP2104 has also no strict input and output pin + * modes. + * Do the same input mode emulation as CP2102N. + */ + for (i = 0; i < priv->gc.ngpio; ++i) { + /* + * Set direction to "input" iff pin is open-drain and reset + * value is 1. + */ + if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i))) + priv->gpio_input |= BIT(i); + } + + return 0; +} + static int cp2102n_gpioconf_init(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); @@ -1574,12 +1653,6 @@ static int cp2102n_gpioconf_init(struct usb_serial *serial) if (config_version != 0x01) return -ENOTSUPP; - /* - * We only support 4 GPIOs even on the QFN28 package, because - * config locations of GPIOs 4-6 determined using reverse - * engineering revealed conflicting offsets with other - * documented functions. So we'll just play it safe for now. - */ priv->gc.ngpio = 4; /* @@ -1594,6 +1667,19 @@ static int cp2102n_gpioconf_init(struct usb_serial *serial) /* 0 indicates GPIO mode, 1 is alternate function */ priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f; + if (priv->partnum == CP210X_PARTNUM_CP2102N_QFN28) { + /* + * For the QFN28 package, GPIO4-6 are controlled by + * the low three bits of the mode/latch fields. + * Contrary to the document linked above, the bits for + * the SUSPEND pins are elsewhere. No alternate + * function is available for these pins. + */ + priv->gc.ngpio = 7; + gpio_latch |= (gpio_rst_latch & 7) << 4; + priv->gpio_pushpull |= (gpio_pushpull & 7) << 4; + } + /* * The CP2102N does not strictly has input and output pin modes, * it only knows open-drain and push-pull modes which is set at @@ -1620,6 +1706,9 @@ static int cp210x_gpio_init(struct usb_serial *serial) int result; switch (priv->partnum) { + case CP210X_PARTNUM_CP2104: + result = cp2104_gpioconf_init(serial); + break; case CP210X_PARTNUM_CP2105: result = cp2105_gpioconf_init(serial); break; @@ -1716,6 +1805,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); bool use_actual_rate = false; + speed_t min = 300; speed_t max; switch (priv->partnum) { @@ -1738,6 +1828,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) use_actual_rate = true; max = 2000000; /* ECI */ } else { + min = 2400; max = 921600; /* SCI */ } break; @@ -1752,6 +1843,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) break; } + priv->min_speed = min; priv->max_speed = max; priv->use_actual_rate = use_actual_rate; } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1ab2a6191013..8f5b17471759 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1025,6 +1025,8 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) }, { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) }, { USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) }, + /* EZPrototypes devices */ + { USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) }, { } /* Terminating entry */ }; @@ -1783,6 +1785,10 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) int result; u16 val; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value; result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -1795,6 +1801,8 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) val, result); } + usb_autopm_put_interface(serial->interface); + return result; } @@ -1846,9 +1854,15 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) unsigned char *buf; int result; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + buf = kmalloc(1, GFP_KERNEL); - if (!buf) + if (!buf) { + usb_autopm_put_interface(serial->interface); return -ENOMEM; + } result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -1863,6 +1877,7 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) } kfree(buf); + usb_autopm_put_interface(serial->interface); return result; } diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 975d02666c5a..b863bedb55a1 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1309,6 +1309,12 @@ #define IONICS_PLUGCOMPUTER_PID 0x0102 /* + * EZPrototypes (PID reseller) + */ +#define EZPROTOTYPES_VID 0x1c40 +#define HJELMSLUND_USB485_ISO_PID 0x0477 + +/* * Dresden Elektronik Sensor Terminal Board */ #define DE_VID 0x1cf1 /* Vendor ID */ diff --git a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h index 09e21e84fc4e..a68f1fb25b8a 100644 --- a/drivers/usb/serial/keyspan_usa26msg.h +++ b/drivers/usb/serial/keyspan_usa26msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa26msg.h diff --git a/drivers/usb/serial/keyspan_usa28msg.h b/drivers/usb/serial/keyspan_usa28msg.h index dee454c4609a..a19f3fe5d98d 100644 --- a/drivers/usb/serial/keyspan_usa28msg.h +++ b/drivers/usb/serial/keyspan_usa28msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa28msg.h diff --git a/drivers/usb/serial/keyspan_usa49msg.h b/drivers/usb/serial/keyspan_usa49msg.h index 163b2dea2ec5..8c3970fdd868 100644 --- a/drivers/usb/serial/keyspan_usa49msg.h +++ b/drivers/usb/serial/keyspan_usa49msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa49msg.h diff --git a/drivers/usb/serial/keyspan_usa67msg.h b/drivers/usb/serial/keyspan_usa67msg.h index 20fa3e2f7187..dcf502fdbb44 100644 --- a/drivers/usb/serial/keyspan_usa67msg.h +++ b/drivers/usb/serial/keyspan_usa67msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa67msg.h diff --git a/drivers/usb/serial/keyspan_usa90msg.h b/drivers/usb/serial/keyspan_usa90msg.h index 86708ecd8735..c4ca0f631d20 100644 --- a/drivers/usb/serial/keyspan_usa90msg.h +++ b/drivers/usb/serial/keyspan_usa90msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa90msg.h diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index aef15497ff31..11b21d9410f3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1148,6 +1148,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), .driver_info = NCTRL(0) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */ + .driver_info = NCTRL(0) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 98e7a5df0f6d..bb3f9aa4a909 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -46,6 +46,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID), diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 4e2554d55362..559941ca884d 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -8,6 +8,7 @@ #define PL2303_VENDOR_ID 0x067b #define PL2303_PRODUCT_ID 0x2303 +#define PL2303_PRODUCT_ID_TB 0x2304 #define PL2303_PRODUCT_ID_RSAQ2 0x04bb #define PL2303_PRODUCT_ID_DCU11 0x1234 #define PL2303_PRODUCT_ID_PHAROS 0xaaa0 @@ -20,6 +21,7 @@ #define PL2303_PRODUCT_ID_MOTOROLA 0x0307 #define PL2303_PRODUCT_ID_ZTEK 0xe1f1 + #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 #define ATEN_PRODUCT_ID 0x2008 diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 4d0273508043..edbbb13d6de6 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -85,7 +85,8 @@ DEVICE(moto_modem, MOTO_IDS); /* Motorola Tetra driver */ #define MOTOROLA_TETRA_IDS() \ { USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \ - { USB_DEVICE(0x0cad, 0x9012) } /* MTP6550 */ + { USB_DEVICE(0x0cad, 0x9012) }, /* MTP6550 */ \ + { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); /* Novatel Wireless GPS driver */ |