Skip to contentSkip to conversation

Add Fintek F81534A series usb-to-serial driver

PATCH Superseded Ji-Ze Hong (Peter Hong) 2 participants 24 messages Sep 23, 2019 – Jan 14, 2020 1 message not in the archive

Subsystems (2)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover Add Fintek F81534A series usb-to-serial driver

The Fintek F81532A/534A/535/536 is USB-to-2/4/8/12 serial ports device and the serial port is default disabled when plugin computer.

The part number is a bit same with F81532/534, but F81534A series UART core is enhanced from F81232, not F81532/534.

The IC is contains devices as following:
1. HUB (all devices is connected with this hub)
2. GPIO/Control device. (enable serial port and control all GPIOs)
3. serial port 1 to x (2/4/8/12)

It's most same with F81232, the UART device is difference as follow:

	1. TX/RX bulk size is 128/512bytes
	2. RX bulk layout change:
		F81232: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]...
		F81534A:[LEN][Data.....][LSR]

We'll try to do some code refacting before add F81534A series.

Ji-Ze Hong (Peter Hong) (7):
USB: serial: f81232: Extract LSR handler
USB: serial: f81232: Add tx_empty function
USB: serial: f81232: Use devm_kzalloc
USB: serial: f81232: Add F81534A support
USB: serial: f81232: Set F81534A serial port with RS232 mode
USB: serial: f81232: Add generator for F81534A
USB: serial: f81232: Add gpiolib to GPIO device

 drivers/usb/serial/f81232.c | 604 ++++++++++++++++++++++++++++++++++--
 1 file changed, 570 insertions(+), 34 deletions(-)
Signature · 1 line
2.17.1
#1 lore raw

PATCH v2 1/7 USB: serial: f81232: Extract LSR handler

Extract LSR handler to function.

---
 drivers/usb/serial/f81232.c | 53 +++++++++++++++++++++----------------
 1 file changed, 30 insertions(+), 23 deletions(-)
drivers/usb/serial/f81232.c +30 -23
index 43fa1f0716b7..c07d376c743d 100644
@@ -322,10 +322,38 @@ static void f81232_read_int_callback(struct urb *urb)
 			__func__, retval);
 }
 
+static char f81232_handle_lsr(struct usb_serial_port *port, u8 lsr)
+{
+	struct f81232_private *priv = usb_get_serial_port_data(port);
+	char tty_flag = TTY_NORMAL;
+
+	if (!(lsr & UART_LSR_BRK_ERROR_BITS))
+		return tty_flag;
+
+	if (lsr & UART_LSR_BI) {
+		tty_flag = TTY_BREAK;
+		port->icount.brk++;
+		usb_serial_handle_break(port);
+	} else if (lsr & UART_LSR_PE) {
+		tty_flag = TTY_PARITY;
+		port->icount.parity++;
+	} else if (lsr & UART_LSR_FE) {
+		tty_flag = TTY_FRAME;
+		port->icount.frame++;
+	}
+
+	if (lsr & UART_LSR_OE) {
+		port->icount.overrun++;
+		schedule_work(&priv->lsr_work);
+		tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
+	}
+
+	return tty_flag;
+}
+
 static void f81232_process_read_urb(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
-	struct f81232_private *priv = usb_get_serial_port_data(port);
 	unsigned char *data = urb->transfer_buffer;
 	char tty_flag;
 	unsigned int i;
@@ -341,29 +369,8 @@ static void f81232_process_read_urb(struct urb *urb)
 	/* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */
 
 	for (i = 0; i < urb->actual_length; i += 2) {
-		tty_flag = TTY_NORMAL;
 		lsr = data[i];
-
-		if (lsr & UART_LSR_BRK_ERROR_BITS) {
-			if (lsr & UART_LSR_BI) {
-				tty_flag = TTY_BREAK;
-				port->icount.brk++;
-				usb_serial_handle_break(port);
-			} else if (lsr & UART_LSR_PE) {
-				tty_flag = TTY_PARITY;
-				port->icount.parity++;
-			} else if (lsr & UART_LSR_FE) {
-				tty_flag = TTY_FRAME;
-				port->icount.frame++;
-			}
-
-			if (lsr & UART_LSR_OE) {
-				port->icount.overrun++;
-				schedule_work(&priv->lsr_work);
-				tty_insert_flip_char(&port->port, 0,
-						TTY_OVERRUN);
-			}
-		}
+		tty_flag = f81232_handle_lsr(port, lsr);
 
 		if (port->port.console && port->sysrq) {
 			if (usb_serial_handle_sysrq_char(port, data[i + 1]))
Signature · 1 line
2.17.1
maintainer
#2 lore raw

Re: [PATCH V2 1/7] USB: serial: f81232: Extract LSR handler

Quoted 1 line · Ji-Ze Hong (Peter Hong)

Extract LSR handler to function.

Try to always provide a motivation for your changes, don't just say what you do (e.g. mention reusing this for the new device types if that's what you plan on doing).

Quoted 1 line

Johan

#3 lore raw

PATCH v2 2/7 USB: serial: f81232: Add tx_empty function

In reply to Ji-Ze Hong (Peter Hong)

Add tx_empty() function for F81232.

---
 drivers/usb/serial/f81232.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/usb/serial/f81232.c +18 -0
index c07d376c743d..b42b3738a768 100644
@@ -685,6 +685,23 @@ static void f81232_dtr_rts(struct usb_serial_port *port, int on)
 		f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS);
 }
 
+static bool f81232_tx_empty(struct usb_serial_port *port)
+{
+	int status;
+	u8 tmp;
+
+	status = f81232_get_register(port, LINE_STATUS_REGISTER, &tmp);
+	if (status) {
+		dev_err(&port->dev, "get LSR status failed: %d\n", status);
+		return false;
+	}
+
+	if ((tmp & UART_LSR_TEMT) != UART_LSR_TEMT)
+		return false;
+
+	return true;
+}
+
 static int f81232_carrier_raised(struct usb_serial_port *port)
 {
 	u8 msr;
@@ -820,6 +837,7 @@ static struct usb_serial_driver f81232_device = {
 	.tiocmget =		f81232_tiocmget,
 	.tiocmset =		f81232_tiocmset,
 	.tiocmiwait =		usb_serial_generic_tiocmiwait,
+	.tx_empty =		f81232_tx_empty,
 	.process_read_urb =	f81232_process_read_urb,
 	.read_int_callback =	f81232_read_int_callback,
 	.port_probe =		f81232_port_probe,
Signature · 1 line
2.17.1
maintainer
#4 lore raw

Re: [PATCH V2 2/7] USB: serial: f81232: Add tx_empty function

Quoted 14 lines · Ji-Ze Hong (Peter Hong)

Add tx_empty() function for F81232.

---
 drivers/usb/serial/f81232.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/usb/serial/f81232.c +0 -0
index c07d376c743d..b42b3738a768 100644
@@ -685,6 +685,23 @@ static void f81232_dtr_rts(struct usb_serial_port *port, int on)
 		f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS);
 }

drivers/usb/serial/f81232.c static void f81232_dtr_rts(struct usb_serial_port *port, int on) · line 696

Quoted 10 lines
drivers/usb/serial/f81232.c +9 -0
 
+static bool f81232_tx_empty(struct usb_serial_port *port)
+{
+	int status;
+	u8 tmp;
+
+	status = f81232_get_register(port, LINE_STATUS_REGISTER, &tmp);
+	if (status) {
+		dev_err(&port->dev, "get LSR status failed: %d\n", status);
+		return false;

You need to return true here on errors like the other drivers do (consider a disconnected device where you end up with -ENODEV here).

drivers/usb/serial/f81232.c static void f81232_dtr_rts(struct usb_serial_port *port, int on) · line 703

Quoted 7 lines
drivers/usb/serial/f81232.c +7 -0
+	}
+
+	if ((tmp & UART_LSR_TEMT) != UART_LSR_TEMT)
+		return false;
+
+	return true;
+}

Johan

#5 lore raw

PATCH v2 3/7 USB: serial: f81232: Use devm_kzalloc

In reply to Ji-Ze Hong (Peter Hong)

Use devm_kzalloc() to replace kzalloc().

---
 drivers/usb/serial/f81232.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)
drivers/usb/serial/f81232.c +1 -12
index b42b3738a768..e4db0aec9af0 100644
@@ -756,7 +756,7 @@ static int f81232_port_probe(struct usb_serial_port *port)
 {
 	struct f81232_private *priv;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = devm_kzalloc(&port->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -772,16 +772,6 @@ static int f81232_port_probe(struct usb_serial_port *port)
 	return 0;
 }
 
-static int f81232_port_remove(struct usb_serial_port *port)
-{
-	struct f81232_private *priv;
-
-	priv = usb_get_serial_port_data(port);
-	kfree(priv);
-
-	return 0;
-}
-
 static int f81232_suspend(struct usb_serial *serial, pm_message_t message)
 {
 	struct usb_serial_port *port = serial->port[0];
@@ -841,7 +831,6 @@ static struct usb_serial_driver f81232_device = {
 	.process_read_urb =	f81232_process_read_urb,
 	.read_int_callback =	f81232_read_int_callback,
 	.port_probe =		f81232_port_probe,
-	.port_remove =		f81232_port_remove,
 	.suspend =		f81232_suspend,
 	.resume =		f81232_resume,
 };
Signature · 1 line
2.17.1
#6 lore raw

PATCH v2 4/7 USB: serial: f81232: Add F81534A support

In reply to Ji-Ze Hong (Peter Hong)

The Fintek F81532A/534A/535/536 is USB-to-2/4/8/12 serial ports device and the serial port is default disabled when plugin computer.

The IC is contains devices as following:
1. HUB (all devices is connected with this hub)
2. GPIO/Control device. (enable serial port and control GPIOs)
3. serial port 1 to x (2/4/8/12)

It's most same with F81232, the UART device is difference as follow:

	1. TX/RX bulk size is 128/512bytes
	2. RX bulk layout change:
		F81232: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]...
		F81534A:[LEN][Data.....][LSR]
---
 drivers/usb/serial/f81232.c | 131 ++++++++++++++++++++++++++++++++++--
 1 file changed, 127 insertions(+), 4 deletions(-)
drivers/usb/serial/f81232.c +127 -4
index e4db0aec9af0..36a17aedc2ae 100644
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * Fintek F81232 USB to serial adaptor driver
+ * Fintek F81532A/534A/535/536 USB to 2/4/8/12 serial adaptor driver
  *
  * Copyright (C) 2012 Greg Kroah-Hartman ([email protected])
  * Copyright (C) 2012 Linux Foundation
@@ -21,11 +22,36 @@
 #include <linux/usb/serial.h>
 #include <linux/serial_reg.h>
 
+#define F81232_ID		\
+	{ USB_DEVICE(0x1934, 0x0706) }	/* 1 port UART device */
+
+#define F81534A_SERIES_ID	\
+	{ USB_DEVICE(0x2c42, 0x1602) },	/* In-Box 2 port UART device */	\
+	{ USB_DEVICE(0x2c42, 0x1604) },	/* In-Box 4 port UART device */	\
+	{ USB_DEVICE(0x2c42, 0x1605) },	/* In-Box 8 port UART device */	\
+	{ USB_DEVICE(0x2c42, 0x1606) },	/* In-Box 12 port UART device */ \
+	{ USB_DEVICE(0x2c42, 0x1608) },	/* Non-Flash type */ \
+	{ USB_DEVICE(0x2c42, 0x1632) },	/* 2 port UART device */ \
+	{ USB_DEVICE(0x2c42, 0x1634) },	/* 4 port UART device */ \
+	{ USB_DEVICE(0x2c42, 0x1635) },	/* 8 port UART device */ \
+	{ USB_DEVICE(0x2c42, 0x1636) }	/* 12 port UART device */
+
 static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE(0x1934, 0x0706) },
+	F81232_ID,
+	{ }					/* Terminating entry */
+};
+
+static const struct usb_device_id f81534a_id_table[] = {
+	F81534A_SERIES_ID,
+	{ }					/* Terminating entry */
+};
+
+static const struct usb_device_id all_serial_id_table[] = {
+	F81232_ID,
+	F81534A_SERIES_ID,
 	{ }					/* Terminating entry */
 };
-MODULE_DEVICE_TABLE(usb, id_table);
+MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 
 /* Maximum baudrate for F81232 */
 #define F81232_MAX_BAUDRATE		1500000
@@ -35,6 +61,10 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_REGISTER_REQUEST		0xa0
 #define F81232_GET_REGISTER		0xc0
 #define F81232_SET_REGISTER		0x40
+#define F81534A_REGISTER_REQUEST	F81232_REGISTER_REQUEST
+#define F81534A_GET_REGISTER		F81232_GET_REGISTER
+#define F81534A_SET_REGISTER		F81232_SET_REGISTER
+#define F81534A_ACCESS_REG_RETRY	2
 
 #define SERIAL_BASE_ADDRESS		0x0120
 #define RECEIVE_BUFFER_REGISTER		(0x00 + SERIAL_BASE_ADDRESS)
@@ -61,6 +91,11 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_CLK_14_77_MHZ		(BIT(1) | BIT(0))
 #define F81232_CLK_MASK			GENMASK(1, 0)
 
+#define F81534A_MODE_CONF_REG		0x107
+#define F81534A_TRIGGER_MASK		GENMASK(3, 2)
+#define F81534A_TRIGGER_MULTPILE_4X	BIT(3)
+#define F81534A_FIFO_128BYTE		(BIT(1) | BIT(0))
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;
@@ -383,6 +418,46 @@ static void f81232_process_read_urb(struct urb *urb)
 	tty_flip_buffer_push(&port->port);
 }
 
+static void f81534a_process_read_urb(struct urb *urb)
+{
+	struct usb_serial_port *port = urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	char tty_flag;
+	unsigned int i;
+	u8 lsr;
+	u8 len;
+
+	if (urb->actual_length < 3) {
+		dev_err(&port->dev, "error actual_length: %d\n",
+				urb->actual_length);
+		return;
+	}
+
+	len = data[0];
+	if (len != urb->actual_length) {
+		dev_err(&port->dev, "len(%d) != urb->actual_length(%d)\n", len,
+				urb->actual_length);
+		return;
+	}
+
+	/* bulk-in data: [LEN][Data.....][LSR] */
+	lsr = data[len - 1];
+	tty_flag = f81232_handle_lsr(port, lsr);
+
+	if (port->port.console && port->sysrq) {
+		for (i = 1; i < urb->actual_length - 1; ++i)
+			if (!usb_serial_handle_sysrq_char(port, data[i]))
+				tty_insert_flip_char(&port->port, data[i],
+						tty_flag);
+	} else {
+		tty_insert_flip_string_fixed_flag(&port->port, &data[1],
+							tty_flag,
+							urb->actual_length - 2);
+	}
+
+	tty_flip_buffer_push(&port->port);
+}
+
 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 {
 	struct usb_serial_port *port = tty->driver_data;
@@ -666,6 +741,23 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
 	return 0;
 }
 
+static int f81534a_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+	int status;
+	u8 val;
+
+	val = F81534A_TRIGGER_MULTPILE_4X | F81534A_FIFO_128BYTE;
+	status = f81232_set_mask_register(port, F81534A_MODE_CONF_REG,
+			F81534A_TRIGGER_MASK | F81534A_FIFO_128BYTE, val);
+	if (status) {
+		dev_err(&port->dev, "failed to set MODE_CONF_REG: %d\n",
+				status);
+		return status;
+	}
+
+	return f81232_open(tty, port);
+}
+
 static void f81232_close(struct usb_serial_port *port)
 {
 	struct f81232_private *port_priv = usb_get_serial_port_data(port);
@@ -772,6 +864,11 @@ static int f81232_port_probe(struct usb_serial_port *port)
 	return 0;
 }
 
+static int f81534a_port_probe(struct usb_serial_port *port)
+{
+	return f81232_port_probe(port);
+}
+
 static int f81232_suspend(struct usb_serial *serial, pm_message_t message)
 {
 	struct usb_serial_port *port = serial->port[0];
@@ -835,14 +932,40 @@ static struct usb_serial_driver f81232_device = {
 	.resume =		f81232_resume,
 };
 
+static struct usb_serial_driver f81534a_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"f81534a",
+	},
+	.id_table =		f81534a_id_table,
+	.num_ports =		1,
+	.open =			f81534a_open,
+	.close =		f81232_close,
+	.dtr_rts =		f81232_dtr_rts,
+	.carrier_raised =	f81232_carrier_raised,
+	.get_serial =		f81232_get_serial_info,
+	.break_ctl =		f81232_break_ctl,
+	.set_termios =		f81232_set_termios,
+	.tiocmget =		f81232_tiocmget,
+	.tiocmset =		f81232_tiocmset,
+	.tiocmiwait =		usb_serial_generic_tiocmiwait,
+	.tx_empty =		f81232_tx_empty,
+	.process_read_urb =	f81534a_process_read_urb,
+	.read_int_callback =	f81232_read_int_callback,
+	.port_probe =		f81534a_port_probe,
+	.suspend =		f81232_suspend,
+	.resume =		f81232_resume,
+};
+
 static struct usb_serial_driver * const serial_drivers[] = {
 	&f81232_device,
+	&f81534a_device,
 	NULL,
 };
 
-module_usb_serial_driver(serial_drivers, id_table);
+module_usb_serial_driver(serial_drivers, all_serial_id_table);
 
-MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
+MODULE_DESCRIPTION("Fintek F81232/532A/534A/535/536 USB to serial driver");
 MODULE_AUTHOR("Greg Kroah-Hartman <[email protected]>");
 MODULE_AUTHOR("Peter Hong <[email protected]>");
 MODULE_LICENSE("GPL v2");
Signature · 1 line
2.17.1
maintainer
#7 lore raw

Re: [PATCH V2 4/7] USB: serial: f81232: Add F81534A support

Quoted 40 lines · Ji-Ze Hong (Peter Hong)

The Fintek F81532A/534A/535/536 is USB-to-2/4/8/12 serial ports device and the serial port is default disabled when plugin computer.

The IC is contains devices as following:
1. HUB (all devices is connected with this hub)
2. GPIO/Control device. (enable serial port and control GPIOs)
3. serial port 1 to x (2/4/8/12)

It's most same with F81232, the UART device is difference as follow:

	1. TX/RX bulk size is 128/512bytes
	2. RX bulk layout change:
		F81232: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]...
		F81534A:[LEN][Data.....][LSR]
---
 drivers/usb/serial/f81232.c | 131 ++++++++++++++++++++++++++++++++++--
 1 file changed, 127 insertions(+), 4 deletions(-)
drivers/usb/serial/f81232.c +6 -0
index e4db0aec9af0..36a17aedc2ae 100644
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * Fintek F81232 USB to serial adaptor driver
+ * Fintek F81532A/534A/535/536 USB to 2/4/8/12 serial adaptor driver
  *
  * Copyright (C) 2012 Greg Kroah-Hartman ([email protected])
  * Copyright (C) 2012 Linux Foundation
@@ -21,11 +22,36 @@
 #include <linux/usb/serial.h>
 #include <linux/serial_reg.h>
 
+#define F81232_ID		\
+	{ USB_DEVICE(0x1934, 0x0706) }	/* 1 port UART device */
+
+#define F81534A_SERIES_ID	\
+	{ USB_DEVICE(0x2c42, 0x1602) },	/* In-Box 2 port UART device */	\

drivers/usb/serial/f81232.c line 39

Quoted 10 lines
drivers/usb/serial/f81232.c +9 -0
+	{ USB_DEVICE(0x2c42, 0x1604) },	/* In-Box 4 port UART device */	\
+	{ USB_DEVICE(0x2c42, 0x1605) },	/* In-Box 8 port UART device */	\
+	{ USB_DEVICE(0x2c42, 0x1606) },	/* In-Box 12 port UART device */ \
+	{ USB_DEVICE(0x2c42, 0x1608) },	/* Non-Flash type */ \
+	{ USB_DEVICE(0x2c42, 0x1632) },	/* 2 port UART device */ \
+	{ USB_DEVICE(0x2c42, 0x1634) },	/* 4 port UART device */ \
+	{ USB_DEVICE(0x2c42, 0x1635) },	/* 8 port UART device */ \
+	{ USB_DEVICE(0x2c42, 0x1636) }	/* 12 port UART device */
+
 static const struct usb_device_id id_table[] = {

Add a prefix here as well?

drivers/usb/serial/f81232.c line 49

Quoted 11 lines
drivers/usb/serial/f81232.c +10 -1
-	{ USB_DEVICE(0x1934, 0x0706) },
+	F81232_ID,
+	{ }					/* Terminating entry */
+};
+
+static const struct usb_device_id f81534a_id_table[] = {
+	F81534A_SERIES_ID,
+	{ }					/* Terminating entry */
+};
+
+static const struct usb_device_id all_serial_id_table[] = {

combined_id_table would be a name more in line with the rest of the drivers, if you end up using this one for the MODULE_DEVICE_TABLE.

Quoted 10 lines
drivers/usb/serial/f81232.c +3 -1
+	F81232_ID,
+	F81534A_SERIES_ID,
 	{ }					/* Terminating entry */
 };
-MODULE_DEVICE_TABLE(usb, id_table);
+MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 
 /* Maximum baudrate for F81232 */
 #define F81232_MAX_BAUDRATE		1500000

drivers/usb/serial/f81232.c MODULE_DEVICE_TABLE(usb, id_table); · line 67

Quoted 7 lines
drivers/usb/serial/f81232.c +4 -0
@@ -35,6 +61,10 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_REGISTER_REQUEST		0xa0
 #define F81232_GET_REGISTER		0xc0
 #define F81232_SET_REGISTER		0x40
+#define F81534A_REGISTER_REQUEST	F81232_REGISTER_REQUEST
+#define F81534A_GET_REGISTER		F81232_GET_REGISTER
+#define F81534A_SET_REGISTER		F81232_SET_REGISTER
+#define F81534A_ACCESS_REG_RETRY	2

This patch doesn't use any of these, and looks like you can just use the F81232 defines directly anyway.

drivers/usb/serial/f81232.c MODULE_DEVICE_TABLE(usb, id_table); · line 96

Quoted 9 lines
drivers/usb/serial/f81232.c +3 -0
 #define SERIAL_BASE_ADDRESS		0x0120
 #define RECEIVE_BUFFER_REGISTER		(0x00 + SERIAL_BASE_ADDRESS)
@@ -61,6 +91,11 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_CLK_14_77_MHZ		(BIT(1) | BIT(0))
 #define F81232_CLK_MASK			GENMASK(1, 0)
 
+#define F81534A_MODE_CONF_REG		0x107
+#define F81534A_TRIGGER_MASK		GENMASK(3, 2)
+#define F81534A_TRIGGER_MULTPILE_4X	BIT(3)

MULTPILE typo?

Quoted 10 lines
drivers/usb/serial/f81232.c +3 -0
+#define F81534A_FIFO_128BYTE		(BIT(1) | BIT(0))
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;
@@ -383,6 +418,46 @@ static void f81232_process_read_urb(struct urb *urb)
 	tty_flip_buffer_push(&port->port);
 }
 
+static void f81534a_process_read_urb(struct urb *urb)

drivers/usb/serial/f81232.c static void f81232_process_read_urb(struct urb *urb) · line 431

Quoted 10 lines
drivers/usb/serial/f81232.c +10 -0
+{
+	struct usb_serial_port *port = urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	char tty_flag;
+	unsigned int i;
+	u8 lsr;
+	u8 len;
+
+	if (urb->actual_length < 3) {
+		dev_err(&port->dev, "error actual_length: %d\n",

Rephrase as "short message received" or similar.

drivers/usb/serial/f81232.c static void f81232_process_read_urb(struct urb *urb) · line 439

Quoted 8 lines
drivers/usb/serial/f81232.c +8 -0
+				urb->actual_length);
+		return;
+	}
+
+	len = data[0];
+	if (len != urb->actual_length) {
+		dev_err(&port->dev, "len(%d) != urb->actual_length(%d)\n", len,
+				urb->actual_length);

Avoid c-expressions in error messages, rephrase this in English (e.g. unexpected length or similar).

drivers/usb/serial/f81232.c static void f81232_process_read_urb(struct urb *urb) · line 448

Quoted 9 lines
drivers/usb/serial/f81232.c +9 -0
+		return;
+	}
+
+	/* bulk-in data: [LEN][Data.....][LSR] */
+	lsr = data[len - 1];
+	tty_flag = f81232_handle_lsr(port, lsr);
+
+	if (port->port.console && port->sysrq) {
+		for (i = 1; i < urb->actual_length - 1; ++i)

Use len here?

And please add brackets here since the body is a multi-line statement.

drivers/usb/serial/f81232.c static void f81232_process_read_urb(struct urb *urb) · line 449

Quoted 1 line
drivers/usb/serial/f81232.c +1 -0
+			if (!usb_serial_handle_sysrq_char(port, data[i]))

Maybe also here.

drivers/usb/serial/f81232.c static void f81232_process_read_urb(struct urb *urb) · line 455

Quoted 6 lines
drivers/usb/serial/f81232.c +6 -0
+				tty_insert_flip_char(&port->port, data[i],
+						tty_flag);
+	} else {
+		tty_insert_flip_string_fixed_flag(&port->port, &data[1],
+							tty_flag,
+							urb->actual_length - 2);

len

Quoted 10 lines
drivers/usb/serial/f81232.c +5 -0
+	}
+
+	tty_flip_buffer_push(&port->port);
+}
+
 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 {
 	struct usb_serial_port *port = tty->driver_data;
@@ -666,6 +741,23 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
 	return 0;

drivers/usb/serial/f81232.c static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) · line 751

Quoted 10 lines
drivers/usb/serial/f81232.c +8 -0
 }
 
+static int f81534a_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+	int status;
+	u8 val;
+
+	val = F81534A_TRIGGER_MULTPILE_4X | F81534A_FIFO_128BYTE;
+	status = f81232_set_mask_register(port, F81534A_MODE_CONF_REG,
+			F81534A_TRIGGER_MASK | F81534A_FIFO_128BYTE, val);

Add also a mask temporary if that can avoid the line break?

Quoted 13 lines
drivers/usb/serial/f81232.c +9 -0
+	if (status) {
+		dev_err(&port->dev, "failed to set MODE_CONF_REG: %d\n",
+				status);
+		return status;
+	}
+
+	return f81232_open(tty, port);
+}
+
 static void f81232_close(struct usb_serial_port *port)
 {
 	struct f81232_private *port_priv = usb_get_serial_port_data(port);

drivers/usb/serial/f81232.c static int f81232_port_probe(struct usb_serial_port *port) · line 870

Quoted 7 lines
drivers/usb/serial/f81232.c +4 -0
@@ -772,6 +864,11 @@ static int f81232_port_probe(struct usb_serial_port *port)
 	return 0;
 }
 
+static int f81534a_port_probe(struct usb_serial_port *port)
+{
+	return f81232_port_probe(port);
+}

Maybe wait with adding this one until you need it and use f18232_port_probe below instead.

Quoted 37 lines
drivers/usb/serial/f81232.c +27 -0
+
 static int f81232_suspend(struct usb_serial *serial, pm_message_t message)
 {
 	struct usb_serial_port *port = serial->port[0];
@@ -835,14 +932,40 @@ static struct usb_serial_driver f81232_device = {
 	.resume =		f81232_resume,
 };
 
+static struct usb_serial_driver f81534a_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"f81534a",
+	},
+	.id_table =		f81534a_id_table,
+	.num_ports =		1,
+	.open =			f81534a_open,
+	.close =		f81232_close,
+	.dtr_rts =		f81232_dtr_rts,
+	.carrier_raised =	f81232_carrier_raised,
+	.get_serial =		f81232_get_serial_info,
+	.break_ctl =		f81232_break_ctl,
+	.set_termios =		f81232_set_termios,
+	.tiocmget =		f81232_tiocmget,
+	.tiocmset =		f81232_tiocmset,
+	.tiocmiwait =		usb_serial_generic_tiocmiwait,
+	.tx_empty =		f81232_tx_empty,
+	.process_read_urb =	f81534a_process_read_urb,
+	.read_int_callback =	f81232_read_int_callback,
+	.port_probe =		f81534a_port_probe,
+	.suspend =		f81232_suspend,
+	.resume =		f81232_resume,
+};
+
 static struct usb_serial_driver * const serial_drivers[] = {
 	&f81232_device,
+	&f81534a_device,
 	NULL,

drivers/usb/serial/f81232.c static struct usb_serial_driver f81232_device = { · line 971

Quoted 10 lines
drivers/usb/serial/f81232.c +2 -2
 };
 
-module_usb_serial_driver(serial_drivers, id_table);
+module_usb_serial_driver(serial_drivers, all_serial_id_table);
 
-MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
+MODULE_DESCRIPTION("Fintek F81232/532A/534A/535/536 USB to serial driver");
 MODULE_AUTHOR("Greg Kroah-Hartman <[email protected]>");
 MODULE_AUTHOR("Peter Hong <[email protected]>");
 MODULE_LICENSE("GPL v2");

Johan

#8 lore raw

PATCH v2 5/7 USB: serial: f81232: Set F81534A serial port with RS232 mode

In reply to Ji-Ze Hong (Peter Hong)

The Fintek F81532A/534A/535/536 is USB-to-2/4/8/12 serial ports device and the serial ports are default disabled. Each port contains max 3 pins GPIO and the 3 pins are default pull high with input mode.

When the serial port had activated (running probe()), we'll transform the 3 pins from GPIO function publicly to control Tranceiver privately use. We'll default set to 0/0/1 for control transceiver to RS232 mode.

Otherwise, If the serial port is not active, the 3 pins is in GPIO mode and controlled by global GPIO device with VID/PID: 2c42/16f8.

---
 drivers/usb/serial/f81232.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
drivers/usb/serial/f81232.c +17 -0
index 36a17aedc2ae..01cb5a5ea1d2 100644
@@ -96,6 +96,15 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 #define F81534A_TRIGGER_MULTPILE_4X	BIT(3)
 #define F81534A_FIFO_128BYTE		(BIT(1) | BIT(0))
 
+/* Serial port self GPIO control, 2bytes [control&output data][input data] */
+#define F81534A_GPIO_REG		0x10e
+#define F81534A_GPIO_MODE2_DIR		BIT(6) /* 1: input, 0: output */
+#define F81534A_GPIO_MODE1_DIR		BIT(5)
+#define F81534A_GPIO_MODE0_DIR		BIT(4)
+#define F81534A_GPIO_MODE2_OUTPUT	BIT(2)
+#define F81534A_GPIO_MODE1_OUTPUT	BIT(1)
+#define F81534A_GPIO_MODE0_OUTPUT	BIT(0)
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;
@@ -866,6 +875,14 @@ static int f81232_port_probe(struct usb_serial_port *port)
 
 static int f81534a_port_probe(struct usb_serial_port *port)
 {
+	int status;
+
+	/* tri-state with pull-high, default RS232 Mode */
+	status = f81232_set_register(port, F81534A_GPIO_REG,
+					F81534A_GPIO_MODE2_DIR);
+	if (status)
+		return status;
+
 	return f81232_port_probe(port);
 }
 
Signature · 1 line
2.17.1
maintainer
#9 lore raw

Re: [PATCH V2 5/7] USB: serial: f81232: Set F81534A serial port with RS232 mode

Quoted 6 lines · Ji-Ze Hong (Peter Hong)

The Fintek F81532A/534A/535/536 is USB-to-2/4/8/12 serial ports device and the serial ports are default disabled. Each port contains max 3 pins GPIO and the 3 pins are default pull high with input mode.

When the serial port had activated (running probe()), we'll transform the 3 pins from GPIO function publicly to control Tranceiver privately use.

I'm not sure I understand what you're saying here.

Quoted 4 lines

We'll default set to 0/0/1 for control transceiver to RS232 mode.

Otherwise, If the serial port is not active, the 3 pins is in GPIO mode and controlled by global GPIO device with VID/PID: 2c42/16f8.

Does this mean that you can control the three GPIOs either through the serial device or through the gpio-control device (which are two separate USB devices)?

Quoted 26 lines
---
 drivers/usb/serial/f81232.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
drivers/usb/serial/f81232.c +9 -0
index 36a17aedc2ae..01cb5a5ea1d2 100644
@@ -96,6 +96,15 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 #define F81534A_TRIGGER_MULTPILE_4X	BIT(3)
 #define F81534A_FIFO_128BYTE		(BIT(1) | BIT(0))
 
+/* Serial port self GPIO control, 2bytes [control&output data][input data] */
+#define F81534A_GPIO_REG		0x10e
+#define F81534A_GPIO_MODE2_DIR		BIT(6) /* 1: input, 0: output */
+#define F81534A_GPIO_MODE1_DIR		BIT(5)
+#define F81534A_GPIO_MODE0_DIR		BIT(4)
+#define F81534A_GPIO_MODE2_OUTPUT	BIT(2)
+#define F81534A_GPIO_MODE1_OUTPUT	BIT(1)
+#define F81534A_GPIO_MODE0_OUTPUT	BIT(0)
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;

drivers/usb/serial/f81232.c static int f81232_port_probe(struct usb_serial_port *port) · line 884

Quoted 10 lines
drivers/usb/serial/f81232.c +7 -0
@@ -866,6 +875,14 @@ static int f81232_port_probe(struct usb_serial_port *port)
 
 static int f81534a_port_probe(struct usb_serial_port *port)
 {
+	int status;
+
+	/* tri-state with pull-high, default RS232 Mode */
+	status = f81232_set_register(port, F81534A_GPIO_REG,
+					F81534A_GPIO_MODE2_DIR);
+	if (status)
+		return status;

Ok, so you reset the tranceiver config on every probe.

Are the three GPIOs always connected to one particular tranceiver, or are they truly general purpose?

In the latter case, it doesn't seem like a good idea to drive pins 0 and 1 low here as you have know idea what they're used for.

drivers/usb/serial/f81232.c static int f81232_port_probe(struct usb_serial_port *port) · line 887

Quoted 3 lines
drivers/usb/serial/f81232.c +1 -0
+
 	return f81232_port_probe(port);
 }

Johan

#10 lore raw

Re: [PATCH V2 5/7] USB: serial: f81232: Set F81534A serial port with RS232 mode

Hi Johan,

Johan Hovold 於 2019/10/23 下午 07:53 寫道:

Quoted 10 lines · Ji-Ze Hong (Peter Hong)
Quoted 6 lines

The Fintek F81532A/534A/535/536 is USB-to-2/4/8/12 serial ports device and the serial ports are default disabled. Each port contains max 3 pins GPIO and the 3 pins are default pull high with input mode.

When the serial port had activated (running probe()), we'll transform the 3 pins from GPIO function publicly to control Tranceiver privately use.

I'm not sure I understand what you're saying here.

Quoted 9 lines
Quoted 4 lines

We'll default set to 0/0/1 for control transceiver to RS232 mode.

Otherwise, If the serial port is not active, the 3 pins is in GPIO mode and controlled by global GPIO device with VID/PID: 2c42/16f8.

Does this mean that you can control the three GPIOs either through the serial device or through the gpio-control device (which are two separate USB devices)?

Yes, when 1 F81534A connect to Host, it'll report device as following.
virtual HUB
GPIO Device.
serial port 1
...
serial port n

The link are F81534A pin-out:

	https://imgur.com/a/AZHqQ1N

So we can control F81534A series all GPIO pins via GPIO Device. Serial ports are also control MODE0_x, MODE1_x, MODE2_x (e.g. UART1 MODE0_1, MODE1_1, MODE2_1), but when Serial ports is h/w disabled (DTR pull low), the mode pin will change to GPIO pin.

Quoted 7 lines

Ok, so you reset the tranceiver config on every probe.

Are the three GPIOs always connected to one particular tranceiver, or are they truly general purpose?

In the latter case, it doesn't seem like a good idea to drive pins 0 and 1 low here as you have know idea what they're used for.

If we want to change the mode pin to GPIO pin, it need do h/w disable. It the serial ports are activated, the 3 pin will be mode pin and set default 0/0/1 to RS232 mode due to this driver not implement RS422/485 currently.

Thanks

Signature · 2 lines
With Best Regards,
Peter Hong
maintainer
#11 lore raw

Re: [PATCH V2 5/7] USB: serial: f81232: Set F81534A serial port with RS232 mode

Hi Peter,

Sorry about the late reply. Had a change to look into this again today.

Quoted 22 lines · Ji-Ze Hong (Peter Hong)

Hi Johan,

Johan Hovold 於 2019/10/23 下午 07:53 寫道:

Quoted 10 lines · Ji-Ze Hong (Peter Hong)
Quoted 6 lines

The Fintek F81532A/534A/535/536 is USB-to-2/4/8/12 serial ports device and the serial ports are default disabled. Each port contains max 3 pins GPIO and the 3 pins are default pull high with input mode.

When the serial port had activated (running probe()), we'll transform the 3 pins from GPIO function publicly to control Tranceiver privately use.

I'm not sure I understand what you're saying here.

Quoted 8 lines
Quoted 4 lines

We'll default set to 0/0/1 for control transceiver to RS232 mode.

Otherwise, If the serial port is not active, the 3 pins is in GPIO mode and controlled by global GPIO device with VID/PID: 2c42/16f8.

Does this mean that you can control the three GPIOs either through the serial device or through the gpio-control device (which are two separate USB devices)?

Quoted 6 lines

Yes, when 1 F81534A connect to Host, it'll report device as following.
virtual HUB
GPIO Device.
serial port 1
...
serial port n

Could you post lsusb -v output for this with a couple of UARTs enabled?

Quoted 2 lines

The link are F81534A pin-out:

	https://imgur.com/a/AZHqQ1N

Do you have a datasheet for the device?

I think I'm starting to get an idea of how this work, but I really don't like having to spend this much time on detective work just to understand how the hw works.

Quoted 4 lines

So we can control F81534A series all GPIO pins via GPIO Device. Serial ports are also control MODE0_x, MODE1_x, MODE2_x (e.g. UART1 MODE0_1, MODE1_1, MODE2_1), but when Serial ports is h/w disabled (DTR pull low), the mode pin will change to GPIO pin.

So you tie a ports DTR pin, even though it's normally an output, and use that at boot to determine whether the UART should be enabled or not?

And the GPIO device can only control a pin if the corresponding port is disabled?

Can you read back the enable state of each port?

Quoted 5 lines
Quoted 5 lines

Ok, so you reset the tranceiver config on every probe.

Are the three GPIOs always connected to one particular tranceiver, or are they truly general purpose?

Quoted 7 lines
Quoted 2 lines

In the latter case, it doesn't seem like a good idea to drive pins 0 and 1 low here as you have know idea what they're used for.

If we want to change the mode pin to GPIO pin, it need do h/w disable. It the serial ports are activated, the 3 pin will be mode pin and set default 0/0/1 to RS232 mode due to this driver not implement RS422/485 currently.

What about devices using a different tranceiver? Should the state of the mode pins ultimately be tied to VID/PID (can your customers change VID/PID)?

Johan

A message that is not in the archive (sent off-list or not yet received): [email protected]

maintainer
#13 lore raw

Re: [PATCH V2 5/7] USB: serial: f81232: Set F81534A serial port with RS232 mode

Quoted 17 lines · Ji-Ze Hong (Peter Hong)

Hi Johan,

Johan Hovold 於 2020/1/8 下午 10:35 寫道:

Quoted 8 lines
Quoted 6 lines

Yes, when 1 F81534A connect to Host, it'll report device as following.
virtual HUB
GPIO Device.
serial port 1
...
serial port n

Could you post lsusb -v output for this with a couple of UARTs enabled?

The following lsusb log is F81536 informations
2c42:1608 => HUB
2c42:16f8 => GPIO device
2c42:163x => UART (need driver enable)

Quoted 5 lines

*after insmod driver and wait for complete

Bus 001 Device 053: ID 2c42:1636
Bus 001 Device 044: ID 2c42:16f8
Bus 001 Device 043: ID 2c42:1608

Can you post verbose ("lsusb -v") output for the three device types for completeness?

Quoted 11 lines
Quoted 8 lines
Quoted 2 lines

The link are F81534A pin-out:

	https://imgur.com/a/AZHqQ1N

Do you have a datasheet for the device?

I think I'm starting to get an idea of how this work, but I really don't like having to spend this much time on detective work just to understand how the hw works.

The following link is F81536 spec:
https://drive.google.com/drive/folders/1oA8DvpevFXoTLCDfPZHzaBWKr32ch5xc?usp=sharing

Thanks!

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines

So we can control F81534A series all GPIO pins via GPIO Device. Serial ports are also control MODE0_x, MODE1_x, MODE2_x (e.g. UART1 MODE0_1, MODE1_1, MODE2_1), but when Serial ports is h/w disabled (DTR pull low), the mode pin will change to GPIO pin.

So you tie a ports DTR pin, even though it's normally an output, and use that at boot to determine whether the UART should be enabled or not?

Quoted 8 lines
Quoted 4 lines

And the GPIO device can only control a pin if the corresponding port is disabled?

Can you read back the enable state of each port?

DTR pin of the F81534A series are strap pin on power on, when IC detect it pulled to low, the UART device can't enable and DTR change to input mode.

Can you read back the state of the DTR pin when pulled low? So that you can determine which UARTs have been disabled in hardware?

Quoted 3 lines

I can read the UART enable state from GPIO Device, so I can do when the GPIO is associated with UART enabled, change it as output only otherwise can be set to input/output. Is this OK ??

I'm leaning more towards not exporting this as a gpio device at all. It's clear from the datasheet (and your implementation) that these pins are supposed to be used with your own tranceivers. You can start with only supporting RS232, and then we can discuss an interface for switching modes later.

Quoted 6 lines
Quoted 4 lines

What about devices using a different tranceiver? Should the state of the mode pins ultimately be tied to VID/PID (can your customers change VID/PID)?

Our device VID/PID is changeable, but we assume don't change it.

Ok, then I guess we must assume that the MODE pins are only connected to your tranceivers and hardcoding the various configurations is fine.

Johan

#14 lore raw

Re: [PATCH V2 5/7] USB: serial: f81232: Set F81534A serial port with RS232 mode

Hi Johan,

Johan Hovold 於 2020/1/13 下午 11:17 寫道:

Quoted 7 lines · Ji-Ze Hong (Peter Hong)
Quoted 3 lines

Bus 001 Device 053: ID 2c42:1636
Bus 001 Device 044: ID 2c42:16f8
Bus 001 Device 043: ID 2c42:1608

Can you post verbose ("lsusb -v") output for the three device types for completeness?

Bus 001 Device 007: ID 2c42:1608
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            9 Hub
  bDeviceSubClass         0 Unused
  bDeviceProtocol         1 Single TT
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1608
  bcdDevice           80.ff
  iManufacturer           0
  iProduct                1 FINTEK_USB2.0 HUB
  iSerial                 0
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 25
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xe0
Self Powered
Remote Wakeup
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 9 Hub
bInterfaceSubClass 0 Unused
bInterfaceProtocol 0 Full speed (or root) hub
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0002 1x 2 bytes
bInterval 12
Hub Descriptor:

  bLength              10
  bDescriptorType      41
  nNbrPorts            13

wHubCharacteristic 0x00e9
Per-port power switching
Per-port overcurrent protection
TT think time 32 FS bits
Port indicators
bPwrOn2PwrGood 8 * 2 milli seconds
bHubContrCurrent 100 milli Ampere
DeviceRemovable 0x03 0xc0
PortPwrCtrlMask 0xff 0xa2
Hub Port Status:
Port 1: 0000.0503 highspeed power enable connect Port 2: 0000.0503 highspeed power enable connect Port 3: 0000.0503 highspeed power enable connect Port 4: 0000.0503 highspeed power enable connect Port 5: 0000.0503 highspeed power enable connect Port 6: 0000.0503 highspeed power enable connect Port 7: 0000.0503 highspeed power enable connect Port 8: 0000.0503 highspeed power enable connect Port 9: 0000.0503 highspeed power enable connect Port 10: 0000.0503 highspeed power enable connect Port 11: 0000.0503 highspeed power enable connect Port 12: 0000.0503 highspeed power enable connect Port 13: 0000.0503 highspeed power enable connect
Device Qualifier (for other device speed):
bLength 10
bDescriptorType 6
bcdUSB 2.00

  bDeviceClass            9 Hub
  bDeviceSubClass         0 Unused
  bDeviceProtocol         0 Full speed (or root) hub

bMaxPacketSize0 64
bNumConfigurations 1
Device Status: 0x0001
Self Powered

Bus 001 Device 008: ID 2c42:16f8
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x16f8
  bcdDevice           80.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3 88635600168801
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 18
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Device Status: 0x0000
(Bus Powered)

Bus 001 Device 016: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           88.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 015: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           87.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 014: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           86.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 013: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           85.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 012: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           84.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 011: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           83.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 010: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           82.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 009: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           81.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 020: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           8c.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 019: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           8b.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 018: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           8a.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Bus 001 Device 017: ID 2c42:1636
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00

  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x2c42
  idProduct          0x1636
  bcdDevice           89.00
  iManufacturer           1 FINTEK
  iProduct                2 USB TO UART BRIDGE
  iSerial                 3
  bNumConfigurations      1

Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 0 (Defined at Interface level)
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

Can you read back the enable state of each port?

DTR pin of the F81534A series are strap pin on power on, when IC detect it pulled to low, the UART device can't enable and DTR change to input mode.

Can you read back the state of the DTR pin when pulled low? So that you can determine which UARTs have been disabled in hardware?

If the DTR pin pulled low, the UART device always can't be enabled. We can read the port en/disabled infomation in GPIO device only.

Quoted 6 lines

I'm leaning more towards not exporting this as a gpio device at all. It's clear from the datasheet (and your implementation) that these pins are supposed to be used with your own tranceivers. You can start with only supporting RS232, and then we can discuss an interface for switching modes later.

OK, I'll send patch v3 only with UART & device enable function after clarify all issues.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Our device VID/PID is changeable, but we assume don't change it.

Ok, then I guess we must assume that the MODE pins are only connected to your tranceivers and hardcoding the various configurations is fine.

Agree

Signature · 2 lines
With Best Regards,
Peter Hong
#15 lore raw

PATCH v2 6/7 USB: serial: f81232: Add generator for F81534A

In reply to Ji-Ze Hong (Peter Hong)

The Fintek F81534A series is contains 1 HUB / 1 GPIO device / n UARTs, but the UART is default disable and need enabled by GPIO device(2c42/16F8).

When F81534A plug to host, we can only see 1 HUB & 1 GPIO device and we need write 0x8fff to GPIO device register F81534A_CMD_ENABLE_PORT(116h) to enable all available serial ports.

---
 drivers/usb/serial/f81232.c | 135 +++++++++++++++++++++++++++++++++++-
 1 file changed, 134 insertions(+), 1 deletion(-)
drivers/usb/serial/f81232.c +134 -1
index 01cb5a5ea1d2..82cc1e6cff62 100644
@@ -36,6 +36,9 @@
 	{ USB_DEVICE(0x2c42, 0x1635) },	/* 8 port UART device */ \
 	{ USB_DEVICE(0x2c42, 0x1636) }	/* 12 port UART device */
 
+#define F81534A_CTRL_ID		\
+	{ USB_DEVICE(0x2c42, 0x16f8) }	/* Global control device */
+
 static const struct usb_device_id id_table[] = {
 	F81232_ID,
 	{ }					/* Terminating entry */
@@ -46,6 +49,11 @@ static const struct usb_device_id f81534a_id_table[] = {
 	{ }					/* Terminating entry */
 };
 
+static const struct usb_device_id f81534a_ctrl_id_table[] = {
+	F81534A_CTRL_ID,
+	{ }					/* Terminating entry */
+};
+
 static const struct usb_device_id all_serial_id_table[] = {
 	F81232_ID,
 	F81534A_SERIES_ID,
@@ -105,6 +113,8 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 #define F81534A_GPIO_MODE1_OUTPUT	BIT(1)
 #define F81534A_GPIO_MODE0_OUTPUT	BIT(0)
 
+#define F81534A_CMD_ENABLE_PORT		0x116
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;
@@ -853,6 +863,95 @@ static void f81232_lsr_worker(struct work_struct *work)
 		dev_warn(&port->dev, "read LSR failed: %d\n", status);
 }
 
+static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size,
+					void *val)
+{
+	int retry = F81534A_ACCESS_REG_RETRY;
+	int status;
+	u8 *tmp;
+
+	tmp = kmalloc(size, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	memcpy(tmp, val, size);
+
+	while (retry--) {
+		status = usb_control_msg(dev,
+					usb_sndctrlpipe(dev, 0),
+					F81534A_REGISTER_REQUEST,
+					F81534A_SET_REGISTER,
+					reg,
+					0,
+					tmp,
+					size,
+					USB_CTRL_SET_TIMEOUT);
+		if (status != size) {
+			status = usb_translate_errors(status);
+			if (status == -EIO)
+				continue;
+
+			status = -EIO;
+		} else {
+			status = 0;
+		}
+
+		break;
+	}
+
+	if (status) {
+		dev_err(&dev->dev, "set ctrl reg: %x, failed status: %d\n", reg,
+				status);
+	}
+
+	kfree(tmp);
+	return status;
+}
+
+static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	unsigned char enable[2];
+	int status;
+
+	/* enable all available serial ports */
+	enable[0] = 0xff;
+	enable[1] = 0x8f;
+
+	status = f81534a_ctrl_set_register(dev, F81534A_CMD_ENABLE_PORT,
+			sizeof(enable), enable);
+	if (status)
+		dev_warn(&dev->dev, "set CMD_ENABLE_PORT failed: %d\n", status);
+
+	return status;
+}
+
+static int f81534a_ctrl_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+
+	status = f81534a_ctrl_enable_all_ports(intf);
+	if (status)
+		return status;
+
+	dev = usb_get_dev(dev);
+	return 0;
+}
+
+static void f81534a_ctrl_disconnect(struct usb_interface *intf)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+
+	usb_put_dev(dev);
+}
+
+static int f81534a_ctrl_resume(struct usb_interface *intf)
+{
+	return f81534a_ctrl_enable_all_ports(intf);
+}
+
 static int f81232_port_probe(struct usb_serial_port *port)
 {
 	struct f81232_private *priv;
@@ -980,7 +1079,41 @@ static struct usb_serial_driver * const serial_drivers[] = {
 	NULL,
 };
 
-module_usb_serial_driver(serial_drivers, all_serial_id_table);
+static struct usb_driver f81534a_ctrl_driver = {
+	.name =		"f81534a_ctrl",
+	.id_table =	f81534a_ctrl_id_table,
+	.probe =	f81534a_ctrl_probe,
+	.disconnect =	f81534a_ctrl_disconnect,
+	.resume =	f81534a_ctrl_resume,
+};
+
+static int __init f81232_init(void)
+{
+	int status;
+
+	status = usb_register_driver(&f81534a_ctrl_driver, THIS_MODULE,
+			KBUILD_MODNAME);
+	if (status)
+		return status;
+
+	status = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME,
+			all_serial_id_table);
+	if (status) {
+		usb_deregister(&f81534a_ctrl_driver);
+		return status;
+	}
+
+	return 0;
+}
+
+static void __exit f81232_exit(void)
+{
+	usb_serial_deregister_drivers(serial_drivers);
+	usb_deregister(&f81534a_ctrl_driver);
+}
+
+module_init(f81232_init);
+module_exit(f81232_exit);
 
 MODULE_DESCRIPTION("Fintek F81232/532A/534A/535/536 USB to serial driver");
 MODULE_AUTHOR("Greg Kroah-Hartman <[email protected]>");
Signature · 1 line
2.17.1
maintainer
#16 lore raw

Re: [PATCH V2 6/7] USB: serial: f81232: Add generator for F81534A

Quoted 39 lines · Ji-Ze Hong (Peter Hong)

The Fintek F81534A series is contains 1 HUB / 1 GPIO device / n UARTs, but the UART is default disable and need enabled by GPIO device(2c42/16F8).

When F81534A plug to host, we can only see 1 HUB & 1 GPIO device and we need write 0x8fff to GPIO device register F81534A_CMD_ENABLE_PORT(116h) to enable all available serial ports.

---
 drivers/usb/serial/f81232.c | 135 +++++++++++++++++++++++++++++++++++-
 1 file changed, 134 insertions(+), 1 deletion(-)
drivers/usb/serial/f81232.c +8 -0
index 01cb5a5ea1d2..82cc1e6cff62 100644
@@ -36,6 +36,9 @@
 	{ USB_DEVICE(0x2c42, 0x1635) },	/* 8 port UART device */ \
 	{ USB_DEVICE(0x2c42, 0x1636) }	/* 12 port UART device */
 
+#define F81534A_CTRL_ID		\
+	{ USB_DEVICE(0x2c42, 0x16f8) }	/* Global control device */
+
 static const struct usb_device_id id_table[] = {
 	F81232_ID,
 	{ }					/* Terminating entry */
@@ -46,6 +49,11 @@ static const struct usb_device_id f81534a_id_table[] = {
 	{ }					/* Terminating entry */
 };
 
+static const struct usb_device_id f81534a_ctrl_id_table[] = {
+	F81534A_CTRL_ID,
+	{ }					/* Terminating entry */
+};
+
 static const struct usb_device_id all_serial_id_table[] = {
 	F81232_ID,
 	F81534A_SERIES_ID,

drivers/usb/serial/f81232.c MODULE_DEVICE_TABLE(usb, all_serial_id_table); · line 116

Quoted 4 lines
drivers/usb/serial/f81232.c +1 -0
@@ -105,6 +113,8 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 #define F81534A_GPIO_MODE1_OUTPUT	BIT(1)
 #define F81534A_GPIO_MODE0_OUTPUT	BIT(0)
 
+#define F81534A_CMD_ENABLE_PORT		0x116

Maybe use a distinct prefix for requests to the control device (e.g. F81534A_CTRL_).

Quoted 10 lines
drivers/usb/serial/f81232.c +3 -0
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;
@@ -853,6 +863,95 @@ static void f81232_lsr_worker(struct work_struct *work)
 		dev_warn(&port->dev, "read LSR failed: %d\n", status);
 }
 
+static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size,
+					void *val)

drivers/usb/serial/f81232.c static void f81232_lsr_worker(struct work_struct *work) · line 877

Quoted 10 lines
drivers/usb/serial/f81232.c +10 -0
+{
+	int retry = F81534A_ACCESS_REG_RETRY;
+	int status;
+	u8 *tmp;
+
+	tmp = kmalloc(size, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	memcpy(tmp, val, size);

Use kmemdup().

Quoted 5 lines
drivers/usb/serial/f81232.c +5 -0
+
+	while (retry--) {
+		status = usb_control_msg(dev,
+					usb_sndctrlpipe(dev, 0),
+					F81534A_REGISTER_REQUEST,

drivers/usb/serial/f81232.c static void f81232_lsr_worker(struct work_struct *work) · line 892

Quoted 10 lines
drivers/usb/serial/f81232.c +10 -0
+					F81534A_SET_REGISTER,
+					reg,
+					0,
+					tmp,
+					size,
+					USB_CTRL_SET_TIMEOUT);
+		if (status != size) {
+			status = usb_translate_errors(status);
+			if (status == -EIO)
+				continue;

This will retry on short transfers, is that what you intended?

Quoted 17 lines
drivers/usb/serial/f81232.c +17 -0
+
+			status = -EIO;
+		} else {
+			status = 0;
+		}
+
+		break;
+	}
+
+	if (status) {
+		dev_err(&dev->dev, "set ctrl reg: %x, failed status: %d\n", reg,
+				status);
+	}
+
+	kfree(tmp);
+	return status;
+}

drivers/usb/serial/f81232.c static void f81232_lsr_worker(struct work_struct *work) · line 919

Quoted 10 lines
drivers/usb/serial/f81232.c +10 -0
+
+static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	unsigned char enable[2];
+	int status;
+
+	/* enable all available serial ports */
+	enable[0] = 0xff;
+	enable[1] = 0x8f;

What are these magic constants?

Quoted 10 lines
drivers/usb/serial/f81232.c +10 -0
+
+	status = f81534a_ctrl_set_register(dev, F81534A_CMD_ENABLE_PORT,
+			sizeof(enable), enable);
+	if (status)
+		dev_warn(&dev->dev, "set CMD_ENABLE_PORT failed: %d\n", status);
+
+	return status;
+}
+
+static int f81534a_ctrl_probe(struct usb_interface *intf,

drivers/usb/serial/f81232.c static void f81232_lsr_worker(struct work_struct *work) · line 939

Quoted 10 lines
drivers/usb/serial/f81232.c +10 -0
+				const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+
+	status = f81534a_ctrl_enable_all_ports(intf);
+	if (status)
+		return status;
+
+	dev = usb_get_dev(dev);

This isn't strictly needed.

drivers/usb/serial/f81232.c static void f81232_lsr_worker(struct work_struct *work) · line 941

Quoted 2 lines
drivers/usb/serial/f81232.c +2 -0
+	return 0;
+}

Johan

maintainer
#17 lore raw

Re: [PATCH V2 6/7] USB: serial: f81232: Add generator for F81534A

In reply to Ji-Ze Hong (Peter Hong)
Quoted 28 lines · Ji-Ze Hong (Peter Hong)

The Fintek F81534A series is contains 1 HUB / 1 GPIO device / n UARTs, but the UART is default disable and need enabled by GPIO device(2c42/16F8).

When F81534A plug to host, we can only see 1 HUB & 1 GPIO device and we need write 0x8fff to GPIO device register F81534A_CMD_ENABLE_PORT(116h) to enable all available serial ports.

---
 drivers/usb/serial/f81232.c | 135 +++++++++++++++++++++++++++++++++++-
 1 file changed, 134 insertions(+), 1 deletion(-)
drivers/usb/serial/f81232.c +3 -0
index 01cb5a5ea1d2..82cc1e6cff62 100644
@@ -36,6 +36,9 @@
 	{ USB_DEVICE(0x2c42, 0x1635) },	/* 8 port UART device */ \
 	{ USB_DEVICE(0x2c42, 0x1636) }	/* 12 port UART device */
 
+#define F81534A_CTRL_ID		\
+	{ USB_DEVICE(0x2c42, 0x16f8) }	/* Global control device */
+
 static const struct usb_device_id id_table[] = {
 	F81232_ID,
 	{ }					/* Terminating entry */
@@ -46,6 +49,11 @@ static const struct usb_device_id f81534a_id_table[] = {
 	{ }					/* Terminating entry */

drivers/usb/serial/f81232.c static const struct usb_device_id f81534a_id_table[] = { · line 59

Quoted 10 lines
drivers/usb/serial/f81232.c +5 -0
 };
 
+static const struct usb_device_id f81534a_ctrl_id_table[] = {
+	F81534A_CTRL_ID,
+	{ }					/* Terminating entry */
+};
+
 static const struct usb_device_id all_serial_id_table[] = {
 	F81232_ID,
 	F81534A_SERIES_ID,

Forgot to mention: don't you want F81534A_CTRL_ID in the combined (MODULE_DEVICE_TABLE) as well?

Johan

#18 lore raw

PATCH v2 7/7 USB: serial: f81232: Add gpiolib to GPIO device

In reply to Ji-Ze Hong (Peter Hong)

The Fintek F81534A series contains 3 GPIOs per UART and The max GPIOs is 12x3 = 36 GPIOs and this patch will implements GPIO device as a gpiochip to control all GPIO pins even transforms to transceiver pins.

---
 drivers/usb/serial/f81232.c | 249 ++++++++++++++++++++++++++++++++++++
 1 file changed, 249 insertions(+)
drivers/usb/serial/f81232.c +249 -0
index 82cc1e6cff62..dc9b28738b80 100644
@@ -18,6 +18,7 @@
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
+#include <linux/gpio.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <linux/serial_reg.h>
@@ -104,6 +105,8 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 #define F81534A_TRIGGER_MULTPILE_4X	BIT(3)
 #define F81534A_FIFO_128BYTE		(BIT(1) | BIT(0))
 
+#define F81534A_MAX_PORT		12
+
 /* Serial port self GPIO control, 2bytes [control&output data][input data] */
 #define F81534A_GPIO_REG		0x10e
 #define F81534A_GPIO_MODE2_DIR		BIT(6) /* 1: input, 0: output */
@@ -115,6 +118,13 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 
 #define F81534A_CMD_ENABLE_PORT		0x116
 
+/*
+ * Control device global GPIO control,
+ * 2bytes [control&output data][input data]
+ */
+#define F81534A_CTRL_GPIO_REG		0x1601
+#define F81534A_CTRL_GPIO_MAX_PIN	3
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;
@@ -126,6 +136,12 @@ struct f81232_private {
 	struct usb_serial_port *port;
 };
 
+struct f81534a_ctrl_private {
+	struct usb_interface *intf;
+	struct gpio_chip chip;
+	struct mutex lock;
+};
+
 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 };
@@ -863,6 +879,50 @@ static void f81232_lsr_worker(struct work_struct *work)
 		dev_warn(&port->dev, "read LSR failed: %d\n", status);
 }
 
+static int f81534a_ctrl_get_register(struct usb_device *dev, u16 reg, u16 size,
+					void *val)
+{
+	int retry = F81534A_ACCESS_REG_RETRY;
+	int status;
+	u8 *tmp;
+
+	tmp = kmalloc(size, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	while (retry--) {
+		status = usb_control_msg(dev,
+					usb_rcvctrlpipe(dev, 0),
+					F81534A_REGISTER_REQUEST,
+					F81534A_GET_REGISTER,
+					reg,
+					0,
+					tmp,
+					size,
+					USB_CTRL_GET_TIMEOUT);
+		if (status != size) {
+			status = usb_translate_errors(status);
+			if (status == -EIO)
+				continue;
+
+			status = -EIO;
+		} else {
+			status = 0;
+			memcpy(val, tmp, size);
+		}
+
+		break;
+	}
+
+	if (status) {
+		dev_err(&dev->dev, "get reg: %x, failed status: %d\n", reg,
+				status);
+	}
+
+	kfree(tmp);
+	return status;
+}
+
 static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size,
 					void *val)
 {
@@ -908,6 +968,182 @@ static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size,
 	return status;
 }
 
+#ifdef CONFIG_GPIOLIB
+static int f81534a_ctrl_set_mask_register(struct usb_device *dev, u16 reg,
+		u8 mask, u8 val)
+{
+	int status;
+	u8 tmp;
+
+	status = f81534a_ctrl_get_register(dev, reg, 1, &tmp);
+	if (status)
+		return status;
+
+
+	tmp = (tmp & ~mask) | (val & mask);
+
+	status = f81534a_ctrl_set_register(dev, reg, 1, &tmp);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+static int f81534a_gpio_get(struct gpio_chip *chip, unsigned int gpio_num)
+{
+	struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+	struct usb_interface *intf = priv->intf;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+	u8 tmp[2];
+	int set;
+	int idx;
+	int reg;
+
+	set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+	idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+	reg = F81534A_CTRL_GPIO_REG + set;
+
+	mutex_lock(&priv->lock);
+
+	status = f81534a_ctrl_get_register(dev, reg, sizeof(tmp), tmp);
+	if (status) {
+		mutex_unlock(&priv->lock);
+		return status;
+	}
+
+	mutex_unlock(&priv->lock);
+
+	return !!(tmp[1] & BIT(idx));
+}
+
+static int f81534a_gpio_direction_in(struct gpio_chip *chip,
+					unsigned int gpio_num)
+{
+	struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+	struct usb_interface *intf = priv->intf;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+	int set;
+	int idx;
+	int reg;
+	u8 mask;
+
+	set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+	idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+	mask = F81534A_GPIO_MODE0_DIR << idx;
+	reg = F81534A_CTRL_GPIO_REG + set;
+
+	mutex_lock(&priv->lock);
+	status = f81534a_ctrl_set_mask_register(dev, reg, mask, mask);
+	mutex_unlock(&priv->lock);
+
+	return status;
+}
+
+static int f81534a_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned int gpio_num, int val)
+{
+	struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+	struct usb_interface *intf = priv->intf;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+	int set;
+	int idx;
+	int reg;
+	u8 mask;
+	u8 data;
+
+	set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+	idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+	mask = (F81534A_GPIO_MODE0_DIR << idx) | BIT(idx);
+	reg = F81534A_CTRL_GPIO_REG + set;
+	data = val ? BIT(idx) : 0;
+
+	mutex_lock(&priv->lock);
+	status = f81534a_ctrl_set_mask_register(dev, reg, mask, data);
+	mutex_unlock(&priv->lock);
+
+	return status;
+}
+
+static void f81534a_gpio_set(struct gpio_chip *chip, unsigned int gpio_num,
+				int val)
+{
+	f81534a_gpio_direction_out(chip, gpio_num, val);
+}
+
+static int f81534a_gpio_get_direction(struct gpio_chip *chip,
+				unsigned int gpio_num)
+{
+	struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+	struct usb_interface *intf = priv->intf;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+	u8 tmp[2];
+	int set;
+	int idx;
+	int reg;
+	u8 mask;
+
+	set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+	idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+	mask = F81534A_GPIO_MODE0_DIR << idx;
+	reg = F81534A_CTRL_GPIO_REG + set;
+
+	mutex_lock(&priv->lock);
+
+	status = f81534a_ctrl_get_register(dev, reg, sizeof(tmp), tmp);
+	if (status) {
+		mutex_unlock(&priv->lock);
+		return status;
+	}
+
+	mutex_unlock(&priv->lock);
+
+	if (tmp[0] & mask)
+		return GPIOF_DIR_IN;
+
+	return GPIOF_DIR_OUT;
+}
+
+static int f81534a_prepare_gpio(struct usb_interface *intf)
+{
+	struct f81534a_ctrl_private *priv = usb_get_intfdata(intf);
+	int status;
+
+	priv->chip.parent = &intf->dev;
+	priv->chip.owner = THIS_MODULE;
+	priv->chip.get_direction = f81534a_gpio_get_direction,
+	priv->chip.get = f81534a_gpio_get;
+	priv->chip.direction_input = f81534a_gpio_direction_in;
+	priv->chip.set = f81534a_gpio_set;
+	priv->chip.direction_output = f81534a_gpio_direction_out;
+	priv->chip.label = "f81534a";
+	priv->chip.can_sleep = true;
+	/* M0(SD)/M1/M2 */
+	priv->chip.ngpio = F81534A_CTRL_GPIO_MAX_PIN * F81534A_MAX_PORT;
+	priv->chip.base = -1;
+
+	priv->intf = intf;
+	mutex_init(&priv->lock);
+
+	status = devm_gpiochip_add_data(&intf->dev, &priv->chip, priv);
+	if (status) {
+		dev_err(&intf->dev, "failed to register gpiochip: %d\n",
+				status);
+		return status;
+	}
+
+	return 0;
+}
+#else
+static int f81534a_prepare_gpio(struct usb_interface *intf)
+{
+	return 0;
+}
+#endif
+
 static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
@@ -930,8 +1166,21 @@ static int f81534a_ctrl_probe(struct usb_interface *intf,
 				const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
+	struct f81534a_ctrl_private *priv;
 	int status;
 
+	priv = devm_kzalloc(&intf->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	usb_set_intfdata(intf, priv);
+	priv->intf = intf;
+
+	status = f81534a_prepare_gpio(intf);
+	if (status)
+		return status;
+
 	status = f81534a_ctrl_enable_all_ports(intf);
 	if (status)
 		return status;
Signature · 1 line
2.17.1
maintainer
#19 lore raw

Re: [PATCH V2 7/7] USB: serial: f81232: Add gpiolib to GPIO device

Quoted 3 lines · Ji-Ze Hong (Peter Hong)

The Fintek F81534A series contains 3 GPIOs per UART and The max GPIOs is 12x3 = 36 GPIOs and this patch will implements GPIO device as a gpiochip to control all GPIO pins even transforms to transceiver pins.

Depending to your answer to my question whether these pins are truly general purpose or not, this may not be the right interface.

Quoted 54 lines
---
 drivers/usb/serial/f81232.c | 249 ++++++++++++++++++++++++++++++++++++
 1 file changed, 249 insertions(+)
drivers/usb/serial/f81232.c +16 -0
index 82cc1e6cff62..dc9b28738b80 100644
@@ -18,6 +18,7 @@
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
+#include <linux/gpio.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <linux/serial_reg.h>
@@ -104,6 +105,8 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 #define F81534A_TRIGGER_MULTPILE_4X	BIT(3)
 #define F81534A_FIFO_128BYTE		(BIT(1) | BIT(0))
 
+#define F81534A_MAX_PORT		12
+
 /* Serial port self GPIO control, 2bytes [control&output data][input data] */
 #define F81534A_GPIO_REG		0x10e
 #define F81534A_GPIO_MODE2_DIR		BIT(6) /* 1: input, 0: output */
@@ -115,6 +118,13 @@ MODULE_DEVICE_TABLE(usb, all_serial_id_table);
 
 #define F81534A_CMD_ENABLE_PORT		0x116
 
+/*
+ * Control device global GPIO control,
+ * 2bytes [control&output data][input data]
+ */
+#define F81534A_CTRL_GPIO_REG		0x1601
+#define F81534A_CTRL_GPIO_MAX_PIN	3
+
 struct f81232_private {
 	struct mutex lock;
 	u8 modem_control;
@@ -126,6 +136,12 @@ struct f81232_private {
 	struct usb_serial_port *port;
 };
 
+struct f81534a_ctrl_private {
+	struct usb_interface *intf;
+	struct gpio_chip chip;
+	struct mutex lock;
+};
+
 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 };

drivers/usb/serial/f81232.c static void f81232_lsr_worker(struct work_struct *work) · line 883

Quoted 5 lines
drivers/usb/serial/f81232.c +2 -0
@@ -863,6 +879,50 @@ static void f81232_lsr_worker(struct work_struct *work)
 		dev_warn(&port->dev, "read LSR failed: %d\n", status);
 }
 
+static int f81534a_ctrl_get_register(struct usb_device *dev, u16 reg, u16 size,
+					void *val)

Looks like this one needs to go under CONFIG_GPIOLIB as well.

Quoted 179 lines
drivers/usb/serial/f81232.c +172 -0
+{
+	int retry = F81534A_ACCESS_REG_RETRY;
+	int status;
+	u8 *tmp;
+
+	tmp = kmalloc(size, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	while (retry--) {
+		status = usb_control_msg(dev,
+					usb_rcvctrlpipe(dev, 0),
+					F81534A_REGISTER_REQUEST,
+					F81534A_GET_REGISTER,
+					reg,
+					0,
+					tmp,
+					size,
+					USB_CTRL_GET_TIMEOUT);
+		if (status != size) {
+			status = usb_translate_errors(status);
+			if (status == -EIO)
+				continue;
+
+			status = -EIO;
+		} else {
+			status = 0;
+			memcpy(val, tmp, size);
+		}
+
+		break;
+	}
+
+	if (status) {
+		dev_err(&dev->dev, "get reg: %x, failed status: %d\n", reg,
+				status);
+	}
+
+	kfree(tmp);
+	return status;
+}
+
 static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size,
 					void *val)
 {
@@ -908,6 +968,182 @@ static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size,
 	return status;
 }
 
+#ifdef CONFIG_GPIOLIB
+static int f81534a_ctrl_set_mask_register(struct usb_device *dev, u16 reg,
+		u8 mask, u8 val)
+{
+	int status;
+	u8 tmp;
+
+	status = f81534a_ctrl_get_register(dev, reg, 1, &tmp);
+	if (status)
+		return status;
+
+
+	tmp = (tmp & ~mask) | (val & mask);
+
+	status = f81534a_ctrl_set_register(dev, reg, 1, &tmp);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+static int f81534a_gpio_get(struct gpio_chip *chip, unsigned int gpio_num)
+{
+	struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+	struct usb_interface *intf = priv->intf;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+	u8 tmp[2];
+	int set;
+	int idx;
+	int reg;
+
+	set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+	idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+	reg = F81534A_CTRL_GPIO_REG + set;
+
+	mutex_lock(&priv->lock);
+
+	status = f81534a_ctrl_get_register(dev, reg, sizeof(tmp), tmp);
+	if (status) {
+		mutex_unlock(&priv->lock);
+		return status;
+	}
+
+	mutex_unlock(&priv->lock);
+
+	return !!(tmp[1] & BIT(idx));
+}
+
+static int f81534a_gpio_direction_in(struct gpio_chip *chip,
+					unsigned int gpio_num)
+{
+	struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+	struct usb_interface *intf = priv->intf;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+	int set;
+	int idx;
+	int reg;
+	u8 mask;
+
+	set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+	idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+	mask = F81534A_GPIO_MODE0_DIR << idx;
+	reg = F81534A_CTRL_GPIO_REG + set;
+
+	mutex_lock(&priv->lock);
+	status = f81534a_ctrl_set_mask_register(dev, reg, mask, mask);
+	mutex_unlock(&priv->lock);
+
+	return status;
+}
+
+static int f81534a_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned int gpio_num, int val)
+{
+	struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+	struct usb_interface *intf = priv->intf;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+	int set;
+	int idx;
+	int reg;
+	u8 mask;
+	u8 data;
+
+	set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+	idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+	mask = (F81534A_GPIO_MODE0_DIR << idx) | BIT(idx);
+	reg = F81534A_CTRL_GPIO_REG + set;
+	data = val ? BIT(idx) : 0;
+
+	mutex_lock(&priv->lock);
+	status = f81534a_ctrl_set_mask_register(dev, reg, mask, data);
+	mutex_unlock(&priv->lock);
+
+	return status;
+}
+
+static void f81534a_gpio_set(struct gpio_chip *chip, unsigned int gpio_num,
+				int val)
+{
+	f81534a_gpio_direction_out(chip, gpio_num, val);
+}
+
+static int f81534a_gpio_get_direction(struct gpio_chip *chip,
+				unsigned int gpio_num)
+{
+	struct f81534a_ctrl_private *priv = gpiochip_get_data(chip);
+	struct usb_interface *intf = priv->intf;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int status;
+	u8 tmp[2];
+	int set;
+	int idx;
+	int reg;
+	u8 mask;
+
+	set = gpio_num / F81534A_CTRL_GPIO_MAX_PIN;
+	idx = gpio_num % F81534A_CTRL_GPIO_MAX_PIN;
+	mask = F81534A_GPIO_MODE0_DIR << idx;
+	reg = F81534A_CTRL_GPIO_REG + set;
+
+	mutex_lock(&priv->lock);
+
+	status = f81534a_ctrl_get_register(dev, reg, sizeof(tmp), tmp);
+	if (status) {
+		mutex_unlock(&priv->lock);
+		return status;
+	}

drivers/usb/serial/f81232.c static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size, · line 1110

Quoted 10 lines
drivers/usb/serial/f81232.c +10 -0
+
+	mutex_unlock(&priv->lock);
+
+	if (tmp[0] & mask)
+		return GPIOF_DIR_IN;
+
+	return GPIOF_DIR_OUT;
+}
+
+static int f81534a_prepare_gpio(struct usb_interface *intf)

Could you rename this f81534a_gpiochip_register or similar?

Quoted 8 lines
drivers/usb/serial/f81232.c +8 -0
+{
+	struct f81534a_ctrl_private *priv = usb_get_intfdata(intf);
+	int status;
+
+	priv->chip.parent = &intf->dev;
+	priv->chip.owner = THIS_MODULE;
+	priv->chip.get_direction = f81534a_gpio_get_direction,
+	priv->chip.get = f81534a_gpio_get;

drivers/usb/serial/f81232.c static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size, · line 1128

Quoted 10 lines
drivers/usb/serial/f81232.c +10 -0
+	priv->chip.direction_input = f81534a_gpio_direction_in;
+	priv->chip.set = f81534a_gpio_set;
+	priv->chip.direction_output = f81534a_gpio_direction_out;
+	priv->chip.label = "f81534a";
+	priv->chip.can_sleep = true;
+	/* M0(SD)/M1/M2 */
+	priv->chip.ngpio = F81534A_CTRL_GPIO_MAX_PIN * F81534A_MAX_PORT;
+	priv->chip.base = -1;
+
+	priv->intf = intf;

Maybe store the parent struct usb_device instead since that's what you end up using?

drivers/usb/serial/f81232.c static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size, · line 1129

Quoted 1 line
drivers/usb/serial/f81232.c +1 -0
+	mutex_init(&priv->lock);

Already initialised in probe() below. Same with priv->intf by the way.

drivers/usb/serial/f81232.c static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size, · line 1136

Quoted 7 lines
drivers/usb/serial/f81232.c +7 -0
+
+	status = devm_gpiochip_add_data(&intf->dev, &priv->chip, priv);
+	if (status) {
+		dev_err(&intf->dev, "failed to register gpiochip: %d\n",
+				status);
+		return status;
+	}

Have you tried disconnecting the device with gpios requested? This used to break gpiolib, but was fixed. Just want to make sure it hasn't regressed.

Quoted 25 lines
drivers/usb/serial/f81232.c +16 -0
+
+	return 0;
+}
+#else
+static int f81534a_prepare_gpio(struct usb_interface *intf)
+{
+	return 0;
+}
+#endif
+
 static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
@@ -930,8 +1166,21 @@ static int f81534a_ctrl_probe(struct usb_interface *intf,
 				const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
+	struct f81534a_ctrl_private *priv;
 	int status;
 
+	priv = devm_kzalloc(&intf->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);

drivers/usb/serial/f81232.c static int f81534a_ctrl_probe(struct usb_interface *intf, · line 1186

Quoted 10 lines
drivers/usb/serial/f81232.c +7 -0
+	usb_set_intfdata(intf, priv);
+	priv->intf = intf;
+
+	status = f81534a_prepare_gpio(intf);
+	if (status)
+		return status;
+
 	status = f81534a_ctrl_enable_all_ports(intf);
 	if (status)
 		return status;

Overall this all look much better now.

Thanks,
Johan

#20 lore raw

Re: [PATCH V2 7/7] USB: serial: f81232: Add gpiolib to GPIO device

Hi Johan,

Johan Hovold 於 2019/10/23 下午 08:22 寫道:

Quoted 7 lines · Ji-Ze Hong (Peter Hong)
Quoted 3 lines

The Fintek F81534A series contains 3 GPIOs per UART and The max GPIOs is 12x3 = 36 GPIOs and this patch will implements GPIO device as a gpiochip to control all GPIO pins even transforms to transceiver pins.

Depending to your answer to my question whether these pins are truly general purpose or not, this may not be the right interface.

Our F81534A series contains F81532A/534A/535/536. For the following link of F81534A pin-out:

	https://imgur.com/a/AZHqQ1N

We had 2 type about GPIO pins, MODEx_y & GPIOxx. All MODEx_y & GPIOxx are GPIOs and can be controlled by GPIO device, but they had some difference about usage.
MODEx_y:
1. 3 pins(x: 0/1/2) can be access by UART port y.
2. Used to control UART's transceiver normally, but it also can be configure as GPIO when UART disabled by H/W (DTR strap to GND).
GPIOxx:
1. Access only by GPIO device.

The series patch only support RS233 mode for all serial port, So we'll direct set all MODEx_y to (0/0/1) for our demo board for default. If user really want to use the pin, we had provide the gpiolib with GPIO device, but we'll recommend user to use GPIOxy first.

Is any suggest about this ? Could I maintain this for this series patch?

Quoted 11 lines

drivers/usb/serial/f81232.c static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size, · line 1136

Quoted 7 lines
drivers/usb/serial/f81232.c +7 -0
+
+	status = devm_gpiochip_add_data(&intf->dev, &priv->chip, priv);
+	if (status) {
+		dev_err(&intf->dev, "failed to register gpiochip: %d\n",
+				status);
+		return status;
+	}

Have you tried disconnecting the device with gpios requested? This used to break gpiolib, but was fixed. Just want to make sure it hasn't regressed.

I had try export GPIOs and detach the F81534A in kernel 5.0.0, it seems no problem. Is any link about this issue for me to do more test ?

Thanks

Signature · 2 lines
With Best Regards,
Peter Hong
maintainer
#21 lore raw

Re: [PATCH V2 7/7] USB: serial: f81232: Add gpiolib to GPIO device

Quoted 26 lines · Ji-Ze Hong (Peter Hong)

Hi Johan,

Johan Hovold 於 2019/10/23 下午 08:22 寫道:

Quoted 7 lines · Ji-Ze Hong (Peter Hong)
Quoted 3 lines

The Fintek F81534A series contains 3 GPIOs per UART and The max GPIOs is 12x3 = 36 GPIOs and this patch will implements GPIO device as a gpiochip to control all GPIO pins even transforms to transceiver pins.

Depending to your answer to my question whether these pins are truly general purpose or not, this may not be the right interface.

Our F81534A series contains F81532A/534A/535/536. For the following link of F81534A pin-out:

	https://imgur.com/a/AZHqQ1N

We had 2 type about GPIO pins, MODEx_y & GPIOxx. All MODEx_y & GPIOxx are GPIOs and can be controlled by GPIO device, but they had some difference about usage.
MODEx_y:
1. 3 pins(x: 0/1/2) can be access by UART port y.
2. Used to control UART's transceiver normally, but it also can be configure as GPIO when UART disabled by H/W (DTR strap to GND).
GPIOxx:
1. Access only by GPIO device.

Quoted 4 lines

The series patch only support RS233 mode for all serial port, So we'll direct set all MODEx_y to (0/0/1) for our demo board for default. If user really want to use the pin, we had provide the gpiolib with GPIO device, but we'll recommend user to use GPIOxy first.

Do you mean that you'd need to register a separate gpio chip per port in order to expose an interface for changing the MODEx_y pins for an enabled UART? Or can you do that through the "global" gpio device?

Quoted 1 line

Is any suggest about this ? Could I maintain this for this series patch?

I understood from your other mail that the gpio device would not be able to control the pins of an enabled port. In either case, I think you need to refuse a request for a pin that's already in use by the corresponding port.

Also is there a way to determine the number of available pins by detecting the chip/package type? I'm assuming not all 36 pins are always accessible?

Quoted 11 lines
Quoted 10 lines

drivers/usb/serial/f81232.c static int f81534a_ctrl_set_register(struct usb_device *dev, u16 reg, u16 size, · line 1136

Quoted 6 lines
drivers/usb/serial/f81232.c +6 -0
+	status = devm_gpiochip_add_data(&intf->dev, &priv->chip, priv);
+	if (status) {
+		dev_err(&intf->dev, "failed to register gpiochip: %d\n",
+				status);
+		return status;
+	}

Have you tried disconnecting the device with gpios requested? This used to break gpiolib, but was fixed. Just want to make sure it hasn't regressed.

Quoted 2 lines

I had try export GPIOs and detach the F81534A in kernel 5.0.0, it seems no problem. Is any link about this issue for me to do more test ?

Then it's hopefully fine. Thanks for verifying.

Johan

#22 lore raw

Re: [PATCH V2 7/7] USB: serial: f81232: Add gpiolib to GPIO device

Hi Johan,

Johan Hovold 於 2020/1/8 下午 10:46 寫道:

Quoted 13 lines · Ji-Ze Hong (Peter Hong)
Quoted 12 lines

We had 2 type about GPIO pins, MODEx_y & GPIOxx. All MODEx_y & GPIOxx are GPIOs and can be controlled by GPIO device, but they had some difference about usage.
MODEx_y:
1. 3 pins(x: 0/1/2) can be access by UART port y.
2. Used to control UART's transceiver normally, but it also can be configure as GPIO when UART disabled by H/W (DTR strap to GND).
GPIOxx:
1. Access only by GPIO device.

Quoted 8 lines
Quoted 4 lines

The series patch only support RS233 mode for all serial port, So we'll direct set all MODEx_y to (0/0/1) for our demo board for default. If user really want to use the pin, we had provide the gpiolib with GPIO device, but we'll recommend user to use GPIOxy first.

Do you mean that you'd need to register a separate gpio chip per port in order to expose an interface for changing the MODEx_y pins for an enabled UART? Or can you do that through the "global" gpio device?

No, I still implement the gpiolib in GPIO Device. Sorry for bad describe.

Quoted 6 lines
Quoted 1 line

Is any suggest about this ? Could I maintain this for this series patch?

I understood from your other mail that the gpio device would not be able to control the pins of an enabled port. In either case, I think you need to refuse a request for a pin that's already in use by the corresponding port.

OK, I'll change the code as previous mail as following:

I can read the UART enable state from GPIO Device, so I can do when the GPIO is associated with UART enabled, change it as output only otherwise can be set to input/output.

Quoted 3 lines

Also is there a way to determine the number of available pins by detecting the chip/package type? I'm assuming not all 36 pins are always accessible?

Yes, we had register to get package type, I'll add UART enable & package type to determinate final GPIO pin out.

Signature · 2 lines
With Best Regards,
Peter Hong
maintainer
#23 lore raw

Re: [PATCH V2 7/7] USB: serial: f81232: Add gpiolib to GPIO device

Quoted 13 lines · Ji-Ze Hong (Peter Hong)

Johan Hovold 於 2020/1/8 下午 10:46 寫道:

Quoted 4 lines

I understood from your other mail that the gpio device would not be able to control the pins of an enabled port. In either case, I think you need to refuse a request for a pin that's already in use by the corresponding port.

OK, I'll change the code as previous mail as following:

I can read the UART enable state from GPIO Device, so I can do when the GPIO is associated with UART enabled, change it as output only otherwise can be set to input/output.

Quoted 6 lines
Quoted 3 lines

Also is there a way to determine the number of available pins by detecting the chip/package type? I'm assuming not all 36 pins are always accessible?

Yes, we had register to get package type, I'll add UART enable & package type to determinate final GPIO pin out.

I suggest you start without any gpiochip, just add a simple control driver which enables each UART (only the ones available in the package and which have not been hardware disabled perhaps).

We don't want a user to be able to change the tranceiver mode behind the serial driver's back so to speak.

Exposing GPIO pins (not MODE pins) in packages which have those enabled should be fine, but you can add that later.

Johan

maintainer
#24 lore raw
In reply to Ji-Ze Hong (Peter Hong)
Quoted 11 lines · Ji-Ze Hong (Peter Hong)

The Fintek F81532A/534A/535/536 is USB-to-2/4/8/12 serial ports device and the serial port is default disabled when plugin computer.

The part number is a bit same with F81532/534, but F81534A series UART core is enhanced from F81232, not F81532/534.

The IC is contains devices as following:
1. HUB (all devices is connected with this hub)
2. GPIO/Control device. (enable serial port and control all GPIOs)
3. serial port 1 to x (2/4/8/12)

Quoted 7 lines

It's most same with F81232, the UART device is difference as follow:

	1. TX/RX bulk size is 128/512bytes
	2. RX bulk layout change:
		F81232: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]...
		F81534A:[LEN][Data.....][LSR]

We'll try to do some code refacting before add F81534A series.

Make sure to always provide a changelog when sending an updated series (either here for the entire series or below the --- line in the individual patches).

What has changed since v1?

Quoted 11 lines

Ji-Ze Hong (Peter Hong) (7):
USB: serial: f81232: Extract LSR handler
USB: serial: f81232: Add tx_empty function
USB: serial: f81232: Use devm_kzalloc
USB: serial: f81232: Add F81534A support
USB: serial: f81232: Set F81534A serial port with RS232 mode
USB: serial: f81232: Add generator for F81534A
USB: serial: f81232: Add gpiolib to GPIO device

 drivers/usb/serial/f81232.c | 604 ++++++++++++++++++++++++++++++++++--
 1 file changed, 570 insertions(+), 34 deletions(-)

Johan