MLK-14546 tty: serial: fsl_lpuart: add per_clk support
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>pull/10/head
parent
90110f2499
commit
ca29eee743
|
@ -8,14 +8,22 @@ Required properties:
|
|||
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.
|
||||
|
||||
|
|
|
@ -240,7 +240,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;
|
||||
|
||||
|
@ -1283,9 +1284,19 @@ static void rx_dma_timer_init(struct lpuart_port *sport)
|
|||
static int lpuart_startup(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
||||
int ret;
|
||||
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);
|
||||
|
||||
|
@ -1336,6 +1347,16 @@ static int lpuart32_startup(struct uart_port *port)
|
|||
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
||||
unsigned long flags;
|
||||
unsigned long temp;
|
||||
int ret;
|
||||
|
||||
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, UARTFIFO);
|
||||
|
@ -1386,10 +1407,13 @@ 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)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
||||
unsigned long temp;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -1402,6 +1426,9 @@ static void lpuart32_shutdown(struct uart_port *port)
|
|||
lpuart32_write(port, temp, UARTCTRL);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
clk_disable_unprepare(sport->per_clk);
|
||||
clk_disable_unprepare(sport->ipg_clk);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1955,7 +1982,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)
|
||||
*/
|
||||
|
@ -1998,7 +2028,11 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
|
|||
bd = lpuart32_read(&sport->port, 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)
|
||||
*/
|
||||
|
@ -2016,6 +2050,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
|
||||
|
@ -2029,6 +2064,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
|
||||
|
@ -2186,21 +2230,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;
|
||||
|
||||
|
@ -2233,7 +2287,8 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||
|
||||
failed_attach_port:
|
||||
failed_irq_request:
|
||||
clk_disable_unprepare(sport->clk);
|
||||
clk_disable_unprepare(sport->per_clk);
|
||||
clk_disable_unprepare(sport->ipg_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2243,7 +2298,8 @@ static int lpuart_remove(struct platform_device *pdev)
|
|||
|
||||
uart_remove_one_port(&lpuart_reg, &sport->port);
|
||||
|
||||
clk_disable_unprepare(sport->clk);
|
||||
clk_disable_unprepare(sport->per_clk);
|
||||
clk_disable_unprepare(sport->ipg_clk);
|
||||
|
||||
if (sport->dma_tx_chan)
|
||||
dma_release_channel(sport->dma_tx_chan);
|
||||
|
@ -2260,6 +2316,11 @@ static int lpuart_suspend(struct device *dev)
|
|||
struct lpuart_port *sport = dev_get_drvdata(dev);
|
||||
unsigned long temp;
|
||||
bool irq_wake;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(sport->ipg_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (lpuart_is_32(sport)) {
|
||||
/* disable Rx/Tx and interrupts */
|
||||
|
@ -2301,8 +2362,7 @@ static int lpuart_suspend(struct device *dev)
|
|||
dmaengine_terminate_all(sport->dma_tx_chan);
|
||||
}
|
||||
|
||||
if (sport->port.suspended && !irq_wake)
|
||||
clk_disable_unprepare(sport->clk);
|
||||
clk_disable_unprepare(sport->ipg_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2313,8 +2373,7 @@ static int lpuart_resume(struct device *dev)
|
|||
bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
|
||||
unsigned long temp;
|
||||
|
||||
if (sport->port.suspended && !irq_wake)
|
||||
clk_prepare_enable(sport->clk);
|
||||
clk_prepare_enable(sport->ipg_clk);
|
||||
|
||||
if (lpuart_is_32(sport)) {
|
||||
lpuart32_setup_watermark(sport);
|
||||
|
@ -2349,6 +2408,8 @@ static int lpuart_resume(struct device *dev)
|
|||
|
||||
uart_resume_port(&lpuart_reg, &sport->port);
|
||||
|
||||
clk_disable_unprepare(sport->ipg_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue