I don't have any driver developpement knowledge and I didn't have time so I fixed it in an ugly way.
I modified imx.c under drivers/tty/serial like that (this is ugly and only working for my specific case but It can help so I share it ...):
index c9bd603d395b..7cf00d3f1c4b 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -39,6 +39,7 @@
#include <linux/of_device.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
#include <asm/irq.h>
#include <linux/platform_data/serial-imx.h>
@@ -330,6 +331,11 @@ static void imx_port_ucrs_restore(struct uart_port *port,
}
#endif
+static void rs485_init(void);
+static void rs485_free(void);
+static void rs485_start_tx(struct imx_port *sport);
+static void rs485_stop_tx(struct imx_port *sport);
+
/*
* Handle any change of modem status signal since we were last called.
*/
@@ -382,7 +388,7 @@ static void imx_stop_tx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
-
+ // rs485_stop_tx(sport);
/*
* We are maybe in the SMP context, so if the DMA TX thread is running
* on other cpu, we have to wait for it to finish.
@@ -595,6 +601,7 @@ static void imx_start_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
+ rs485_start_tx(sport);
if (port->rs485.flags & SER_RS485_ENABLED) {
/* enable transmitter and shifter empty irq */
temp = readl(port->membase + UCR2);
@@ -732,9 +739,16 @@ static irqreturn_t imx_int(int irq, void *dev_id)
struct imx_port *sport = dev_id;
unsigned int sts;
unsigned int sts2;
+ unsigned int cr4;
sts = readl(sport->port.membase + USR1);
sts2 = readl(sport->port.membase + USR2);
+ cr4 = readl(sport->port.membase + UCR4);
+
+ if ((cr4 & UCR4_TCEN) && (sts2 & USR2_TXDC))
+ {
+ rs485_stop_tx(sport);
+ }
if ((sts & USR1_RRDY || sts & USR1_AGTIM) &&
!sport->dma_is_enabled) {
@@ -746,7 +760,7 @@ static irqreturn_t imx_int(int irq, void *dev_id)
if ((sts & USR1_TRDY &&
readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) ||
(sts2 & USR2_TXDC &&
- readl(sport->port.membase + UCR4) & UCR4_TCEN))
+ cr4 & UCR4_TCEN))
imx_txint(irq, dev_id);
if (sts & USR1_RTSD)
@@ -1122,6 +1136,7 @@ static int imx_startup(struct uart_port *port)
return retval;
}
+ rs485_init();
imx_setup_ufcr(sport, 0);
/* disable the DREN bit (Data Ready interrupt enable) before
@@ -1222,6 +1237,7 @@ static void imx_shutdown(struct uart_port *port)
imx_disable_dma(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
imx_uart_dma_exit(sport);
+ rs485_free();
}
spin_lock_irqsave(&sport->port.lock, flags);
@@ -1966,6 +1982,78 @@ static void serial_imx_probe_pdata(struct imx_port *sport,
sport->have_rtscts = 1;
}
+/*
+ Init the GPIO for DE/RE communication for UART7 and UART8
+*/
+static void rs485_init(void)
+{
+ static int done;
+ if (done == 0)
+ {
+ gpio_request(4, "DERE_485_2");
+ gpio_request(5, "DERE_485_1");
+ gpio_direction_output(4, 1);
+ gpio_direction_output(5, 1);
+ done = 1;
+ }
+}
+
+/*
+ Free the GPIOs used for DE/RE com on UART7/8
+*/
+static void rs485_free(void)
+{
+ static int done;
+ if (done == 0)
+ {
+ gpio_free(4);
+ gpio_free(5);
+ done = 1;
+ }
+}
+
+/*
+ Activate the corresponding gpio for UART7/8
+*/
+static void rs485_start_tx(struct imx_port *sport)
+{
+ if (sport == imx_ports[6])
+ {
+ unsigned long temp;
+ gpio_set_value(5, 1);
+ temp = readl(sport->port.membase + UCR4);
+ writel(temp | UCR4_TCEN, sport->port.membase + UCR4);
+ }
+ else if (sport == imx_ports[7])
+ {
+ unsigned long temp;
+ gpio_set_value(4, 1);
+ temp = readl(sport->port.membase + UCR4);
+ writel(temp | UCR4_TCEN, sport->port.membase + UCR4);
+ }
+}
+
+/*
+ Deactivate the corresponding gpio for UART7/8
+*/
+static void rs485_stop_tx(struct imx_port *sport)
+{
+ if (sport == imx_ports[6])
+ {
+ unsigned long temp;
+ gpio_set_value(5, 0);
+ temp = readl(sport->port.membase + UCR4);
+ writel(temp & ~UCR4_TCEN, sport->port.membase + UCR4);
+ }
+ else if (sport == imx_ports[7])
+ {
+ unsigned long temp;
+ gpio_set_value(4, 0);
+ temp = readl(sport->port.membase + UCR4);
+ writel(temp & ~UCR4_TCEN, sport->port.membase + UCR4);
+ }
+}
+
static int serial_imx_probe(struct platform_device *pdev)
{
struct imx_port *sport;