mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
serial: 8250_omap: provide complete custom startup & shutdown callbacks
The currently in-use port->startup and port->shutdown are "okay". The startup part for instance does the tiny omap extra part and invokes serial8250_do_startup() for the remaining pieces. The workflow in serial8250_do_startup() is okay except for the part where UART_RX is read without a check if there is something to read. I tried to workaround it in commit0aa525d118
("tty: serial: 8250_core: read only RX if there is something in the FIFO") but then reverted it later in commitca8bb4aefb
("serial: 8250: Revert "tty: serial: 8250_core: read only RX if there is something in the FIFO""). This is the second attempt to get it to work on older OMAPs without breaking other chips this time Peter Hurley suggested to pull in the few needed lines from serial8250_do_startup() and drop everything else that is not required including making it simpler like using just request_irq() instead the chain handler like it is doing now. So lets try that. Fixes:ca8bb4aefb
("serial: 8250: Revert "tty: serial: 8250_core: read only RX if there is something in the FIFO"") Tested-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
da555db6b0
commit
9809889c70
1 changed files with 73 additions and 9 deletions
|
@ -562,12 +562,36 @@ static irqreturn_t omap_wake_irq(int irq, void *dev_id)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_8250_DMA
|
||||||
|
static int omap_8250_dma_handle_irq(struct uart_port *port);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static irqreturn_t omap8250_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct uart_port *port = dev_id;
|
||||||
|
struct uart_8250_port *up = up_to_u8250p(port);
|
||||||
|
unsigned int iir;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_8250_DMA
|
||||||
|
if (up->dma) {
|
||||||
|
ret = omap_8250_dma_handle_irq(port);
|
||||||
|
return IRQ_RETVAL(ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
serial8250_rpm_get(up);
|
||||||
|
iir = serial_port_in(port, UART_IIR);
|
||||||
|
ret = serial8250_handle_irq(port, iir);
|
||||||
|
serial8250_rpm_put(up);
|
||||||
|
|
||||||
|
return IRQ_RETVAL(ret);
|
||||||
|
}
|
||||||
|
|
||||||
static int omap_8250_startup(struct uart_port *port)
|
static int omap_8250_startup(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_8250_port *up =
|
struct uart_8250_port *up = up_to_u8250p(port);
|
||||||
container_of(port, struct uart_8250_port, port);
|
|
||||||
struct omap8250_priv *priv = port->private_data;
|
struct omap8250_priv *priv = port->private_data;
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (priv->wakeirq) {
|
if (priv->wakeirq) {
|
||||||
|
@ -580,10 +604,31 @@ static int omap_8250_startup(struct uart_port *port)
|
||||||
|
|
||||||
pm_runtime_get_sync(port->dev);
|
pm_runtime_get_sync(port->dev);
|
||||||
|
|
||||||
ret = serial8250_do_startup(port);
|
up->mcr = 0;
|
||||||
if (ret)
|
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
|
||||||
|
|
||||||
|
serial_out(up, UART_LCR, UART_LCR_WLEN8);
|
||||||
|
|
||||||
|
up->lsr_saved_flags = 0;
|
||||||
|
up->msr_saved_flags = 0;
|
||||||
|
|
||||||
|
if (up->dma) {
|
||||||
|
ret = serial8250_request_dma(up);
|
||||||
|
if (ret) {
|
||||||
|
dev_warn_ratelimited(port->dev,
|
||||||
|
"failed to request DMA\n");
|
||||||
|
up->dma = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = request_irq(port->irq, omap8250_irq, IRQF_SHARED,
|
||||||
|
dev_name(port->dev), port);
|
||||||
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
up->ier = UART_IER_RLSI | UART_IER_RDI;
|
||||||
|
serial_out(up, UART_IER, up->ier);
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
up->capabilities |= UART_CAP_RPM;
|
up->capabilities |= UART_CAP_RPM;
|
||||||
#endif
|
#endif
|
||||||
|
@ -610,8 +655,7 @@ static int omap_8250_startup(struct uart_port *port)
|
||||||
|
|
||||||
static void omap_8250_shutdown(struct uart_port *port)
|
static void omap_8250_shutdown(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_8250_port *up =
|
struct uart_8250_port *up = up_to_u8250p(port);
|
||||||
container_of(port, struct uart_8250_port, port);
|
|
||||||
struct omap8250_priv *priv = port->private_data;
|
struct omap8250_priv *priv = port->private_data;
|
||||||
|
|
||||||
flush_work(&priv->qos_work);
|
flush_work(&priv->qos_work);
|
||||||
|
@ -621,11 +665,24 @@ static void omap_8250_shutdown(struct uart_port *port)
|
||||||
pm_runtime_get_sync(port->dev);
|
pm_runtime_get_sync(port->dev);
|
||||||
|
|
||||||
serial_out(up, UART_OMAP_WER, 0);
|
serial_out(up, UART_OMAP_WER, 0);
|
||||||
serial8250_do_shutdown(port);
|
|
||||||
|
up->ier = 0;
|
||||||
|
serial_out(up, UART_IER, 0);
|
||||||
|
|
||||||
|
if (up->dma)
|
||||||
|
serial8250_release_dma(up);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable break condition and FIFOs
|
||||||
|
*/
|
||||||
|
if (up->lcr & UART_LCR_SBC)
|
||||||
|
serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC);
|
||||||
|
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
|
||||||
|
|
||||||
pm_runtime_mark_last_busy(port->dev);
|
pm_runtime_mark_last_busy(port->dev);
|
||||||
pm_runtime_put_autosuspend(port->dev);
|
pm_runtime_put_autosuspend(port->dev);
|
||||||
|
|
||||||
|
free_irq(port->irq, port);
|
||||||
if (priv->wakeirq)
|
if (priv->wakeirq)
|
||||||
free_irq(priv->wakeirq, port);
|
free_irq(priv->wakeirq, port);
|
||||||
}
|
}
|
||||||
|
@ -974,6 +1031,13 @@ static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int omap8250_no_handle_irq(struct uart_port *port)
|
||||||
|
{
|
||||||
|
/* IRQ has not been requested but handling irq? */
|
||||||
|
WARN_ONCE(1, "Unexpected irq handling before port startup\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int omap8250_probe(struct platform_device *pdev)
|
static int omap8250_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
@ -1075,6 +1139,7 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||||
pm_runtime_get_sync(&pdev->dev);
|
pm_runtime_get_sync(&pdev->dev);
|
||||||
|
|
||||||
omap_serial_fill_features_erratas(&up, priv);
|
omap_serial_fill_features_erratas(&up, priv);
|
||||||
|
up.port.handle_irq = omap8250_no_handle_irq;
|
||||||
#ifdef CONFIG_SERIAL_8250_DMA
|
#ifdef CONFIG_SERIAL_8250_DMA
|
||||||
if (pdev->dev.of_node) {
|
if (pdev->dev.of_node) {
|
||||||
/*
|
/*
|
||||||
|
@ -1088,7 +1153,6 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||||
ret = of_property_count_strings(pdev->dev.of_node, "dma-names");
|
ret = of_property_count_strings(pdev->dev.of_node, "dma-names");
|
||||||
if (ret == 2) {
|
if (ret == 2) {
|
||||||
up.dma = &priv->omap8250_dma;
|
up.dma = &priv->omap8250_dma;
|
||||||
up.port.handle_irq = omap_8250_dma_handle_irq;
|
|
||||||
priv->omap8250_dma.fn = the_no_dma_filter_fn;
|
priv->omap8250_dma.fn = the_no_dma_filter_fn;
|
||||||
priv->omap8250_dma.tx_dma = omap_8250_tx_dma;
|
priv->omap8250_dma.tx_dma = omap_8250_tx_dma;
|
||||||
priv->omap8250_dma.rx_dma = omap_8250_rx_dma;
|
priv->omap8250_dma.rx_dma = omap_8250_rx_dma;
|
||||||
|
|
Loading…
Reference in a new issue