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