|
@@ -355,6 +355,9 @@ static struct usb_serial_driver * const serial_drivers[] = {
|
|
|
#define CP210X_PARTNUM_CP2104 0x04
|
|
|
#define CP210X_PARTNUM_CP2105 0x05
|
|
|
#define CP210X_PARTNUM_CP2108 0x08
|
|
|
+#define CP210X_PARTNUM_CP2102N_QFN28 0x20
|
|
|
+#define CP210X_PARTNUM_CP2102N_QFN24 0x21
|
|
|
+#define CP210X_PARTNUM_CP2102N_QFN20 0x22
|
|
|
#define CP210X_PARTNUM_UNKNOWN 0xFF
|
|
|
|
|
|
/* CP210X_GET_COMM_STATUS returns these 0x13 bytes */
|
|
@@ -454,6 +457,15 @@ struct cp210x_gpio_write {
|
|
|
u8 state;
|
|
|
} __packed;
|
|
|
|
|
|
+static bool cp210x_is_cp2102n(struct usb_serial *serial)
|
|
|
+{
|
|
|
+ struct cp210x_serial_private *priv = usb_get_serial_data(serial);
|
|
|
+
|
|
|
+ return (priv->partnum == CP210X_PARTNUM_CP2102N_QFN28) ||
|
|
|
+ (priv->partnum == CP210X_PARTNUM_CP2102N_QFN24) ||
|
|
|
+ (priv->partnum == CP210X_PARTNUM_CP2102N_QFN20);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Helper to get interface number when we only have struct usb_serial.
|
|
|
*/
|
|
@@ -1053,20 +1065,32 @@ static speed_t cp210x_get_an205_rate(speed_t baud)
|
|
|
static void cp210x_change_speed(struct tty_struct *tty,
|
|
|
struct usb_serial_port *port, struct ktermios *old_termios)
|
|
|
{
|
|
|
- struct cp210x_serial_private *priv = usb_get_serial_data(port->serial);
|
|
|
+ struct usb_serial *serial = port->serial;
|
|
|
+ struct cp210x_serial_private *priv = usb_get_serial_data(serial);
|
|
|
u32 baud;
|
|
|
|
|
|
baud = tty->termios.c_ospeed;
|
|
|
|
|
|
- /* This maps the requested rate to a rate valid on cp2102 or cp2103,
|
|
|
- * or to an arbitrary rate in [1M, max_speed]
|
|
|
+ /*
|
|
|
+ * This maps the requested rate to the actual rate on cp2102n, a valid
|
|
|
+ * rate on cp2102 or cp2103, or to an arbitrary rate in
|
|
|
+ * [1M, max_speed].
|
|
|
*
|
|
|
* NOTE: B0 is not implemented.
|
|
|
*/
|
|
|
- if (baud < 1000000)
|
|
|
+ if (cp210x_is_cp2102n(serial)) {
|
|
|
+ int clk_div;
|
|
|
+ int prescaler;
|
|
|
+
|
|
|
+ baud = clamp(baud, 300u, priv->max_speed);
|
|
|
+ prescaler = (baud <= 365) ? 4 : 1;
|
|
|
+ clk_div = DIV_ROUND_CLOSEST(48000000, 2 * prescaler * baud);
|
|
|
+ baud = 48000000 / (2 * prescaler * clk_div);
|
|
|
+ } else if (baud < 1000000) {
|
|
|
baud = cp210x_get_an205_rate(baud);
|
|
|
- else if (baud > priv->max_speed)
|
|
|
+ } 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)) {
|
|
@@ -1520,6 +1544,11 @@ static void cp210x_init_max_speed(struct usb_serial *serial)
|
|
|
else
|
|
|
max = 921600; /* SCI */
|
|
|
break;
|
|
|
+ case CP210X_PARTNUM_CP2102N_QFN28:
|
|
|
+ case CP210X_PARTNUM_CP2102N_QFN24:
|
|
|
+ case CP210X_PARTNUM_CP2102N_QFN20:
|
|
|
+ max = 3000000;
|
|
|
+ break;
|
|
|
default:
|
|
|
max = 2000000;
|
|
|
break;
|