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.c107
1 files changed, 77 insertions, 30 deletions
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index fba1147ed916..08a5575724cd 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 *);
@@ -134,10 +136,13 @@ static const struct usb_device_id id_table[] = {
134 { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ 136 { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
135 { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ 137 { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */
136 { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ 138 { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */
139 { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */
140 { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */
137 { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ 141 { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
138 { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ 142 { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
139 { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ 143 { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
140 { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ 144 { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
145 { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
141 { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ 146 { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
142 { } /* Terminating Entry */ 147 { } /* Terminating Entry */
143}; 148};
@@ -201,6 +206,8 @@ static struct usb_serial_driver cp210x_device = {
201#define CP210X_EMBED_EVENTS 0x15 206#define CP210X_EMBED_EVENTS 0x15
202#define CP210X_GET_EVENTSTATE 0x16 207#define CP210X_GET_EVENTSTATE 0x16
203#define CP210X_SET_CHARS 0x19 208#define CP210X_SET_CHARS 0x19
209#define CP210X_GET_BAUDRATE 0x1D
210#define CP210X_SET_BAUDRATE 0x1E
204 211
205/* CP210X_IFC_ENABLE */ 212/* CP210X_IFC_ENABLE */
206#define UART_ENABLE 0x0001 213#define UART_ENABLE 0x0001
@@ -360,8 +367,8 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port,
360 * Quantises the baud rate as per AN205 Table 1 367 * Quantises the baud rate as per AN205 Table 1
361 */ 368 */
362static unsigned int cp210x_quantise_baudrate(unsigned int baud) { 369static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
363 if (baud <= 56) baud = 0; 370 if (baud <= 300)
364 else if (baud <= 300) baud = 300; 371 baud = 300;
365 else if (baud <= 600) baud = 600; 372 else if (baud <= 600) baud = 600;
366 else if (baud <= 1200) baud = 1200; 373 else if (baud <= 1200) baud = 1200;
367 else if (baud <= 1800) baud = 1800; 374 else if (baud <= 1800) baud = 1800;
@@ -389,10 +396,10 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
389 else if (baud <= 491520) baud = 460800; 396 else if (baud <= 491520) baud = 460800;
390 else if (baud <= 567138) baud = 500000; 397 else if (baud <= 567138) baud = 500000;
391 else if (baud <= 670254) baud = 576000; 398 else if (baud <= 670254) baud = 576000;
392 else if (baud <= 1053257) baud = 921600; 399 else if (baud < 1000000)
393 else if (baud <= 1474560) baud = 1228800; 400 baud = 921600;
394 else if (baud <= 2457600) baud = 1843200; 401 else if (baud > 2000000)
395 else baud = 3686400; 402 baud = 2000000;
396 return baud; 403 return baud;
397} 404}
398 405
@@ -409,13 +416,14 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
409 return result; 416 return result;
410 } 417 }
411 418
412 result = usb_serial_generic_open(tty, port);
413 if (result)
414 return result;
415
416 /* Configure the termios structure */ 419 /* Configure the termios structure */
417 cp210x_get_termios(tty, port); 420 cp210x_get_termios(tty, port);
418 return 0; 421
422 /* The baud rate must be initialised on cp2104 */
423 if (tty)
424 cp210x_change_speed(tty, port, NULL);
425
426 return usb_serial_generic_open(tty, port);
419} 427}
420 428
421static void cp210x_close(struct usb_serial_port *port) 429static void cp210x_close(struct usb_serial_port *port)
@@ -467,10 +475,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
467 475
468 dbg("%s - port %d", __func__, port->number); 476 dbg("%s - port %d", __func__, port->number);
469 477
470 cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2); 478 cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
471 /* Convert to baudrate */
472 if (baud)
473 baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
474 479
475 dbg("%s - baud rate = %d", __func__, baud); 480 dbg("%s - baud rate = %d", __func__, baud);
476 *baudp = baud; 481 *baudp = baud;
@@ -579,11 +584,64 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
579 *cflagp = cflag; 584 *cflagp = cflag;
580} 585}
581 586
587/*
588 * CP2101 supports the following baud rates:
589 *
590 * 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800,
591 * 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600
592 *
593 * CP2102 and CP2103 support the following additional rates:
594 *
595 * 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000,
596 * 576000
597 *
598 * The device will map a requested rate to a supported one, but the result
599 * of requests for rates greater than 1053257 is undefined (see AN205).
600 *
601 * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud,
602 * respectively, with an error less than 1%. The actual rates are determined
603 * by
604 *
605 * div = round(freq / (2 x prescale x request))
606 * actual = freq / (2 x prescale x div)
607 *
608 * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps
609 * or 1 otherwise.
610 * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1
611 * otherwise.
612 */
613static void cp210x_change_speed(struct tty_struct *tty,
614 struct usb_serial_port *port, struct ktermios *old_termios)
615{
616 u32 baud;
617
618 baud = tty->termios->c_ospeed;
619
620 /* This maps the requested rate to a rate valid on cp2102 or cp2103,
621 * or to an arbitrary rate in [1M,2M].
622 *
623 * NOTE: B0 is not implemented.
624 */
625 baud = cp210x_quantise_baudrate(baud);
626
627 dbg("%s - setting baud rate to %u", __func__, baud);
628 if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud,
629 sizeof(baud))) {
630 dev_warn(&port->dev, "failed to set baud rate to %u\n", baud);
631 if (old_termios)
632 baud = old_termios->c_ospeed;
633 else
634 baud = 9600;
635 }
636
637 tty_encode_baud_rate(tty, baud, baud);
638}
639
582static void cp210x_set_termios(struct tty_struct *tty, 640static void cp210x_set_termios(struct tty_struct *tty,
583 struct usb_serial_port *port, struct ktermios *old_termios) 641 struct usb_serial_port *port, struct ktermios *old_termios)
584{ 642{
585 unsigned int cflag, old_cflag; 643 unsigned int cflag, old_cflag;
586 unsigned int baud = 0, bits; 644 unsigned int bits;
587 unsigned int modem_ctl[4]; 645 unsigned int modem_ctl[4];
588 646
589 dbg("%s - port %d", __func__, port->number); 647 dbg("%s - port %d", __func__, port->number);
@@ -593,20 +651,9 @@ static void cp210x_set_termios(struct tty_struct *tty,
593 651
594 cflag = tty->termios->c_cflag; 652 cflag = tty->termios->c_cflag;
595 old_cflag = old_termios->c_cflag; 653 old_cflag = old_termios->c_cflag;
596 baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty)); 654
597 655 if (tty->termios->c_ospeed != old_termios->c_ospeed)
598 /* If the baud rate is to be updated*/ 656 cp210x_change_speed(tty, port, old_termios);
599 if (baud != tty_termios_baud_rate(old_termios) && baud != 0) {
600 dbg("%s - Setting baud rate to %d baud", __func__,
601 baud);
602 if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV,
603 ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
604 dbg("Baud rate requested not supported by device");
605 baud = tty_termios_baud_rate(old_termios);
606 }
607 }
608 /* Report back the resulting baud rate */
609 tty_encode_baud_rate(tty, baud, baud);
610 657
611 /* If the number of data bits is to be updated */ 658 /* If the number of data bits is to be updated */
612 if ((cflag & CSIZE) != (old_cflag & CSIZE)) { 659 if ((cflag & CSIZE) != (old_cflag & CSIZE)) {