summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/serial/fsl-lpuart.txt12
-rw-r--r--drivers/tty/serial/fsl_lpuart.c102
2 files changed, 91 insertions, 23 deletions
diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index c95005efbcb8..9ad9ddc7c666 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -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.
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 531bbb773879..41cf98fdaba4 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -237,7 +237,8 @@
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
@@ -1905,7 +1945,9 @@ static int lpuart_probe(struct platform_device *pdev)
return -EINVAL;
}
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);
@@ -1931,21 +1973,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;
@@ -1958,7 +2010,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;
}
@@ -1968,6 +2021,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;
}
@@ -1977,8 +2032,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);
@@ -1993,6 +2046,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 */
@@ -2031,8 +2089,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;
}
@@ -2042,8 +2099,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);
@@ -2080,6 +2136,8 @@ static int lpuart_resume(struct device *dev)
uart_resume_port(&lpuart_reg, &sport->port);
+ clk_disable_unprepare(sport->ipg_clk);
+
return 0;
}
#endif