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