2 * Copyright (C) 2010 Lars-Peter Clausen <lars@metafoo.de>
3 * Copyright (C) 2015 Imagination Technologies
5 * Ingenic SoC UART support
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
12 * You should have received a copy of the GNU General Public License along
13 * with this program; if not, write to the Free Software Foundation, Inc.,
14 * 675 Mass Ave, Cambridge, MA 02139, USA.
17 #include <linux/clk.h>
18 #include <linux/console.h>
20 #include <linux/libfdt.h>
21 #include <linux/module.h>
23 #include <linux/of_fdt.h>
24 #include <linux/of_device.h>
25 #include <linux/platform_device.h>
26 #include <linux/serial_8250.h>
27 #include <linux/serial_core.h>
28 #include <linux/serial_reg.h>
32 /** ingenic_uart_config: SOC specific config data. */
33 struct ingenic_uart_config
{
38 struct ingenic_uart_data
{
39 struct clk
*clk_module
;
44 static const struct of_device_id of_match
[];
46 #define UART_FCR_UME BIT(4)
48 #define UART_MCR_MDCE BIT(7)
49 #define UART_MCR_FCM BIT(6)
51 static struct earlycon_device
*early_device
;
53 static uint8_t __init
early_in(struct uart_port
*port
, int offset
)
55 return readl(port
->membase
+ (offset
<< 2));
58 static void __init
early_out(struct uart_port
*port
, int offset
, uint8_t value
)
60 writel(value
, port
->membase
+ (offset
<< 2));
63 static void __init
ingenic_early_console_putc(struct uart_port
*port
, int c
)
68 lsr
= early_in(port
, UART_LSR
);
69 } while ((lsr
& UART_LSR_TEMT
) == 0);
71 early_out(port
, UART_TX
, c
);
74 static void __init
ingenic_early_console_write(struct console
*console
,
75 const char *s
, unsigned int count
)
77 uart_console_write(&early_device
->port
, s
, count
,
78 ingenic_early_console_putc
);
81 static void __init
ingenic_early_console_setup_clock(struct earlycon_device
*dev
)
83 void *fdt
= initial_boot_params
;
87 offset
= fdt_path_offset(fdt
, "/ext");
91 prop
= fdt_getprop(fdt
, offset
, "clock-frequency", NULL
);
95 dev
->port
.uartclk
= be32_to_cpup(prop
);
98 static int __init
ingenic_early_console_setup(struct earlycon_device
*dev
,
101 struct uart_port
*port
= &dev
->port
;
102 unsigned int baud
, divisor
;
104 if (!dev
->port
.membase
)
107 ingenic_early_console_setup_clock(dev
);
109 baud
= dev
->baud
?: 115200;
110 divisor
= DIV_ROUND_CLOSEST(port
->uartclk
, 16 * baud
);
112 early_out(port
, UART_IER
, 0);
113 early_out(port
, UART_LCR
, UART_LCR_DLAB
| UART_LCR_WLEN8
);
114 early_out(port
, UART_DLL
, 0);
115 early_out(port
, UART_DLM
, 0);
116 early_out(port
, UART_LCR
, UART_LCR_WLEN8
);
117 early_out(port
, UART_FCR
, UART_FCR_UME
| UART_FCR_CLEAR_XMIT
|
118 UART_FCR_CLEAR_RCVR
| UART_FCR_ENABLE_FIFO
);
119 early_out(port
, UART_MCR
, UART_MCR_RTS
| UART_MCR_DTR
);
121 early_out(port
, UART_LCR
, UART_LCR_DLAB
| UART_LCR_WLEN8
);
122 early_out(port
, UART_DLL
, divisor
& 0xff);
123 early_out(port
, UART_DLM
, (divisor
>> 8) & 0xff);
124 early_out(port
, UART_LCR
, UART_LCR_WLEN8
);
127 dev
->con
->write
= ingenic_early_console_write
;
132 EARLYCON_DECLARE(jz4740_uart
, ingenic_early_console_setup
);
133 OF_EARLYCON_DECLARE(jz4740_uart
, "ingenic,jz4740-uart",
134 ingenic_early_console_setup
);
136 EARLYCON_DECLARE(jz4775_uart
, ingenic_early_console_setup
);
137 OF_EARLYCON_DECLARE(jz4775_uart
, "ingenic,jz4775-uart",
138 ingenic_early_console_setup
);
140 EARLYCON_DECLARE(jz4780_uart
, ingenic_early_console_setup
);
141 OF_EARLYCON_DECLARE(jz4780_uart
, "ingenic,jz4780-uart",
142 ingenic_early_console_setup
);
144 static void ingenic_uart_serial_out(struct uart_port
*p
, int offset
, int value
)
150 /* UART module enable */
151 value
|= UART_FCR_UME
;
156 * Enable receive timeout interrupt with the receive line
159 value
|= (value
& 0x4) << 2;
164 * If we have enabled modem status IRQs we should enable
167 ier
= p
->serial_in(p
, UART_IER
);
169 if (ier
& UART_IER_MSI
)
170 value
|= UART_MCR_MDCE
| UART_MCR_FCM
;
172 value
&= ~(UART_MCR_MDCE
| UART_MCR_FCM
);
179 writeb(value
, p
->membase
+ (offset
<< p
->regshift
));
182 static unsigned int ingenic_uart_serial_in(struct uart_port
*p
, int offset
)
186 value
= readb(p
->membase
+ (offset
<< p
->regshift
));
188 /* Hide non-16550 compliant bits from higher levels */
191 value
&= ~UART_FCR_UME
;
195 value
&= ~(UART_MCR_MDCE
| UART_MCR_FCM
);
204 static int ingenic_uart_probe(struct platform_device
*pdev
)
206 struct uart_8250_port uart
= {};
207 struct resource
*regs
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
208 struct resource
*irq
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
209 struct ingenic_uart_data
*data
;
210 const struct ingenic_uart_config
*cdata
;
211 const struct of_device_id
*match
;
214 match
= of_match_device(of_match
, &pdev
->dev
);
216 dev_err(&pdev
->dev
, "Error: No device match found\n");
222 dev_err(&pdev
->dev
, "no registers/irq defined\n");
226 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
230 spin_lock_init(&uart
.port
.lock
);
231 uart
.port
.type
= PORT_16550A
;
232 uart
.port
.flags
= UPF_SKIP_TEST
| UPF_IOREMAP
| UPF_FIXED_TYPE
;
233 uart
.port
.iotype
= UPIO_MEM
;
234 uart
.port
.mapbase
= regs
->start
;
235 uart
.port
.regshift
= 2;
236 uart
.port
.serial_out
= ingenic_uart_serial_out
;
237 uart
.port
.serial_in
= ingenic_uart_serial_in
;
238 uart
.port
.irq
= irq
->start
;
239 uart
.port
.dev
= &pdev
->dev
;
240 uart
.port
.fifosize
= cdata
->fifosize
;
241 uart
.tx_loadsz
= cdata
->tx_loadsz
;
242 uart
.capabilities
= UART_CAP_FIFO
| UART_CAP_RTOIE
;
244 /* Check for a fixed line number */
245 line
= of_alias_get_id(pdev
->dev
.of_node
, "serial");
247 uart
.port
.line
= line
;
249 uart
.port
.membase
= devm_ioremap(&pdev
->dev
, regs
->start
,
250 resource_size(regs
));
251 if (!uart
.port
.membase
)
254 data
->clk_module
= devm_clk_get(&pdev
->dev
, "module");
255 if (IS_ERR(data
->clk_module
)) {
256 err
= PTR_ERR(data
->clk_module
);
257 if (err
!= -EPROBE_DEFER
)
259 "unable to get module clock: %d\n", err
);
263 data
->clk_baud
= devm_clk_get(&pdev
->dev
, "baud");
264 if (IS_ERR(data
->clk_baud
)) {
265 err
= PTR_ERR(data
->clk_baud
);
266 if (err
!= -EPROBE_DEFER
)
268 "unable to get baud clock: %d\n", err
);
272 err
= clk_prepare_enable(data
->clk_module
);
274 dev_err(&pdev
->dev
, "could not enable module clock: %d\n", err
);
278 err
= clk_prepare_enable(data
->clk_baud
);
280 dev_err(&pdev
->dev
, "could not enable baud clock: %d\n", err
);
281 goto out_disable_moduleclk
;
283 uart
.port
.uartclk
= clk_get_rate(data
->clk_baud
);
285 data
->line
= serial8250_register_8250_port(&uart
);
286 if (data
->line
< 0) {
288 goto out_disable_baudclk
;
291 platform_set_drvdata(pdev
, data
);
295 clk_disable_unprepare(data
->clk_baud
);
296 out_disable_moduleclk
:
297 clk_disable_unprepare(data
->clk_module
);
302 static int ingenic_uart_remove(struct platform_device
*pdev
)
304 struct ingenic_uart_data
*data
= platform_get_drvdata(pdev
);
306 serial8250_unregister_port(data
->line
);
307 clk_disable_unprepare(data
->clk_module
);
308 clk_disable_unprepare(data
->clk_baud
);
312 static const struct ingenic_uart_config jz4740_uart_config
= {
317 static const struct ingenic_uart_config jz4760_uart_config
= {
322 static const struct ingenic_uart_config jz4780_uart_config
= {
327 static const struct of_device_id of_match
[] = {
328 { .compatible
= "ingenic,jz4740-uart", .data
= &jz4740_uart_config
},
329 { .compatible
= "ingenic,jz4760-uart", .data
= &jz4760_uart_config
},
330 { .compatible
= "ingenic,jz4775-uart", .data
= &jz4760_uart_config
},
331 { .compatible
= "ingenic,jz4780-uart", .data
= &jz4780_uart_config
},
334 MODULE_DEVICE_TABLE(of
, of_match
);
336 static struct platform_driver ingenic_uart_platform_driver
= {
338 .name
= "ingenic-uart",
339 .of_match_table
= of_match
,
341 .probe
= ingenic_uart_probe
,
342 .remove
= ingenic_uart_remove
,
345 module_platform_driver(ingenic_uart_platform_driver
);
347 MODULE_AUTHOR("Paul Burton");
348 MODULE_LICENSE("GPL");
349 MODULE_DESCRIPTION("Ingenic SoC UART driver");