AnsweredAssumed Answered

i.MX6 UART Driver and RS485 Support

Question asked by Paul DeMetrotion on Sep 23, 2013
Latest reply on Oct 26, 2017 by Yuri Muhin
Branched to a new discussion

I am currently attempting to use RS-485 mode on a custom device based on the i.MX6Q. I am altering the imx.c driver found in ltib/rpm/BUILD/Linux/drivers/tty/serial. Using the assistance found in the 'RS485 Serial Communications' documentation, I have made the following changes to the driver. Unfortunately this has not helped. The signal CTS which I am using to control the direction of the RS-485 driver is never enabled so the device can never transmit. Anybody have any experience with RS-485 and this part? Should I be using the RS-485 mode by enabling the MDEN bit in the UMCR register?

 

Index: imx.c

===================================================================

--- imx.c (revision 34)

+++ imx.c (working copy)

@@ -46,6 +46,7 @@

#include <linux/rational.h>

#include <linux/slab.h>

#include <linux/dma-mapping.h>

+#include <linux/uaccess.h>

 

#include <asm/io.h>

#include <asm/irq.h>

@@ -213,6 +214,9 @@

  unsigned int  dma_tx_nents;

  bool   dma_is_rxing;

  wait_queue_head_t dma_wait;

+

+ // RS485 Support

+ struct serial_rs485 rs485;

};

 

struct imx_port_ucrs {

@@ -227,6 +231,33 @@

#define USE_IRDA(sport) (0)

#endif

 

+static inline struct imx_port *

+to_imx_uart_port(struct uart_port *uart)

+{

+ return container_of(uart, struct imx_port, port);

+}

+

+/* Enable or disable the rs485 support */

+void imx_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)

+{

+ struct imx_port *imx_port = to_imx_uart_port(port);

+ //unsigned int mode;

+ unsigned long flags;

+ //unsigned long temp;

+

+ spin_lock_irqsave(&port->lock, flags);

+

+ imx_port->rs485 = *rs485conf;

+

+ if (rs485conf->flags & SER_RS485_ENABLED) {

+  dev_dbg(port->dev, "Setting UART to RS485\n");

+ } else {

+  dev_dbg(port->dev, "Setting UART to RS232\n");

+ }

+

+ spin_unlock_irqrestore(&port->lock, flags);

+}

+

/*

  * Save and restore functions for UCR1, UCR2 and UCR3 registers

  */

@@ -345,6 +376,13 @@

 

  temp = readl(sport->port.membase + UCR1);

  writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);

+

+ // disable CTS if rs485

+ if (sport->rs485.flags & SER_RS485_ENABLED) {

+  temp = readl(sport->port.membase + UCR2);

+  temp &= ~(UCR2_CTS);

+  writel(temp, sport->port.membase + UCR2);

+ }

}

 

/*

@@ -477,6 +515,13 @@

  struct imx_port *sport = (struct imx_port *)port;

  unsigned long temp;

 

+ // enable CTS if rs485

+ if (sport->rs485.flags & SER_RS485_ENABLED) {

+  temp = readl(sport->port.membase + UCR2);

+  temp |= UCR2_CTS;

+  writel(temp, sport->port.membase + UCR2);

+ }

+

  if (USE_IRDA(sport)) {

   /* half duplex in IrDA mode; have to disable receive mode */

   temp = readl(sport->port.membase + UCR4);

@@ -1446,6 +1491,36 @@

  return ret;

}

 

+static int imx_ioctl(struct uart_port *port,

+ unsigned int cmd,

+ unsigned long arg)

+{

+ struct serial_rs485 rs485conf;

+

+ switch (cmd) {

+ case TIOCSRS485:

+  if (copy_from_user(&rs485conf,

+   (struct serial_rs485 *) arg,

+   sizeof(rs485conf)))

+    return -EFAULT;

+

+  imx_config_rs485(port, &rs485conf);

+  break;

+

+ case TIOCGRS485:

+  if (copy_to_user((struct serial_rs485 *) arg,

+   &(to_imx_uart_port(port)->rs485),

+   sizeof(rs485conf)))

+    return -EFAULT;

+  break;

+

+        default:

+                return -ENOIOCTLCMD;

+ }

+

+ return 0;

+}

+

#if defined(CONFIG_CONSOLE_POLL)

static int imx_poll_get_char(struct uart_port *port)

{

@@ -1527,6 +1602,8 @@

  .request_port = imx_request_port,

  .config_port = imx_config_port,

  .verify_port = imx_verify_port,

+ // rs485 support

+ .ioctl  = imx_ioctl,

#if defined(CONFIG_CONSOLE_POLL)

  .poll_get_char  = imx_poll_get_char,

  .poll_put_char  = imx_poll_put_char,

Outcomes