1
0
Fork 0

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
Andy Duan 2017-03-29 14:56:19 +08:00 committed by Jason Liu
parent 90110f2499
commit ca29eee743
2 changed files with 87 additions and 18 deletions

View File

@ -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.

View File

@ -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