blob: 2d5eac20c5cd4329b4e717d9a9a020604896d32e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Driver for Motorola IMX serial ports
3 *
4 * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
5 *
6 * Author: Sascha Hauer <sascha@saschahauer.de>
7 * Copyright (C) 2004 Pengutronix
8 *
Fabian Godehardtb6e49132009-06-11 14:53:18 +01009 * Copyright (C) 2009 emlix GmbH
10 * Author: Fabian Godehardt (added IrDA support for iMX)
11 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 * [29-Mar-2005] Mike Lee
27 * Added hardware handshake
28 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
31#define SUPPORT_SYSRQ
32#endif
33
34#include <linux/module.h>
35#include <linux/ioport.h>
36#include <linux/init.h>
37#include <linux/console.h>
38#include <linux/sysrq.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010039#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/tty.h>
41#include <linux/tty_flip.h>
42#include <linux/serial_core.h>
43#include <linux/serial.h>
Sascha Hauer38a41fd2008-07-05 10:02:46 +020044#include <linux/clk.h>
Fabian Godehardtb6e49132009-06-11 14:53:18 +010045#include <linux/delay.h>
Oskar Schirmer534fca02009-06-11 14:52:23 +010046#include <linux/rational.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090047#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#include <asm/io.h>
50#include <asm/irq.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010051#include <mach/imx-uart.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Sascha Hauerff4bfb22007-04-26 08:26:13 +010053/* Register definitions */
54#define URXD0 0x0 /* Receiver Register */
55#define URTX0 0x40 /* Transmitter Register */
56#define UCR1 0x80 /* Control Register 1 */
57#define UCR2 0x84 /* Control Register 2 */
58#define UCR3 0x88 /* Control Register 3 */
59#define UCR4 0x8c /* Control Register 4 */
60#define UFCR 0x90 /* FIFO Control Register */
61#define USR1 0x94 /* Status Register 1 */
62#define USR2 0x98 /* Status Register 2 */
63#define UESC 0x9c /* Escape Character Register */
64#define UTIM 0xa0 /* Escape Timer Register */
65#define UBIR 0xa4 /* BRM Incremental Register */
66#define UBMR 0xa8 /* BRM Modulator Register */
67#define UBRC 0xac /* Baud Rate Count Register */
Shawn Guofe6b5402011-06-25 02:04:33 +080068#define IMX21_ONEMS 0xb0 /* One Millisecond register */
69#define IMX1_UTS 0xd0 /* UART Test Register on i.mx1 */
70#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
Sascha Hauerff4bfb22007-04-26 08:26:13 +010071
72/* UART Control Register Bit Fields.*/
73#define URXD_CHARRDY (1<<15)
74#define URXD_ERR (1<<14)
75#define URXD_OVRRUN (1<<13)
76#define URXD_FRMERR (1<<12)
77#define URXD_BRK (1<<11)
78#define URXD_PRERR (1<<10)
Lucas De Marchi25985ed2011-03-30 22:57:33 -030079#define UCR1_ADEN (1<<15) /* Auto detect interrupt */
Sascha Hauerff4bfb22007-04-26 08:26:13 +010080#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
81#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
82#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
83#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
84#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
85#define UCR1_IREN (1<<7) /* Infrared interface enable */
86#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
87#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
88#define UCR1_SNDBRK (1<<4) /* Send break */
89#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
Shawn Guofe6b5402011-06-25 02:04:33 +080090#define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */
Sascha Hauerff4bfb22007-04-26 08:26:13 +010091#define UCR1_DOZE (1<<1) /* Doze */
92#define UCR1_UARTEN (1<<0) /* UART enabled */
93#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */
94#define UCR2_IRTS (1<<14) /* Ignore RTS pin */
95#define UCR2_CTSC (1<<13) /* CTS pin control */
96#define UCR2_CTS (1<<12) /* Clear to send */
97#define UCR2_ESCEN (1<<11) /* Escape enable */
98#define UCR2_PREN (1<<8) /* Parity enable */
99#define UCR2_PROE (1<<7) /* Parity odd/even */
100#define UCR2_STPB (1<<6) /* Stop */
101#define UCR2_WS (1<<5) /* Word size */
102#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */
103#define UCR2_TXEN (1<<2) /* Transmitter enabled */
104#define UCR2_RXEN (1<<1) /* Receiver enabled */
105#define UCR2_SRST (1<<0) /* SW reset */
106#define UCR3_DTREN (1<<13) /* DTR interrupt enable */
107#define UCR3_PARERREN (1<<12) /* Parity enable */
108#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */
109#define UCR3_DSR (1<<10) /* Data set ready */
110#define UCR3_DCD (1<<9) /* Data carrier detect */
111#define UCR3_RI (1<<8) /* Ring indicator */
112#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
113#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
114#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
115#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
Shawn Guofe6b5402011-06-25 02:04:33 +0800116#define IMX21_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select */
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100117#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
118#define UCR3_BPEN (1<<0) /* Preset registers enable */
Valentin Longchamp1c5250d2010-05-05 11:47:07 +0200119#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */
120#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100121#define UCR4_INVR (1<<9) /* Inverted infrared reception */
122#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
123#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
124#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */
125#define UCR4_IRSC (1<<5) /* IR special case */
126#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */
127#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */
128#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
129#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
130#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
131#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100132#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7)
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100133#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
134#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
135#define USR1_RTSS (1<<14) /* RTS pin status */
136#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */
137#define USR1_RTSD (1<<12) /* RTS delta */
138#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
139#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
140#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
141#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
142#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
143#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
144#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */
145#define USR2_ADET (1<<15) /* Auto baud rate detect complete */
146#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
147#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
148#define USR2_IDLE (1<<12) /* Idle condition */
149#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
150#define USR2_WAKE (1<<7) /* Wake */
151#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
152#define USR2_TXDC (1<<3) /* Transmitter complete */
153#define USR2_BRCD (1<<2) /* Break condition */
154#define USR2_ORE (1<<1) /* Overrun error */
155#define USR2_RDR (1<<0) /* Recv data ready */
156#define UTS_FRCPERR (1<<13) /* Force parity error */
157#define UTS_LOOP (1<<12) /* Loop tx and rx */
158#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
159#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
160#define UTS_TXFULL (1<<4) /* TxFIFO full */
161#define UTS_RXFULL (1<<3) /* RxFIFO full */
162#define UTS_SOFTRST (1<<0) /* Software reset */
163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164/* We've been assigned a range on the "Low-density serial ports" major */
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200165#define SERIAL_IMX_MAJOR 207
166#define MINOR_START 16
167#define DEV_NAME "ttymxc"
Sascha Hauer9d631b82008-12-18 11:08:55 +0100168#define MAX_INTERNAL_IRQ MXC_INTERNAL_IRQS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 * This determines how often we check the modem status signals
172 * for any change. They generally aren't connected to an IRQ
173 * so we have to poll them. We also check immediately before
174 * filling the TX fifo incase CTS has been dropped.
175 */
176#define MCTRL_TIMEOUT (250*HZ/1000)
177
178#define DRIVER_NAME "IMX-uart"
179
Sascha Hauerdbff4e92008-07-05 10:02:45 +0200180#define UART_NR 8
181
Shawn Guofe6b5402011-06-25 02:04:33 +0800182/* i.mx21 type uart runs on all i.mx except i.mx1 */
183enum imx_uart_type {
184 IMX1_UART,
185 IMX21_UART,
186};
187
188/* device type dependent stuff */
189struct imx_uart_data {
190 unsigned uts_reg;
191 enum imx_uart_type devtype;
192};
193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194struct imx_port {
195 struct uart_port port;
196 struct timer_list timer;
197 unsigned int old_status;
Sascha Hauer5b802342006-05-04 14:07:42 +0100198 int txirq,rxirq,rtsirq;
Daniel Glöckner26bbb3f2009-06-11 14:36:29 +0100199 unsigned int have_rtscts:1;
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100200 unsigned int use_irda:1;
201 unsigned int irda_inv_rx:1;
202 unsigned int irda_inv_tx:1;
203 unsigned short trcv_delay; /* transceiver delay */
Sascha Hauer38a41fd2008-07-05 10:02:46 +0200204 struct clk *clk;
Shawn Guofe6b5402011-06-25 02:04:33 +0800205 struct imx_uart_data *devdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206};
207
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100208#ifdef CONFIG_IRDA
209#define USE_IRDA(sport) ((sport)->use_irda)
210#else
211#define USE_IRDA(sport) (0)
212#endif
213
Shawn Guofe6b5402011-06-25 02:04:33 +0800214static struct imx_uart_data imx_uart_devdata[] = {
215 [IMX1_UART] = {
216 .uts_reg = IMX1_UTS,
217 .devtype = IMX1_UART,
218 },
219 [IMX21_UART] = {
220 .uts_reg = IMX21_UTS,
221 .devtype = IMX21_UART,
222 },
223};
224
225static struct platform_device_id imx_uart_devtype[] = {
226 {
227 .name = "imx1-uart",
228 .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART],
229 }, {
230 .name = "imx21-uart",
231 .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART],
232 }, {
233 /* sentinel */
234 }
235};
236MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
237
238static inline unsigned uts_reg(struct imx_port *sport)
239{
240 return sport->devdata->uts_reg;
241}
242
243static inline int is_imx1_uart(struct imx_port *sport)
244{
245 return sport->devdata->devtype == IMX1_UART;
246}
247
248static inline int is_imx21_uart(struct imx_port *sport)
249{
250 return sport->devdata->devtype == IMX21_UART;
251}
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253/*
254 * Handle any change of modem status signal since we were last called.
255 */
256static void imx_mctrl_check(struct imx_port *sport)
257{
258 unsigned int status, changed;
259
260 status = sport->port.ops->get_mctrl(&sport->port);
261 changed = status ^ sport->old_status;
262
263 if (changed == 0)
264 return;
265
266 sport->old_status = status;
267
268 if (changed & TIOCM_RI)
269 sport->port.icount.rng++;
270 if (changed & TIOCM_DSR)
271 sport->port.icount.dsr++;
272 if (changed & TIOCM_CAR)
273 uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
274 if (changed & TIOCM_CTS)
275 uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
276
Alan Coxbdc04e32009-09-19 13:13:31 -0700277 wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278}
279
280/*
281 * This is our per-port timeout handler, for checking the
282 * modem status signals.
283 */
284static void imx_timeout(unsigned long data)
285{
286 struct imx_port *sport = (struct imx_port *)data;
287 unsigned long flags;
288
Alan Coxebd2c8f2009-09-19 13:13:28 -0700289 if (sport->port.state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 spin_lock_irqsave(&sport->port.lock, flags);
291 imx_mctrl_check(sport);
292 spin_unlock_irqrestore(&sport->port.lock, flags);
293
294 mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
295 }
296}
297
298/*
299 * interrupts disabled on entry
300 */
Russell Kingb129a8c2005-08-31 10:12:14 +0100301static void imx_stop_tx(struct uart_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
303 struct imx_port *sport = (struct imx_port *)port;
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100304 unsigned long temp;
305
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100306 if (USE_IRDA(sport)) {
307 /* half duplex - wait for end of transmission */
308 int n = 256;
309 while ((--n > 0) &&
310 !(readl(sport->port.membase + USR2) & USR2_TXDC)) {
311 udelay(5);
312 barrier();
313 }
314 /*
315 * irda transceiver - wait a bit more to avoid
316 * cutoff, hardware dependent
317 */
318 udelay(sport->trcv_delay);
319
320 /*
321 * half duplex - reactivate receive mode,
322 * flush receive pipe echo crap
323 */
324 if (readl(sport->port.membase + USR2) & USR2_TXDC) {
325 temp = readl(sport->port.membase + UCR1);
326 temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN);
327 writel(temp, sport->port.membase + UCR1);
328
329 temp = readl(sport->port.membase + UCR4);
330 temp &= ~(UCR4_TCEN);
331 writel(temp, sport->port.membase + UCR4);
332
333 while (readl(sport->port.membase + URXD0) &
334 URXD_CHARRDY)
335 barrier();
336
337 temp = readl(sport->port.membase + UCR1);
338 temp |= UCR1_RRDYEN;
339 writel(temp, sport->port.membase + UCR1);
340
341 temp = readl(sport->port.membase + UCR4);
342 temp |= UCR4_DREN;
343 writel(temp, sport->port.membase + UCR4);
344 }
345 return;
346 }
347
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100348 temp = readl(sport->port.membase + UCR1);
349 writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350}
351
352/*
353 * interrupts disabled on entry
354 */
355static void imx_stop_rx(struct uart_port *port)
356{
357 struct imx_port *sport = (struct imx_port *)port;
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100358 unsigned long temp;
359
360 temp = readl(sport->port.membase + UCR2);
361 writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
364/*
365 * Set the modem control timer to fire immediately.
366 */
367static void imx_enable_ms(struct uart_port *port)
368{
369 struct imx_port *sport = (struct imx_port *)port;
370
371 mod_timer(&sport->timer, jiffies);
372}
373
374static inline void imx_transmit_buffer(struct imx_port *sport)
375{
Alan Coxebd2c8f2009-09-19 13:13:28 -0700376 struct circ_buf *xmit = &sport->port.state->xmit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Volker Ernst4e4e6602010-10-13 11:03:57 +0200378 while (!uart_circ_empty(xmit) &&
Shawn Guofe6b5402011-06-25 02:04:33 +0800379 !(readl(sport->port.membase + uts_reg(sport))
380 & UTS_TXFULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 /* send xmit->buf[xmit->tail]
382 * out the port here */
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100383 writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
Oskar Schirmerd3810cd2009-06-11 14:35:01 +0100384 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 sport->port.icount.tx++;
Sascha Hauer8c0b2542007-02-05 16:10:16 -0800386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Fabian Godehardt977757312009-06-11 14:37:19 +0100388 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
389 uart_write_wakeup(&sport->port);
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 if (uart_circ_empty(xmit))
Russell Kingb129a8c2005-08-31 10:12:14 +0100392 imx_stop_tx(&sport->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393}
394
395/*
396 * interrupts disabled on entry
397 */
Russell Kingb129a8c2005-08-31 10:12:14 +0100398static void imx_start_tx(struct uart_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
400 struct imx_port *sport = (struct imx_port *)port;
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100401 unsigned long temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100403 if (USE_IRDA(sport)) {
404 /* half duplex in IrDA mode; have to disable receive mode */
405 temp = readl(sport->port.membase + UCR4);
406 temp &= ~(UCR4_DREN);
407 writel(temp, sport->port.membase + UCR4);
408
409 temp = readl(sport->port.membase + UCR1);
410 temp &= ~(UCR1_RRDYEN);
411 writel(temp, sport->port.membase + UCR1);
412 }
413
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100414 temp = readl(sport->port.membase + UCR1);
415 writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100417 if (USE_IRDA(sport)) {
418 temp = readl(sport->port.membase + UCR1);
419 temp |= UCR1_TRDYEN;
420 writel(temp, sport->port.membase + UCR1);
421
422 temp = readl(sport->port.membase + UCR4);
423 temp |= UCR4_TCEN;
424 writel(temp, sport->port.membase + UCR4);
425 }
426
Shawn Guofe6b5402011-06-25 02:04:33 +0800427 if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100428 imx_transmit_buffer(sport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429}
430
David Howells7d12e782006-10-05 14:55:46 +0100431static irqreturn_t imx_rtsint(int irq, void *dev_id)
Sascha Hauerceca6292005-10-12 19:58:08 +0100432{
Jeff Garzik15aafa22008-02-06 01:36:20 -0800433 struct imx_port *sport = dev_id;
Uwe Kleine-König5680e942011-04-11 10:59:09 +0200434 unsigned int val;
Sascha Hauerceca6292005-10-12 19:58:08 +0100435 unsigned long flags;
436
437 spin_lock_irqsave(&sport->port.lock, flags);
438
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100439 writel(USR1_RTSD, sport->port.membase + USR1);
Uwe Kleine-König5680e942011-04-11 10:59:09 +0200440 val = readl(sport->port.membase + USR1) & USR1_RTSS;
Sascha Hauerceca6292005-10-12 19:58:08 +0100441 uart_handle_cts_change(&sport->port, !!val);
Alan Coxbdc04e32009-09-19 13:13:31 -0700442 wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
Sascha Hauerceca6292005-10-12 19:58:08 +0100443
444 spin_unlock_irqrestore(&sport->port.lock, flags);
445 return IRQ_HANDLED;
446}
447
David Howells7d12e782006-10-05 14:55:46 +0100448static irqreturn_t imx_txint(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
Jeff Garzik15aafa22008-02-06 01:36:20 -0800450 struct imx_port *sport = dev_id;
Alan Coxebd2c8f2009-09-19 13:13:28 -0700451 struct circ_buf *xmit = &sport->port.state->xmit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 unsigned long flags;
453
454 spin_lock_irqsave(&sport->port.lock,flags);
455 if (sport->port.x_char)
456 {
457 /* Send next char */
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100458 writel(sport->port.x_char, sport->port.membase + URTX0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 goto out;
460 }
461
462 if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
Russell Kingb129a8c2005-08-31 10:12:14 +0100463 imx_stop_tx(&sport->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 goto out;
465 }
466
467 imx_transmit_buffer(sport);
468
469 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
470 uart_write_wakeup(&sport->port);
471
472out:
473 spin_unlock_irqrestore(&sport->port.lock,flags);
474 return IRQ_HANDLED;
475}
476
David Howells7d12e782006-10-05 14:55:46 +0100477static irqreturn_t imx_rxint(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478{
479 struct imx_port *sport = dev_id;
480 unsigned int rx,flg,ignored = 0;
Alan Coxebd2c8f2009-09-19 13:13:28 -0700481 struct tty_struct *tty = sport->port.state->port.tty;
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100482 unsigned long flags, temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 spin_lock_irqsave(&sport->port.lock,flags);
485
Sascha Hauer0d3c3932008-04-17 08:43:14 +0100486 while (readl(sport->port.membase + USR2) & USR2_RDR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 flg = TTY_NORMAL;
488 sport->port.icount.rx++;
489
Sascha Hauer0d3c3932008-04-17 08:43:14 +0100490 rx = readl(sport->port.membase + URXD0);
491
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100492 temp = readl(sport->port.membase + USR2);
Sascha Hauer864eeed2008-04-17 08:39:22 +0100493 if (temp & USR2_BRCD) {
Andy Green94d32f92010-02-01 13:28:54 +0100494 writel(USR2_BRCD, sport->port.membase + USR2);
Sascha Hauer864eeed2008-04-17 08:39:22 +0100495 if (uart_handle_break(&sport->port))
496 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
498
Oskar Schirmerd3810cd2009-06-11 14:35:01 +0100499 if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
Sascha Hauer864eeed2008-04-17 08:39:22 +0100500 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Sascha Hauer864eeed2008-04-17 08:39:22 +0100502 if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
503 if (rx & URXD_PRERR)
504 sport->port.icount.parity++;
505 else if (rx & URXD_FRMERR)
506 sport->port.icount.frame++;
507 if (rx & URXD_OVRRUN)
508 sport->port.icount.overrun++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Sascha Hauer864eeed2008-04-17 08:39:22 +0100510 if (rx & sport->port.ignore_status_mask) {
511 if (++ignored > 100)
512 goto out;
513 continue;
514 }
515
516 rx &= sport->port.read_status_mask;
517
518 if (rx & URXD_PRERR)
519 flg = TTY_PARITY;
520 else if (rx & URXD_FRMERR)
521 flg = TTY_FRAME;
522 if (rx & URXD_OVRRUN)
523 flg = TTY_OVERRUN;
524
525#ifdef SUPPORT_SYSRQ
526 sport->port.sysrq = 0;
527#endif
528 }
529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 tty_insert_flip_char(tty, rx, flg);
Sascha Hauer864eeed2008-04-17 08:39:22 +0100531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533out:
534 spin_unlock_irqrestore(&sport->port.lock,flags);
535 tty_flip_buffer_push(tty);
536 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200539static irqreturn_t imx_int(int irq, void *dev_id)
540{
541 struct imx_port *sport = dev_id;
542 unsigned int sts;
543
544 sts = readl(sport->port.membase + USR1);
545
546 if (sts & USR1_RRDY)
547 imx_rxint(irq, dev_id);
548
549 if (sts & USR1_TRDY &&
550 readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
551 imx_txint(irq, dev_id);
552
Marc Kleine-Budde9fbe6042008-07-28 21:26:01 +0200553 if (sts & USR1_RTSD)
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200554 imx_rtsint(irq, dev_id);
555
556 return IRQ_HANDLED;
557}
558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559/*
560 * Return TIOCSER_TEMT when transmitter is not busy.
561 */
562static unsigned int imx_tx_empty(struct uart_port *port)
563{
564 struct imx_port *sport = (struct imx_port *)port;
565
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100566 return (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567}
568
Sascha Hauer0f302dc2005-08-31 21:48:47 +0100569/*
570 * We have a modem side uart, so the meanings of RTS and CTS are inverted.
571 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572static unsigned int imx_get_mctrl(struct uart_port *port)
573{
Oskar Schirmerd3810cd2009-06-11 14:35:01 +0100574 struct imx_port *sport = (struct imx_port *)port;
575 unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
Sascha Hauer0f302dc2005-08-31 21:48:47 +0100576
Oskar Schirmerd3810cd2009-06-11 14:35:01 +0100577 if (readl(sport->port.membase + USR1) & USR1_RTSS)
578 tmp |= TIOCM_CTS;
Sascha Hauer0f302dc2005-08-31 21:48:47 +0100579
Oskar Schirmerd3810cd2009-06-11 14:35:01 +0100580 if (readl(sport->port.membase + UCR2) & UCR2_CTS)
581 tmp |= TIOCM_RTS;
Sascha Hauer0f302dc2005-08-31 21:48:47 +0100582
Oskar Schirmerd3810cd2009-06-11 14:35:01 +0100583 return tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
586static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
587{
Oskar Schirmerd3810cd2009-06-11 14:35:01 +0100588 struct imx_port *sport = (struct imx_port *)port;
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100589 unsigned long temp;
590
591 temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
Sascha Hauer0f302dc2005-08-31 21:48:47 +0100592
Oskar Schirmerd3810cd2009-06-11 14:35:01 +0100593 if (mctrl & TIOCM_RTS)
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100594 temp |= UCR2_CTS;
595
596 writel(temp, sport->port.membase + UCR2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597}
598
599/*
600 * Interrupts always disabled.
601 */
602static void imx_break_ctl(struct uart_port *port, int break_state)
603{
604 struct imx_port *sport = (struct imx_port *)port;
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100605 unsigned long flags, temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607 spin_lock_irqsave(&sport->port.lock, flags);
608
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100609 temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 if ( break_state != 0 )
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100612 temp |= UCR1_SNDBRK;
613
614 writel(temp, sport->port.membase + UCR1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 spin_unlock_irqrestore(&sport->port.lock, flags);
617}
618
619#define TXTL 2 /* reset default */
620#define RXTL 1 /* reset default */
621
Sascha Hauer587897f2005-04-29 22:46:40 +0100622static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
623{
624 unsigned int val;
625 unsigned int ufcr_rfdiv;
626
627 /* set receiver / transmitter trigger level.
628 * RFDIV is set such way to satisfy requested uartclk value
629 */
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100630 val = TXTL << 10 | RXTL;
Sascha Hauer38a41fd2008-07-05 10:02:46 +0200631 ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2)
632 / sport->port.uartclk;
Sascha Hauer587897f2005-04-29 22:46:40 +0100633
634 if(!ufcr_rfdiv)
635 ufcr_rfdiv = 1;
636
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100637 val |= UFCR_RFDIV_REG(ufcr_rfdiv);
Sascha Hauer587897f2005-04-29 22:46:40 +0100638
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100639 writel(val, sport->port.membase + UFCR);
Sascha Hauer587897f2005-04-29 22:46:40 +0100640
641 return 0;
642}
643
Valentin Longchamp1c5250d2010-05-05 11:47:07 +0200644/* half the RX buffer size */
645#define CTSTL 16
646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647static int imx_startup(struct uart_port *port)
648{
649 struct imx_port *sport = (struct imx_port *)port;
650 int retval;
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100651 unsigned long flags, temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
Sascha Hauer587897f2005-04-29 22:46:40 +0100653 imx_setup_ufcr(sport, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 /* disable the DREN bit (Data Ready interrupt enable) before
656 * requesting IRQs
657 */
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100658 temp = readl(sport->port.membase + UCR4);
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100659
660 if (USE_IRDA(sport))
661 temp |= UCR4_IRSC;
662
Valentin Longchamp1c5250d2010-05-05 11:47:07 +0200663 /* set the trigger level for CTS */
664 temp &= ~(UCR4_CTSTL_MASK<< UCR4_CTSTL_SHF);
665 temp |= CTSTL<< UCR4_CTSTL_SHF;
666
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100667 writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100669 if (USE_IRDA(sport)) {
670 /* reset fifo's and state machines */
671 int i = 100;
672 temp = readl(sport->port.membase + UCR2);
673 temp &= ~UCR2_SRST;
674 writel(temp, sport->port.membase + UCR2);
675 while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
676 (--i > 0)) {
677 udelay(1);
678 }
679 }
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 /*
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200682 * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
683 * chips only have one interrupt.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 */
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200685 if (sport->txirq > 0) {
686 retval = request_irq(sport->rxirq, imx_rxint, 0,
687 DRIVER_NAME, sport);
688 if (retval)
689 goto error_out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200691 retval = request_irq(sport->txirq, imx_txint, 0,
692 DRIVER_NAME, sport);
693 if (retval)
694 goto error_out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100696 /* do not use RTS IRQ on IrDA */
697 if (!USE_IRDA(sport)) {
698 retval = request_irq(sport->rtsirq, imx_rtsint,
699 (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
700 IRQF_TRIGGER_FALLING |
701 IRQF_TRIGGER_RISING,
702 DRIVER_NAME, sport);
703 if (retval)
704 goto error_out3;
705 }
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200706 } else {
707 retval = request_irq(sport->port.irq, imx_int, 0,
708 DRIVER_NAME, sport);
709 if (retval) {
710 free_irq(sport->port.irq, sport);
711 goto error_out1;
712 }
713 }
Sascha Hauerceca6292005-10-12 19:58:08 +0100714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 /*
716 * Finally, clear and enable interrupts
717 */
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100718 writel(USR1_RTSD, sport->port.membase + USR1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100720 temp = readl(sport->port.membase + UCR1);
Sascha Hauer789d5252008-04-17 08:44:47 +0100721 temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100722
723 if (USE_IRDA(sport)) {
724 temp |= UCR1_IREN;
725 temp &= ~(UCR1_RTSDEN);
726 }
727
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100728 writel(temp, sport->port.membase + UCR1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100730 temp = readl(sport->port.membase + UCR2);
731 temp |= (UCR2_RXEN | UCR2_TXEN);
732 writel(temp, sport->port.membase + UCR2);
733
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100734 if (USE_IRDA(sport)) {
735 /* clear RX-FIFO */
736 int i = 64;
737 while ((--i > 0) &&
738 (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
739 barrier();
740 }
741 }
742
Shawn Guofe6b5402011-06-25 02:04:33 +0800743 if (is_imx21_uart(sport)) {
Sascha Hauer37d6fb62009-05-27 18:23:48 +0200744 temp = readl(sport->port.membase + UCR3);
Shawn Guofe6b5402011-06-25 02:04:33 +0800745 temp |= IMX21_UCR3_RXDMUXSEL;
Sascha Hauer37d6fb62009-05-27 18:23:48 +0200746 writel(temp, sport->port.membase + UCR3);
747 }
Marc Kleine-Budde44118052008-07-28 12:10:34 +0200748
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100749 if (USE_IRDA(sport)) {
750 temp = readl(sport->port.membase + UCR4);
751 if (sport->irda_inv_rx)
752 temp |= UCR4_INVR;
753 else
754 temp &= ~(UCR4_INVR);
755 writel(temp | UCR4_DREN, sport->port.membase + UCR4);
756
757 temp = readl(sport->port.membase + UCR3);
758 if (sport->irda_inv_tx)
759 temp |= UCR3_INVT;
760 else
761 temp &= ~(UCR3_INVT);
762 writel(temp, sport->port.membase + UCR3);
763 }
764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 /*
766 * Enable modem status interrupts
767 */
768 spin_lock_irqsave(&sport->port.lock,flags);
769 imx_enable_ms(&sport->port);
770 spin_unlock_irqrestore(&sport->port.lock,flags);
771
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100772 if (USE_IRDA(sport)) {
773 struct imxuart_platform_data *pdata;
774 pdata = sport->port.dev->platform_data;
775 sport->irda_inv_rx = pdata->irda_inv_rx;
776 sport->irda_inv_tx = pdata->irda_inv_tx;
777 sport->trcv_delay = pdata->transceiver_delay;
778 if (pdata->irda_enable)
779 pdata->irda_enable(1);
780 }
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return 0;
783
Sascha Hauerceca6292005-10-12 19:58:08 +0100784error_out3:
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200785 if (sport->txirq)
786 free_irq(sport->txirq, sport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787error_out2:
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200788 if (sport->rxirq)
789 free_irq(sport->rxirq, sport);
Sascha Hauer86371d02005-10-10 10:17:42 +0100790error_out1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 return retval;
792}
793
794static void imx_shutdown(struct uart_port *port)
795{
796 struct imx_port *sport = (struct imx_port *)port;
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100797 unsigned long temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Fabian Godehardt2e146392009-06-11 14:38:38 +0100799 temp = readl(sport->port.membase + UCR2);
800 temp &= ~(UCR2_TXEN);
801 writel(temp, sport->port.membase + UCR2);
802
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100803 if (USE_IRDA(sport)) {
804 struct imxuart_platform_data *pdata;
805 pdata = sport->port.dev->platform_data;
806 if (pdata->irda_enable)
807 pdata->irda_enable(0);
808 }
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 /*
811 * Stop our timer.
812 */
813 del_timer_sync(&sport->timer);
814
815 /*
816 * Free the interrupts
817 */
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200818 if (sport->txirq > 0) {
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100819 if (!USE_IRDA(sport))
820 free_irq(sport->rtsirq, sport);
Sascha Hauere3d13ff2008-07-05 10:02:48 +0200821 free_irq(sport->txirq, sport);
822 free_irq(sport->rxirq, sport);
823 } else
824 free_irq(sport->port.irq, sport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826 /*
827 * Disable all interrupts, port and break condition.
828 */
829
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100830 temp = readl(sport->port.membase + UCR1);
831 temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100832 if (USE_IRDA(sport))
833 temp &= ~(UCR1_IREN);
834
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100835 writel(temp, sport->port.membase + UCR1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836}
837
838static void
Alan Cox606d0992006-12-08 02:38:45 -0800839imx_set_termios(struct uart_port *port, struct ktermios *termios,
840 struct ktermios *old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
842 struct imx_port *sport = (struct imx_port *)port;
843 unsigned long flags;
844 unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
845 unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
Oskar Schirmer534fca02009-06-11 14:52:23 +0100846 unsigned int div, ufcr;
847 unsigned long num, denom;
Oskar Schirmerd7f8d432009-06-11 14:55:22 +0100848 uint64_t tdiv64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
850 /*
851 * If we don't support modem control lines, don't allow
852 * these to be set.
853 */
854 if (0) {
855 termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
856 termios->c_cflag |= CLOCAL;
857 }
858
859 /*
860 * We only support CS7 and CS8.
861 */
862 while ((termios->c_cflag & CSIZE) != CS7 &&
863 (termios->c_cflag & CSIZE) != CS8) {
864 termios->c_cflag &= ~CSIZE;
865 termios->c_cflag |= old_csize;
866 old_csize = CS8;
867 }
868
869 if ((termios->c_cflag & CSIZE) == CS8)
870 ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
871 else
872 ucr2 = UCR2_SRST | UCR2_IRTS;
873
874 if (termios->c_cflag & CRTSCTS) {
Sascha Hauer5b802342006-05-04 14:07:42 +0100875 if( sport->have_rtscts ) {
876 ucr2 &= ~UCR2_IRTS;
877 ucr2 |= UCR2_CTSC;
878 } else {
879 termios->c_cflag &= ~CRTSCTS;
880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
882
883 if (termios->c_cflag & CSTOPB)
884 ucr2 |= UCR2_STPB;
885 if (termios->c_cflag & PARENB) {
886 ucr2 |= UCR2_PREN;
Matt Reimer3261e362006-01-13 20:51:44 +0000887 if (termios->c_cflag & PARODD)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 ucr2 |= UCR2_PROE;
889 }
890
891 /*
892 * Ask the core to calculate the divisor for us.
893 */
Sascha Hauer036bb152008-07-05 10:02:44 +0200894 baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 quot = uart_get_divisor(port, baud);
896
897 spin_lock_irqsave(&sport->port.lock, flags);
898
899 sport->port.read_status_mask = 0;
900 if (termios->c_iflag & INPCK)
901 sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
902 if (termios->c_iflag & (BRKINT | PARMRK))
903 sport->port.read_status_mask |= URXD_BRK;
904
905 /*
906 * Characters to ignore
907 */
908 sport->port.ignore_status_mask = 0;
909 if (termios->c_iflag & IGNPAR)
910 sport->port.ignore_status_mask |= URXD_PRERR;
911 if (termios->c_iflag & IGNBRK) {
912 sport->port.ignore_status_mask |= URXD_BRK;
913 /*
914 * If we're ignoring parity and break indicators,
915 * ignore overruns too (for real raw support).
916 */
917 if (termios->c_iflag & IGNPAR)
918 sport->port.ignore_status_mask |= URXD_OVRRUN;
919 }
920
921 del_timer_sync(&sport->timer);
922
923 /*
924 * Update the per-port timeout.
925 */
926 uart_update_timeout(port, termios->c_cflag, baud);
927
928 /*
929 * disable interrupts and drain transmitter
930 */
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100931 old_ucr1 = readl(sport->port.membase + UCR1);
932 writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
933 sport->port.membase + UCR1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100935 while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 barrier();
937
938 /* then, disable everything */
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100939 old_txrxen = readl(sport->port.membase + UCR2);
940 writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),
941 sport->port.membase + UCR2);
942 old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100944 if (USE_IRDA(sport)) {
945 /*
946 * use maximum available submodule frequency to
947 * avoid missing short pulses due to low sampling rate
948 */
Sascha Hauer036bb152008-07-05 10:02:44 +0200949 div = 1;
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100950 } else {
951 div = sport->port.uartclk / (baud * 16);
952 if (div > 7)
953 div = 7;
954 if (!div)
955 div = 1;
956 }
Sascha Hauer036bb152008-07-05 10:02:44 +0200957
Oskar Schirmer534fca02009-06-11 14:52:23 +0100958 rational_best_approximation(16 * div * baud, sport->port.uartclk,
959 1 << 16, 1 << 16, &num, &denom);
Sascha Hauer036bb152008-07-05 10:02:44 +0200960
Alan Coxeab4f5a2010-06-01 22:52:52 +0200961 tdiv64 = sport->port.uartclk;
962 tdiv64 *= num;
963 do_div(tdiv64, denom * 16 * div);
964 tty_termios_encode_baud_rate(termios,
Sascha Hauer1a2c4b32009-06-16 17:02:15 +0100965 (speed_t)tdiv64, (speed_t)tdiv64);
Oskar Schirmerd7f8d432009-06-11 14:55:22 +0100966
Oskar Schirmer534fca02009-06-11 14:52:23 +0100967 num -= 1;
968 denom -= 1;
Sascha Hauer036bb152008-07-05 10:02:44 +0200969
970 ufcr = readl(sport->port.membase + UFCR);
Fabian Godehardtb6e49132009-06-11 14:53:18 +0100971 ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
Sascha Hauer036bb152008-07-05 10:02:44 +0200972 writel(ufcr, sport->port.membase + UFCR);
973
Oskar Schirmer534fca02009-06-11 14:52:23 +0100974 writel(num, sport->port.membase + UBIR);
975 writel(denom, sport->port.membase + UBMR);
976
Shawn Guofe6b5402011-06-25 02:04:33 +0800977 if (is_imx21_uart(sport))
Sascha Hauer37d6fb62009-05-27 18:23:48 +0200978 writel(sport->port.uartclk / div / 1000,
Shawn Guofe6b5402011-06-25 02:04:33 +0800979 sport->port.membase + IMX21_ONEMS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Sascha Hauerff4bfb22007-04-26 08:26:13 +0100981 writel(old_ucr1, sport->port.membase + UCR1);
982
983 /* set the parity, stop bits and data size */
984 writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
987 imx_enable_ms(&sport->port);
988
989 spin_unlock_irqrestore(&sport->port.lock, flags);
990}
991
992static const char *imx_type(struct uart_port *port)
993{
994 struct imx_port *sport = (struct imx_port *)port;
995
996 return sport->port.type == PORT_IMX ? "IMX" : NULL;
997}
998
999/*
1000 * Release the memory region(s) being used by 'port'.
1001 */
1002static void imx_release_port(struct uart_port *port)
1003{
Sascha Hauer3d454442008-04-17 08:47:32 +01001004 struct platform_device *pdev = to_platform_device(port->dev);
1005 struct resource *mmres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Sascha Hauer3d454442008-04-17 08:47:32 +01001007 mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Joe Perches28f65c12011-06-09 09:13:32 -07001008 release_mem_region(mmres->start, resource_size(mmres));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009}
1010
1011/*
1012 * Request the memory region(s) being used by 'port'.
1013 */
1014static int imx_request_port(struct uart_port *port)
1015{
Sascha Hauer3d454442008-04-17 08:47:32 +01001016 struct platform_device *pdev = to_platform_device(port->dev);
1017 struct resource *mmres;
1018 void *ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Sascha Hauer3d454442008-04-17 08:47:32 +01001020 mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1021 if (!mmres)
1022 return -ENODEV;
1023
Joe Perches28f65c12011-06-09 09:13:32 -07001024 ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart");
Sascha Hauer3d454442008-04-17 08:47:32 +01001025
1026 return ret ? 0 : -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027}
1028
1029/*
1030 * Configure/autoconfigure the port.
1031 */
1032static void imx_config_port(struct uart_port *port, int flags)
1033{
1034 struct imx_port *sport = (struct imx_port *)port;
1035
1036 if (flags & UART_CONFIG_TYPE &&
1037 imx_request_port(&sport->port) == 0)
1038 sport->port.type = PORT_IMX;
1039}
1040
1041/*
1042 * Verify the new serial_struct (for TIOCSSERIAL).
1043 * The only change we allow are to the flags and type, and
1044 * even then only between PORT_IMX and PORT_UNKNOWN
1045 */
1046static int
1047imx_verify_port(struct uart_port *port, struct serial_struct *ser)
1048{
1049 struct imx_port *sport = (struct imx_port *)port;
1050 int ret = 0;
1051
1052 if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX)
1053 ret = -EINVAL;
1054 if (sport->port.irq != ser->irq)
1055 ret = -EINVAL;
1056 if (ser->io_type != UPIO_MEM)
1057 ret = -EINVAL;
1058 if (sport->port.uartclk / 16 != ser->baud_base)
1059 ret = -EINVAL;
1060 if ((void *)sport->port.mapbase != ser->iomem_base)
1061 ret = -EINVAL;
1062 if (sport->port.iobase != ser->port)
1063 ret = -EINVAL;
1064 if (ser->hub6 != 0)
1065 ret = -EINVAL;
1066 return ret;
1067}
1068
1069static struct uart_ops imx_pops = {
1070 .tx_empty = imx_tx_empty,
1071 .set_mctrl = imx_set_mctrl,
1072 .get_mctrl = imx_get_mctrl,
1073 .stop_tx = imx_stop_tx,
1074 .start_tx = imx_start_tx,
1075 .stop_rx = imx_stop_rx,
1076 .enable_ms = imx_enable_ms,
1077 .break_ctl = imx_break_ctl,
1078 .startup = imx_startup,
1079 .shutdown = imx_shutdown,
1080 .set_termios = imx_set_termios,
1081 .type = imx_type,
1082 .release_port = imx_release_port,
1083 .request_port = imx_request_port,
1084 .config_port = imx_config_port,
1085 .verify_port = imx_verify_port,
1086};
1087
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001088static struct imx_port *imx_ports[UART_NR];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090#ifdef CONFIG_SERIAL_IMX_CONSOLE
Russell Kingd3587882006-03-20 20:00:09 +00001091static void imx_console_putchar(struct uart_port *port, int ch)
1092{
1093 struct imx_port *sport = (struct imx_port *)port;
Sascha Hauerff4bfb22007-04-26 08:26:13 +01001094
Shawn Guofe6b5402011-06-25 02:04:33 +08001095 while (readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)
Russell Kingd3587882006-03-20 20:00:09 +00001096 barrier();
Sascha Hauerff4bfb22007-04-26 08:26:13 +01001097
1098 writel(ch, sport->port.membase + URTX0);
Russell Kingd3587882006-03-20 20:00:09 +00001099}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101/*
1102 * Interrupts are disabled on entering
1103 */
1104static void
1105imx_console_write(struct console *co, const char *s, unsigned int count)
1106{
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001107 struct imx_port *sport = imx_ports[co->index];
Sascha Hauer37d6fb62009-05-27 18:23:48 +02001108 unsigned int old_ucr1, old_ucr2, ucr1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
1110 /*
1111 * First, save UCR1/2 and then disable interrupts
1112 */
Sascha Hauer37d6fb62009-05-27 18:23:48 +02001113 ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
Sascha Hauerff4bfb22007-04-26 08:26:13 +01001114 old_ucr2 = readl(sport->port.membase + UCR2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
Shawn Guofe6b5402011-06-25 02:04:33 +08001116 if (is_imx1_uart(sport))
1117 ucr1 |= IMX1_UCR1_UARTCLKEN;
Sascha Hauer37d6fb62009-05-27 18:23:48 +02001118 ucr1 |= UCR1_UARTEN;
1119 ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
1120
1121 writel(ucr1, sport->port.membase + UCR1);
Sascha Hauerff4bfb22007-04-26 08:26:13 +01001122
1123 writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Russell Kingd3587882006-03-20 20:00:09 +00001125 uart_console_write(&sport->port, s, count, imx_console_putchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
1127 /*
1128 * Finally, wait for transmitter to become empty
1129 * and restore UCR1/2
1130 */
Sascha Hauerff4bfb22007-04-26 08:26:13 +01001131 while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Sascha Hauerff4bfb22007-04-26 08:26:13 +01001133 writel(old_ucr1, sport->port.membase + UCR1);
1134 writel(old_ucr2, sport->port.membase + UCR2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135}
1136
1137/*
1138 * If the port was already initialised (eg, by a boot loader),
1139 * try to determine the current setup.
1140 */
1141static void __init
1142imx_console_get_options(struct imx_port *sport, int *baud,
1143 int *parity, int *bits)
1144{
Sascha Hauer587897f2005-04-29 22:46:40 +01001145
Roel Kluin2e2eb502009-12-09 12:31:36 -08001146 if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 /* ok, the port was enabled */
1148 unsigned int ucr2, ubir,ubmr, uartclk;
Sascha Hauer587897f2005-04-29 22:46:40 +01001149 unsigned int baud_raw;
1150 unsigned int ucfr_rfdiv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Sascha Hauerff4bfb22007-04-26 08:26:13 +01001152 ucr2 = readl(sport->port.membase + UCR2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
1154 *parity = 'n';
1155 if (ucr2 & UCR2_PREN) {
1156 if (ucr2 & UCR2_PROE)
1157 *parity = 'o';
1158 else
1159 *parity = 'e';
1160 }
1161
1162 if (ucr2 & UCR2_WS)
1163 *bits = 8;
1164 else
1165 *bits = 7;
1166
Sascha Hauerff4bfb22007-04-26 08:26:13 +01001167 ubir = readl(sport->port.membase + UBIR) & 0xffff;
1168 ubmr = readl(sport->port.membase + UBMR) & 0xffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Sascha Hauerff4bfb22007-04-26 08:26:13 +01001170 ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;
Sascha Hauer587897f2005-04-29 22:46:40 +01001171 if (ucfr_rfdiv == 6)
1172 ucfr_rfdiv = 7;
1173 else
1174 ucfr_rfdiv = 6 - ucfr_rfdiv;
1175
Sascha Hauer38a41fd2008-07-05 10:02:46 +02001176 uartclk = clk_get_rate(sport->clk);
Sascha Hauer587897f2005-04-29 22:46:40 +01001177 uartclk /= ucfr_rfdiv;
1178
1179 { /*
1180 * The next code provides exact computation of
1181 * baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))
1182 * without need of float support or long long division,
1183 * which would be required to prevent 32bit arithmetic overflow
1184 */
1185 unsigned int mul = ubir + 1;
1186 unsigned int div = 16 * (ubmr + 1);
1187 unsigned int rem = uartclk % div;
1188
1189 baud_raw = (uartclk / div) * mul;
1190 baud_raw += (rem * mul + div / 2) / div;
1191 *baud = (baud_raw + 50) / 100 * 100;
1192 }
1193
1194 if(*baud != baud_raw)
1195 printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
1196 baud_raw, *baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 }
1198}
1199
1200static int __init
1201imx_console_setup(struct console *co, char *options)
1202{
1203 struct imx_port *sport;
1204 int baud = 9600;
1205 int bits = 8;
1206 int parity = 'n';
1207 int flow = 'n';
1208
1209 /*
1210 * Check whether an invalid uart number has been specified, and
1211 * if so, search for the first available port that does have
1212 * console support.
1213 */
1214 if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
1215 co->index = 0;
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001216 sport = imx_ports[co->index];
Eric Lammertse76afc42009-05-19 20:53:20 -04001217 if(sport == NULL)
1218 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
1220 if (options)
1221 uart_parse_options(options, &baud, &parity, &bits, &flow);
1222 else
1223 imx_console_get_options(sport, &baud, &parity, &bits);
1224
Sascha Hauer587897f2005-04-29 22:46:40 +01001225 imx_setup_ufcr(sport, 0);
1226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 return uart_set_options(&sport->port, co, baud, parity, bits, flow);
1228}
1229
Vincent Sanders9f4426d2005-10-01 22:56:34 +01001230static struct uart_driver imx_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231static struct console imx_console = {
Sascha Hauere3d13ff2008-07-05 10:02:48 +02001232 .name = DEV_NAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 .write = imx_console_write,
1234 .device = uart_console_device,
1235 .setup = imx_console_setup,
1236 .flags = CON_PRINTBUFFER,
1237 .index = -1,
1238 .data = &imx_reg,
1239};
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241#define IMX_CONSOLE &imx_console
1242#else
1243#define IMX_CONSOLE NULL
1244#endif
1245
1246static struct uart_driver imx_reg = {
1247 .owner = THIS_MODULE,
1248 .driver_name = DRIVER_NAME,
Sascha Hauere3d13ff2008-07-05 10:02:48 +02001249 .dev_name = DEV_NAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 .major = SERIAL_IMX_MAJOR,
1251 .minor = MINOR_START,
1252 .nr = ARRAY_SIZE(imx_ports),
1253 .cons = IMX_CONSOLE,
1254};
1255
Russell King3ae5eae2005-11-09 22:32:44 +00001256static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
Oskar Schirmerd3810cd2009-06-11 14:35:01 +01001258 struct imx_port *sport = platform_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
Oskar Schirmerd3810cd2009-06-11 14:35:01 +01001260 if (sport)
1261 uart_suspend_port(&imx_reg, &sport->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
Oskar Schirmerd3810cd2009-06-11 14:35:01 +01001263 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264}
1265
Russell King3ae5eae2005-11-09 22:32:44 +00001266static int serial_imx_resume(struct platform_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267{
Oskar Schirmerd3810cd2009-06-11 14:35:01 +01001268 struct imx_port *sport = platform_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
Oskar Schirmerd3810cd2009-06-11 14:35:01 +01001270 if (sport)
1271 uart_resume_port(&imx_reg, &sport->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Oskar Schirmerd3810cd2009-06-11 14:35:01 +01001273 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274}
1275
Sascha Hauer2582d8c2008-07-05 10:02:45 +02001276static int serial_imx_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277{
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001278 struct imx_port *sport;
Sascha Hauer5b802342006-05-04 14:07:42 +01001279 struct imxuart_platform_data *pdata;
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001280 void __iomem *base;
1281 int ret = 0;
1282 struct resource *res;
Sascha Hauer5b802342006-05-04 14:07:42 +01001283
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001284 sport = kzalloc(sizeof(*sport), GFP_KERNEL);
1285 if (!sport)
1286 return -ENOMEM;
1287
1288 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1289 if (!res) {
1290 ret = -ENODEV;
1291 goto free;
1292 }
1293
1294 base = ioremap(res->start, PAGE_SIZE);
1295 if (!base) {
1296 ret = -ENOMEM;
1297 goto free;
1298 }
1299
1300 sport->port.dev = &pdev->dev;
1301 sport->port.mapbase = res->start;
1302 sport->port.membase = base;
1303 sport->port.type = PORT_IMX,
1304 sport->port.iotype = UPIO_MEM;
1305 sport->port.irq = platform_get_irq(pdev, 0);
1306 sport->rxirq = platform_get_irq(pdev, 0);
1307 sport->txirq = platform_get_irq(pdev, 1);
1308 sport->rtsirq = platform_get_irq(pdev, 2);
1309 sport->port.fifosize = 32;
1310 sport->port.ops = &imx_pops;
1311 sport->port.flags = UPF_BOOT_AUTOCONF;
1312 sport->port.line = pdev->id;
1313 init_timer(&sport->timer);
1314 sport->timer.function = imx_timeout;
1315 sport->timer.data = (unsigned long)sport;
Shawn Guofe6b5402011-06-25 02:04:33 +08001316 sport->devdata = (struct imx_uart_data *) pdev->id_entry->driver_data;
Sascha Hauer38a41fd2008-07-05 10:02:46 +02001317
Sascha Hauere65fb002009-02-16 14:29:10 +01001318 sport->clk = clk_get(&pdev->dev, "uart");
Sascha Hauer38a41fd2008-07-05 10:02:46 +02001319 if (IS_ERR(sport->clk)) {
1320 ret = PTR_ERR(sport->clk);
1321 goto unmap;
1322 }
1323 clk_enable(sport->clk);
1324
1325 sport->port.uartclk = clk_get_rate(sport->clk);
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001326
1327 imx_ports[pdev->id] = sport;
Sascha Hauer5b802342006-05-04 14:07:42 +01001328
Sascha Hauer2582d8c2008-07-05 10:02:45 +02001329 pdata = pdev->dev.platform_data;
Oskar Schirmerd3810cd2009-06-11 14:35:01 +01001330 if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001331 sport->have_rtscts = 1;
Sascha Hauer5b802342006-05-04 14:07:42 +01001332
Fabian Godehardtb6e49132009-06-11 14:53:18 +01001333#ifdef CONFIG_IRDA
1334 if (pdata && (pdata->flags & IMXUART_IRDA))
1335 sport->use_irda = 1;
1336#endif
1337
Baruch Siachbbcd18d2009-12-21 16:26:46 -08001338 if (pdata && pdata->init) {
Darius Augulisc45e7d72008-09-02 10:19:29 +02001339 ret = pdata->init(pdev);
1340 if (ret)
1341 goto clkput;
1342 }
Sascha Hauer2582d8c2008-07-05 10:02:45 +02001343
Daniel Glöckner9f322ad2009-06-11 14:39:21 +01001344 ret = uart_add_one_port(&imx_reg, &sport->port);
1345 if (ret)
1346 goto deinit;
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001347 platform_set_drvdata(pdev, &sport->port);
Sascha Hauer2582d8c2008-07-05 10:02:45 +02001348
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 return 0;
Daniel Glöckner9f322ad2009-06-11 14:39:21 +01001350deinit:
Baruch Siachbbcd18d2009-12-21 16:26:46 -08001351 if (pdata && pdata->exit)
Daniel Glöckner9f322ad2009-06-11 14:39:21 +01001352 pdata->exit(pdev);
Darius Augulisc45e7d72008-09-02 10:19:29 +02001353clkput:
1354 clk_put(sport->clk);
1355 clk_disable(sport->clk);
Sascha Hauer38a41fd2008-07-05 10:02:46 +02001356unmap:
1357 iounmap(sport->port.membase);
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001358free:
1359 kfree(sport);
1360
1361 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362}
1363
Sascha Hauer2582d8c2008-07-05 10:02:45 +02001364static int serial_imx_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365{
Sascha Hauer2582d8c2008-07-05 10:02:45 +02001366 struct imxuart_platform_data *pdata;
1367 struct imx_port *sport = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
Sascha Hauer2582d8c2008-07-05 10:02:45 +02001369 pdata = pdev->dev.platform_data;
1370
1371 platform_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Sascha Hauer38a41fd2008-07-05 10:02:46 +02001373 if (sport) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 uart_remove_one_port(&imx_reg, &sport->port);
Sascha Hauer38a41fd2008-07-05 10:02:46 +02001375 clk_put(sport->clk);
1376 }
1377
1378 clk_disable(sport->clk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Baruch Siachbbcd18d2009-12-21 16:26:46 -08001380 if (pdata && pdata->exit)
Sascha Hauer2582d8c2008-07-05 10:02:45 +02001381 pdata->exit(pdev);
1382
Sascha Hauerdbff4e92008-07-05 10:02:45 +02001383 iounmap(sport->port.membase);
1384 kfree(sport);
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 return 0;
1387}
1388
Russell King3ae5eae2005-11-09 22:32:44 +00001389static struct platform_driver serial_imx_driver = {
Oskar Schirmerd3810cd2009-06-11 14:35:01 +01001390 .probe = serial_imx_probe,
1391 .remove = serial_imx_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
1393 .suspend = serial_imx_suspend,
1394 .resume = serial_imx_resume,
Shawn Guofe6b5402011-06-25 02:04:33 +08001395 .id_table = imx_uart_devtype,
Russell King3ae5eae2005-11-09 22:32:44 +00001396 .driver = {
Oskar Schirmerd3810cd2009-06-11 14:35:01 +01001397 .name = "imx-uart",
Kay Sieverse169c132008-04-15 14:34:35 -07001398 .owner = THIS_MODULE,
Russell King3ae5eae2005-11-09 22:32:44 +00001399 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400};
1401
1402static int __init imx_serial_init(void)
1403{
1404 int ret;
1405
1406 printk(KERN_INFO "Serial: IMX driver\n");
1407
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 ret = uart_register_driver(&imx_reg);
1409 if (ret)
1410 return ret;
1411
Russell King3ae5eae2005-11-09 22:32:44 +00001412 ret = platform_driver_register(&serial_imx_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 if (ret != 0)
1414 uart_unregister_driver(&imx_reg);
1415
1416 return 0;
1417}
1418
1419static void __exit imx_serial_exit(void)
1420{
Russell Kingc889b892005-11-21 17:05:21 +00001421 platform_driver_unregister(&serial_imx_driver);
Sascha Hauer4b300c32007-07-17 13:35:46 +01001422 uart_unregister_driver(&imx_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423}
1424
1425module_init(imx_serial_init);
1426module_exit(imx_serial_exit);
1427
1428MODULE_AUTHOR("Sascha Hauer");
1429MODULE_DESCRIPTION("IMX generic serial port driver");
1430MODULE_LICENSE("GPL");
Kay Sieverse169c132008-04-15 14:34:35 -07001431MODULE_ALIAS("platform:imx-uart");