All of lore.kernel.org
 help / color / mirror / Atom feed
From: Grigori Goronzy <greg@chown.ath.cx>
To: Johan Hovold <johan@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
	Grigori Goronzy <greg@chown.ath.cx>
Subject: [PATCH v4 05/13] USB: ch341: reinitialize chip on reconfiguration
Date: Fri, 15 Apr 2016 23:14:08 +0200	[thread overview]
Message-ID: <1460754856-27908-6-git-send-email-greg@chown.ath.cx> (raw)
In-Reply-To: <1460754856-27908-1-git-send-email-greg@chown.ath.cx>

Changing the LCR register after initialization does not seem to be
reliable on all chips (particularly not on CH341A).  Restructure
initialization and configuration to always reinit the chip on
configuration changes instead and pass the LCR register value directly
to the initialization command.

v2: get rid of unused variable, improve error handling.

Tested-by: Ryan Barber <rfb@skyscraper.nu>
Signed-off-by: Grigori Goronzy <greg@chown.ath.cx>
---
 drivers/usb/serial/ch341.c | 47 ++++++++++++++++++++++++----------------------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 95c8a40..6181616 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -61,6 +61,8 @@
  * the Net/FreeBSD uchcom.c driver by Takanori Watanabe.  Domo arigato.
  */
 
+#define CH341_SERIAL_INIT      0xA1
+#define CH341_VERSION          0x5F
 #define CH341_MODEM_CTRL       0xA4
 #define CH341_REQ_WRITE_REG    0x9A
 #define CH341_REQ_READ_REG     0x95
@@ -129,10 +131,10 @@ static int ch341_control_in(struct usb_device *dev,
 	return r;
 }
 
-static int ch341_set_baudrate(struct usb_device *dev,
-			      struct ch341_private *priv)
+static int ch341_init_set_baudrate(struct usb_device *dev,
+			      struct ch341_private *priv, unsigned ctrl)
 {
-	short a, b;
+	short a;
 	int r;
 	unsigned long factor;
 	short divisor;
@@ -152,11 +154,8 @@ static int ch341_set_baudrate(struct usb_device *dev,
 
 	factor = 0x10000 - factor;
 	a = (factor & 0xff00) | divisor;
-	b = factor & 0xff;
 
-	r = ch341_control_out(dev, 0x9a, 0x1312, a);
-	if (!r)
-		r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
+	r = ch341_control_out(dev, CH341_SERIAL_INIT, 0x9c | (ctrl << 8), a | 0x80);
 
 	return r;
 }
@@ -177,7 +176,7 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
 	if (!buffer)
 		return -ENOMEM;
 
-	r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
+	r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x0706, 0, buffer, size);
 	if (r < 0)
 		goto out;
 
@@ -207,24 +206,20 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
 		return -ENOMEM;
 
 	/* expect two bytes 0x27 0x00 */
-	r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
+	r = ch341_control_in(dev, CH341_VERSION, 0, 0, buffer, size);
 	if (r < 0)
 		goto out;
 
-	r = ch341_control_out(dev, 0xa1, 0, 0);
-	if (r < 0)
-		goto out;
-
-	r = ch341_set_baudrate(dev, priv);
+	r = ch341_control_out(dev, CH341_SERIAL_INIT, 0, 0);
 	if (r < 0)
 		goto out;
 
 	/* expect two bytes 0x56 0x00 */
-	r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
+	r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x2518, 0, buffer, size);
 	if (r < 0)
 		goto out;
 
-	r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
+	r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, 0x00c3);
 	if (r < 0)
 		goto out;
 
@@ -233,11 +228,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
 	if (r < 0)
 		goto out;
 
-	r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
-	if (r < 0)
-		goto out;
-
-	r = ch341_set_baudrate(dev, priv);
+	r = ch341_init_set_baudrate(dev, priv, 0);
 	if (r < 0)
 		goto out;
 
@@ -352,16 +343,28 @@ static void ch341_set_termios(struct tty_struct *tty,
 	struct ch341_private *priv = usb_get_serial_port_data(port);
 	unsigned baud_rate;
 	unsigned long flags;
+	unsigned char ctrl;
+	int r;
+
+	/* redundant changes may cause the chip to lose bytes */
+	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
+		return;
 
 	baud_rate = tty_get_baud_rate(tty);
 
 	priv->baud_rate = baud_rate;
 
+	ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8;
+
 	if (baud_rate) {
 		spin_lock_irqsave(&priv->lock, flags);
 		priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
 		spin_unlock_irqrestore(&priv->lock, flags);
-		ch341_set_baudrate(port->serial->dev, priv);
+		r = ch341_init_set_baudrate(port->serial->dev, priv, ctrl);
+		if (r < 0 && old_termios) {
+			priv->baud_rate = tty_termios_baud_rate(old_termios);
+			tty_termios_copy_hw(&tty->termios, old_termios);
+		}
 	} else {
 		spin_lock_irqsave(&priv->lock, flags);
 		priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
-- 
1.9.1

  parent reply	other threads:[~2016-04-15 21:17 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-15 21:14 Major improvements to the ch341 driver v4 Grigori Goronzy
2016-04-15 21:14 ` [PATCH v4 01/13] USB: ch341: fix error handling on resume Grigori Goronzy
2016-04-29 12:16   ` Johan Hovold
2016-04-29 15:11     ` Grigori Goronzy
2016-05-02 13:45       ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 02/13] USB: ch341: add LCR register definitions Grigori Goronzy
2016-04-29 12:18   ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 03/13] USB: ch341: add definitions for modem control Grigori Goronzy
2016-04-29 12:22   ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 04/13] USB: ch341: fix USB buffer allocations Grigori Goronzy
2016-04-29 12:52   ` Johan Hovold
2016-04-29 15:12     ` Grigori Goronzy
2016-04-15 21:14 ` Grigori Goronzy [this message]
2016-04-29 13:03   ` [PATCH v4 05/13] USB: ch341: reinitialize chip on reconfiguration Johan Hovold
2016-04-15 21:14 ` [PATCH v4 06/13] USB: ch341: add support for parity, frame length, stop bits Grigori Goronzy
2016-04-29 13:11   ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 07/13] USB: ch341: add debug output for chip version Grigori Goronzy
2016-04-29 13:13   ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 08/13] USB: ch341: add support for RTS/CTS flow control Grigori Goronzy
2016-04-29 13:23   ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 09/13] USB: ch341: fix coding style Grigori Goronzy
2016-04-29 13:29   ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 10/13] USB: ch341: clean up messages Grigori Goronzy
2016-04-29 13:40   ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 11/13] USB: ch341: improve B0 handling Grigori Goronzy
2016-04-29 13:41   ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 12/13] USB: ch341: get rid of default configuration Grigori Goronzy
2016-04-29 13:43   ` Johan Hovold
2016-04-15 21:14 ` [PATCH v4 13/13] USB: ch341: implement tx_empty callback Grigori Goronzy
2016-04-29 13:47   ` Johan Hovold
2016-04-28 23:24 ` Major improvements to the ch341 driver v4 Grigori Goronzy

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=1460754856-27908-6-git-send-email-greg@chown.ath.cx \
    --to=greg@chown.ath.cx \
    --cc=gregkh@linuxfoundation.org \
    --cc=johan@kernel.org \
    --cc=linux-kernel@vger.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.