Linux Audio

Check our new training course

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