public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support
@ 2024-10-24 10:08 Tony Chung
  2024-10-24 10:09 ` [PATCH 1/3] drivers: usb: serial: mos7840: Add defines for clock select register offset Tony Chung
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Tony Chung @ 2024-10-24 10:08 UTC (permalink / raw)
  To: gregkh; +Cc: johan, linux-kernel, linux-usb, Tony Chung

This patch set has made some improvements for baud rate setup:
1. Optimized register configurations for common baud rates.
2. Added clock select registers to choose between 96M, 30M, or external clock sources,
   allowing baud rate setup to 6M, matching the hardware's maximum data rate.

Tony Chung (3):
  drivers: usb: serial: mos7840: Add defines for clock select register
    offset
  drivers: usb: serial: mos7840: added optimized register setups for
    common baudrates.
  driver: usb: serial: mos7840: add more baudrate options

 drivers/usb/serial/mos7840.c | 273 ++++++++++++++++++++++++++++++++++-
 1 file changed, 269 insertions(+), 4 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] drivers: usb: serial: mos7840: Add defines for clock select register offset
  2024-10-24 10:08 [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support Tony Chung
@ 2024-10-24 10:09 ` Tony Chung
  2025-02-11  9:44   ` Johan Hovold
  2024-10-24 10:09 ` [PATCH 2/3] drivers: usb: serial: mos7840: added optimized register setups for common baudrates Tony Chung
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Tony Chung @ 2024-10-24 10:09 UTC (permalink / raw)
  To: gregkh; +Cc: johan, linux-kernel, linux-usb, Tony Chung

This patch adds define for CLOCK_SELECT_REG1 & CLOCK_SELECT_REG2 offsets.
These two registers can select clock source between 30M/96M/External.

Signed-off-by: Tony Chung <tony467913@gmail.com>
---
 drivers/usb/serial/mos7840.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index ca3da79af..362875a53 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -144,6 +144,9 @@
 
 #define SERIAL_LCR_DLAB            ((__u16)(0x0080))
 
+#define CLOCK_SELECT_REG1          ((__u16)(0x13))
+#define CLOCK_SELECT_REG2          ((__u16)(0x14))
+
 /*
  * URB POOL related defines
  */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3] drivers: usb: serial: mos7840: added optimized register setups for common baudrates.
  2024-10-24 10:08 [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support Tony Chung
  2024-10-24 10:09 ` [PATCH 1/3] drivers: usb: serial: mos7840: Add defines for clock select register offset Tony Chung
@ 2024-10-24 10:09 ` Tony Chung
  2025-02-11 10:16   ` Johan Hovold
  2024-10-24 10:09 ` [PATCH 3/3] driver: usb: serial: mos7840: add more baudrate options Tony Chung
  2025-02-11  9:41 ` [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support Johan Hovold
  3 siblings, 1 reply; 8+ messages in thread
From: Tony Chung @ 2024-10-24 10:09 UTC (permalink / raw)
  To: gregkh; +Cc: johan, linux-kernel, linux-usb, Tony Chung

added optimized register setups for common baudrates.

Signed-off-by: Tony Chung <tony467913@gmail.com>
---
 drivers/usb/serial/mos7840.c | 114 ++++++++++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 362875a53..acc16737b 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1063,11 +1063,116 @@ static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port,
 {
 	dev_dbg(&port->dev, "%s - %d\n", __func__, baudRate);
 
-	if (baudRate <= 115200) {
+	// divisor = (256*DLM)+DLL
+	// baudrate = InputCLK/(16*Divisor)
+	if (baudRate == 50) {
+		*divisor = (256*0x09)+0x04; // DLM=0x09, DLL=0x04
+		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
+	} else if (baudRate == 75) {
+		*divisor = (256*0x06)+0x02; // DLM=0x06, DLL=0x02
+		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
+	} else if (baudRate == 110) {
+		*divisor = (256*0x04)+0x19; // DLM=0x04, DLL=0x19
+		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
+	} else if (baudRate == 134) {
+		*divisor = (256*0x03)+0x5d; // DLM=0x03, DLL=0x5d
+		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
+	} else if (baudRate == 150) {
+		*divisor = (256*0x03)+0x01; // DLM=0x03, DLL=0x01
+		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
+	} else if (baudRate == 300) {
+		*divisor = (256*0x01)+0x81; // DLM=0x01, DLL=0x81
+		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
+	} else if (baudRate == 600) {
+		*divisor = 0xc0;		// DLM=0, DLL=0xc0
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 1200) {
+		*divisor = 0x60;		// DLM=0, DLL=0x60
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 1800) {
+		*divisor = 0x40;		// DLM=0, DLL=0x40
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 2400) {
+		*divisor = 0x30;		// DLM=0, DLL=0x30
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 4800) {
+		*divisor = 0x18;		// DLM=0, DLL=0x18
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 7200) {
+		*divisor = 0x10;		// DLM=0, DLL=0x10
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 9600) {
+		*divisor = 0x0c;		// DLM=0, DLL=0x0c
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 14400) {
+		*divisor = 0x08;		// DLM=0, DLL=0x08
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 19200) {
+		*divisor = 0x06;		// DLM=0, DLL=0x06
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 28800) {
+		*divisor = 0x04;		// DLM=0, DLL=0x04
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 38400) {
+		*divisor = 0x03;		// DLM=0, DLL=0x03
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 57600) {
+		*divisor = 0x02;		// DLM=0, DLL=0x02
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 115200) {
+		*divisor = 0x01;		// DLM=0, DLL=0x01
+		*clk_sel_val = 0x0;		// clock source = 1.846153846M
+	} else if (baudRate == 230400) {
+		*divisor = 0x01;		// DLM=0, DLL=0x01
+		*clk_sel_val = 0x10;	// clock source = 3.692307692M
+	} else if (baudRate == 460800) {
+		*divisor = 0x01;		// DLM=0, DLL=0x01
+		*clk_sel_val = 0x30;	// clock source = 7.384615384M
+	} else if (baudRate == 806400) {
+		*divisor = 0x01;		// DLM=0, DLL=0x01
+		*clk_sel_val = 0x40;	// clock source = 12.923076922M
+	} else if (baudRate == 921600) {
+		*divisor = 0x01;		// DLM=0, DLL=0x01
+		*clk_sel_val = 0x50;	// clock source = 14.769230768M
+	} else if (baudRate == 25000) {
+		*divisor = 0x78;		// DLM=0, DLL=0x78
+		*clk_sel_val = 0x70;	// clock source=48M
+	} else if (baudRate == 50000) {
+		*divisor = 0x3c;		// DLM=0, DLL=0x3c
+		*clk_sel_val = 0x70;	// clock source=48M
+	} else if (baudRate == 75000) {
+		*divisor = 0x28;		// DLM=0, DLL=0x28
+		*clk_sel_val = 0x70;	// clock source=48M
+	} else if (baudRate == 100000) {
+		*divisor = 0x1e;		// DLM=0, DLL=0x1e
+		*clk_sel_val = 0x70;	// clock source=48M
+	} else if (baudRate == 250000) {
+		*divisor = 0x0c;		// DLM=0, DLL=0x0c
+		*clk_sel_val = 0x70;	// clock source=48M
+	} else if (baudRate == 300000) {
+		*divisor = 0x0a;		// DLM=0, DLL=0x0a
+		*clk_sel_val = 0x70;	// clock source=48M
+	} else if (baudRate == 500000) {
+		*divisor = 0x06;		// DLM=0, DLL=0x06
+		*clk_sel_val = 0x70;	// clock source=48M
+	} else if (baudRate == 600000) {
+		*divisor = 0x05;		// DLM=0, DLL=0x05
+		*clk_sel_val = 0x70;	// clock source=48M
+	} else if (baudRate == 1000000) {
+		*divisor = 0x03;		// DLM=0, DLL=0x03
+		*clk_sel_val = 0x70;	// clock source=48M
+	} else if (baudRate == 3000000) {
+		*divisor = 0x01;		// DLM=0, DLL=0x01
+		*clk_sel_val = 0x70;	// clock source=48M
+
+	} else if (baudRate == 1500000) {
+		*divisor = 0x01;		// DLM=0, DLL=0x01
+		*clk_sel_val = 0x60;	// clock source=24M
+
+	} else if (baudRate <= 115200) {
 		*divisor = 115200 / baudRate;
 		*clk_sel_val = 0x0;
-	}
-	if ((baudRate > 115200) && (baudRate <= 230400)) {
+	} else if ((baudRate > 115200) && (baudRate <= 230400)) {
 		*divisor = 230400 / baudRate;
 		*clk_sel_val = 0x10;
 	} else if ((baudRate > 230400) && (baudRate <= 403200)) {
@@ -1088,6 +1193,9 @@ static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port,
 	} else if ((baudRate > 1572864) && (baudRate <= 3145728)) {
 		*divisor = 3145728 / baudRate;
 		*clk_sel_val = 0x70;
+	} else {
+		dev_dbg(&port->dev, "func: %s -baudrate %d not supported.\n", __func__, baudRate);
+		return -1;
 	}
 	return 0;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3] driver: usb: serial: mos7840: add more baudrate options
  2024-10-24 10:08 [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support Tony Chung
  2024-10-24 10:09 ` [PATCH 1/3] drivers: usb: serial: mos7840: Add defines for clock select register offset Tony Chung
  2024-10-24 10:09 ` [PATCH 2/3] drivers: usb: serial: mos7840: added optimized register setups for common baudrates Tony Chung
@ 2024-10-24 10:09 ` Tony Chung
  2025-02-11 13:08   ` Johan Hovold
  2025-02-11  9:41 ` [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support Johan Hovold
  3 siblings, 1 reply; 8+ messages in thread
From: Tony Chung @ 2024-10-24 10:09 UTC (permalink / raw)
  To: gregkh; +Cc: johan, linux-kernel, linux-usb, Tony Chung

Adds more baud rate options using 96M/30M/External clock sources.
To use these clock sources,
set through Clk_Select_Reg1 and Clk_Select_Reg2.

Signed-off-by: Tony Chung <tony467913@gmail.com>
---
 drivers/usb/serial/mos7840.c | 156 ++++++++++++++++++++++++++++++++++-
 1 file changed, 155 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index acc16737b..70ee4a638 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1169,6 +1169,37 @@ static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port,
 		*divisor = 0x01;		// DLM=0, DLL=0x01
 		*clk_sel_val = 0x60;	// clock source=24M
 
+	/* below are using 96M or 30M clock source
+	 * will determine the clock source later
+	 * in function mos7840_send_cmd_write_baud_rate
+	 */
+	} else if (baudRate == 6000000) {
+		*divisor = 0x01;		// DLM=0, DLL=0x01
+		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M
+	} else if (baudRate == 2000000) {
+		*divisor = 0x03;		// DLM=0, DLL=0x03
+		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M
+	} else if (baudRate == 403200) {
+		*divisor = 0x0f;		// DLM=0, DLL=0x0f
+		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M
+	} else if (baudRate == 225000) {
+		*divisor = 0x1b;		// DLM=0, DLL=0x1b
+		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M
+	} else if (baudRate == 153600) {
+		*divisor = 0x27;		// DLM=0, DLL=0x27
+		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M
+
+	} else if (baudRate == 10000) {
+		*divisor = 0xbb;		// DLM=0, DLL=0xbb
+		*clk_sel_val = 0x80;	// DUMMY val, clock source = 30M
+	} else if (baudRate == 125000) {
+		*divisor = 0x0f;		// DLM=0, DLL=0x0f
+		*clk_sel_val = 0x80;	// DUMMY val, clock source = 30M
+	} else if (baudRate == 625000) {
+		*divisor = 0x03;		// DLM=0, DLL=0x03
+		*clk_sel_val = 0x80;	// DUMMY val, clock source = 30M
+
+
 	} else if (baudRate <= 115200) {
 		*divisor = 115200 / baudRate;
 		*clk_sel_val = 0x0;
@@ -1246,11 +1277,134 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
 
 	}
 
-	if (1) {		/* baudRate <= 115200) */
+	if (1) {
 		clk_sel_val = 0x0;
 		Data = 0x0;
 		status = mos7840_calc_baud_rate_divisor(port, baudRate, &divisor,
 						   &clk_sel_val);
+		if (status < 0) {
+			dev_dbg(&port->dev, "%s failed in set_serial_baud\n", __func__);
+			return -1;
+		}
+
+		/* Write clk_sel_val to SP_Reg or Clk_Select_Reg*/
+		// check clk_sel_val before setting the clk_sel_val
+		if (clk_sel_val == 0x80) {
+		// clk_sel_val is DUMMY value -> Write the corresponding value to Clk_Select_Reg
+			// 0x01:30M, 0x02:96M, 0x05:External Clock
+			if (baudRate == 125000 || baudRate == 625000 || baudRate == 10000) {
+				clk_sel_val = 0x01;
+			} else if (baudRate == 153600 || baudRate == 225000 || baudRate == 403200 ||
+					baudRate == 2000000 || baudRate == 6000000) {
+				clk_sel_val = 0x02;
+			} else {
+				clk_sel_val = 0x05; // externel clk for custom case.
+			}
+
+			// needs to set clock source through
+			// Clk_Select_Reg1(offset 0x13) & Clk_Select_Reg2(offset 0x14)
+			// Clk_Select_Reg1 for port1,2		Clk_Select_Reg2 for port3,4
+			if (mos7840_port->port_num <= 2) {
+				status = mos7840_get_reg_sync(port, CLOCK_SELECT_REG1, &Data);
+				if (status < 0) {
+					dev_dbg(&port->dev, "reading Clk_Select_Reg failed in set_serial_baud\n");
+					return -1;
+				}
+				if (mos7840_port->port_num == 1) {
+					Data = (Data & 0xf8) | clk_sel_val;
+					status =
+						mos7840_set_reg_sync(port, CLOCK_SELECT_REG1, Data);
+				} else if (mos7840_port->port_num == 2) {
+					Data = (Data & 0xc7) | (clk_sel_val<<3);
+					status =
+						mos7840_set_reg_sync(port, CLOCK_SELECT_REG1, Data);
+				}
+				if (status < 0) {
+					dev_dbg(&port->dev, "setting Clk_Select_Reg failed\n");
+					return -1;
+				}
+			} else if (mos7840_port->port_num <= 4) {
+				status = mos7840_get_reg_sync(port, CLOCK_SELECT_REG2, &Data);
+				if (status < 0) {
+					dev_dbg(&port->dev, "reading Clk_Select_Reg failed in set_serial_baud\n");
+					return -1;
+				}
+				if (mos7840_port->port_num == 3) {
+					Data = (Data & 0xf8) | clk_sel_val;
+					status =
+						mos7840_set_reg_sync(port, CLOCK_SELECT_REG2, Data);
+				} else if (mos7840_port->port_num == 4) {
+					Data = (Data & 0xc7) | (clk_sel_val<<3);
+					status =
+						mos7840_set_reg_sync(port, CLOCK_SELECT_REG2, Data);
+				}
+				if (status < 0) {
+					dev_dbg(&port->dev, "setting Clk_Select_Reg failed\n");
+					return -1;
+				}
+			}
+		} else {
+		// clk_sel_val is not DUMMY value -> Write the corresponding value to SP_Reg
+
+			/* First, needs to write default value to
+			 * Clk_Select_Reg1(offset 0x13) & Clk_Select_Reg2(offset 0x14)
+			 * Clk_Select_Reg1 for port1,2		Clk_Select_Reg2 for port3,4
+			 */
+			if (mos7840_port->port_num <= 2) {
+				status = mos7840_get_reg_sync(port, CLOCK_SELECT_REG1, &Data);
+				if (status < 0) {
+					dev_dbg(&port->dev, "reading Clk_Select_Reg failed in set_serial_baud\n");
+					return -1;
+				}
+				if (mos7840_port->port_num == 1) {
+					Data = (Data & 0xf8) | 0x00;
+					status =
+						mos7840_set_reg_sync(port, CLOCK_SELECT_REG1, Data);
+				} else if (mos7840_port->port_num == 2) {
+					Data = (Data & 0xc7) | (0x00<<3);
+					status =
+						mos7840_set_reg_sync(port, CLOCK_SELECT_REG1, Data);
+				}
+				if (status < 0) {
+					dev_dbg(&port->dev, "setting Clk_Select_Reg failed\n");
+					return -1;
+				}
+			} else if (mos7840_port->port_num <= 4) {
+				status = mos7840_get_reg_sync(port, CLOCK_SELECT_REG2, &Data);
+				if (status < 0) {
+					dev_dbg(&port->dev, "reading Clk_Select_Reg failed in set_serial_baud\n");
+					return -1;
+				}
+				if (mos7840_port->port_num == 3) {
+					Data = (Data & 0xf8) | 0x00;
+					status =
+						mos7840_set_reg_sync(port, CLOCK_SELECT_REG2, Data);
+				} else if (mos7840_port->port_num == 4) {
+					Data = (Data & 0xc7) | (0x00<<3);
+					status =
+						mos7840_set_reg_sync(port, CLOCK_SELECT_REG2, Data);
+				}
+				if (status < 0) {
+					dev_dbg(&port->dev, "setting Clk_Select_Reg failed\n");
+					return -1;
+				}
+			}
+			// select clock source by writing clk_sel_val to SPx_Reg
+			status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
+									 &Data);
+			if (status < 0) {
+				dev_dbg(&port->dev, "reading spreg failed in set_serial_baud\n");
+				return -1;
+			}
+			Data = (Data & 0x8f) | clk_sel_val;
+			status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset,
+									Data);
+			if (status < 0) {
+				dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n");
+				return -1;
+			}
+		}
+
 		status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
 								 &Data);
 		if (status < 0) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support
  2024-10-24 10:08 [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support Tony Chung
                   ` (2 preceding siblings ...)
  2024-10-24 10:09 ` [PATCH 3/3] driver: usb: serial: mos7840: add more baudrate options Tony Chung
@ 2025-02-11  9:41 ` Johan Hovold
  3 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2025-02-11  9:41 UTC (permalink / raw)
  To: Tony Chung; +Cc: gregkh, linux-kernel, linux-usb

On Thu, Oct 24, 2024 at 06:08:59PM +0800, Tony Chung wrote:
> This patch set has made some improvements for baud rate setup:
> 1. Optimized register configurations for common baud rates.
> 2. Added clock select registers to choose between 96M, 30M, or external clock sources,
>    allowing baud rate setup to 6M, matching the hardware's maximum data rate.
> 
> Tony Chung (3):
>   drivers: usb: serial: mos7840: Add defines for clock select register
>     offset
>   drivers: usb: serial: mos7840: added optimized register setups for
>     common baudrates.
>   driver: usb: serial: mos7840: add more baudrate options

Thanks for these. As for the clean up series, use the established
patch prefix here too:

	USB: serial: mos7840: ...

Johan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] drivers: usb: serial: mos7840: Add defines for clock select register offset
  2024-10-24 10:09 ` [PATCH 1/3] drivers: usb: serial: mos7840: Add defines for clock select register offset Tony Chung
@ 2025-02-11  9:44   ` Johan Hovold
  0 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2025-02-11  9:44 UTC (permalink / raw)
  To: Tony Chung; +Cc: gregkh, linux-kernel, linux-usb

On Thu, Oct 24, 2024 at 06:09:01PM +0800, Tony Chung wrote:
> This patch adds define for CLOCK_SELECT_REG1 & CLOCK_SELECT_REG2 offsets.
> These two registers can select clock source between 30M/96M/External.

I think should just add these as part of the patch that uses them. If
you have some information on how they are used, that would be useful to
have in the commit message and possibly also in a comment above the
defines.

Where did you learn about these settings?

Johan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] drivers: usb: serial: mos7840: added optimized register setups for common baudrates.
  2024-10-24 10:09 ` [PATCH 2/3] drivers: usb: serial: mos7840: added optimized register setups for common baudrates Tony Chung
@ 2025-02-11 10:16   ` Johan Hovold
  0 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2025-02-11 10:16 UTC (permalink / raw)
  To: Tony Chung; +Cc: gregkh, linux-kernel, linux-usb

On Thu, Oct 24, 2024 at 06:09:03PM +0800, Tony Chung wrote:
> added optimized register setups for common baudrates.

First, how did you determine the base clocks here? Do you have access to
some documentation or did you just measure them?

These are all derived from the internal PLL IIUC?

> Signed-off-by: Tony Chung <tony467913@gmail.com>
> ---
>  drivers/usb/serial/mos7840.c | 114 ++++++++++++++++++++++++++++++++++-
>  1 file changed, 111 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
> index 362875a53..acc16737b 100644
> --- a/drivers/usb/serial/mos7840.c
> +++ b/drivers/usb/serial/mos7840.c
> @@ -1063,11 +1063,116 @@ static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port,
>  {
>  	dev_dbg(&port->dev, "%s - %d\n", __func__, baudRate);
>  
> -	if (baudRate <= 115200) {
> +	// divisor = (256*DLM)+DLL
> +	// baudrate = InputCLK/(16*Divisor)

Style nit: Please avoid using c99 comments (here and below), just use a
block comment here and add spaces around the operators.

> +	if (baudRate == 50) {
> +		*divisor = (256*0x09)+0x04; // DLM=0x09, DLL=0x04
> +		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
> +	} else if (baudRate == 75) {
> +		*divisor = (256*0x06)+0x02; // DLM=0x06, DLL=0x02
> +		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
> +	} else if (baudRate == 110) {
> +		*divisor = (256*0x04)+0x19; // DLM=0x04, DLL=0x19
> +		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
> +	} else if (baudRate == 134) {
> +		*divisor = (256*0x03)+0x5d; // DLM=0x03, DLL=0x5d
> +		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
> +	} else if (baudRate == 150) {
> +		*divisor = (256*0x03)+0x01; // DLM=0x03, DLL=0x01
> +		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
> +	} else if (baudRate == 300) {
> +		*divisor = (256*0x01)+0x81; // DLM=0x01, DLL=0x81
> +		*clk_sel_val = 0x0;	    // clock source = 1.846153846M
> +	} else if (baudRate == 600) {
> +		*divisor = 0xc0;		// DLM=0, DLL=0xc0
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 1200) {
> +		*divisor = 0x60;		// DLM=0, DLL=0x60
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 1800) {
> +		*divisor = 0x40;		// DLM=0, DLL=0x40
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 2400) {
> +		*divisor = 0x30;		// DLM=0, DLL=0x30
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 4800) {
> +		*divisor = 0x18;		// DLM=0, DLL=0x18
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 7200) {
> +		*divisor = 0x10;		// DLM=0, DLL=0x10
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 9600) {
> +		*divisor = 0x0c;		// DLM=0, DLL=0x0c
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 14400) {
> +		*divisor = 0x08;		// DLM=0, DLL=0x08
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 19200) {
> +		*divisor = 0x06;		// DLM=0, DLL=0x06
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 28800) {
> +		*divisor = 0x04;		// DLM=0, DLL=0x04
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 38400) {
> +		*divisor = 0x03;		// DLM=0, DLL=0x03
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 57600) {
> +		*divisor = 0x02;		// DLM=0, DLL=0x02
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 115200) {
> +		*divisor = 0x01;		// DLM=0, DLL=0x01
> +		*clk_sel_val = 0x0;		// clock source = 1.846153846M
> +	} else if (baudRate == 230400) {
> +		*divisor = 0x01;		// DLM=0, DLL=0x01
> +		*clk_sel_val = 0x10;	// clock source = 3.692307692M
> +	} else if (baudRate == 460800) {
> +		*divisor = 0x01;		// DLM=0, DLL=0x01
> +		*clk_sel_val = 0x30;	// clock source = 7.384615384M
> +	} else if (baudRate == 806400) {
> +		*divisor = 0x01;		// DLM=0, DLL=0x01
> +		*clk_sel_val = 0x40;	// clock source = 12.923076922M
> +	} else if (baudRate == 921600) {
> +		*divisor = 0x01;		// DLM=0, DLL=0x01
> +		*clk_sel_val = 0x50;	// clock source = 14.769230768M
> +	} else if (baudRate == 25000) {
> +		*divisor = 0x78;		// DLM=0, DLL=0x78
> +		*clk_sel_val = 0x70;	// clock source=48M
> +	} else if (baudRate == 50000) {
> +		*divisor = 0x3c;		// DLM=0, DLL=0x3c
> +		*clk_sel_val = 0x70;	// clock source=48M
> +	} else if (baudRate == 75000) {
> +		*divisor = 0x28;		// DLM=0, DLL=0x28
> +		*clk_sel_val = 0x70;	// clock source=48M
> +	} else if (baudRate == 100000) {
> +		*divisor = 0x1e;		// DLM=0, DLL=0x1e
> +		*clk_sel_val = 0x70;	// clock source=48M
> +	} else if (baudRate == 250000) {
> +		*divisor = 0x0c;		// DLM=0, DLL=0x0c
> +		*clk_sel_val = 0x70;	// clock source=48M
> +	} else if (baudRate == 300000) {
> +		*divisor = 0x0a;		// DLM=0, DLL=0x0a
> +		*clk_sel_val = 0x70;	// clock source=48M
> +	} else if (baudRate == 500000) {
> +		*divisor = 0x06;		// DLM=0, DLL=0x06
> +		*clk_sel_val = 0x70;	// clock source=48M
> +	} else if (baudRate == 600000) {
> +		*divisor = 0x05;		// DLM=0, DLL=0x05
> +		*clk_sel_val = 0x70;	// clock source=48M
> +	} else if (baudRate == 1000000) {
> +		*divisor = 0x03;		// DLM=0, DLL=0x03
> +		*clk_sel_val = 0x70;	// clock source=48M
> +	} else if (baudRate == 3000000) {
> +		*divisor = 0x01;		// DLM=0, DLL=0x01
> +		*clk_sel_val = 0x70;	// clock source=48M
> +
> +	} else if (baudRate == 1500000) {
> +		*divisor = 0x01;		// DLM=0, DLL=0x01
> +		*clk_sel_val = 0x60;	// clock source=24M
> +

You should be able to determine at least most of the above by just
calculating the divisors from the base clocks. Perhaps you need a lookup
table as well to determine which base to use in some cases too.

Note sure we need to add non-standard rates like 25000 etc either.

> +	} else if (baudRate <= 115200) {
>  		*divisor = 115200 / baudRate;
>  		*clk_sel_val = 0x0;
> -	}
> -	if ((baudRate > 115200) && (baudRate <= 230400)) {
> +	} else if ((baudRate > 115200) && (baudRate <= 230400)) {
>  		*divisor = 230400 / baudRate;
>  		*clk_sel_val = 0x10;
>  	} else if ((baudRate > 230400) && (baudRate <= 403200)) {
> @@ -1088,6 +1193,9 @@ static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port,
>  	} else if ((baudRate > 1572864) && (baudRate <= 3145728)) {
>  		*divisor = 3145728 / baudRate;
>  		*clk_sel_val = 0x70;
> +	} else {
> +		dev_dbg(&port->dev, "func: %s -baudrate %d not supported.\n", __func__, baudRate);

Here you could drop "func: %s -" and the period, if you need this at
all.

> +		return -1;

The calling code does not check for errors, so either fix that or,
better still, make sure the function always returns a valid divisor
(e.g. by making sure the input rate is always valid).

>  	}
>  	return 0;
>  }

Johan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] driver: usb: serial: mos7840: add more baudrate options
  2024-10-24 10:09 ` [PATCH 3/3] driver: usb: serial: mos7840: add more baudrate options Tony Chung
@ 2025-02-11 13:08   ` Johan Hovold
  0 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2025-02-11 13:08 UTC (permalink / raw)
  To: Tony Chung; +Cc: gregkh, linux-kernel, linux-usb

On Thu, Oct 24, 2024 at 06:09:05PM +0800, Tony Chung wrote:
> Adds more baud rate options using 96M/30M/External clock sources.
> To use these clock sources,
> set through Clk_Select_Reg1 and Clk_Select_Reg2.
> 
> Signed-off-by: Tony Chung <tony467913@gmail.com>
> ---
>  drivers/usb/serial/mos7840.c | 156 ++++++++++++++++++++++++++++++++++-
>  1 file changed, 155 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
> index acc16737b..70ee4a638 100644
> --- a/drivers/usb/serial/mos7840.c
> +++ b/drivers/usb/serial/mos7840.c
> @@ -1169,6 +1169,37 @@ static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port,
>  		*divisor = 0x01;		// DLM=0, DLL=0x01
>  		*clk_sel_val = 0x60;	// clock source=24M
>  
> +	/* below are using 96M or 30M clock source
> +	 * will determine the clock source later
> +	 * in function mos7840_send_cmd_write_baud_rate
> +	 */

Block comment style, also try to follow style of driver and capitalise
"Below".

That said, this one should not be needed after you add proper
abstractions for this. For example, instead of returning a raw
clk_sel_val you return an enum which you handle in the caller.

> +	} else if (baudRate == 6000000) {
> +		*divisor = 0x01;		// DLM=0, DLL=0x01
> +		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M
> +	} else if (baudRate == 2000000) {
> +		*divisor = 0x03;		// DLM=0, DLL=0x03
> +		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M

The above looks useful.

> +	} else if (baudRate == 403200) {
> +		*divisor = 0x0f;		// DLM=0, DLL=0x0f
> +		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M
> +	} else if (baudRate == 225000) {
> +		*divisor = 0x1b;		// DLM=0, DLL=0x1b
> +		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M
> +	} else if (baudRate == 153600) {
> +		*divisor = 0x27;		// DLM=0, DLL=0x27
> +		*clk_sel_val = 0x80;	// DUMMY val, clock source = 96M

But why would anyone use these?

> +	} else if (baudRate == 10000) {
> +		*divisor = 0xbb;		// DLM=0, DLL=0xbb
> +		*clk_sel_val = 0x80;	// DUMMY val, clock source = 30M
> +	} else if (baudRate == 125000) {
> +		*divisor = 0x0f;		// DLM=0, DLL=0x0f
> +		*clk_sel_val = 0x80;	// DUMMY val, clock source = 30M
> +	} else if (baudRate == 625000) {
> +		*divisor = 0x03;		// DLM=0, DLL=0x03
> +		*clk_sel_val = 0x80;	// DUMMY val, clock source = 30M

Or these?

In any case, these would probably also need to go in a lookup table.

> +
> +
>  	} else if (baudRate <= 115200) {
>  		*divisor = 115200 / baudRate;
>  		*clk_sel_val = 0x0;
> @@ -1246,11 +1277,134 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
>  
>  	}
>  
> -	if (1) {		/* baudRate <= 115200) */
> +	if (1) {

Probably a good time to get rid of this in a preparatory patch to reduce
the indentation.

>  		clk_sel_val = 0x0;
>  		Data = 0x0;
>  		status = mos7840_calc_baud_rate_divisor(port, baudRate, &divisor,
>  						   &clk_sel_val);
> +		if (status < 0) {
> +			dev_dbg(&port->dev, "%s failed in set_serial_baud\n", __func__);
> +			return -1;
> +		}

Ok, here you add the error handling. But as I mentioned it's better to
fix the caller so that it does not pass in a speed that too high for the
driver. Just keep the old rate and update the termios to reflect that
that requested rate was rejected.

> +
> +		/* Write clk_sel_val to SP_Reg or Clk_Select_Reg*/

Space before */

> +		// check clk_sel_val before setting the clk_sel_val

No c99 comments, please.

> +		if (clk_sel_val == 0x80) {
> +		// clk_sel_val is DUMMY value -> Write the corresponding value to Clk_Select_Reg

Odd indentation.

> +			// 0x01:30M, 0x02:96M, 0x05:External Clock

Ok, so here's the comment I asked for earlier. That should probably go
above the clock register defines, and/or with defines for these
constants added as well.

> +			if (baudRate == 125000 || baudRate == 625000 || baudRate == 10000) {
> +				clk_sel_val = 0x01;
> +			} else if (baudRate == 153600 || baudRate == 225000 || baudRate == 403200 ||
> +					baudRate == 2000000 || baudRate == 6000000) {
> +				clk_sel_val = 0x02;
> +			} else {
> +				clk_sel_val = 0x05; // externel clk for custom case.
> +			}

This needs to be cleaned up using a lookup table and a clk_sel enum.

If there are product that would benefit from using the external clock
input, this would need to be handled on a per-device basis so that we
know its frequency.

> +			// needs to set clock source through
> +			// Clk_Select_Reg1(offset 0x13) & Clk_Select_Reg2(offset 0x14)
> +			// Clk_Select_Reg1 for port1,2		Clk_Select_Reg2 for port3,4
> +			if (mos7840_port->port_num <= 2) {
> +				status = mos7840_get_reg_sync(port, CLOCK_SELECT_REG1, &Data);
> +				if (status < 0) {
> +					dev_dbg(&port->dev, "reading Clk_Select_Reg failed in set_serial_baud\n");

Looks like the driver is currently using dev_dbg() for errors, but this
should most likely be dev_err() throughout. No need to say in which
function it fails, just 
	
	failed to read clock select register: %d\n

or similar should do.

> +					return -1;
> +				}
> +				if (mos7840_port->port_num == 1) {
> +					Data = (Data & 0xf8) | clk_sel_val;
> +					status =
> +						mos7840_set_reg_sync(port, CLOCK_SELECT_REG1, Data);
> +				} else if (mos7840_port->port_num == 2) {
> +					Data = (Data & 0xc7) | (clk_sel_val<<3);

Spaces around binary operator throughout.

> +					status =
> +						mos7840_set_reg_sync(port, CLOCK_SELECT_REG1, Data);
> +				}
> +				if (status < 0) {
> +					dev_dbg(&port->dev, "setting Clk_Select_Reg failed\n");
> +					return -1;
> +				}
> +			} else if (mos7840_port->port_num <= 4) {
> +				status = mos7840_get_reg_sync(port, CLOCK_SELECT_REG2, &Data);
> +				if (status < 0) {
> +					dev_dbg(&port->dev, "reading Clk_Select_Reg failed in set_serial_baud\n");
> +					return -1;
> +				}
> +				if (mos7840_port->port_num == 3) {
> +					Data = (Data & 0xf8) | clk_sel_val;
> +					status =
> +						mos7840_set_reg_sync(port, CLOCK_SELECT_REG2, Data);
> +				} else if (mos7840_port->port_num == 4) {
> +					Data = (Data & 0xc7) | (clk_sel_val<<3);
> +					status =
> +						mos7840_set_reg_sync(port, CLOCK_SELECT_REG2, Data);
> +				}
> +				if (status < 0) {
> +					dev_dbg(&port->dev, "setting Clk_Select_Reg failed\n");
> +					return -1;
> +				}
> +			}

The above needs to be cleaned up and abstracted better too. It's hardly
readable currently and the patterns looks too similar to be repeated
like this (i.e. a helper function may be the right choice).

> +		} else {
> +		// clk_sel_val is not DUMMY value -> Write the corresponding value to SP_Reg
> +
> +			/* First, needs to write default value to
> +			 * Clk_Select_Reg1(offset 0x13) & Clk_Select_Reg2(offset 0x14)
> +			 * Clk_Select_Reg1 for port1,2		Clk_Select_Reg2 for port3,4
> +			 */
> +			if (mos7840_port->port_num <= 2) {
> +				status = mos7840_get_reg_sync(port, CLOCK_SELECT_REG1, &Data);
> +				if (status < 0) {
> +					dev_dbg(&port->dev, "reading Clk_Select_Reg failed in set_serial_baud\n");
> +					return -1;
> +				}
> +				if (mos7840_port->port_num == 1) {
> +					Data = (Data & 0xf8) | 0x00;
> +					status =
> +						mos7840_set_reg_sync(port, CLOCK_SELECT_REG1, Data);
> +				} else if (mos7840_port->port_num == 2) {
> +					Data = (Data & 0xc7) | (0x00<<3);
> +					status =
> +						mos7840_set_reg_sync(port, CLOCK_SELECT_REG1, Data);
> +				}
> +				if (status < 0) {
> +					dev_dbg(&port->dev, "setting Clk_Select_Reg failed\n");
> +					return -1;
> +				}
> +			} else if (mos7840_port->port_num <= 4) {
> +				status = mos7840_get_reg_sync(port, CLOCK_SELECT_REG2, &Data);
> +				if (status < 0) {
> +					dev_dbg(&port->dev, "reading Clk_Select_Reg failed in set_serial_baud\n");
> +					return -1;
> +				}
> +				if (mos7840_port->port_num == 3) {
> +					Data = (Data & 0xf8) | 0x00;
> +					status =
> +						mos7840_set_reg_sync(port, CLOCK_SELECT_REG2, Data);
> +				} else if (mos7840_port->port_num == 4) {
> +					Data = (Data & 0xc7) | (0x00<<3);
> +					status =
> +						mos7840_set_reg_sync(port, CLOCK_SELECT_REG2, Data);
> +				}
> +				if (status < 0) {
> +					dev_dbg(&port->dev, "setting Clk_Select_Reg failed\n");
> +					return -1;
> +				}
> +			}

This is the same code as above, just writing the default value. This
obviously needs to be refactored.

> +			// select clock source by writing clk_sel_val to SPx_Reg
> +			status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
> +									 &Data);
> +			if (status < 0) {
> +				dev_dbg(&port->dev, "reading spreg failed in set_serial_baud\n");
> +				return -1;
> +			}
> +			Data = (Data & 0x8f) | clk_sel_val;
> +			status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset,
> +									Data);
> +			if (status < 0) {
> +				dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n");
> +				return -1;
> +			}
> +		}

Johan

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-02-11 13:08 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-24 10:08 [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support Tony Chung
2024-10-24 10:09 ` [PATCH 1/3] drivers: usb: serial: mos7840: Add defines for clock select register offset Tony Chung
2025-02-11  9:44   ` Johan Hovold
2024-10-24 10:09 ` [PATCH 2/3] drivers: usb: serial: mos7840: added optimized register setups for common baudrates Tony Chung
2025-02-11 10:16   ` Johan Hovold
2024-10-24 10:09 ` [PATCH 3/3] driver: usb: serial: mos7840: add more baudrate options Tony Chung
2025-02-11 13:08   ` Johan Hovold
2025-02-11  9:41 ` [PATCH 0/3] drivers: usb: serial: mos7840: Improved baud rate support Johan Hovold

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox