@@ -13,8 +13,9 @@ Required properties:
Optional properties:
- atmel,use-dma-rx: use of PDC or DMA for receiving data
- atmel,use-dma-tx: use of PDC or DMA for transmitting data
-- rts-gpios: specify a GPIO for RTS line. It will use specified PIO instead of the peripheral
- function pin for the USART RTS feature. If unsure, don't specify this property.
+- {rts,cts,dtr,dsr,ri,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively.
+ It will use specified PIO instead of the peripheral function pin for the USART feature.
+ If unsure, don't specify this property.
- add dma bindings for dma transfer:
- dmas: DMA specifier, consisting of a phandle to DMA controller node,
memory peripheral interface and USART DMA channel ID, FIFO configuration.
@@ -35,7 +36,12 @@ Example:
clock-names = "usart";
atmel,use-dma-rx;
atmel,use-dma-tx;
- rts-gpios = <&pioD 15 0>;
+ rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
+ cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>;
+ dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>;
+ dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>;
+ dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>;
+ ri-gpios = <&pioD 19 GPIO_ACTIVE_LOW>;
};
- use DMA:
@@ -923,6 +923,11 @@ static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -962,6 +967,11 @@ static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1013,6 +1023,11 @@ static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1065,6 +1080,11 @@ static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1109,6 +1129,11 @@ static struct atmel_uart_data uart3_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart3_dmamask = DMA_BIT_MASK(32);
@@ -820,6 +820,11 @@ static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -859,6 +864,11 @@ static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -911,6 +921,11 @@ static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -955,6 +970,11 @@ static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -999,6 +1019,11 @@ static struct atmel_uart_data uart3_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart3_dmamask = DMA_BIT_MASK(32);
@@ -1043,6 +1068,11 @@ static struct atmel_uart_data uart4_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart4_dmamask = DMA_BIT_MASK(32);
@@ -1082,6 +1112,11 @@ static struct atmel_uart_data uart5_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart5_dmamask = DMA_BIT_MASK(32);
@@ -881,6 +881,11 @@ static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -920,6 +925,11 @@ static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -964,6 +974,11 @@ static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1008,6 +1023,11 @@ static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1325,6 +1325,11 @@ static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -1364,6 +1369,11 @@ static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1408,6 +1418,11 @@ static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1452,6 +1467,11 @@ static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1588,6 +1588,11 @@ static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -1627,6 +1632,11 @@ static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1671,6 +1681,11 @@ static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1715,6 +1730,11 @@ static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1759,6 +1779,11 @@ static struct atmel_uart_data uart3_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart3_dmamask = DMA_BIT_MASK(32);
@@ -957,6 +957,11 @@ static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -996,6 +1001,11 @@ static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1048,6 +1058,11 @@ static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1092,6 +1107,11 @@ static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1136,6 +1156,11 @@ static struct atmel_uart_data uart3_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
+ .cts_gpio = -EINVAL,
+ .dtr_gpio = -EINVAL,
+ .dsr_gpio = -EINVAL,
+ .ri_gpio = -EINVAL,
+ .dcd_gpio = -EINVAL,
};
static u64 uart3_dmamask = DMA_BIT_MASK(32);
@@ -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/irq.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,8 +166,10 @@ 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;
+ int gpio_irq[UART_GPIO_MAX_INPUT];
unsigned int tx_done_mask;
+ bool ms_irq_enabled;
bool is_usart; /* usart or uart */
struct timer_list uart_timer; /* uart timer */
int (*prepare_rx)(struct uart_port *port);
@@ -237,6 +243,46 @@ 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(atmel_port->gpios.gpio[UART_GPIO_CTS])) {
+ if (ret & TIOCM_CTS)
+ status &= ~ATMEL_US_CTS;
+ else
+ status |= ATMEL_US_CTS;
+ }
+
+ if (!IS_ERR_OR_NULL(atmel_port->gpios.gpio[UART_GPIO_DSR])) {
+ if (ret & TIOCM_DSR)
+ status &= ~ATMEL_US_DSR;
+ else
+ status |= ATMEL_US_DSR;
+ }
+
+ if (!IS_ERR_OR_NULL(atmel_port->gpios.gpio[UART_GPIO_RI])) {
+ if (ret & TIOCM_RI)
+ status &= ~ATMEL_US_RI;
+ else
+ status |= ATMEL_US_RI;
+ }
+
+ if (!IS_ERR_OR_NULL(atmel_port->gpios.gpio[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 +342,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 +354,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 +383,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 +400,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);
}
/*
@@ -449,8 +487,38 @@ static void atmel_stop_rx(struct uart_port *port)
*/
static void atmel_enable_ms(struct uart_port *port)
{
- UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
- | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ uint32_t ier = 0;
+
+ /*
+ * Interrupt should not be enabled twice
+ */
+ if (atmel_port->ms_irq_enabled)
+ return;
+
+ atmel_port->ms_irq_enabled = true;
+
+ if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
+ enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
+ else
+ ier |= ATMEL_US_CTSIC;
+
+ if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
+ enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
+ else
+ ier |= ATMEL_US_DSRIC;
+
+ if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
+ enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
+ else
+ ier |= ATMEL_US_RIIC;
+
+ if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
+ enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
+ else
+ ier |= ATMEL_US_DCDIC;
+
+ UART_PUT_IER(port, ier);
}
/*
@@ -1039,11 +1107,35 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
static irqreturn_t atmel_interrupt(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status, pending, pass_counter = 0;
+ bool gpio_handled = false;
do {
- status = UART_GET_CSR(port);
+ status = atmel_get_lines_status(port);
pending = status & UART_GET_IMR(port);
+ if (!gpio_handled) {
+ /*
+ * Dealing with GPIO interrupt
+ */
+ if ((irq >= 0) &&
+ (irq == atmel_port->gpio_irq[UART_GPIO_CTS]))
+ pending |= ATMEL_US_CTSIC;
+
+ if ((irq >= 0) &&
+ (irq == atmel_port->gpio_irq[UART_GPIO_DSR]))
+ pending |= ATMEL_US_DSRIC;
+
+ if ((irq >= 0) &&
+ (irq == atmel_port->gpio_irq[UART_GPIO_RI]))
+ pending |= ATMEL_US_RIIC;
+
+ if ((irq >= 0) &&
+ (irq == atmel_port->gpio_irq[UART_GPIO_DCD]))
+ pending |= ATMEL_US_DCDIC;
+
+ gpio_handled = true;
+ }
if (!pending)
break;
@@ -1523,6 +1615,45 @@ static void atmel_get_ip_name(struct uart_port *port)
}
}
+static void atmel_free_gpio_irq(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ enum mctrl_gpio_idx i;
+
+ for (i = UART_GPIO_MIN; i < UART_GPIO_MAX_INPUT; i++)
+ if (atmel_port->gpio_irq[i] >= 0)
+ free_irq(atmel_port->gpio_irq[i], port);
+}
+
+static int atmel_request_gpio_irq(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ int *irq = atmel_port->gpio_irq;
+ enum mctrl_gpio_idx i;
+ int err = 0;
+
+ for (i = UART_GPIO_MIN; (i < UART_GPIO_MAX_INPUT) && !err; i++) {
+ if (irq[i] < 0)
+ continue;
+
+ irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
+ err = request_irq(irq[i], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
+ get_mctrl_gpio_name(i), port);
+ if (err)
+ dev_err(port->dev, "atmel_startup - Can't get %s irq\n",
+ get_mctrl_gpio_name(i));
+ }
+
+ /*
+ * If something went wrong, rollback.
+ */
+ while (err && --i)
+ if (irq[i] >= 0)
+ free_irq(irq[i], port);
+
+ return err;
+}
+
/*
* Perform initialization and enable port for reception
*/
@@ -1539,6 +1670,7 @@ static int atmel_startup(struct uart_port *port)
* handle an unexpected interrupt
*/
UART_PUT_IDR(port, -1);
+ atmel_port->ms_irq_enabled = false;
/*
* Allocate the IRQ
@@ -1551,6 +1683,13 @@ static int atmel_startup(struct uart_port *port)
}
/*
+ * Get the GPIO lines IRQ
+ */
+ retval = atmel_request_gpio_irq(port);
+ if (retval)
+ goto free_irq;
+
+ /*
* Initialize DMA (if necessary)
*/
atmel_init_property(atmel_port, pdev);
@@ -1568,7 +1707,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;
/*
@@ -1614,6 +1753,11 @@ static int atmel_startup(struct uart_port *port)
}
return 0;
+
+free_irq:
+ free_irq(port->irq, port);
+
+ return retval;
}
/*
@@ -1661,9 +1805,12 @@ static void atmel_shutdown(struct uart_port *port)
atmel_port->rx_ring.tail = 0;
/*
- * Free the interrupt
+ * Free the interrupts
*/
free_irq(port->irq, port);
+ atmel_free_gpio_irq(port);
+
+ atmel_port->ms_irq_enabled = false;
}
/*
@@ -2327,6 +2474,86 @@ static int atmel_serial_resume(struct platform_device *pdev)
#define atmel_serial_resume NULL
#endif
+/*
+ * TODO:
+ * Suppress that stuff when the platform data is eradicated
+ */
+static int atmel_get_pdata_gpio(struct atmel_uart_port *p, struct device *dev)
+{
+ struct atmel_uart_data *pdata = dev_get_platdata(dev);
+ enum mctrl_gpio_idx i;
+ int err;
+ int ret = 0;
+
+ if (gpio_is_valid(pdata->cts_gpio))
+ p->gpios.gpio[UART_GPIO_CTS] = gpio_to_desc(pdata->cts_gpio);
+ if (gpio_is_valid(pdata->rts_gpio))
+ p->gpios.gpio[UART_GPIO_RTS] = gpio_to_desc(pdata->rts_gpio);
+ if (gpio_is_valid(pdata->dtr_gpio))
+ p->gpios.gpio[UART_GPIO_DTR] = gpio_to_desc(pdata->dtr_gpio);
+ if (gpio_is_valid(pdata->dsr_gpio))
+ p->gpios.gpio[UART_GPIO_DSR] = gpio_to_desc(pdata->dsr_gpio);
+ if (gpio_is_valid(pdata->dcd_gpio))
+ p->gpios.gpio[UART_GPIO_DCD] = gpio_to_desc(pdata->dcd_gpio);
+ if (gpio_is_valid(pdata->ri_gpio))
+ p->gpios.gpio[UART_GPIO_RI] = gpio_to_desc(pdata->ri_gpio);
+
+ for (i = UART_GPIO_MIN; i < UART_GPIO_MAX; i++) {
+ /*
+ * The GPIOs are maybe not all filled,
+ * this is not an error.
+ */
+ if (IS_ERR_OR_NULL(p->gpios.gpio[i]))
+ continue;
+
+ err = devm_gpio_request(dev, desc_to_gpio(p->gpios.gpio[i]),
+ get_mctrl_gpio_name(i));
+ if (err) {
+ dev_err(dev, "error requesting %s GPIO\n",
+ get_mctrl_gpio_name(i));
+ ret--;
+ continue;
+ }
+
+ /* Default to 1 as all signals are active low */
+ (void) gpiod_sysfs_set_active_low(p->gpios.gpio[i], 1);
+
+ if (i < UART_GPIO_MAX_INPUT)
+ err = gpiod_direction_input(p->gpios.gpio[i]);
+ else
+ err = gpiod_direction_output(p->gpios.gpio[i], 0);
+ if (err) {
+ dev_err(dev, "Unable to set direction for %s GPIO",
+ get_mctrl_gpio_name(i));
+ devm_gpio_free(dev, desc_to_gpio(p->gpios.gpio[i]));
+ p->gpios.gpio[i] = NULL;
+ ret--;
+ }
+ }
+
+ return ret;
+}
+
+static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
+{
+ struct atmel_uart_data *pdata = dev_get_platdata(dev);
+ enum mctrl_gpio_idx i;
+ int err;
+
+ if (pdata)
+ err = atmel_get_pdata_gpio(p, dev);
+ else
+ err = mctrl_gpio_init(dev, &p->gpios);
+
+ for (i = UART_GPIO_MIN; i < UART_GPIO_MAX_INPUT; i++)
+ if (IS_ERR_OR_NULL(p->gpios.gpio[i]))
+ p->gpio_irq[i] = -EINVAL;
+ else
+ p->gpio_irq[i] = gpiod_to_irq(p->gpios.gpio[i]);
+
+ return err;
+}
+
static int atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *port;
@@ -2362,25 +2589,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, "Failed to initialize %d GPIOs. The serial port may not work as expected",
+ ret * -1);
ret = atmel_init_port(port, pdev);
if (ret)
@@ -2434,6 +2647,7 @@ err_alloc_ring:
port->clk = NULL;
}
err:
+ mctrl_gpio_free(&port->gpios);
return ret;
}
@@ -2457,6 +2671,8 @@ static int atmel_serial_remove(struct platform_device *pdev)
clk_put(atmel_port->clk);
+ mctrl_gpio_free(&atmel_port->gpios);
+
return ret;
}
@@ -85,6 +85,11 @@ struct atmel_uart_data {
void __iomem *regs; /* virt. base address, if any */
struct serial_rs485 rs485; /* rs485 settings */
int rts_gpio; /* optional RTS GPIO */
+ int cts_gpio; /* optional CTS GPIO */
+ int dtr_gpio; /* optional DTR GPIO */
+ int dsr_gpio; /* optional DSR GPIO */
+ int dcd_gpio; /* optional DCD GPIO */
+ int ri_gpio; /* optional Ring GPIO */
};
/* Touchscreen Controller */
On sam9x5, dedicated CTS (and RTS) pins are unusable together with the LCDC, the EMAC, or the MMC because they share the same line. Moreover, the USART controller doesn't handle DTR/DSR/DCD/RI signals, so we have to control them via GPIO. This patch permits to use GPIOs to control the CTS/RTS/DTR/DSR/DCD/RI signals. Signed-off-by: Richard Genoud <richard.genoud@gmail.com> --- .../devicetree/bindings/serial/atmel-usart.txt | 12 +- arch/arm/mach-at91/at91rm9200_devices.c | 25 ++ arch/arm/mach-at91/at91sam9260_devices.c | 35 +++ arch/arm/mach-at91/at91sam9261_devices.c | 20 ++ arch/arm/mach-at91/at91sam9263_devices.c | 20 ++ arch/arm/mach-at91/at91sam9g45_devices.c | 25 ++ arch/arm/mach-at91/at91sam9rl_devices.c | 25 ++ drivers/tty/serial/atmel_serial.c | 290 ++++++++++++++++++--- include/linux/platform_data/atmel.h | 5 + 9 files changed, 417 insertions(+), 40 deletions(-)