[PATCH v2] usb: serial: mos7840.c Support RS485 mode in B&B Electronics USOPTL4-4P and USOPTL4-2P

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The USOPTL4-4P and USOPTL4-2P USB-to-quad/dual RS-485/422 hubs use the Moschip 7840/7820. For correct operation in RS-485, the chip must be configured in “RS-485 mode” through the scratchpad register as per the datasheet. This strobes the DTR line on transmission, enabling the driver on the RS485 transceiver chip.

Patch enables RS485 mode automatically for the USOPTL4-4P and USOPTL4-2P based on USB product ID. It also includes a module command line option "force_rs485={0|1}" to manually force-enable (for all devices regardless of USB ID) and force-disable (for no devices, not even USOPTL*) the functionality.

Signed-off-by: Aaron Marburg <amarburg@xxxxxxxxxxxxxxxxxx>
---
Changes in v2:
   - Includes suggested formatting changes.

 drivers/usb/serial/mos7840.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 2c69bfc..29bb361 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -182,6 +182,9 @@
 #define LED_ON_MS	500
 #define LED_OFF_MS	500

+/* Kernel option to force RS485 mode which triggers the DTR on transmit */
+static int force_rs485 = -1;
+
 enum mos7840_flag {
 	MOS7840_FLAG_CTRL_BUSY,
 	MOS7840_FLAG_LED_BUSY,
@@ -853,6 +856,9 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
 	struct moschip_port *mos7840_port;
 	struct moschip_port *port0;

+	/* Req'd to check for RS485 devices and enable appropriate mode */
+	u16 product = le16_to_cpu(port->serial->dev->descriptor.idProduct);
+
 	if (mos7840_port_paranoia_check(port, __func__))
 		return -ENODEV;

@@ -991,6 +997,22 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
 	status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
 	mos7840_port->shadowLCR = Data;

+	if (force_rs485 != 0) {
+		if (force_rs485 == 1 ||
+		    product == BANDB_DEVICE_ID_USOPTL4_4P ||
+		    product == BANDB_DEVICE_ID_USOPTL4_2P) {
+
+			/* Enable RS485 mode by setting bytes in
+			 * scratchpad register:
+			 * 0x00  RS485 mode disabled
+			 * 0x80  = RS485 mode enabled, DTR Low on tx
+			 * 0xC0  = RS485 mode enabled, DTR High on tx
+			 */
+			dev_notice(&port->dev, "Detected B&B Electronics USOPTL4_4P, enabling RS485 mode.\n");
+			status = mos7840_set_uart_reg(port, SCRATCH_PAD_REGISTER, 0xC0);
+		}
+	}
+
 	/* clearing Bulkin and Bulkout Fifo */
 	Data = 0x0;
 	status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
@@ -2403,5 +2425,8 @@ static struct usb_serial_driver * const serial_drivers[] = {

 module_usb_serial_driver(serial_drivers, id_table);

+module_param(force_rs485, int, S_IRUGO);
+MODULE_PARM_DESC(force_rs845, "Force RS-485 mode (1 = force enable, 0 = force disable).  Otherwise automatically enabled for B&B Elec. USOPTL4-4P and USOPTL4-2P.");
+
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
--
1.9.1

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux