Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6 and git://git.infradea...
[pandora-kernel.git] / drivers / tty / serial / samsung.c
1 /*
2  * Driver core for Samsung SoC onboard UARTs.
3  *
4  * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
5  *      http://armlinux.simtec.co.uk/
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10 */
11
12 /* Hote on 2410 error handling
13  *
14  * The s3c2410 manual has a love/hate affair with the contents of the
15  * UERSTAT register in the UART blocks, and keeps marking some of the
16  * error bits as reserved. Having checked with the s3c2410x01,
17  * it copes with BREAKs properly, so I am happy to ignore the RESERVED
18  * feature from the latter versions of the manual.
19  *
20  * If it becomes aparrent that latter versions of the 2410 remove these
21  * bits, then action will have to be taken to differentiate the versions
22  * and change the policy on BREAK
23  *
24  * BJD, 04-Nov-2004
25 */
26
27 #if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
28 #define SUPPORT_SYSRQ
29 #endif
30
31 #include <linux/module.h>
32 #include <linux/ioport.h>
33 #include <linux/io.h>
34 #include <linux/platform_device.h>
35 #include <linux/init.h>
36 #include <linux/sysrq.h>
37 #include <linux/console.h>
38 #include <linux/tty.h>
39 #include <linux/tty_flip.h>
40 #include <linux/serial_core.h>
41 #include <linux/serial.h>
42 #include <linux/delay.h>
43 #include <linux/clk.h>
44 #include <linux/cpufreq.h>
45
46 #include <asm/irq.h>
47
48 #include <mach/hardware.h>
49 #include <mach/map.h>
50
51 #include <plat/regs-serial.h>
52
53 #include "samsung.h"
54
55 /* UART name and device definitions */
56
57 #define S3C24XX_SERIAL_NAME     "ttySAC"
58 #define S3C24XX_SERIAL_MAJOR    204
59 #define S3C24XX_SERIAL_MINOR    64
60
61 /* macros to change one thing to another */
62
63 #define tx_enabled(port) ((port)->unused[0])
64 #define rx_enabled(port) ((port)->unused[1])
65
66 /* flag to ignore all characters coming in */
67 #define RXSTAT_DUMMY_READ (0x10000000)
68
69 static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
70 {
71         return container_of(port, struct s3c24xx_uart_port, port);
72 }
73
74 /* translate a port to the device name */
75
76 static inline const char *s3c24xx_serial_portname(struct uart_port *port)
77 {
78         return to_platform_device(port->dev)->name;
79 }
80
81 static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
82 {
83         return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
84 }
85
86 static void s3c24xx_serial_rx_enable(struct uart_port *port)
87 {
88         unsigned long flags;
89         unsigned int ucon, ufcon;
90         int count = 10000;
91
92         spin_lock_irqsave(&port->lock, flags);
93
94         while (--count && !s3c24xx_serial_txempty_nofifo(port))
95                 udelay(100);
96
97         ufcon = rd_regl(port, S3C2410_UFCON);
98         ufcon |= S3C2410_UFCON_RESETRX;
99         wr_regl(port, S3C2410_UFCON, ufcon);
100
101         ucon = rd_regl(port, S3C2410_UCON);
102         ucon |= S3C2410_UCON_RXIRQMODE;
103         wr_regl(port, S3C2410_UCON, ucon);
104
105         rx_enabled(port) = 1;
106         spin_unlock_irqrestore(&port->lock, flags);
107 }
108
109 static void s3c24xx_serial_rx_disable(struct uart_port *port)
110 {
111         unsigned long flags;
112         unsigned int ucon;
113
114         spin_lock_irqsave(&port->lock, flags);
115
116         ucon = rd_regl(port, S3C2410_UCON);
117         ucon &= ~S3C2410_UCON_RXIRQMODE;
118         wr_regl(port, S3C2410_UCON, ucon);
119
120         rx_enabled(port) = 0;
121         spin_unlock_irqrestore(&port->lock, flags);
122 }
123
124 static void s3c24xx_serial_stop_tx(struct uart_port *port)
125 {
126         struct s3c24xx_uart_port *ourport = to_ourport(port);
127
128         if (tx_enabled(port)) {
129                 disable_irq_nosync(ourport->tx_irq);
130                 tx_enabled(port) = 0;
131                 if (port->flags & UPF_CONS_FLOW)
132                         s3c24xx_serial_rx_enable(port);
133         }
134 }
135
136 static void s3c24xx_serial_start_tx(struct uart_port *port)
137 {
138         struct s3c24xx_uart_port *ourport = to_ourport(port);
139
140         if (!tx_enabled(port)) {
141                 if (port->flags & UPF_CONS_FLOW)
142                         s3c24xx_serial_rx_disable(port);
143
144                 enable_irq(ourport->tx_irq);
145                 tx_enabled(port) = 1;
146         }
147 }
148
149
150 static void s3c24xx_serial_stop_rx(struct uart_port *port)
151 {
152         struct s3c24xx_uart_port *ourport = to_ourport(port);
153
154         if (rx_enabled(port)) {
155                 dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
156                 disable_irq_nosync(ourport->rx_irq);
157                 rx_enabled(port) = 0;
158         }
159 }
160
161 static void s3c24xx_serial_enable_ms(struct uart_port *port)
162 {
163 }
164
165 static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
166 {
167         return to_ourport(port)->info;
168 }
169
170 static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
171 {
172         if (port->dev == NULL)
173                 return NULL;
174
175         return (struct s3c2410_uartcfg *)port->dev->platform_data;
176 }
177
178 static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
179                                      unsigned long ufstat)
180 {
181         struct s3c24xx_uart_info *info = ourport->info;
182
183         if (ufstat & info->rx_fifofull)
184                 return info->fifosize;
185
186         return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
187 }
188
189
190 /* ? - where has parity gone?? */
191 #define S3C2410_UERSTAT_PARITY (0x1000)
192
193 static irqreturn_t
194 s3c24xx_serial_rx_chars(int irq, void *dev_id)
195 {
196         struct s3c24xx_uart_port *ourport = dev_id;
197         struct uart_port *port = &ourport->port;
198         struct tty_struct *tty = port->state->port.tty;
199         unsigned int ufcon, ch, flag, ufstat, uerstat;
200         int max_count = 64;
201
202         while (max_count-- > 0) {
203                 ufcon = rd_regl(port, S3C2410_UFCON);
204                 ufstat = rd_regl(port, S3C2410_UFSTAT);
205
206                 if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
207                         break;
208
209                 uerstat = rd_regl(port, S3C2410_UERSTAT);
210                 ch = rd_regb(port, S3C2410_URXH);
211
212                 if (port->flags & UPF_CONS_FLOW) {
213                         int txe = s3c24xx_serial_txempty_nofifo(port);
214
215                         if (rx_enabled(port)) {
216                                 if (!txe) {
217                                         rx_enabled(port) = 0;
218                                         continue;
219                                 }
220                         } else {
221                                 if (txe) {
222                                         ufcon |= S3C2410_UFCON_RESETRX;
223                                         wr_regl(port, S3C2410_UFCON, ufcon);
224                                         rx_enabled(port) = 1;
225                                         goto out;
226                                 }
227                                 continue;
228                         }
229                 }
230
231                 /* insert the character into the buffer */
232
233                 flag = TTY_NORMAL;
234                 port->icount.rx++;
235
236                 if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
237                         dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
238                             ch, uerstat);
239
240                         /* check for break */
241                         if (uerstat & S3C2410_UERSTAT_BREAK) {
242                                 dbg("break!\n");
243                                 port->icount.brk++;
244                                 if (uart_handle_break(port))
245                                     goto ignore_char;
246                         }
247
248                         if (uerstat & S3C2410_UERSTAT_FRAME)
249                                 port->icount.frame++;
250                         if (uerstat & S3C2410_UERSTAT_OVERRUN)
251                                 port->icount.overrun++;
252
253                         uerstat &= port->read_status_mask;
254
255                         if (uerstat & S3C2410_UERSTAT_BREAK)
256                                 flag = TTY_BREAK;
257                         else if (uerstat & S3C2410_UERSTAT_PARITY)
258                                 flag = TTY_PARITY;
259                         else if (uerstat & (S3C2410_UERSTAT_FRAME |
260                                             S3C2410_UERSTAT_OVERRUN))
261                                 flag = TTY_FRAME;
262                 }
263
264                 if (uart_handle_sysrq_char(port, ch))
265                         goto ignore_char;
266
267                 uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
268                                  ch, flag);
269
270  ignore_char:
271                 continue;
272         }
273         tty_flip_buffer_push(tty);
274
275  out:
276         return IRQ_HANDLED;
277 }
278
279 static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
280 {
281         struct s3c24xx_uart_port *ourport = id;
282         struct uart_port *port = &ourport->port;
283         struct circ_buf *xmit = &port->state->xmit;
284         int count = 256;
285
286         if (port->x_char) {
287                 wr_regb(port, S3C2410_UTXH, port->x_char);
288                 port->icount.tx++;
289                 port->x_char = 0;
290                 goto out;
291         }
292
293         /* if there isn't anything more to transmit, or the uart is now
294          * stopped, disable the uart and exit
295         */
296
297         if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
298                 s3c24xx_serial_stop_tx(port);
299                 goto out;
300         }
301
302         /* try and drain the buffer... */
303
304         while (!uart_circ_empty(xmit) && count-- > 0) {
305                 if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
306                         break;
307
308                 wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
309                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
310                 port->icount.tx++;
311         }
312
313         if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
314                 uart_write_wakeup(port);
315
316         if (uart_circ_empty(xmit))
317                 s3c24xx_serial_stop_tx(port);
318
319  out:
320         return IRQ_HANDLED;
321 }
322
323 static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
324 {
325         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
326         unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
327         unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
328
329         if (ufcon & S3C2410_UFCON_FIFOMODE) {
330                 if ((ufstat & info->tx_fifomask) != 0 ||
331                     (ufstat & info->tx_fifofull))
332                         return 0;
333
334                 return 1;
335         }
336
337         return s3c24xx_serial_txempty_nofifo(port);
338 }
339
340 /* no modem control lines */
341 static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
342 {
343         unsigned int umstat = rd_regb(port, S3C2410_UMSTAT);
344
345         if (umstat & S3C2410_UMSTAT_CTS)
346                 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
347         else
348                 return TIOCM_CAR | TIOCM_DSR;
349 }
350
351 static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
352 {
353         /* todo - possibly remove AFC and do manual CTS */
354 }
355
356 static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
357 {
358         unsigned long flags;
359         unsigned int ucon;
360
361         spin_lock_irqsave(&port->lock, flags);
362
363         ucon = rd_regl(port, S3C2410_UCON);
364
365         if (break_state)
366                 ucon |= S3C2410_UCON_SBREAK;
367         else
368                 ucon &= ~S3C2410_UCON_SBREAK;
369
370         wr_regl(port, S3C2410_UCON, ucon);
371
372         spin_unlock_irqrestore(&port->lock, flags);
373 }
374
375 static void s3c24xx_serial_shutdown(struct uart_port *port)
376 {
377         struct s3c24xx_uart_port *ourport = to_ourport(port);
378
379         if (ourport->tx_claimed) {
380                 free_irq(ourport->tx_irq, ourport);
381                 tx_enabled(port) = 0;
382                 ourport->tx_claimed = 0;
383         }
384
385         if (ourport->rx_claimed) {
386                 free_irq(ourport->rx_irq, ourport);
387                 ourport->rx_claimed = 0;
388                 rx_enabled(port) = 0;
389         }
390 }
391
392
393 static int s3c24xx_serial_startup(struct uart_port *port)
394 {
395         struct s3c24xx_uart_port *ourport = to_ourport(port);
396         int ret;
397
398         dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
399             port->mapbase, port->membase);
400
401         rx_enabled(port) = 1;
402
403         ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
404                           s3c24xx_serial_portname(port), ourport);
405
406         if (ret != 0) {
407                 printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
408                 return ret;
409         }
410
411         ourport->rx_claimed = 1;
412
413         dbg("requesting tx irq...\n");
414
415         tx_enabled(port) = 1;
416
417         ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
418                           s3c24xx_serial_portname(port), ourport);
419
420         if (ret) {
421                 printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
422                 goto err;
423         }
424
425         ourport->tx_claimed = 1;
426
427         dbg("s3c24xx_serial_startup ok\n");
428
429         /* the port reset code should have done the correct
430          * register setup for the port controls */
431
432         return ret;
433
434  err:
435         s3c24xx_serial_shutdown(port);
436         return ret;
437 }
438
439 /* power power management control */
440
441 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
442                               unsigned int old)
443 {
444         struct s3c24xx_uart_port *ourport = to_ourport(port);
445
446         ourport->pm_level = level;
447
448         switch (level) {
449         case 3:
450                 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
451                         clk_disable(ourport->baudclk);
452
453                 clk_disable(ourport->clk);
454                 break;
455
456         case 0:
457                 clk_enable(ourport->clk);
458
459                 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
460                         clk_enable(ourport->baudclk);
461
462                 break;
463         default:
464                 printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
465         }
466 }
467
468 /* baud rate calculation
469  *
470  * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
471  * of different sources, including the peripheral clock ("pclk") and an
472  * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
473  * with a programmable extra divisor.
474  *
475  * The following code goes through the clock sources, and calculates the
476  * baud clocks (and the resultant actual baud rates) and then tries to
477  * pick the closest one and select that.
478  *
479 */
480
481
482 #define MAX_CLKS (8)
483
484 static struct s3c24xx_uart_clksrc tmp_clksrc = {
485         .name           = "pclk",
486         .min_baud       = 0,
487         .max_baud       = 0,
488         .divisor        = 1,
489 };
490
491 static inline int
492 s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
493 {
494         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
495
496         return (info->get_clksrc)(port, c);
497 }
498
499 static inline int
500 s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
501 {
502         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
503
504         return (info->set_clksrc)(port, c);
505 }
506
507 struct baud_calc {
508         struct s3c24xx_uart_clksrc      *clksrc;
509         unsigned int                     calc;
510         unsigned int                     divslot;
511         unsigned int                     quot;
512         struct clk                      *src;
513 };
514
515 static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
516                                    struct uart_port *port,
517                                    struct s3c24xx_uart_clksrc *clksrc,
518                                    unsigned int baud)
519 {
520         struct s3c24xx_uart_port *ourport = to_ourport(port);
521         unsigned long rate;
522
523         calc->src = clk_get(port->dev, clksrc->name);
524         if (calc->src == NULL || IS_ERR(calc->src))
525                 return 0;
526
527         rate = clk_get_rate(calc->src);
528         rate /= clksrc->divisor;
529
530         calc->clksrc = clksrc;
531
532         if (ourport->info->has_divslot) {
533                 unsigned long div = rate / baud;
534
535                 /* The UDIVSLOT register on the newer UARTs allows us to
536                  * get a divisor adjustment of 1/16th on the baud clock.
537                  *
538                  * We don't keep the UDIVSLOT value (the 16ths we calculated
539                  * by not multiplying the baud by 16) as it is easy enough
540                  * to recalculate.
541                  */
542
543                 calc->quot = div / 16;
544                 calc->calc = rate / div;
545         } else {
546                 calc->quot = (rate + (8 * baud)) / (16 * baud);
547                 calc->calc = (rate / (calc->quot * 16));
548         }
549
550         calc->quot--;
551         return 1;
552 }
553
554 static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
555                                           struct s3c24xx_uart_clksrc **clksrc,
556                                           struct clk **clk,
557                                           unsigned int baud)
558 {
559         struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
560         struct s3c24xx_uart_clksrc *clkp;
561         struct baud_calc res[MAX_CLKS];
562         struct baud_calc *resptr, *best, *sptr;
563         int i;
564
565         clkp = cfg->clocks;
566         best = NULL;
567
568         if (cfg->clocks_size < 2) {
569                 if (cfg->clocks_size == 0)
570                         clkp = &tmp_clksrc;
571
572                 /* check to see if we're sourcing fclk, and if so we're
573                  * going to have to update the clock source
574                  */
575
576                 if (strcmp(clkp->name, "fclk") == 0) {
577                         struct s3c24xx_uart_clksrc src;
578
579                         s3c24xx_serial_getsource(port, &src);
580
581                         /* check that the port already using fclk, and if
582                          * not, then re-select fclk
583                          */
584
585                         if (strcmp(src.name, clkp->name) == 0) {
586                                 s3c24xx_serial_setsource(port, clkp);
587                                 s3c24xx_serial_getsource(port, &src);
588                         }
589
590                         clkp->divisor = src.divisor;
591                 }
592
593                 s3c24xx_serial_calcbaud(res, port, clkp, baud);
594                 best = res;
595                 resptr = best + 1;
596         } else {
597                 resptr = res;
598
599                 for (i = 0; i < cfg->clocks_size; i++, clkp++) {
600                         if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
601                                 resptr++;
602                 }
603         }
604
605         /* ok, we now need to select the best clock we found */
606
607         if (!best) {
608                 unsigned int deviation = (1<<30)|((1<<30)-1);
609                 int calc_deviation;
610
611                 for (sptr = res; sptr < resptr; sptr++) {
612                         calc_deviation = baud - sptr->calc;
613                         if (calc_deviation < 0)
614                                 calc_deviation = -calc_deviation;
615
616                         if (calc_deviation < deviation) {
617                                 best = sptr;
618                                 deviation = calc_deviation;
619                         }
620                 }
621         }
622
623         /* store results to pass back */
624
625         *clksrc = best->clksrc;
626         *clk    = best->src;
627
628         return best->quot;
629 }
630
631 /* udivslot_table[]
632  *
633  * This table takes the fractional value of the baud divisor and gives
634  * the recommended setting for the UDIVSLOT register.
635  */
636 static u16 udivslot_table[16] = {
637         [0] = 0x0000,
638         [1] = 0x0080,
639         [2] = 0x0808,
640         [3] = 0x0888,
641         [4] = 0x2222,
642         [5] = 0x4924,
643         [6] = 0x4A52,
644         [7] = 0x54AA,
645         [8] = 0x5555,
646         [9] = 0xD555,
647         [10] = 0xD5D5,
648         [11] = 0xDDD5,
649         [12] = 0xDDDD,
650         [13] = 0xDFDD,
651         [14] = 0xDFDF,
652         [15] = 0xFFDF,
653 };
654
655 static void s3c24xx_serial_set_termios(struct uart_port *port,
656                                        struct ktermios *termios,
657                                        struct ktermios *old)
658 {
659         struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
660         struct s3c24xx_uart_port *ourport = to_ourport(port);
661         struct s3c24xx_uart_clksrc *clksrc = NULL;
662         struct clk *clk = NULL;
663         unsigned long flags;
664         unsigned int baud, quot;
665         unsigned int ulcon;
666         unsigned int umcon;
667         unsigned int udivslot = 0;
668
669         /*
670          * We don't support modem control lines.
671          */
672         termios->c_cflag &= ~(HUPCL | CMSPAR);
673         termios->c_cflag |= CLOCAL;
674
675         /*
676          * Ask the core to calculate the divisor for us.
677          */
678
679         baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
680
681         if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
682                 quot = port->custom_divisor;
683         else
684                 quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
685
686         /* check to see if we need  to change clock source */
687
688         if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
689                 dbg("selecting clock %p\n", clk);
690                 s3c24xx_serial_setsource(port, clksrc);
691
692                 if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
693                         clk_disable(ourport->baudclk);
694                         ourport->baudclk  = NULL;
695                 }
696
697                 clk_enable(clk);
698
699                 ourport->clksrc = clksrc;
700                 ourport->baudclk = clk;
701                 ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
702         }
703
704         if (ourport->info->has_divslot) {
705                 unsigned int div = ourport->baudclk_rate / baud;
706
707                 if (cfg->has_fracval) {
708                         udivslot = (div & 15);
709                         dbg("fracval = %04x\n", udivslot);
710                 } else {
711                         udivslot = udivslot_table[div & 15];
712                         dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);
713                 }
714         }
715
716         switch (termios->c_cflag & CSIZE) {
717         case CS5:
718                 dbg("config: 5bits/char\n");
719                 ulcon = S3C2410_LCON_CS5;
720                 break;
721         case CS6:
722                 dbg("config: 6bits/char\n");
723                 ulcon = S3C2410_LCON_CS6;
724                 break;
725         case CS7:
726                 dbg("config: 7bits/char\n");
727                 ulcon = S3C2410_LCON_CS7;
728                 break;
729         case CS8:
730         default:
731                 dbg("config: 8bits/char\n");
732                 ulcon = S3C2410_LCON_CS8;
733                 break;
734         }
735
736         /* preserve original lcon IR settings */
737         ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
738
739         if (termios->c_cflag & CSTOPB)
740                 ulcon |= S3C2410_LCON_STOPB;
741
742         umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
743
744         if (termios->c_cflag & PARENB) {
745                 if (termios->c_cflag & PARODD)
746                         ulcon |= S3C2410_LCON_PODD;
747                 else
748                         ulcon |= S3C2410_LCON_PEVEN;
749         } else {
750                 ulcon |= S3C2410_LCON_PNONE;
751         }
752
753         spin_lock_irqsave(&port->lock, flags);
754
755         dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
756             ulcon, quot, udivslot);
757
758         wr_regl(port, S3C2410_ULCON, ulcon);
759         wr_regl(port, S3C2410_UBRDIV, quot);
760         wr_regl(port, S3C2410_UMCON, umcon);
761
762         if (ourport->info->has_divslot)
763                 wr_regl(port, S3C2443_DIVSLOT, udivslot);
764
765         dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
766             rd_regl(port, S3C2410_ULCON),
767             rd_regl(port, S3C2410_UCON),
768             rd_regl(port, S3C2410_UFCON));
769
770         /*
771          * Update the per-port timeout.
772          */
773         uart_update_timeout(port, termios->c_cflag, baud);
774
775         /*
776          * Which character status flags are we interested in?
777          */
778         port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
779         if (termios->c_iflag & INPCK)
780                 port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
781
782         /*
783          * Which character status flags should we ignore?
784          */
785         port->ignore_status_mask = 0;
786         if (termios->c_iflag & IGNPAR)
787                 port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
788         if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
789                 port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
790
791         /*
792          * Ignore all characters if CREAD is not set.
793          */
794         if ((termios->c_cflag & CREAD) == 0)
795                 port->ignore_status_mask |= RXSTAT_DUMMY_READ;
796
797         spin_unlock_irqrestore(&port->lock, flags);
798 }
799
800 static const char *s3c24xx_serial_type(struct uart_port *port)
801 {
802         switch (port->type) {
803         case PORT_S3C2410:
804                 return "S3C2410";
805         case PORT_S3C2440:
806                 return "S3C2440";
807         case PORT_S3C2412:
808                 return "S3C2412";
809         case PORT_S3C6400:
810                 return "S3C6400/10";
811         default:
812                 return NULL;
813         }
814 }
815
816 #define MAP_SIZE (0x100)
817
818 static void s3c24xx_serial_release_port(struct uart_port *port)
819 {
820         release_mem_region(port->mapbase, MAP_SIZE);
821 }
822
823 static int s3c24xx_serial_request_port(struct uart_port *port)
824 {
825         const char *name = s3c24xx_serial_portname(port);
826         return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
827 }
828
829 static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
830 {
831         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
832
833         if (flags & UART_CONFIG_TYPE &&
834             s3c24xx_serial_request_port(port) == 0)
835                 port->type = info->type;
836 }
837
838 /*
839  * verify the new serial_struct (for TIOCSSERIAL).
840  */
841 static int
842 s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
843 {
844         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
845
846         if (ser->type != PORT_UNKNOWN && ser->type != info->type)
847                 return -EINVAL;
848
849         return 0;
850 }
851
852
853 #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
854
855 static struct console s3c24xx_serial_console;
856
857 #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
858 #else
859 #define S3C24XX_SERIAL_CONSOLE NULL
860 #endif
861
862 static struct uart_ops s3c24xx_serial_ops = {
863         .pm             = s3c24xx_serial_pm,
864         .tx_empty       = s3c24xx_serial_tx_empty,
865         .get_mctrl      = s3c24xx_serial_get_mctrl,
866         .set_mctrl      = s3c24xx_serial_set_mctrl,
867         .stop_tx        = s3c24xx_serial_stop_tx,
868         .start_tx       = s3c24xx_serial_start_tx,
869         .stop_rx        = s3c24xx_serial_stop_rx,
870         .enable_ms      = s3c24xx_serial_enable_ms,
871         .break_ctl      = s3c24xx_serial_break_ctl,
872         .startup        = s3c24xx_serial_startup,
873         .shutdown       = s3c24xx_serial_shutdown,
874         .set_termios    = s3c24xx_serial_set_termios,
875         .type           = s3c24xx_serial_type,
876         .release_port   = s3c24xx_serial_release_port,
877         .request_port   = s3c24xx_serial_request_port,
878         .config_port    = s3c24xx_serial_config_port,
879         .verify_port    = s3c24xx_serial_verify_port,
880 };
881
882
883 static struct uart_driver s3c24xx_uart_drv = {
884         .owner          = THIS_MODULE,
885         .driver_name    = "s3c2410_serial",
886         .nr             = CONFIG_SERIAL_SAMSUNG_UARTS,
887         .cons           = S3C24XX_SERIAL_CONSOLE,
888         .dev_name       = S3C24XX_SERIAL_NAME,
889         .major          = S3C24XX_SERIAL_MAJOR,
890         .minor          = S3C24XX_SERIAL_MINOR,
891 };
892
893 static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
894         [0] = {
895                 .port = {
896                         .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
897                         .iotype         = UPIO_MEM,
898                         .irq            = IRQ_S3CUART_RX0,
899                         .uartclk        = 0,
900                         .fifosize       = 16,
901                         .ops            = &s3c24xx_serial_ops,
902                         .flags          = UPF_BOOT_AUTOCONF,
903                         .line           = 0,
904                 }
905         },
906         [1] = {
907                 .port = {
908                         .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
909                         .iotype         = UPIO_MEM,
910                         .irq            = IRQ_S3CUART_RX1,
911                         .uartclk        = 0,
912                         .fifosize       = 16,
913                         .ops            = &s3c24xx_serial_ops,
914                         .flags          = UPF_BOOT_AUTOCONF,
915                         .line           = 1,
916                 }
917         },
918 #if CONFIG_SERIAL_SAMSUNG_UARTS > 2
919
920         [2] = {
921                 .port = {
922                         .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
923                         .iotype         = UPIO_MEM,
924                         .irq            = IRQ_S3CUART_RX2,
925                         .uartclk        = 0,
926                         .fifosize       = 16,
927                         .ops            = &s3c24xx_serial_ops,
928                         .flags          = UPF_BOOT_AUTOCONF,
929                         .line           = 2,
930                 }
931         },
932 #endif
933 #if CONFIG_SERIAL_SAMSUNG_UARTS > 3
934         [3] = {
935                 .port = {
936                         .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
937                         .iotype         = UPIO_MEM,
938                         .irq            = IRQ_S3CUART_RX3,
939                         .uartclk        = 0,
940                         .fifosize       = 16,
941                         .ops            = &s3c24xx_serial_ops,
942                         .flags          = UPF_BOOT_AUTOCONF,
943                         .line           = 3,
944                 }
945         }
946 #endif
947 };
948
949 /* s3c24xx_serial_resetport
950  *
951  * wrapper to call the specific reset for this port (reset the fifos
952  * and the settings)
953 */
954
955 static inline int s3c24xx_serial_resetport(struct uart_port *port,
956                                            struct s3c2410_uartcfg *cfg)
957 {
958         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
959
960         return (info->reset_port)(port, cfg);
961 }
962
963
964 #ifdef CONFIG_CPU_FREQ
965
966 static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
967                                              unsigned long val, void *data)
968 {
969         struct s3c24xx_uart_port *port;
970         struct uart_port *uport;
971
972         port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
973         uport = &port->port;
974
975         /* check to see if port is enabled */
976
977         if (port->pm_level != 0)
978                 return 0;
979
980         /* try and work out if the baudrate is changing, we can detect
981          * a change in rate, but we do not have support for detecting
982          * a disturbance in the clock-rate over the change.
983          */
984
985         if (IS_ERR(port->clk))
986                 goto exit;
987
988         if (port->baudclk_rate == clk_get_rate(port->clk))
989                 goto exit;
990
991         if (val == CPUFREQ_PRECHANGE) {
992                 /* we should really shut the port down whilst the
993                  * frequency change is in progress. */
994
995         } else if (val == CPUFREQ_POSTCHANGE) {
996                 struct ktermios *termios;
997                 struct tty_struct *tty;
998
999                 if (uport->state == NULL)
1000                         goto exit;
1001
1002                 tty = uport->state->port.tty;
1003
1004                 if (tty == NULL)
1005                         goto exit;
1006
1007                 termios = tty->termios;
1008
1009                 if (termios == NULL) {
1010                         printk(KERN_WARNING "%s: no termios?\n", __func__);
1011                         goto exit;
1012                 }
1013
1014                 s3c24xx_serial_set_termios(uport, termios, NULL);
1015         }
1016
1017  exit:
1018         return 0;
1019 }
1020
1021 static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
1022 {
1023         port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
1024
1025         return cpufreq_register_notifier(&port->freq_transition,
1026                                          CPUFREQ_TRANSITION_NOTIFIER);
1027 }
1028
1029 static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
1030 {
1031         cpufreq_unregister_notifier(&port->freq_transition,
1032                                     CPUFREQ_TRANSITION_NOTIFIER);
1033 }
1034
1035 #else
1036 static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
1037 {
1038         return 0;
1039 }
1040
1041 static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
1042 {
1043 }
1044 #endif
1045
1046 /* s3c24xx_serial_init_port
1047  *
1048  * initialise a single serial port from the platform device given
1049  */
1050
1051 static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
1052                                     struct s3c24xx_uart_info *info,
1053                                     struct platform_device *platdev)
1054 {
1055         struct uart_port *port = &ourport->port;
1056         struct s3c2410_uartcfg *cfg;
1057         struct resource *res;
1058         int ret;
1059
1060         dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
1061
1062         if (platdev == NULL)
1063                 return -ENODEV;
1064
1065         cfg = s3c24xx_dev_to_cfg(&platdev->dev);
1066
1067         if (port->mapbase != 0)
1068                 return 0;
1069
1070         if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
1071                 printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
1072                        cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
1073                 return -ERANGE;
1074         }
1075
1076         /* setup info for port */
1077         port->dev       = &platdev->dev;
1078         ourport->info   = info;
1079
1080         /* copy the info in from provided structure */
1081         ourport->port.fifosize = info->fifosize;
1082
1083         dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
1084
1085         port->uartclk = 1;
1086
1087         if (cfg->uart_flags & UPF_CONS_FLOW) {
1088                 dbg("s3c24xx_serial_init_port: enabling flow control\n");
1089                 port->flags |= UPF_CONS_FLOW;
1090         }
1091
1092         /* sort our the physical and virtual addresses for each UART */
1093
1094         res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
1095         if (res == NULL) {
1096                 printk(KERN_ERR "failed to find memory resource for uart\n");
1097                 return -EINVAL;
1098         }
1099
1100         dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
1101
1102         port->mapbase = res->start;
1103         port->membase = S3C_VA_UART + (res->start & 0xfffff);
1104         ret = platform_get_irq(platdev, 0);
1105         if (ret < 0)
1106                 port->irq = 0;
1107         else {
1108                 port->irq = ret;
1109                 ourport->rx_irq = ret;
1110                 ourport->tx_irq = ret + 1;
1111         }
1112         
1113         ret = platform_get_irq(platdev, 1);
1114         if (ret > 0)
1115                 ourport->tx_irq = ret;
1116
1117         ourport->clk    = clk_get(&platdev->dev, "uart");
1118
1119         dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
1120             port->mapbase, port->membase, port->irq,
1121             ourport->rx_irq, ourport->tx_irq, port->uartclk);
1122
1123         /* reset the fifos (and setup the uart) */
1124         s3c24xx_serial_resetport(port, cfg);
1125         return 0;
1126 }
1127
1128 static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
1129                                           struct device_attribute *attr,
1130                                           char *buf)
1131 {
1132         struct uart_port *port = s3c24xx_dev_to_port(dev);
1133         struct s3c24xx_uart_port *ourport = to_ourport(port);
1134
1135         return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->clksrc->name);
1136 }
1137
1138 static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
1139
1140 /* Device driver serial port probe */
1141
1142 static int probe_index;
1143
1144 int s3c24xx_serial_probe(struct platform_device *dev,
1145                          struct s3c24xx_uart_info *info)
1146 {
1147         struct s3c24xx_uart_port *ourport;
1148         int ret;
1149
1150         dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
1151
1152         ourport = &s3c24xx_serial_ports[probe_index];
1153         probe_index++;
1154
1155         dbg("%s: initialising port %p...\n", __func__, ourport);
1156
1157         ret = s3c24xx_serial_init_port(ourport, info, dev);
1158         if (ret < 0)
1159                 goto probe_err;
1160
1161         dbg("%s: adding port\n", __func__);
1162         uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
1163         platform_set_drvdata(dev, &ourport->port);
1164
1165         ret = device_create_file(&dev->dev, &dev_attr_clock_source);
1166         if (ret < 0)
1167                 printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
1168
1169         ret = s3c24xx_serial_cpufreq_register(ourport);
1170         if (ret < 0)
1171                 dev_err(&dev->dev, "failed to add cpufreq notifier\n");
1172
1173         return 0;
1174
1175  probe_err:
1176         return ret;
1177 }
1178
1179 EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
1180
1181 int __devexit s3c24xx_serial_remove(struct platform_device *dev)
1182 {
1183         struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1184
1185         if (port) {
1186                 s3c24xx_serial_cpufreq_deregister(to_ourport(port));
1187                 device_remove_file(&dev->dev, &dev_attr_clock_source);
1188                 uart_remove_one_port(&s3c24xx_uart_drv, port);
1189         }
1190
1191         return 0;
1192 }
1193
1194 EXPORT_SYMBOL_GPL(s3c24xx_serial_remove);
1195
1196 /* UART power management code */
1197 #ifdef CONFIG_PM_SLEEP
1198 static int s3c24xx_serial_suspend(struct device *dev)
1199 {
1200         struct uart_port *port = s3c24xx_dev_to_port(dev);
1201
1202         if (port)
1203                 uart_suspend_port(&s3c24xx_uart_drv, port);
1204
1205         return 0;
1206 }
1207
1208 static int s3c24xx_serial_resume(struct device *dev)
1209 {
1210         struct uart_port *port = s3c24xx_dev_to_port(dev);
1211         struct s3c24xx_uart_port *ourport = to_ourport(port);
1212
1213         if (port) {
1214                 clk_enable(ourport->clk);
1215                 s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
1216                 clk_disable(ourport->clk);
1217
1218                 uart_resume_port(&s3c24xx_uart_drv, port);
1219         }
1220
1221         return 0;
1222 }
1223
1224 static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
1225         .suspend = s3c24xx_serial_suspend,
1226         .resume = s3c24xx_serial_resume,
1227 };
1228 #define SERIAL_SAMSUNG_PM_OPS   (&s3c24xx_serial_pm_ops)
1229
1230 #else /* !CONFIG_PM_SLEEP */
1231
1232 #define SERIAL_SAMSUNG_PM_OPS   NULL
1233 #endif /* CONFIG_PM_SLEEP */
1234
1235 int s3c24xx_serial_init(struct platform_driver *drv,
1236                         struct s3c24xx_uart_info *info)
1237 {
1238         dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
1239
1240         drv->driver.pm = SERIAL_SAMSUNG_PM_OPS;
1241
1242         return platform_driver_register(drv);
1243 }
1244
1245 EXPORT_SYMBOL_GPL(s3c24xx_serial_init);
1246
1247 /* module initialisation code */
1248
1249 static int __init s3c24xx_serial_modinit(void)
1250 {
1251         int ret;
1252
1253         ret = uart_register_driver(&s3c24xx_uart_drv);
1254         if (ret < 0) {
1255                 printk(KERN_ERR "failed to register UART driver\n");
1256                 return -1;
1257         }
1258
1259         return 0;
1260 }
1261
1262 static void __exit s3c24xx_serial_modexit(void)
1263 {
1264         uart_unregister_driver(&s3c24xx_uart_drv);
1265 }
1266
1267 module_init(s3c24xx_serial_modinit);
1268 module_exit(s3c24xx_serial_modexit);
1269
1270 /* Console code */
1271
1272 #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
1273
1274 static struct uart_port *cons_uart;
1275
1276 static int
1277 s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
1278 {
1279         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
1280         unsigned long ufstat, utrstat;
1281
1282         if (ufcon & S3C2410_UFCON_FIFOMODE) {
1283                 /* fifo mode - check amount of data in fifo registers... */
1284
1285                 ufstat = rd_regl(port, S3C2410_UFSTAT);
1286                 return (ufstat & info->tx_fifofull) ? 0 : 1;
1287         }
1288
1289         /* in non-fifo mode, we go and use the tx buffer empty */
1290
1291         utrstat = rd_regl(port, S3C2410_UTRSTAT);
1292         return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
1293 }
1294
1295 static void
1296 s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
1297 {
1298         unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
1299         while (!s3c24xx_serial_console_txrdy(port, ufcon))
1300                 barrier();
1301         wr_regb(cons_uart, S3C2410_UTXH, ch);
1302 }
1303
1304 static void
1305 s3c24xx_serial_console_write(struct console *co, const char *s,
1306                              unsigned int count)
1307 {
1308         uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
1309 }
1310
1311 static void __init
1312 s3c24xx_serial_get_options(struct uart_port *port, int *baud,
1313                            int *parity, int *bits)
1314 {
1315         struct s3c24xx_uart_clksrc clksrc;
1316         struct clk *clk;
1317         unsigned int ulcon;
1318         unsigned int ucon;
1319         unsigned int ubrdiv;
1320         unsigned long rate;
1321
1322         ulcon  = rd_regl(port, S3C2410_ULCON);
1323         ucon   = rd_regl(port, S3C2410_UCON);
1324         ubrdiv = rd_regl(port, S3C2410_UBRDIV);
1325
1326         dbg("s3c24xx_serial_get_options: port=%p\n"
1327             "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
1328             port, ulcon, ucon, ubrdiv);
1329
1330         if ((ucon & 0xf) != 0) {
1331                 /* consider the serial port configured if the tx/rx mode set */
1332
1333                 switch (ulcon & S3C2410_LCON_CSMASK) {
1334                 case S3C2410_LCON_CS5:
1335                         *bits = 5;
1336                         break;
1337                 case S3C2410_LCON_CS6:
1338                         *bits = 6;
1339                         break;
1340                 case S3C2410_LCON_CS7:
1341                         *bits = 7;
1342                         break;
1343                 default:
1344                 case S3C2410_LCON_CS8:
1345                         *bits = 8;
1346                         break;
1347                 }
1348
1349                 switch (ulcon & S3C2410_LCON_PMASK) {
1350                 case S3C2410_LCON_PEVEN:
1351                         *parity = 'e';
1352                         break;
1353
1354                 case S3C2410_LCON_PODD:
1355                         *parity = 'o';
1356                         break;
1357
1358                 case S3C2410_LCON_PNONE:
1359                 default:
1360                         *parity = 'n';
1361                 }
1362
1363                 /* now calculate the baud rate */
1364
1365                 s3c24xx_serial_getsource(port, &clksrc);
1366
1367                 clk = clk_get(port->dev, clksrc.name);
1368                 if (!IS_ERR(clk) && clk != NULL)
1369                         rate = clk_get_rate(clk) / clksrc.divisor;
1370                 else
1371                         rate = 1;
1372
1373
1374                 *baud = rate / (16 * (ubrdiv + 1));
1375                 dbg("calculated baud %d\n", *baud);
1376         }
1377
1378 }
1379
1380 /* s3c24xx_serial_init_ports
1381  *
1382  * initialise the serial ports from the machine provided initialisation
1383  * data.
1384 */
1385
1386 static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
1387 {
1388         struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
1389         struct platform_device **platdev_ptr;
1390         int i;
1391
1392         dbg("s3c24xx_serial_init_ports: initialising ports...\n");
1393
1394         platdev_ptr = s3c24xx_uart_devs;
1395
1396         for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
1397                 s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
1398         }
1399
1400         return 0;
1401 }
1402
1403 static int __init
1404 s3c24xx_serial_console_setup(struct console *co, char *options)
1405 {
1406         struct uart_port *port;
1407         int baud = 9600;
1408         int bits = 8;
1409         int parity = 'n';
1410         int flow = 'n';
1411
1412         dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
1413             co, co->index, options);
1414
1415         /* is this a valid port */
1416
1417         if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
1418                 co->index = 0;
1419
1420         port = &s3c24xx_serial_ports[co->index].port;
1421
1422         /* is the port configured? */
1423
1424         if (port->mapbase == 0x0)
1425                 return -ENODEV;
1426
1427         cons_uart = port;
1428
1429         dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
1430
1431         /*
1432          * Check whether an invalid uart number has been specified, and
1433          * if so, search for the first available port that does have
1434          * console support.
1435          */
1436         if (options)
1437                 uart_parse_options(options, &baud, &parity, &bits, &flow);
1438         else
1439                 s3c24xx_serial_get_options(port, &baud, &parity, &bits);
1440
1441         dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
1442
1443         return uart_set_options(port, co, baud, parity, bits, flow);
1444 }
1445
1446 /* s3c24xx_serial_initconsole
1447  *
1448  * initialise the console from one of the uart drivers
1449 */
1450
1451 static struct console s3c24xx_serial_console = {
1452         .name           = S3C24XX_SERIAL_NAME,
1453         .device         = uart_console_device,
1454         .flags          = CON_PRINTBUFFER,
1455         .index          = -1,
1456         .write          = s3c24xx_serial_console_write,
1457         .setup          = s3c24xx_serial_console_setup,
1458         .data           = &s3c24xx_uart_drv,
1459 };
1460
1461 int s3c24xx_serial_initconsole(struct platform_driver *drv,
1462                                struct s3c24xx_uart_info **info)
1463
1464 {
1465         struct platform_device *dev = s3c24xx_uart_devs[0];
1466
1467         dbg("s3c24xx_serial_initconsole\n");
1468
1469         /* select driver based on the cpu */
1470
1471         if (dev == NULL) {
1472                 printk(KERN_ERR "s3c24xx: no devices for console init\n");
1473                 return 0;
1474         }
1475
1476         if (strcmp(dev->name, drv->driver.name) != 0)
1477                 return 0;
1478
1479         s3c24xx_serial_console.data = &s3c24xx_uart_drv;
1480         s3c24xx_serial_init_ports(info);
1481
1482         register_console(&s3c24xx_serial_console);
1483         return 0;
1484 }
1485
1486 #endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
1487
1488 MODULE_DESCRIPTION("Samsung SoC Serial port driver");
1489 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
1490 MODULE_LICENSE("GPL v2");