serial: lantiq: Update driver to support new SoC
v2 cover serial: lantiq: Update driver to support new SoC
There is a new Intel Atom based Lightning Mountain(LGM) network processor SoC which reuses Lantiq ASC serial controller IP. This patch series updates the driver design and code to add support for LGM SoC as well.
These patches are baselined upon Linux 5.3-rc2 at below Git tree:git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
Patch 1 modifies devicetree compatible string to a use explicit string instead of a fixed macro because this patch series adds support for multiple SoCs.
Patch 2 modifies driver design to support dynamic assignment of IRQ resources & ISRs based on devicetree node compatible entries. This is because new LGM SoC supports single IRQ for all tx/rx/err interrupts while older SoCs support three separate IRQs for tx/rx/err interrupts.
Patch 3 adds LGM SoC specific IRQ/ISR support.
v2:
* Address review concerns.
* Separate dt binding document from this patch series. Will try to push it separately by first converting existing txt file to YAML and then add new properties.
* Omit resending one patch in this series which is already reviewed & added to tty-next.
Rahul Tanwar (3):
serial: lantiq: Use proper DT compatible string
serial: lantiq: Make IRQ & ISR assignment dynamic
serial: lantiq: Add support for Lightning Mountain SoC
drivers/tty/serial/lantiq.c | 214 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 168 insertions(+), 46 deletions(-)
Signature · 1 line
2.11.0
PATCH v2 1/3 serial: lantiq: Use proper DT compatible string
Use explicit string instead of a macro for devicetree compatible string.
This series of patches is to add support for multiple SoCs which reuse the same serial controller IP. The following patches will add another compatible string to support new Lightning Mountain(LGM) SoC. So it makes sense to have the compatible strings explicitly mentioned instead of a fixed macro.
--- drivers/tty/serial/lantiq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/tty/serial/lantiq.c +2 -2
@@ -693,7 +693,7 @@ lqasc_serial_early_console_setup(struct earlycon_device *device, device->con->write = lqasc_serial_early_console_write;return 0 ; } -OF_EARLYCON_DECLARE (lantiq,DRVNAME , lqasc_serial_early_console_setup); +OF_EARLYCON_DECLARE (lantiq,"lantiq,asc" , lqasc_serial_early_console_setup);static struct uart_driver lqasc_reg = { .owner =THIS_MODULE ,
@@ -792,7 +792,7 @@ lqasc_probe(struct platform_device *pdev) }static const struct of_device_id ltq_asc_match[] = { - { .compatible =DRVNAME }, + { .compatible ="lantiq,asc" }, {}, };
Signature · 1 line
2.11.0
PATCH v2 2/3 serial: lantiq: Make IRQ & ISR assignment dynamic
In reply to Rahul TanwarThis driver/IP is reused across multiple SoCs. Older SoCs supported three separate IRQs for tx, rx & err interrupts. Newer Lightning Mountain SoC supports single IRQ for all of tx/rx/err interrupts. This patch modifies the driver design to support dynamic assignment of IRQ resources & ISRs based on devicetree node compatible entries.
--- drivers/tty/serial/lantiq.c | 141 ++++++++++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 45 deletions(-)
drivers/tty/serial/lantiq.c +96 -45
@@ -100,6 +100,12 @@ static void lqasc_tx_chars(struct uart_port *port);static struct ltq_uart_port *lqasc_port[MAXPORTS ];static struct uart_driver lqasc_reg; +struct ltq_soc_data { +int (*fetch_irq)(struct device *dev,struct ltq_uart_port *ltq_port); +int (*request_irq)(struct uart_port *port); +void (*free_irq)(struct uart_port *port); +}; +struct ltq_uart_port {struct uart_port port;/* clock used to derive divider */
@@ -110,6 +116,8 @@ struct ltq_uart_port {unsigned int rx_irq;unsigned int err_irq;spinlock_t lock;/* exclusive access for multi core */ + +const struct ltq_soc_data *soc; };static inline void asc_update_bits (u32 clear,u32 set,void __iomem *reg)
@@ -343,35 +351,12 @@ lqasc_startup(struct uart_port *port)spin_unlock_irqrestore (<q_port->lock, flags); - retval =request_irq (ltq_port->tx_irq, lqasc_tx_int, -0 ,"asc_tx" , port); -if (retval) { -pr_err ("failed to request lqasc_tx_int\n" ); + retval = ltq_port->soc->request_irq (port); +if (retval)return retval; - } - - retval =request_irq (ltq_port->rx_irq, lqasc_rx_int, -0 ,"asc_rx" , port); -if (retval) { -pr_err ("failed to request lqasc_rx_int\n" ); - goto err1; - } - - retval =request_irq (ltq_port->err_irq, lqasc_err_int, -0 ,"asc_err" , port); -if (retval) { -pr_err ("failed to request lqasc_err_int\n" ); - goto err2; - }__raw_writel (ASC_IRNREN_RX |ASC_IRNREN_ERR |ASC_IRNREN_TX , port->membase +LTQ_ASC_IRNREN ); -return 0 ; - -err2: -free_irq (ltq_port->rx_irq, port); -err1: -free_irq (ltq_port->tx_irq, port);return retval; }
@@ -381,9 +366,7 @@ lqasc_shutdown(struct uart_port *port)struct ltq_uart_port *ltq_port =to_ltq_uart_port (port);unsigned long flags; -free_irq (ltq_port->tx_irq, port); -free_irq (ltq_port->rx_irq, port); -free_irq (ltq_port->err_irq, port); + ltq_port->soc->free_irq (port);spin_lock_irqsave (<q_port->lock, flags);__raw_writel (0 , port->membase +LTQ_ASC_CON );
@@ -705,24 +688,98 @@ static struct uart_driver lqasc_reg = { .cons = &lqasc_console, }; +static int fetch_irq_lantiq (struct device *dev,struct ltq_uart_port *ltq_port) +{ +struct uart_port *port = <q_port->port; +struct resource irqres[3 ]; +int ret; + + ret =of_irq_to_resource_table (dev->of_node, irqres,3 ); +if (ret !=3 ) { +dev_err (dev, +"failed to get IRQs for serial port\n" ); +return -ENODEV ; + } + ltq_port->tx_irq = irqres[0 ].start; + ltq_port->rx_irq = irqres[1 ].start; + ltq_port->err_irq = irqres[2 ].start; + port->irq = irqres[0 ].start; + +return 0 ; +} + +static int request_irq_lantiq (struct uart_port *port) +{ +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); +int retval; + + retval =request_irq (ltq_port->tx_irq, lqasc_tx_int, +0 ,"asc_tx" , port); +if (retval) { +dev_err (port->dev,"failed to request asc_tx\n" ); +return retval; + } + + retval =request_irq (ltq_port->rx_irq, lqasc_rx_int, +0 ,"asc_rx" , port); +if (retval) { +dev_err (port->dev,"failed to request asc_rx\n" ); + goto err1; + } + + retval =request_irq (ltq_port->err_irq, lqasc_err_int, +0 ,"asc_err" , port); +if (retval) { +dev_err (port->dev,"failed to request asc_err\n" ); + goto err2; + } +return 0 ; + +err2: +free_irq (ltq_port->rx_irq, port); +err1: +free_irq (ltq_port->tx_irq, port); +return retval; +} + +static void free_irq_lantiq (struct uart_port *port) +{ +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); + +free_irq (ltq_port->tx_irq, port); +free_irq (ltq_port->rx_irq, port); +free_irq (ltq_port->err_irq, port); +} +static int __init lqasc_probe (struct platform_device *pdev) {struct device_node *node = pdev->dev.of_node;struct ltq_uart_port *ltq_port;struct uart_port *port; -struct resource *mmres, irqres[3 ]; +struct resource *mmres;int line;int ret; mmres =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); - ret =of_irq_to_resource_table (node, irqres,3 ); -if (!mmres || (ret !=3 )) { +if (!mmres) {dev_err (&pdev->dev, -"failed to get memory/irq for serial port\n" ); +"failed to get memory for serial port\n" );return -ENODEV ; } + ltq_port =devm_kzalloc (&pdev->dev,sizeof (struct ltq_uart_port ), +GFP_KERNEL ); +if (!ltq_port) +return -ENOMEM ; + + port = <q_port->port; + + ltq_port->soc =of_device_get_match_data (&pdev->dev); + ret = ltq_port->soc->fetch_irq (&pdev->dev, ltq_port); +if (ret) +return ret; +/* get serial id */ line =of_alias_get_id (node,"serial" );if (line <0 ) {
@@ -743,13 +800,6 @@ lqasc_probe(struct platform_device *pdev)return -EBUSY ; } - ltq_port =devm_kzalloc (&pdev->dev,sizeof (struct ltq_uart_port ), -GFP_KERNEL ); -if (!ltq_port) -return -ENOMEM ; - - port = <q_port->port; - port->iotype =SERIAL_IO_MEM ; port->flags =UPF_BOOT_AUTOCONF |UPF_IOREMAP ; port->ops = &lqasc_pops;
@@ -758,7 +808,6 @@ lqasc_probe(struct platform_device *pdev) port->line = line; port->dev = &pdev->dev;/* unused, just to be backward-compatible */ - port->irq = irqres[0 ].start; port->mapbase = mmres->start;if (IS_ENABLED (CONFIG_LANTIQ ) && !IS_ENABLED (CONFIG_COMMON_CLK ))
@@ -778,10 +827,6 @@ lqasc_probe(struct platform_device *pdev)else ltq_port->clk =devm_clk_get (&pdev->dev,"asc" ); - ltq_port->tx_irq = irqres[0 ].start; - ltq_port->rx_irq = irqres[1 ].start; - ltq_port->err_irq = irqres[2 ].start; -spin_lock_init (<q_port->lock); lqasc_port[line] = ltq_port;platform_set_drvdata (pdev, ltq_port);
@@ -791,8 +836,14 @@ lqasc_probe(struct platform_device *pdev)return ret; } +static const struct ltq_soc_data soc_data_lantiq = { + .fetch_irq = fetch_irq_lantiq, + .request_irq = request_irq_lantiq, + .free_irq = free_irq_lantiq, +}; +static const struct of_device_id ltq_asc_match[] = { - { .compatible ="lantiq,asc" }, + { .compatible ="lantiq,asc" , .data = &soc_data_lantiq }, {}, };
Signature · 1 line
2.11.0
PATCH v2 3/3 serial: lantiq: Add support for Lightning Mountain SoC
In reply to Rahul TanwarThis patch adds IRQ & ISR support in the driver for Lightning Mountain SoC.
--- drivers/tty/serial/lantiq.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+)
drivers/tty/serial/lantiq.c +71 -0
@@ -57,6 +57,7 @@#define ASC_IRNCR_TIR 0x1#define ASC_IRNCR_RIR 0x2#define ASC_IRNCR_EIR 0x4 +#define ASC_IRNCR_MASK GENMASK(2, 0)#define ASCOPT_CSIZE 0x3#define TXFIFO_FL 1
@@ -115,6 +116,7 @@ struct ltq_uart_port {unsigned int tx_irq;unsigned int rx_irq;unsigned int err_irq; +unsigned int common_irq;spinlock_t lock;/* exclusive access for multi core */ const struct ltq_soc_data *soc;
@@ -293,6 +295,31 @@ lqasc_rx_int(int irq, void *_port)return IRQ_HANDLED ; } +static irqreturn_t lqasc_irq (int irq,void *p) +{ +unsigned long flags; +u32 stat; +struct uart_port *port = p; +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); + +spin_lock_irqsave (<q_port->lock, flags); + stat =readl (port->membase +LTQ_ASC_IRNCR ); +spin_unlock_irqrestore (<q_port->lock, flags); +if (!(stat &ASC_IRNCR_MASK )) +return IRQ_NONE ; + +if (stat &ASC_IRNCR_TIR ) +lqasc_tx_int (irq, p); + +if (stat &ASC_IRNCR_RIR ) +lqasc_rx_int (irq, p); + +if (stat &ASC_IRNCR_EIR ) +lqasc_err_int (irq, p); + +return IRQ_HANDLED ; +} +static unsigned int lqasc_tx_empty (struct uart_port *port) {
@@ -677,6 +704,7 @@ lqasc_serial_early_console_setup(struct earlycon_device *device,return 0 ; }OF_EARLYCON_DECLARE (lantiq,"lantiq,asc" , lqasc_serial_early_console_setup); +OF_EARLYCON_DECLARE (lantiq,"intel,lgm-asc" , lqasc_serial_early_console_setup);static struct uart_driver lqasc_reg = { .owner =THIS_MODULE ,
@@ -751,6 +779,42 @@ static void free_irq_lantiq(struct uart_port *port)free_irq (ltq_port->err_irq, port); } +static int fetch_irq_intel (struct device *dev,struct ltq_uart_port *ltq_port) +{ +struct uart_port *port = <q_port->port; +int ret; + + ret =of_irq_get (dev->of_node,0 ); +if (ret <0 ) { +dev_err (dev,"failed to fetch IRQ for serial port\n" ); +return ret; + } + ltq_port->common_irq = ret; + port->irq = ret; + +return 0 ; +} + +static int request_irq_intel (struct uart_port *port) +{ +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); +int retval; + + retval =request_irq (ltq_port->common_irq, lqasc_irq,0 , +"asc_irq" , port); +if (retval) +dev_err (port->dev,"failed to request asc_irq\n" ); + +return retval; +} + +static void free_irq_intel (struct uart_port *port) +{ +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); + +free_irq (ltq_port->common_irq, port); +} +static int __init lqasc_probe (struct platform_device *pdev) {
@@ -842,8 +906,15 @@ static const struct ltq_soc_data soc_data_lantiq = { .free_irq = free_irq_lantiq, }; +static const struct ltq_soc_data soc_data_intel = { + .fetch_irq = fetch_irq_intel, + .request_irq = request_irq_intel, + .free_irq = free_irq_intel, +}; +static const struct of_device_id ltq_asc_match[] = { { .compatible ="lantiq,asc" , .data = &soc_data_lantiq }, + { .compatible ="intel,lgm-asc" , .data = &soc_data_intel }, {}, };
Signature · 1 line
2.11.0
Re: [PATCH v2 1/3] serial: lantiq: Use proper DT compatible string
In reply to Rahul TanwarQuoted 7 lines · Rahul Tanwar
Use explicit string instead of a macro for devicetree compatible string.
This series of patches is to add support for multiple SoCs which reuse the same serial controller IP. The following patches will add another compatible string to support new Lightning Mountain(LGM) SoC. So it makes sense to have the compatible strings explicitly mentioned instead of a fixed macro.
Quoted 31 lines
Suggested-by Andy Shevchenko <[email protected]>Signed-off-by Rahul Tanwar <[email protected]>--- drivers/tty/serial/lantiq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)drivers/tty/serial/lantiq.c +2
-2@@ -693,7 +693,7 @@ lqasc_serial_early_console_setup(struct earlycon_device *device, device->con->write = lqasc_serial_early_console_write;return 0 ; } -OF_EARLYCON_DECLARE (lantiq,DRVNAME , lqasc_serial_early_console_setup); +OF_EARLYCON_DECLARE (lantiq,"lantiq,asc" , lqasc_serial_early_console_setup);static struct uart_driver lqasc_reg = { .owner =THIS_MODULE ,@@ -792,7 +792,7 @@ lqasc_probe(struct platform_device *pdev) }static const struct of_device_id ltq_asc_match[] = { - { .compatible =DRVNAME }, + { .compatible ="lantiq,asc" }, {}, };Signature · 1 line
2.11.0
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v2 2/3] serial: lantiq: Make IRQ & ISR assignment dynamic
In reply to Rahul TanwarQuoted 5 lines · Rahul Tanwar
This driver/IP is reused across multiple SoCs. Older SoCs supported three separate IRQs for tx, rx & err interrupts. Newer Lightning Mountain SoC supports single IRQ for all of tx/rx/err interrupts. This patch modifies the driver design to support dynamic assignment of IRQ resources & ISRs based on devicetree node compatible entries.
Quoted 237 lines
Suggested-by Andy Shevchenko <[email protected]>Signed-off-by Rahul Tanwar <[email protected]>--- drivers/tty/serial/lantiq.c | 141 ++++++++++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 45 deletions(-)drivers/tty/serial/lantiq.c +96
-45@@ -100,6 +100,12 @@ static void lqasc_tx_chars(struct uart_port *port);static struct ltq_uart_port *lqasc_port[MAXPORTS ];static struct uart_driver lqasc_reg; +struct ltq_soc_data { +int (*fetch_irq)(struct device *dev,struct ltq_uart_port *ltq_port); +int (*request_irq)(struct uart_port *port); +void (*free_irq)(struct uart_port *port); +}; +struct ltq_uart_port {struct uart_port port;/* clock used to derive divider */ @@ -110,6 +116,8 @@ struct ltq_uart_port {unsigned int rx_irq;unsigned int err_irq;spinlock_t lock;/* exclusive access for multi core */ + +const struct ltq_soc_data *soc; };static inline void asc_update_bits (u32 clear,u32 set,void __iomem *reg)@@ -343,35 +351,12 @@ lqasc_startup(struct uart_port *port)spin_unlock_irqrestore (<q_port->lock, flags); - retval =request_irq (ltq_port->tx_irq, lqasc_tx_int, -0 ,"asc_tx" , port); -if (retval) { -pr_err ("failed to request lqasc_tx_int\n" ); + retval = ltq_port->soc->request_irq (port); +if (retval)return retval; - } - - retval =request_irq (ltq_port->rx_irq, lqasc_rx_int, -0 ,"asc_rx" , port); -if (retval) { -pr_err ("failed to request lqasc_rx_int\n" ); - goto err1; - } - - retval =request_irq (ltq_port->err_irq, lqasc_err_int, -0 ,"asc_err" , port); -if (retval) { -pr_err ("failed to request lqasc_err_int\n" ); - goto err2; - }__raw_writel (ASC_IRNREN_RX |ASC_IRNREN_ERR |ASC_IRNREN_TX , port->membase +LTQ_ASC_IRNREN ); -return 0 ; - -err2: -free_irq (ltq_port->rx_irq, port); -err1: -free_irq (ltq_port->tx_irq, port);return retval; }@@ -381,9 +366,7 @@ lqasc_shutdown(struct uart_port *port)struct ltq_uart_port *ltq_port =to_ltq_uart_port (port);unsigned long flags; -free_irq (ltq_port->tx_irq, port); -free_irq (ltq_port->rx_irq, port); -free_irq (ltq_port->err_irq, port); + ltq_port->soc->free_irq (port);spin_lock_irqsave (<q_port->lock, flags);__raw_writel (0 , port->membase +LTQ_ASC_CON );@@ -705,24 +688,98 @@ static struct uart_driver lqasc_reg = { .cons = &lqasc_console, }; +static int fetch_irq_lantiq (struct device *dev,struct ltq_uart_port *ltq_port) +{ +struct uart_port *port = <q_port->port; +struct resource irqres[3 ]; +int ret; + + ret =of_irq_to_resource_table (dev->of_node, irqres,3 ); +if (ret !=3 ) { +dev_err (dev, +"failed to get IRQs for serial port\n" ); +return -ENODEV ; + } + ltq_port->tx_irq = irqres[0 ].start; + ltq_port->rx_irq = irqres[1 ].start; + ltq_port->err_irq = irqres[2 ].start; + port->irq = irqres[0 ].start; + +return 0 ; +} + +static int request_irq_lantiq (struct uart_port *port) +{ +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); +int retval; + + retval =request_irq (ltq_port->tx_irq, lqasc_tx_int, +0 ,"asc_tx" , port); +if (retval) { +dev_err (port->dev,"failed to request asc_tx\n" ); +return retval; + } + + retval =request_irq (ltq_port->rx_irq, lqasc_rx_int, +0 ,"asc_rx" , port); +if (retval) { +dev_err (port->dev,"failed to request asc_rx\n" ); + goto err1; + } + + retval =request_irq (ltq_port->err_irq, lqasc_err_int, +0 ,"asc_err" , port); +if (retval) { +dev_err (port->dev,"failed to request asc_err\n" ); + goto err2; + } +return 0 ; + +err2: +free_irq (ltq_port->rx_irq, port); +err1: +free_irq (ltq_port->tx_irq, port); +return retval; +} + +static void free_irq_lantiq (struct uart_port *port) +{ +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); + +free_irq (ltq_port->tx_irq, port); +free_irq (ltq_port->rx_irq, port); +free_irq (ltq_port->err_irq, port); +} +static int __init lqasc_probe (struct platform_device *pdev) {struct device_node *node = pdev->dev.of_node;struct ltq_uart_port *ltq_port;struct uart_port *port; -struct resource *mmres, irqres[3 ]; +struct resource *mmres;int line;int ret; mmres =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); - ret =of_irq_to_resource_table (node, irqres,3 ); -if (!mmres || (ret !=3 )) { +if (!mmres) {dev_err (&pdev->dev, -"failed to get memory/irq for serial port\n" ); +"failed to get memory for serial port\n" );return -ENODEV ; } + ltq_port =devm_kzalloc (&pdev->dev,sizeof (struct ltq_uart_port ), +GFP_KERNEL ); +if (!ltq_port) +return -ENOMEM ; + + port = <q_port->port; + + ltq_port->soc =of_device_get_match_data (&pdev->dev); + ret = ltq_port->soc->fetch_irq (&pdev->dev, ltq_port); +if (ret) +return ret; +/* get serial id */ line =of_alias_get_id (node,"serial" );if (line <0 ) {@@ -743,13 +800,6 @@ lqasc_probe(struct platform_device *pdev)return -EBUSY ; } - ltq_port =devm_kzalloc (&pdev->dev,sizeof (struct ltq_uart_port ), -GFP_KERNEL ); -if (!ltq_port) -return -ENOMEM ; - - port = <q_port->port; - port->iotype =SERIAL_IO_MEM ; port->flags =UPF_BOOT_AUTOCONF |UPF_IOREMAP ; port->ops = &lqasc_pops;@@ -758,7 +808,6 @@ lqasc_probe(struct platform_device *pdev) port->line = line; port->dev = &pdev->dev;/* unused, just to be backward-compatible */ - port->irq = irqres[0 ].start; port->mapbase = mmres->start;if (IS_ENABLED (CONFIG_LANTIQ ) && !IS_ENABLED (CONFIG_COMMON_CLK ))@@ -778,10 +827,6 @@ lqasc_probe(struct platform_device *pdev)else ltq_port->clk =devm_clk_get (&pdev->dev,"asc" ); - ltq_port->tx_irq = irqres[0 ].start; - ltq_port->rx_irq = irqres[1 ].start; - ltq_port->err_irq = irqres[2 ].start; -spin_lock_init (<q_port->lock); lqasc_port[line] = ltq_port;platform_set_drvdata (pdev, ltq_port);@@ -791,8 +836,14 @@ lqasc_probe(struct platform_device *pdev)return ret; } +static const struct ltq_soc_data soc_data_lantiq = { + .fetch_irq = fetch_irq_lantiq, + .request_irq = request_irq_lantiq, + .free_irq = free_irq_lantiq, +}; +static const struct of_device_id ltq_asc_match[] = { - { .compatible ="lantiq,asc" }, + { .compatible ="lantiq,asc" , .data = &soc_data_lantiq }, {}, };Signature · 1 line
2.11.0
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v2 3/3] serial: lantiq: Add support for Lightning Mountain SoC
In reply to Rahul TanwarQuoted 2 lines · Rahul Tanwar
This patch adds IRQ & ISR support in the driver for Lightning Mountain SoC.
I dunno if DT binding should go first, otherwise, FWIW,
Quoted 127 lines
Signed-off-by Rahul Tanwar <[email protected]>--- drivers/tty/serial/lantiq.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+)drivers/tty/serial/lantiq.c +71
-0@@ -57,6 +57,7 @@#define ASC_IRNCR_TIR 0x1#define ASC_IRNCR_RIR 0x2#define ASC_IRNCR_EIR 0x4 +#define ASC_IRNCR_MASK GENMASK(2, 0)#define ASCOPT_CSIZE 0x3#define TXFIFO_FL 1@@ -115,6 +116,7 @@ struct ltq_uart_port {unsigned int tx_irq;unsigned int rx_irq;unsigned int err_irq; +unsigned int common_irq;spinlock_t lock;/* exclusive access for multi core */ const struct ltq_soc_data *soc;@@ -293,6 +295,31 @@ lqasc_rx_int(int irq, void *_port)return IRQ_HANDLED ; } +static irqreturn_t lqasc_irq (int irq,void *p) +{ +unsigned long flags; +u32 stat; +struct uart_port *port = p; +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); + +spin_lock_irqsave (<q_port->lock, flags); + stat =readl (port->membase +LTQ_ASC_IRNCR ); +spin_unlock_irqrestore (<q_port->lock, flags); +if (!(stat &ASC_IRNCR_MASK )) +return IRQ_NONE ; + +if (stat &ASC_IRNCR_TIR ) +lqasc_tx_int (irq, p); + +if (stat &ASC_IRNCR_RIR ) +lqasc_rx_int (irq, p); + +if (stat &ASC_IRNCR_EIR ) +lqasc_err_int (irq, p); + +return IRQ_HANDLED ; +} +static unsigned int lqasc_tx_empty (struct uart_port *port) {@@ -677,6 +704,7 @@ lqasc_serial_early_console_setup(struct earlycon_device *device,return 0 ; }OF_EARLYCON_DECLARE (lantiq,"lantiq,asc" , lqasc_serial_early_console_setup); +OF_EARLYCON_DECLARE (lantiq,"intel,lgm-asc" , lqasc_serial_early_console_setup);static struct uart_driver lqasc_reg = { .owner =THIS_MODULE ,@@ -751,6 +779,42 @@ static void free_irq_lantiq(struct uart_port *port)free_irq (ltq_port->err_irq, port); } +static int fetch_irq_intel (struct device *dev,struct ltq_uart_port *ltq_port) +{ +struct uart_port *port = <q_port->port; +int ret; + + ret =of_irq_get (dev->of_node,0 ); +if (ret <0 ) { +dev_err (dev,"failed to fetch IRQ for serial port\n" ); +return ret; + } + ltq_port->common_irq = ret; + port->irq = ret; + +return 0 ; +} + +static int request_irq_intel (struct uart_port *port) +{ +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); +int retval; + + retval =request_irq (ltq_port->common_irq, lqasc_irq,0 , +"asc_irq" , port); +if (retval) +dev_err (port->dev,"failed to request asc_irq\n" ); + +return retval; +} + +static void free_irq_intel (struct uart_port *port) +{ +struct ltq_uart_port *ltq_port =to_ltq_uart_port (port); + +free_irq (ltq_port->common_irq, port); +} +static int __init lqasc_probe (struct platform_device *pdev) {@@ -842,8 +906,15 @@ static const struct ltq_soc_data soc_data_lantiq = { .free_irq = free_irq_lantiq, }; +static const struct ltq_soc_data soc_data_intel = { + .fetch_irq = fetch_irq_intel, + .request_irq = request_irq_intel, + .free_irq = free_irq_intel, +}; +static const struct of_device_id ltq_asc_match[] = { { .compatible ="lantiq,asc" , .data = &soc_data_lantiq }, + { .compatible ="intel,lgm-asc" , .data = &soc_data_intel }, {}, };Signature · 1 line
2.11.0
Signature · 2 lines
With Best Regards, Andy Shevchenko