Message ID | 20210316120620.888110-1-michaelk@IEEE.org (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [1/1] USB: serial: pl2303: TA & TB alternate divider | expand |
On Tue, Mar 16, 2021 at 08:06:20AM -0400, michaelk@IEEE.org wrote: > From: Michael Katzmann <michaelk@IEEE.org> > > Use an alternate clock divider algorithm and bit ordering for the TA and > TB versions of the pl2303. It was discovered that these variants do not > produce the correct baud rates with the existing scheme. > > see https://lore.kernel.org/r/3aee5708-7961-f464-8c5f-6685d96920d6@IEEE.org > > Signed-off-by: Michael G. Katzmann <michaelk@IEEE.org> > --- > drivers/usb/serial/pl2303.c | 45 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 45 insertions(+) > +static speed_t pl2303_encode_baud_rate_divisor_alt(unsigned char buf[4], > + speed_t baud) > +{ > + unsigned int baseline, mantissa, exponent; > + > + /* > + * Apparently, for the TA version the formula is: > + * baudrate = 12M * 32 / (mantissa * 2^exponent) > + * where > + * mantissa = buf[10:0] > + * exponent = buf[15:13 16] > + */ > + baseline = 12000000 * 32; > + mantissa = baseline / baud; > + if (mantissa == 0) > + mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */ > + exponent = 0; > + while (mantissa >= 2048) { > + if (exponent < 15) { > + mantissa >>= 1; /* divide by 2 */ > + exponent++; > + } else { > + /* Exponent is maxed. Trim mantissa and leave. */ > + mantissa = 2047; > + break; > + } > + } > + > + buf[3] = 0x80; > + buf[2] = exponent & 0x01; > + buf[1] = (exponent & ~0x01) << 4 | mantissa >> 8; > + buf[0] = mantissa & 0xff; > + > + /* Calculate and return the exact baud rate. */ > + baud = (baseline / mantissa) >> exponent; > + > + return baud; > +} The code above is still indented using spaces rather than tabs. > + > + > static void pl2303_encode_baud_rate(struct tty_struct *tty, > struct usb_serial_port *port, > u8 buf[4]) > @@ -645,6 +688,8 @@ static void pl2303_encode_baud_rate(struct tty_struct *tty, > > if (baud == baud_sup) > baud = pl2303_encode_baud_rate_direct(buf, baud); > + else if (spriv->type->alt_divisors) > + baud = pl2303_encode_baud_rate_divisor_alt(buf, baud); Same here. > else > baud = pl2303_encode_baud_rate_divisor(buf, baud); Please include a revision in the subject prefix when resending (e.g. this would be "[PATCH v2]: USB: ...", generally there should be a matching short changelog below the '---' cut-off line as well). Johan
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 7208966891d0..bf5828579918 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -188,6 +188,7 @@ struct pl2303_type_data { unsigned long quirks; unsigned int no_autoxonxoff:1; unsigned int no_divisors:1; + unsigned int alt_divisors:1; }; struct pl2303_serial_private { @@ -217,10 +218,12 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { [TYPE_TA] = { .name = "TA", .max_baud_rate = 6000000, + .alt_divisors = true, }, [TYPE_TB] = { .name = "TB", .max_baud_rate = 12000000, + .alt_divisors = true, }, [TYPE_HXD] = { .name = "HXD", @@ -618,6 +621,46 @@ static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4], return baud; } +static speed_t pl2303_encode_baud_rate_divisor_alt(unsigned char buf[4], + speed_t baud) +{ + unsigned int baseline, mantissa, exponent; + + /* + * Apparently, for the TA version the formula is: + * baudrate = 12M * 32 / (mantissa * 2^exponent) + * where + * mantissa = buf[10:0] + * exponent = buf[15:13 16] + */ + baseline = 12000000 * 32; + mantissa = baseline / baud; + if (mantissa == 0) + mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */ + exponent = 0; + while (mantissa >= 2048) { + if (exponent < 15) { + mantissa >>= 1; /* divide by 2 */ + exponent++; + } else { + /* Exponent is maxed. Trim mantissa and leave. */ + mantissa = 2047; + break; + } + } + + buf[3] = 0x80; + buf[2] = exponent & 0x01; + buf[1] = (exponent & ~0x01) << 4 | mantissa >> 8; + buf[0] = mantissa & 0xff; + + /* Calculate and return the exact baud rate. */ + baud = (baseline / mantissa) >> exponent; + + return baud; +} + + static void pl2303_encode_baud_rate(struct tty_struct *tty, struct usb_serial_port *port, u8 buf[4]) @@ -645,6 +688,8 @@ static void pl2303_encode_baud_rate(struct tty_struct *tty, if (baud == baud_sup) baud = pl2303_encode_baud_rate_direct(buf, baud); + else if (spriv->type->alt_divisors) + baud = pl2303_encode_baud_rate_divisor_alt(buf, baud); else baud = pl2303_encode_baud_rate_divisor(buf, baud);