From: "Pali Rohár" <pali@kernel.org>
To: "Johan Hovold" <johan@kernel.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Marek Behún" <kabel@kernel.org>
Cc: linux-usb@vger.kernel.org
Subject: [PATCH v3 7/7] USB: serial: ftdi_sio: Fill c_*speed fields with real baud rate
Date: Sat, 24 Sep 2022 12:27:18 +0200 [thread overview]
Message-ID: <20220924102718.2984-8-pali@kernel.org> (raw)
In-Reply-To: <20220924102718.2984-1-pali@kernel.org>
Calculate baud rate value in c_*speed fields to the real values which were
set on hardware. For this operation, add a new set of methods
*_divisor_to_baud() for each chip and use them for calculating the real
baud rate values.
Each *_divisor_to_baud() method is constructed as an inverse function of
its corresponding *_baud_to_divisor() method.
Signed-off-by: Pali Rohár <pali@kernel.org>
Tested-by: Marek Behún <kabel@kernel.org>
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/usb/serial/ftdi_sio.c | 93 +++++++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 79b00912c81c..350ed14b014c 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1183,6 +1183,34 @@ static u32 ftdi_sio_baud_to_divisor(int baud)
}
}
+static int ftdi_sdio_divisor_to_baud(u32 divisor)
+{
+ switch (divisor) {
+ case ftdi_sio_b300:
+ return 300;
+ case ftdi_sio_b600:
+ return 600;
+ case ftdi_sio_b1200:
+ return 1200;
+ case ftdi_sio_b2400:
+ return 2400;
+ case ftdi_sio_b4800:
+ return 4800;
+ case ftdi_sio_b9600:
+ return 9600;
+ case ftdi_sio_b19200:
+ return 19200;
+ case ftdi_sio_b38400:
+ return 38400;
+ case ftdi_sio_b57600:
+ return 57600;
+ case ftdi_sio_b115200:
+ return 115200;
+ default:
+ return 9600;
+ }
+}
+
static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
{
unsigned short int divisor;
@@ -1205,11 +1233,28 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
return divisor;
}
+static int ftdi_232am_divisor_base_to_baud(unsigned short int divisor, int base)
+{
+ static const unsigned char divfrac_inv[4] = { 0, 4, 2, 1 };
+ unsigned int divisor3;
+
+ if (divisor == 0)
+ divisor = 1;
+ divisor3 = (GENMASK(13, 0) & divisor) << 3;
+ divisor3 |= divfrac_inv[(divisor >> 14) & 0x3];
+ return DIV_ROUND_CLOSEST(base, 2 * divisor3);
+}
+
static unsigned short int ftdi_232am_baud_to_divisor(int baud)
{
return ftdi_232am_baud_base_to_divisor(baud, 48000000);
}
+static int ftdi_232am_divisor_to_baud(unsigned short int divisor)
+{
+ return ftdi_232am_divisor_base_to_baud(divisor, 48000000);
+}
+
static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
{
static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
@@ -1228,11 +1273,31 @@ static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
return divisor;
}
+static int ftdi_232bm_divisor_base_to_baud(u32 divisor, int base)
+{
+ static const unsigned char divfrac_inv[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
+ u32 divisor3;
+
+ /* Deal with special cases for highest baud rates. */
+ if (divisor == 0)
+ divisor = 1; /* 1.0 */
+ else if (divisor == 1)
+ divisor = 0x4001; /* 1.5 */
+ divisor3 = (GENMASK(13, 0) & divisor) << 3;
+ divisor3 |= divfrac_inv[(divisor >> 14) & 0x7];
+ return DIV_ROUND_CLOSEST(base, 2 * divisor3);
+}
+
static u32 ftdi_232bm_baud_to_divisor(int baud)
{
return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
}
+static int ftdi_232bm_divisor_to_baud(u32 divisor)
+{
+ return ftdi_232bm_divisor_base_to_baud(divisor, 48000000);
+}
+
static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
{
static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
@@ -1260,11 +1325,32 @@ static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
return divisor;
}
+static int ftdi_2232h_divisor_base_to_baud(u32 divisor, int base)
+{
+ static const unsigned char divfrac_inv[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
+ u32 divisor3;
+
+ divisor &= GENMASK(16, 0);
+ /* Deal with special cases for highest baud rates. */
+ if (divisor == 0)
+ divisor = 1; /* 1.0 */
+ else if (divisor == 1)
+ divisor = 0x4001; /* 1.5 */
+ divisor3 = (GENMASK(13, 0) & divisor) << 3;
+ divisor3 |= divfrac_inv[(divisor >> 14) & 0x7];
+ return DIV_ROUND_CLOSEST(8 * base, 10 * divisor3);
+}
+
static u32 ftdi_2232h_baud_to_divisor(int baud)
{
return ftdi_2232h_baud_base_to_divisor(baud, 120000000);
}
+static int ftdi_2232h_divisor_to_baud(u32 divisor)
+{
+ return ftdi_2232h_divisor_base_to_baud(divisor, 120000000);
+}
+
#define set_mctrl(port, set) update_mctrl((port), (set), 0)
#define clear_mctrl(port, clear) update_mctrl((port), 0, (clear))
@@ -1358,6 +1444,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
}
div_okay = 0;
}
+ baud = ftdi_sdio_divisor_to_baud(div_value);
break;
case FT8U232AM: /* 8U232AM chip */
if (baud >= 183 && baud <= 3000000) {
@@ -1371,6 +1458,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
div_value = ftdi_232am_baud_to_divisor(baud);
div_okay = 0;
}
+ baud = ftdi_232am_divisor_to_baud(div_value);
break;
case FT232BM: /* FT232BM chip */
case FT2232C: /* FT2232C chip */
@@ -1397,25 +1485,30 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
div_value = ftdi_232bm_baud_to_divisor(baud);
div_okay = 0;
}
+ baud = ftdi_232bm_divisor_to_baud(div_value);
break;
case FT2232H: /* FT2232H chip */
case FT4232H: /* FT4232H chip */
case FT232H: /* FT232H chip */
if ((baud <= 12000000) && (baud >= 1200)) {
div_value = ftdi_2232h_baud_to_divisor(baud);
+ baud = ftdi_2232h_divisor_to_baud(div_value);
} else if (baud >= 183 && baud < 1200) {
div_value = ftdi_232bm_baud_to_divisor(baud);
+ baud = ftdi_232bm_divisor_to_baud(div_value);
} else {
dev_dbg(dev, "%s - Baud rate too high!\n", __func__);
if (old_baud >= 183 && old_baud < 1200) {
baud = old_baud;
div_value = ftdi_232bm_baud_to_divisor(baud);
+ baud = ftdi_232bm_divisor_to_baud(div_value);
} else {
if (old_baud >= 1200 && old_baud <= 12000000)
baud = old_baud;
else
baud = 9600;
div_value = ftdi_2232h_baud_to_divisor(baud);
+ baud = ftdi_2232h_divisor_to_baud(div_value);
}
div_okay = 0;
}
--
2.20.1
next prev parent reply other threads:[~2022-09-24 10:29 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-24 10:27 [PATCH v3 0/7] ftdi_sio driver improvements Pali Rohár
2022-09-24 10:27 ` [PATCH v3 1/7] USB: serial: ftdi_sio: Fix divisor overflow Pali Rohár
2022-11-28 14:54 ` Johan Hovold
2022-09-24 10:27 ` [PATCH v3 2/7] USB: serial: ftdi_sio: Add missing baud rate validation Pali Rohár
2022-11-28 15:00 ` Johan Hovold
2022-09-24 10:27 ` [PATCH v3 3/7] USB: serial: ftdi_sio: Extract SIO divisor code to function Pali Rohár
2022-09-24 10:47 ` Greg Kroah-Hartman
2022-10-09 12:17 ` Pali Rohár
2022-11-01 22:50 ` Pali Rohár
2022-11-02 1:47 ` Greg Kroah-Hartman
2022-11-26 16:29 ` Pali Rohár
2022-11-02 7:34 ` Johan Hovold
2022-11-28 15:10 ` Johan Hovold
2022-09-24 10:27 ` [PATCH v3 4/7] USB: serial: ftdi_sio: Do not reset baud rate to 9600 Baud on error Pali Rohár
2022-11-28 16:37 ` Johan Hovold
2022-09-24 10:27 ` [PATCH v3 5/7] USB: serial: ftdi_sio: Fix baud rate rounding for ASYNC_SPD_CUST Pali Rohár
2022-11-28 16:57 ` Johan Hovold
2022-09-24 10:27 ` [PATCH v3 6/7] USB: serial: ftdi_sio: Fix custom_divisor for TIOCGSERIAL and c_*speed for TCGETS2 Pali Rohár
2022-11-28 17:05 ` Johan Hovold
2022-09-24 10:27 ` Pali Rohár [this message]
2022-11-28 17:16 ` [PATCH v3 7/7] USB: serial: ftdi_sio: Fill c_*speed fields with real baud rate Johan Hovold
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220924102718.2984-8-pali@kernel.org \
--to=pali@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=johan@kernel.org \
--cc=kabel@kernel.org \
--cc=linux-usb@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).