MLK-14546 tty: serial: fsl_lpuart: add per_clk support
authorAndy Duan <fugang.duan@nxp.com>
Wed, 29 Mar 2017 06:56:19 +0000 (14:56 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:21:44 +0000 (15:21 -0500)
i.MX8QM lpuart has ipg_clk and per_clk, ipg_clk for bus and register
accessing, per_clk is lpuart module clock. Add per_clk support in
driver.

Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
Documentation/devicetree/bindings/serial/fsl-lpuart.txt
drivers/tty/serial/fsl_lpuart.c

index c95005e..9ad9ddc 100644 (file)
@@ -6,14 +6,24 @@ Required properties:
     on Vybrid vf610 SoC with 8-bit register organization
   - "fsl,ls1021a-lpuart" for lpuart compatible with the one integrated
     on LS1021A SoC with 32-bit big-endian register organization
+  - "fsl,imx7ulp-lpuart" for lpuart  compatible with the one integrated
+    on i.MX7ULP SoC with 32-bit little-endian register organization
+  - "fsl,imx8qm-lpuart"for lpuart  compatible with the one integrated
+    on i.MX8QM SoC with 32-bit little-endian register organization, which
+    is based on i.MX7ULP lpuart IP but add EEOP new feature.
 - reg : Address and length of the register set for the device
 - interrupts : Should contain uart interrupt
 - clocks : phandle + clock specifier pairs, one for each entry in clock-names
-- clock-names : should contain: "ipg" - the uart clock
+- clock-names : should contain: "ipg" - the uart peripheral register accessing
+  clock source, if "per" clock missing, the "ipg" clock also is the uart module
+  clock.
 
 Optional properties:
 - dmas: A list of two dma specifiers, one for each entry in dma-names.
 - dma-names: should contain "tx" and "rx".
+- clocks : phandle + clock specifier pairs, one for each entry in clock-names
+- clock-names : "per" - the uart module clock.
+  clock.
 
 Note: Optional properties for DMA support. Write them both or both not.
 
index 83c0a4c..2eabc9a 100644 (file)
 
 struct lpuart_port {
        struct uart_port        port;
-       struct clk              *clk;
+       struct clk              *ipg_clk;
+       struct clk              *per_clk;
        unsigned int            txfifo_size;
        unsigned int            rxfifo_size;
        bool                    lpuart32;
@@ -270,12 +271,11 @@ static const struct of_device_id lpuart_dt_ids[] = {
                .compatible = "fsl,ls1021a-lpuart",
        },
        {
-               .compatible = "fsl,imx8qm-lpuart",
+               .compatible = "fsl,imx7ulp-lpuart",
        },
        {
-               .compatible = "fsl,imx7ulp-lpuart",
+               .compatible = "fsl,imx8qm-lpuart",
        },
-
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
@@ -1140,6 +1140,15 @@ static int lpuart_startup(struct uart_port *port)
        unsigned long flags;
        unsigned char temp;
 
+       ret = clk_prepare_enable(sport->ipg_clk);
+       if (ret)
+               return ret;
+       ret = clk_prepare_enable(sport->per_clk);
+       if (ret) {
+               clk_disable_unprepare(sport->ipg_clk);
+               return ret;
+       }
+
        /* determine FIFO size and enable FIFO mode */
        temp = readb(sport->port.membase + UARTPFIFO);
 
@@ -1197,6 +1206,15 @@ static int lpuart32_startup(struct uart_port *port)
        unsigned long flags;
        unsigned long temp;
 
+       ret = clk_prepare_enable(sport->ipg_clk);
+       if (ret)
+               return ret;
+       ret = clk_prepare_enable(sport->per_clk);
+       if (ret) {
+               clk_disable_unprepare(sport->ipg_clk);
+               return ret;
+       }
+
        /* determine FIFO size */
        temp = lpuart32_read(sport->port.membase + UARTFIFO);
 
@@ -1253,6 +1271,8 @@ static void lpuart_shutdown(struct uart_port *port)
 
                lpuart_stop_tx(port);
        }
+       clk_disable_unprepare(sport->per_clk);
+       clk_disable_unprepare(sport->ipg_clk);
 }
 
 static void lpuart32_shutdown(struct uart_port *port)
@@ -1272,6 +1292,9 @@ static void lpuart32_shutdown(struct uart_port *port)
        spin_unlock_irqrestore(&port->lock, flags);
 
        devm_free_irq(port->dev, port->irq, sport);
+
+       clk_disable_unprepare(sport->per_clk);
+       clk_disable_unprepare(sport->ipg_clk);
 }
 
 static void
@@ -1755,7 +1778,10 @@ lpuart_console_get_options(struct lpuart_port *sport, int *baud,
        brfa = readb(sport->port.membase + UARTCR4);
        brfa &= UARTCR4_BRFA_MASK;
 
-       uartclk = clk_get_rate(sport->clk);
+       if (sport->per_clk)
+               uartclk = clk_get_rate(sport->per_clk);
+       else
+               uartclk = clk_get_rate(sport->ipg_clk);
        /*
         * baud = mod_clk/(16*(sbr[13]+(brfa)/32)
         */
@@ -1798,7 +1824,11 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
        bd = lpuart32_read(sport->port.membase + UARTBAUD);
        bd &= UARTBAUD_SBR_MASK;
        sbr = bd;
-       uartclk = clk_get_rate(sport->clk);
+       if (sport->per_clk)
+               uartclk = clk_get_rate(sport->per_clk);
+       else
+               uartclk = clk_get_rate(sport->ipg_clk);
+
        /*
         * baud = mod_clk/(16*(sbr[13]+(brfa)/32)
         */
@@ -1816,6 +1846,7 @@ static int __init lpuart_console_setup(struct console *co, char *options)
        int bits = 8;
        int parity = 'n';
        int flow = 'n';
+       int ret;
 
        /*
         * check whether an invalid uart number has been specified, and
@@ -1829,6 +1860,15 @@ static int __init lpuart_console_setup(struct console *co, char *options)
        if (sport == NULL)
                return -ENODEV;
 
+       ret = clk_prepare_enable(sport->ipg_clk);
+       if (ret)
+               return ret;
+       ret = clk_prepare_enable(sport->per_clk);
+       if (ret) {
+               clk_disable_unprepare(sport->ipg_clk);
+               return ret;
+       }
+
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
        else
@@ -1901,7 +1941,9 @@ static int lpuart_probe(struct platform_device *pdev)
                return ret;
        }
        sport->port.line = ret;
-       sport->lpuart32 = 1; /* of_device_is_compatible(np, "fsl,imx8dv-lpuart"); */
+       sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart") |
+                       of_device_is_compatible(np, "fsl,imx7ulp-lpuart") |
+                       of_device_is_compatible(np, "fsl,imx8qm-lpuart");
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
@@ -1927,21 +1969,31 @@ static int lpuart_probe(struct platform_device *pdev)
 
        sport->port.rs485_config = lpuart_config_rs485;
 
-       sport->clk = devm_clk_get(&pdev->dev, "ipg");
-       if (IS_ERR(sport->clk)) {
-               ret = PTR_ERR(sport->clk);
-               dev_err(&pdev->dev, "failed to get uart clk: %d\n", ret);
+       sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+       if (IS_ERR(sport->ipg_clk)) {
+               ret = PTR_ERR(sport->per_clk);
+               dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
                return ret;
        }
+       sport->per_clk = devm_clk_get(&pdev->dev, "per");
+       if (IS_ERR(sport->per_clk))
+               sport->per_clk = NULL;
 
-       ret = clk_prepare_enable(sport->clk);
+       ret = clk_prepare_enable(sport->ipg_clk);
        if (ret) {
+               dev_err(&pdev->dev, "failed to enable uart ipg clk: %d\n", ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(sport->per_clk);
+       if (ret) {
+               clk_disable_unprepare(sport->ipg_clk);
                dev_err(&pdev->dev, "failed to enable uart clk: %d\n", ret);
                return ret;
        }
-
-       sport->port.uartclk = clk_get_rate(sport->clk);
-       pr_info("uartclk = %ld\n", clk_get_rate(sport->clk));
+       if (sport->per_clk)
+               sport->port.uartclk = clk_get_rate(sport->per_clk);
+       else
+               sport->port.uartclk = clk_get_rate(sport->ipg_clk);
 
        lpuart_ports[sport->port.line] = sport;
 
@@ -1954,7 +2006,8 @@ static int lpuart_probe(struct platform_device *pdev)
 
        ret = uart_add_one_port(&lpuart_reg, &sport->port);
        if (ret) {
-               clk_disable_unprepare(sport->clk);
+               clk_disable_unprepare(sport->per_clk);
+               clk_disable_unprepare(sport->ipg_clk);
                return ret;
        }
 
@@ -1964,6 +2017,8 @@ static int lpuart_probe(struct platform_device *pdev)
                writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM);
        }
 
+       clk_disable_unprepare(sport->per_clk);
+       clk_disable_unprepare(sport->ipg_clk);
        return 0;
 }
 
@@ -1973,8 +2028,6 @@ static int lpuart_remove(struct platform_device *pdev)
 
        uart_remove_one_port(&lpuart_reg, &sport->port);
 
-       clk_disable_unprepare(sport->clk);
-
        if (sport->dma_tx_chan)
                dma_release_channel(sport->dma_tx_chan);
 
@@ -1989,6 +2042,11 @@ static int lpuart_suspend(struct device *dev)
 {
        struct lpuart_port *sport = dev_get_drvdata(dev);
        unsigned long temp;
+       int ret;
+
+       ret = clk_prepare_enable(sport->ipg_clk);
+       if (ret)
+               return ret;
 
        if (sport->lpuart32) {
                /* disable Rx/Tx and interrupts */
@@ -2027,8 +2085,7 @@ static int lpuart_suspend(struct device *dev)
                dmaengine_terminate_all(sport->dma_tx_chan);
        }
 
-       if (sport->port.suspended && !sport->port.irq_wake)
-               clk_disable_unprepare(sport->clk);
+       clk_disable_unprepare(sport->ipg_clk);
 
        return 0;
 }
@@ -2038,8 +2095,7 @@ static int lpuart_resume(struct device *dev)
        struct lpuart_port *sport = dev_get_drvdata(dev);
        unsigned long temp;
 
-       if (sport->port.suspended && !sport->port.irq_wake)
-               clk_prepare_enable(sport->clk);
+       clk_prepare_enable(sport->ipg_clk);
 
        if (sport->lpuart32) {
                lpuart32_setup_watermark(sport);
@@ -2076,6 +2132,8 @@ static int lpuart_resume(struct device *dev)
 
        uart_resume_port(&lpuart_reg, &sport->port);
 
+       clk_disable_unprepare(sport->ipg_clk);
+
        return 0;
 }
 #endif