* [PATCH V3 2/6] usb: serial: f81534: add auto RTS direction support
2018-01-11 6:47 [PATCH V3 1/6] usb: serial: f81534: add high baud rate support Ji-Ze Hong (Peter Hong)
@ 2018-01-11 6:47 ` Ji-Ze Hong (Peter Hong)
2018-01-11 10:05 ` Johan Hovold
2018-01-11 6:47 ` [PATCH V3 3/6] usb: serial: f81534: add output pin control Ji-Ze Hong (Peter Hong)
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Ji-Ze Hong (Peter Hong) @ 2018-01-11 6:47 UTC (permalink / raw)
To: johan; +Cc: gregkh, linux-usb, linux-kernel, peter_hong,
Ji-Ze Hong (Peter Hong)
The F81532/534 had auto RTS direction support for RS485 mode.
We'll read it from internal Flash with address 0x2f01~0x2f04 for 4 ports.
There are 4 conditions below:
0: F81534_PORT_CONF_RS232.
1: F81534_PORT_CONF_RS485.
2: value error, default to F81534_PORT_CONF_RS232.
3: F81534_PORT_CONF_RS485_INVERT.
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.
Bit4: Auto direction(RTS) control (RTS pin Low when TX)
Bit5: Invert direction(RTS) when Bit4 enabled (RTS pin high when TX)
Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
---
V3:
1: change some BIT() operation to GENMASK().
2: change some dev_info() to dev_dbg().
V2:
1: Read the configure data from flash and save it to shadow clock
register.
drivers/usb/serial/f81534.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
index 1563d3f34381..2201be577dd3 100644
--- a/drivers/usb/serial/f81534.c
+++ b/drivers/usb/serial/f81534.c
@@ -98,11 +98,16 @@
#define F81534_DEFAULT_BAUD_RATE 9600
+#define F81534_PORT_CONF_RS232 0
+#define F81534_PORT_CONF_RS485 BIT(0)
+#define F81534_PORT_CONF_RS485_INVERT GENMASK(1, 0)
#define F81534_PORT_CONF_DISABLE_PORT BIT(3)
#define F81534_PORT_CONF_NOT_EXIST_PORT BIT(7)
#define F81534_PORT_UNAVAILABLE \
(F81534_PORT_CONF_DISABLE_PORT | F81534_PORT_CONF_NOT_EXIST_PORT)
+#define F81534_UART_MODE_MASK GENMASK(1, 0)
+
#define F81534_1X_RXTRIGGER 0xc3
#define F81534_8X_RXTRIGGER 0xcf
@@ -115,6 +120,8 @@
* 01: 18.46MHz.
* 10: 24MHz.
* 11: 14.77MHz.
+ * Bit4: Auto direction(RTS) control (RTS pin Low when TX)
+ * Bit5: Invert direction(RTS) when Bit4 enabled (RTS pin high when TX)
*/
#define F81534_UART_EN BIT(0)
@@ -123,6 +130,8 @@
#define F81534_CLK_24_MHZ BIT(2)
#define F81534_CLK_14_77_MHZ GENMASK(2, 1)
#define F81534_CLK_MASK GENMASK(2, 1)
+#define F81534_CLK_RS485_MODE BIT(4)
+#define F81534_CLK_RS485_INVERT BIT(5)
static const struct usb_device_id f81534_id_table[] = {
{ USB_DEVICE(FINTEK_VENDOR_ID_1, FINTEK_DEVICE_ID) },
@@ -1274,9 +1283,12 @@ static void f81534_lsr_worker(struct work_struct *work)
static int f81534_port_probe(struct usb_serial_port *port)
{
+ struct f81534_serial_private *serial_priv;
struct f81534_port_private *port_priv;
int ret;
+ u8 value;
+ serial_priv = usb_get_serial_data(port->serial);
port_priv = devm_kzalloc(&port->dev, sizeof(*port_priv), GFP_KERNEL);
if (!port_priv)
return -ENOMEM;
@@ -1309,6 +1321,24 @@ static int f81534_port_probe(struct usb_serial_port *port)
if (ret)
return ret;
+ value = serial_priv->conf_data[port_priv->phy_num];
+ switch (value & F81534_UART_MODE_MASK) {
+ case F81534_PORT_CONF_RS485_INVERT:
+ port_priv->shadow_clk |= F81534_CLK_RS485_MODE |
+ F81534_CLK_RS485_INVERT;
+ dev_dbg(&port->dev, "RS485 invert mode.\n");
+ break;
+ case F81534_PORT_CONF_RS485:
+ port_priv->shadow_clk |= F81534_CLK_RS485_MODE;
+ dev_dbg(&port->dev, "RS485 mode.\n");
+ break;
+
+ default:
+ case F81534_PORT_CONF_RS232:
+ dev_dbg(&port->dev, "RS232 mode.\n");
+ break;
+ }
+
return 0;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH V3 2/6] usb: serial: f81534: add auto RTS direction support
2018-01-11 6:47 ` [PATCH V3 2/6] usb: serial: f81534: add auto RTS direction support Ji-Ze Hong (Peter Hong)
@ 2018-01-11 10:05 ` Johan Hovold
0 siblings, 0 replies; 7+ messages in thread
From: Johan Hovold @ 2018-01-11 10:05 UTC (permalink / raw)
To: Ji-Ze Hong (Peter Hong)
Cc: johan, gregkh, linux-usb, linux-kernel, peter_hong,
Ji-Ze Hong (Peter Hong)
On Thu, Jan 11, 2018 at 02:47:16PM +0800, Ji-Ze Hong (Peter Hong) wrote:
> The F81532/534 had auto RTS direction support for RS485 mode.
> We'll read it from internal Flash with address 0x2f01~0x2f04 for 4 ports.
> There are 4 conditions below:
> 0: F81534_PORT_CONF_RS232.
> 1: F81534_PORT_CONF_RS485.
> 2: value error, default to F81534_PORT_CONF_RS232.
> 3: F81534_PORT_CONF_RS485_INVERT.
>
> 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.
> Bit4: Auto direction(RTS) control (RTS pin Low when TX)
> Bit5: Invert direction(RTS) when Bit4 enabled (RTS pin high when TX)
>
> Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
> ---
> V3:
> 1: change some BIT() operation to GENMASK().
> 2: change some dev_info() to dev_dbg().
>
> V2:
> 1: Read the configure data from flash and save it to shadow clock
> register.
Series now applied with a few minor tweaks.
> +#define F81534_PORT_CONF_RS232 0
> +#define F81534_PORT_CONF_RS485 BIT(0)
> +#define F81534_PORT_CONF_RS485_INVERT GENMASK(1, 0)
I replaced GENMASK() with your original (BIT(x) | BIT(y)) for register
values like this one.
> #define F81534_PORT_CONF_DISABLE_PORT BIT(3)
> #define F81534_PORT_CONF_NOT_EXIST_PORT BIT(7)
> #define F81534_PORT_UNAVAILABLE \
> (F81534_PORT_CONF_DISABLE_PORT | F81534_PORT_CONF_NOT_EXIST_PORT)
>
> +#define F81534_UART_MODE_MASK GENMASK(1, 0)
And renamed this mask to F81534_PORT_CONF_MODE_MASK so its more
obvious to what it applies.
Thanks,
Johan
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH V3 3/6] usb: serial: f81534: add output pin control
2018-01-11 6:47 [PATCH V3 1/6] usb: serial: f81534: add high baud rate support Ji-Ze Hong (Peter Hong)
2018-01-11 6:47 ` [PATCH V3 2/6] usb: serial: f81534: add auto RTS direction support Ji-Ze Hong (Peter Hong)
@ 2018-01-11 6:47 ` Ji-Ze Hong (Peter Hong)
2018-01-11 6:47 ` [PATCH V3 4/6] usb: serial: f81534: refactoring calc_num_ports() Ji-Ze Hong (Peter Hong)
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Ji-Ze Hong (Peter Hong) @ 2018-01-11 6:47 UTC (permalink / raw)
To: johan; +Cc: gregkh, linux-usb, linux-kernel, peter_hong,
Ji-Ze Hong (Peter Hong)
The F81532/534 had 3 output pin (M0/SD, M1, M2) with open-drain mode to
control transceiver. We'll read it from internal Flash with address
0x2f05~0x2f08 for 4 ports. The value is range from 0 to 7. The M0/SD is
MSB of this value. For a examples, If read value is 6, we'll write M0/SD,
M1, M2 as 1, 1, 0.
Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
---
V3:
1: change reg_mask type from u16 to u8.
2: change space around "{" & "}".
V2:
1: Fix for space between brace.
2: Remain the old pin control method.
drivers/usb/serial/f81534.c | 67 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 66 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
index 2201be577dd3..e7dd01310f20 100644
--- a/drivers/usb/serial/f81534.c
+++ b/drivers/usb/serial/f81534.c
@@ -52,6 +52,7 @@
#define F81534_CUSTOM_NO_CUSTOM_DATA 0xff
#define F81534_CUSTOM_VALID_TOKEN 0xf0
#define F81534_CONF_OFFSET 1
+#define F81534_CONF_GPIO_OFFSET 4
#define F81534_MAX_DATA_BLOCK 64
#define F81534_MAX_BUS_RETRY 20
@@ -164,6 +165,23 @@ struct f81534_port_private {
u8 phy_num;
};
+struct f81534_pin_data {
+ const u16 reg_addr;
+ const u8 reg_mask;
+};
+
+struct f81534_port_out_pin {
+ struct f81534_pin_data pin[3];
+};
+
+/* Pin output value for M2/M1/M0(SD) */
+static const struct f81534_port_out_pin f81534_port_out_pins[] = {
+ { { { 0x2ae8, BIT(7) }, { 0x2a90, BIT(5) }, { 0x2a90, BIT(4) } } },
+ { { { 0x2ae8, BIT(6) }, { 0x2ae8, BIT(0) }, { 0x2ae8, BIT(3) } } },
+ { { { 0x2a90, BIT(0) }, { 0x2ae8, BIT(2) }, { 0x2a80, BIT(6) } } },
+ { { { 0x2a90, BIT(3) }, { 0x2a90, BIT(2) }, { 0x2a90, BIT(1) } } },
+};
+
static u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 };
static u8 const clock_table[] = { F81534_CLK_1_846_MHZ, F81534_CLK_14_77_MHZ,
F81534_CLK_18_46_MHZ, F81534_CLK_24_MHZ };
@@ -273,6 +291,22 @@ static int f81534_get_register(struct usb_serial *serial, u16 reg, u8 *data)
return status;
}
+static int f81534_set_mask_register(struct usb_serial *serial, u16 reg,
+ u8 mask, u8 data)
+{
+ int status;
+ u8 tmp;
+
+ status = f81534_get_register(serial, reg, &tmp);
+ if (status)
+ return status;
+
+ tmp &= ~mask;
+ tmp |= (mask & data);
+
+ return f81534_set_register(serial, reg, tmp);
+}
+
static int f81534_set_port_register(struct usb_serial_port *port, u16 reg,
u8 data)
{
@@ -1281,6 +1315,37 @@ static void f81534_lsr_worker(struct work_struct *work)
dev_warn(&port->dev, "read LSR failed: %d\n", status);
}
+static int f81534_set_port_output_pin(struct usb_serial_port *port)
+{
+ struct f81534_serial_private *serial_priv;
+ struct f81534_port_private *port_priv;
+ struct usb_serial *serial;
+ const struct f81534_port_out_pin *pins;
+ int status;
+ int i;
+ u8 value;
+ u8 idx;
+
+ serial = port->serial;
+ serial_priv = usb_get_serial_data(serial);
+ port_priv = usb_get_serial_port_data(port);
+
+ idx = F81534_CONF_GPIO_OFFSET + port_priv->phy_num;
+ value = serial_priv->conf_data[idx];
+ pins = &f81534_port_out_pins[port_priv->phy_num];
+
+ for (i = 0; i < ARRAY_SIZE(pins->pin); ++i) {
+ status = f81534_set_mask_register(serial,
+ pins->pin[i].reg_addr, pins->pin[i].reg_mask,
+ value & BIT(i) ? pins->pin[i].reg_mask : 0);
+ if (status)
+ return status;
+ }
+
+ dev_dbg(&port->dev, "Output pin (M0/M1/M2): %d\n", value);
+ return 0;
+}
+
static int f81534_port_probe(struct usb_serial_port *port)
{
struct f81534_serial_private *serial_priv;
@@ -1339,7 +1404,7 @@ static int f81534_port_probe(struct usb_serial_port *port)
break;
}
- return 0;
+ return f81534_set_port_output_pin(port);
}
static int f81534_port_remove(struct usb_serial_port *port)
--
2.7.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH V3 4/6] usb: serial: f81534: refactoring calc_num_ports()
2018-01-11 6:47 [PATCH V3 1/6] usb: serial: f81534: add high baud rate support Ji-Ze Hong (Peter Hong)
2018-01-11 6:47 ` [PATCH V3 2/6] usb: serial: f81534: add auto RTS direction support Ji-Ze Hong (Peter Hong)
2018-01-11 6:47 ` [PATCH V3 3/6] usb: serial: f81534: add output pin control Ji-Ze Hong (Peter Hong)
@ 2018-01-11 6:47 ` Ji-Ze Hong (Peter Hong)
2018-01-11 6:47 ` [PATCH V3 5/6] usb: serial: f81534: add H/W disable port support Ji-Ze Hong (Peter Hong)
2018-01-11 6:47 ` [PATCH V3 6/6] usb: serial: f81534: fix tx error on some baud rate Ji-Ze Hong (Peter Hong)
4 siblings, 0 replies; 7+ messages in thread
From: Ji-Ze Hong (Peter Hong) @ 2018-01-11 6:47 UTC (permalink / raw)
To: johan; +Cc: gregkh, linux-usb, linux-kernel, peter_hong,
Ji-Ze Hong (Peter Hong)
In the original code, We'll read configuration in calc_num_ports()
and read again in attach(). In fact, we can move all content from
attach() to calc_num_ports() to simplify the code.
Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
---
V3:
1: First introduced in this series patches.
drivers/usb/serial/f81534.c | 116 ++++++++++++--------------------------------
1 file changed, 31 insertions(+), 85 deletions(-)
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
index e7dd01310f20..bc0a4bd5dcec 100644
--- a/drivers/usb/serial/f81534.c
+++ b/drivers/usb/serial/f81534.c
@@ -753,14 +753,14 @@ static int f81534_find_config_idx(struct usb_serial *serial, u8 *index)
static int f81534_calc_num_ports(struct usb_serial *serial,
struct usb_serial_endpoints *epds)
{
+ struct f81534_serial_private *serial_priv;
struct device *dev = &serial->interface->dev;
int size_bulk_in = usb_endpoint_maxp(epds->bulk_in[0]);
int size_bulk_out = usb_endpoint_maxp(epds->bulk_out[0]);
- u8 setting[F81534_CUSTOM_DATA_SIZE];
- u8 setting_idx;
u8 num_port = 0;
+ int index = 0;
int status;
- size_t i;
+ int i;
if (size_bulk_out != F81534_WRITE_BUFFER_SIZE ||
size_bulk_in != F81534_MAX_RECEIVE_BLOCK_SIZE) {
@@ -768,8 +768,16 @@ static int f81534_calc_num_ports(struct usb_serial *serial,
return -ENODEV;
}
+ serial_priv = devm_kzalloc(&serial->interface->dev,
+ sizeof(*serial_priv), GFP_KERNEL);
+ if (!serial_priv)
+ return -ENOMEM;
+
+ usb_set_serial_data(serial, serial_priv);
+ mutex_init(&serial_priv->urb_mutex);
+
/* Check had custom setting */
- status = f81534_find_config_idx(serial, &setting_idx);
+ status = f81534_find_config_idx(serial, &serial_priv->setting_idx);
if (status) {
dev_err(&serial->interface->dev, "%s: find idx failed: %d\n",
__func__, status);
@@ -780,11 +788,12 @@ static int f81534_calc_num_ports(struct usb_serial *serial,
* We'll read custom data only when data available, otherwise we'll
* read default value instead.
*/
- if (setting_idx != F81534_CUSTOM_NO_CUSTOM_DATA) {
+ if (serial_priv->setting_idx != F81534_CUSTOM_NO_CUSTOM_DATA) {
status = f81534_read_flash(serial,
F81534_CUSTOM_ADDRESS_START +
F81534_CONF_OFFSET,
- sizeof(setting), setting);
+ sizeof(serial_priv->conf_data),
+ serial_priv->conf_data);
if (status) {
dev_err(&serial->interface->dev,
"%s: get custom data failed: %d\n",
@@ -794,13 +803,13 @@ static int f81534_calc_num_ports(struct usb_serial *serial,
dev_dbg(&serial->interface->dev,
"%s: read config from block: %d\n", __func__,
- setting_idx);
+ serial_priv->setting_idx);
} else {
/* Read default board setting */
status = f81534_read_flash(serial,
- F81534_DEF_CONF_ADDRESS_START, F81534_NUM_PORT,
- setting);
-
+ F81534_DEF_CONF_ADDRESS_START,
+ sizeof(serial_priv->conf_data),
+ serial_priv->conf_data);
if (status) {
dev_err(&serial->interface->dev,
"%s: read failed: %d\n", __func__,
@@ -814,7 +823,7 @@ static int f81534_calc_num_ports(struct usb_serial *serial,
/* New style, find all possible ports */
for (i = 0; i < F81534_NUM_PORT; ++i) {
- if (setting[i] & F81534_PORT_UNAVAILABLE)
+ if (serial_priv->conf_data[i] & F81534_PORT_UNAVAILABLE)
continue;
++num_port;
@@ -826,6 +835,17 @@ static int f81534_calc_num_ports(struct usb_serial *serial,
num_port = 4; /* Nothing found, oldest version IC */
}
+ /* Assign phy-to-logic mapping */
+ for (i = 0; i < F81534_NUM_PORT; ++i) {
+ if (serial_priv->conf_data[i] & F81534_PORT_UNAVAILABLE)
+ continue;
+
+ serial_priv->tty_idx[i] = index++;
+ dev_dbg(&serial->interface->dev,
+ "%s: phy_num: %d, tty_idx: %d\n", __func__, i,
+ serial_priv->tty_idx[i]);
+ }
+
/*
* Setup bulk-out endpoint multiplexing. All ports share the same
* bulk-out endpoint.
@@ -1227,79 +1247,6 @@ static void f81534_write_usb_callback(struct urb *urb)
}
}
-static int f81534_attach(struct usb_serial *serial)
-{
- struct f81534_serial_private *serial_priv;
- int index = 0;
- int status;
- int i;
-
- serial_priv = devm_kzalloc(&serial->interface->dev,
- sizeof(*serial_priv), GFP_KERNEL);
- if (!serial_priv)
- return -ENOMEM;
-
- usb_set_serial_data(serial, serial_priv);
-
- mutex_init(&serial_priv->urb_mutex);
-
- /* Check had custom setting */
- status = f81534_find_config_idx(serial, &serial_priv->setting_idx);
- if (status) {
- dev_err(&serial->interface->dev, "%s: find idx failed: %d\n",
- __func__, status);
- return status;
- }
-
- /*
- * We'll read custom data only when data available, otherwise we'll
- * read default value instead.
- */
- if (serial_priv->setting_idx == F81534_CUSTOM_NO_CUSTOM_DATA) {
- /*
- * The default configuration layout:
- * byte 0/1/2/3: uart setting
- */
- status = f81534_read_flash(serial,
- F81534_DEF_CONF_ADDRESS_START,
- F81534_DEF_CONF_SIZE,
- serial_priv->conf_data);
- if (status) {
- dev_err(&serial->interface->dev,
- "%s: read reserve data failed: %d\n",
- __func__, status);
- return status;
- }
- } else {
- /* Only read 8 bytes for mode & GPIO */
- status = f81534_read_flash(serial,
- F81534_CUSTOM_ADDRESS_START +
- F81534_CONF_OFFSET,
- sizeof(serial_priv->conf_data),
- serial_priv->conf_data);
- if (status) {
- dev_err(&serial->interface->dev,
- "%s: idx: %d get data failed: %d\n",
- __func__, serial_priv->setting_idx,
- status);
- return status;
- }
- }
-
- /* Assign phy-to-logic mapping */
- for (i = 0; i < F81534_NUM_PORT; ++i) {
- if (serial_priv->conf_data[i] & F81534_PORT_UNAVAILABLE)
- continue;
-
- serial_priv->tty_idx[i] = index++;
- dev_dbg(&serial->interface->dev,
- "%s: phy_num: %d, tty_idx: %d\n", __func__, i,
- serial_priv->tty_idx[i]);
- }
-
- return 0;
-}
-
static void f81534_lsr_worker(struct work_struct *work)
{
struct f81534_port_private *port_priv;
@@ -1543,7 +1490,6 @@ static struct usb_serial_driver f81534_device = {
.write = f81534_write,
.tx_empty = f81534_tx_empty,
.calc_num_ports = f81534_calc_num_ports,
- .attach = f81534_attach,
.port_probe = f81534_port_probe,
.port_remove = f81534_port_remove,
.break_ctl = f81534_break_ctl,
--
2.7.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH V3 5/6] usb: serial: f81534: add H/W disable port support
2018-01-11 6:47 [PATCH V3 1/6] usb: serial: f81534: add high baud rate support Ji-Ze Hong (Peter Hong)
` (2 preceding siblings ...)
2018-01-11 6:47 ` [PATCH V3 4/6] usb: serial: f81534: refactoring calc_num_ports() Ji-Ze Hong (Peter Hong)
@ 2018-01-11 6:47 ` Ji-Ze Hong (Peter Hong)
2018-01-11 6:47 ` [PATCH V3 6/6] usb: serial: f81534: fix tx error on some baud rate Ji-Ze Hong (Peter Hong)
4 siblings, 0 replies; 7+ messages in thread
From: Ji-Ze Hong (Peter Hong) @ 2018-01-11 6:47 UTC (permalink / raw)
To: johan; +Cc: gregkh, linux-usb, linux-kernel, peter_hong,
Ji-Ze Hong (Peter Hong)
The F81532/534 can be disable port by manufacturer with
following H/W design.
1: Connect DCD/DSR/CTS/RI pin to ground.
2: Connect RX pin to ground.
In driver, we'll implements some detect method likes following:
1: Read MSR.
2: Turn MCR LOOP bit on, off and read LSR after delay with 60ms.
It'll contain BREAK status in LSR.
Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
---
V3:
1: Separate old patch into refacting and H/W disable patches.
V2:
1: f81534_check_port_hw_disabled() change return type from int to bool.
2: Add help function f81534_set_phy_port_register() /
f81534_get_phy_port_register() for f81534_check_port_hw_disabled()
to read register without port.
3: Re-write f81534_calc_num_ports() & f81534_attach() to reduce the
f81534_check_port_hw_disabled() repeatedly called.
drivers/usb/serial/f81534.c | 81 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
index bc0a4bd5dcec..08ef72ea2eec 100644
--- a/drivers/usb/serial/f81534.c
+++ b/drivers/usb/serial/f81534.c
@@ -307,6 +307,20 @@ static int f81534_set_mask_register(struct usb_serial *serial, u16 reg,
return f81534_set_register(serial, reg, tmp);
}
+static int f81534_set_phy_port_register(struct usb_serial *serial, int phy,
+ u16 reg, u8 data)
+{
+ return f81534_set_register(serial, reg + F81534_UART_OFFSET * phy,
+ data);
+}
+
+static int f81534_get_phy_port_register(struct usb_serial *serial, int phy,
+ u16 reg, u8 *data)
+{
+ return f81534_get_register(serial, reg + F81534_UART_OFFSET * phy,
+ data);
+}
+
static int f81534_set_port_register(struct usb_serial_port *port, u16 reg,
u8 data)
{
@@ -733,6 +747,70 @@ static int f81534_find_config_idx(struct usb_serial *serial, u8 *index)
}
/*
+ * The F81532/534 will not report serial port to USB serial subsystem when
+ * H/W DCD/DSR/CTS/RI/RX pin connected to ground.
+ *
+ * To detect RX pin status, we'll enable MCR interal loopback, disable it and
+ * delayed for 60ms. It connected to ground If LSR register report UART_LSR_BI.
+ */
+static bool f81534_check_port_hw_disabled(struct usb_serial *serial, int phy)
+{
+ int status;
+ u8 old_mcr;
+ u8 msr;
+ u8 lsr;
+ u8 msr_mask;
+
+ msr_mask = UART_MSR_DCD | UART_MSR_RI | UART_MSR_DSR | UART_MSR_CTS;
+
+ status = f81534_get_phy_port_register(serial, phy,
+ F81534_MODEM_STATUS_REG, &msr);
+ if (status)
+ return false;
+
+ if ((msr & msr_mask) != msr_mask)
+ return false;
+
+ status = f81534_set_phy_port_register(serial, phy,
+ F81534_FIFO_CONTROL_REG, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ if (status)
+ return false;
+
+ status = f81534_get_phy_port_register(serial, phy,
+ F81534_MODEM_CONTROL_REG, &old_mcr);
+ if (status)
+ return false;
+
+ status = f81534_set_phy_port_register(serial, phy,
+ F81534_MODEM_CONTROL_REG, UART_MCR_LOOP);
+ if (status)
+ return false;
+
+ status = f81534_set_phy_port_register(serial, phy,
+ F81534_MODEM_CONTROL_REG, 0x0);
+ if (status)
+ return false;
+
+ msleep(60);
+
+ status = f81534_get_phy_port_register(serial, phy,
+ F81534_LINE_STATUS_REG, &lsr);
+ if (status)
+ return false;
+
+ status = f81534_set_phy_port_register(serial, phy,
+ F81534_MODEM_CONTROL_REG, old_mcr);
+ if (status)
+ return false;
+
+ if ((lsr & UART_LSR_BI) == UART_LSR_BI)
+ return true;
+
+ return false;
+}
+
+/*
* We had 2 generation of F81532/534 IC. All has an internal storage.
*
* 1st is pure USB-to-TTL RS232 IC and designed for 4 ports only, no any
@@ -823,6 +901,9 @@ static int f81534_calc_num_ports(struct usb_serial *serial,
/* New style, find all possible ports */
for (i = 0; i < F81534_NUM_PORT; ++i) {
+ if (f81534_check_port_hw_disabled(serial, i))
+ serial_priv->conf_data[i] |= F81534_PORT_UNAVAILABLE;
+
if (serial_priv->conf_data[i] & F81534_PORT_UNAVAILABLE)
continue;
--
2.7.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH V3 6/6] usb: serial: f81534: fix tx error on some baud rate
2018-01-11 6:47 [PATCH V3 1/6] usb: serial: f81534: add high baud rate support Ji-Ze Hong (Peter Hong)
` (3 preceding siblings ...)
2018-01-11 6:47 ` [PATCH V3 5/6] usb: serial: f81534: add H/W disable port support Ji-Ze Hong (Peter Hong)
@ 2018-01-11 6:47 ` Ji-Ze Hong (Peter Hong)
4 siblings, 0 replies; 7+ messages in thread
From: Ji-Ze Hong (Peter Hong) @ 2018-01-11 6:47 UTC (permalink / raw)
To: johan; +Cc: gregkh, linux-usb, linux-kernel, peter_hong,
Ji-Ze Hong (Peter Hong)
The F81532/534 had 4 clocksource 1.846/18.46/14.77/24MHz and baud rates
can be up to 1.5Mbits with 24MHz. But on some baud rate (384~500kps), the
TX side will send the data frame too close to treat frame error on RX
side. This patch will force all TX data frame with delay 1bit gap.
Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
---
V3:
1: had not noticeable changes.
V2:
1: First introduced in this series patches.
drivers/usb/serial/f81534.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
index 08ef72ea2eec..92c9d8f18a5a 100644
--- a/drivers/usb/serial/f81534.c
+++ b/drivers/usb/serial/f81534.c
@@ -131,6 +131,8 @@
#define F81534_CLK_24_MHZ BIT(2)
#define F81534_CLK_14_77_MHZ GENMASK(2, 1)
#define F81534_CLK_MASK GENMASK(2, 1)
+#define F81534_CLK_TX_DELAY_1BIT BIT(3)
+
#define F81534_CLK_RS485_MODE BIT(4)
#define F81534_CLK_RS485_INVERT BIT(5)
@@ -1386,7 +1388,11 @@ static int f81534_port_probe(struct usb_serial_port *port)
if (!port_priv)
return -ENOMEM;
- port_priv->shadow_clk = F81534_UART_EN;
+ /*
+ * We'll make tx frame error when baud rate from 384~500kps. So we'll
+ * delay all tx data frame with 1bit.
+ */
+ port_priv->shadow_clk = F81534_UART_EN | F81534_CLK_TX_DELAY_1BIT;
spin_lock_init(&port_priv->msr_lock);
mutex_init(&port_priv->mcr_mutex);
mutex_init(&port_priv->lcr_mutex);
--
2.7.4
^ permalink raw reply related [flat|nested] 7+ messages in thread