RK3588添加支持RS485收发

RS485是在串口基础上利用电平转换芯片,将TTL电平转换成485的差分信号,电路图如下:

RO: 接收器输出----接RX
RE: 接收器输出使能(低电平-接收使能)
DE: 驱动器输出使能(高电平-发送使能)
DI: 驱动器输入----接TX
在传输数据时候需要将RS485 RE置高,发送使能,接收禁止;发送完数据以后需要将RS485 RE置低,接收使能,发送禁止。

清楚原理,修改驱动:

1.dts添加re使能口:

&uart6 {
        pinctrl-0 = <&uart6m1_xfer>;
        status = "okay";
        rs485-gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>;
    };

2.驱动修改:

 
diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 93eb3c496ff1..0828068cca44 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -130,6 +130,7 @@ struct serial_rs485 {
        __u32   delay_rts_after_send;   /* Delay after send (milliseconds) */
        __u32   padding[5];             /* Memory is cheap, new structs
                                           are a royal PITA .. */
+       __u32    rs485_tx_en_gpio;
 };
 
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 82a4f6dab59a..f0a3da1b2930 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -26,6 +26,8 @@
 #include <linux/clk.h>
 #include <linux/reset.h>
 #include <linux/pm_runtime.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
 
 #include <asm/byteorder.h>
 
@@ -502,6 +504,7 @@ static int dw8250_probe(struct platform_device *pdev)
        int irq;
        int err;
        u32 val;
+       int ret = 0;
 
        if (!regs) {
                dev_err(dev, "no registers defined\n");
@@ -544,6 +547,24 @@ static int dw8250_probe(struct platform_device *pdev)
        data->uart_16550_compatible = device_property_read_bool(dev,
                                                "snps,uart-16550-compatible");
 
+       //wmc add
+       ret = of_get_named_gpio(p->dev->of_node, "rs485-gpios", 0);//GPIO4_B5
+       uart.port.rs485.rs485_tx_en_gpio = ret;
+       if(141 == uart.port.rs485.rs485_tx_en_gpio)
+       {
+               err = gpio_request(141, "rs485-ctl");
+               if(err<0){
+                       printk("wmc....rs485-ctl...failed..\n");
+                       return err;
+               }
+    
+    
+        gpio_direction_output(uart.port.rs485.rs485_tx_en_gpio, 0);
+        gpio_set_value(uart.port.rs485.rs485_tx_en_gpio, 0); // defalut low-level
+
+    }
+       //end
+
        err = device_property_read_u32(dev, "reg-shift", &val);

实现逻辑是,发送数据拉高re引脚,发送完数据再置低:

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 9e681b375bad..4d4fe01b328d 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -31,6 +31,7 @@
 #include <linux/uaccess.h>
 #include <linux/pm_runtime.h>
 #include <linux/ktime.h>
+#include <linux/of_gpio.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -1797,6 +1798,8 @@ void serial8250_tx_chars(struct uart_8250_port *up)
        struct uart_port *port = &up->port;
        struct circ_buf *xmit = &port->state->xmit;
        int count;
+       int lsr; // 用于获取状态
+       int i;   // 用于循环计数
 
        if (port->x_char) {
                uart_xchar_out(port, UART_TX);
@@ -1811,6 +1814,11 @@ void serial8250_tx_chars(struct uart_8250_port *up)
                return;
        }
 
+       if(141 == up->port.rs485.rs485_tx_en_gpio)
+       {
+        gpio_set_value(up->port.rs485.rs485_tx_en_gpio, 1);
+       }
+
        count = up->tx_loadsz;
        do {
                serial_out(up, UART_TX, xmit->buf[xmit->tail]);
@@ -1848,7 +1856,25 @@ void serial8250_tx_chars(struct uart_8250_port *up)
         * the interrupt and RPM in __stop_tx()
         */
        if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+       {
                __stop_tx(up);
+               lsr = serial_in(up, UART_LSR);
+               if(141 == up->port.rs485.rs485_tx_en_gpio)
+               {
+                       for(i = 0; i < 200; i++)
+                       {
+                                       mdelay(3);
+                                       lsr = serial_in(up, UART_LSR);
+                                       if(UART_LSR_TEMT == (lsr & UART_LSR_TEMT))
+                                       {
+                                               // printk("[%d] wait finished: %d, lsr: %d\n", i, (lsr & UART_LSR_TEMT) == UART_LSR_TEMT, lsr);
+                                               break;
+                                       }
+                       }
+                       gpio_set_value(up->port.rs485.rs485_tx_en_gpio, 0);
+               }
+       }
+               
 }
 EXPORT_SYMBOL_GPL(serial8250_tx_chars);

 

 

参考:https://blog.csdn.net/weixin_46461874/article/details/132718936

https://blog.csdn.net/guowuoo2008/article/details/131771333

https://blog.csdn.net/bing328924/article/details/134503353

  

posted @ 2024-08-23 18:04  M-kobe  阅读(114)  评论(0编辑  收藏  举报