aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-17 22:08:06 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-17 22:08:06 -0400
commit411f5c7a502769ccc0377c5ba36cb0b283847ba8 (patch)
tree2c3a29671e3f923de48c55f94194849264a7bf53 /drivers/tty
parent6d7ed21d17e640b120b902a314143e5ef4917a70 (diff)
parent9ced9f03d12d7539e86b0bff5bc750153c976c34 (diff)
Merge branch 'devel-stable' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel-stable' of master.kernel.org:/home/rmk/linux-2.6-arm: (289 commits) davinci: DM644x EVM: register MUSB device earlier davinci: add spi devices on tnetv107x evm davinci: add ssp config for tnetv107x evm board davinci: add tnetv107x ssp platform device spi: add ti-ssp spi master driver mfd: add driver for sequencer serial port ARM: EXYNOS4: Implement Clock gating for System MMU ARM: EXYNOS4: Enhancement of System MMU driver ARM: EXYNOS4: Add support for gpio interrupts ARM: S5P: Add function to register gpio interrupt bank data ARM: S5P: Cleanup S5P gpio interrupt code ARM: EXYNOS4: Add missing GPYx banks ARM: S3C64XX: Fix section mismatch from cpufreq init ARM: EXYNOS4: Add keypad device to the SMDKV310 ARM: EXYNOS4: Update clocks for keypad ARM: EXYNOS4: Update keypad base address ARM: EXYNOS4: Add keypad device helpers ARM: EXYNOS4: Add support for SATA on ARMLEX4210 plat-nomadik: make GPIO interrupts work with cpuidle ApSleep mach-u300: define a dummy filter function for coh901318 ... Fix up various conflicts in - arch/arm/mach-exynos4/cpufreq.c - arch/arm/mach-mxs/gpio.c - drivers/net/Kconfig - drivers/tty/serial/Kconfig - drivers/tty/serial/Makefile - drivers/usb/gadget/fsl_mxc_udc.c - drivers/video/Kconfig
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/Kconfig18
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/mxs-auart.c798
3 files changed, 815 insertions, 2 deletions
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index e461be164f67..e1aee37270f5 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -537,8 +537,8 @@ config SERIAL_S3C6400
537 537
538config SERIAL_S5PV210 538config SERIAL_S5PV210
539 tristate "Samsung S5PV210 Serial port support" 539 tristate "Samsung S5PV210 Serial port support"
540 depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_S5PV310) 540 depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_EXYNOS4210)
541 select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_S5PV310) 541 select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210)
542 default y 542 default y
543 help 543 help
544 Serial port support for Samsung's S5P Family of SoC's 544 Serial port support for Samsung's S5P Family of SoC's
@@ -1598,4 +1598,18 @@ config SERIAL_MSM_SMD
1598 Enables userspace clients to read and write to some streaming SMD 1598 Enables userspace clients to read and write to some streaming SMD
1599 ports via tty device interface for MSM chipset. 1599 ports via tty device interface for MSM chipset.
1600 1600
1601config SERIAL_MXS_AUART
1602 depends on ARCH_MXS
1603 tristate "MXS AUART support"
1604 select SERIAL_CORE
1605 help
1606 This driver supports the MXS Application UART (AUART) port.
1607
1608config SERIAL_MXS_AUART_CONSOLE
1609 bool "MXS AUART console support"
1610 depends on SERIAL_MXS_AUART=y
1611 select SERIAL_CORE_CONSOLE
1612 help
1613 Enable a MXS AUART port to be the system console.
1614
1601endmenu 1615endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 31e868cb49b2..fee0690ef8e3 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -93,3 +93,4 @@ obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
93obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o 93obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
94obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o 94obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
95obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o 95obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
96obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
new file mode 100644
index 000000000000..7e02c9c344fe
--- /dev/null
+++ b/drivers/tty/serial/mxs-auart.c
@@ -0,0 +1,798 @@
1/*
2 * Freescale STMP37XX/STMP378X Application UART driver
3 *
4 * Author: dmitry pervushin <dimka@embeddedalley.com>
5 *
6 * Copyright 2008-2010 Freescale Semiconductor, Inc.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 *
9 * The code contained herein is licensed under the GNU General Public
10 * License. You may obtain a copy of the GNU General Public License
11 * Version 2 or later at the following locations:
12 *
13 * http://www.opensource.org/licenses/gpl-license.html
14 * http://www.gnu.org/copyleft/gpl.html
15 */
16
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/init.h>
20#include <linux/console.h>
21#include <linux/interrupt.h>
22#include <linux/module.h>
23#include <linux/slab.h>
24#include <linux/wait.h>
25#include <linux/tty.h>
26#include <linux/tty_driver.h>
27#include <linux/tty_flip.h>
28#include <linux/serial.h>
29#include <linux/serial_core.h>
30#include <linux/platform_device.h>
31#include <linux/device.h>
32#include <linux/clk.h>
33#include <linux/delay.h>
34#include <linux/io.h>
35
36#include <asm/cacheflush.h>
37
38#define MXS_AUART_PORTS 5
39
40#define AUART_CTRL0 0x00000000
41#define AUART_CTRL0_SET 0x00000004
42#define AUART_CTRL0_CLR 0x00000008
43#define AUART_CTRL0_TOG 0x0000000c
44#define AUART_CTRL1 0x00000010
45#define AUART_CTRL1_SET 0x00000014
46#define AUART_CTRL1_CLR 0x00000018
47#define AUART_CTRL1_TOG 0x0000001c
48#define AUART_CTRL2 0x00000020
49#define AUART_CTRL2_SET 0x00000024
50#define AUART_CTRL2_CLR 0x00000028
51#define AUART_CTRL2_TOG 0x0000002c
52#define AUART_LINECTRL 0x00000030
53#define AUART_LINECTRL_SET 0x00000034
54#define AUART_LINECTRL_CLR 0x00000038
55#define AUART_LINECTRL_TOG 0x0000003c
56#define AUART_LINECTRL2 0x00000040
57#define AUART_LINECTRL2_SET 0x00000044
58#define AUART_LINECTRL2_CLR 0x00000048
59#define AUART_LINECTRL2_TOG 0x0000004c
60#define AUART_INTR 0x00000050
61#define AUART_INTR_SET 0x00000054
62#define AUART_INTR_CLR 0x00000058
63#define AUART_INTR_TOG 0x0000005c
64#define AUART_DATA 0x00000060
65#define AUART_STAT 0x00000070
66#define AUART_DEBUG 0x00000080
67#define AUART_VERSION 0x00000090
68#define AUART_AUTOBAUD 0x000000a0
69
70#define AUART_CTRL0_SFTRST (1 << 31)
71#define AUART_CTRL0_CLKGATE (1 << 30)
72
73#define AUART_CTRL2_CTSEN (1 << 15)
74#define AUART_CTRL2_RTS (1 << 11)
75#define AUART_CTRL2_RXE (1 << 9)
76#define AUART_CTRL2_TXE (1 << 8)
77#define AUART_CTRL2_UARTEN (1 << 0)
78
79#define AUART_LINECTRL_BAUD_DIVINT_SHIFT 16
80#define AUART_LINECTRL_BAUD_DIVINT_MASK 0xffff0000
81#define AUART_LINECTRL_BAUD_DIVINT(v) (((v) & 0xffff) << 16)
82#define AUART_LINECTRL_BAUD_DIVFRAC_SHIFT 8
83#define AUART_LINECTRL_BAUD_DIVFRAC_MASK 0x00003f00
84#define AUART_LINECTRL_BAUD_DIVFRAC(v) (((v) & 0x3f) << 8)
85#define AUART_LINECTRL_WLEN_MASK 0x00000060
86#define AUART_LINECTRL_WLEN(v) (((v) & 0x3) << 5)
87#define AUART_LINECTRL_FEN (1 << 4)
88#define AUART_LINECTRL_STP2 (1 << 3)
89#define AUART_LINECTRL_EPS (1 << 2)
90#define AUART_LINECTRL_PEN (1 << 1)
91#define AUART_LINECTRL_BRK (1 << 0)
92
93#define AUART_INTR_RTIEN (1 << 22)
94#define AUART_INTR_TXIEN (1 << 21)
95#define AUART_INTR_RXIEN (1 << 20)
96#define AUART_INTR_CTSMIEN (1 << 17)
97#define AUART_INTR_RTIS (1 << 6)
98#define AUART_INTR_TXIS (1 << 5)
99#define AUART_INTR_RXIS (1 << 4)
100#define AUART_INTR_CTSMIS (1 << 1)
101
102#define AUART_STAT_BUSY (1 << 29)
103#define AUART_STAT_CTS (1 << 28)
104#define AUART_STAT_TXFE (1 << 27)
105#define AUART_STAT_TXFF (1 << 25)
106#define AUART_STAT_RXFE (1 << 24)
107#define AUART_STAT_OERR (1 << 19)
108#define AUART_STAT_BERR (1 << 18)
109#define AUART_STAT_PERR (1 << 17)
110#define AUART_STAT_FERR (1 << 16)
111
112static struct uart_driver auart_driver;
113
114struct mxs_auart_port {
115 struct uart_port port;
116
117 unsigned int flags;
118 unsigned int ctrl;
119
120 unsigned int irq;
121
122 struct clk *clk;
123 struct device *dev;
124};
125
126static void mxs_auart_stop_tx(struct uart_port *u);
127
128#define to_auart_port(u) container_of(u, struct mxs_auart_port, port)
129
130static inline void mxs_auart_tx_chars(struct mxs_auart_port *s)
131{
132 struct circ_buf *xmit = &s->port.state->xmit;
133
134 while (!(readl(s->port.membase + AUART_STAT) &
135 AUART_STAT_TXFF)) {
136 if (s->port.x_char) {
137 s->port.icount.tx++;
138 writel(s->port.x_char,
139 s->port.membase + AUART_DATA);
140 s->port.x_char = 0;
141 continue;
142 }
143 if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
144 s->port.icount.tx++;
145 writel(xmit->buf[xmit->tail],
146 s->port.membase + AUART_DATA);
147 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
148 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
149 uart_write_wakeup(&s->port);
150 } else
151 break;
152 }
153 if (uart_circ_empty(&(s->port.state->xmit)))
154 writel(AUART_INTR_TXIEN,
155 s->port.membase + AUART_INTR_CLR);
156 else
157 writel(AUART_INTR_TXIEN,
158 s->port.membase + AUART_INTR_SET);
159
160 if (uart_tx_stopped(&s->port))
161 mxs_auart_stop_tx(&s->port);
162}
163
164static void mxs_auart_rx_char(struct mxs_auart_port *s)
165{
166 int flag;
167 u32 stat;
168 u8 c;
169
170 c = readl(s->port.membase + AUART_DATA);
171 stat = readl(s->port.membase + AUART_STAT);
172
173 flag = TTY_NORMAL;
174 s->port.icount.rx++;
175
176 if (stat & AUART_STAT_BERR) {
177 s->port.icount.brk++;
178 if (uart_handle_break(&s->port))
179 goto out;
180 } else if (stat & AUART_STAT_PERR) {
181 s->port.icount.parity++;
182 } else if (stat & AUART_STAT_FERR) {
183 s->port.icount.frame++;
184 }
185
186 /*
187 * Mask off conditions which should be ingored.
188 */
189 stat &= s->port.read_status_mask;
190
191 if (stat & AUART_STAT_BERR) {
192 flag = TTY_BREAK;
193 } else if (stat & AUART_STAT_PERR)
194 flag = TTY_PARITY;
195 else if (stat & AUART_STAT_FERR)
196 flag = TTY_FRAME;
197
198 if (stat & AUART_STAT_OERR)
199 s->port.icount.overrun++;
200
201 if (uart_handle_sysrq_char(&s->port, c))
202 goto out;
203
204 uart_insert_char(&s->port, stat, AUART_STAT_OERR, c, flag);
205out:
206 writel(stat, s->port.membase + AUART_STAT);
207}
208
209static void mxs_auart_rx_chars(struct mxs_auart_port *s)
210{
211 struct tty_struct *tty = s->port.state->port.tty;
212 u32 stat = 0;
213
214 for (;;) {
215 stat = readl(s->port.membase + AUART_STAT);
216 if (stat & AUART_STAT_RXFE)
217 break;
218 mxs_auart_rx_char(s);
219 }
220
221 writel(stat, s->port.membase + AUART_STAT);
222 tty_flip_buffer_push(tty);
223}
224
225static int mxs_auart_request_port(struct uart_port *u)
226{
227 return 0;
228}
229
230static int mxs_auart_verify_port(struct uart_port *u,
231 struct serial_struct *ser)
232{
233 if (u->type != PORT_UNKNOWN && u->type != PORT_IMX)
234 return -EINVAL;
235 return 0;
236}
237
238static void mxs_auart_config_port(struct uart_port *u, int flags)
239{
240}
241
242static const char *mxs_auart_type(struct uart_port *u)
243{
244 struct mxs_auart_port *s = to_auart_port(u);
245
246 return dev_name(s->dev);
247}
248
249static void mxs_auart_release_port(struct uart_port *u)
250{
251}
252
253static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
254{
255 struct mxs_auart_port *s = to_auart_port(u);
256
257 u32 ctrl = readl(u->membase + AUART_CTRL2);
258
259 ctrl &= ~AUART_CTRL2_RTS;
260 if (mctrl & TIOCM_RTS)
261 ctrl |= AUART_CTRL2_RTS;
262 s->ctrl = mctrl;
263 writel(ctrl, u->membase + AUART_CTRL2);
264}
265
266static u32 mxs_auart_get_mctrl(struct uart_port *u)
267{
268 struct mxs_auart_port *s = to_auart_port(u);
269 u32 stat = readl(u->membase + AUART_STAT);
270 int ctrl2 = readl(u->membase + AUART_CTRL2);
271 u32 mctrl = s->ctrl;
272
273 mctrl &= ~TIOCM_CTS;
274 if (stat & AUART_STAT_CTS)
275 mctrl |= TIOCM_CTS;
276
277 if (ctrl2 & AUART_CTRL2_RTS)
278 mctrl |= TIOCM_RTS;
279
280 return mctrl;
281}
282
283static void mxs_auart_settermios(struct uart_port *u,
284 struct ktermios *termios,
285 struct ktermios *old)
286{
287 u32 bm, ctrl, ctrl2, div;
288 unsigned int cflag, baud;
289
290 cflag = termios->c_cflag;
291
292 ctrl = AUART_LINECTRL_FEN;
293 ctrl2 = readl(u->membase + AUART_CTRL2);
294
295 /* byte size */
296 switch (cflag & CSIZE) {
297 case CS5:
298 bm = 0;
299 break;
300 case CS6:
301 bm = 1;
302 break;
303 case CS7:
304 bm = 2;
305 break;
306 case CS8:
307 bm = 3;
308 break;
309 default:
310 return;
311 }
312
313 ctrl |= AUART_LINECTRL_WLEN(bm);
314
315 /* parity */
316 if (cflag & PARENB) {
317 ctrl |= AUART_LINECTRL_PEN;
318 if ((cflag & PARODD) == 0)
319 ctrl |= AUART_LINECTRL_EPS;
320 }
321
322 u->read_status_mask = 0;
323
324 if (termios->c_iflag & INPCK)
325 u->read_status_mask |= AUART_STAT_PERR;
326 if (termios->c_iflag & (BRKINT | PARMRK))
327 u->read_status_mask |= AUART_STAT_BERR;
328
329 /*
330 * Characters to ignore
331 */
332 u->ignore_status_mask = 0;
333 if (termios->c_iflag & IGNPAR)
334 u->ignore_status_mask |= AUART_STAT_PERR;
335 if (termios->c_iflag & IGNBRK) {
336 u->ignore_status_mask |= AUART_STAT_BERR;
337 /*
338 * If we're ignoring parity and break indicators,
339 * ignore overruns too (for real raw support).
340 */
341 if (termios->c_iflag & IGNPAR)
342 u->ignore_status_mask |= AUART_STAT_OERR;
343 }
344
345 /*
346 * ignore all characters if CREAD is not set
347 */
348 if (cflag & CREAD)
349 ctrl2 |= AUART_CTRL2_RXE;
350 else
351 ctrl2 &= ~AUART_CTRL2_RXE;
352
353 /* figure out the stop bits requested */
354 if (cflag & CSTOPB)
355 ctrl |= AUART_LINECTRL_STP2;
356
357 /* figure out the hardware flow control settings */
358 if (cflag & CRTSCTS)
359 ctrl2 |= AUART_CTRL2_CTSEN;
360 else
361 ctrl2 &= ~AUART_CTRL2_CTSEN;
362
363 /* set baud rate */
364 baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk);
365 div = u->uartclk * 32 / baud;
366 ctrl |= AUART_LINECTRL_BAUD_DIVFRAC(div & 0x3F);
367 ctrl |= AUART_LINECTRL_BAUD_DIVINT(div >> 6);
368
369 writel(ctrl, u->membase + AUART_LINECTRL);
370 writel(ctrl2, u->membase + AUART_CTRL2);
371}
372
373static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
374{
375 u32 istatus, istat;
376 struct mxs_auart_port *s = context;
377 u32 stat = readl(s->port.membase + AUART_STAT);
378
379 istatus = istat = readl(s->port.membase + AUART_INTR);
380
381 if (istat & AUART_INTR_CTSMIS) {
382 uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
383 writel(AUART_INTR_CTSMIS,
384 s->port.membase + AUART_INTR_CLR);
385 istat &= ~AUART_INTR_CTSMIS;
386 }
387
388 if (istat & (AUART_INTR_RTIS | AUART_INTR_RXIS)) {
389 mxs_auart_rx_chars(s);
390 istat &= ~(AUART_INTR_RTIS | AUART_INTR_RXIS);
391 }
392
393 if (istat & AUART_INTR_TXIS) {
394 mxs_auart_tx_chars(s);
395 istat &= ~AUART_INTR_TXIS;
396 }
397
398 writel(istatus & (AUART_INTR_RTIS
399 | AUART_INTR_TXIS
400 | AUART_INTR_RXIS
401 | AUART_INTR_CTSMIS),
402 s->port.membase + AUART_INTR_CLR);
403
404 return IRQ_HANDLED;
405}
406
407static void mxs_auart_reset(struct uart_port *u)
408{
409 int i;
410 unsigned int reg;
411
412 writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_CLR);
413
414 for (i = 0; i < 10000; i++) {
415 reg = readl(u->membase + AUART_CTRL0);
416 if (!(reg & AUART_CTRL0_SFTRST))
417 break;
418 udelay(3);
419 }
420 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
421}
422
423static int mxs_auart_startup(struct uart_port *u)
424{
425 struct mxs_auart_port *s = to_auart_port(u);
426
427 clk_enable(s->clk);
428
429 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
430
431 writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_SET);
432
433 writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
434 u->membase + AUART_INTR);
435
436 /*
437 * Enable fifo so all four bytes of a DMA word are written to
438 * output (otherwise, only the LSB is written, ie. 1 in 4 bytes)
439 */
440 writel(AUART_LINECTRL_FEN, u->membase + AUART_LINECTRL_SET);
441
442 return 0;
443}
444
445static void mxs_auart_shutdown(struct uart_port *u)
446{
447 struct mxs_auart_port *s = to_auart_port(u);
448
449 writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR);
450
451 writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET);
452
453 writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
454 u->membase + AUART_INTR_CLR);
455
456 clk_disable(s->clk);
457}
458
459static unsigned int mxs_auart_tx_empty(struct uart_port *u)
460{
461 if (readl(u->membase + AUART_STAT) & AUART_STAT_TXFE)
462 return TIOCSER_TEMT;
463 else
464 return 0;
465}
466
467static void mxs_auart_start_tx(struct uart_port *u)
468{
469 struct mxs_auart_port *s = to_auart_port(u);
470
471 /* enable transmitter */
472 writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_SET);
473
474 mxs_auart_tx_chars(s);
475}
476
477static void mxs_auart_stop_tx(struct uart_port *u)
478{
479 writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_CLR);
480}
481
482static void mxs_auart_stop_rx(struct uart_port *u)
483{
484 writel(AUART_CTRL2_RXE, u->membase + AUART_CTRL2_CLR);
485}
486
487static void mxs_auart_break_ctl(struct uart_port *u, int ctl)
488{
489 if (ctl)
490 writel(AUART_LINECTRL_BRK,
491 u->membase + AUART_LINECTRL_SET);
492 else
493 writel(AUART_LINECTRL_BRK,
494 u->membase + AUART_LINECTRL_CLR);
495}
496
497static void mxs_auart_enable_ms(struct uart_port *port)
498{
499 /* just empty */
500}
501
502static struct uart_ops mxs_auart_ops = {
503 .tx_empty = mxs_auart_tx_empty,
504 .start_tx = mxs_auart_start_tx,
505 .stop_tx = mxs_auart_stop_tx,
506 .stop_rx = mxs_auart_stop_rx,
507 .enable_ms = mxs_auart_enable_ms,
508 .break_ctl = mxs_auart_break_ctl,
509 .set_mctrl = mxs_auart_set_mctrl,
510 .get_mctrl = mxs_auart_get_mctrl,
511 .startup = mxs_auart_startup,
512 .shutdown = mxs_auart_shutdown,
513 .set_termios = mxs_auart_settermios,
514 .type = mxs_auart_type,
515 .release_port = mxs_auart_release_port,
516 .request_port = mxs_auart_request_port,
517 .config_port = mxs_auart_config_port,
518 .verify_port = mxs_auart_verify_port,
519};
520
521static struct mxs_auart_port *auart_port[MXS_AUART_PORTS];
522
523#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
524static void mxs_auart_console_putchar(struct uart_port *port, int ch)
525{
526 unsigned int to = 1000;
527
528 while (readl(port->membase + AUART_STAT) & AUART_STAT_TXFF) {
529 if (!to--)
530 break;
531 udelay(1);
532 }
533
534 writel(ch, port->membase + AUART_DATA);
535}
536
537static void
538auart_console_write(struct console *co, const char *str, unsigned int count)
539{
540 struct mxs_auart_port *s;
541 struct uart_port *port;
542 unsigned int old_ctrl0, old_ctrl2;
543 unsigned int to = 1000;
544
545 if (co->index > MXS_AUART_PORTS || co->index < 0)
546 return;
547
548 s = auart_port[co->index];
549 port = &s->port;
550
551 clk_enable(s->clk);
552
553 /* First save the CR then disable the interrupts */
554 old_ctrl2 = readl(port->membase + AUART_CTRL2);
555 old_ctrl0 = readl(port->membase + AUART_CTRL0);
556
557 writel(AUART_CTRL0_CLKGATE,
558 port->membase + AUART_CTRL0_CLR);
559 writel(AUART_CTRL2_UARTEN | AUART_CTRL2_TXE,
560 port->membase + AUART_CTRL2_SET);
561
562 uart_console_write(port, str, count, mxs_auart_console_putchar);
563
564 /*
565 * Finally, wait for transmitter to become empty
566 * and restore the TCR
567 */
568 while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
569 if (!to--)
570 break;
571 udelay(1);
572 }
573
574 writel(old_ctrl0, port->membase + AUART_CTRL0);
575 writel(old_ctrl2, port->membase + AUART_CTRL2);
576
577 clk_disable(s->clk);
578}
579
580static void __init
581auart_console_get_options(struct uart_port *port, int *baud,
582 int *parity, int *bits)
583{
584 unsigned int lcr_h, quot;
585
586 if (!(readl(port->membase + AUART_CTRL2) & AUART_CTRL2_UARTEN))
587 return;
588
589 lcr_h = readl(port->membase + AUART_LINECTRL);
590
591 *parity = 'n';
592 if (lcr_h & AUART_LINECTRL_PEN) {
593 if (lcr_h & AUART_LINECTRL_EPS)
594 *parity = 'e';
595 else
596 *parity = 'o';
597 }
598
599 if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(2))
600 *bits = 7;
601 else
602 *bits = 8;
603
604 quot = ((readl(port->membase + AUART_LINECTRL)
605 & AUART_LINECTRL_BAUD_DIVINT_MASK))
606 >> (AUART_LINECTRL_BAUD_DIVINT_SHIFT - 6);
607 quot |= ((readl(port->membase + AUART_LINECTRL)
608 & AUART_LINECTRL_BAUD_DIVFRAC_MASK))
609 >> AUART_LINECTRL_BAUD_DIVFRAC_SHIFT;
610 if (quot == 0)
611 quot = 1;
612
613 *baud = (port->uartclk << 2) / quot;
614}
615
616static int __init
617auart_console_setup(struct console *co, char *options)
618{
619 struct mxs_auart_port *s;
620 int baud = 9600;
621 int bits = 8;
622 int parity = 'n';
623 int flow = 'n';
624 int ret;
625
626 /*
627 * Check whether an invalid uart number has been specified, and
628 * if so, search for the first available port that does have
629 * console support.
630 */
631 if (co->index == -1 || co->index >= ARRAY_SIZE(auart_port))
632 co->index = 0;
633 s = auart_port[co->index];
634 if (!s)
635 return -ENODEV;
636
637 clk_enable(s->clk);
638
639 if (options)
640 uart_parse_options(options, &baud, &parity, &bits, &flow);
641 else
642 auart_console_get_options(&s->port, &baud, &parity, &bits);
643
644 ret = uart_set_options(&s->port, co, baud, parity, bits, flow);
645
646 clk_disable(s->clk);
647
648 return ret;
649}
650
651static struct console auart_console = {
652 .name = "ttyAPP",
653 .write = auart_console_write,
654 .device = uart_console_device,
655 .setup = auart_console_setup,
656 .flags = CON_PRINTBUFFER,
657 .index = -1,
658 .data = &auart_driver,
659};
660#endif
661
662static struct uart_driver auart_driver = {
663 .owner = THIS_MODULE,
664 .driver_name = "ttyAPP",
665 .dev_name = "ttyAPP",
666 .major = 0,
667 .minor = 0,
668 .nr = MXS_AUART_PORTS,
669#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
670 .cons = &auart_console,
671#endif
672};
673
674static int __devinit mxs_auart_probe(struct platform_device *pdev)
675{
676 struct mxs_auart_port *s;
677 u32 version;
678 int ret = 0;
679 struct resource *r;
680
681 s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
682 if (!s) {
683 ret = -ENOMEM;
684 goto out;
685 }
686
687 s->clk = clk_get(&pdev->dev, NULL);
688 if (IS_ERR(s->clk)) {
689 ret = PTR_ERR(s->clk);
690 goto out_free;
691 }
692
693 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
694 if (!r) {
695 ret = -ENXIO;
696 goto out_free_clk;
697 }
698
699 s->port.mapbase = r->start;
700 s->port.membase = ioremap(r->start, resource_size(r));
701 s->port.ops = &mxs_auart_ops;
702 s->port.iotype = UPIO_MEM;
703 s->port.line = pdev->id < 0 ? 0 : pdev->id;
704 s->port.fifosize = 16;
705 s->port.uartclk = clk_get_rate(s->clk);
706 s->port.type = PORT_IMX;
707 s->port.dev = s->dev = get_device(&pdev->dev);
708
709 s->flags = 0;
710 s->ctrl = 0;
711
712 s->irq = platform_get_irq(pdev, 0);
713 s->port.irq = s->irq;
714 ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
715 if (ret)
716 goto out_free_clk;
717
718 platform_set_drvdata(pdev, s);
719
720 auart_port[pdev->id] = s;
721
722 mxs_auart_reset(&s->port);
723
724 ret = uart_add_one_port(&auart_driver, &s->port);
725 if (ret)
726 goto out_free_irq;
727
728 version = readl(s->port.membase + AUART_VERSION);
729 dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n",
730 (version >> 24) & 0xff,
731 (version >> 16) & 0xff, version & 0xffff);
732
733 return 0;
734
735out_free_irq:
736 auart_port[pdev->id] = NULL;
737 free_irq(s->irq, s);
738out_free_clk:
739 clk_put(s->clk);
740out_free:
741 kfree(s);
742out:
743 return ret;
744}
745
746static int __devexit mxs_auart_remove(struct platform_device *pdev)
747{
748 struct mxs_auart_port *s = platform_get_drvdata(pdev);
749
750 uart_remove_one_port(&auart_driver, &s->port);
751
752 auart_port[pdev->id] = NULL;
753
754 clk_put(s->clk);
755 free_irq(s->irq, s);
756 kfree(s);
757
758 return 0;
759}
760
761static struct platform_driver mxs_auart_driver = {
762 .probe = mxs_auart_probe,
763 .remove = __devexit_p(mxs_auart_remove),
764 .driver = {
765 .name = "mxs-auart",
766 .owner = THIS_MODULE,
767 },
768};
769
770static int __init mxs_auart_init(void)
771{
772 int r;
773
774 r = uart_register_driver(&auart_driver);
775 if (r)
776 goto out;
777
778 r = platform_driver_register(&mxs_auart_driver);
779 if (r)
780 goto out_err;
781
782 return 0;
783out_err:
784 uart_unregister_driver(&auart_driver);
785out:
786 return r;
787}
788
789static void __exit mxs_auart_exit(void)
790{
791 platform_driver_unregister(&mxs_auart_driver);
792 uart_unregister_driver(&auart_driver);
793}
794
795module_init(mxs_auart_init);
796module_exit(mxs_auart_exit);
797MODULE_LICENSE("GPL");
798MODULE_DESCRIPTION("Freescale MXS application uart driver");