Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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