- 查找瑞芯微rk3568,rk3588系列串口驱动
查看串口的 “compatible”属性,其中有两个名称。
先在源码搜索"rockchip,rk3568-uart",没有搜索到,再搜索"snps,dw-apb-uart"。在8250_dw.c文件中找到了匹配的名称,采用的是8250的串口驱动。 - 设备树适配
首先,在设备树中添加485控制引脚,用于区分普通串口和485
485_ctrl_gpio = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
- 适配8250驱动
查找8250驱动的probe函数dw8250_probe,定义在drivers/tty/serial/8250/8250_dw.c文件中。
在“p->private_data = &data->data;”代码后面添加如下内容。
先判断下是否定义485_ctrl_gpio,从而判断是否为485。如果是,则初始化一个低电平,将控制引脚拉低切为接收状态,然后添加Linux内核中的下半部机制之tasklet的初始化。
数据收发时,控制引脚电平默认为低电平接收状态,不影响接收。
发送数据时,会先进入到serial8250_start_tx
在serial8250_start_tx函数中,将控制引脚拉高,切为发送状态。
接着,会产生一个中断,进入dw8250_handle_irq中断处理函数中。其中,发送字符会调用serial8250_rx_chars,在if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))里面将tasklet调度起来
中断执行后,会进入tasklet的回调函数,代码为:void serial8250_485_do_tasklet(unsigned long param) { //printk("serial8250_485_do_tasklet\n"); struct uart_port *port; unsigned int lsr; //printk("param = %ld\n", ((struct dw8250_port_data *)param)->suart_port); port = (struct uart_port *)((struct dw8250_port_data *)param)->suart_port; while (1) { lsr = serial_port_in(port, UART_LSR); if (((lsr & UART_LSR_TEMT) == UART_LSR_TEMT)) break; } gpio_direction_output(((struct dw8250_port_data *)port->private_data)->gpiocrtl_485, 0); }
先通过参数param获取对应的struct uart_port结构体,然后通过serial_port_in一直读取寄存器UART_LSR的值,如果判断UART_LSR_TEMT成立,则已发送完成退出循环,将控制引脚拉低切为接收状态。
4,测试
经测试,发送完数据,控制引脚会在100us左右拉低,满足需求。