]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
tty/serial: atmel_serial: add device tree support
authorNicolas Ferre <nicolas.ferre@atmel.com>
Wed, 12 Oct 2011 16:07:00 +0000 (18:07 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 18 Oct 2011 23:42:08 +0000 (16:42 -0700)
Will use aliases to enumerate ports, if available.

Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/tty/serial/atmel_serial.c

index 10743297a001ed524046ac79c0e6e238f61ece45..fc4081ead7275814514213654c6b2745fc0042bb 100644 (file)
@@ -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),
        },
 };