linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] serial: lantiq: Update driver to support new SoC
@ 2019-08-08 10:02 Rahul Tanwar
  2019-08-08 10:02 ` [PATCH v2 1/3] serial: lantiq: Use proper DT compatible string Rahul Tanwar
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Rahul Tanwar @ 2019-08-08 10:02 UTC (permalink / raw)
  To: linux-serial, gregkh
  Cc: linux-kernel, jslaby, andriy.shevchenko, qi-ming.wu,
	cheol.yong.kim, rahul.tanwar, Rahul Tanwar

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(-)

-- 
2.11.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 1/3] serial: lantiq: Use proper DT compatible string
  2019-08-08 10:02 [PATCH v2 0/3] serial: lantiq: Update driver to support new SoC Rahul Tanwar
@ 2019-08-08 10:02 ` Rahul Tanwar
  2019-08-08 11:20   ` Andy Shevchenko
  2019-08-08 10:02 ` [PATCH v2 2/3] serial: lantiq: Make IRQ & ISR assignment dynamic Rahul Tanwar
  2019-08-08 10:02 ` [PATCH v2 3/3] serial: lantiq: Add support for Lightning Mountain SoC Rahul Tanwar
  2 siblings, 1 reply; 7+ messages in thread
From: Rahul Tanwar @ 2019-08-08 10:02 UTC (permalink / raw)
  To: linux-serial, gregkh
  Cc: linux-kernel, jslaby, andriy.shevchenko, qi-ming.wu,
	cheol.yong.kim, rahul.tanwar, 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.

Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Rahul Tanwar <rahul.tanwar@linux.intel.com>
---
 drivers/tty/serial/lantiq.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 42e27b48e9cc..660d21db57dc 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -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" },
 	{},
 };
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 2/3] serial: lantiq: Make IRQ & ISR assignment dynamic
  2019-08-08 10:02 [PATCH v2 0/3] serial: lantiq: Update driver to support new SoC Rahul Tanwar
  2019-08-08 10:02 ` [PATCH v2 1/3] serial: lantiq: Use proper DT compatible string Rahul Tanwar
@ 2019-08-08 10:02 ` Rahul Tanwar
  2019-08-08 11:24   ` Andy Shevchenko
  2019-08-08 10:02 ` [PATCH v2 3/3] serial: lantiq: Add support for Lightning Mountain SoC Rahul Tanwar
  2 siblings, 1 reply; 7+ messages in thread
From: Rahul Tanwar @ 2019-08-08 10:02 UTC (permalink / raw)
  To: linux-serial, gregkh
  Cc: linux-kernel, jslaby, andriy.shevchenko, qi-ming.wu,
	cheol.yong.kim, rahul.tanwar, 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.

Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Rahul Tanwar <rahul.tanwar@linux.intel.com>
---
 drivers/tty/serial/lantiq.c | 141 ++++++++++++++++++++++++++++++--------------
 1 file changed, 96 insertions(+), 45 deletions(-)

diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 660d21db57dc..b129531dfb9a 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -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(&ltq_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(&ltq_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 = &ltq_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 = &ltq_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 = &ltq_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(&ltq_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 },
 	{},
 };
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 3/3] serial: lantiq: Add support for Lightning Mountain SoC
  2019-08-08 10:02 [PATCH v2 0/3] serial: lantiq: Update driver to support new SoC Rahul Tanwar
  2019-08-08 10:02 ` [PATCH v2 1/3] serial: lantiq: Use proper DT compatible string Rahul Tanwar
  2019-08-08 10:02 ` [PATCH v2 2/3] serial: lantiq: Make IRQ & ISR assignment dynamic Rahul Tanwar
@ 2019-08-08 10:02 ` Rahul Tanwar
  2019-08-08 11:26   ` Andy Shevchenko
  2 siblings, 1 reply; 7+ messages in thread
From: Rahul Tanwar @ 2019-08-08 10:02 UTC (permalink / raw)
  To: linux-serial, gregkh
  Cc: linux-kernel, jslaby, andriy.shevchenko, qi-ming.wu,
	cheol.yong.kim, rahul.tanwar, Rahul Tanwar

This patch adds IRQ & ISR support in the driver for Lightning Mountain SoC.

Signed-off-by: Rahul Tanwar <rahul.tanwar@linux.intel.com>
---
 drivers/tty/serial/lantiq.c | 71 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index b129531dfb9a..fcbea43dc334 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -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(&ltq_port->lock, flags);
+	stat = readl(port->membase + LTQ_ASC_IRNCR);
+	spin_unlock_irqrestore(&ltq_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 = &ltq_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 },
 	{},
 };
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/3] serial: lantiq: Use proper DT compatible string
  2019-08-08 10:02 ` [PATCH v2 1/3] serial: lantiq: Use proper DT compatible string Rahul Tanwar
@ 2019-08-08 11:20   ` Andy Shevchenko
  0 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2019-08-08 11:20 UTC (permalink / raw)
  To: Rahul Tanwar
  Cc: linux-serial, gregkh, linux-kernel, jslaby, qi-ming.wu,
	cheol.yong.kim, rahul.tanwar

On Thu, Aug 08, 2019 at 06:02:06PM +0800, Rahul Tanwar wrote:
> 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.
> 

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

> Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
> Signed-off-by: Rahul Tanwar <rahul.tanwar@linux.intel.com>
> ---
>  drivers/tty/serial/lantiq.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
> index 42e27b48e9cc..660d21db57dc 100644
> --- a/drivers/tty/serial/lantiq.c
> +++ b/drivers/tty/serial/lantiq.c
> @@ -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" },
>  	{},
>  };
>  
> -- 
> 2.11.0
> 

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 2/3] serial: lantiq: Make IRQ & ISR assignment dynamic
  2019-08-08 10:02 ` [PATCH v2 2/3] serial: lantiq: Make IRQ & ISR assignment dynamic Rahul Tanwar
@ 2019-08-08 11:24   ` Andy Shevchenko
  0 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2019-08-08 11:24 UTC (permalink / raw)
  To: Rahul Tanwar
  Cc: linux-serial, gregkh, linux-kernel, jslaby, qi-ming.wu,
	cheol.yong.kim, rahul.tanwar

On Thu, Aug 08, 2019 at 06:02:07PM +0800, Rahul Tanwar wrote:
> 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.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

> 
> Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
> Signed-off-by: Rahul Tanwar <rahul.tanwar@linux.intel.com>
> ---
>  drivers/tty/serial/lantiq.c | 141 ++++++++++++++++++++++++++++++--------------
>  1 file changed, 96 insertions(+), 45 deletions(-)
> 
> diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
> index 660d21db57dc..b129531dfb9a 100644
> --- a/drivers/tty/serial/lantiq.c
> +++ b/drivers/tty/serial/lantiq.c
> @@ -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(&ltq_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(&ltq_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 = &ltq_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 = &ltq_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 = &ltq_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(&ltq_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 },
>  	{},
>  };
>  
> -- 
> 2.11.0
> 

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 3/3] serial: lantiq: Add support for Lightning Mountain SoC
  2019-08-08 10:02 ` [PATCH v2 3/3] serial: lantiq: Add support for Lightning Mountain SoC Rahul Tanwar
@ 2019-08-08 11:26   ` Andy Shevchenko
  0 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2019-08-08 11:26 UTC (permalink / raw)
  To: Rahul Tanwar
  Cc: linux-serial, gregkh, linux-kernel, jslaby, qi-ming.wu,
	cheol.yong.kim, rahul.tanwar

On Thu, Aug 08, 2019 at 06:02:08PM +0800, Rahul Tanwar wrote:
> This patch adds IRQ & ISR support in the driver for Lightning Mountain SoC.
> 

I dunno if DT binding should go first, otherwise, FWIW,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

> Signed-off-by: Rahul Tanwar <rahul.tanwar@linux.intel.com>
> ---
>  drivers/tty/serial/lantiq.c | 71 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 71 insertions(+)
> 
> diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
> index b129531dfb9a..fcbea43dc334 100644
> --- a/drivers/tty/serial/lantiq.c
> +++ b/drivers/tty/serial/lantiq.c
> @@ -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(&ltq_port->lock, flags);
> +	stat = readl(port->membase + LTQ_ASC_IRNCR);
> +	spin_unlock_irqrestore(&ltq_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 = &ltq_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 },
>  	{},
>  };
>  
> -- 
> 2.11.0
> 

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-08-08 11:26 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-08 10:02 [PATCH v2 0/3] serial: lantiq: Update driver to support new SoC Rahul Tanwar
2019-08-08 10:02 ` [PATCH v2 1/3] serial: lantiq: Use proper DT compatible string Rahul Tanwar
2019-08-08 11:20   ` Andy Shevchenko
2019-08-08 10:02 ` [PATCH v2 2/3] serial: lantiq: Make IRQ & ISR assignment dynamic Rahul Tanwar
2019-08-08 11:24   ` Andy Shevchenko
2019-08-08 10:02 ` [PATCH v2 3/3] serial: lantiq: Add support for Lightning Mountain SoC Rahul Tanwar
2019-08-08 11:26   ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).