ia64/linux-2.6.18-xen.hg

view drivers/serial/s3c2410.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /*
2 * linux/drivers/serial/s3c2410.c
3 *
4 * Driver for onboard UARTs on the Samsung S3C24XX
5 *
6 * Based on drivers/char/serial.c and drivers/char/21285.c
7 *
8 * Ben Dooks, (c) 2003-2005 Simtec Electronics
9 * http://www.simtec.co.uk/products/SWLINUX/
10 *
11 * Changelog:
12 *
13 * 22-Jul-2004 BJD Finished off device rewrite
14 *
15 * 21-Jul-2004 BJD Thanks to <herbet@13thfloor.at> for pointing out
16 * problems with baud rate and loss of IR settings. Update
17 * to add configuration via platform_device structure
18 *
19 * 28-Sep-2004 BJD Re-write for the following items
20 * - S3C2410 and S3C2440 serial support
21 * - Power Management support
22 * - Fix console via IrDA devices
23 * - SysReq (Herbert P÷tzl)
24 * - Break character handling (Herbert P÷tzl)
25 * - spin-lock initialisation (Dimitry Andric)
26 * - added clock control
27 * - updated init code to use platform_device info
28 *
29 * 06-Mar-2005 BJD Add s3c2440 fclk clock source
30 *
31 * 09-Mar-2005 BJD Add s3c2400 support
32 *
33 * 10-Mar-2005 LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART
34 */
36 /* Note on 2440 fclk clock source handling
37 *
38 * Whilst it is possible to use the fclk as clock source, the method
39 * of properly switching too/from this is currently un-implemented, so
40 * whichever way is configured at startup is the one that will be used.
41 */
43 /* Hote on 2410 error handling
44 *
45 * The s3c2410 manual has a love/hate affair with the contents of the
46 * UERSTAT register in the UART blocks, and keeps marking some of the
47 * error bits as reserved. Having checked with the s3c2410x01,
48 * it copes with BREAKs properly, so I am happy to ignore the RESERVED
49 * feature from the latter versions of the manual.
50 *
51 * If it becomes aparrent that latter versions of the 2410 remove these
52 * bits, then action will have to be taken to differentiate the versions
53 * and change the policy on BREAK
54 *
55 * BJD, 04-Nov-2004
56 */
59 #if defined(CONFIG_SERIAL_S3C2410_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
60 #define SUPPORT_SYSRQ
61 #endif
63 #include <linux/module.h>
64 #include <linux/ioport.h>
65 #include <linux/platform_device.h>
66 #include <linux/init.h>
67 #include <linux/sysrq.h>
68 #include <linux/console.h>
69 #include <linux/tty.h>
70 #include <linux/tty_flip.h>
71 #include <linux/serial_core.h>
72 #include <linux/serial.h>
73 #include <linux/delay.h>
74 #include <linux/clk.h>
76 #include <asm/io.h>
77 #include <asm/irq.h>
79 #include <asm/hardware.h>
81 #include <asm/arch/regs-serial.h>
82 #include <asm/arch/regs-gpio.h>
84 /* structures */
86 struct s3c24xx_uart_info {
87 char *name;
88 unsigned int type;
89 unsigned int fifosize;
90 unsigned long rx_fifomask;
91 unsigned long rx_fifoshift;
92 unsigned long rx_fifofull;
93 unsigned long tx_fifomask;
94 unsigned long tx_fifoshift;
95 unsigned long tx_fifofull;
97 /* clock source control */
99 int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
100 int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
102 /* uart controls */
103 int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
104 };
106 struct s3c24xx_uart_port {
107 unsigned char rx_claimed;
108 unsigned char tx_claimed;
110 struct s3c24xx_uart_info *info;
111 struct s3c24xx_uart_clksrc *clksrc;
112 struct clk *clk;
113 struct clk *baudclk;
114 struct uart_port port;
115 };
118 /* configuration defines */
120 #if 0
121 #if 1
122 /* send debug to the low-level output routines */
124 extern void printascii(const char *);
126 static void
127 s3c24xx_serial_dbg(const char *fmt, ...)
128 {
129 va_list va;
130 char buff[256];
132 va_start(va, fmt);
133 vsprintf(buff, fmt, va);
134 va_end(va);
136 printascii(buff);
137 }
139 #define dbg(x...) s3c24xx_serial_dbg(x)
141 #else
142 #define dbg(x...) printk(KERN_DEBUG "s3c24xx: ");
143 #endif
144 #else /* no debug */
145 #define dbg(x...) do {} while(0)
146 #endif
148 /* UART name and device definitions */
150 #define S3C24XX_SERIAL_NAME "ttySAC"
151 #define S3C24XX_SERIAL_MAJOR 204
152 #define S3C24XX_SERIAL_MINOR 64
155 /* conversion functions */
157 #define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
158 #define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
160 /* we can support 3 uarts, but not always use them */
162 #ifdef CONFIG_CPU_S3C2400
163 #define NR_PORTS (2)
164 #else
165 #define NR_PORTS (3)
166 #endif
168 /* port irq numbers */
170 #define TX_IRQ(port) ((port)->irq + 1)
171 #define RX_IRQ(port) ((port)->irq)
173 /* register access controls */
175 #define portaddr(port, reg) ((port)->membase + (reg))
177 #define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
178 #define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
180 #define wr_regb(port, reg, val) \
181 do { __raw_writeb(val, portaddr(port, reg)); } while(0)
183 #define wr_regl(port, reg, val) \
184 do { __raw_writel(val, portaddr(port, reg)); } while(0)
186 /* macros to change one thing to another */
188 #define tx_enabled(port) ((port)->unused[0])
189 #define rx_enabled(port) ((port)->unused[1])
191 /* flag to ignore all characters comming in */
192 #define RXSTAT_DUMMY_READ (0x10000000)
194 static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
195 {
196 return container_of(port, struct s3c24xx_uart_port, port);
197 }
199 /* translate a port to the device name */
201 static inline const char *s3c24xx_serial_portname(struct uart_port *port)
202 {
203 return to_platform_device(port->dev)->name;
204 }
206 static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
207 {
208 return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
209 }
211 static void s3c24xx_serial_rx_enable(struct uart_port *port)
212 {
213 unsigned long flags;
214 unsigned int ucon, ufcon;
215 int count = 10000;
217 spin_lock_irqsave(&port->lock, flags);
219 while (--count && !s3c24xx_serial_txempty_nofifo(port))
220 udelay(100);
222 ufcon = rd_regl(port, S3C2410_UFCON);
223 ufcon |= S3C2410_UFCON_RESETRX;
224 wr_regl(port, S3C2410_UFCON, ufcon);
226 ucon = rd_regl(port, S3C2410_UCON);
227 ucon |= S3C2410_UCON_RXIRQMODE;
228 wr_regl(port, S3C2410_UCON, ucon);
230 rx_enabled(port) = 1;
231 spin_unlock_irqrestore(&port->lock, flags);
232 }
234 static void s3c24xx_serial_rx_disable(struct uart_port *port)
235 {
236 unsigned long flags;
237 unsigned int ucon;
239 spin_lock_irqsave(&port->lock, flags);
241 ucon = rd_regl(port, S3C2410_UCON);
242 ucon &= ~S3C2410_UCON_RXIRQMODE;
243 wr_regl(port, S3C2410_UCON, ucon);
245 rx_enabled(port) = 0;
246 spin_unlock_irqrestore(&port->lock, flags);
247 }
249 static void s3c24xx_serial_stop_tx(struct uart_port *port)
250 {
251 if (tx_enabled(port)) {
252 disable_irq(TX_IRQ(port));
253 tx_enabled(port) = 0;
254 if (port->flags & UPF_CONS_FLOW)
255 s3c24xx_serial_rx_enable(port);
256 }
257 }
259 static void s3c24xx_serial_start_tx(struct uart_port *port)
260 {
261 if (!tx_enabled(port)) {
262 if (port->flags & UPF_CONS_FLOW)
263 s3c24xx_serial_rx_disable(port);
265 enable_irq(TX_IRQ(port));
266 tx_enabled(port) = 1;
267 }
268 }
271 static void s3c24xx_serial_stop_rx(struct uart_port *port)
272 {
273 if (rx_enabled(port)) {
274 dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
275 disable_irq(RX_IRQ(port));
276 rx_enabled(port) = 0;
277 }
278 }
280 static void s3c24xx_serial_enable_ms(struct uart_port *port)
281 {
282 }
284 static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
285 {
286 return to_ourport(port)->info;
287 }
289 static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
290 {
291 if (port->dev == NULL)
292 return NULL;
294 return (struct s3c2410_uartcfg *)port->dev->platform_data;
295 }
297 static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
298 unsigned long ufstat)
299 {
300 struct s3c24xx_uart_info *info = ourport->info;
302 if (ufstat & info->rx_fifofull)
303 return info->fifosize;
305 return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
306 }
309 /* ? - where has parity gone?? */
310 #define S3C2410_UERSTAT_PARITY (0x1000)
312 static irqreturn_t
313 s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
314 {
315 struct s3c24xx_uart_port *ourport = dev_id;
316 struct uart_port *port = &ourport->port;
317 struct tty_struct *tty = port->info->tty;
318 unsigned int ufcon, ch, flag, ufstat, uerstat;
319 int max_count = 64;
321 while (max_count-- > 0) {
322 ufcon = rd_regl(port, S3C2410_UFCON);
323 ufstat = rd_regl(port, S3C2410_UFSTAT);
325 if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
326 break;
328 uerstat = rd_regl(port, S3C2410_UERSTAT);
329 ch = rd_regb(port, S3C2410_URXH);
331 if (port->flags & UPF_CONS_FLOW) {
332 int txe = s3c24xx_serial_txempty_nofifo(port);
334 if (rx_enabled(port)) {
335 if (!txe) {
336 rx_enabled(port) = 0;
337 continue;
338 }
339 } else {
340 if (txe) {
341 ufcon |= S3C2410_UFCON_RESETRX;
342 wr_regl(port, S3C2410_UFCON, ufcon);
343 rx_enabled(port) = 1;
344 goto out;
345 }
346 continue;
347 }
348 }
350 /* insert the character into the buffer */
352 flag = TTY_NORMAL;
353 port->icount.rx++;
355 if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
356 dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
357 ch, uerstat);
359 /* check for break */
360 if (uerstat & S3C2410_UERSTAT_BREAK) {
361 dbg("break!\n");
362 port->icount.brk++;
363 if (uart_handle_break(port))
364 goto ignore_char;
365 }
367 if (uerstat & S3C2410_UERSTAT_FRAME)
368 port->icount.frame++;
369 if (uerstat & S3C2410_UERSTAT_OVERRUN)
370 port->icount.overrun++;
372 uerstat &= port->read_status_mask;
374 if (uerstat & S3C2410_UERSTAT_BREAK)
375 flag = TTY_BREAK;
376 else if (uerstat & S3C2410_UERSTAT_PARITY)
377 flag = TTY_PARITY;
378 else if (uerstat & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN))
379 flag = TTY_FRAME;
380 }
382 if (uart_handle_sysrq_char(port, ch, regs))
383 goto ignore_char;
385 uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);
387 ignore_char:
388 continue;
389 }
390 tty_flip_buffer_push(tty);
392 out:
393 return IRQ_HANDLED;
394 }
396 static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id, struct pt_regs *regs)
397 {
398 struct s3c24xx_uart_port *ourport = id;
399 struct uart_port *port = &ourport->port;
400 struct circ_buf *xmit = &port->info->xmit;
401 int count = 256;
403 if (port->x_char) {
404 wr_regb(port, S3C2410_UTXH, port->x_char);
405 port->icount.tx++;
406 port->x_char = 0;
407 goto out;
408 }
410 /* if there isnt anything more to transmit, or the uart is now
411 * stopped, disable the uart and exit
412 */
414 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
415 s3c24xx_serial_stop_tx(port);
416 goto out;
417 }
419 /* try and drain the buffer... */
421 while (!uart_circ_empty(xmit) && count-- > 0) {
422 if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
423 break;
425 wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
426 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
427 port->icount.tx++;
428 }
430 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
431 uart_write_wakeup(port);
433 if (uart_circ_empty(xmit))
434 s3c24xx_serial_stop_tx(port);
436 out:
437 return IRQ_HANDLED;
438 }
440 static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
441 {
442 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
443 unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
444 unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
446 if (ufcon & S3C2410_UFCON_FIFOMODE) {
447 if ((ufstat & info->tx_fifomask) != 0 ||
448 (ufstat & info->tx_fifofull))
449 return 0;
451 return 1;
452 }
454 return s3c24xx_serial_txempty_nofifo(port);
455 }
457 /* no modem control lines */
458 static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
459 {
460 unsigned int umstat = rd_regb(port,S3C2410_UMSTAT);
462 if (umstat & S3C2410_UMSTAT_CTS)
463 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
464 else
465 return TIOCM_CAR | TIOCM_DSR;
466 }
468 static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
469 {
470 /* todo - possibly remove AFC and do manual CTS */
471 }
473 static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
474 {
475 unsigned long flags;
476 unsigned int ucon;
478 spin_lock_irqsave(&port->lock, flags);
480 ucon = rd_regl(port, S3C2410_UCON);
482 if (break_state)
483 ucon |= S3C2410_UCON_SBREAK;
484 else
485 ucon &= ~S3C2410_UCON_SBREAK;
487 wr_regl(port, S3C2410_UCON, ucon);
489 spin_unlock_irqrestore(&port->lock, flags);
490 }
492 static void s3c24xx_serial_shutdown(struct uart_port *port)
493 {
494 struct s3c24xx_uart_port *ourport = to_ourport(port);
496 if (ourport->tx_claimed) {
497 free_irq(TX_IRQ(port), ourport);
498 tx_enabled(port) = 0;
499 ourport->tx_claimed = 0;
500 }
502 if (ourport->rx_claimed) {
503 free_irq(RX_IRQ(port), ourport);
504 ourport->rx_claimed = 0;
505 rx_enabled(port) = 0;
506 }
507 }
510 static int s3c24xx_serial_startup(struct uart_port *port)
511 {
512 struct s3c24xx_uart_port *ourport = to_ourport(port);
513 int ret;
515 dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
516 port->mapbase, port->membase);
518 rx_enabled(port) = 1;
520 ret = request_irq(RX_IRQ(port),
521 s3c24xx_serial_rx_chars, 0,
522 s3c24xx_serial_portname(port), ourport);
524 if (ret != 0) {
525 printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port));
526 return ret;
527 }
529 ourport->rx_claimed = 1;
531 dbg("requesting tx irq...\n");
533 tx_enabled(port) = 1;
535 ret = request_irq(TX_IRQ(port),
536 s3c24xx_serial_tx_chars, 0,
537 s3c24xx_serial_portname(port), ourport);
539 if (ret) {
540 printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port));
541 goto err;
542 }
544 ourport->tx_claimed = 1;
546 dbg("s3c24xx_serial_startup ok\n");
548 /* the port reset code should have done the correct
549 * register setup for the port controls */
551 return ret;
553 err:
554 s3c24xx_serial_shutdown(port);
555 return ret;
556 }
558 /* power power management control */
560 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
561 unsigned int old)
562 {
563 struct s3c24xx_uart_port *ourport = to_ourport(port);
565 switch (level) {
566 case 3:
567 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
568 clk_disable(ourport->baudclk);
570 clk_disable(ourport->clk);
571 break;
573 case 0:
574 clk_enable(ourport->clk);
576 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
577 clk_enable(ourport->baudclk);
579 break;
580 default:
581 printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
582 }
583 }
585 /* baud rate calculation
586 *
587 * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
588 * of different sources, including the peripheral clock ("pclk") and an
589 * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
590 * with a programmable extra divisor.
591 *
592 * The following code goes through the clock sources, and calculates the
593 * baud clocks (and the resultant actual baud rates) and then tries to
594 * pick the closest one and select that.
595 *
596 */
599 #define MAX_CLKS (8)
601 static struct s3c24xx_uart_clksrc tmp_clksrc = {
602 .name = "pclk",
603 .min_baud = 0,
604 .max_baud = 0,
605 .divisor = 1,
606 };
608 static inline int
609 s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
610 {
611 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
613 return (info->get_clksrc)(port, c);
614 }
616 static inline int
617 s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
618 {
619 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
621 return (info->set_clksrc)(port, c);
622 }
624 struct baud_calc {
625 struct s3c24xx_uart_clksrc *clksrc;
626 unsigned int calc;
627 unsigned int quot;
628 struct clk *src;
629 };
631 static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
632 struct uart_port *port,
633 struct s3c24xx_uart_clksrc *clksrc,
634 unsigned int baud)
635 {
636 unsigned long rate;
638 calc->src = clk_get(port->dev, clksrc->name);
639 if (calc->src == NULL || IS_ERR(calc->src))
640 return 0;
642 rate = clk_get_rate(calc->src);
643 rate /= clksrc->divisor;
645 calc->clksrc = clksrc;
646 calc->quot = (rate + (8 * baud)) / (16 * baud);
647 calc->calc = (rate / (calc->quot * 16));
649 calc->quot--;
650 return 1;
651 }
653 static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
654 struct s3c24xx_uart_clksrc **clksrc,
655 struct clk **clk,
656 unsigned int baud)
657 {
658 struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
659 struct s3c24xx_uart_clksrc *clkp;
660 struct baud_calc res[MAX_CLKS];
661 struct baud_calc *resptr, *best, *sptr;
662 int i;
664 clkp = cfg->clocks;
665 best = NULL;
667 if (cfg->clocks_size < 2) {
668 if (cfg->clocks_size == 0)
669 clkp = &tmp_clksrc;
671 /* check to see if we're sourcing fclk, and if so we're
672 * going to have to update the clock source
673 */
675 if (strcmp(clkp->name, "fclk") == 0) {
676 struct s3c24xx_uart_clksrc src;
678 s3c24xx_serial_getsource(port, &src);
680 /* check that the port already using fclk, and if
681 * not, then re-select fclk
682 */
684 if (strcmp(src.name, clkp->name) == 0) {
685 s3c24xx_serial_setsource(port, clkp);
686 s3c24xx_serial_getsource(port, &src);
687 }
689 clkp->divisor = src.divisor;
690 }
692 s3c24xx_serial_calcbaud(res, port, clkp, baud);
693 best = res;
694 resptr = best + 1;
695 } else {
696 resptr = res;
698 for (i = 0; i < cfg->clocks_size; i++, clkp++) {
699 if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
700 resptr++;
701 }
702 }
704 /* ok, we now need to select the best clock we found */
706 if (!best) {
707 unsigned int deviation = (1<<30)|((1<<30)-1);
708 int calc_deviation;
710 for (sptr = res; sptr < resptr; sptr++) {
711 printk(KERN_DEBUG
712 "found clk %p (%s) quot %d, calc %d\n",
713 sptr->clksrc, sptr->clksrc->name,
714 sptr->quot, sptr->calc);
716 calc_deviation = baud - sptr->calc;
717 if (calc_deviation < 0)
718 calc_deviation = -calc_deviation;
720 if (calc_deviation < deviation) {
721 best = sptr;
722 deviation = calc_deviation;
723 }
724 }
726 printk(KERN_DEBUG "best %p (deviation %d)\n", best, deviation);
727 }
729 printk(KERN_DEBUG "selected clock %p (%s) quot %d, calc %d\n",
730 best->clksrc, best->clksrc->name, best->quot, best->calc);
732 /* store results to pass back */
734 *clksrc = best->clksrc;
735 *clk = best->src;
737 return best->quot;
738 }
740 static void s3c24xx_serial_set_termios(struct uart_port *port,
741 struct termios *termios,
742 struct termios *old)
743 {
744 struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
745 struct s3c24xx_uart_port *ourport = to_ourport(port);
746 struct s3c24xx_uart_clksrc *clksrc = NULL;
747 struct clk *clk = NULL;
748 unsigned long flags;
749 unsigned int baud, quot;
750 unsigned int ulcon;
751 unsigned int umcon;
753 /*
754 * We don't support modem control lines.
755 */
756 termios->c_cflag &= ~(HUPCL | CMSPAR);
757 termios->c_cflag |= CLOCAL;
759 /*
760 * Ask the core to calculate the divisor for us.
761 */
763 baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
765 if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
766 quot = port->custom_divisor;
767 else
768 quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
770 /* check to see if we need to change clock source */
772 if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
773 s3c24xx_serial_setsource(port, clksrc);
775 if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
776 clk_disable(ourport->baudclk);
777 ourport->baudclk = NULL;
778 }
780 clk_enable(clk);
782 ourport->clksrc = clksrc;
783 ourport->baudclk = clk;
784 }
786 switch (termios->c_cflag & CSIZE) {
787 case CS5:
788 dbg("config: 5bits/char\n");
789 ulcon = S3C2410_LCON_CS5;
790 break;
791 case CS6:
792 dbg("config: 6bits/char\n");
793 ulcon = S3C2410_LCON_CS6;
794 break;
795 case CS7:
796 dbg("config: 7bits/char\n");
797 ulcon = S3C2410_LCON_CS7;
798 break;
799 case CS8:
800 default:
801 dbg("config: 8bits/char\n");
802 ulcon = S3C2410_LCON_CS8;
803 break;
804 }
806 /* preserve original lcon IR settings */
807 ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
809 if (termios->c_cflag & CSTOPB)
810 ulcon |= S3C2410_LCON_STOPB;
812 umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
814 if (termios->c_cflag & PARENB) {
815 if (termios->c_cflag & PARODD)
816 ulcon |= S3C2410_LCON_PODD;
817 else
818 ulcon |= S3C2410_LCON_PEVEN;
819 } else {
820 ulcon |= S3C2410_LCON_PNONE;
821 }
823 spin_lock_irqsave(&port->lock, flags);
825 dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);
827 wr_regl(port, S3C2410_ULCON, ulcon);
828 wr_regl(port, S3C2410_UBRDIV, quot);
829 wr_regl(port, S3C2410_UMCON, umcon);
831 dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
832 rd_regl(port, S3C2410_ULCON),
833 rd_regl(port, S3C2410_UCON),
834 rd_regl(port, S3C2410_UFCON));
836 /*
837 * Update the per-port timeout.
838 */
839 uart_update_timeout(port, termios->c_cflag, baud);
841 /*
842 * Which character status flags are we interested in?
843 */
844 port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
845 if (termios->c_iflag & INPCK)
846 port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
848 /*
849 * Which character status flags should we ignore?
850 */
851 port->ignore_status_mask = 0;
852 if (termios->c_iflag & IGNPAR)
853 port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
854 if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
855 port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
857 /*
858 * Ignore all characters if CREAD is not set.
859 */
860 if ((termios->c_cflag & CREAD) == 0)
861 port->ignore_status_mask |= RXSTAT_DUMMY_READ;
863 spin_unlock_irqrestore(&port->lock, flags);
864 }
866 static const char *s3c24xx_serial_type(struct uart_port *port)
867 {
868 switch (port->type) {
869 case PORT_S3C2410:
870 return "S3C2410";
871 case PORT_S3C2440:
872 return "S3C2440";
873 case PORT_S3C2412:
874 return "S3C2412";
875 default:
876 return NULL;
877 }
878 }
880 #define MAP_SIZE (0x100)
882 static void s3c24xx_serial_release_port(struct uart_port *port)
883 {
884 release_mem_region(port->mapbase, MAP_SIZE);
885 }
887 static int s3c24xx_serial_request_port(struct uart_port *port)
888 {
889 const char *name = s3c24xx_serial_portname(port);
890 return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
891 }
893 static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
894 {
895 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
897 if (flags & UART_CONFIG_TYPE &&
898 s3c24xx_serial_request_port(port) == 0)
899 port->type = info->type;
900 }
902 /*
903 * verify the new serial_struct (for TIOCSSERIAL).
904 */
905 static int
906 s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
907 {
908 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
910 if (ser->type != PORT_UNKNOWN && ser->type != info->type)
911 return -EINVAL;
913 return 0;
914 }
917 #ifdef CONFIG_SERIAL_S3C2410_CONSOLE
919 static struct console s3c24xx_serial_console;
921 #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
922 #else
923 #define S3C24XX_SERIAL_CONSOLE NULL
924 #endif
926 static struct uart_ops s3c24xx_serial_ops = {
927 .pm = s3c24xx_serial_pm,
928 .tx_empty = s3c24xx_serial_tx_empty,
929 .get_mctrl = s3c24xx_serial_get_mctrl,
930 .set_mctrl = s3c24xx_serial_set_mctrl,
931 .stop_tx = s3c24xx_serial_stop_tx,
932 .start_tx = s3c24xx_serial_start_tx,
933 .stop_rx = s3c24xx_serial_stop_rx,
934 .enable_ms = s3c24xx_serial_enable_ms,
935 .break_ctl = s3c24xx_serial_break_ctl,
936 .startup = s3c24xx_serial_startup,
937 .shutdown = s3c24xx_serial_shutdown,
938 .set_termios = s3c24xx_serial_set_termios,
939 .type = s3c24xx_serial_type,
940 .release_port = s3c24xx_serial_release_port,
941 .request_port = s3c24xx_serial_request_port,
942 .config_port = s3c24xx_serial_config_port,
943 .verify_port = s3c24xx_serial_verify_port,
944 };
947 static struct uart_driver s3c24xx_uart_drv = {
948 .owner = THIS_MODULE,
949 .dev_name = "s3c2410_serial",
950 .nr = 3,
951 .cons = S3C24XX_SERIAL_CONSOLE,
952 .driver_name = S3C24XX_SERIAL_NAME,
953 .major = S3C24XX_SERIAL_MAJOR,
954 .minor = S3C24XX_SERIAL_MINOR,
955 };
957 static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
958 [0] = {
959 .port = {
960 .lock = SPIN_LOCK_UNLOCKED,
961 .iotype = UPIO_MEM,
962 .irq = IRQ_S3CUART_RX0,
963 .uartclk = 0,
964 .fifosize = 16,
965 .ops = &s3c24xx_serial_ops,
966 .flags = UPF_BOOT_AUTOCONF,
967 .line = 0,
968 }
969 },
970 [1] = {
971 .port = {
972 .lock = SPIN_LOCK_UNLOCKED,
973 .iotype = UPIO_MEM,
974 .irq = IRQ_S3CUART_RX1,
975 .uartclk = 0,
976 .fifosize = 16,
977 .ops = &s3c24xx_serial_ops,
978 .flags = UPF_BOOT_AUTOCONF,
979 .line = 1,
980 }
981 },
982 #if NR_PORTS > 2
984 [2] = {
985 .port = {
986 .lock = SPIN_LOCK_UNLOCKED,
987 .iotype = UPIO_MEM,
988 .irq = IRQ_S3CUART_RX2,
989 .uartclk = 0,
990 .fifosize = 16,
991 .ops = &s3c24xx_serial_ops,
992 .flags = UPF_BOOT_AUTOCONF,
993 .line = 2,
994 }
995 }
996 #endif
997 };
999 /* s3c24xx_serial_resetport
1001 * wrapper to call the specific reset for this port (reset the fifos
1002 * and the settings)
1003 */
1005 static inline int s3c24xx_serial_resetport(struct uart_port * port,
1006 struct s3c2410_uartcfg *cfg)
1008 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
1010 return (info->reset_port)(port, cfg);
1013 /* s3c24xx_serial_init_port
1015 * initialise a single serial port from the platform device given
1016 */
1018 static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
1019 struct s3c24xx_uart_info *info,
1020 struct platform_device *platdev)
1022 struct uart_port *port = &ourport->port;
1023 struct s3c2410_uartcfg *cfg;
1024 struct resource *res;
1026 dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
1028 if (platdev == NULL)
1029 return -ENODEV;
1031 cfg = s3c24xx_dev_to_cfg(&platdev->dev);
1033 if (port->mapbase != 0)
1034 return 0;
1036 if (cfg->hwport > 3)
1037 return -EINVAL;
1039 /* setup info for port */
1040 port->dev = &platdev->dev;
1041 ourport->info = info;
1043 /* copy the info in from provided structure */
1044 ourport->port.fifosize = info->fifosize;
1046 dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
1048 port->uartclk = 1;
1050 if (cfg->uart_flags & UPF_CONS_FLOW) {
1051 dbg("s3c24xx_serial_init_port: enabling flow control\n");
1052 port->flags |= UPF_CONS_FLOW;
1055 /* sort our the physical and virtual addresses for each UART */
1057 res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
1058 if (res == NULL) {
1059 printk(KERN_ERR "failed to find memory resource for uart\n");
1060 return -EINVAL;
1063 dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
1065 port->mapbase = res->start;
1066 port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
1067 port->irq = platform_get_irq(platdev, 0);
1068 if (port->irq < 0)
1069 port->irq = 0;
1071 ourport->clk = clk_get(&platdev->dev, "uart");
1073 dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld\n",
1074 port->mapbase, port->membase, port->irq, port->uartclk);
1076 /* reset the fifos (and setup the uart) */
1077 s3c24xx_serial_resetport(port, cfg);
1078 return 0;
1081 /* Device driver serial port probe */
1083 static int probe_index = 0;
1085 static int s3c24xx_serial_probe(struct platform_device *dev,
1086 struct s3c24xx_uart_info *info)
1088 struct s3c24xx_uart_port *ourport;
1089 int ret;
1091 dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
1093 ourport = &s3c24xx_serial_ports[probe_index];
1094 probe_index++;
1096 dbg("%s: initialising port %p...\n", __FUNCTION__, ourport);
1098 ret = s3c24xx_serial_init_port(ourport, info, dev);
1099 if (ret < 0)
1100 goto probe_err;
1102 dbg("%s: adding port\n", __FUNCTION__);
1103 uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
1104 platform_set_drvdata(dev, &ourport->port);
1106 return 0;
1108 probe_err:
1109 return ret;
1112 static int s3c24xx_serial_remove(struct platform_device *dev)
1114 struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1116 if (port)
1117 uart_remove_one_port(&s3c24xx_uart_drv, port);
1119 return 0;
1122 /* UART power management code */
1124 #ifdef CONFIG_PM
1126 static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
1128 struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1130 if (port)
1131 uart_suspend_port(&s3c24xx_uart_drv, port);
1133 return 0;
1136 static int s3c24xx_serial_resume(struct platform_device *dev)
1138 struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1139 struct s3c24xx_uart_port *ourport = to_ourport(port);
1141 if (port) {
1142 clk_enable(ourport->clk);
1143 s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
1144 clk_disable(ourport->clk);
1146 uart_resume_port(&s3c24xx_uart_drv, port);
1149 return 0;
1152 #else
1153 #define s3c24xx_serial_suspend NULL
1154 #define s3c24xx_serial_resume NULL
1155 #endif
1157 static int s3c24xx_serial_init(struct platform_driver *drv,
1158 struct s3c24xx_uart_info *info)
1160 dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
1161 return platform_driver_register(drv);
1165 /* now comes the code to initialise either the s3c2410 or s3c2440 serial
1166 * port information
1167 */
1169 /* cpu specific variations on the serial port support */
1171 #ifdef CONFIG_CPU_S3C2400
1173 static int s3c2400_serial_getsource(struct uart_port *port,
1174 struct s3c24xx_uart_clksrc *clk)
1176 clk->divisor = 1;
1177 clk->name = "pclk";
1179 return 0;
1182 static int s3c2400_serial_setsource(struct uart_port *port,
1183 struct s3c24xx_uart_clksrc *clk)
1185 return 0;
1188 static int s3c2400_serial_resetport(struct uart_port *port,
1189 struct s3c2410_uartcfg *cfg)
1191 dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n",
1192 port, port->mapbase, cfg);
1194 wr_regl(port, S3C2410_UCON, cfg->ucon);
1195 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1197 /* reset both fifos */
1199 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1200 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1202 return 0;
1205 static struct s3c24xx_uart_info s3c2400_uart_inf = {
1206 .name = "Samsung S3C2400 UART",
1207 .type = PORT_S3C2400,
1208 .fifosize = 16,
1209 .rx_fifomask = S3C2410_UFSTAT_RXMASK,
1210 .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT,
1211 .rx_fifofull = S3C2410_UFSTAT_RXFULL,
1212 .tx_fifofull = S3C2410_UFSTAT_TXFULL,
1213 .tx_fifomask = S3C2410_UFSTAT_TXMASK,
1214 .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT,
1215 .get_clksrc = s3c2400_serial_getsource,
1216 .set_clksrc = s3c2400_serial_setsource,
1217 .reset_port = s3c2400_serial_resetport,
1218 };
1220 static int s3c2400_serial_probe(struct platform_device *dev)
1222 return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
1225 static struct platform_driver s3c2400_serial_drv = {
1226 .probe = s3c2400_serial_probe,
1227 .remove = s3c24xx_serial_remove,
1228 .suspend = s3c24xx_serial_suspend,
1229 .resume = s3c24xx_serial_resume,
1230 .driver = {
1231 .name = "s3c2400-uart",
1232 .owner = THIS_MODULE,
1233 },
1234 };
1236 static inline int s3c2400_serial_init(void)
1238 return s3c24xx_serial_init(&s3c2400_serial_drv, &s3c2400_uart_inf);
1241 static inline void s3c2400_serial_exit(void)
1243 platform_driver_unregister(&s3c2400_serial_drv);
1246 #define s3c2400_uart_inf_at &s3c2400_uart_inf
1247 #else
1249 static inline int s3c2400_serial_init(void)
1251 return 0;
1254 static inline void s3c2400_serial_exit(void)
1258 #define s3c2400_uart_inf_at NULL
1260 #endif /* CONFIG_CPU_S3C2400 */
1262 /* S3C2410 support */
1264 #ifdef CONFIG_CPU_S3C2410
1266 static int s3c2410_serial_setsource(struct uart_port *port,
1267 struct s3c24xx_uart_clksrc *clk)
1269 unsigned long ucon = rd_regl(port, S3C2410_UCON);
1271 if (strcmp(clk->name, "uclk") == 0)
1272 ucon |= S3C2410_UCON_UCLK;
1273 else
1274 ucon &= ~S3C2410_UCON_UCLK;
1276 wr_regl(port, S3C2410_UCON, ucon);
1277 return 0;
1280 static int s3c2410_serial_getsource(struct uart_port *port,
1281 struct s3c24xx_uart_clksrc *clk)
1283 unsigned long ucon = rd_regl(port, S3C2410_UCON);
1285 clk->divisor = 1;
1286 clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
1288 return 0;
1291 static int s3c2410_serial_resetport(struct uart_port *port,
1292 struct s3c2410_uartcfg *cfg)
1294 dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",
1295 port, port->mapbase, cfg);
1297 wr_regl(port, S3C2410_UCON, cfg->ucon);
1298 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1300 /* reset both fifos */
1302 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1303 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1305 return 0;
1308 static struct s3c24xx_uart_info s3c2410_uart_inf = {
1309 .name = "Samsung S3C2410 UART",
1310 .type = PORT_S3C2410,
1311 .fifosize = 16,
1312 .rx_fifomask = S3C2410_UFSTAT_RXMASK,
1313 .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT,
1314 .rx_fifofull = S3C2410_UFSTAT_RXFULL,
1315 .tx_fifofull = S3C2410_UFSTAT_TXFULL,
1316 .tx_fifomask = S3C2410_UFSTAT_TXMASK,
1317 .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT,
1318 .get_clksrc = s3c2410_serial_getsource,
1319 .set_clksrc = s3c2410_serial_setsource,
1320 .reset_port = s3c2410_serial_resetport,
1321 };
1323 /* device management */
1325 static int s3c2410_serial_probe(struct platform_device *dev)
1327 return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
1330 static struct platform_driver s3c2410_serial_drv = {
1331 .probe = s3c2410_serial_probe,
1332 .remove = s3c24xx_serial_remove,
1333 .suspend = s3c24xx_serial_suspend,
1334 .resume = s3c24xx_serial_resume,
1335 .driver = {
1336 .name = "s3c2410-uart",
1337 .owner = THIS_MODULE,
1338 },
1339 };
1341 static inline int s3c2410_serial_init(void)
1343 return s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf);
1346 static inline void s3c2410_serial_exit(void)
1348 platform_driver_unregister(&s3c2410_serial_drv);
1351 #define s3c2410_uart_inf_at &s3c2410_uart_inf
1352 #else
1354 static inline int s3c2410_serial_init(void)
1356 return 0;
1359 static inline void s3c2410_serial_exit(void)
1363 #define s3c2410_uart_inf_at NULL
1365 #endif /* CONFIG_CPU_S3C2410 */
1367 #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
1369 static int s3c2440_serial_setsource(struct uart_port *port,
1370 struct s3c24xx_uart_clksrc *clk)
1372 unsigned long ucon = rd_regl(port, S3C2410_UCON);
1374 // todo - proper fclk<>nonfclk switch //
1376 ucon &= ~S3C2440_UCON_CLKMASK;
1378 if (strcmp(clk->name, "uclk") == 0)
1379 ucon |= S3C2440_UCON_UCLK;
1380 else if (strcmp(clk->name, "pclk") == 0)
1381 ucon |= S3C2440_UCON_PCLK;
1382 else if (strcmp(clk->name, "fclk") == 0)
1383 ucon |= S3C2440_UCON_FCLK;
1384 else {
1385 printk(KERN_ERR "unknown clock source %s\n", clk->name);
1386 return -EINVAL;
1389 wr_regl(port, S3C2410_UCON, ucon);
1390 return 0;
1394 static int s3c2440_serial_getsource(struct uart_port *port,
1395 struct s3c24xx_uart_clksrc *clk)
1397 unsigned long ucon = rd_regl(port, S3C2410_UCON);
1398 unsigned long ucon0, ucon1, ucon2;
1400 switch (ucon & S3C2440_UCON_CLKMASK) {
1401 case S3C2440_UCON_UCLK:
1402 clk->divisor = 1;
1403 clk->name = "uclk";
1404 break;
1406 case S3C2440_UCON_PCLK:
1407 case S3C2440_UCON_PCLK2:
1408 clk->divisor = 1;
1409 clk->name = "pclk";
1410 break;
1412 case S3C2440_UCON_FCLK:
1413 /* the fun of calculating the uart divisors on
1414 * the s3c2440 */
1416 ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
1417 ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
1418 ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
1420 printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
1422 ucon0 &= S3C2440_UCON0_DIVMASK;
1423 ucon1 &= S3C2440_UCON1_DIVMASK;
1424 ucon2 &= S3C2440_UCON2_DIVMASK;
1426 if (ucon0 != 0) {
1427 clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
1428 clk->divisor += 6;
1429 } else if (ucon1 != 0) {
1430 clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
1431 clk->divisor += 21;
1432 } else if (ucon2 != 0) {
1433 clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
1434 clk->divisor += 36;
1435 } else {
1436 /* manual calims 44, seems to be 9 */
1437 clk->divisor = 9;
1440 clk->name = "fclk";
1441 break;
1444 return 0;
1447 static int s3c2440_serial_resetport(struct uart_port *port,
1448 struct s3c2410_uartcfg *cfg)
1450 unsigned long ucon = rd_regl(port, S3C2410_UCON);
1452 dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n",
1453 port, port->mapbase, cfg);
1455 /* ensure we don't change the clock settings... */
1457 ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));
1459 wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
1460 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1462 /* reset both fifos */
1464 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1465 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1467 return 0;
1470 static struct s3c24xx_uart_info s3c2440_uart_inf = {
1471 .name = "Samsung S3C2440 UART",
1472 .type = PORT_S3C2440,
1473 .fifosize = 64,
1474 .rx_fifomask = S3C2440_UFSTAT_RXMASK,
1475 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
1476 .rx_fifofull = S3C2440_UFSTAT_RXFULL,
1477 .tx_fifofull = S3C2440_UFSTAT_TXFULL,
1478 .tx_fifomask = S3C2440_UFSTAT_TXMASK,
1479 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
1480 .get_clksrc = s3c2440_serial_getsource,
1481 .set_clksrc = s3c2440_serial_setsource,
1482 .reset_port = s3c2440_serial_resetport,
1483 };
1485 /* device management */
1487 static int s3c2440_serial_probe(struct platform_device *dev)
1489 dbg("s3c2440_serial_probe: dev=%p\n", dev);
1490 return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
1493 static struct platform_driver s3c2440_serial_drv = {
1494 .probe = s3c2440_serial_probe,
1495 .remove = s3c24xx_serial_remove,
1496 .suspend = s3c24xx_serial_suspend,
1497 .resume = s3c24xx_serial_resume,
1498 .driver = {
1499 .name = "s3c2440-uart",
1500 .owner = THIS_MODULE,
1501 },
1502 };
1505 static inline int s3c2440_serial_init(void)
1507 return s3c24xx_serial_init(&s3c2440_serial_drv, &s3c2440_uart_inf);
1510 static inline void s3c2440_serial_exit(void)
1512 platform_driver_unregister(&s3c2440_serial_drv);
1515 #define s3c2440_uart_inf_at &s3c2440_uart_inf
1516 #else
1518 static inline int s3c2440_serial_init(void)
1520 return 0;
1523 static inline void s3c2440_serial_exit(void)
1527 #define s3c2440_uart_inf_at NULL
1528 #endif /* CONFIG_CPU_S3C2440 */
1530 #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
1532 static int s3c2412_serial_setsource(struct uart_port *port,
1533 struct s3c24xx_uart_clksrc *clk)
1535 unsigned long ucon = rd_regl(port, S3C2410_UCON);
1537 ucon &= ~S3C2412_UCON_CLKMASK;
1539 if (strcmp(clk->name, "uclk") == 0)
1540 ucon |= S3C2440_UCON_UCLK;
1541 else if (strcmp(clk->name, "pclk") == 0)
1542 ucon |= S3C2440_UCON_PCLK;
1543 else if (strcmp(clk->name, "usysclk") == 0)
1544 ucon |= S3C2412_UCON_USYSCLK;
1545 else {
1546 printk(KERN_ERR "unknown clock source %s\n", clk->name);
1547 return -EINVAL;
1550 wr_regl(port, S3C2410_UCON, ucon);
1551 return 0;
1555 static int s3c2412_serial_getsource(struct uart_port *port,
1556 struct s3c24xx_uart_clksrc *clk)
1558 unsigned long ucon = rd_regl(port, S3C2410_UCON);
1560 switch (ucon & S3C2412_UCON_CLKMASK) {
1561 case S3C2412_UCON_UCLK:
1562 clk->divisor = 1;
1563 clk->name = "uclk";
1564 break;
1566 case S3C2412_UCON_PCLK:
1567 case S3C2412_UCON_PCLK2:
1568 clk->divisor = 1;
1569 clk->name = "pclk";
1570 break;
1572 case S3C2412_UCON_USYSCLK:
1573 clk->divisor = 1;
1574 clk->name = "usysclk";
1575 break;
1578 return 0;
1581 static int s3c2412_serial_resetport(struct uart_port *port,
1582 struct s3c2410_uartcfg *cfg)
1584 unsigned long ucon = rd_regl(port, S3C2410_UCON);
1586 dbg("%s: port=%p (%08lx), cfg=%p\n",
1587 __FUNCTION__, port, port->mapbase, cfg);
1589 /* ensure we don't change the clock settings... */
1591 ucon &= S3C2412_UCON_CLKMASK;
1593 wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
1594 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1596 /* reset both fifos */
1598 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1599 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1601 return 0;
1604 static struct s3c24xx_uart_info s3c2412_uart_inf = {
1605 .name = "Samsung S3C2412 UART",
1606 .type = PORT_S3C2412,
1607 .fifosize = 64,
1608 .rx_fifomask = S3C2440_UFSTAT_RXMASK,
1609 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
1610 .rx_fifofull = S3C2440_UFSTAT_RXFULL,
1611 .tx_fifofull = S3C2440_UFSTAT_TXFULL,
1612 .tx_fifomask = S3C2440_UFSTAT_TXMASK,
1613 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
1614 .get_clksrc = s3c2412_serial_getsource,
1615 .set_clksrc = s3c2412_serial_setsource,
1616 .reset_port = s3c2412_serial_resetport,
1617 };
1619 /* device management */
1621 static int s3c2412_serial_probe(struct platform_device *dev)
1623 dbg("s3c2440_serial_probe: dev=%p\n", dev);
1624 return s3c24xx_serial_probe(dev, &s3c2412_uart_inf);
1627 static struct platform_driver s3c2412_serial_drv = {
1628 .probe = s3c2412_serial_probe,
1629 .remove = s3c24xx_serial_remove,
1630 .suspend = s3c24xx_serial_suspend,
1631 .resume = s3c24xx_serial_resume,
1632 .driver = {
1633 .name = "s3c2412-uart",
1634 .owner = THIS_MODULE,
1635 },
1636 };
1639 static inline int s3c2412_serial_init(void)
1641 return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf);
1644 static inline void s3c2412_serial_exit(void)
1646 platform_driver_unregister(&s3c2412_serial_drv);
1649 #define s3c2412_uart_inf_at &s3c2412_uart_inf
1650 #else
1652 static inline int s3c2412_serial_init(void)
1654 return 0;
1657 static inline void s3c2412_serial_exit(void)
1661 #define s3c2412_uart_inf_at NULL
1662 #endif /* CONFIG_CPU_S3C2440 */
1665 /* module initialisation code */
1667 static int __init s3c24xx_serial_modinit(void)
1669 int ret;
1671 ret = uart_register_driver(&s3c24xx_uart_drv);
1672 if (ret < 0) {
1673 printk(KERN_ERR "failed to register UART driver\n");
1674 return -1;
1677 s3c2400_serial_init();
1678 s3c2410_serial_init();
1679 s3c2412_serial_init();
1680 s3c2440_serial_init();
1682 return 0;
1685 static void __exit s3c24xx_serial_modexit(void)
1687 s3c2400_serial_exit();
1688 s3c2410_serial_exit();
1689 s3c2412_serial_exit();
1690 s3c2440_serial_exit();
1692 uart_unregister_driver(&s3c24xx_uart_drv);
1696 module_init(s3c24xx_serial_modinit);
1697 module_exit(s3c24xx_serial_modexit);
1699 /* Console code */
1701 #ifdef CONFIG_SERIAL_S3C2410_CONSOLE
1703 static struct uart_port *cons_uart;
1705 static int
1706 s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
1708 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
1709 unsigned long ufstat, utrstat;
1711 if (ufcon & S3C2410_UFCON_FIFOMODE) {
1712 /* fifo mode - check ammount of data in fifo registers... */
1714 ufstat = rd_regl(port, S3C2410_UFSTAT);
1715 return (ufstat & info->tx_fifofull) ? 0 : 1;
1718 /* in non-fifo mode, we go and use the tx buffer empty */
1720 utrstat = rd_regl(port, S3C2410_UTRSTAT);
1721 return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
1724 static void
1725 s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
1727 unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
1728 while (!s3c24xx_serial_console_txrdy(port, ufcon))
1729 barrier();
1730 wr_regb(cons_uart, S3C2410_UTXH, ch);
1733 static void
1734 s3c24xx_serial_console_write(struct console *co, const char *s,
1735 unsigned int count)
1737 uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
1740 static void __init
1741 s3c24xx_serial_get_options(struct uart_port *port, int *baud,
1742 int *parity, int *bits)
1744 struct s3c24xx_uart_clksrc clksrc;
1745 struct clk *clk;
1746 unsigned int ulcon;
1747 unsigned int ucon;
1748 unsigned int ubrdiv;
1749 unsigned long rate;
1751 ulcon = rd_regl(port, S3C2410_ULCON);
1752 ucon = rd_regl(port, S3C2410_UCON);
1753 ubrdiv = rd_regl(port, S3C2410_UBRDIV);
1755 dbg("s3c24xx_serial_get_options: port=%p\n"
1756 "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
1757 port, ulcon, ucon, ubrdiv);
1759 if ((ucon & 0xf) != 0) {
1760 /* consider the serial port configured if the tx/rx mode set */
1762 switch (ulcon & S3C2410_LCON_CSMASK) {
1763 case S3C2410_LCON_CS5:
1764 *bits = 5;
1765 break;
1766 case S3C2410_LCON_CS6:
1767 *bits = 6;
1768 break;
1769 case S3C2410_LCON_CS7:
1770 *bits = 7;
1771 break;
1772 default:
1773 case S3C2410_LCON_CS8:
1774 *bits = 8;
1775 break;
1778 switch (ulcon & S3C2410_LCON_PMASK) {
1779 case S3C2410_LCON_PEVEN:
1780 *parity = 'e';
1781 break;
1783 case S3C2410_LCON_PODD:
1784 *parity = 'o';
1785 break;
1787 case S3C2410_LCON_PNONE:
1788 default:
1789 *parity = 'n';
1792 /* now calculate the baud rate */
1794 s3c24xx_serial_getsource(port, &clksrc);
1796 clk = clk_get(port->dev, clksrc.name);
1797 if (!IS_ERR(clk) && clk != NULL)
1798 rate = clk_get_rate(clk) / clksrc.divisor;
1799 else
1800 rate = 1;
1803 *baud = rate / ( 16 * (ubrdiv + 1));
1804 dbg("calculated baud %d\n", *baud);
1809 /* s3c24xx_serial_init_ports
1811 * initialise the serial ports from the machine provided initialisation
1812 * data.
1813 */
1815 static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info *info)
1817 struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
1818 struct platform_device **platdev_ptr;
1819 int i;
1821 dbg("s3c24xx_serial_init_ports: initialising ports...\n");
1823 platdev_ptr = s3c24xx_uart_devs;
1825 for (i = 0; i < NR_PORTS; i++, ptr++, platdev_ptr++) {
1826 s3c24xx_serial_init_port(ptr, info, *platdev_ptr);
1829 return 0;
1832 static int __init
1833 s3c24xx_serial_console_setup(struct console *co, char *options)
1835 struct uart_port *port;
1836 int baud = 9600;
1837 int bits = 8;
1838 int parity = 'n';
1839 int flow = 'n';
1841 dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
1842 co, co->index, options);
1844 /* is this a valid port */
1846 if (co->index == -1 || co->index >= NR_PORTS)
1847 co->index = 0;
1849 port = &s3c24xx_serial_ports[co->index].port;
1851 /* is the port configured? */
1853 if (port->mapbase == 0x0) {
1854 co->index = 0;
1855 port = &s3c24xx_serial_ports[co->index].port;
1858 cons_uart = port;
1860 dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
1862 /*
1863 * Check whether an invalid uart number has been specified, and
1864 * if so, search for the first available port that does have
1865 * console support.
1866 */
1867 if (options)
1868 uart_parse_options(options, &baud, &parity, &bits, &flow);
1869 else
1870 s3c24xx_serial_get_options(port, &baud, &parity, &bits);
1872 dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
1874 return uart_set_options(port, co, baud, parity, bits, flow);
1877 /* s3c24xx_serial_initconsole
1879 * initialise the console from one of the uart drivers
1880 */
1882 static struct console s3c24xx_serial_console =
1884 .name = S3C24XX_SERIAL_NAME,
1885 .device = uart_console_device,
1886 .flags = CON_PRINTBUFFER,
1887 .index = -1,
1888 .write = s3c24xx_serial_console_write,
1889 .setup = s3c24xx_serial_console_setup
1890 };
1892 static int s3c24xx_serial_initconsole(void)
1894 struct s3c24xx_uart_info *info;
1895 struct platform_device *dev = s3c24xx_uart_devs[0];
1897 dbg("s3c24xx_serial_initconsole\n");
1899 /* select driver based on the cpu */
1901 if (dev == NULL) {
1902 printk(KERN_ERR "s3c24xx: no devices for console init\n");
1903 return 0;
1906 if (strcmp(dev->name, "s3c2400-uart") == 0) {
1907 info = s3c2400_uart_inf_at;
1908 } else if (strcmp(dev->name, "s3c2410-uart") == 0) {
1909 info = s3c2410_uart_inf_at;
1910 } else if (strcmp(dev->name, "s3c2440-uart") == 0) {
1911 info = s3c2440_uart_inf_at;
1912 } else if (strcmp(dev->name, "s3c2412-uart") == 0) {
1913 info = s3c2412_uart_inf_at;
1914 } else {
1915 printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name);
1916 return 0;
1919 if (info == NULL) {
1920 printk(KERN_ERR "s3c24xx: no driver for console\n");
1921 return 0;
1924 s3c24xx_serial_console.data = &s3c24xx_uart_drv;
1925 s3c24xx_serial_init_ports(info);
1927 register_console(&s3c24xx_serial_console);
1928 return 0;
1931 console_initcall(s3c24xx_serial_initconsole);
1933 #endif /* CONFIG_SERIAL_S3C2410_CONSOLE */
1935 MODULE_LICENSE("GPL");
1936 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
1937 MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver");