@ -43,6 +43,8 @@
# include <linux/platform_data/atmel.h>
# include <linux/timer.h>
# include <linux/gpio.h>
# include <linux/gpio/consumer.h>
# include <linux/err.h>
# include <asm/io.h>
# include <asm/ioctls.h>
@ -57,6 +59,8 @@
# include <linux/serial_core.h>
# include "serial_mctrl_gpio.h"
static void atmel_start_rx ( struct uart_port * port ) ;
static void atmel_stop_rx ( struct uart_port * port ) ;
@ -162,7 +166,7 @@ struct atmel_uart_port {
struct circ_buf rx_ring ;
struct serial_rs485 rs485 ; /* rs485 settings */
int rts_gpio ; /* optional RTS GPIO */
struct mctrl_gpios * gpios ;
unsigned int tx_done_mask ;
bool is_usart ; /* usart or uart */
struct timer_list uart_timer ; /* uart timer */
@ -237,6 +241,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)
return atmel_port - > use_dma_rx ;
}
static unsigned int atmel_get_lines_status ( struct uart_port * port )
{
struct atmel_uart_port * atmel_port = to_atmel_uart_port ( port ) ;
unsigned int status , ret = 0 ;
status = UART_GET_CSR ( port ) ;
mctrl_gpio_get ( atmel_port - > gpios , & ret ) ;
if ( ! IS_ERR_OR_NULL ( mctrl_gpio_to_gpiod ( atmel_port - > gpios ,
UART_GPIO_CTS ) ) ) {
if ( ret & TIOCM_CTS )
status & = ~ ATMEL_US_CTS ;
else
status | = ATMEL_US_CTS ;
}
if ( ! IS_ERR_OR_NULL ( mctrl_gpio_to_gpiod ( atmel_port - > gpios ,
UART_GPIO_DSR ) ) ) {
if ( ret & TIOCM_DSR )
status & = ~ ATMEL_US_DSR ;
else
status | = ATMEL_US_DSR ;
}
if ( ! IS_ERR_OR_NULL ( mctrl_gpio_to_gpiod ( atmel_port - > gpios ,
UART_GPIO_RI ) ) ) {
if ( ret & TIOCM_RI )
status & = ~ ATMEL_US_RI ;
else
status | = ATMEL_US_RI ;
}
if ( ! IS_ERR_OR_NULL ( mctrl_gpio_to_gpiod ( atmel_port - > gpios ,
UART_GPIO_DCD ) ) ) {
if ( ret & TIOCM_CD )
status & = ~ ATMEL_US_DCD ;
else
status | = ATMEL_US_DCD ;
}
return status ;
}
/* Enable or disable the rs485 support */
void atmel_config_rs485 ( struct uart_port * port , struct serial_rs485 * rs485conf )
{
@ -296,17 +344,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
unsigned int mode ;
struct atmel_uart_port * atmel_port = to_atmel_uart_port ( port ) ;
/*
* AT91RM9200 Errata # 39 : RTS0 is not internally connected
* to PA21 . We need to drive the pin as a GPIO .
*/
if ( gpio_is_valid ( atmel_port - > rts_gpio ) ) {
if ( mctrl & TIOCM_RTS )
gpio_set_value ( atmel_port - > rts_gpio , 0 ) ;
else
gpio_set_value ( atmel_port - > rts_gpio , 1 ) ;
}
if ( mctrl & TIOCM_RTS )
control | = ATMEL_US_RTSEN ;
else
@ -319,6 +356,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
UART_PUT_CR ( port , control ) ;
mctrl_gpio_set ( atmel_port - > gpios , mctrl ) ;
/* Local loopback mode? */
mode = UART_GET_MR ( port ) & ~ ATMEL_US_CHMODE ;
if ( mctrl & TIOCM_LOOP )
@ -346,7 +385,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
*/
static u_int atmel_get_mctrl ( struct uart_port * port )
{
unsigned int status , ret = 0 ;
struct atmel_uart_port * atmel_port = to_atmel_uart_port ( port ) ;
unsigned int ret = 0 , status ;
status = UART_GET_CSR ( port ) ;
@ -362,7 +402,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)
if ( ! ( status & ATMEL_US_RI ) )
ret | = TIOCM_RI ;
return ret ;
return mctrl_gpio_get ( atmel_port - > gpios , & ret ) ;
}
/*
@ -1042,7 +1082,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
unsigned int status , pending , pass_counter = 0 ;
do {
status = UART_GET_CSR ( port ) ;
status = atmel_get_lines_status ( port ) ;
pending = status & UART_GET_IMR ( port ) ;
if ( ! pending )
break ;
@ -1568,7 +1608,7 @@ static int atmel_startup(struct uart_port *port)
}
/* Save current CSR for comparison in atmel_tasklet_func() */
atmel_port - > irq_status_prev = UART_GET_CSR ( port ) ;
atmel_port - > irq_status_prev = atmel_get_lines_status ( port ) ;
atmel_port - > irq_status = atmel_port - > irq_status_prev ;
/*
@ -2324,6 +2364,15 @@ static int atmel_serial_resume(struct platform_device *pdev)
# define atmel_serial_resume NULL
# endif
static int atmel_init_gpios ( struct atmel_uart_port * p , struct device * dev )
{
p - > gpios = mctrl_gpio_init ( dev , 0 ) ;
if ( IS_ERR_OR_NULL ( p - > gpios ) )
return - 1 ;
return 0 ;
}
static int atmel_serial_probe ( struct platform_device * pdev )
{
struct atmel_uart_port * port ;
@ -2359,25 +2408,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
port = & atmel_ports [ ret ] ;
port - > backup_imr = 0 ;
port - > uart . line = ret ;
port - > rts_gpio = - EINVAL ; /* Invalid, zero could be valid */
if ( pdata )
port - > rts_gpio = pdata - > rts_gpio ;
else if ( np )
port - > rts_gpio = of_get_named_gpio ( np , " rts-gpios " , 0 ) ;
if ( gpio_is_valid ( port - > rts_gpio ) ) {
ret = devm_gpio_request ( & pdev - > dev , port - > rts_gpio , " RTS " ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " error requesting RTS GPIO \n " ) ;
goto err ;
}
/* Default to 1 as RTS is active low */
ret = gpio_direction_output ( port - > rts_gpio , 1 ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " error setting up RTS GPIO \n " ) ;
goto err ;
}
}
ret = atmel_init_gpios ( port , & pdev - > dev ) ;
if ( ret < 0 )
dev_err ( & pdev - > dev , " %s " ,
" Failed to initialize GPIOs. The serial port may not work as expected " ) ;
ret = atmel_init_port ( port , pdev ) ;
if ( ret )