1 // SPDX-License-Identifier: GPL-2.0+
3 * drivers/tty/serial/8250/8250_pxa.c -- driver for PXA on-board UARTS
4 * Copyright: (C) 2013 Sergei Ianovich <ynvich@gmail.com>
6 * replaces drivers/serial/pxa.c by Nicolas Pitre
7 * Created: Feb 20, 2003
8 * Copyright: (C) 2003 Monta Vista Software, Inc.
10 * Based on drivers/serial/8250.c by Russell King.
13 #include <linux/device.h>
14 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/serial_8250.h>
18 #include <linux/serial_core.h>
19 #include <linux/serial_reg.h>
21 #include <linux/of_irq.h>
22 #include <linux/of_platform.h>
23 #include <linux/platform_device.h>
24 #include <linux/slab.h>
25 #include <linux/clk.h>
26 #include <linux/pm_runtime.h>
35 static int __maybe_unused
serial_pxa_suspend(struct device
*dev
)
37 struct pxa8250_data
*data
= dev_get_drvdata(dev
);
39 serial8250_suspend_port(data
->line
);
44 static int __maybe_unused
serial_pxa_resume(struct device
*dev
)
46 struct pxa8250_data
*data
= dev_get_drvdata(dev
);
48 serial8250_resume_port(data
->line
);
53 static const struct dev_pm_ops serial_pxa_pm_ops
= {
54 SET_SYSTEM_SLEEP_PM_OPS(serial_pxa_suspend
, serial_pxa_resume
)
57 static const struct of_device_id serial_pxa_dt_ids
[] = {
58 { .compatible
= "mrvl,pxa-uart", },
59 { .compatible
= "mrvl,mmp-uart", },
62 MODULE_DEVICE_TABLE(of
, serial_pxa_dt_ids
);
64 /* Uart divisor latch write */
65 static void serial_pxa_dl_write(struct uart_8250_port
*up
, int value
)
69 serial_out(up
, UART_DLL
, value
& 0xff);
71 * work around Erratum #74 according to Marvel(R) PXA270M Processor
72 * Specification Update (April 19, 2010)
74 dll
= serial_in(up
, UART_DLL
);
75 WARN_ON(dll
!= (value
& 0xff));
77 serial_out(up
, UART_DLM
, value
>> 8 & 0xff);
81 static void serial_pxa_pm(struct uart_port
*port
, unsigned int state
,
82 unsigned int oldstate
)
84 struct pxa8250_data
*data
= port
->private_data
;
87 clk_prepare_enable(data
->clk
);
89 clk_disable_unprepare(data
->clk
);
92 static int serial_pxa_probe(struct platform_device
*pdev
)
94 struct uart_8250_port uart
= {};
95 struct pxa8250_data
*data
;
96 struct resource
*mmres
, *irqres
;
99 mmres
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
100 irqres
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
101 if (!mmres
|| !irqres
)
104 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
108 data
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
109 if (IS_ERR(data
->clk
))
110 return PTR_ERR(data
->clk
);
112 ret
= clk_prepare(data
->clk
);
116 ret
= of_alias_get_id(pdev
->dev
.of_node
, "serial");
118 uart
.port
.line
= ret
;
120 uart
.port
.type
= PORT_XSCALE
;
121 uart
.port
.iotype
= UPIO_MEM32
;
122 uart
.port
.mapbase
= mmres
->start
;
123 uart
.port
.regshift
= 2;
124 uart
.port
.irq
= irqres
->start
;
125 uart
.port
.fifosize
= 64;
126 uart
.port
.flags
= UPF_IOREMAP
| UPF_SKIP_TEST
;
127 uart
.port
.dev
= &pdev
->dev
;
128 uart
.port
.uartclk
= clk_get_rate(data
->clk
);
129 uart
.port
.pm
= serial_pxa_pm
;
130 uart
.port
.private_data
= data
;
131 uart
.dl_write
= serial_pxa_dl_write
;
133 ret
= serial8250_register_8250_port(&uart
);
139 platform_set_drvdata(pdev
, data
);
144 clk_unprepare(data
->clk
);
148 static int serial_pxa_remove(struct platform_device
*pdev
)
150 struct pxa8250_data
*data
= platform_get_drvdata(pdev
);
152 serial8250_unregister_port(data
->line
);
154 clk_unprepare(data
->clk
);
159 static struct platform_driver serial_pxa_driver
= {
160 .probe
= serial_pxa_probe
,
161 .remove
= serial_pxa_remove
,
164 .name
= "pxa2xx-uart",
165 .pm
= &serial_pxa_pm_ops
,
166 .of_match_table
= serial_pxa_dt_ids
,
170 module_platform_driver(serial_pxa_driver
);
172 #ifdef CONFIG_SERIAL_8250_CONSOLE
173 static int __init
early_serial_pxa_setup(struct earlycon_device
*device
,
176 struct uart_port
*port
= &device
->port
;
178 if (!(device
->port
.membase
|| device
->port
.iobase
))
182 return early_serial8250_setup(device
, NULL
);
184 OF_EARLYCON_DECLARE(early_pxa
, "mrvl,pxa-uart", early_serial_pxa_setup
);
187 MODULE_AUTHOR("Sergei Ianovich");
188 MODULE_LICENSE("GPL");
189 MODULE_ALIAS("platform:pxa2xx-uart");