This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335x UART is not functioning in RS485 mode

Hi,

I am trying to add RS485  transceiver support to  UART5 in AM335x processor . I already applied patch for RS485 support in linux kernel. And its working file if i configure GPIO  other than RTS of serial ports (Ex : gpio3 20) as Transmission Direction Control (DE).  But if i assigned RTS of UART5 as its DE, it is not working as intended. DE pin is not toggling along with transmission of bytes. 

The linux code and dtb details are as follows.

In dtb, the serial port (ttys5) is configured as follows

uart5_pins: pinmux_uart5_pins {
pinctrl-single,pins = <
0xD8 (PIN_INPUT | MUX_MODE6) /* lcd_data14.uart5_ctsn */
0xDC (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* lcd_data15.uart5_rtsn */
0xC4 (PIN_INPUT_PULLUP | MUX_MODE4) /* lcd_data9.uart5_rxd */
0xC0 (PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* lcd_data8.uart5_txd */
>;
};

uart5: serial@481aa000 {
pinctrl-names = "default";
pinctrl-0 = <&uart5_pins>;
status = "okay";
rts-gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
rs485-rts-active-high;
rs485-rts-delay = <1 1>;
linux,rs485-enabled-at-boot-time; 
};

And in omap-serial.c,  modified 'serial_omap_config_rs485' function as follows

/* Enable or disable the rs485 support */
static void
serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags;
unsigned int mode;
int val;
int r = 0, gpioFlag = 1;

pm_runtime_get_sync(up->dev);
spin_lock_irqsave(&up->port.lock, flags);

/* Disable interrupts from this port */
mode = up->ier;
up->ier = 0;
serial_out(up, UART_IER, 0);

if(!(rs485conf->flags & SER_RS485_ENABLED))
{
if ((up->rs485.flags & SER_RS485_ENABLED) && (gpio_is_valid(up->rts_gpio)))
{
gpio_free(up->rts_gpio);
}

up->rs485 = *rs485conf;
gpioFlag = 0;
}

else if(!(up->rs485.flags & SER_RS485_ENABLED) ||
(up->rts_gpio != rs485conf->gpio_pin))
{

val = (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;
if (gpio_is_valid(rs485conf->gpio_pin))
{
r = gpio_request(rs485conf->gpio_pin, "RS485 TXE");
if (r) {
dev_warn(port->dev, "Could not request GPIO %d : %d\n",rs485conf->gpio_pin, r);
gpioFlag = 0;
}
r = gpio_direction_output(rs485conf->gpio_pin, val);
if (r) {
dev_warn(port->dev, "Could not drive GPIO %d : %d\n", rs485conf->gpio_pin, r);
gpio_free(rs485conf->gpio_pin);
gpioFlag = 0;
}
}
}

if (gpioFlag)
{
/* store new config */
up->rs485 = *rs485conf;

/*
* Just as a precaution, only allow rs485
* to be enabled if the gpio pin is valid
*/
up->rts_gpio = rs485conf->gpio_pin;

/* enable / disable rts */
val = (up->rs485.flags & SER_RS485_ENABLED) ?
SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND;
val = (up->rs485.flags & val) ? 1 : 0;

gpio_set_value(up->rts_gpio, val);
}


/* Enable interrupts */
up->ier = mode;
serial_out(up, UART_IER, up->ier);

spin_unlock_irqrestore(&up->port.lock, flags);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
}

And ensured that this function is executing properly.

 

Modified serial_omap_set_mctrl function as following 

static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char mcr = 0, old_mcr;

dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
if (mctrl & TIOCM_RTS)
mcr |= UART_MCR_RTS;
if (mctrl & TIOCM_DTR)
mcr |= UART_MCR_DTR;
if (mctrl & TIOCM_OUT1)
mcr |= UART_MCR_OUT1;
if (mctrl & TIOCM_OUT2)
mcr |= UART_MCR_OUT2;
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;

pm_runtime_get_sync(up->dev);
old_mcr = serial_in(up, UART_MCR);
old_mcr &= ~(UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_OUT1 |
UART_MCR_DTR | UART_MCR_RTS);
up->mcr = old_mcr | mcr;

printk(KERN_INFO "serial_omap_set_mctrl - %d %x \n", up->port.line, up->mcr);

serial_out(up, UART_MCR, up->mcr);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);

if (gpio_is_valid(up->DTR_gpio) &&
!!(mctrl & TIOCM_DTR) != up->DTR_active) {
up->DTR_active = !up->DTR_active;
if (gpio_cansleep(up->DTR_gpio))
schedule_work(&up->qos_work);
else
gpio_set_value(up->DTR_gpio,
up->DTR_active != up->DTR_inverted);
}
}

Still RS485 is not working if RTS pin is configured as  UART5 DE.

Please let me know if any mistake is there in my code/dtb .