aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/cp210x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/cp210x.c')
-rw-r--r--drivers/usb/serial/cp210x.c108
1 files changed, 76 insertions, 32 deletions
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index fd67cc53545..a5152379cb4 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -39,6 +39,8 @@ static void cp210x_get_termios(struct tty_struct *,
39 struct usb_serial_port *port); 39 struct usb_serial_port *port);
40static void cp210x_get_termios_port(struct usb_serial_port *port, 40static void cp210x_get_termios_port(struct usb_serial_port *port,
41 unsigned int *cflagp, unsigned int *baudp); 41 unsigned int *cflagp, unsigned int *baudp);
42static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
43 struct ktermios *);
42static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, 44static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
43 struct ktermios*); 45 struct ktermios*);
44static int cp210x_tiocmget(struct tty_struct *); 46static int cp210x_tiocmget(struct tty_struct *);
@@ -92,6 +94,7 @@ static const struct usb_device_id id_table[] = {
92 { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ 94 { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
93 { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ 95 { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
94 { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ 96 { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
97 { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */
95 { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ 98 { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
96 { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ 99 { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
97 { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ 100 { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
@@ -137,6 +140,7 @@ static const struct usb_device_id id_table[] = {
137 { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ 140 { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
138 { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ 141 { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
139 { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ 142 { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
143 { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
140 { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ 144 { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
141 { } /* Terminating Entry */ 145 { } /* Terminating Entry */
142}; 146};
@@ -200,6 +204,8 @@ static struct usb_serial_driver cp210x_device = {
200#define CP210X_EMBED_EVENTS 0x15 204#define CP210X_EMBED_EVENTS 0x15
201#define CP210X_GET_EVENTSTATE 0x16 205#define CP210X_GET_EVENTSTATE 0x16
202#define CP210X_SET_CHARS 0x19 206#define CP210X_SET_CHARS 0x19
207#define CP210X_GET_BAUDRATE 0x1D
208#define CP210X_SET_BAUDRATE 0x1E
203 209
204/* CP210X_IFC_ENABLE */ 210/* CP210X_IFC_ENABLE */
205#define UART_ENABLE 0x0001 211#define UART_ENABLE 0x0001
@@ -353,8 +359,8 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port,
353 * Quantises the baud rate as per AN205 Table 1 359 * Quantises the baud rate as per AN205 Table 1
354 */ 360 */
355static unsigned int cp210x_quantise_baudrate(unsigned int baud) { 361static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
356 if (baud <= 56) baud = 0; 362 if (baud <= 300)
357 else if (baud <= 300) baud = 300; 363 baud = 300;
358 else if (baud <= 600) baud = 600; 364 else if (baud <= 600) baud = 600;
359 else if (baud <= 1200) baud = 1200; 365 else if (baud <= 1200) baud = 1200;
360 else if (baud <= 1800) baud = 1800; 366 else if (baud <= 1800) baud = 1800;
@@ -382,17 +388,15 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
382 else if (baud <= 491520) baud = 460800; 388 else if (baud <= 491520) baud = 460800;
383 else if (baud <= 567138) baud = 500000; 389 else if (baud <= 567138) baud = 500000;
384 else if (baud <= 670254) baud = 576000; 390 else if (baud <= 670254) baud = 576000;
385 else if (baud <= 1053257) baud = 921600; 391 else if (baud < 1000000)
386 else if (baud <= 1474560) baud = 1228800; 392 baud = 921600;
387 else if (baud <= 2457600) baud = 1843200; 393 else if (baud > 2000000)
388 else baud = 3686400; 394 baud = 2000000;
389 return baud; 395 return baud;
390} 396}
391 397
392static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) 398static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
393{ 399{
394 int result;
395
396 dbg("%s - port %d", __func__, port->number); 400 dbg("%s - port %d", __func__, port->number);
397 401
398 if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) { 402 if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) {
@@ -401,13 +405,14 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
401 return -EPROTO; 405 return -EPROTO;
402 } 406 }
403 407
404 result = usb_serial_generic_open(tty, port);
405 if (result)
406 return result;
407
408 /* Configure the termios structure */ 408 /* Configure the termios structure */
409 cp210x_get_termios(tty, port); 409 cp210x_get_termios(tty, port);
410 return 0; 410
411 /* The baud rate must be initialised on cp2104 */
412 if (tty)
413 cp210x_change_speed(tty, port, NULL);
414
415 return usb_serial_generic_open(tty, port);
411} 416}
412 417
413static void cp210x_close(struct usb_serial_port *port) 418static void cp210x_close(struct usb_serial_port *port)
@@ -459,10 +464,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
459 464
460 dbg("%s - port %d", __func__, port->number); 465 dbg("%s - port %d", __func__, port->number);
461 466
462 cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2); 467 cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
463 /* Convert to baudrate */
464 if (baud)
465 baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
466 468
467 dbg("%s - baud rate = %d", __func__, baud); 469 dbg("%s - baud rate = %d", __func__, baud);
468 *baudp = baud; 470 *baudp = baud;
@@ -576,11 +578,64 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
576 *cflagp = cflag; 578 *cflagp = cflag;
577} 579}
578 580
581/*
582 * CP2101 supports the following baud rates:
583 *
584 * 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800,
585 * 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600
586 *
587 * CP2102 and CP2103 support the following additional rates:
588 *
589 * 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000,
590 * 576000
591 *
592 * The device will map a requested rate to a supported one, but the result
593 * of requests for rates greater than 1053257 is undefined (see AN205).
594 *
595 * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud,
596 * respectively, with an error less than 1%. The actual rates are determined
597 * by
598 *
599 * div = round(freq / (2 x prescale x request))
600 * actual = freq / (2 x prescale x div)
601 *
602 * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps
603 * or 1 otherwise.
604 * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1
605 * otherwise.
606 */
607static void cp210x_change_speed(struct tty_struct *tty,
608 struct usb_serial_port *port, struct ktermios *old_termios)
609{
610 u32 baud;
611
612 baud = tty->termios->c_ospeed;
613
614 /* This maps the requested rate to a rate valid on cp2102 or cp2103,
615 * or to an arbitrary rate in [1M,2M].
616 *
617 * NOTE: B0 is not implemented.
618 */
619 baud = cp210x_quantise_baudrate(baud);
620
621 dbg("%s - setting baud rate to %u", __func__, baud);
622 if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud,
623 sizeof(baud))) {
624 dev_warn(&port->dev, "failed to set baud rate to %u\n", baud);
625 if (old_termios)
626 baud = old_termios->c_ospeed;
627 else
628 baud = 9600;
629 }
630
631 tty_encode_baud_rate(tty, baud, baud);
632}
633
579static void cp210x_set_termios(struct tty_struct *tty, 634static void cp210x_set_termios(struct tty_struct *tty,
580 struct usb_serial_port *port, struct ktermios *old_termios) 635 struct usb_serial_port *port, struct ktermios *old_termios)
581{ 636{
582 unsigned int cflag, old_cflag; 637 unsigned int cflag, old_cflag;
583 unsigned int baud = 0, bits; 638 unsigned int bits;
584 unsigned int modem_ctl[4]; 639 unsigned int modem_ctl[4];
585 640
586 dbg("%s - port %d", __func__, port->number); 641 dbg("%s - port %d", __func__, port->number);
@@ -591,20 +646,9 @@ static void cp210x_set_termios(struct tty_struct *tty,
591 tty->termios->c_cflag &= ~CMSPAR; 646 tty->termios->c_cflag &= ~CMSPAR;
592 cflag = tty->termios->c_cflag; 647 cflag = tty->termios->c_cflag;
593 old_cflag = old_termios->c_cflag; 648 old_cflag = old_termios->c_cflag;
594 baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty)); 649
595 650 if (tty->termios->c_ospeed != old_termios->c_ospeed)
596 /* If the baud rate is to be updated*/ 651 cp210x_change_speed(tty, port, old_termios);
597 if (baud != tty_termios_baud_rate(old_termios) && baud != 0) {
598 dbg("%s - Setting baud rate to %d baud", __func__,
599 baud);
600 if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV,
601 ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
602 dbg("Baud rate requested not supported by device");
603 baud = tty_termios_baud_rate(old_termios);
604 }
605 }
606 /* Report back the resulting baud rate */
607 tty_encode_baud_rate(tty, baud, baud);
608 652
609 /* If the number of data bits is to be updated */ 653 /* If the number of data bits is to be updated */
610 if ((cflag & CSIZE) != (old_cflag & CSIZE)) { 654 if ((cflag & CSIZE) != (old_cflag & CSIZE)) {