diff options
Diffstat (limited to 'drivers/usb/serial/cp210x.c')
-rw-r--r-- | drivers/usb/serial/cp210x.c | 107 |
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); |
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 *); |
@@ -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 | */ |
362 | static unsigned int cp210x_quantise_baudrate(unsigned int baud) { | 369 | static 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 | ||
421 | static void cp210x_close(struct usb_serial_port *port) | 429 | static 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 | */ | ||
613 | static 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 | |||
582 | static void cp210x_set_termios(struct tty_struct *tty, | 640 | static 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)) { |