Added linux rs485 function

Table of contents

Serial port driver hierarchy

485 configuration process

dts related

configuration registration

initialization

485 transceiver switching

delay_after_send


       

Currently, the linux kernel already supports the implementation of 485, but due to the support of the underlying driver, we need to modify the underlying driver when using different chips to meet the various callback interfaces of the kernel 485, and then realize 485 functions.

The 485 mainly lies in the time of switching between sending and receiving control. This article takes 8250 as an example to describe the process of 485 configuration and switching.

Serial port driver hierarchy

Do not discuss tty, tty is divided into three layers

1) Serial common layer

2) 8250 general purpose layer

3) Specific 8250 chip driver layer 

    8250_dw is the specific chip layer. When it is parsed that there is a corresponding configuration in the dts, the probe interface to this is called. If there are three serial ports in the dts, call the probe interface three times . Then call the interface of the upper layer in turn to report the serial port information.

485 configuration process

dts related

   When the 8250_dw registers the serial port with the 8250, the 8250 layer calls back the general 485 dts analysis function uart_get_rs485_mode to obtain the support of the serial port to 485. The code of this function is as follows. Through this code, we can see several dts parameters whose functions are:

dts Function
rs485-rts-delay Delay after 485 transceiver switching, unit ms
rs485-term Switch GPIO pin definition
linux,rs485-enabled-at-boot-time Whether to enable 485 by default, it can also be modified through ioctl later

  


/**
 * uart_get_rs485_mode() - retrieve rs485 properties for given uart
 * @port: uart device's target port
 *
 * This function implements the device tree binding described in
 * Documentation/devicetree/bindings/serial/rs485.txt.
 */
int uart_get_rs485_mode(struct uart_port *port)
{
	struct serial_rs485 *rs485conf = &port->rs485;
	struct device *dev = port->dev;
	u32 rs485_delay[2];
	int ret;

	ret = device_property_read_u32_array(dev, "rs485-rts-delay",
					     rs485_delay, 2);
	if (!ret) {
		rs485conf->delay_rts_before_send = rs485_delay[0];
		rs485conf->delay_rts_after_send = rs485_delay[1];
	} else {
		rs485conf->delay_rts_before_send = 0;
		rs485conf->delay_rts_after_send = 0;
	}

	/*
	 * Clear full-duplex and enabled flags, set RTS polarity to active high
	 * to get to a defined state with the following properties:
	 */
	rs485conf->flags &= ~(SER_RS485_RX_DURING_TX | SER_RS485_ENABLED |
			      SER_RS485_TERMINATE_BUS |
			      SER_RS485_RTS_AFTER_SEND);
	rs485conf->flags |= SER_RS485_RTS_ON_SEND;

	if (device_property_read_bool(dev, "rs485-rx-during-tx"))
		rs485conf->flags |= SER_RS485_RX_DURING_TX;

	if (device_property_read_bool(dev, "linux,rs485-enabled-at-boot-time"))
		rs485conf->flags |= SER_RS485_ENABLED;

	if (device_property_read_bool(dev, "rs485-rts-active-low")) {
		rs485conf->flags &= ~SER_RS485_RTS_ON_SEND;
		rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
	}

	/*
	 * Disabling termination by default is the safe choice:  Else if many
	 * bus participants enable it, no communication is possible at all.
	 * Works fine for short cables and users may enable for longer cables.
	 */
	port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term",
							GPIOD_OUT_LOW);
	if (IS_ERR(port->rs485_term_gpio)) {
		ret = PTR_ERR(port->rs485_term_gpio);
		port->rs485_term_gpio = NULL;
		return dev_err_probe(dev, ret, "Cannot get rs485-term-gpios\n");
	}

	return 0;
}

configuration registration

The lowest chip driver needs to be registered:

 1) The callback interface of the serial layer :

  int            (*rs485_config)(struct uart_port *,   struct serial_rs485 *rs485);

     Complete 485 related initialization

 2) The callback interface of the 8250 layer:

    void            (*rs485_start_tx)(struct uart_8250_port *);
    void            (*rs485_stop_tx)(struct uart_8250_port *);

   Used to control the transceiver switch of 485

initialization

uart_set_rs485_config--"driver rs485_config callback

serial8250_em485_config-, in addition to the initialization of basic structure members, there are two processing functions of high-precision timers, which are used to handle switching after delay.

static int serial8250_em485_init(struct uart_8250_port *p)
{
	if (p->em485)
		return 0;

	p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC);
	if (!p->em485)
		return -ENOMEM;

	hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC,
		     HRTIMER_MODE_REL);
	hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC,
		     HRTIMER_MODE_REL);
	p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx;
	p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
	p->em485->port = p;
	p->em485->active_timer = NULL;
	p->em485->tx_stopped = true;

	p->rs485_stop_tx(p);

	return 0;
}

485 transceiver switching

It is relatively easy to receive by default and switch to send through the interface start_tx_rs485.

When switching back to receiving, due to the existence of sending FIFO, it needs to be processed. Judgment processing is added to the kernel code. The code is as follows:

static inline void __stop_tx(struct uart_8250_port *p)
{
	struct uart_8250_em485 *em485 = p->em485;

	if (em485) {
		unsigned char lsr = serial_in(p, UART_LSR);
		/*
		 * To provide required timeing and allow FIFO transfer,
		 * __stop_tx_rs485() must be called only when both FIFO and
		 * shift register are empty. It is for device driver to enable
		 * interrupt on TEMT.
		 */
		if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
			return;

		__stop_tx_rs485(p);
	}
	__do_stop_tx(p);
}

The LSR register is mainly judged here. If the lsr register is not implemented, the switching of 485 will never be carried outThe author encountered this unsupported situation.

delay_after_send

   Since there is no support of lsr, it is necessary to rely on delay to handle when to switch. The kernel code already supports, that is delay_after_send, the unit is ms.

    For example, send 640 bytes and send fifo size is 64, then we can set this delay as

   10bit*1000ms*len/baud

   =10*1000*64/115200= 5.56~~6ms

   Actual test: trigger when the sending FIFO is configured to be empty, and send 64 pieces each time, then configure a delay of 7ms

    If 650 bytes are sent, 10 bytes are sent for the last time,

  10*1000*10/115200=0~1ms, then the delay configuration is 2ms

  __stop_tx is called by the user after the user buffer data has been sent .

It can be seen that the delay is strongly related to the FIFO size and trigger threshold of the chip.

Guess you like

Origin blog.csdn.net/proware/article/details/130451265