2 * Synopsys DesignWare 8250 driver.
4 * Copyright 2011 Picochip, Jamie Iles.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * The Synopsys DesignWare 8250 has an extra feature whereby it detects if the
12 * LCR is written whilst busy. If it is, then a busy detect interrupt is
13 * raised, the LCR needs to be rewritten and the uart status register read.
15 #include <linux/device.h>
16 #include <linux/init.h>
18 #include <linux/module.h>
19 #include <linux/serial_8250.h>
20 #include <linux/serial_core.h>
21 #include <linux/serial_reg.h>
23 #include <linux/of_irq.h>
24 #include <linux/of_platform.h>
25 #include <linux/platform_device.h>
26 #include <linux/slab.h>
28 /* Offsets for the DesignWare specific registers */
29 #define DW_UART_USR 0x1f /* UART Status Register */
30 #define DW_UART_CPR 0xf4 /* Component Parameter Register */
31 #define DW_UART_UCV 0xf8 /* UART Component Version */
33 /* Component Parameter Register bits */
34 #define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
35 #define DW_UART_CPR_AFCE_MODE (1 << 4)
36 #define DW_UART_CPR_THRE_MODE (1 << 5)
37 #define DW_UART_CPR_SIR_MODE (1 << 6)
38 #define DW_UART_CPR_SIR_LP_MODE (1 << 7)
39 #define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8)
40 #define DW_UART_CPR_FIFO_ACCESS (1 << 9)
41 #define DW_UART_CPR_FIFO_STAT (1 << 10)
42 #define DW_UART_CPR_SHADOW (1 << 11)
43 #define DW_UART_CPR_ENCODED_PARMS (1 << 12)
44 #define DW_UART_CPR_DMA_EXTRA (1 << 13)
45 #define DW_UART_CPR_FIFO_MODE (0xff << 16)
46 /* Helper for fifo size calculation */
47 #define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
55 static void dw8250_serial_out(struct uart_port *p, int offset, int value)
57 struct dw8250_data *d = p->private_data;
59 if (offset == UART_LCR)
62 offset <<= p->regshift;
63 writeb(value, p->membase + offset);
66 static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
68 offset <<= p->regshift;
70 return readb(p->membase + offset);
73 static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
75 struct dw8250_data *d = p->private_data;
77 if (offset == UART_LCR)
80 offset <<= p->regshift;
81 writel(value, p->membase + offset);
84 static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
86 offset <<= p->regshift;
88 return readl(p->membase + offset);
91 static int dw8250_handle_irq(struct uart_port *p)
93 struct dw8250_data *d = p->private_data;
94 unsigned int iir = p->serial_in(p, UART_IIR);
96 if (serial8250_handle_irq(p, iir)) {
98 } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
99 /* Clear the USR and write the LCR again. */
100 (void)p->serial_in(p, DW_UART_USR);
101 p->serial_out(p, d->last_lcr, UART_LCR);
109 static int dw8250_probe_of(struct uart_port *p)
111 struct device_node *np = p->dev->of_node;
114 if (!of_property_read_u32(np, "reg-io-width", &val)) {
119 p->iotype = UPIO_MEM32;
120 p->serial_in = dw8250_serial_in32;
121 p->serial_out = dw8250_serial_out32;
124 dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
129 if (!of_property_read_u32(np, "reg-shift", &val))
132 if (of_property_read_u32(np, "clock-frequency", &val)) {
133 dev_err(p->dev, "no clock-frequency property set\n");
141 static void dw8250_setup_port(struct uart_8250_port *up)
143 struct uart_port *p = &up->port;
144 u32 reg = readl(p->membase + DW_UART_UCV);
147 * If the Component Version Register returns zero, we know that
148 * ADDITIONAL_FEATURES are not enabled. No need to go any further.
153 dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
154 (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
156 reg = readl(p->membase + DW_UART_CPR);
160 /* Select the type based on fifo */
161 if (reg & DW_UART_CPR_FIFO_MODE) {
162 p->type = PORT_16550A;
163 p->flags |= UPF_FIXED_TYPE;
164 p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
165 up->tx_loadsz = p->fifosize;
169 static int dw8250_probe(struct platform_device *pdev)
171 struct uart_8250_port uart = {};
172 struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
173 struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
174 struct dw8250_data *data;
178 dev_err(&pdev->dev, "no registers/irq defined\n");
182 spin_lock_init(&uart.port.lock);
183 uart.port.mapbase = regs->start;
184 uart.port.irq = irq->start;
185 uart.port.handle_irq = dw8250_handle_irq;
186 uart.port.type = PORT_8250;
187 uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
188 uart.port.dev = &pdev->dev;
190 uart.port.membase = ioremap(regs->start, resource_size(regs));
191 if (!uart.port.membase)
194 uart.port.iotype = UPIO_MEM;
195 uart.port.serial_in = dw8250_serial_in;
196 uart.port.serial_out = dw8250_serial_out;
198 if (pdev->dev.of_node) {
199 err = dw8250_probe_of(&uart.port);
206 dw8250_setup_port(&uart);
208 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
212 uart.port.private_data = data;
214 data->line = serial8250_register_8250_port(&uart);
218 platform_set_drvdata(pdev, data);
223 static int dw8250_remove(struct platform_device *pdev)
225 struct dw8250_data *data = platform_get_drvdata(pdev);
227 serial8250_unregister_port(data->line);
233 static int dw8250_suspend(struct platform_device *pdev, pm_message_t state)
235 struct dw8250_data *data = platform_get_drvdata(pdev);
237 serial8250_suspend_port(data->line);
242 static int dw8250_resume(struct platform_device *pdev)
244 struct dw8250_data *data = platform_get_drvdata(pdev);
246 serial8250_resume_port(data->line);
251 #define dw8250_suspend NULL
252 #define dw8250_resume NULL
253 #endif /* CONFIG_PM */
255 static const struct of_device_id dw8250_of_match[] = {
256 { .compatible = "snps,dw-apb-uart" },
259 MODULE_DEVICE_TABLE(of, dw8250_of_match);
261 static struct platform_driver dw8250_platform_driver = {
263 .name = "dw-apb-uart",
264 .owner = THIS_MODULE,
265 .of_match_table = dw8250_of_match,
267 .probe = dw8250_probe,
268 .remove = dw8250_remove,
269 .suspend = dw8250_suspend,
270 .resume = dw8250_resume,
273 module_platform_driver(dw8250_platform_driver);
275 MODULE_AUTHOR("Jamie Iles");
276 MODULE_LICENSE("GPL");
277 MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");