RK3288 Android7.1 基于8250串口驱动---使非自动控制流RS485芯片在软件层实现自动控制收发 (外加分析驱动是如何匹配设备树设备最后走到probe函数的)
分析驱动是如何匹配设备树设备最后走到probe函数的,如何实现软件控制达到无自控流RS485芯片与自动流芯片差不多的效果。
·
一、源码分析
从源码分析,这样我们才能精准定位到收发数据的程序位置
1、驱动是如何匹配设备树设备最后走到probe函数的
以8250串口驱动为例子,如下图所示:
2、分析8250串口驱动,定位数据收发程序位置
分析流程如下图所示:
二、源码修改补丁
commit 1eaa96393d8dc4c8de75e49195fe395a4d45803b
Author: dengjiawen <1411471554@qq.com>
Date: Mon Feb 5 17:30:47 2024 +0800
基于RK3288 Android7.1 RS485自动控制收发
diff --git a/kernel/build_bootimg.sh b/kernel/build_bootimg.sh
new file mode 100755
index 0000000000..47946e6c26
--- /dev/null
+++ b/kernel/build_bootimg.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+echo "Start build kernel"
+make ARCH=arm rockchip_defconfig && make ARCH=arm rk3288-evb-android-rk808-edp.img -j64 && cd ..
+if [ $? -eq 0 ]; then
+ echo "Build kernel ok!"
+ echo "start build bootimg"
+ rm -rf out/target/product/rk3288/kernel
+ rm -rf out/target/product/rk3288/boot.img
+ make bootimage -j48
+ ./mkimage.sh ota boot
+else
+ echo "Build kernel failed!"
+ exit 1
+fi
\ No newline at end of file
diff --git a/kernel/arch/arm/boot/dts/rk3288.dtsi b/kernel/arch/arm/boot/dts/rk3288.dtsi
index 414cb4fbd2..7d2cbacb64 100644
--- a/kernel/arch/arm/boot/dts/rk3288.dtsi
+++ b/kernel/arch/arm/boot/dts/rk3288.dtsi
@@ -544,7 +544,7 @@
clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
clock-names = "baudclk", "apb_pclk";
pinctrl-names = "default";
- pinctrl-0 = <&uart1_xfer>;
+ pinctrl-0 = <&uart1_xfer &uart1_485>;
status = "disabled";
};
@@ -2302,6 +2302,10 @@
uart1_rts: uart1-rts {
rockchip,pins = <5 11 RK_FUNC_1 &pcfg_pull_none>;
};
+
+ uart1_485: uart1-485 {
+ rockchip,pins = <8 3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
};
diff --git a/kernel/arch/arm/boot/dts/rk3288-evb-android-rk808-edp.dts b/kernel/arch/arm/boot/dts/rk3288-evb-android-rk808-edp.dts
index ca37f35195..07b29ec59d 100644
--- a/kernel/arch/arm/boot/dts/rk3288-evb-android-rk808-edp.dts
+++ b/kernel/arch/arm/boot/dts/rk3288-evb-android-rk808-edp.dts
@@ -752,6 +751,7 @@
&uart1 {
status = "okay";
+ rs485-enable = <&gpio8 3 GPIO_ACTIVE_HIGH>;
};
diff --git a/kernel/drivers/tty/serial/8250/8250_dw.c b/kernel/drivers/tty/serial/8250/8250_dw.c
index 1ebbe7c140..0201fbdc3d 100644
--- a/kernel/drivers/tty/serial/8250/8250_dw.c
+++ b/kernel/drivers/tty/serial/8250/8250_dw.c
@@ -32,6 +32,10 @@
#include "8250.h"
+/* by huidu --- djw */
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_RFL 0x21 /* UART Receive Fifo Level Register */
@@ -406,6 +410,9 @@ static int dw8250_probe(struct platform_device *pdev)
int err;
u32 val;
+ /* by huidu --- djw */
+ int ret = 0;
+
if (!regs) {
dev_err(&pdev->dev, "no registers defined\n");
return -EINVAL;
@@ -445,6 +452,27 @@ static int dw8250_probe(struct platform_device *pdev)
data->uart_16550_compatible = device_property_read_bool(p->dev,
"snps,uart-16550-compatible");
+ /* by huidu --- djw */
+ uart.port.rs485.rs485_nd = p->dev->of_node;
+ uart.port.rs485.rs485_dir_gpio = of_get_named_gpio(uart.port.rs485.rs485_nd, "rs485-enable", 0);
+ if(!gpio_is_valid(uart.port.rs485.rs485_dir_gpio)) {
+ dev_err(p->dev, "invalid rs485 gpio %d\n", uart.port.rs485.rs485_dir_gpio);
+ } else {
+ ret = devm_gpio_request(p->dev, uart.port.rs485.rs485_dir_gpio, "rs485_enable");
+ if (ret) {
+ dev_err(p->dev, "failed to request GPIO%d for rs485 gpio\n", uart.port.rs485.rs485_dir_gpio);
+ return -EINVAL;
+ }
+ gpio_direction_output(uart.port.rs485.rs485_dir_gpio, 0); //低电平为接收模式
+ gpio_set_value(uart.port.rs485.rs485_dir_gpio, 0);
+ }
+
err = device_property_read_u32(p->dev, "reg-shift", &val);
if (!err)
p->regshift = val;
diff --git a/kernel/drivers/tty/serial/8250/8250_port.c b/kernel/drivers/tty/serial/8250/8250_port.c
index 14665c09d2..7aa38c7cf2 100644
--- a/kernel/drivers/tty/serial/8250/8250_port.c
+++ b/kernel/drivers/tty/serial/8250/8250_port.c
@@ -43,6 +43,9 @@
#include "8250.h"
+/* by huidu --- djw */
+#include <linux/of_gpio.h>
+
/*
* Debugging.
*/
@@ -1473,6 +1476,11 @@ void serial8250_tx_chars(struct uart_8250_port *up)
struct circ_buf *xmit = &port->state->xmit;
int count;
+ /* by huidu --- djw */
+ int lsr = 0; // 用于获取状态
+
if (port->x_char) {
serial_out(up, UART_TX, port->x_char);
port->icount.tx++;
@@ -1488,6 +1496,10 @@ void serial8250_tx_chars(struct uart_8250_port *up)
return;
}
+ /* by huidu --- djw */
+ printk("%s Set the rs485 to send mode\n", __LINE__);
+ gpio_set_value(up->port.rs485.rs485_dir_gpio, 1);
+
count = up->tx_loadsz;
do {
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
@@ -1512,8 +1524,17 @@ void serial8250_tx_chars(struct uart_8250_port *up)
* HW can go idle. So we get here once again with empty FIFO and disable
* the interrupt and RPM in __stop_tx()
*/
- if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+ if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) {
__stop_tx(up);
+
+ /* by huidu --- djw */
+ do {
+ mdelay(3);
+ lsr = serial_in(up, UART_LSR); //获取8250的线路状态寄存器
+ } while( !(lsr&UART_LSR_TEMT) ); //判断是否发送缓冲区是否为空
+ printk("%s Set the rs485 to receive mode\n", __LINE__);
+ gpio_set_value(up->port.rs485.rs485_dir_gpio, 0); //设置为低电平
+ }
}
EXPORT_SYMBOL_GPL(serial8250_tx_chars);
diff --git a/kernel/include/uapi/linux/serial.h b/kernel/include/uapi/linux/serial.h
index 25331f9faa..75080340dc 100644
--- a/kernel/include/uapi/linux/serial.h
+++ b/kernel/include/uapi/linux/serial.h
@@ -125,6 +125,10 @@ struct serial_rs485 {
__u32 delay_rts_after_send; /* Delay after send (milliseconds) */
__u32 padding[5]; /* Memory is cheap, new structs
are a royal PITA .. */
+
+ /* by huidu --- djw */
+ struct device_node *rs485_nd;
+ int rs485_dir_gpio;
};
#endif /* _UAPI_LINUX_SERIAL_H */
上面的补丁是有点瑕疵的,只针对单个RS485自控有用,下面我提供两种可以满足配置多个RS485自控的补丁
补丁一:
diff --git a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
index 7906621ea62..f92785583d9 100755
--- a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
+++ b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
@@ -6,24 +6,40 @@
#include "rk3568-evb1-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
+
+&uart4 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4m1_xfer>;
+ pinctrl-1 = <&uart4_rs485_pinctrl>;
+ uart-rs485-gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>; //led
+};
+
&uart7{
status ="okay";
pinctrl-name = "default";
pinctrl-0 = <&uart7m1_xfer>;
+ pinctrl-1 = <&uart7_rs485_pinctrl>;
+ uart-rs485-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
};
&pinctrl{
+ uart4_rs485{
+ uart4_rs485_pinctrl:uart4-rs485-pinctrl {
+ rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+ uart7_rs485{
+ uart7_rs485_pinctrl:uart7-rs485-pinctrl {
+ rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
\ No newline at end of file
diff --git a/kernel/drivers/tty/serial/8250/8250_core.c b/kernel/drivers/tty/serial/8250/8250_core.c
index 4e1d450ffd5..a81e490ee8b 100644
--- a/kernel/drivers/tty/serial/8250/8250_core.c
+++ b/kernel/drivers/tty/serial/8250/8250_core.c
@@ -1010,6 +1010,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.rs485_config = up->port.rs485_config;
uart->port.rs485 = up->port.rs485;
uart->dma = up->dma;
+
+ /* 获取uart rs485新定义的变量值 */
+ uart->port.uart_rs485_gpio = up->port.uart_rs485_gpio;
+ uart->port.rs485_gpio_uart_tx_value = up->port.rs485_gpio_uart_tx_value;
+ uart->port.uartx_node = up->port.uartx_node;
+ uart->port.uart_name = up->port.uart_name;
+
#ifdef CONFIG_ARCH_ROCKCHIP
uart->port.line = up->port.line;
#endif
@@ -1022,7 +1029,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
if (up->port.flags & UPF_FIXED_TYPE)
uart->port.type = up->port.type;
-
+ /* 设置私有属性 */
serial8250_set_defaults(uart);
/* Possibly override default I/O functions. */
diff --git a/kernel/drivers/tty/serial/8250/8250_dw.c b/kernel/drivers/tty/serial/8250/8250_dw.c
index 735420b3da4..5297d606049 100644
--- a/kernel/drivers/tty/serial/8250/8250_dw.c
+++ b/kernel/drivers/tty/serial/8250/8250_dw.c
@@ -29,6 +29,10 @@
#include "8250.h"
+/* by djw */
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */
@@ -633,6 +637,23 @@ static int dw8250_probe(struct platform_device *pdev)
data->enable_wakeup = 0;
#endif
+ /* by djw */
+ p->uartx_node = dev->of_node; //uartx节点
+ p->uart_name = "uart-rs485-gpios";
+
+ p->uart_rs485_gpio = of_get_named_gpio_flags(p->uartx_node, p->uart_name, 0, &p->rs485_gpio_uart_tx_value); //获取flag是该属性第三个参赛, HIGH:0; LOW:1
+ if (!gpio_is_valid(p->uart_rs485_gpio)) {
+ dev_err(dev, "djw: %s invalid rs485 gpio%d\n", p->uart_name, p->uart_rs485_gpio);
+ } else {
+ err = devm_gpio_request(dev, p->uart_rs485_gpio, p->uart_name);
+ if(err) {
+ dev_err(p->dev, "djw: failed to request gpio%d for rs485 gpio\n", p->uart_rs485_gpio);
+ } else {
+ gpio_direction_output(p->uart_rs485_gpio, p->rs485_gpio_uart_tx_value); //低电平为接收模式
+ }
+ printk("djw: %s gpio%d=%d, tx value is %d\n", p->uart_name, p->uart_rs485_gpio, gpio_get_value(p->uart_rs485_gpio), !p->rs485_gpio_uart_tx_value);
+ }
+
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &p->uartclk);
@@ -694,6 +715,7 @@ static int dw8250_probe(struct platform_device *pdev)
uart.dma = &data->dma;
}
+ /* 这里是将&uart这个结构体变量的值获取到,然后注册到私有属性中 */
data->line = serial8250_register_8250_port(&uart);
if (data->line < 0) {
err = data->line;
diff --git a/kernel/drivers/tty/serial/8250/8250_port.c b/kernel/drivers/tty/serial/8250/8250_port.c
index 99d52647908..661669208c7 100644
--- a/kernel/drivers/tty/serial/8250/8250_port.c
+++ b/kernel/drivers/tty/serial/8250/8250_port.c
@@ -40,6 +40,9 @@
#include "8250.h"
+/* by djw */
+#include <linux/of_gpio.h>
+
/*
* These are definitions for the Exar XR17V35X and XR17(C|D)15X
*/
@@ -1782,6 +1785,9 @@ void serial8250_tx_chars(struct uart_8250_port *up)
struct circ_buf *xmit = &port->state->xmit;
int count;
+ /* by djw */
+ int lsr_reg = 0;
+
if (port->x_char) {
serial_out(up, UART_TX, port->x_char);
port->icount.tx++;
@@ -1797,6 +1803,10 @@ void serial8250_tx_chars(struct uart_8250_port *up)
return;
}
+ /* by djw */
+ printk("djw: Set the rs485 gpio%d to send mode\n", port->uart_rs485_gpio);
+ gpio_set_value(port->uart_rs485_gpio, !port->rs485_gpio_uart_tx_value);
+
count = up->tx_loadsz;
do {
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
@@ -1821,8 +1831,17 @@ void serial8250_tx_chars(struct uart_8250_port *up)
* HW can go idle. So we get here once again with empty FIFO and disable
* the interrupt and RPM in __stop_tx()
*/
- if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+ if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) {
__stop_tx(up);
+
+ /* by djw */
+ do {
+ udelay(10);
+ lsr_reg = serial_in(up, UART_LSR); //获取8250的线路状态寄存器
+ } while( !(lsr_reg & UART_LSR_TEMT) ); //判断是否发送缓冲区是否为空
+ printk("djw: Set the rs485 gpio%d to receive mode\n", port->uart_rs485_gpio);
+ gpio_set_value(port->uart_rs485_gpio, port->rs485_gpio_uart_tx_value);
+ }
}
EXPORT_SYMBOL_GPL(serial8250_tx_chars);
diff --git a/kernel/include/linux/serial_core.h b/kernel/include/linux/serial_core.h
index 3460b15a260..99edc38f013 100644
--- a/kernel/include/linux/serial_core.h
+++ b/kernel/include/linux/serial_core.h
@@ -31,6 +31,10 @@
#include <linux/sysrq.h>
#include <uapi/linux/serial_core.h>
+/* by djw */
+#include <linux/of_gpio.h>
+
+
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) \
((port)->cons && (port)->cons->index == (port)->line)
@@ -262,6 +266,12 @@ struct uart_port {
const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
struct serial_rs485 rs485;
void *private_data; /* generic platform data pointer */
+
+ /* by djw */
+ int uart_rs485_gpio;
+ enum of_gpio_flags rs485_gpio_uart_tx_value; //保存gpio属性第三个参数
+ struct device_node *uartx_node; //uartx节点
+ char *uart_name;
};
static inline int serial_port_in(struct uart_port *up, int offset)
补丁二:
diff --git a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
index 7906621ea62..f92785583d9 100755
--- a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
+++ b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
@@ -6,24 +6,40 @@
#include "rk3568-evb1-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
+
+&uart4 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4m1_xfer>;
+ pinctrl-1 = <&uart4_rs485_pinctrl>;
+ uart-rs485-gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>; //led
+};
+
&uart7{
status ="okay";
pinctrl-name = "default";
pinctrl-0 = <&uart7m1_xfer>;
+ pinctrl-1 = <&uart7_rs485_pinctrl>;
+ uart-rs485-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
};
&pinctrl{
- rk_485{
- rk_485_gpio:rk-485-gpio {
- rockchip,pins = <3 13 RK_FUNC_GPIO &pcfg_pull_none>;
+ uart4_rs485{
+ uart4_rs485_pinctrl:uart4-rs485-pinctrl {
+ rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+ uart7_rs485{
+ uart7_rs485_pinctrl:uart7-rs485-pinctrl {
+ rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
\ No newline at end of file
diff --git a/kernel/drivers/tty/serial/8250/8250_core.c b/kernel/drivers/tty/serial/8250/8250_core.c
index 4e1d450ffd5..a81e490ee8b 100644
--- a/kernel/drivers/tty/serial/8250/8250_core.c
+++ b/kernel/drivers/tty/serial/8250/8250_core.c
@@ -1010,6 +1010,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.rs485_config = up->port.rs485_config;
uart->port.rs485 = up->port.rs485;
uart->dma = up->dma;
+
+ /* 获取uart rs485新定义的变量值 */
+ uart->port.uart_rs485_gpio = up->port.uart_rs485_gpio;
+ uart->port.rs485_gpio_uart_tx_value = up->port.rs485_gpio_uart_tx_value;
+ uart->port.uartx_node = up->port.uartx_node;
+ uart->port.uart_name = up->port.uart_name;
+
#ifdef CONFIG_ARCH_ROCKCHIP
uart->port.line = up->port.line;
#endif
@@ -1022,7 +1029,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
if (up->port.flags & UPF_FIXED_TYPE)
uart->port.type = up->port.type;
-
+ /* 设置私有属性 */
serial8250_set_defaults(uart);
/* Possibly override default I/O functions. */
diff --git a/kernel/drivers/tty/serial/8250/8250_dw.c b/kernel/drivers/tty/serial/8250/8250_dw.c
index 735420b3da4..1d1cca1cf2e 100644
--- a/kernel/drivers/tty/serial/8250/8250_dw.c
+++ b/kernel/drivers/tty/serial/8250/8250_dw.c
@@ -29,6 +29,10 @@
#include "8250.h"
+/* by djw */
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */
@@ -548,6 +552,10 @@ static int dw8250_probe(struct platform_device *pdev)
int err;
u32 val;
+ /* by djw */
+ u32 uart_rs485_gpios_array[3] = {0};
+ char uart_rs485_gpios_name[50] = {0};
+
if (!regs) {
dev_err(dev, "no registers defined\n");
return -EINVAL;
@@ -633,6 +641,32 @@ static int dw8250_probe(struct platform_device *pdev)
data->enable_wakeup = 0;
#endif
+ /* by djw */
+ p->uartx_node = dev->of_node; //uartx节点
+ p->uart_name = "uart-rs485";
+
+ snprintf(uart_rs485_gpios_name, sizeof(uart_rs485_gpios_name), "%s-gpios", p->uart_name);
+ if (of_property_read_u32_array(p->uartx_node, uart_rs485_gpios_name, uart_rs485_gpios_array, 3) == 0) {
+ printk("djw: uart_rs485_gpios_array[0]=%d, uart_rs485_gpios_array[1]=%d, uart_rs485_gpios_array[2]=%d\n", uart_rs485_gpios_array[0], uart_rs485_gpios_array[1], uart_rs485_gpios_array[2]);
+ /* GPIO_ACTIVE_HIGH=0, GPIO_ACTIVE_LOW=1 */
+ if (uart_rs485_gpios_array[2] == 0) {
+ p->rs485_gpio_uart_tx_value = 1;
+ p->uart_rs485_gpio = devm_gpiod_get(dev, p->uart_name, GPIOD_OUT_LOW); //默认接收模式
+ if (IS_ERR(p->uart_rs485_gpio)) {
+ dev_err(dev, "djw: failed to request reset GPIO: %d\n", PTR_ERR(p->uart_rs485_gpio));
+ }
+ } else if (uart_rs485_gpios_array[2] == 1) {
+ p->rs485_gpio_uart_tx_value = 0;
+ p->uart_rs485_gpio = devm_gpiod_get(dev, p->uart_name, GPIOD_OUT_HIGH);
+ if (IS_ERR(p->uart_rs485_gpio)) {
+ dev_err(dev, "djw: failed to request reset GPIO: %d\n", PTR_ERR(p->uart_rs485_gpio));
+ }
+ }
+ } else {
+ dev_err(dev, "djw: Failed to read uart-rs485-gpios property\n");
+ }
+ printk("djw: rs485 gpio value = %d, rs485 tx value is %d\n", gpiod_get_value(p->uart_rs485_gpio), p->rs485_gpio_uart_tx_value);
+
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &p->uartclk);
@@ -694,6 +728,7 @@ static int dw8250_probe(struct platform_device *pdev)
uart.dma = &data->dma;
}
+ /* 这里是将&uart这个结构体变量的值获取到,然后注册到私有属性中 */
data->line = serial8250_register_8250_port(&uart);
if (data->line < 0) {
err = data->line;
diff --git a/kernel/drivers/tty/serial/8250/8250_port.c b/kernel/drivers/tty/serial/8250/8250_port.c
index 99d52647908..dec213dfb7d 100644
--- a/kernel/drivers/tty/serial/8250/8250_port.c
+++ b/kernel/drivers/tty/serial/8250/8250_port.c
@@ -40,6 +40,9 @@
#include "8250.h"
+/* by djw */
+#include <linux/of_gpio.h>
+
/*
* These are definitions for the Exar XR17V35X and XR17(C|D)15X
*/
@@ -1782,6 +1785,9 @@ void serial8250_tx_chars(struct uart_8250_port *up)
struct circ_buf *xmit = &port->state->xmit;
int count;
+ /* by djw */
+ int lsr_reg = 0;
+
if (port->x_char) {
serial_out(up, UART_TX, port->x_char);
port->icount.tx++;
@@ -1797,6 +1803,10 @@ void serial8250_tx_chars(struct uart_8250_port *up)
return;
}
+ /* by djw */
+ printk("djw: Set the rs485 gpio%d to send mode\n", port->uart_rs485_gpio);
+ gpiod_set_value(port->uart_rs485_gpio, port->rs485_gpio_uart_tx_value);
+
count = up->tx_loadsz;
do {
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
@@ -1821,8 +1831,17 @@ void serial8250_tx_chars(struct uart_8250_port *up)
* HW can go idle. So we get here once again with empty FIFO and disable
* the interrupt and RPM in __stop_tx()
*/
- if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+ if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) {
__stop_tx(up);
+
+ /* by djw */
+ do {
+ udelay(10);
+ lsr_reg = serial_in(up, UART_LSR); //获取8250的线路状态寄存器
+ } while( !(lsr_reg & UART_LSR_TEMT) ); //判断是否发送缓冲区是否为空
+ printk("djw: Set the rs485 gpio%d to receive mode\n", port->uart_rs485_gpio);
+ gpiod_set_value(port->uart_rs485_gpio, !port->rs485_gpio_uart_tx_value);
+ }
}
EXPORT_SYMBOL_GPL(serial8250_tx_chars);
diff --git a/kernel/include/linux/serial_core.h b/kernel/include/linux/serial_core.h
index 3460b15a260..9d19a233999 100644
--- a/kernel/include/linux/serial_core.h
+++ b/kernel/include/linux/serial_core.h
@@ -31,6 +31,10 @@
#include <linux/sysrq.h>
#include <uapi/linux/serial_core.h>
+/* by djw */
+#include <linux/of_gpio.h>
+
+
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) \
((port)->cons && (port)->cons->index == (port)->line)
@@ -262,6 +266,12 @@ struct uart_port {
const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
struct serial_rs485 rs485;
void *private_data; /* generic platform data pointer */
+
+ /* by djw */
+ struct gpio_desc *uart_rs485_gpio;
+ int rs485_gpio_uart_tx_value; //保存gpio属性第三个参数
+ struct device_node *uartx_node; //uartx节点
+ char *uart_name;
};
static inline int serial_port_in(struct uart_port *up, int offset)
三、驱动程序分析技巧
例如我需要分析dw8250_probe这个函数的调用,可以添加dump_stack函数进行打印所有函数的调用,如下图所示:

日志的显示的函数调用顺序是从下往上的。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)