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 dw8250_probe(struct platform_device
*pdev
)
92 struct uart_8250_port uart
= {};
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 uart
.port
.private_data
= data
;
109 spin_lock_init(&uart
.port
.lock
);
110 uart
.port
.mapbase
= regs
->start
;
111 uart
.port
.irq
= irq
->start
;
112 uart
.port
.handle_irq
= dw8250_handle_irq
;
113 uart
.port
.type
= PORT_8250
;
114 uart
.port
.flags
= UPF_SHARE_IRQ
| UPF_BOOT_AUTOCONF
| UPF_IOREMAP
|
115 UPF_FIXED_PORT
| UPF_FIXED_TYPE
;
116 uart
.port
.dev
= &pdev
->dev
;
118 uart
.port
.iotype
= UPIO_MEM
;
119 uart
.port
.serial_in
= dw8250_serial_in
;
120 uart
.port
.serial_out
= dw8250_serial_out
;
121 if (!of_property_read_u32(np
, "reg-io-width", &val
)) {
126 uart
.port
.iotype
= UPIO_MEM32
;
127 uart
.port
.serial_in
= dw8250_serial_in32
;
128 uart
.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
))
138 uart
.port
.regshift
= val
;
140 if (of_property_read_u32(np
, "clock-frequency", &val
)) {
141 dev_err(&pdev
->dev
, "no clock-frequency property set\n");
144 uart
.port
.uartclk
= val
;
146 data
->line
= serial8250_register_8250_port(&uart
);
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
);
165 static int dw8250_suspend(struct platform_device
*pdev
, pm_message_t state
)
167 struct dw8250_data
*data
= platform_get_drvdata(pdev
);
169 serial8250_suspend_port(data
->line
);
174 static int dw8250_resume(struct platform_device
*pdev
)
176 struct dw8250_data
*data
= platform_get_drvdata(pdev
);
178 serial8250_resume_port(data
->line
);
183 #define dw8250_suspend NULL
184 #define dw8250_resume NULL
185 #endif /* CONFIG_PM */
187 static const struct of_device_id dw8250_match
[] = {
188 { .compatible
= "snps,dw-apb-uart" },
191 MODULE_DEVICE_TABLE(of
, dw8250_match
);
193 static struct platform_driver dw8250_platform_driver
= {
195 .name
= "dw-apb-uart",
196 .owner
= THIS_MODULE
,
197 .of_match_table
= dw8250_match
,
199 .probe
= dw8250_probe
,
200 .remove
= dw8250_remove
,
201 .suspend
= dw8250_suspend
,
202 .resume
= dw8250_resume
,
205 module_platform_driver(dw8250_platform_driver
);
207 MODULE_AUTHOR("Jamie Iles");
208 MODULE_LICENSE("GPL");
209 MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");