Commit 775ea4ea authored by Vladimir Murzin's avatar Vladimir Murzin Committed by Greg Kroah-Hartman

serial: mps2-uart: support combined irq

It turns out that some designs went for implementing only combined
interrupt for rx, tx and overrun, which is currently not supported
by the driver.  Support of combined irq is built on top of existent
irq handlers and activated automatically if only single irq was
specified in device tree.
Signed-off-by: default avatarVladimir Murzin <vladimir.murzin@arm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9f25e07b
...@@ -66,11 +66,14 @@ ...@@ -66,11 +66,14 @@
#define MPS2_MAX_PORTS 3 #define MPS2_MAX_PORTS 3
#define UART_PORT_COMBINED_IRQ BIT(0)
struct mps2_uart_port { struct mps2_uart_port {
struct uart_port port; struct uart_port port;
struct clk *clk; struct clk *clk;
unsigned int tx_irq; unsigned int tx_irq;
unsigned int rx_irq; unsigned int rx_irq;
unsigned int flags;
}; };
static inline struct mps2_uart_port *to_mps2_port(struct uart_port *port) static inline struct mps2_uart_port *to_mps2_port(struct uart_port *port)
...@@ -265,6 +268,20 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data) ...@@ -265,6 +268,20 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data)
return handled; return handled;
} }
static irqreturn_t mps2_uart_combinedirq(int irq, void *data)
{
if (mps2_uart_rxirq(irq, data) == IRQ_HANDLED)
return IRQ_HANDLED;
if (mps2_uart_txirq(irq, data) == IRQ_HANDLED)
return IRQ_HANDLED;
if (mps2_uart_oerrirq(irq, data) == IRQ_HANDLED)
return IRQ_HANDLED;
return IRQ_NONE;
}
static int mps2_uart_startup(struct uart_port *port) static int mps2_uart_startup(struct uart_port *port)
{ {
struct mps2_uart_port *mps_port = to_mps2_port(port); struct mps2_uart_port *mps_port = to_mps2_port(port);
...@@ -275,11 +292,28 @@ static int mps2_uart_startup(struct uart_port *port) ...@@ -275,11 +292,28 @@ static int mps2_uart_startup(struct uart_port *port)
mps2_uart_write8(port, control, UARTn_CTRL); mps2_uart_write8(port, control, UARTn_CTRL);
if (mps_port->flags & UART_PORT_COMBINED_IRQ) {
ret = request_irq(port->irq, mps2_uart_combinedirq, 0,
MAKE_NAME(-combined), mps_port);
if (ret) {
dev_err(port->dev, "failed to register combinedirq (%d)\n", ret);
return ret;
}
} else {
ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED,
MAKE_NAME(-overrun), mps_port);
if (ret) {
dev_err(port->dev, "failed to register oerrirq (%d)\n", ret);
return ret;
}
ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0, ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0,
MAKE_NAME(-rx), mps_port); MAKE_NAME(-rx), mps_port);
if (ret) { if (ret) {
dev_err(port->dev, "failed to register rxirq (%d)\n", ret); dev_err(port->dev, "failed to register rxirq (%d)\n", ret);
return ret; goto err_free_oerrirq;
} }
ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0, ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0,
...@@ -289,12 +323,6 @@ static int mps2_uart_startup(struct uart_port *port) ...@@ -289,12 +323,6 @@ static int mps2_uart_startup(struct uart_port *port)
goto err_free_rxirq; goto err_free_rxirq;
} }
ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED,
MAKE_NAME(-overrun), mps_port);
if (ret) {
dev_err(port->dev, "failed to register oerrirq (%d)\n", ret);
goto err_free_txirq;
} }
control |= UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP; control |= UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP;
...@@ -303,10 +331,10 @@ static int mps2_uart_startup(struct uart_port *port) ...@@ -303,10 +331,10 @@ static int mps2_uart_startup(struct uart_port *port)
return 0; return 0;
err_free_txirq:
free_irq(mps_port->tx_irq, mps_port);
err_free_rxirq: err_free_rxirq:
free_irq(mps_port->rx_irq, mps_port); free_irq(mps_port->rx_irq, mps_port);
err_free_oerrirq:
free_irq(port->irq, mps_port);
return ret; return ret;
} }
...@@ -320,8 +348,11 @@ static void mps2_uart_shutdown(struct uart_port *port) ...@@ -320,8 +348,11 @@ static void mps2_uart_shutdown(struct uart_port *port)
mps2_uart_write8(port, control, UARTn_CTRL); mps2_uart_write8(port, control, UARTn_CTRL);
if (!mps_port->flags & UART_PORT_COMBINED_IRQ) {
free_irq(mps_port->rx_irq, mps_port); free_irq(mps_port->rx_irq, mps_port);
free_irq(mps_port->tx_irq, mps_port); free_irq(mps_port->tx_irq, mps_port);
}
free_irq(port->irq, mps_port); free_irq(port->irq, mps_port);
} }
...@@ -511,6 +542,10 @@ static int mps2_of_get_port(struct platform_device *pdev, ...@@ -511,6 +542,10 @@ static int mps2_of_get_port(struct platform_device *pdev,
if (id < 0) if (id < 0)
return id; return id;
/* Only combined irq is presesnt */
if (platform_irq_count(pdev) == 1)
mps_port->flags |= UART_PORT_COMBINED_IRQ;
mps_port->port.line = id; mps_port->port.line = id;
return 0; return 0;
...@@ -529,11 +564,6 @@ static int mps2_init_port(struct platform_device *pdev, ...@@ -529,11 +564,6 @@ static int mps2_init_port(struct platform_device *pdev,
mps_port->port.mapbase = res->start; mps_port->port.mapbase = res->start;
mps_port->port.mapsize = resource_size(res); mps_port->port.mapsize = resource_size(res);
mps_port->rx_irq = platform_get_irq(pdev, 0);
mps_port->tx_irq = platform_get_irq(pdev, 1);
mps_port->port.irq = platform_get_irq(pdev, 2);
mps_port->port.iotype = UPIO_MEM; mps_port->port.iotype = UPIO_MEM;
mps_port->port.flags = UPF_BOOT_AUTOCONF; mps_port->port.flags = UPF_BOOT_AUTOCONF;
mps_port->port.fifosize = 1; mps_port->port.fifosize = 1;
...@@ -552,6 +582,15 @@ static int mps2_init_port(struct platform_device *pdev, ...@@ -552,6 +582,15 @@ static int mps2_init_port(struct platform_device *pdev,
clk_disable_unprepare(mps_port->clk); clk_disable_unprepare(mps_port->clk);
if (mps_port->flags & UART_PORT_COMBINED_IRQ) {
mps_port->port.irq = platform_get_irq(pdev, 0);
} else {
mps_port->rx_irq = platform_get_irq(pdev, 0);
mps_port->tx_irq = platform_get_irq(pdev, 1);
mps_port->port.irq = platform_get_irq(pdev, 2);
}
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment