[ARM] 5050/1: S3C2410: Cleanup header on S3C2410 serial driver
[linux-2.6] / drivers / serial / s3c2410.c
1 /* linux/drivers/serial/s3c2410.c
2  *
3  * Driver for Samsung SoC onboard UARTs.
4  *
5  * Ben Dooks, Copyright (c) 2003-2005 Simtec Electronics
6  *      http://armlinux.simtec.co.uk/
7 */
8
9 /* Note on 2440 fclk clock source handling
10  *
11  * Whilst it is possible to use the fclk as clock source, the method
12  * of properly switching too/from this is currently un-implemented, so
13  * whichever way is configured at startup is the one that will be used.
14 */
15
16 /* Hote on 2410 error handling
17  *
18  * The s3c2410 manual has a love/hate affair with the contents of the
19  * UERSTAT register in the UART blocks, and keeps marking some of the
20  * error bits as reserved. Having checked with the s3c2410x01,
21  * it copes with BREAKs properly, so I am happy to ignore the RESERVED
22  * feature from the latter versions of the manual.
23  *
24  * If it becomes aparrent that latter versions of the 2410 remove these
25  * bits, then action will have to be taken to differentiate the versions
26  * and change the policy on BREAK
27  *
28  * BJD, 04-Nov-2004
29 */
30
31
32 #if defined(CONFIG_SERIAL_S3C2410_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
33 #define SUPPORT_SYSRQ
34 #endif
35
36 #include <linux/module.h>
37 #include <linux/ioport.h>
38 #include <linux/platform_device.h>
39 #include <linux/init.h>
40 #include <linux/sysrq.h>
41 #include <linux/console.h>
42 #include <linux/tty.h>
43 #include <linux/tty_flip.h>
44 #include <linux/serial_core.h>
45 #include <linux/serial.h>
46 #include <linux/delay.h>
47 #include <linux/clk.h>
48
49 #include <asm/io.h>
50 #include <asm/irq.h>
51
52 #include <asm/hardware.h>
53
54 #include <asm/plat-s3c/regs-serial.h>
55 #include <asm/arch/regs-gpio.h>
56
57 /* structures */
58
59 struct s3c24xx_uart_info {
60         char                    *name;
61         unsigned int            type;
62         unsigned int            fifosize;
63         unsigned long           rx_fifomask;
64         unsigned long           rx_fifoshift;
65         unsigned long           rx_fifofull;
66         unsigned long           tx_fifomask;
67         unsigned long           tx_fifoshift;
68         unsigned long           tx_fifofull;
69
70         /* clock source control */
71
72         int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
73         int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
74
75         /* uart controls */
76         int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
77 };
78
79 struct s3c24xx_uart_port {
80         unsigned char                   rx_claimed;
81         unsigned char                   tx_claimed;
82
83         struct s3c24xx_uart_info        *info;
84         struct s3c24xx_uart_clksrc      *clksrc;
85         struct clk                      *clk;
86         struct clk                      *baudclk;
87         struct uart_port                port;
88 };
89
90
91 /* configuration defines */
92
93 #if 0
94 #if 1
95 /* send debug to the low-level output routines */
96
97 extern void printascii(const char *);
98
99 static void
100 s3c24xx_serial_dbg(const char *fmt, ...)
101 {
102         va_list va;
103         char buff[256];
104
105         va_start(va, fmt);
106         vsprintf(buff, fmt, va);
107         va_end(va);
108
109         printascii(buff);
110 }
111
112 #define dbg(x...) s3c24xx_serial_dbg(x)
113
114 #else
115 #define dbg(x...) printk(KERN_DEBUG "s3c24xx: ");
116 #endif
117 #else /* no debug */
118 #define dbg(x...) do {} while(0)
119 #endif
120
121 /* UART name and device definitions */
122
123 #define S3C24XX_SERIAL_NAME     "ttySAC"
124 #define S3C24XX_SERIAL_MAJOR    204
125 #define S3C24XX_SERIAL_MINOR    64
126
127
128 /* conversion functions */
129
130 #define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
131 #define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
132
133 /* we can support 3 uarts, but not always use them */
134
135 #ifdef CONFIG_CPU_S3C2400
136 #define NR_PORTS (2)
137 #else
138 #define NR_PORTS (3)
139 #endif
140
141 /* port irq numbers */
142
143 #define TX_IRQ(port) ((port)->irq + 1)
144 #define RX_IRQ(port) ((port)->irq)
145
146 /* register access controls */
147
148 #define portaddr(port, reg) ((port)->membase + (reg))
149
150 #define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
151 #define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
152
153 #define wr_regb(port, reg, val) \
154   do { __raw_writeb(val, portaddr(port, reg)); } while(0)
155
156 #define wr_regl(port, reg, val) \
157   do { __raw_writel(val, portaddr(port, reg)); } while(0)
158
159 /* macros to change one thing to another */
160
161 #define tx_enabled(port) ((port)->unused[0])
162 #define rx_enabled(port) ((port)->unused[1])
163
164 /* flag to ignore all characters comming in */
165 #define RXSTAT_DUMMY_READ (0x10000000)
166
167 static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
168 {
169         return container_of(port, struct s3c24xx_uart_port, port);
170 }
171
172 /* translate a port to the device name */
173
174 static inline const char *s3c24xx_serial_portname(struct uart_port *port)
175 {
176         return to_platform_device(port->dev)->name;
177 }
178
179 static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
180 {
181         return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
182 }
183
184 static void s3c24xx_serial_rx_enable(struct uart_port *port)
185 {
186         unsigned long flags;
187         unsigned int ucon, ufcon;
188         int count = 10000;
189
190         spin_lock_irqsave(&port->lock, flags);
191
192         while (--count && !s3c24xx_serial_txempty_nofifo(port))
193                 udelay(100);
194
195         ufcon = rd_regl(port, S3C2410_UFCON);
196         ufcon |= S3C2410_UFCON_RESETRX;
197         wr_regl(port, S3C2410_UFCON, ufcon);
198
199         ucon = rd_regl(port, S3C2410_UCON);
200         ucon |= S3C2410_UCON_RXIRQMODE;
201         wr_regl(port, S3C2410_UCON, ucon);
202
203         rx_enabled(port) = 1;
204         spin_unlock_irqrestore(&port->lock, flags);
205 }
206
207 static void s3c24xx_serial_rx_disable(struct uart_port *port)
208 {
209         unsigned long flags;
210         unsigned int ucon;
211
212         spin_lock_irqsave(&port->lock, flags);
213
214         ucon = rd_regl(port, S3C2410_UCON);
215         ucon &= ~S3C2410_UCON_RXIRQMODE;
216         wr_regl(port, S3C2410_UCON, ucon);
217
218         rx_enabled(port) = 0;
219         spin_unlock_irqrestore(&port->lock, flags);
220 }
221
222 static void s3c24xx_serial_stop_tx(struct uart_port *port)
223 {
224         if (tx_enabled(port)) {
225                 disable_irq(TX_IRQ(port));
226                 tx_enabled(port) = 0;
227                 if (port->flags & UPF_CONS_FLOW)
228                         s3c24xx_serial_rx_enable(port);
229         }
230 }
231
232 static void s3c24xx_serial_start_tx(struct uart_port *port)
233 {
234         if (!tx_enabled(port)) {
235                 if (port->flags & UPF_CONS_FLOW)
236                         s3c24xx_serial_rx_disable(port);
237
238                 enable_irq(TX_IRQ(port));
239                 tx_enabled(port) = 1;
240         }
241 }
242
243
244 static void s3c24xx_serial_stop_rx(struct uart_port *port)
245 {
246         if (rx_enabled(port)) {
247                 dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
248                 disable_irq(RX_IRQ(port));
249                 rx_enabled(port) = 0;
250         }
251 }
252
253 static void s3c24xx_serial_enable_ms(struct uart_port *port)
254 {
255 }
256
257 static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
258 {
259         return to_ourport(port)->info;
260 }
261
262 static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
263 {
264         if (port->dev == NULL)
265                 return NULL;
266
267         return (struct s3c2410_uartcfg *)port->dev->platform_data;
268 }
269
270 static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
271                                      unsigned long ufstat)
272 {
273         struct s3c24xx_uart_info *info = ourport->info;
274
275         if (ufstat & info->rx_fifofull)
276                 return info->fifosize;
277
278         return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
279 }
280
281
282 /* ? - where has parity gone?? */
283 #define S3C2410_UERSTAT_PARITY (0x1000)
284
285 static irqreturn_t
286 s3c24xx_serial_rx_chars(int irq, void *dev_id)
287 {
288         struct s3c24xx_uart_port *ourport = dev_id;
289         struct uart_port *port = &ourport->port;
290         struct tty_struct *tty = port->info->tty;
291         unsigned int ufcon, ch, flag, ufstat, uerstat;
292         int max_count = 64;
293
294         while (max_count-- > 0) {
295                 ufcon = rd_regl(port, S3C2410_UFCON);
296                 ufstat = rd_regl(port, S3C2410_UFSTAT);
297
298                 if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
299                         break;
300
301                 uerstat = rd_regl(port, S3C2410_UERSTAT);
302                 ch = rd_regb(port, S3C2410_URXH);
303
304                 if (port->flags & UPF_CONS_FLOW) {
305                         int txe = s3c24xx_serial_txempty_nofifo(port);
306
307                         if (rx_enabled(port)) {
308                                 if (!txe) {
309                                         rx_enabled(port) = 0;
310                                         continue;
311                                 }
312                         } else {
313                                 if (txe) {
314                                         ufcon |= S3C2410_UFCON_RESETRX;
315                                         wr_regl(port, S3C2410_UFCON, ufcon);
316                                         rx_enabled(port) = 1;
317                                         goto out;
318                                 }
319                                 continue;
320                         }
321                 }
322
323                 /* insert the character into the buffer */
324
325                 flag = TTY_NORMAL;
326                 port->icount.rx++;
327
328                 if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
329                         dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
330                             ch, uerstat);
331
332                         /* check for break */
333                         if (uerstat & S3C2410_UERSTAT_BREAK) {
334                                 dbg("break!\n");
335                                 port->icount.brk++;
336                                 if (uart_handle_break(port))
337                                     goto ignore_char;
338                         }
339
340                         if (uerstat & S3C2410_UERSTAT_FRAME)
341                                 port->icount.frame++;
342                         if (uerstat & S3C2410_UERSTAT_OVERRUN)
343                                 port->icount.overrun++;
344
345                         uerstat &= port->read_status_mask;
346
347                         if (uerstat & S3C2410_UERSTAT_BREAK)
348                                 flag = TTY_BREAK;
349                         else if (uerstat & S3C2410_UERSTAT_PARITY)
350                                 flag = TTY_PARITY;
351                         else if (uerstat & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN))
352                                 flag = TTY_FRAME;
353                 }
354
355                 if (uart_handle_sysrq_char(port, ch))
356                         goto ignore_char;
357
358                 uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);
359
360         ignore_char:
361                 continue;
362         }
363         tty_flip_buffer_push(tty);
364
365  out:
366         return IRQ_HANDLED;
367 }
368
369 static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
370 {
371         struct s3c24xx_uart_port *ourport = id;
372         struct uart_port *port = &ourport->port;
373         struct circ_buf *xmit = &port->info->xmit;
374         int count = 256;
375
376         if (port->x_char) {
377                 wr_regb(port, S3C2410_UTXH, port->x_char);
378                 port->icount.tx++;
379                 port->x_char = 0;
380                 goto out;
381         }
382
383         /* if there isnt anything more to transmit, or the uart is now
384          * stopped, disable the uart and exit
385         */
386
387         if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
388                 s3c24xx_serial_stop_tx(port);
389                 goto out;
390         }
391
392         /* try and drain the buffer... */
393
394         while (!uart_circ_empty(xmit) && count-- > 0) {
395                 if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
396                         break;
397
398                 wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
399                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
400                 port->icount.tx++;
401         }
402
403         if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
404                 uart_write_wakeup(port);
405
406         if (uart_circ_empty(xmit))
407                 s3c24xx_serial_stop_tx(port);
408
409  out:
410         return IRQ_HANDLED;
411 }
412
413 static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
414 {
415         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
416         unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
417         unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
418
419         if (ufcon & S3C2410_UFCON_FIFOMODE) {
420                 if ((ufstat & info->tx_fifomask) != 0 ||
421                     (ufstat & info->tx_fifofull))
422                         return 0;
423
424                 return 1;
425         }
426
427         return s3c24xx_serial_txempty_nofifo(port);
428 }
429
430 /* no modem control lines */
431 static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
432 {
433         unsigned int umstat = rd_regb(port,S3C2410_UMSTAT);
434
435         if (umstat & S3C2410_UMSTAT_CTS)
436                 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
437         else
438                 return TIOCM_CAR | TIOCM_DSR;
439 }
440
441 static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
442 {
443         /* todo - possibly remove AFC and do manual CTS */
444 }
445
446 static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
447 {
448         unsigned long flags;
449         unsigned int ucon;
450
451         spin_lock_irqsave(&port->lock, flags);
452
453         ucon = rd_regl(port, S3C2410_UCON);
454
455         if (break_state)
456                 ucon |= S3C2410_UCON_SBREAK;
457         else
458                 ucon &= ~S3C2410_UCON_SBREAK;
459
460         wr_regl(port, S3C2410_UCON, ucon);
461
462         spin_unlock_irqrestore(&port->lock, flags);
463 }
464
465 static void s3c24xx_serial_shutdown(struct uart_port *port)
466 {
467         struct s3c24xx_uart_port *ourport = to_ourport(port);
468
469         if (ourport->tx_claimed) {
470                 free_irq(TX_IRQ(port), ourport);
471                 tx_enabled(port) = 0;
472                 ourport->tx_claimed = 0;
473         }
474
475         if (ourport->rx_claimed) {
476                 free_irq(RX_IRQ(port), ourport);
477                 ourport->rx_claimed = 0;
478                 rx_enabled(port) = 0;
479         }
480 }
481
482
483 static int s3c24xx_serial_startup(struct uart_port *port)
484 {
485         struct s3c24xx_uart_port *ourport = to_ourport(port);
486         int ret;
487
488         dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
489             port->mapbase, port->membase);
490
491         rx_enabled(port) = 1;
492
493         ret = request_irq(RX_IRQ(port),
494                           s3c24xx_serial_rx_chars, 0,
495                           s3c24xx_serial_portname(port), ourport);
496
497         if (ret != 0) {
498                 printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port));
499                 return ret;
500         }
501
502         ourport->rx_claimed = 1;
503
504         dbg("requesting tx irq...\n");
505
506         tx_enabled(port) = 1;
507
508         ret = request_irq(TX_IRQ(port),
509                           s3c24xx_serial_tx_chars, 0,
510                           s3c24xx_serial_portname(port), ourport);
511
512         if (ret) {
513                 printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port));
514                 goto err;
515         }
516
517         ourport->tx_claimed = 1;
518
519         dbg("s3c24xx_serial_startup ok\n");
520
521         /* the port reset code should have done the correct
522          * register setup for the port controls */
523
524         return ret;
525
526  err:
527         s3c24xx_serial_shutdown(port);
528         return ret;
529 }
530
531 /* power power management control */
532
533 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
534                               unsigned int old)
535 {
536         struct s3c24xx_uart_port *ourport = to_ourport(port);
537
538         switch (level) {
539         case 3:
540                 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
541                         clk_disable(ourport->baudclk);
542
543                 clk_disable(ourport->clk);
544                 break;
545
546         case 0:
547                 clk_enable(ourport->clk);
548
549                 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
550                         clk_enable(ourport->baudclk);
551
552                 break;
553         default:
554                 printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
555         }
556 }
557
558 /* baud rate calculation
559  *
560  * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
561  * of different sources, including the peripheral clock ("pclk") and an
562  * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
563  * with a programmable extra divisor.
564  *
565  * The following code goes through the clock sources, and calculates the
566  * baud clocks (and the resultant actual baud rates) and then tries to
567  * pick the closest one and select that.
568  *
569 */
570
571
572 #define MAX_CLKS (8)
573
574 static struct s3c24xx_uart_clksrc tmp_clksrc = {
575         .name           = "pclk",
576         .min_baud       = 0,
577         .max_baud       = 0,
578         .divisor        = 1,
579 };
580
581 static inline int
582 s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
583 {
584         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
585
586         return (info->get_clksrc)(port, c);
587 }
588
589 static inline int
590 s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
591 {
592         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
593
594         return (info->set_clksrc)(port, c);
595 }
596
597 struct baud_calc {
598         struct s3c24xx_uart_clksrc      *clksrc;
599         unsigned int                     calc;
600         unsigned int                     quot;
601         struct clk                      *src;
602 };
603
604 static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
605                                    struct uart_port *port,
606                                    struct s3c24xx_uart_clksrc *clksrc,
607                                    unsigned int baud)
608 {
609         unsigned long rate;
610
611         calc->src = clk_get(port->dev, clksrc->name);
612         if (calc->src == NULL || IS_ERR(calc->src))
613                 return 0;
614
615         rate = clk_get_rate(calc->src);
616         rate /= clksrc->divisor;
617
618         calc->clksrc = clksrc;
619         calc->quot = (rate + (8 * baud)) / (16 * baud);
620         calc->calc = (rate / (calc->quot * 16));
621
622         calc->quot--;
623         return 1;
624 }
625
626 static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
627                                           struct s3c24xx_uart_clksrc **clksrc,
628                                           struct clk **clk,
629                                           unsigned int baud)
630 {
631         struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
632         struct s3c24xx_uart_clksrc *clkp;
633         struct baud_calc res[MAX_CLKS];
634         struct baud_calc *resptr, *best, *sptr;
635         int i;
636
637         clkp = cfg->clocks;
638         best = NULL;
639
640         if (cfg->clocks_size < 2) {
641                 if (cfg->clocks_size == 0)
642                         clkp = &tmp_clksrc;
643
644                 /* check to see if we're sourcing fclk, and if so we're
645                  * going to have to update the clock source
646                  */
647
648                 if (strcmp(clkp->name, "fclk") == 0) {
649                         struct s3c24xx_uart_clksrc src;
650
651                         s3c24xx_serial_getsource(port, &src);
652
653                         /* check that the port already using fclk, and if
654                          * not, then re-select fclk
655                          */
656
657                         if (strcmp(src.name, clkp->name) == 0) {
658                                 s3c24xx_serial_setsource(port, clkp);
659                                 s3c24xx_serial_getsource(port, &src);
660                         }
661
662                         clkp->divisor = src.divisor;
663                 }
664
665                 s3c24xx_serial_calcbaud(res, port, clkp, baud);
666                 best = res;
667                 resptr = best + 1;
668         } else {
669                 resptr = res;
670
671                 for (i = 0; i < cfg->clocks_size; i++, clkp++) {
672                         if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
673                                 resptr++;
674                 }
675         }
676
677         /* ok, we now need to select the best clock we found */
678
679         if (!best) {
680                 unsigned int deviation = (1<<30)|((1<<30)-1);
681                 int calc_deviation;
682
683                 for (sptr = res; sptr < resptr; sptr++) {
684                         printk(KERN_DEBUG
685                                "found clk %p (%s) quot %d, calc %d\n",
686                                sptr->clksrc, sptr->clksrc->name,
687                                sptr->quot, sptr->calc);
688
689                         calc_deviation = baud - sptr->calc;
690                         if (calc_deviation < 0)
691                                 calc_deviation = -calc_deviation;
692
693                         if (calc_deviation < deviation) {
694                                 best = sptr;
695                                 deviation = calc_deviation;
696                         }
697                 }
698
699                 printk(KERN_DEBUG "best %p (deviation %d)\n", best, deviation);
700         }
701
702         printk(KERN_DEBUG "selected clock %p (%s) quot %d, calc %d\n",
703                best->clksrc, best->clksrc->name, best->quot, best->calc);
704
705         /* store results to pass back */
706
707         *clksrc = best->clksrc;
708         *clk    = best->src;
709
710         return best->quot;
711 }
712
713 static void s3c24xx_serial_set_termios(struct uart_port *port,
714                                        struct ktermios *termios,
715                                        struct ktermios *old)
716 {
717         struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
718         struct s3c24xx_uart_port *ourport = to_ourport(port);
719         struct s3c24xx_uart_clksrc *clksrc = NULL;
720         struct clk *clk = NULL;
721         unsigned long flags;
722         unsigned int baud, quot;
723         unsigned int ulcon;
724         unsigned int umcon;
725
726         /*
727          * We don't support modem control lines.
728          */
729         termios->c_cflag &= ~(HUPCL | CMSPAR);
730         termios->c_cflag |= CLOCAL;
731
732         /*
733          * Ask the core to calculate the divisor for us.
734          */
735
736         baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
737
738         if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
739                 quot = port->custom_divisor;
740         else
741                 quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
742
743         /* check to see if we need  to change clock source */
744
745         if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
746                 s3c24xx_serial_setsource(port, clksrc);
747
748                 if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
749                         clk_disable(ourport->baudclk);
750                         ourport->baudclk  = NULL;
751                 }
752
753                 clk_enable(clk);
754
755                 ourport->clksrc = clksrc;
756                 ourport->baudclk = clk;
757         }
758
759         switch (termios->c_cflag & CSIZE) {
760         case CS5:
761                 dbg("config: 5bits/char\n");
762                 ulcon = S3C2410_LCON_CS5;
763                 break;
764         case CS6:
765                 dbg("config: 6bits/char\n");
766                 ulcon = S3C2410_LCON_CS6;
767                 break;
768         case CS7:
769                 dbg("config: 7bits/char\n");
770                 ulcon = S3C2410_LCON_CS7;
771                 break;
772         case CS8:
773         default:
774                 dbg("config: 8bits/char\n");
775                 ulcon = S3C2410_LCON_CS8;
776                 break;
777         }
778
779         /* preserve original lcon IR settings */
780         ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
781
782         if (termios->c_cflag & CSTOPB)
783                 ulcon |= S3C2410_LCON_STOPB;
784
785         umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
786
787         if (termios->c_cflag & PARENB) {
788                 if (termios->c_cflag & PARODD)
789                         ulcon |= S3C2410_LCON_PODD;
790                 else
791                         ulcon |= S3C2410_LCON_PEVEN;
792         } else {
793                 ulcon |= S3C2410_LCON_PNONE;
794         }
795
796         spin_lock_irqsave(&port->lock, flags);
797
798         dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);
799
800         wr_regl(port, S3C2410_ULCON, ulcon);
801         wr_regl(port, S3C2410_UBRDIV, quot);
802         wr_regl(port, S3C2410_UMCON, umcon);
803
804         dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
805             rd_regl(port, S3C2410_ULCON),
806             rd_regl(port, S3C2410_UCON),
807             rd_regl(port, S3C2410_UFCON));
808
809         /*
810          * Update the per-port timeout.
811          */
812         uart_update_timeout(port, termios->c_cflag, baud);
813
814         /*
815          * Which character status flags are we interested in?
816          */
817         port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
818         if (termios->c_iflag & INPCK)
819                 port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
820
821         /*
822          * Which character status flags should we ignore?
823          */
824         port->ignore_status_mask = 0;
825         if (termios->c_iflag & IGNPAR)
826                 port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
827         if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
828                 port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
829
830         /*
831          * Ignore all characters if CREAD is not set.
832          */
833         if ((termios->c_cflag & CREAD) == 0)
834                 port->ignore_status_mask |= RXSTAT_DUMMY_READ;
835
836         spin_unlock_irqrestore(&port->lock, flags);
837 }
838
839 static const char *s3c24xx_serial_type(struct uart_port *port)
840 {
841         switch (port->type) {
842         case PORT_S3C2410:
843                 return "S3C2410";
844         case PORT_S3C2440:
845                 return "S3C2440";
846         case PORT_S3C2412:
847                 return "S3C2412";
848         default:
849                 return NULL;
850         }
851 }
852
853 #define MAP_SIZE (0x100)
854
855 static void s3c24xx_serial_release_port(struct uart_port *port)
856 {
857         release_mem_region(port->mapbase, MAP_SIZE);
858 }
859
860 static int s3c24xx_serial_request_port(struct uart_port *port)
861 {
862         const char *name = s3c24xx_serial_portname(port);
863         return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
864 }
865
866 static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
867 {
868         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
869
870         if (flags & UART_CONFIG_TYPE &&
871             s3c24xx_serial_request_port(port) == 0)
872                 port->type = info->type;
873 }
874
875 /*
876  * verify the new serial_struct (for TIOCSSERIAL).
877  */
878 static int
879 s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
880 {
881         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
882
883         if (ser->type != PORT_UNKNOWN && ser->type != info->type)
884                 return -EINVAL;
885
886         return 0;
887 }
888
889
890 #ifdef CONFIG_SERIAL_S3C2410_CONSOLE
891
892 static struct console s3c24xx_serial_console;
893
894 #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
895 #else
896 #define S3C24XX_SERIAL_CONSOLE NULL
897 #endif
898
899 static struct uart_ops s3c24xx_serial_ops = {
900         .pm             = s3c24xx_serial_pm,
901         .tx_empty       = s3c24xx_serial_tx_empty,
902         .get_mctrl      = s3c24xx_serial_get_mctrl,
903         .set_mctrl      = s3c24xx_serial_set_mctrl,
904         .stop_tx        = s3c24xx_serial_stop_tx,
905         .start_tx       = s3c24xx_serial_start_tx,
906         .stop_rx        = s3c24xx_serial_stop_rx,
907         .enable_ms      = s3c24xx_serial_enable_ms,
908         .break_ctl      = s3c24xx_serial_break_ctl,
909         .startup        = s3c24xx_serial_startup,
910         .shutdown       = s3c24xx_serial_shutdown,
911         .set_termios    = s3c24xx_serial_set_termios,
912         .type           = s3c24xx_serial_type,
913         .release_port   = s3c24xx_serial_release_port,
914         .request_port   = s3c24xx_serial_request_port,
915         .config_port    = s3c24xx_serial_config_port,
916         .verify_port    = s3c24xx_serial_verify_port,
917 };
918
919
920 static struct uart_driver s3c24xx_uart_drv = {
921         .owner          = THIS_MODULE,
922         .dev_name       = "s3c2410_serial",
923         .nr             = 3,
924         .cons           = S3C24XX_SERIAL_CONSOLE,
925         .driver_name    = S3C24XX_SERIAL_NAME,
926         .major          = S3C24XX_SERIAL_MAJOR,
927         .minor          = S3C24XX_SERIAL_MINOR,
928 };
929
930 static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
931         [0] = {
932                 .port = {
933                         .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
934                         .iotype         = UPIO_MEM,
935                         .irq            = IRQ_S3CUART_RX0,
936                         .uartclk        = 0,
937                         .fifosize       = 16,
938                         .ops            = &s3c24xx_serial_ops,
939                         .flags          = UPF_BOOT_AUTOCONF,
940                         .line           = 0,
941                 }
942         },
943         [1] = {
944                 .port = {
945                         .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
946                         .iotype         = UPIO_MEM,
947                         .irq            = IRQ_S3CUART_RX1,
948                         .uartclk        = 0,
949                         .fifosize       = 16,
950                         .ops            = &s3c24xx_serial_ops,
951                         .flags          = UPF_BOOT_AUTOCONF,
952                         .line           = 1,
953                 }
954         },
955 #if NR_PORTS > 2
956
957         [2] = {
958                 .port = {
959                         .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
960                         .iotype         = UPIO_MEM,
961                         .irq            = IRQ_S3CUART_RX2,
962                         .uartclk        = 0,
963                         .fifosize       = 16,
964                         .ops            = &s3c24xx_serial_ops,
965                         .flags          = UPF_BOOT_AUTOCONF,
966                         .line           = 2,
967                 }
968         }
969 #endif
970 };
971
972 /* s3c24xx_serial_resetport
973  *
974  * wrapper to call the specific reset for this port (reset the fifos
975  * and the settings)
976 */
977
978 static inline int s3c24xx_serial_resetport(struct uart_port * port,
979                                            struct s3c2410_uartcfg *cfg)
980 {
981         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
982
983         return (info->reset_port)(port, cfg);
984 }
985
986 /* s3c24xx_serial_init_port
987  *
988  * initialise a single serial port from the platform device given
989  */
990
991 static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
992                                     struct s3c24xx_uart_info *info,
993                                     struct platform_device *platdev)
994 {
995         struct uart_port *port = &ourport->port;
996         struct s3c2410_uartcfg *cfg;
997         struct resource *res;
998         int ret;
999
1000         dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
1001
1002         if (platdev == NULL)
1003                 return -ENODEV;
1004
1005         cfg = s3c24xx_dev_to_cfg(&platdev->dev);
1006
1007         if (port->mapbase != 0)
1008                 return 0;
1009
1010         if (cfg->hwport > 3)
1011                 return -EINVAL;
1012
1013         /* setup info for port */
1014         port->dev       = &platdev->dev;
1015         ourport->info   = info;
1016
1017         /* copy the info in from provided structure */
1018         ourport->port.fifosize = info->fifosize;
1019
1020         dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
1021
1022         port->uartclk = 1;
1023
1024         if (cfg->uart_flags & UPF_CONS_FLOW) {
1025                 dbg("s3c24xx_serial_init_port: enabling flow control\n");
1026                 port->flags |= UPF_CONS_FLOW;
1027         }
1028
1029         /* sort our the physical and virtual addresses for each UART */
1030
1031         res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
1032         if (res == NULL) {
1033                 printk(KERN_ERR "failed to find memory resource for uart\n");
1034                 return -EINVAL;
1035         }
1036
1037         dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
1038
1039         port->mapbase   = res->start;
1040         port->membase   = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
1041         ret = platform_get_irq(platdev, 0);
1042         if (ret < 0)
1043                 port->irq = 0;
1044         else
1045                 port->irq = ret;
1046
1047         ourport->clk    = clk_get(&platdev->dev, "uart");
1048
1049         dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld\n",
1050             port->mapbase, port->membase, port->irq, port->uartclk);
1051
1052         /* reset the fifos (and setup the uart) */
1053         s3c24xx_serial_resetport(port, cfg);
1054         return 0;
1055 }
1056
1057 /* Device driver serial port probe */
1058
1059 static int probe_index = 0;
1060
1061 static int s3c24xx_serial_probe(struct platform_device *dev,
1062                                 struct s3c24xx_uart_info *info)
1063 {
1064         struct s3c24xx_uart_port *ourport;
1065         int ret;
1066
1067         dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
1068
1069         ourport = &s3c24xx_serial_ports[probe_index];
1070         probe_index++;
1071
1072         dbg("%s: initialising port %p...\n", __func__, ourport);
1073
1074         ret = s3c24xx_serial_init_port(ourport, info, dev);
1075         if (ret < 0)
1076                 goto probe_err;
1077
1078         dbg("%s: adding port\n", __func__);
1079         uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
1080         platform_set_drvdata(dev, &ourport->port);
1081
1082         return 0;
1083
1084  probe_err:
1085         return ret;
1086 }
1087
1088 static int s3c24xx_serial_remove(struct platform_device *dev)
1089 {
1090         struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1091
1092         if (port)
1093                 uart_remove_one_port(&s3c24xx_uart_drv, port);
1094
1095         return 0;
1096 }
1097
1098 /* UART power management code */
1099
1100 #ifdef CONFIG_PM
1101
1102 static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
1103 {
1104         struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1105
1106         if (port)
1107                 uart_suspend_port(&s3c24xx_uart_drv, port);
1108
1109         return 0;
1110 }
1111
1112 static int s3c24xx_serial_resume(struct platform_device *dev)
1113 {
1114         struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1115         struct s3c24xx_uart_port *ourport = to_ourport(port);
1116
1117         if (port) {
1118                 clk_enable(ourport->clk);
1119                 s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
1120                 clk_disable(ourport->clk);
1121
1122                 uart_resume_port(&s3c24xx_uart_drv, port);
1123         }
1124
1125         return 0;
1126 }
1127
1128 #else
1129 #define s3c24xx_serial_suspend NULL
1130 #define s3c24xx_serial_resume  NULL
1131 #endif
1132
1133 static int s3c24xx_serial_init(struct platform_driver *drv,
1134                                struct s3c24xx_uart_info *info)
1135 {
1136         dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
1137         return platform_driver_register(drv);
1138 }
1139
1140
1141 /* now comes the code to initialise either the s3c2410 or s3c2440 serial
1142  * port information
1143 */
1144
1145 /* cpu specific variations on the serial port support */
1146
1147 #ifdef CONFIG_CPU_S3C2400
1148
1149 static int s3c2400_serial_getsource(struct uart_port *port,
1150                                     struct s3c24xx_uart_clksrc *clk)
1151 {
1152         clk->divisor = 1;
1153         clk->name = "pclk";
1154
1155         return 0;
1156 }
1157
1158 static int s3c2400_serial_setsource(struct uart_port *port,
1159                                     struct s3c24xx_uart_clksrc *clk)
1160 {
1161         return 0;
1162 }
1163
1164 static int s3c2400_serial_resetport(struct uart_port *port,
1165                                     struct s3c2410_uartcfg *cfg)
1166 {
1167         dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n",
1168             port, port->mapbase, cfg);
1169
1170         wr_regl(port, S3C2410_UCON,  cfg->ucon);
1171         wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1172
1173         /* reset both fifos */
1174
1175         wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1176         wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1177
1178         return 0;
1179 }
1180
1181 static struct s3c24xx_uart_info s3c2400_uart_inf = {
1182         .name           = "Samsung S3C2400 UART",
1183         .type           = PORT_S3C2400,
1184         .fifosize       = 16,
1185         .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
1186         .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
1187         .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
1188         .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
1189         .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
1190         .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
1191         .get_clksrc     = s3c2400_serial_getsource,
1192         .set_clksrc     = s3c2400_serial_setsource,
1193         .reset_port     = s3c2400_serial_resetport,
1194 };
1195
1196 static int s3c2400_serial_probe(struct platform_device *dev)
1197 {
1198         return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
1199 }
1200
1201 static struct platform_driver s3c2400_serial_drv = {
1202         .probe          = s3c2400_serial_probe,
1203         .remove         = s3c24xx_serial_remove,
1204         .suspend        = s3c24xx_serial_suspend,
1205         .resume         = s3c24xx_serial_resume,
1206         .driver         = {
1207                 .name   = "s3c2400-uart",
1208                 .owner  = THIS_MODULE,
1209         },
1210 };
1211
1212 static inline int s3c2400_serial_init(void)
1213 {
1214         return s3c24xx_serial_init(&s3c2400_serial_drv, &s3c2400_uart_inf);
1215 }
1216
1217 static inline void s3c2400_serial_exit(void)
1218 {
1219         platform_driver_unregister(&s3c2400_serial_drv);
1220 }
1221
1222 #define s3c2400_uart_inf_at &s3c2400_uart_inf
1223 #else
1224
1225 static inline int s3c2400_serial_init(void)
1226 {
1227         return 0;
1228 }
1229
1230 static inline void s3c2400_serial_exit(void)
1231 {
1232 }
1233
1234 #define s3c2400_uart_inf_at NULL
1235
1236 #endif /* CONFIG_CPU_S3C2400 */
1237
1238 /* S3C2410 support */
1239
1240 #ifdef CONFIG_CPU_S3C2410
1241
1242 static int s3c2410_serial_setsource(struct uart_port *port,
1243                                     struct s3c24xx_uart_clksrc *clk)
1244 {
1245         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1246
1247         if (strcmp(clk->name, "uclk") == 0)
1248                 ucon |= S3C2410_UCON_UCLK;
1249         else
1250                 ucon &= ~S3C2410_UCON_UCLK;
1251
1252         wr_regl(port, S3C2410_UCON, ucon);
1253         return 0;
1254 }
1255
1256 static int s3c2410_serial_getsource(struct uart_port *port,
1257                                     struct s3c24xx_uart_clksrc *clk)
1258 {
1259         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1260
1261         clk->divisor = 1;
1262         clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
1263
1264         return 0;
1265 }
1266
1267 static int s3c2410_serial_resetport(struct uart_port *port,
1268                                     struct s3c2410_uartcfg *cfg)
1269 {
1270         dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",
1271             port, port->mapbase, cfg);
1272
1273         wr_regl(port, S3C2410_UCON,  cfg->ucon);
1274         wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1275
1276         /* reset both fifos */
1277
1278         wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1279         wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1280
1281         return 0;
1282 }
1283
1284 static struct s3c24xx_uart_info s3c2410_uart_inf = {
1285         .name           = "Samsung S3C2410 UART",
1286         .type           = PORT_S3C2410,
1287         .fifosize       = 16,
1288         .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
1289         .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
1290         .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
1291         .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
1292         .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
1293         .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
1294         .get_clksrc     = s3c2410_serial_getsource,
1295         .set_clksrc     = s3c2410_serial_setsource,
1296         .reset_port     = s3c2410_serial_resetport,
1297 };
1298
1299 /* device management */
1300
1301 static int s3c2410_serial_probe(struct platform_device *dev)
1302 {
1303         return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
1304 }
1305
1306 static struct platform_driver s3c2410_serial_drv = {
1307         .probe          = s3c2410_serial_probe,
1308         .remove         = s3c24xx_serial_remove,
1309         .suspend        = s3c24xx_serial_suspend,
1310         .resume         = s3c24xx_serial_resume,
1311         .driver         = {
1312                 .name   = "s3c2410-uart",
1313                 .owner  = THIS_MODULE,
1314         },
1315 };
1316
1317 static inline int s3c2410_serial_init(void)
1318 {
1319         return s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf);
1320 }
1321
1322 static inline void s3c2410_serial_exit(void)
1323 {
1324         platform_driver_unregister(&s3c2410_serial_drv);
1325 }
1326
1327 #define s3c2410_uart_inf_at &s3c2410_uart_inf
1328 #else
1329
1330 static inline int s3c2410_serial_init(void)
1331 {
1332         return 0;
1333 }
1334
1335 static inline void s3c2410_serial_exit(void)
1336 {
1337 }
1338
1339 #define s3c2410_uart_inf_at NULL
1340
1341 #endif /* CONFIG_CPU_S3C2410 */
1342
1343 #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
1344
1345 static int s3c2440_serial_setsource(struct uart_port *port,
1346                                      struct s3c24xx_uart_clksrc *clk)
1347 {
1348         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1349
1350         // todo - proper fclk<>nonfclk switch //
1351
1352         ucon &= ~S3C2440_UCON_CLKMASK;
1353
1354         if (strcmp(clk->name, "uclk") == 0)
1355                 ucon |= S3C2440_UCON_UCLK;
1356         else if (strcmp(clk->name, "pclk") == 0)
1357                 ucon |= S3C2440_UCON_PCLK;
1358         else if (strcmp(clk->name, "fclk") == 0)
1359                 ucon |= S3C2440_UCON_FCLK;
1360         else {
1361                 printk(KERN_ERR "unknown clock source %s\n", clk->name);
1362                 return -EINVAL;
1363         }
1364
1365         wr_regl(port, S3C2410_UCON, ucon);
1366         return 0;
1367 }
1368
1369
1370 static int s3c2440_serial_getsource(struct uart_port *port,
1371                                     struct s3c24xx_uart_clksrc *clk)
1372 {
1373         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1374         unsigned long ucon0, ucon1, ucon2;
1375
1376         switch (ucon & S3C2440_UCON_CLKMASK) {
1377         case S3C2440_UCON_UCLK:
1378                 clk->divisor = 1;
1379                 clk->name = "uclk";
1380                 break;
1381
1382         case S3C2440_UCON_PCLK:
1383         case S3C2440_UCON_PCLK2:
1384                 clk->divisor = 1;
1385                 clk->name = "pclk";
1386                 break;
1387
1388         case S3C2440_UCON_FCLK:
1389                 /* the fun of calculating the uart divisors on
1390                  * the s3c2440 */
1391
1392                 ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
1393                 ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
1394                 ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
1395
1396                 printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
1397
1398                 ucon0 &= S3C2440_UCON0_DIVMASK;
1399                 ucon1 &= S3C2440_UCON1_DIVMASK;
1400                 ucon2 &= S3C2440_UCON2_DIVMASK;
1401
1402                 if (ucon0 != 0) {
1403                         clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
1404                         clk->divisor += 6;
1405                 } else if (ucon1 != 0) {
1406                         clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
1407                         clk->divisor += 21;
1408                 } else if (ucon2 != 0) {
1409                         clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
1410                         clk->divisor += 36;
1411                 } else {
1412                         /* manual calims 44, seems to be 9 */
1413                         clk->divisor = 9;
1414                 }
1415
1416                 clk->name = "fclk";
1417                 break;
1418         }
1419
1420         return 0;
1421 }
1422
1423 static int s3c2440_serial_resetport(struct uart_port *port,
1424                                     struct s3c2410_uartcfg *cfg)
1425 {
1426         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1427
1428         dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n",
1429             port, port->mapbase, cfg);
1430
1431         /* ensure we don't change the clock settings... */
1432
1433         ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));
1434
1435         wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
1436         wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1437
1438         /* reset both fifos */
1439
1440         wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1441         wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1442
1443         return 0;
1444 }
1445
1446 static struct s3c24xx_uart_info s3c2440_uart_inf = {
1447         .name           = "Samsung S3C2440 UART",
1448         .type           = PORT_S3C2440,
1449         .fifosize       = 64,
1450         .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
1451         .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
1452         .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
1453         .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
1454         .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
1455         .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
1456         .get_clksrc     = s3c2440_serial_getsource,
1457         .set_clksrc     = s3c2440_serial_setsource,
1458         .reset_port     = s3c2440_serial_resetport,
1459 };
1460
1461 /* device management */
1462
1463 static int s3c2440_serial_probe(struct platform_device *dev)
1464 {
1465         dbg("s3c2440_serial_probe: dev=%p\n", dev);
1466         return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
1467 }
1468
1469 static struct platform_driver s3c2440_serial_drv = {
1470         .probe          = s3c2440_serial_probe,
1471         .remove         = s3c24xx_serial_remove,
1472         .suspend        = s3c24xx_serial_suspend,
1473         .resume         = s3c24xx_serial_resume,
1474         .driver         = {
1475                 .name   = "s3c2440-uart",
1476                 .owner  = THIS_MODULE,
1477         },
1478 };
1479
1480
1481 static inline int s3c2440_serial_init(void)
1482 {
1483         return s3c24xx_serial_init(&s3c2440_serial_drv, &s3c2440_uart_inf);
1484 }
1485
1486 static inline void s3c2440_serial_exit(void)
1487 {
1488         platform_driver_unregister(&s3c2440_serial_drv);
1489 }
1490
1491 #define s3c2440_uart_inf_at &s3c2440_uart_inf
1492 #else
1493
1494 static inline int s3c2440_serial_init(void)
1495 {
1496         return 0;
1497 }
1498
1499 static inline void s3c2440_serial_exit(void)
1500 {
1501 }
1502
1503 #define s3c2440_uart_inf_at NULL
1504 #endif /* CONFIG_CPU_S3C2440 */
1505
1506 #if defined(CONFIG_CPU_S3C2412)
1507
1508 static int s3c2412_serial_setsource(struct uart_port *port,
1509                                      struct s3c24xx_uart_clksrc *clk)
1510 {
1511         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1512
1513         ucon &= ~S3C2412_UCON_CLKMASK;
1514
1515         if (strcmp(clk->name, "uclk") == 0)
1516                 ucon |= S3C2440_UCON_UCLK;
1517         else if (strcmp(clk->name, "pclk") == 0)
1518                 ucon |= S3C2440_UCON_PCLK;
1519         else if (strcmp(clk->name, "usysclk") == 0)
1520                 ucon |= S3C2412_UCON_USYSCLK;
1521         else {
1522                 printk(KERN_ERR "unknown clock source %s\n", clk->name);
1523                 return -EINVAL;
1524         }
1525
1526         wr_regl(port, S3C2410_UCON, ucon);
1527         return 0;
1528 }
1529
1530
1531 static int s3c2412_serial_getsource(struct uart_port *port,
1532                                     struct s3c24xx_uart_clksrc *clk)
1533 {
1534         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1535
1536         switch (ucon & S3C2412_UCON_CLKMASK) {
1537         case S3C2412_UCON_UCLK:
1538                 clk->divisor = 1;
1539                 clk->name = "uclk";
1540                 break;
1541
1542         case S3C2412_UCON_PCLK:
1543         case S3C2412_UCON_PCLK2:
1544                 clk->divisor = 1;
1545                 clk->name = "pclk";
1546                 break;
1547
1548         case S3C2412_UCON_USYSCLK:
1549                 clk->divisor = 1;
1550                 clk->name = "usysclk";
1551                 break;
1552         }
1553
1554         return 0;
1555 }
1556
1557 static int s3c2412_serial_resetport(struct uart_port *port,
1558                                     struct s3c2410_uartcfg *cfg)
1559 {
1560         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1561
1562         dbg("%s: port=%p (%08lx), cfg=%p\n",
1563             __func__, port, port->mapbase, cfg);
1564
1565         /* ensure we don't change the clock settings... */
1566
1567         ucon &= S3C2412_UCON_CLKMASK;
1568
1569         wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
1570         wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1571
1572         /* reset both fifos */
1573
1574         wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1575         wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1576
1577         return 0;
1578 }
1579
1580 static struct s3c24xx_uart_info s3c2412_uart_inf = {
1581         .name           = "Samsung S3C2412 UART",
1582         .type           = PORT_S3C2412,
1583         .fifosize       = 64,
1584         .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
1585         .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
1586         .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
1587         .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
1588         .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
1589         .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
1590         .get_clksrc     = s3c2412_serial_getsource,
1591         .set_clksrc     = s3c2412_serial_setsource,
1592         .reset_port     = s3c2412_serial_resetport,
1593 };
1594
1595 /* device management */
1596
1597 static int s3c2412_serial_probe(struct platform_device *dev)
1598 {
1599         dbg("s3c2440_serial_probe: dev=%p\n", dev);
1600         return s3c24xx_serial_probe(dev, &s3c2412_uart_inf);
1601 }
1602
1603 static struct platform_driver s3c2412_serial_drv = {
1604         .probe          = s3c2412_serial_probe,
1605         .remove         = s3c24xx_serial_remove,
1606         .suspend        = s3c24xx_serial_suspend,
1607         .resume         = s3c24xx_serial_resume,
1608         .driver         = {
1609                 .name   = "s3c2412-uart",
1610                 .owner  = THIS_MODULE,
1611         },
1612 };
1613
1614
1615 static inline int s3c2412_serial_init(void)
1616 {
1617         return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf);
1618 }
1619
1620 static inline void s3c2412_serial_exit(void)
1621 {
1622         platform_driver_unregister(&s3c2412_serial_drv);
1623 }
1624
1625 #define s3c2412_uart_inf_at &s3c2412_uart_inf
1626 #else
1627
1628 static inline int s3c2412_serial_init(void)
1629 {
1630         return 0;
1631 }
1632
1633 static inline void s3c2412_serial_exit(void)
1634 {
1635 }
1636
1637 #define s3c2412_uart_inf_at NULL
1638 #endif /* CONFIG_CPU_S3C2440 */
1639
1640
1641 /* module initialisation code */
1642
1643 static int __init s3c24xx_serial_modinit(void)
1644 {
1645         int ret;
1646
1647         ret = uart_register_driver(&s3c24xx_uart_drv);
1648         if (ret < 0) {
1649                 printk(KERN_ERR "failed to register UART driver\n");
1650                 return -1;
1651         }
1652
1653         s3c2400_serial_init();
1654         s3c2410_serial_init();
1655         s3c2412_serial_init();
1656         s3c2440_serial_init();
1657
1658         return 0;
1659 }
1660
1661 static void __exit s3c24xx_serial_modexit(void)
1662 {
1663         s3c2400_serial_exit();
1664         s3c2410_serial_exit();
1665         s3c2412_serial_exit();
1666         s3c2440_serial_exit();
1667
1668         uart_unregister_driver(&s3c24xx_uart_drv);
1669 }
1670
1671
1672 module_init(s3c24xx_serial_modinit);
1673 module_exit(s3c24xx_serial_modexit);
1674
1675 /* Console code */
1676
1677 #ifdef CONFIG_SERIAL_S3C2410_CONSOLE
1678
1679 static struct uart_port *cons_uart;
1680
1681 static int
1682 s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
1683 {
1684         struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
1685         unsigned long ufstat, utrstat;
1686
1687         if (ufcon & S3C2410_UFCON_FIFOMODE) {
1688                 /* fifo mode - check ammount of data in fifo registers... */
1689
1690                 ufstat = rd_regl(port, S3C2410_UFSTAT);
1691                 return (ufstat & info->tx_fifofull) ? 0 : 1;
1692         }
1693
1694         /* in non-fifo mode, we go and use the tx buffer empty */
1695
1696         utrstat = rd_regl(port, S3C2410_UTRSTAT);
1697         return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
1698 }
1699
1700 static void
1701 s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
1702 {
1703         unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
1704         while (!s3c24xx_serial_console_txrdy(port, ufcon))
1705                 barrier();
1706         wr_regb(cons_uart, S3C2410_UTXH, ch);
1707 }
1708
1709 static void
1710 s3c24xx_serial_console_write(struct console *co, const char *s,
1711                              unsigned int count)
1712 {
1713         uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
1714 }
1715
1716 static void __init
1717 s3c24xx_serial_get_options(struct uart_port *port, int *baud,
1718                            int *parity, int *bits)
1719 {
1720         struct s3c24xx_uart_clksrc clksrc;
1721         struct clk *clk;
1722         unsigned int ulcon;
1723         unsigned int ucon;
1724         unsigned int ubrdiv;
1725         unsigned long rate;
1726
1727         ulcon  = rd_regl(port, S3C2410_ULCON);
1728         ucon   = rd_regl(port, S3C2410_UCON);
1729         ubrdiv = rd_regl(port, S3C2410_UBRDIV);
1730
1731         dbg("s3c24xx_serial_get_options: port=%p\n"
1732             "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
1733             port, ulcon, ucon, ubrdiv);
1734
1735         if ((ucon & 0xf) != 0) {
1736                 /* consider the serial port configured if the tx/rx mode set */
1737
1738                 switch (ulcon & S3C2410_LCON_CSMASK) {
1739                 case S3C2410_LCON_CS5:
1740                         *bits = 5;
1741                         break;
1742                 case S3C2410_LCON_CS6:
1743                         *bits = 6;
1744                         break;
1745                 case S3C2410_LCON_CS7:
1746                         *bits = 7;
1747                         break;
1748                 default:
1749                 case S3C2410_LCON_CS8:
1750                         *bits = 8;
1751                         break;
1752                 }
1753
1754                 switch (ulcon & S3C2410_LCON_PMASK) {
1755                 case S3C2410_LCON_PEVEN:
1756                         *parity = 'e';
1757                         break;
1758
1759                 case S3C2410_LCON_PODD:
1760                         *parity = 'o';
1761                         break;
1762
1763                 case S3C2410_LCON_PNONE:
1764                 default:
1765                         *parity = 'n';
1766                 }
1767
1768                 /* now calculate the baud rate */
1769
1770                 s3c24xx_serial_getsource(port, &clksrc);
1771
1772                 clk = clk_get(port->dev, clksrc.name);
1773                 if (!IS_ERR(clk) && clk != NULL)
1774                         rate = clk_get_rate(clk) / clksrc.divisor;
1775                 else
1776                         rate = 1;
1777
1778
1779                 *baud = rate / ( 16 * (ubrdiv + 1));
1780                 dbg("calculated baud %d\n", *baud);
1781         }
1782
1783 }
1784
1785 /* s3c24xx_serial_init_ports
1786  *
1787  * initialise the serial ports from the machine provided initialisation
1788  * data.
1789 */
1790
1791 static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info *info)
1792 {
1793         struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
1794         struct platform_device **platdev_ptr;
1795         int i;
1796
1797         dbg("s3c24xx_serial_init_ports: initialising ports...\n");
1798
1799         platdev_ptr = s3c24xx_uart_devs;
1800
1801         for (i = 0; i < NR_PORTS; i++, ptr++, platdev_ptr++) {
1802                 s3c24xx_serial_init_port(ptr, info, *platdev_ptr);
1803         }
1804
1805         return 0;
1806 }
1807
1808 static int __init
1809 s3c24xx_serial_console_setup(struct console *co, char *options)
1810 {
1811         struct uart_port *port;
1812         int baud = 9600;
1813         int bits = 8;
1814         int parity = 'n';
1815         int flow = 'n';
1816
1817         dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
1818             co, co->index, options);
1819
1820         /* is this a valid port */
1821
1822         if (co->index == -1 || co->index >= NR_PORTS)
1823                 co->index = 0;
1824
1825         port = &s3c24xx_serial_ports[co->index].port;
1826
1827         /* is the port configured? */
1828
1829         if (port->mapbase == 0x0) {
1830                 co->index = 0;
1831                 port = &s3c24xx_serial_ports[co->index].port;
1832         }
1833
1834         cons_uart = port;
1835
1836         dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
1837
1838         /*
1839          * Check whether an invalid uart number has been specified, and
1840          * if so, search for the first available port that does have
1841          * console support.
1842          */
1843         if (options)
1844                 uart_parse_options(options, &baud, &parity, &bits, &flow);
1845         else
1846                 s3c24xx_serial_get_options(port, &baud, &parity, &bits);
1847
1848         dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
1849
1850         return uart_set_options(port, co, baud, parity, bits, flow);
1851 }
1852
1853 /* s3c24xx_serial_initconsole
1854  *
1855  * initialise the console from one of the uart drivers
1856 */
1857
1858 static struct console s3c24xx_serial_console =
1859 {
1860         .name           = S3C24XX_SERIAL_NAME,
1861         .device         = uart_console_device,
1862         .flags          = CON_PRINTBUFFER,
1863         .index          = -1,
1864         .write          = s3c24xx_serial_console_write,
1865         .setup          = s3c24xx_serial_console_setup
1866 };
1867
1868 static int s3c24xx_serial_initconsole(void)
1869 {
1870         struct s3c24xx_uart_info *info;
1871         struct platform_device *dev = s3c24xx_uart_devs[0];
1872
1873         dbg("s3c24xx_serial_initconsole\n");
1874
1875         /* select driver based on the cpu */
1876
1877         if (dev == NULL) {
1878                 printk(KERN_ERR "s3c24xx: no devices for console init\n");
1879                 return 0;
1880         }
1881
1882         if (strcmp(dev->name, "s3c2400-uart") == 0) {
1883                 info = s3c2400_uart_inf_at;
1884         } else if (strcmp(dev->name, "s3c2410-uart") == 0) {
1885                 info = s3c2410_uart_inf_at;
1886         } else if (strcmp(dev->name, "s3c2440-uart") == 0) {
1887                 info = s3c2440_uart_inf_at;
1888         } else if (strcmp(dev->name, "s3c2412-uart") == 0) {
1889                 info = s3c2412_uart_inf_at;
1890         } else {
1891                 printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name);
1892                 return 0;
1893         }
1894
1895         if (info == NULL) {
1896                 printk(KERN_ERR "s3c24xx: no driver for console\n");
1897                 return 0;
1898         }
1899
1900         s3c24xx_serial_console.data = &s3c24xx_uart_drv;
1901         s3c24xx_serial_init_ports(info);
1902
1903         register_console(&s3c24xx_serial_console);
1904         return 0;
1905 }
1906
1907 console_initcall(s3c24xx_serial_initconsole);
1908
1909 #endif /* CONFIG_SERIAL_S3C2410_CONSOLE */
1910
1911 MODULE_LICENSE("GPL");
1912 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
1913 MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver");
1914 MODULE_ALIAS("platform:s3c2400-uart");
1915 MODULE_ALIAS("platform:s3c2410-uart");
1916 MODULE_ALIAS("platform:s3c2412-uart");
1917 MODULE_ALIAS("platform:s3c2440-uart");