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.
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;
.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);
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);
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);
lpuart_stop_tx(port);
}
+ clk_disable_unprepare(sport->per_clk);
+ clk_disable_unprepare(sport->ipg_clk);
}
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
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)
*/
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)
*/
int bits = 8;
int parity = 'n';
int flow = 'n';
+ int ret;
/*
* check whether an invalid uart number has been specified, and
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
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);
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;
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;
}
writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM);
}
+ clk_disable_unprepare(sport->per_clk);
+ clk_disable_unprepare(sport->ipg_clk);
return 0;
}
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);
{
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 */
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;
}
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);
uart_resume_port(&lpuart_reg, &sport->port);
+ clk_disable_unprepare(sport->ipg_clk);
+
return 0;
}
#endif