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