|
@@ -33,6 +33,8 @@
|
|
|
#include <linux/sysrq.h>
|
|
|
#include <linux/tty_flip.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
+#include <linux/of.h>
|
|
|
+#include <linux/of_device.h>
|
|
|
#include <linux/dma-mapping.h>
|
|
|
#include <linux/atmel_pdc.h>
|
|
|
#include <linux/atmel_serial.h>
|
|
@@ -163,6 +165,16 @@ static unsigned long atmel_ports_in_use;
|
|
|
static struct console atmel_console;
|
|
|
#endif
|
|
|
|
|
|
+#if defined(CONFIG_OF)
|
|
|
+static const struct of_device_id atmel_serial_dt_ids[] = {
|
|
|
+ { .compatible = "atmel,at91rm9200-usart" },
|
|
|
+ { .compatible = "atmel,at91sam9260-usart" },
|
|
|
+ { /* sentinel */ }
|
|
|
+};
|
|
|
+
|
|
|
+MODULE_DEVICE_TABLE(of, atmel_serial_dt_ids);
|
|
|
+#endif
|
|
|
+
|
|
|
static inline struct atmel_uart_port *
|
|
|
to_atmel_uart_port(struct uart_port *uart)
|
|
|
{
|
|
@@ -1411,6 +1423,48 @@ static struct uart_ops atmel_pops = {
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
+static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
|
|
|
+ struct device_node *np)
|
|
|
+{
|
|
|
+ u32 rs485_delay[2];
|
|
|
+
|
|
|
+ /* DMA/PDC usage specification */
|
|
|
+ if (of_get_property(np, "atmel,use-dma-rx", NULL))
|
|
|
+ atmel_port->use_dma_rx = 1;
|
|
|
+ else
|
|
|
+ atmel_port->use_dma_rx = 0;
|
|
|
+ if (of_get_property(np, "atmel,use-dma-tx", NULL))
|
|
|
+ atmel_port->use_dma_tx = 1;
|
|
|
+ else
|
|
|
+ atmel_port->use_dma_tx = 0;
|
|
|
+
|
|
|
+ /* rs485 properties */
|
|
|
+ if (of_property_read_u32_array(np, "rs485-rts-delay",
|
|
|
+ rs485_delay, 2) == 0) {
|
|
|
+ struct serial_rs485 *rs485conf = &atmel_port->rs485;
|
|
|
+
|
|
|
+ rs485conf->delay_rts_before_send = rs485_delay[0];
|
|
|
+ rs485conf->delay_rts_after_send = rs485_delay[1];
|
|
|
+ rs485conf->flags = 0;
|
|
|
+
|
|
|
+ if (rs485conf->delay_rts_before_send == 0 &&
|
|
|
+ rs485conf->delay_rts_after_send == 0) {
|
|
|
+ rs485conf->flags |= SER_RS485_RTS_ON_SEND;
|
|
|
+ } else {
|
|
|
+ if (rs485conf->delay_rts_before_send)
|
|
|
+ rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND;
|
|
|
+ if (rs485conf->delay_rts_after_send)
|
|
|
+ rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (of_get_property(np, "rs485-rx-during-tx", NULL))
|
|
|
+ rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
|
|
+
|
|
|
+ if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
|
|
|
+ rs485conf->flags |= SER_RS485_ENABLED;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Configure the port from the platform device resource info.
|
|
|
*/
|
|
@@ -1420,6 +1474,14 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
|
|
|
struct uart_port *port = &atmel_port->uart;
|
|
|
struct atmel_uart_data *pdata = pdev->dev.platform_data;
|
|
|
|
|
|
+ if (pdev->dev.of_node) {
|
|
|
+ atmel_of_init_port(atmel_port, pdev->dev.of_node);
|
|
|
+ } else {
|
|
|
+ atmel_port->use_dma_rx = pdata->use_dma_rx;
|
|
|
+ atmel_port->use_dma_tx = pdata->use_dma_tx;
|
|
|
+ atmel_port->rs485 = pdata->rs485;
|
|
|
+ }
|
|
|
+
|
|
|
port->iotype = UPIO_MEM;
|
|
|
port->flags = UPF_BOOT_AUTOCONF;
|
|
|
port->ops = &atmel_pops;
|
|
@@ -1433,7 +1495,7 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
|
|
|
|
|
|
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
|
|
|
|
|
|
- if (pdata->regs) {
|
|
|
+ if (pdata && pdata->regs) {
|
|
|
/* Already mapped by setup code */
|
|
|
port->membase = pdata->regs;
|
|
|
} else {
|
|
@@ -1450,10 +1512,6 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
|
|
|
/* only enable clock when USART is in use */
|
|
|
}
|
|
|
|
|
|
- atmel_port->use_dma_rx = pdata->use_dma_rx;
|
|
|
- atmel_port->use_dma_tx = pdata->use_dma_tx;
|
|
|
- atmel_port->rs485 = pdata->rs485;
|
|
|
-
|
|
|
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
|
|
|
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
|
|
|
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
|
|
@@ -1718,17 +1776,21 @@ static int atmel_serial_resume(struct platform_device *pdev)
|
|
|
static int __devinit atmel_serial_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct atmel_uart_port *port;
|
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
|
struct atmel_uart_data *pdata = pdev->dev.platform_data;
|
|
|
void *data;
|
|
|
int ret = -ENODEV;
|
|
|
|
|
|
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
|
|
|
|
|
|
- if (pdata)
|
|
|
- ret = pdata->num;
|
|
|
+ if (np)
|
|
|
+ ret = of_alias_get_id(np, "serial");
|
|
|
+ else
|
|
|
+ if (pdata)
|
|
|
+ ret = pdata->num;
|
|
|
|
|
|
if (ret < 0)
|
|
|
- /* port id not found in platform data:
|
|
|
+ /* port id not found in platform data nor device-tree aliases:
|
|
|
* auto-enumerate it */
|
|
|
ret = find_first_zero_bit(&atmel_ports_in_use,
|
|
|
sizeof(atmel_ports_in_use));
|
|
@@ -1827,6 +1889,7 @@ static struct platform_driver atmel_serial_driver = {
|
|
|
.driver = {
|
|
|
.name = "atmel_usart",
|
|
|
.owner = THIS_MODULE,
|
|
|
+ .of_match_table = of_match_ptr(atmel_serial_dt_ids),
|
|
|
},
|
|
|
};
|
|
|
|