serial/efm32: parse location property
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Mon, 21 Jan 2013 13:22:56 +0000 (14:22 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 21 Jan 2013 21:56:46 +0000 (13:56 -0800)
The non-dt probing allowed passing the location via platform data from
the beginning. So make up leeway for device tree probing.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/devicetree/bindings/tty/serial/efm32-uart.txt
drivers/tty/serial/efm32-uart.c

index 6588b69..8e080b8 100644 (file)
@@ -5,10 +5,16 @@ Required properties:
 - reg : Address and length of the register set
 - interrupts : Should contain uart interrupt
 
+Optional properties:
+- location : Decides the location of the USART I/O pins.
+  Allowed range : [0 .. 5]
+  Default: 0
+
 Example:
 
 uart@0x4000c400 {
        compatible = "efm32,uart";
        reg = <0x4000c400 0x400>;
        interrupts = <15>;
+       location = <0>;
 };
index de14bd7..7d199c8 100644 (file)
@@ -81,6 +81,7 @@ struct efm32_uart_port {
        struct uart_port port;
        unsigned int txirq;
        struct clk *clk;
+       struct efm32_uart_pdata pdata;
 };
 #define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port)
 #define efm_debug(efm_port, format, arg...)                    \
@@ -293,13 +294,8 @@ static irqreturn_t efm32_uart_txirq(int irq, void *data)
 static int efm32_uart_startup(struct uart_port *port)
 {
        struct efm32_uart_port *efm_port = to_efm_port(port);
-       u32 location = 0;
-       struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev);
        int ret;
 
-       if (pdata)
-               location = UARTn_ROUTE_LOCATION(pdata->location);
-
        ret = clk_enable(efm_port->clk);
        if (ret) {
                efm_debug(efm_port, "failed to enable clk\n");
@@ -308,7 +304,9 @@ static int efm32_uart_startup(struct uart_port *port)
        port->uartclk = clk_get_rate(efm_port->clk);
 
        /* Enable pins at configured location */
-       efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
+       efm32_uart_write32(efm_port,
+                       UARTn_ROUTE_LOCATION(efm_port->pdata.location) |
+                       UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
                        UARTn_ROUTE);
 
        ret = request_irq(port->irq, efm32_uart_rxirq, 0,
@@ -667,11 +665,24 @@ static int efm32_uart_probe_dt(struct platform_device *pdev,
                struct efm32_uart_port *efm_port)
 {
        struct device_node *np = pdev->dev.of_node;
+       u32 location;
        int ret;
 
        if (!np)
                return 1;
 
+       ret = of_property_read_u32(np, "location", &location);
+       if (!ret) {
+               if (location > 5) {
+                       dev_err(&pdev->dev, "invalid location\n");
+                       return -EINVAL;
+               }
+               efm_debug(efm_port, "using location %u\n", location);
+               efm_port->pdata.location = location;
+       } else {
+               efm_debug(efm_port, "fall back to location 0\n");
+       }
+
        ret = of_alias_get_id(np, "serial");
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
@@ -731,10 +742,16 @@ static int efm32_uart_probe(struct platform_device *pdev)
        efm_port->port.flags = UPF_BOOT_AUTOCONF;
 
        ret = efm32_uart_probe_dt(pdev, efm_port);
-       if (ret > 0)
+       if (ret > 0) {
                /* not created by device tree */
+               const struct efm32_uart_pdata *pdata = dev_get_platdata(&pdev->dev);
+
                efm_port->port.line = pdev->id;
 
+               if (pdata)
+                       efm_port->pdata = *pdata;
+       }
+
        if (efm_port->port.line >= 0 &&
                        efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
                efm32_uart_ports[efm_port->port.line] = efm_port;