Linux Audio

Check our new training course

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