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>
33 static void dw8250_serial_out(struct uart_port
*p
, int offset
, int value
)
35 struct dw8250_data
*d
= p
->private_data
;
37 if (offset
== UART_LCR
)
40 offset
<<= p
->regshift
;
41 writeb(value
, p
->membase
+ offset
);
44 static unsigned int dw8250_serial_in(struct uart_port
*p
, int offset
)
46 offset
<<= p
->regshift
;
48 return readb(p
->membase
+ offset
);
51 static void dw8250_serial_out32(struct uart_port
*p
, int offset
, int value
)
53 struct dw8250_data
*d
= p
->private_data
;
55 if (offset
== UART_LCR
)
58 offset
<<= p
->regshift
;
59 writel(value
, p
->membase
+ offset
);
62 static unsigned int dw8250_serial_in32(struct uart_port
*p
, int offset
)
64 offset
<<= p
->regshift
;
66 return readl(p
->membase
+ offset
);
69 /* Offset for the DesignWare's UART Status Register. */
72 static int dw8250_handle_irq(struct uart_port
*p
)
74 struct dw8250_data
*d
= p
->private_data
;
75 unsigned int iir
= p
->serial_in(p
, UART_IIR
);
77 if (serial8250_handle_irq(p
, iir
)) {
79 } else if ((iir
& UART_IIR_BUSY
) == UART_IIR_BUSY
) {
80 /* Clear the USR and write the LCR again. */
81 (void)p
->serial_in(p
, UART_USR
);
82 p
->serial_out(p
, d
->last_lcr
, UART_LCR
);
90 static int __devinit
dw8250_probe(struct platform_device
*pdev
)
92 struct uart_port port
= {};
93 struct resource
*regs
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
94 struct resource
*irq
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
95 struct device_node
*np
= pdev
->dev
.of_node
;
97 struct dw8250_data
*data
;
100 dev_err(&pdev
->dev
, "no registers/irq defined\n");
104 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
107 port
.private_data
= data
;
109 spin_lock_init(&port
.lock
);
110 port
.mapbase
= regs
->start
;
111 port
.irq
= irq
->start
;
112 port
.handle_irq
= dw8250_handle_irq
;
113 port
.type
= PORT_8250
;
114 port
.flags
= UPF_SHARE_IRQ
| UPF_BOOT_AUTOCONF
| UPF_IOREMAP
|
115 UPF_FIXED_PORT
| UPF_FIXED_TYPE
;
116 port
.dev
= &pdev
->dev
;
118 port
.iotype
= UPIO_MEM
;
119 port
.serial_in
= dw8250_serial_in
;
120 port
.serial_out
= dw8250_serial_out
;
121 if (!of_property_read_u32(np
, "reg-io-width", &val
)) {
126 port
.iotype
= UPIO_MEM32
;
127 port
.serial_in
= dw8250_serial_in32
;
128 port
.serial_out
= dw8250_serial_out32
;
131 dev_err(&pdev
->dev
, "unsupported reg-io-width (%u)\n",
137 if (!of_property_read_u32(np
, "reg-shift", &val
))
140 if (of_property_read_u32(np
, "clock-frequency", &val
)) {
141 dev_err(&pdev
->dev
, "no clock-frequency property set\n");
146 data
->line
= serial8250_register_port(&port
);
150 platform_set_drvdata(pdev
, data
);
155 static int __devexit
dw8250_remove(struct platform_device
*pdev
)
157 struct dw8250_data
*data
= platform_get_drvdata(pdev
);
159 serial8250_unregister_port(data
->line
);
164 static const struct of_device_id dw8250_match
[] = {
165 { .compatible
= "snps,dw-apb-uart" },
168 MODULE_DEVICE_TABLE(of
, dw8250_match
);
170 static struct platform_driver dw8250_platform_driver
= {
172 .name
= "dw-apb-uart",
173 .owner
= THIS_MODULE
,
174 .of_match_table
= dw8250_match
,
176 .probe
= dw8250_probe
,
177 .remove
= __devexit_p(dw8250_remove
),
180 module_platform_driver(dw8250_platform_driver
);
182 MODULE_AUTHOR("Jamie Iles");
183 MODULE_LICENSE("GPL");
184 MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");