mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
tty: serial: fsl_lpuart: add imx8qxp support
The lpuart of imx8ulp is basically the same as imx7ulp, but it has new feature support based on imx7ulp, like it can assert a DMA request on EOP(end-of-packet). imx8ulp lpuart use two clocks, one is ipg bus clock that is used to access registers, the other is baud clock that is used to transmit-receive data. Signed-off-by: Fugang Duan <fugang.duan@nxp.com> Link: https://lore.kernel.org/r/20190704134007.2316-1-fugang.duan@nxp.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
011bd05d1f
commit
35a4ed0164
1 changed files with 86 additions and 20 deletions
|
@ -234,9 +234,18 @@
|
|||
|
||||
static DEFINE_IDA(fsl_lpuart_ida);
|
||||
|
||||
enum lpuart_type {
|
||||
VF610_LPUART,
|
||||
LS1021A_LPUART,
|
||||
IMX7ULP_LPUART,
|
||||
IMX8QXP_LPUART,
|
||||
};
|
||||
|
||||
struct lpuart_port {
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
enum lpuart_type devtype;
|
||||
struct clk *ipg_clk;
|
||||
struct clk *baud_clk;
|
||||
unsigned int txfifo_size;
|
||||
unsigned int rxfifo_size;
|
||||
|
||||
|
@ -261,19 +270,29 @@ struct lpuart_port {
|
|||
};
|
||||
|
||||
struct lpuart_soc_data {
|
||||
char iotype;
|
||||
u8 reg_off;
|
||||
enum lpuart_type devtype;
|
||||
char iotype;
|
||||
u8 reg_off;
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data vf_data = {
|
||||
.devtype = VF610_LPUART,
|
||||
.iotype = UPIO_MEM,
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data ls_data = {
|
||||
.devtype = LS1021A_LPUART,
|
||||
.iotype = UPIO_MEM32BE,
|
||||
};
|
||||
|
||||
static struct lpuart_soc_data imx_data = {
|
||||
static struct lpuart_soc_data imx7ulp_data = {
|
||||
.devtype = IMX7ULP_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
.reg_off = IMX_REG_OFF,
|
||||
};
|
||||
|
||||
static struct lpuart_soc_data imx8qxp_data = {
|
||||
.devtype = IMX8QXP_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
.reg_off = IMX_REG_OFF,
|
||||
};
|
||||
|
@ -281,7 +300,8 @@ static struct lpuart_soc_data imx_data = {
|
|||
static const struct of_device_id lpuart_dt_ids[] = {
|
||||
{ .compatible = "fsl,vf610-lpuart", .data = &vf_data, },
|
||||
{ .compatible = "fsl,ls1021a-lpuart", .data = &ls_data, },
|
||||
{ .compatible = "fsl,imx7ulp-lpuart", .data = &imx_data, },
|
||||
{ .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, },
|
||||
{ .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
||||
|
@ -289,6 +309,11 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
|||
/* Forward declare this for the dma callbacks*/
|
||||
static void lpuart_dma_tx_complete(void *arg);
|
||||
|
||||
static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
|
||||
{
|
||||
return sport->devtype == IMX8QXP_LPUART;
|
||||
}
|
||||
|
||||
static inline u32 lpuart32_read(struct uart_port *port, u32 off)
|
||||
{
|
||||
switch (port->iotype) {
|
||||
|
@ -314,6 +339,39 @@ static inline void lpuart32_write(struct uart_port *port, u32 val,
|
|||
}
|
||||
}
|
||||
|
||||
static int __lpuart_enable_clks(struct lpuart_port *sport, bool is_en)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (is_en) {
|
||||
ret = clk_prepare_enable(sport->ipg_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(sport->baud_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(sport->ipg_clk);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
clk_disable_unprepare(sport->baud_clk);
|
||||
clk_disable_unprepare(sport->ipg_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
|
||||
{
|
||||
if (is_imx8qxp_lpuart(sport))
|
||||
return clk_get_rate(sport->baud_clk);
|
||||
|
||||
return clk_get_rate(sport->ipg_clk);
|
||||
}
|
||||
|
||||
#define lpuart_enable_clks(x) __lpuart_enable_clks(x, true)
|
||||
#define lpuart_disable_clks(x) __lpuart_enable_clks(x, false)
|
||||
|
||||
static void lpuart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned char temp;
|
||||
|
@ -2069,7 +2127,7 @@ 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);
|
||||
uartclk = lpuart_get_baud_clk_rate(sport);
|
||||
/*
|
||||
* baud = mod_clk/(16*(sbr[13]+(brfa)/32)
|
||||
*/
|
||||
|
@ -2112,7 +2170,7 @@ 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);
|
||||
uartclk = lpuart_get_baud_clk_rate(sport);
|
||||
/*
|
||||
* baud = mod_clk/(16*(sbr[13]+(brfa)/32)
|
||||
*/
|
||||
|
@ -2286,6 +2344,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||
sport->port.mapbase = res->start;
|
||||
sport->port.dev = &pdev->dev;
|
||||
sport->port.type = PORT_LPUART;
|
||||
sport->devtype = sdata->devtype;
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot obtain irq\n");
|
||||
|
@ -2301,20 +2360,27 @@ 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->ipg_clk);
|
||||
dev_err(&pdev->dev, "failed to get uart ipg clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(sport->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable uart clk: %d\n", ret);
|
||||
return ret;
|
||||
sport->baud_clk = NULL;
|
||||
if (is_imx8qxp_lpuart(sport)) {
|
||||
sport->baud_clk = devm_clk_get(&pdev->dev, "baud");
|
||||
if (IS_ERR(sport->baud_clk)) {
|
||||
ret = PTR_ERR(sport->baud_clk);
|
||||
dev_err(&pdev->dev, "failed to get uart baud clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
sport->port.uartclk = clk_get_rate(sport->clk);
|
||||
ret = lpuart_enable_clks(sport);
|
||||
if (ret)
|
||||
return ret;
|
||||
sport->port.uartclk = lpuart_get_baud_clk_rate(sport);
|
||||
|
||||
lpuart_ports[sport->port.line] = sport;
|
||||
|
||||
|
@ -2362,7 +2428,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||
|
||||
failed_attach_port:
|
||||
failed_irq_request:
|
||||
clk_disable_unprepare(sport->clk);
|
||||
lpuart_disable_clks(sport);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2374,7 +2440,7 @@ static int lpuart_remove(struct platform_device *pdev)
|
|||
|
||||
ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
|
||||
|
||||
clk_disable_unprepare(sport->clk);
|
||||
lpuart_disable_clks(sport);
|
||||
|
||||
if (sport->dma_tx_chan)
|
||||
dma_release_channel(sport->dma_tx_chan);
|
||||
|
@ -2439,7 +2505,7 @@ static int lpuart_suspend(struct device *dev)
|
|||
}
|
||||
|
||||
if (sport->port.suspended && !irq_wake)
|
||||
clk_disable_unprepare(sport->clk);
|
||||
lpuart_disable_clks(sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2451,7 +2517,7 @@ static int lpuart_resume(struct device *dev)
|
|||
unsigned long temp;
|
||||
|
||||
if (sport->port.suspended && !irq_wake)
|
||||
clk_prepare_enable(sport->clk);
|
||||
lpuart_enable_clks(sport);
|
||||
|
||||
if (lpuart_is_32(sport)) {
|
||||
lpuart32_setup_watermark(sport);
|
||||
|
|
Loading…
Reference in a new issue