diff options
Diffstat (limited to 'drivers/usb/serial/cp210x.c')
-rw-r--r-- | drivers/usb/serial/cp210x.c | 108 |
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); |
40 | static void cp210x_get_termios_port(struct usb_serial_port *port, | 40 | static void cp210x_get_termios_port(struct usb_serial_port *port, |
41 | unsigned int *cflagp, unsigned int *baudp); | 41 | unsigned int *cflagp, unsigned int *baudp); |
42 | static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, | ||
43 | struct ktermios *); | ||
42 | static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, | 44 | static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, |
43 | struct ktermios*); | 45 | struct ktermios*); |
44 | static int cp210x_tiocmget(struct tty_struct *); | 46 | static 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 | */ |
355 | static unsigned int cp210x_quantise_baudrate(unsigned int baud) { | 361 | static 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 | ||
392 | static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) | 398 | static 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 | ||
413 | static void cp210x_close(struct usb_serial_port *port) | 418 | static 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 | */ | ||
607 | static 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 | |||
579 | static void cp210x_set_termios(struct tty_struct *tty, | 634 | static 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)) { |