All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Ji-Ze Hong \(Peter Hong\)" <hpeter@gmail.com>
To: johan@kernel.org
Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org,
	linux-kernel@vger.kernel.org, peter_hong@fintek.com.tw,
	"Ji-Ze Hong \(Peter Hong\)" <hpeter+linux_kernel@gmail.com>
Subject: [2/5] USB: serial: f81232: add high baud rate support
Date: Mon, 22 Jan 2018 15:58:44 +0800	[thread overview]
Message-ID: <1516607927-8887-2-git-send-email-hpeter+linux_kernel@gmail.com> (raw)

The F81232 had 4 clocksource 1.846/18.46/14.77/24MHz and baud rates
can be up to 1.5Mbits with 24MHz.

F81232 Clock registers (106h)

Bit1-0:     Clock source selector
                    00: 1.846MHz.
                    01: 18.46MHz.
                    10: 24MHz.
                    11: 14.77MHz.

Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
---
 drivers/usb/serial/f81232.c | 105 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 94 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 46836041c50e..bdd7f337cd5f 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -28,7 +28,8 @@ static const struct usb_device_id id_table[] = {
 MODULE_DEVICE_TABLE(usb, id_table);
 
 /* Maximum baudrate for F81232 */
-#define F81232_MAX_BAUDRATE		115200
+#define F81232_MAX_BAUDRATE		1500000
+#define F81232_DEF_BAUDRATE		9600
 
 /* USB Control EP parameter */
 #define F81232_REGISTER_REQUEST		0xa0
@@ -44,18 +45,42 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define LINE_STATUS_REGISTER		(0x05 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER		(0x06 + SERIAL_BASE_ADDRESS)
 
+/*
+ * F81232 Clock registers (106h)
+ *
+ * Bit1-0:	Clock source selector
+ *			00: 1.846MHz.
+ *			01: 18.46MHz.
+ *			10: 24MHz.
+ *			11: 14.77MHz.
+ */
+#define F81232_CLK_REGISTER		0x106
+#define F81232_CLK_1_846_MHZ		0
+#define F81232_CLK_18_46_MHZ		BIT(0)
+#define F81232_CLK_24_MHZ		BIT(1)
+#define F81232_CLK_14_77_MHZ		(BIT(1) | BIT(0))
+#define F81232_CLK_MASK			GENMASK(1, 0)
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;
 	u8 modem_status;
+	speed_t baud_base;
 	struct work_struct lsr_work;
 	struct work_struct interrupt_work;
 	struct usb_serial_port *port;
 };
 
-static int calc_baud_divisor(speed_t baudrate)
+static u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 };
+static u8 const clock_table[] = { F81232_CLK_1_846_MHZ, F81232_CLK_14_77_MHZ,
+				F81232_CLK_18_46_MHZ, F81232_CLK_24_MHZ };
+
+static int calc_baud_divisor(speed_t baudrate, speed_t clockrate)
 {
-	return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate);
+	if (!baudrate)
+		return 0;
+
+	return DIV_ROUND_CLOSEST(clockrate, baudrate);
 }
 
 static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
@@ -129,6 +154,21 @@ static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val)
 	return status;
 }
 
+static int f81232_set_mask_register(struct usb_serial_port *port, u16 reg,
+					u8 mask, u8 val)
+{
+	int status;
+	u8 tmp;
+
+	status = f81232_get_register(port, reg, &tmp);
+	if (status)
+		return status;
+
+	tmp = (tmp & ~mask) | (val & mask);
+
+	return f81232_set_register(port, reg, tmp);
+}
+
 static void f81232_read_msr(struct usb_serial_port *port)
 {
 	int status;
@@ -346,13 +386,53 @@ static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 	 */
 }
 
-static void f81232_set_baudrate(struct usb_serial_port *port, speed_t baudrate)
+static int f81232_find_clk(speed_t baudrate)
+{
+	int idx;
+
+	for (idx = 0; idx < ARRAY_SIZE(baudrate_table); ++idx) {
+		if (baudrate <= baudrate_table[idx] &&
+				baudrate_table[idx] % baudrate == 0)
+			return idx;
+	}
+
+	return -EINVAL;
+}
+
+static void f81232_set_baudrate(struct tty_struct *tty,
+				struct usb_serial_port *port, speed_t baudrate,
+				speed_t old_baudrate)
 {
+	struct f81232_private *priv = usb_get_serial_port_data(port);
 	u8 lcr;
 	int divisor;
 	int status = 0;
+	int i;
+	int idx;
+	speed_t baud_list[] = {baudrate, old_baudrate, F81232_DEF_BAUDRATE};
+
+	for (i = 0; i < ARRAY_SIZE(baud_list); ++i) {
+		idx = f81232_find_clk(baud_list[i]);
+		if (idx >= 0) {
+			baudrate = baud_list[i];
+			tty_encode_baud_rate(tty, baudrate, baudrate);
+			break;
+		}
+	}
 
-	divisor = calc_baud_divisor(baudrate);
+	if (idx < 0)
+		return;
+
+	priv->baud_base = baudrate_table[idx];
+	divisor = calc_baud_divisor(baudrate, priv->baud_base);
+
+	status = f81232_set_mask_register(port, F81232_CLK_REGISTER,
+			F81232_CLK_MASK, clock_table[idx]);
+	if (status) {
+		dev_err(&port->dev, "%s failed to set CLK_REG: %d\n",
+			__func__, status);
+		return;
+	}
 
 	status = f81232_get_register(port, LINE_CONTROL_REGISTER,
 			 &lcr); /* get LCR */
@@ -442,6 +522,7 @@ static void f81232_set_termios(struct tty_struct *tty,
 	u8 new_lcr = 0;
 	int status = 0;
 	speed_t baudrate;
+	speed_t old_baud;
 
 	/* Don't change anything if nothing has changed */
 	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
@@ -454,11 +535,12 @@ static void f81232_set_termios(struct tty_struct *tty,
 
 	baudrate = tty_get_baud_rate(tty);
 	if (baudrate > 0) {
-		if (baudrate > F81232_MAX_BAUDRATE) {
-			baudrate = F81232_MAX_BAUDRATE;
-			tty_encode_baud_rate(tty, baudrate, baudrate);
-		}
-		f81232_set_baudrate(port, baudrate);
+		if (old_termios)
+			old_baud = tty_termios_baud_rate(old_termios);
+		else
+			old_baud = F81232_DEF_BAUDRATE;
+
+		f81232_set_baudrate(tty, port, baudrate, old_baud);
 	}
 
 	if (C_PARENB(tty)) {
@@ -590,6 +672,7 @@ static int f81232_carrier_raised(struct usb_serial_port *port)
 static int f81232_get_serial_info(struct usb_serial_port *port,
 		unsigned long arg)
 {
+	struct f81232_private *priv = usb_get_serial_port_data(port);
 	struct serial_struct ser;
 
 	memset(&ser, 0, sizeof(ser));
@@ -597,7 +680,7 @@ static int f81232_get_serial_info(struct usb_serial_port *port,
 	ser.type = PORT_16550A;
 	ser.line = port->minor;
 	ser.port = port->port_number;
-	ser.baud_base = F81232_MAX_BAUDRATE;
+	ser.baud_base = priv->baud_base;
 
 	if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
 		return -EFAULT;

WARNING: multiple messages have this Message-ID (diff)
From: "Ji-Ze Hong (Peter Hong)" <hpeter@gmail.com>
To: johan@kernel.org
Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org,
	linux-kernel@vger.kernel.org, peter_hong@fintek.com.tw,
	"Ji-Ze Hong (Peter Hong)" <hpeter+linux_kernel@gmail.com>
Subject: [PATCH 2/5] USB: serial: f81232: add high baud rate support
Date: Mon, 22 Jan 2018 15:58:44 +0800	[thread overview]
Message-ID: <1516607927-8887-2-git-send-email-hpeter+linux_kernel@gmail.com> (raw)
In-Reply-To: <1516607927-8887-1-git-send-email-hpeter+linux_kernel@gmail.com>

The F81232 had 4 clocksource 1.846/18.46/14.77/24MHz and baud rates
can be up to 1.5Mbits with 24MHz.

F81232 Clock registers (106h)

Bit1-0:     Clock source selector
                    00: 1.846MHz.
                    01: 18.46MHz.
                    10: 24MHz.
                    11: 14.77MHz.

Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
---
 drivers/usb/serial/f81232.c | 105 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 94 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 46836041c50e..bdd7f337cd5f 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -28,7 +28,8 @@ static const struct usb_device_id id_table[] = {
 MODULE_DEVICE_TABLE(usb, id_table);
 
 /* Maximum baudrate for F81232 */
-#define F81232_MAX_BAUDRATE		115200
+#define F81232_MAX_BAUDRATE		1500000
+#define F81232_DEF_BAUDRATE		9600
 
 /* USB Control EP parameter */
 #define F81232_REGISTER_REQUEST		0xa0
@@ -44,18 +45,42 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define LINE_STATUS_REGISTER		(0x05 + SERIAL_BASE_ADDRESS)
 #define MODEM_STATUS_REGISTER		(0x06 + SERIAL_BASE_ADDRESS)
 
+/*
+ * F81232 Clock registers (106h)
+ *
+ * Bit1-0:	Clock source selector
+ *			00: 1.846MHz.
+ *			01: 18.46MHz.
+ *			10: 24MHz.
+ *			11: 14.77MHz.
+ */
+#define F81232_CLK_REGISTER		0x106
+#define F81232_CLK_1_846_MHZ		0
+#define F81232_CLK_18_46_MHZ		BIT(0)
+#define F81232_CLK_24_MHZ		BIT(1)
+#define F81232_CLK_14_77_MHZ		(BIT(1) | BIT(0))
+#define F81232_CLK_MASK			GENMASK(1, 0)
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;
 	u8 modem_status;
+	speed_t baud_base;
 	struct work_struct lsr_work;
 	struct work_struct interrupt_work;
 	struct usb_serial_port *port;
 };
 
-static int calc_baud_divisor(speed_t baudrate)
+static u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 };
+static u8 const clock_table[] = { F81232_CLK_1_846_MHZ, F81232_CLK_14_77_MHZ,
+				F81232_CLK_18_46_MHZ, F81232_CLK_24_MHZ };
+
+static int calc_baud_divisor(speed_t baudrate, speed_t clockrate)
 {
-	return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate);
+	if (!baudrate)
+		return 0;
+
+	return DIV_ROUND_CLOSEST(clockrate, baudrate);
 }
 
 static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
@@ -129,6 +154,21 @@ static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val)
 	return status;
 }
 
+static int f81232_set_mask_register(struct usb_serial_port *port, u16 reg,
+					u8 mask, u8 val)
+{
+	int status;
+	u8 tmp;
+
+	status = f81232_get_register(port, reg, &tmp);
+	if (status)
+		return status;
+
+	tmp = (tmp & ~mask) | (val & mask);
+
+	return f81232_set_register(port, reg, tmp);
+}
+
 static void f81232_read_msr(struct usb_serial_port *port)
 {
 	int status;
@@ -346,13 +386,53 @@ static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 	 */
 }
 
-static void f81232_set_baudrate(struct usb_serial_port *port, speed_t baudrate)
+static int f81232_find_clk(speed_t baudrate)
+{
+	int idx;
+
+	for (idx = 0; idx < ARRAY_SIZE(baudrate_table); ++idx) {
+		if (baudrate <= baudrate_table[idx] &&
+				baudrate_table[idx] % baudrate == 0)
+			return idx;
+	}
+
+	return -EINVAL;
+}
+
+static void f81232_set_baudrate(struct tty_struct *tty,
+				struct usb_serial_port *port, speed_t baudrate,
+				speed_t old_baudrate)
 {
+	struct f81232_private *priv = usb_get_serial_port_data(port);
 	u8 lcr;
 	int divisor;
 	int status = 0;
+	int i;
+	int idx;
+	speed_t baud_list[] = {baudrate, old_baudrate, F81232_DEF_BAUDRATE};
+
+	for (i = 0; i < ARRAY_SIZE(baud_list); ++i) {
+		idx = f81232_find_clk(baud_list[i]);
+		if (idx >= 0) {
+			baudrate = baud_list[i];
+			tty_encode_baud_rate(tty, baudrate, baudrate);
+			break;
+		}
+	}
 
-	divisor = calc_baud_divisor(baudrate);
+	if (idx < 0)
+		return;
+
+	priv->baud_base = baudrate_table[idx];
+	divisor = calc_baud_divisor(baudrate, priv->baud_base);
+
+	status = f81232_set_mask_register(port, F81232_CLK_REGISTER,
+			F81232_CLK_MASK, clock_table[idx]);
+	if (status) {
+		dev_err(&port->dev, "%s failed to set CLK_REG: %d\n",
+			__func__, status);
+		return;
+	}
 
 	status = f81232_get_register(port, LINE_CONTROL_REGISTER,
 			 &lcr); /* get LCR */
@@ -442,6 +522,7 @@ static void f81232_set_termios(struct tty_struct *tty,
 	u8 new_lcr = 0;
 	int status = 0;
 	speed_t baudrate;
+	speed_t old_baud;
 
 	/* Don't change anything if nothing has changed */
 	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
@@ -454,11 +535,12 @@ static void f81232_set_termios(struct tty_struct *tty,
 
 	baudrate = tty_get_baud_rate(tty);
 	if (baudrate > 0) {
-		if (baudrate > F81232_MAX_BAUDRATE) {
-			baudrate = F81232_MAX_BAUDRATE;
-			tty_encode_baud_rate(tty, baudrate, baudrate);
-		}
-		f81232_set_baudrate(port, baudrate);
+		if (old_termios)
+			old_baud = tty_termios_baud_rate(old_termios);
+		else
+			old_baud = F81232_DEF_BAUDRATE;
+
+		f81232_set_baudrate(tty, port, baudrate, old_baud);
 	}
 
 	if (C_PARENB(tty)) {
@@ -590,6 +672,7 @@ static int f81232_carrier_raised(struct usb_serial_port *port)
 static int f81232_get_serial_info(struct usb_serial_port *port,
 		unsigned long arg)
 {
+	struct f81232_private *priv = usb_get_serial_port_data(port);
 	struct serial_struct ser;
 
 	memset(&ser, 0, sizeof(ser));
@@ -597,7 +680,7 @@ static int f81232_get_serial_info(struct usb_serial_port *port,
 	ser.type = PORT_16550A;
 	ser.line = port->minor;
 	ser.port = port->port_number;
-	ser.baud_base = F81232_MAX_BAUDRATE;
+	ser.baud_base = priv->baud_base;
 
 	if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
 		return -EFAULT;
-- 
2.7.4


             reply	other threads:[~2018-01-22  7:58 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-22  7:58 Ji-Ze Hong (Peter Hong) [this message]
2018-01-22  7:58 ` [PATCH 2/5] USB: serial: f81232: add high baud rate support Ji-Ze Hong (Peter Hong)
  -- strict thread matches above, loose matches on Subject: below --
2018-02-08  9:17 [3/5] USB: serial: f81232: enable remote wakeup via RX/RI pin Ji-Ze Hong (Peter Hong)
2018-02-08  9:17 ` [PATCH 3/5] " Ji-Ze Hong (Peter Hong)
2018-02-04  1:50 [5/5] USB: serial: f81232: fix bulk_in/out size Johan Hovold
2018-02-04  1:50 ` [PATCH 5/5] " Johan Hovold
2018-02-04  1:46 [3/5] USB: serial: f81232: enable remote wakeup via RX/RI pin Johan Hovold
2018-02-04  1:46 ` [PATCH 3/5] " Johan Hovold
2018-02-01  5:50 [5/5] USB: serial: f81232: fix bulk_in/out size Ji-Ze Hong (Peter Hong)
2018-02-01  5:50 ` [PATCH 5/5] " Ji-Ze Hong (Peter Hong)
2018-02-01  3:13 [3/5] USB: serial: f81232: enable remote wakeup via RX/RI pin Ji-Ze Hong (Peter Hong)
2018-02-01  3:13 ` [PATCH 3/5] " Ji-Ze Hong (Peter Hong)
2018-01-30  4:11 [5/5] USB: serial: f81232: fix bulk_in/out size Johan Hovold
2018-01-30  4:11 ` [PATCH 5/5] " Johan Hovold
2018-01-30  3:57 [3/5] USB: serial: f81232: enable remote wakeup via RX/RI pin Johan Hovold
2018-01-30  3:57 ` [PATCH 3/5] " Johan Hovold
2018-01-30  3:30 [2/5] USB: serial: f81232: add high baud rate support Johan Hovold
2018-01-30  3:30 ` [PATCH 2/5] " Johan Hovold
2018-01-23  2:08 [2/5] " Ji-Ze Hong (Peter Hong)
2018-01-23  2:08 ` [PATCH 2/5] " Ji-Ze Hong (Peter Hong)
2018-01-23  1:50 [1/5] USB: serial: f81232: clear overrun flag Ji-Ze Hong (Peter Hong)
2018-01-23  1:50 ` [PATCH 1/5] " Ji-Ze Hong (Peter Hong)
2018-01-22 14:55 [2/5] USB: serial: f81232: add high baud rate support Andy Shevchenko
2018-01-22 14:55 ` [PATCH 2/5] " Andy Shevchenko
2018-01-22 10:06 [1/5] USB: serial: f81232: clear overrun flag Oliver Neukum
2018-01-22 10:06 ` [PATCH 1/5] " Oliver Neukum
2018-01-22  7:58 [5/5] USB: serial: f81232: fix bulk_in/out size Ji-Ze Hong (Peter Hong)
2018-01-22  7:58 ` [PATCH 5/5] " Ji-Ze Hong (Peter Hong)
2018-01-22  7:58 [4/5] USB: serial: f81232: implement break control Ji-Ze Hong (Peter Hong)
2018-01-22  7:58 ` [PATCH 4/5] " Ji-Ze Hong (Peter Hong)
2018-01-22  7:58 [3/5] USB: serial: f81232: enable remote wakeup via RX/RI pin Ji-Ze Hong (Peter Hong)
2018-01-22  7:58 ` [PATCH 3/5] " Ji-Ze Hong (Peter Hong)
2018-01-22  7:58 [1/5] USB: serial: f81232: clear overrun flag Ji-Ze Hong (Peter Hong)
2018-01-22  7:58 ` [PATCH 1/5] " Ji-Ze Hong (Peter Hong)

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=1516607927-8887-2-git-send-email-hpeter+linux_kernel@gmail.com \
    --to=hpeter@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hpeter+linux_kernel@gmail.com \
    --cc=johan@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=peter_hong@fintek.com.tw \
    /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.