.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | | -#include <linux/serial_reg.h> |
---|
3 | | -#include <linux/serial_8250.h> |
---|
4 | | - |
---|
5 | | -#include "8250.h" |
---|
6 | | - |
---|
7 | 2 | /* |
---|
8 | 3 | * Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker. |
---|
| 4 | + * Copyright 2020 NXP |
---|
| 5 | + * Copyright 2020 Puresoftware Ltd. |
---|
9 | 6 | * |
---|
10 | 7 | * This isn't a full driver; it just provides an alternate IRQ |
---|
11 | | - * handler to deal with an errata. Everything else is just |
---|
12 | | - * using the bog standard 8250 support. |
---|
| 8 | + * handler to deal with an errata and provide ACPI wrapper. |
---|
| 9 | + * Everything else is just using the bog standard 8250 support. |
---|
13 | 10 | * |
---|
14 | 11 | * We follow code flow of serial8250_default_handle_irq() but add |
---|
15 | 12 | * a check for a break and insert a dummy read on the Rx for the |
---|
.. | .. |
---|
19 | 16 | * field to carry the "what we just did" information from the one |
---|
20 | 17 | * IRQ event to the next one. |
---|
21 | 18 | */ |
---|
| 19 | + |
---|
| 20 | +#include <linux/acpi.h> |
---|
| 21 | +#include <linux/serial_reg.h> |
---|
| 22 | +#include <linux/serial_8250.h> |
---|
| 23 | + |
---|
| 24 | +#include "8250.h" |
---|
| 25 | + |
---|
| 26 | +struct fsl8250_data { |
---|
| 27 | + int line; |
---|
| 28 | +}; |
---|
22 | 29 | |
---|
23 | 30 | int fsl8250_handle_irq(struct uart_port *port) |
---|
24 | 31 | { |
---|
.. | .. |
---|
71 | 78 | |
---|
72 | 79 | serial8250_modem_status(up); |
---|
73 | 80 | |
---|
74 | | - if (lsr & UART_LSR_THRE) |
---|
| 81 | + if ((lsr & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) |
---|
75 | 82 | serial8250_tx_chars(up); |
---|
76 | 83 | |
---|
77 | 84 | up->lsr_saved_flags = orig_lsr; |
---|
78 | | - spin_unlock_irqrestore(&up->port.lock, flags); |
---|
| 85 | + uart_unlock_and_check_sysrq(&up->port, flags); |
---|
79 | 86 | return 1; |
---|
80 | 87 | } |
---|
81 | 88 | EXPORT_SYMBOL_GPL(fsl8250_handle_irq); |
---|
| 89 | + |
---|
| 90 | +#ifdef CONFIG_ACPI |
---|
| 91 | +static int fsl8250_acpi_probe(struct platform_device *pdev) |
---|
| 92 | +{ |
---|
| 93 | + struct fsl8250_data *data; |
---|
| 94 | + struct uart_8250_port port8250; |
---|
| 95 | + struct device *dev = &pdev->dev; |
---|
| 96 | + struct resource *regs; |
---|
| 97 | + |
---|
| 98 | + int ret, irq; |
---|
| 99 | + |
---|
| 100 | + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
| 101 | + if (!regs) { |
---|
| 102 | + dev_err(dev, "no registers defined\n"); |
---|
| 103 | + return -EINVAL; |
---|
| 104 | + } |
---|
| 105 | + |
---|
| 106 | + irq = platform_get_irq(pdev, 0); |
---|
| 107 | + if (irq < 0) { |
---|
| 108 | + if (irq != -EPROBE_DEFER) |
---|
| 109 | + dev_err(dev, "cannot get irq\n"); |
---|
| 110 | + return irq; |
---|
| 111 | + } |
---|
| 112 | + |
---|
| 113 | + memset(&port8250, 0, sizeof(port8250)); |
---|
| 114 | + |
---|
| 115 | + ret = device_property_read_u32(dev, "clock-frequency", |
---|
| 116 | + &port8250.port.uartclk); |
---|
| 117 | + if (ret) |
---|
| 118 | + return ret; |
---|
| 119 | + |
---|
| 120 | + spin_lock_init(&port8250.port.lock); |
---|
| 121 | + |
---|
| 122 | + port8250.port.mapbase = regs->start; |
---|
| 123 | + port8250.port.irq = irq; |
---|
| 124 | + port8250.port.handle_irq = fsl8250_handle_irq; |
---|
| 125 | + port8250.port.type = PORT_16550A; |
---|
| 126 | + port8250.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF |
---|
| 127 | + | UPF_FIXED_PORT | UPF_IOREMAP |
---|
| 128 | + | UPF_FIXED_TYPE; |
---|
| 129 | + port8250.port.dev = dev; |
---|
| 130 | + port8250.port.mapsize = resource_size(regs); |
---|
| 131 | + port8250.port.iotype = UPIO_MEM; |
---|
| 132 | + port8250.port.irqflags = IRQF_SHARED; |
---|
| 133 | + |
---|
| 134 | + port8250.port.membase = devm_ioremap(dev, port8250.port.mapbase, |
---|
| 135 | + port8250.port.mapsize); |
---|
| 136 | + if (!port8250.port.membase) |
---|
| 137 | + return -ENOMEM; |
---|
| 138 | + |
---|
| 139 | + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); |
---|
| 140 | + if (!data) |
---|
| 141 | + return -ENOMEM; |
---|
| 142 | + |
---|
| 143 | + data->line = serial8250_register_8250_port(&port8250); |
---|
| 144 | + if (data->line < 0) |
---|
| 145 | + return data->line; |
---|
| 146 | + |
---|
| 147 | + platform_set_drvdata(pdev, data); |
---|
| 148 | + return 0; |
---|
| 149 | +} |
---|
| 150 | + |
---|
| 151 | +static int fsl8250_acpi_remove(struct platform_device *pdev) |
---|
| 152 | +{ |
---|
| 153 | + struct fsl8250_data *data = platform_get_drvdata(pdev); |
---|
| 154 | + |
---|
| 155 | + serial8250_unregister_port(data->line); |
---|
| 156 | + return 0; |
---|
| 157 | +} |
---|
| 158 | + |
---|
| 159 | +static const struct acpi_device_id fsl_8250_acpi_id[] = { |
---|
| 160 | + { "NXP0018", 0 }, |
---|
| 161 | + { }, |
---|
| 162 | +}; |
---|
| 163 | +MODULE_DEVICE_TABLE(acpi, fsl_8250_acpi_id); |
---|
| 164 | + |
---|
| 165 | +static struct platform_driver fsl8250_platform_driver = { |
---|
| 166 | + .driver = { |
---|
| 167 | + .name = "fsl-16550-uart", |
---|
| 168 | + .acpi_match_table = ACPI_PTR(fsl_8250_acpi_id), |
---|
| 169 | + }, |
---|
| 170 | + .probe = fsl8250_acpi_probe, |
---|
| 171 | + .remove = fsl8250_acpi_remove, |
---|
| 172 | +}; |
---|
| 173 | + |
---|
| 174 | +module_platform_driver(fsl8250_platform_driver); |
---|
| 175 | +#endif |
---|