From: Michael Hanselmann <public@hansmi.ch>
To: linux-usb@vger.kernel.org, Johan Hovold <johan@kernel.org>
Cc: Michael Hanselmann <public@hansmi.ch>,
Michael Dreher <michael@5dot1.de>,
Jonathan Olds <jontio@i4free.co.nz>
Subject: [PATCH 3/4] ch341: Limit prescaler on HL340 variant
Date: Fri, 6 Mar 2020 19:00:44 +0000 [thread overview]
Message-ID: <d76985a6dcf1b4aeec783dd8c8b59f054b51e07d.1583520568.git.public@hansmi.ch> (raw)
In-Reply-To: <cover.1583520568.git.public@hansmi.ch>
HL340 devices, a subset of all CH340 devices, do not work correctly when
the highest prescaler bit (0b100) is set. Limit these to the lower
prescaler values at the cost of timing precision.
Signed-off-by: Michael Hanselmann <public@hansmi.ch>
---
drivers/usb/serial/ch341.c | 53 ++++++++++++++++++++++++++++----------
1 file changed, 40 insertions(+), 13 deletions(-)
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 0523f46f53c7..48a704174aec 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -24,6 +24,8 @@
#define DEFAULT_BAUD_RATE 9600
#define DEFAULT_TIMEOUT 1000
+#define CH341_QUIRK_LIMITED_PRESCALER 0x01
+
/* flags for IO-Bits */
#define CH341_BIT_RTS (1 << 6)
#define CH341_BIT_DTR (1 << 5)
@@ -143,13 +145,19 @@ static int ch341_control_in(struct usb_device *dev,
#define CH341_CLKRATE 48000000
#define CH341_CLK_DIV(ps, fact) (1 << (12 - 3 * (ps) - (fact)))
-#define CH341_MIN_RATE(ps) (CH341_CLKRATE / (CH341_CLK_DIV((ps), 1) * 512))
+#define CH341_MIN_RATE(ps, fact) \
+ (CH341_CLKRATE / (CH341_CLK_DIV((ps), (fact)) * 512))
static const speed_t ch341_min_rates[] = {
- CH341_MIN_RATE(0),
- CH341_MIN_RATE(1),
- CH341_MIN_RATE(2),
- CH341_MIN_RATE(3),
+ CH341_MIN_RATE(0, 0),
+ CH341_MIN_RATE(1, 0),
+ CH341_MIN_RATE(2, 0),
+ CH341_MIN_RATE(3, 0),
+
+ CH341_MIN_RATE(0, 1),
+ CH341_MIN_RATE(1, 1),
+ CH341_MIN_RATE(2, 1),
+ CH341_MIN_RATE(3, 1),
};
/*
@@ -162,24 +170,41 @@ static const speed_t ch341_min_rates[] = {
* 2 <= div <= 256 if fact = 0, or
* 9 <= div <= 256 if fact = 1
*/
-static int ch341_get_divisor(speed_t speed)
+static int ch341_get_divisor(struct ch341_private *priv)
{
+ const speed_t *min_rates;
+ speed_t speed;
unsigned int fact, div, clk_div;
int ps;
+ speed = priv->baud_rate;
+
/*
* Clamp to supported range, this makes the (ps < 0) and (div < 2)
* sanity checks below redundant.
*/
speed = clamp(speed, 46U, 3000000U);
- /*
- * Start with highest possible base clock (fact = 1) that will give a
- * divisor strictly less than 512.
- */
- fact = 1;
+ if (priv->flags & CH341_QUIRK_LIMITED_PRESCALER) {
+ /*
+ * Devices of the "HL340" variant don't work reliably when the
+ * third bit is set in the prescaler (0b100). Limit these to
+ * prescaler values in the range 0..3 (fact = 0) at the cost of
+ * precision.
+ */
+ min_rates = &ch341_min_rates[4];
+ fact = 0;
+ } else {
+ /*
+ * Start with highest possible base clock (fact = 1) that will
+ * give a divisor strictly less than 512.
+ */
+ min_rates = ch341_min_rates;
+ fact = 1;
+ }
+
for (ps = 3; ps >= 0; ps--) {
- if (speed > ch341_min_rates[ps])
+ if (speed > min_rates[ps])
break;
}
@@ -231,7 +256,7 @@ static int ch341_set_baudrate_lcr(struct usb_device *dev,
if (!priv->baud_rate)
return -EINVAL;
- val = ch341_get_divisor(priv->baud_rate);
+ val = ch341_get_divisor(priv);
if (val < 0)
return -EINVAL;
@@ -377,6 +402,8 @@ static int ch341_port_probe(struct usb_serial_port *port)
r = ch341_detect_hl340(port->serial->dev);
if (r < 0)
goto error;
+ else if (r != 0)
+ priv->flags |= CH341_QUIRK_LIMITED_PRESCALER;
usb_set_serial_port_data(port, priv);
return 0;
--
2.20.1
next prev parent reply other threads:[~2020-03-06 19:00 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-06 19:00 [PATCH 0/4] ch341: Add support for HL340 devices Michael Hanselmann
2020-03-06 19:00 ` [PATCH 1/4] ch341: Name more registers Michael Hanselmann
2020-03-24 10:20 ` Johan Hovold
2020-03-31 23:34 ` Michael Hanselmann
2020-03-06 19:00 ` [PATCH 2/4] ch341: Detect HL340 variant Michael Hanselmann
2020-03-24 10:31 ` Johan Hovold
2020-03-31 23:35 ` Michael Hanselmann
2020-03-06 19:00 ` Michael Hanselmann [this message]
2020-03-24 10:41 ` [PATCH 3/4] ch341: Limit prescaler on " Johan Hovold
2020-03-31 23:35 ` Michael Hanselmann
2020-03-06 19:00 ` [PATCH 4/4] ch341: Simulate break condition " Michael Hanselmann
2020-03-24 10:55 ` Johan Hovold
2020-03-24 10:05 ` [PATCH 0/4] ch341: Add support for HL340 devices Johan Hovold
2020-03-31 23:35 ` Michael Hanselmann
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=d76985a6dcf1b4aeec783dd8c8b59f054b51e07d.1583520568.git.public@hansmi.ch \
--to=public@hansmi.ch \
--cc=johan@kernel.org \
--cc=jontio@i4free.co.nz \
--cc=linux-usb@vger.kernel.org \
--cc=michael@5dot1.de \
/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).