aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolaj Fogh <nikolajfogh@gmail.com>2018-11-22 15:27:46 -0500
committerJohan Hovold <johan@kernel.org>2018-11-23 03:49:37 -0500
commit6abd837104a3a8e1cda64fc4d7675f6c3ece9d8b (patch)
treeafe20ef75ef356768f87ff6c4e4dc84dd1351932
parentab60075f2a4eebca1abb04f712569963fb4d9d6c (diff)
USB: serial: ftdi_sio: use rounding when calculating baud rate divisors
Improve baud-rate generation by using rounding-to-closest instead of truncation in divisor calculation. Results have been verified by logic analyzer on an FT232RT (232BM) chip. The following table shows the wanted baud rate, the baud rate obtained with the old method (truncation), with the new method (rounding) and the baud rate generated by the windows 10 driver. The numbers in parentheses is the error. +- Wanted --+------ Old -------+------ New -------+------ Win -------+ |   9600  |   9600 (0.00%)  |   9604 (0.05%)  |   9605 (0.05%)  | |   19200   |   19200 (0.00%)  |   19199 (0.01%)  |   19198 (0.01%)  | |   38400   |   38395 (0.01%)  |   38431 (0.08%)  |   38394 (0.02%)  | |   57600   |   57725 (0.22%)  |   57540 (0.10%)  |   57673 (0.13%)  | |  115200   |  115307 (0.09%)  |  115330 (0.11%)  |  115320 (0.10%)  | |  921600   |  919963 (0.18%)  |  920386 (0.13%)  |  920810 (0.09%)  | |  961200   |  996512 (3.67%)  |  956480 (0.49%)  |  956937 (0.44%)  | +-----------+------------------+------------------+------------------+ The error due to noise in the measurements is in the order of a few tenths of a %. As can be seen, the baud rate is significantly improved for some rates (e.g. 961200), and corresponds to the output given by the windows driver. The theoretical baud rate has been calculated for all baud rates from 1 to 3M, and as expected, the error is centered around 0, with a triangle shape instead of a sawtooth, so the maximum error is decreased to half. Signed-off-by: Nikolaj Fogh <nikolajfogh@gmail.com> [ johan: edit commit message slightly ] Signed-off-by: Johan Hovold <johan@kernel.org>
-rw-r--r--drivers/usb/serial/ftdi_sio.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 609198d9594c..1ab2a6191013 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1130,7 +1130,7 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
1130{ 1130{
1131 unsigned short int divisor; 1131 unsigned short int divisor;
1132 /* divisor shifted 3 bits to the left */ 1132 /* divisor shifted 3 bits to the left */
1133 int divisor3 = base / 2 / baud; 1133 int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
1134 if ((divisor3 & 0x7) == 7) 1134 if ((divisor3 & 0x7) == 7)
1135 divisor3++; /* round x.7/8 up to x+1 */ 1135 divisor3++; /* round x.7/8 up to x+1 */
1136 divisor = divisor3 >> 3; 1136 divisor = divisor3 >> 3;
@@ -1156,7 +1156,7 @@ static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
1156 static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; 1156 static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
1157 u32 divisor; 1157 u32 divisor;
1158 /* divisor shifted 3 bits to the left */ 1158 /* divisor shifted 3 bits to the left */
1159 int divisor3 = base / 2 / baud; 1159 int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
1160 divisor = divisor3 >> 3; 1160 divisor = divisor3 >> 3;
1161 divisor |= (u32)divfrac[divisor3 & 0x7] << 14; 1161 divisor |= (u32)divfrac[divisor3 & 0x7] << 14;
1162 /* Deal with special cases for highest baud rates. */ 1162 /* Deal with special cases for highest baud rates. */
@@ -1179,7 +1179,7 @@ static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
1179 int divisor3; 1179 int divisor3;
1180 1180
1181 /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ 1181 /* hi-speed baud rate is 10-bit sampling instead of 16-bit */
1182 divisor3 = base * 8 / (baud * 10); 1182 divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud);
1183 1183
1184 divisor = divisor3 >> 3; 1184 divisor = divisor3 >> 3;
1185 divisor |= (u32)divfrac[divisor3 & 0x7] << 14; 1185 divisor |= (u32)divfrac[divisor3 & 0x7] << 14;