xref: /OK3568_Linux_fs/kernel/drivers/tty/serial/8250/8250_fsl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker.
4*4882a593Smuzhiyun  * Copyright 2020 NXP
5*4882a593Smuzhiyun  * Copyright 2020 Puresoftware Ltd.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This isn't a full driver; it just provides an alternate IRQ
8*4882a593Smuzhiyun  * handler to deal with an errata and provide ACPI wrapper.
9*4882a593Smuzhiyun  * Everything else is just using the bog standard 8250 support.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * We follow code flow of serial8250_default_handle_irq() but add
12*4882a593Smuzhiyun  * a check for a break and insert a dummy read on the Rx for the
13*4882a593Smuzhiyun  * immediately following IRQ event.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * We re-use the already existing "bug handling" lsr_saved_flags
16*4882a593Smuzhiyun  * field to carry the "what we just did" information from the one
17*4882a593Smuzhiyun  * IRQ event to the next one.
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/acpi.h>
21*4882a593Smuzhiyun #include <linux/serial_reg.h>
22*4882a593Smuzhiyun #include <linux/serial_8250.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include "8250.h"
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun struct fsl8250_data {
27*4882a593Smuzhiyun 	int	line;
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun 
fsl8250_handle_irq(struct uart_port * port)30*4882a593Smuzhiyun int fsl8250_handle_irq(struct uart_port *port)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	unsigned char lsr, orig_lsr;
33*4882a593Smuzhiyun 	unsigned long flags;
34*4882a593Smuzhiyun 	unsigned int iir;
35*4882a593Smuzhiyun 	struct uart_8250_port *up = up_to_u8250p(port);
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	spin_lock_irqsave(&up->port.lock, flags);
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	iir = port->serial_in(port, UART_IIR);
40*4882a593Smuzhiyun 	if (iir & UART_IIR_NO_INT) {
41*4882a593Smuzhiyun 		spin_unlock_irqrestore(&up->port.lock, flags);
42*4882a593Smuzhiyun 		return 0;
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	/* This is the WAR; if last event was BRK, then read and return */
46*4882a593Smuzhiyun 	if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) {
47*4882a593Smuzhiyun 		up->lsr_saved_flags &= ~UART_LSR_BI;
48*4882a593Smuzhiyun 		port->serial_in(port, UART_RX);
49*4882a593Smuzhiyun 		spin_unlock_irqrestore(&up->port.lock, flags);
50*4882a593Smuzhiyun 		return 1;
51*4882a593Smuzhiyun 	}
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/* Process incoming characters first */
56*4882a593Smuzhiyun 	if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
57*4882a593Smuzhiyun 	    (up->ier & (UART_IER_RLSI | UART_IER_RDI))) {
58*4882a593Smuzhiyun 		lsr = serial8250_rx_chars(up, lsr);
59*4882a593Smuzhiyun 	}
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	/* Stop processing interrupts on input overrun */
62*4882a593Smuzhiyun 	if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
63*4882a593Smuzhiyun 		unsigned long delay;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 		up->ier = port->serial_in(port, UART_IER);
66*4882a593Smuzhiyun 		if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
67*4882a593Smuzhiyun 			port->ops->stop_rx(port);
68*4882a593Smuzhiyun 		} else {
69*4882a593Smuzhiyun 			/* Keep restarting the timer until
70*4882a593Smuzhiyun 			 * the input overrun subsides.
71*4882a593Smuzhiyun 			 */
72*4882a593Smuzhiyun 			cancel_delayed_work(&up->overrun_backoff);
73*4882a593Smuzhiyun 		}
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 		delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
76*4882a593Smuzhiyun 		schedule_delayed_work(&up->overrun_backoff, delay);
77*4882a593Smuzhiyun 	}
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	serial8250_modem_status(up);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	if ((lsr & UART_LSR_THRE) && (up->ier & UART_IER_THRI))
82*4882a593Smuzhiyun 		serial8250_tx_chars(up);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	up->lsr_saved_flags = orig_lsr;
85*4882a593Smuzhiyun 	uart_unlock_and_check_sysrq(&up->port, flags);
86*4882a593Smuzhiyun 	return 1;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun #ifdef CONFIG_ACPI
fsl8250_acpi_probe(struct platform_device * pdev)91*4882a593Smuzhiyun static int fsl8250_acpi_probe(struct platform_device *pdev)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	struct fsl8250_data *data;
94*4882a593Smuzhiyun 	struct uart_8250_port port8250;
95*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
96*4882a593Smuzhiyun 	struct resource *regs;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	int ret, irq;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
101*4882a593Smuzhiyun 	if (!regs) {
102*4882a593Smuzhiyun 		dev_err(dev, "no registers defined\n");
103*4882a593Smuzhiyun 		return -EINVAL;
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
107*4882a593Smuzhiyun 	if (irq < 0) {
108*4882a593Smuzhiyun 		if (irq != -EPROBE_DEFER)
109*4882a593Smuzhiyun 			dev_err(dev, "cannot get irq\n");
110*4882a593Smuzhiyun 		return irq;
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	memset(&port8250, 0, sizeof(port8250));
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	ret = device_property_read_u32(dev, "clock-frequency",
116*4882a593Smuzhiyun 					&port8250.port.uartclk);
117*4882a593Smuzhiyun 	if (ret)
118*4882a593Smuzhiyun 		return ret;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	spin_lock_init(&port8250.port.lock);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	port8250.port.mapbase           = regs->start;
123*4882a593Smuzhiyun 	port8250.port.irq               = irq;
124*4882a593Smuzhiyun 	port8250.port.handle_irq        = fsl8250_handle_irq;
125*4882a593Smuzhiyun 	port8250.port.type              = PORT_16550A;
126*4882a593Smuzhiyun 	port8250.port.flags             = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
127*4882a593Smuzhiyun 						| UPF_FIXED_PORT | UPF_IOREMAP
128*4882a593Smuzhiyun 						| UPF_FIXED_TYPE;
129*4882a593Smuzhiyun 	port8250.port.dev               = dev;
130*4882a593Smuzhiyun 	port8250.port.mapsize           = resource_size(regs);
131*4882a593Smuzhiyun 	port8250.port.iotype            = UPIO_MEM;
132*4882a593Smuzhiyun 	port8250.port.irqflags          = IRQF_SHARED;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	port8250.port.membase = devm_ioremap(dev,  port8250.port.mapbase,
135*4882a593Smuzhiyun 							port8250.port.mapsize);
136*4882a593Smuzhiyun 	if (!port8250.port.membase)
137*4882a593Smuzhiyun 		return -ENOMEM;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
140*4882a593Smuzhiyun 	if (!data)
141*4882a593Smuzhiyun 		return -ENOMEM;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	data->line = serial8250_register_8250_port(&port8250);
144*4882a593Smuzhiyun 	if (data->line < 0)
145*4882a593Smuzhiyun 		return data->line;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	platform_set_drvdata(pdev, data);
148*4882a593Smuzhiyun 	return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
fsl8250_acpi_remove(struct platform_device * pdev)151*4882a593Smuzhiyun static int fsl8250_acpi_remove(struct platform_device *pdev)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	struct fsl8250_data *data = platform_get_drvdata(pdev);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	serial8250_unregister_port(data->line);
156*4882a593Smuzhiyun 	return 0;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun static const struct acpi_device_id fsl_8250_acpi_id[] = {
160*4882a593Smuzhiyun 	{ "NXP0018", 0 },
161*4882a593Smuzhiyun 	{ },
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun MODULE_DEVICE_TABLE(acpi, fsl_8250_acpi_id);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun static struct platform_driver fsl8250_platform_driver = {
166*4882a593Smuzhiyun 	.driver = {
167*4882a593Smuzhiyun 		.name			= "fsl-16550-uart",
168*4882a593Smuzhiyun 		.acpi_match_table	= ACPI_PTR(fsl_8250_acpi_id),
169*4882a593Smuzhiyun 	},
170*4882a593Smuzhiyun 	.probe			= fsl8250_acpi_probe,
171*4882a593Smuzhiyun 	.remove			= fsl8250_acpi_remove,
172*4882a593Smuzhiyun };
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun module_platform_driver(fsl8250_platform_driver);
175*4882a593Smuzhiyun #endif
176