aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2012-05-03 08:13:09 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-04 19:45:07 -0400
commit22886ee96895b7a9f9d06da4dc9420b61b4ef1f7 (patch)
treece6a442c280827b21da66c771aaec9a4e8613193
parent8b979f7c6bf13a57e7b6002f1175312a44773960 (diff)
serial8250-em: Emma Mobile UART driver V2
This is V2 of the Emma Mobile 8250 platform driver. The hardware itself has according to the data sheet up to 64 byte FIFOs but at this point we only make use of the 16550 compatible mode. To support this piece of hardware the common UART registers need to be remapped, and the access size differences need to be handled. The DLL and DLM registers can due to offset collision not be remapped easily, and because of that this driver makes use of ->dl_read() and ->dl_write() callbacks. This in turn requires a registration function that takes 8250-specific paramenters. Future potential enhancements include DT support, early platform driver console and fine grained PM. Signed-off-by: Magnus Damm <damm@opensource.se> Acked-by: Alan Cox <alan@linux.intel.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/8250/8250_em.c178
-rw-r--r--drivers/tty/serial/8250/Kconfig8
-rw-r--r--drivers/tty/serial/8250/Makefile1
3 files changed, 187 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
new file mode 100644
index 000000000000..ff4254249bd8
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -0,0 +1,178 @@
1/*
2 * Renesas Emma Mobile 8250 driver
3 *
4 * Copyright (C) 2012 Magnus Damm
5 *
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
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include <linux/device.h>
21#include <linux/init.h>
22#include <linux/io.h>
23#include <linux/module.h>
24#include <linux/serial_8250.h>
25#include <linux/serial_core.h>
26#include <linux/serial_reg.h>
27#include <linux/platform_device.h>
28#include <linux/clk.h>
29#include <linux/slab.h>
30
31#include "8250.h"
32
33#define UART_DLL_EM 9
34#define UART_DLM_EM 10
35
36struct serial8250_em_priv {
37 struct clk *sclk;
38 int line;
39};
40
41static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
42{
43 switch (offset) {
44 case UART_TX: /* TX @ 0x00 */
45 writeb(value, p->membase);
46 break;
47 case UART_FCR: /* FCR @ 0x0c (+1) */
48 case UART_LCR: /* LCR @ 0x10 (+1) */
49 case UART_MCR: /* MCR @ 0x14 (+1) */
50 case UART_SCR: /* SCR @ 0x20 (+1) */
51 writel(value, p->membase + ((offset + 1) << 2));
52 break;
53 case UART_IER: /* IER @ 0x04 */
54 value &= 0x0f; /* only 4 valid bits - not Xscale */
55 /* fall-through */
56 case UART_DLL_EM: /* DLL @ 0x24 (+9) */
57 case UART_DLM_EM: /* DLM @ 0x28 (+9) */
58 writel(value, p->membase + (offset << 2));
59 }
60}
61
62static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset)
63{
64 switch (offset) {
65 case UART_RX: /* RX @ 0x00 */
66 return readb(p->membase);
67 case UART_MCR: /* MCR @ 0x14 (+1) */
68 case UART_LSR: /* LSR @ 0x18 (+1) */
69 case UART_MSR: /* MSR @ 0x1c (+1) */
70 case UART_SCR: /* SCR @ 0x20 (+1) */
71 return readl(p->membase + ((offset + 1) << 2));
72 case UART_IER: /* IER @ 0x04 */
73 case UART_IIR: /* IIR @ 0x08 */
74 case UART_DLL_EM: /* DLL @ 0x24 (+9) */
75 case UART_DLM_EM: /* DLM @ 0x28 (+9) */
76 return readl(p->membase + (offset << 2));
77 }
78 return 0;
79}
80
81static int serial8250_em_serial_dl_read(struct uart_8250_port *up)
82{
83 return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8;
84}
85
86static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
87{
88 serial_out(up, UART_DLL_EM, value & 0xff);
89 serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
90}
91
92static int __devinit serial8250_em_probe(struct platform_device *pdev)
93{
94 struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
95 struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
96 struct serial8250_em_priv *priv;
97 struct uart_8250_port up;
98 int ret = -EINVAL;
99
100 if (!regs || !irq) {
101 dev_err(&pdev->dev, "missing registers or irq\n");
102 goto err0;
103 }
104
105 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
106 if (!priv) {
107 dev_err(&pdev->dev, "unable to allocate private data\n");
108 ret = -ENOMEM;
109 goto err0;
110 }
111
112 priv->sclk = clk_get(&pdev->dev, "sclk");
113 if (!priv->sclk) {
114 dev_err(&pdev->dev, "unable to get clock\n");
115 goto err1;
116 }
117
118 memset(&up, 0, sizeof(up));
119 up.port.mapbase = regs->start;
120 up.port.irq = irq->start;
121 up.port.type = PORT_UNKNOWN;
122 up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
123 up.port.dev = &pdev->dev;
124 up.port.private_data = priv;
125
126 clk_enable(priv->sclk);
127 up.port.uartclk = clk_get_rate(priv->sclk);
128
129 up.port.iotype = UPIO_MEM32;
130 up.port.serial_in = serial8250_em_serial_in;
131 up.port.serial_out = serial8250_em_serial_out;
132 up.dl_read = serial8250_em_serial_dl_read;
133 up.dl_write = serial8250_em_serial_dl_write;
134
135 ret = serial8250_register_8250_port(&up);
136 if (ret < 0) {
137 dev_err(&pdev->dev, "unable to register 8250 port\n");
138 goto err2;
139 }
140
141 priv->line = ret;
142 platform_set_drvdata(pdev, priv);
143 return 0;
144
145 err2:
146 clk_disable(priv->sclk);
147 clk_put(priv->sclk);
148 err1:
149 kfree(priv);
150 err0:
151 return ret;
152}
153
154static int __devexit serial8250_em_remove(struct platform_device *pdev)
155{
156 struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
157
158 serial8250_unregister_port(priv->line);
159 clk_disable(priv->sclk);
160 clk_put(priv->sclk);
161 kfree(priv);
162 return 0;
163}
164
165static struct platform_driver serial8250_em_platform_driver = {
166 .driver = {
167 .name = "serial8250-em",
168 .owner = THIS_MODULE,
169 },
170 .probe = serial8250_em_probe,
171 .remove = __devexit_p(serial8250_em_remove),
172};
173
174module_platform_driver(serial8250_em_platform_driver);
175
176MODULE_AUTHOR("Magnus Damm");
177MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver");
178MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 591f8018e7dd..8bc7ecbf6bea 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -278,3 +278,11 @@ config SERIAL_8250_DW
278 help 278 help
279 Selecting this option will enable handling of the extra features 279 Selecting this option will enable handling of the extra features
280 present in the Synopsys DesignWare APB UART. 280 present in the Synopsys DesignWare APB UART.
281
282config SERIAL_8250_EM
283 tristate "Support for Emma Mobile intergrated serial port"
284 depends on SERIAL_8250 && ARM && HAVE_CLK
285 help
286 Selecting this option will add support for the integrated serial
287 port hardware found on the Emma Mobile line of processors.
288 If unsure, say N.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 867bba738908..3f35eacdf673 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
18obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o 18obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
19obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o 19obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
20obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o 20obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
21obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o