Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
   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");