Skip to content

Commit 3aacac0

Browse files
hpeterjhovold
authored andcommitted
USB: serial: f81534: add high baud rate support
The F81532/534 had 4 clocksource 1.846/18.46/14.77/24MHz and baud rates can be up to 1.5Mbits with 24MHz. This device may generate data overrun when baud rate setting to 921600bps or higher with old UART trigger level setting (8x14=112) with full loading. We'll change trigger level from 8x14=112 to 8x8=64 to avoid data overrun. Also the read/write of EP0 will be affected by this patch. The worst case of responding time is 20s when all serial port are full loading and trying to access EP0, so we change EP0 timeout from 10 to 20s. F81532/534 Clock register (offset +08h) Bit0: UART Enable (always on) Bit2-1: 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> [ johan: only use GENMASK() for masks ] Signed-off-by: Johan Hovold <johan@kernel.org>
1 parent e255f20 commit 3aacac0

File tree

1 file changed

+77
-16
lines changed

1 file changed

+77
-16
lines changed

drivers/usb/serial/f81534.c

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#define F81534_MODEM_CONTROL_REG (0x04 + F81534_UART_BASE_ADDRESS)
4242
#define F81534_LINE_STATUS_REG (0x05 + F81534_UART_BASE_ADDRESS)
4343
#define F81534_MODEM_STATUS_REG (0x06 + F81534_UART_BASE_ADDRESS)
44+
#define F81534_CLOCK_REG (0x08 + F81534_UART_BASE_ADDRESS)
4445
#define F81534_CONFIG1_REG (0x09 + F81534_UART_BASE_ADDRESS)
4546

4647
#define F81534_DEF_CONF_ADDRESS_START 0x3000
@@ -57,7 +58,7 @@
5758

5859
/* Default URB timeout for USB operations */
5960
#define F81534_USB_MAX_RETRY 10
60-
#define F81534_USB_TIMEOUT 1000
61+
#define F81534_USB_TIMEOUT 2000
6162
#define F81534_SET_GET_REGISTER 0xA0
6263

6364
#define F81534_NUM_PORT 4
@@ -96,7 +97,6 @@
9697
#define F81534_CMD_READ 0x03
9798

9899
#define F81534_DEFAULT_BAUD_RATE 9600
99-
#define F81534_MAX_BAUDRATE 115200
100100

101101
#define F81534_PORT_CONF_DISABLE_PORT BIT(3)
102102
#define F81534_PORT_CONF_NOT_EXIST_PORT BIT(7)
@@ -106,6 +106,24 @@
106106
#define F81534_1X_RXTRIGGER 0xc3
107107
#define F81534_8X_RXTRIGGER 0xcf
108108

109+
/*
110+
* F81532/534 Clock registers (offset +08h)
111+
*
112+
* Bit0: UART Enable (always on)
113+
* Bit2-1: Clock source selector
114+
* 00: 1.846MHz.
115+
* 01: 18.46MHz.
116+
* 10: 24MHz.
117+
* 11: 14.77MHz.
118+
*/
119+
120+
#define F81534_UART_EN BIT(0)
121+
#define F81534_CLK_1_846_MHZ 0
122+
#define F81534_CLK_18_46_MHZ BIT(1)
123+
#define F81534_CLK_24_MHZ BIT(2)
124+
#define F81534_CLK_14_77_MHZ (BIT(1) | BIT(2))
125+
#define F81534_CLK_MASK GENMASK(2, 1)
126+
109127
static const struct usb_device_id f81534_id_table[] = {
110128
{ USB_DEVICE(FINTEK_VENDOR_ID_1, FINTEK_DEVICE_ID) },
111129
{ USB_DEVICE(FINTEK_VENDOR_ID_2, FINTEK_DEVICE_ID) },
@@ -129,12 +147,18 @@ struct f81534_port_private {
129147
struct usb_serial_port *port;
130148
unsigned long tx_empty;
131149
spinlock_t msr_lock;
150+
u32 baud_base;
132151
u8 shadow_mcr;
133152
u8 shadow_lcr;
134153
u8 shadow_msr;
154+
u8 shadow_clk;
135155
u8 phy_num;
136156
};
137157

158+
static u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 };
159+
static u8 const clock_table[] = { F81534_CLK_1_846_MHZ, F81534_CLK_14_77_MHZ,
160+
F81534_CLK_18_46_MHZ, F81534_CLK_24_MHZ };
161+
138162
static int f81534_logic_to_phy_port(struct usb_serial *serial,
139163
struct usb_serial_port *port)
140164
{
@@ -460,13 +484,52 @@ static u32 f81534_calc_baud_divisor(u32 baudrate, u32 clockrate)
460484
return DIV_ROUND_CLOSEST(clockrate, baudrate);
461485
}
462486

463-
static int f81534_set_port_config(struct usb_serial_port *port, u32 baudrate,
464-
u8 lcr)
487+
static int f81534_find_clk(u32 baudrate)
488+
{
489+
int idx;
490+
491+
for (idx = 0; idx < ARRAY_SIZE(baudrate_table); ++idx) {
492+
if (baudrate <= baudrate_table[idx] &&
493+
baudrate_table[idx] % baudrate == 0)
494+
return idx;
495+
}
496+
497+
return -EINVAL;
498+
}
499+
500+
static int f81534_set_port_config(struct usb_serial_port *port,
501+
struct tty_struct *tty, u32 baudrate, u32 old_baudrate, u8 lcr)
465502
{
466503
struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
467504
u32 divisor;
468505
int status;
506+
int i;
507+
int idx;
469508
u8 value;
509+
u32 baud_list[] = {baudrate, old_baudrate, F81534_DEFAULT_BAUD_RATE};
510+
511+
for (i = 0; i < ARRAY_SIZE(baud_list); ++i) {
512+
idx = f81534_find_clk(baud_list[i]);
513+
if (idx >= 0) {
514+
baudrate = baud_list[i];
515+
tty_encode_baud_rate(tty, baudrate, baudrate);
516+
break;
517+
}
518+
}
519+
520+
if (idx < 0)
521+
return -EINVAL;
522+
523+
port_priv->baud_base = baudrate_table[idx];
524+
port_priv->shadow_clk &= ~F81534_CLK_MASK;
525+
port_priv->shadow_clk |= clock_table[idx];
526+
527+
status = f81534_set_port_register(port, F81534_CLOCK_REG,
528+
port_priv->shadow_clk);
529+
if (status) {
530+
dev_err(&port->dev, "CLOCK_REG setting failed\n");
531+
return status;
532+
}
470533

471534
if (baudrate <= 1200)
472535
value = F81534_1X_RXTRIGGER; /* 128 FIFO & TL: 1x */
@@ -482,7 +545,7 @@ static int f81534_set_port_config(struct usb_serial_port *port, u32 baudrate,
482545
if (baudrate <= 1200)
483546
value = UART_FCR_TRIGGER_1 | UART_FCR_ENABLE_FIFO; /* TL: 1 */
484547
else
485-
value = UART_FCR_R_TRIG_11 | UART_FCR_ENABLE_FIFO; /* TL: 14 */
548+
value = UART_FCR_TRIGGER_8 | UART_FCR_ENABLE_FIFO; /* TL: 8 */
486549

487550
status = f81534_set_port_register(port, F81534_FIFO_CONTROL_REG,
488551
value);
@@ -491,7 +554,7 @@ static int f81534_set_port_config(struct usb_serial_port *port, u32 baudrate,
491554
return status;
492555
}
493556

494-
divisor = f81534_calc_baud_divisor(baudrate, F81534_MAX_BAUDRATE);
557+
divisor = f81534_calc_baud_divisor(baudrate, port_priv->baud_base);
495558

496559
mutex_lock(&port_priv->lcr_mutex);
497560

@@ -741,6 +804,7 @@ static void f81534_set_termios(struct tty_struct *tty,
741804
u8 new_lcr = 0;
742805
int status;
743806
u32 baud;
807+
u32 old_baud;
744808

745809
if (C_BAUD(tty) == B0)
746810
f81534_update_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS);
@@ -780,18 +844,14 @@ static void f81534_set_termios(struct tty_struct *tty,
780844
if (!baud)
781845
return;
782846

783-
if (baud > F81534_MAX_BAUDRATE) {
784-
if (old_termios)
785-
baud = tty_termios_baud_rate(old_termios);
786-
else
787-
baud = F81534_DEFAULT_BAUD_RATE;
788-
789-
tty_encode_baud_rate(tty, baud, baud);
790-
}
847+
if (old_termios)
848+
old_baud = tty_termios_baud_rate(old_termios);
849+
else
850+
old_baud = F81534_DEFAULT_BAUD_RATE;
791851

792852
dev_dbg(&port->dev, "%s: baud: %d\n", __func__, baud);
793853

794-
status = f81534_set_port_config(port, baud, new_lcr);
854+
status = f81534_set_port_config(port, tty, baud, old_baud, new_lcr);
795855
if (status < 0) {
796856
dev_err(&port->dev, "%s: set port config failed: %d\n",
797857
__func__, status);
@@ -947,7 +1007,7 @@ static int f81534_get_serial_info(struct usb_serial_port *port,
9471007
tmp.type = PORT_16550A;
9481008
tmp.port = port->port_number;
9491009
tmp.line = port->minor;
950-
tmp.baud_base = F81534_MAX_BAUDRATE;
1010+
tmp.baud_base = port_priv->baud_base;
9511011

9521012
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
9531013
return -EFAULT;
@@ -1221,6 +1281,7 @@ static int f81534_port_probe(struct usb_serial_port *port)
12211281
if (!port_priv)
12221282
return -ENOMEM;
12231283

1284+
port_priv->shadow_clk = F81534_UART_EN;
12241285
spin_lock_init(&port_priv->msr_lock);
12251286
mutex_init(&port_priv->mcr_mutex);
12261287
mutex_init(&port_priv->lcr_mutex);

0 commit comments

Comments
 (0)