serial_s3c2410.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:13k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * device for S3C2410 Development Board
  3.  *
  4.  * Author: Janghoon Lyu <nandy@mizi.com>
  5.  * Date  : $Date: 2002/05/14 02:19:42 $ 
  6.  *
  7.  * $Revision: 1.1.2.4 $
  8.    Mon May 20 2002 Janghoon Lyu <nandy@mizi.com>
  9.    - initial, based on linux/drivers/serial/serial_s3c2400.c
  10.    Wed Aug 14 2002 Yong-iL Joh <tolkien@mizi.com>
  11.    - adopt new irq scheme
  12.  *
  13.  * This file is subject to the terms and conditions of the GNU General Public
  14.  * License.  See the file COPYING in the main directory of this archive
  15.  * for more details.
  16.  */
  17. #include <linux/config.h>
  18. #include <linux/module.h>
  19. #include <linux/kernel.h>
  20. #include <linux/init.h>
  21. #include <linux/slab.h>
  22. #include <linux/console.h>
  23. #include <linux/serial_core.h>
  24. #include <asm/irq.h>
  25. #include <asm/hardware.h>
  26. #include <asm/arch/cpu_s3c2410.h>
  27. #define CONFIG_USE_ERR_IRQ 1     
  28. #define SERIAL_S3C2410_MAJOR 204
  29. #define CALLOUT_S3C2410_MAJOR 205
  30. #define MINOR_START 5
  31. #define UART_NR 3
  32. #define UART_ULCON(port) __REG((port)->iobase + 0x00)
  33. #define UART_UCON(port) __REG((port)->iobase + 0x04)
  34. #define UART_UFCON(port) __REG((port)->iobase + 0x08)
  35. #define UART_UTRSTAT(port) __REG((port)->iobase + 0x10)
  36. #define UART_UERSTAT(port) __REG((port)->iobase + 0x14)
  37. #define UART_UTXH(port) __REG((port)->iobase + 0x20)
  38. #define UART_URXH(port) __REG((port)->iobase + 0x24)
  39. #define UART_UBRDIV(port) __REG((port)->iobase + 0x28)
  40. #define ERR_IRQ(port) ((port)->irq + 2)
  41. #define TX_IRQ(port) ((port)->irq + 1)
  42. #define RX_IRQ(port) ((port)->irq)
  43. static struct tty_driver normal, callout;
  44. static struct tty_struct *s3c2410_table[UART_NR];
  45. static struct termios *s3c2410_termios[UART_NR], *s3c2410_termios_locked[UART_NR];
  46. static void s3c2410uart_stop_tx(struct uart_port *port, u_int from_tty) {
  47. disable_irq(TX_IRQ(port));
  48. }
  49. static void s3c2410uart_start_tx(struct uart_port *port, u_int nonempty,
  50.  u_int from_tty) {
  51. enable_irq(TX_IRQ(port));
  52. }
  53. static void s3c2410uart_stop_rx(struct uart_port *port) {
  54. disable_irq(RX_IRQ(port));
  55. }
  56. static void s3c2410uart_enable_ms(struct uart_port *port)
  57. {
  58. }
  59. static u_int s3c2410uart_tx_empty(struct uart_port *port)
  60. {
  61.     return (UART_UTRSTAT(port) & UTRSTAT_TR_EMP ? 0 : TIOCSER_TEMT);
  62. }
  63. static u_int s3c2410uart_get_mctrl(struct uart_port *port)
  64. {
  65.     return (TIOCM_CTS | TIOCM_DSR | TIOCM_CAR);
  66. }
  67. static void s3c2410uart_set_mctrl(struct uart_port *port, u_int mctrl)
  68. {
  69. }
  70. static void s3c2410uart_break_ctl(struct uart_port *port, int break_state)
  71. {
  72.     u_int ucon;
  73.     ucon = UART_UCON(port);
  74.     if (break_state == -1)
  75. ucon |= UCON_BRK_SIG;
  76.     else
  77. ucon &= ~UCON_BRK_SIG;
  78.     UART_UCON(port) = ucon;
  79. }
  80. static void s3c2410uart_rx_interrupt(int irq, void *dev_id,
  81.      struct pt_regs *regs) {
  82.     struct uart_info *info = dev_id;
  83.     struct tty_struct *tty = info->tty;
  84.     unsigned int status, ch, max_count = 256;
  85.     struct uart_port *port = info->port;
  86.     status = UART_UTRSTAT(port);
  87.     while ((status & UTRSTAT_RX_RDY) && max_count--) {
  88.       if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
  89. tty->flip.tqueue.routine((void *) tty);
  90. if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
  91.   printk(KERN_WARNING "TTY_DONT_FLIP setn");
  92.   return;
  93. }
  94.       }
  95.       ch = UART_URXH(port);
  96.       *tty->flip.char_buf_ptr = ch;
  97.       *tty->flip.flag_buf_ptr = TTY_NORMAL;
  98.       port->icount.rx++;
  99.       tty->flip.flag_buf_ptr++;
  100.       tty->flip.char_buf_ptr++;
  101.       tty->flip.count++;
  102.       /* No error handling just yet.
  103.        * On the MX1 these are seperate
  104.        * IRQs, so we need to deal with
  105.        * the sanity of 5 IRQs for one
  106.        * serial port before we deal
  107.        * with the error path properly.
  108.        */
  109.       status = UART_UTRSTAT(port);
  110.     }
  111.     tty_flip_buffer_push(tty);
  112.     return;
  113. }
  114. static void s3c2410uart_tx_interrupt(int irq, void *dev_id,
  115.      struct pt_regs *reg) {
  116.     struct uart_info *info = dev_id;
  117.     struct uart_port *port = info->port;
  118.     int count;
  119.     if (port->x_char) {
  120. UART_UTXH(port) = port->x_char;
  121. port->icount.tx++;
  122. port->x_char = 0;
  123. return;
  124.     }
  125.     if (info->xmit.head == info->xmit.tail
  126.         || info->tty->stopped || info->tty->hw_stopped) {
  127.       s3c2410uart_stop_tx(info->port, 0);
  128.       return;
  129.     }
  130.     count = port->fifosize >> 1;
  131.     do {
  132. UART_UTXH(port) = info->xmit.buf[info->xmit.tail];
  133. info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
  134. port->icount.tx++;
  135. if (info->xmit.head == info->xmit.tail)
  136.     break;
  137.     } while (--count > 0);
  138.     if (CIRC_CNT(info->xmit.head, info->xmit.tail,
  139.  UART_XMIT_SIZE) < WAKEUP_CHARS)
  140. uart_event(info, EVT_WRITE_WAKEUP);
  141.     if (info->xmit.head == info->xmit.tail)
  142. s3c2410uart_stop_tx(info->port, 0);
  143. }
  144. #ifdef CONFIG_USE_ERR_IRQ
  145. static void s3c2410uart_err_interrupt(int irq, void *dev_id,
  146.       struct pt_regs *reg) {
  147.     struct uart_info *info = dev_id;
  148.     struct uart_port *port = info->port;
  149.     struct tty_struct *tty = info->tty;
  150.     unsigned char err = UART_UERSTAT(port) & UART_ERR_MASK;
  151.     unsigned int ch, flg;
  152.     ch = UART_URXH(port);
  153.     if (!(err & (UERSTAT_BRK | UERSTAT_FRAME |
  154.  UERSTAT_PARITY | UERSTAT_OVERRUN)))
  155.       return;
  156.     if (err & UERSTAT_BRK)
  157.       port->icount.brk++;
  158.     if (err & UERSTAT_FRAME)
  159.       port->icount.frame++;
  160.     if (err & UERSTAT_PARITY)
  161.       port->icount.parity++;
  162.     if (err & UERSTAT_OVERRUN)
  163.       port->icount.overrun++;
  164.     err &= port->read_status_mask;
  165.     if (err & UERSTAT_PARITY)
  166.       flg = TTY_PARITY;
  167.     else if (err & UERSTAT_FRAME)
  168.       flg = TTY_FRAME;
  169.     else
  170.       flg = TTY_NORMAL;
  171.     if (err & UERSTAT_OVERRUN) {
  172.       *tty->flip.char_buf_ptr = ch;
  173.       *tty->flip.flag_buf_ptr = flg;
  174.       tty->flip.flag_buf_ptr++;
  175.       tty->flip.char_buf_ptr++;
  176.       tty->flip.count++;
  177.       if (tty->flip.count < TTY_FLIPBUF_SIZE) {
  178. ch = 0;
  179. flg = TTY_OVERRUN;
  180.       }
  181.     }
  182.      
  183.     *tty->flip.flag_buf_ptr++ = flg;
  184.     *tty->flip.char_buf_ptr++ = ch;
  185.     tty->flip.count++;
  186. }
  187. #endif
  188. static int s3c2410uart_startup(struct uart_port *port, struct uart_info *info)
  189. {
  190.     int ret, flags;
  191.     u_int ucon;
  192.     ret = request_irq(RX_IRQ(port), s3c2410uart_rx_interrupt, SA_INTERRUPT,
  193.       "serial_s3c2410_rx", info);
  194.     if (ret) goto rx_failed;
  195.     ret = request_irq(TX_IRQ(port), s3c2410uart_tx_interrupt, SA_INTERRUPT,
  196.       "serial_s3c2410_tx", info);
  197.     if (ret) goto tx_failed;
  198. #ifdef CONFIG_USE_ERR_IRQ
  199.     ret = request_irq(ERR_IRQ(port), s3c2410uart_err_interrupt, SA_INTERRUPT,
  200.       "serial_s3c2410_err", info);
  201.     if (ret) goto err_failed;
  202. #endif
  203.     ucon = (UCON_TX_INT_LVL | UCON_RX_INT_LVL |
  204.     UCON_TX_INT | UCON_RX_INT | UCON_RX_TIMEOUT);
  205. #if defined(CONFIG_IRDA) || defined(CONFIG_IRDA_MODULE)
  206.       ULCON2 |= ULCON_IR | ULCON_PAR_NONE | ULCON_WL8 | ULCON_ONE_STOP;
  207. #endif
  208.     save_flags(flags);
  209.     cli();
  210.     
  211.     UART_UCON(port) = ucon;
  212.     
  213.     sti();
  214.     restore_flags(flags);
  215.     return 0;
  216. #ifdef CONFIG_USE_ERR_IRQ
  217.  err_failed:
  218.     free_irq(TX_IRQ(port), info);
  219. #endif
  220.  tx_failed:
  221.     free_irq(RX_IRQ(port), info);
  222.  rx_failed:
  223.     return ret;
  224. }
  225. static void s3c2410uart_shutdown(struct uart_port *port, struct uart_info *info)
  226. {
  227.     free_irq(RX_IRQ(port), info);
  228.     free_irq(TX_IRQ(port), info);
  229. #ifdef CONFIG_USE_ERR_IRQ
  230.     free_irq(ERR_IRQ(port), info);
  231. #endif
  232.     UART_UCON(port) = 0x0;
  233. }
  234. static void s3c2410uart_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
  235. {
  236.     u_int ulcon, ufcon;
  237.     int flags;
  238.     ufcon = UART_UFCON(port);
  239.     switch (cflag & CSIZE) {
  240. case CS5: ulcon = ULCON_WL5; break;
  241. case CS6: ulcon = ULCON_WL6; break;
  242. case CS7: ulcon = ULCON_WL7; break;
  243. default: ulcon = ULCON_WL8; break;
  244.     }
  245.     if (cflag & CSTOPB)
  246. ulcon |= ULCON_STOP;
  247.     if (cflag & PARENB) {
  248. if (!(cflag & PARODD))
  249.     ulcon |= ULCON_PAR_EVEN;
  250.     }
  251.     
  252.     if (port->fifosize > 1)
  253. ufcon |= UFCON_FIFO_EN;
  254.     
  255.     port->read_status_mask =  UERSTAT_OVERRUN;
  256.     if (iflag & INPCK)
  257. port->read_status_mask |= UERSTAT_PARITY | UERSTAT_FRAME;
  258.     port->ignore_status_mask = 0;
  259.     if (iflag & IGNPAR)
  260. port->ignore_status_mask |= UERSTAT_FRAME | UERSTAT_PARITY;
  261.     if (iflag & IGNBRK) {
  262. if (iflag & IGNPAR)
  263.     port->ignore_status_mask |= UERSTAT_OVERRUN;
  264.     }
  265.     quot -= 1;
  266.     save_flags(flags);
  267.     cli();
  268.     UART_UFCON(port) = ufcon;
  269.     UART_ULCON(port) = (UART_ULCON(port) & ~(ULCON_PAR | ULCON_WL)) | ulcon;
  270.     UART_UBRDIV(port) = quot;
  271.     sti();
  272.     restore_flags(flags);
  273. }
  274. static const char *s3c2410uart_type(struct uart_port *port)
  275. {
  276.     return port->type == PORT_S3C2410 ? "S3C2410" : NULL;
  277. }
  278. static void s3c2410uart_config_port(struct uart_port *port, int flags)
  279. {
  280.     if (flags & UART_CONFIG_TYPE)
  281. port->type = PORT_S3C2410;
  282. }
  283. static void s3c2410uart_release_port(struct uart_port *port)
  284. {
  285. }
  286. static int s3c2410uart_request_port(struct uart_port *port)
  287. {
  288. return 0;
  289. }
  290. static struct uart_ops s3c2410_pops = {
  291.         tx_empty: s3c2410uart_tx_empty,
  292. set_mctrl: s3c2410uart_set_mctrl,
  293. get_mctrl: s3c2410uart_get_mctrl,
  294. stop_tx: s3c2410uart_stop_tx,
  295. start_tx: s3c2410uart_start_tx,
  296. stop_rx: s3c2410uart_stop_rx,
  297. enable_ms: s3c2410uart_enable_ms,
  298. break_ctl: s3c2410uart_break_ctl,
  299. startup: s3c2410uart_startup,
  300. shutdown: s3c2410uart_shutdown,
  301. change_speed: s3c2410uart_change_speed,
  302. type: s3c2410uart_type,
  303. config_port: s3c2410uart_config_port,
  304. release_port: s3c2410uart_release_port,
  305. request_port: s3c2410uart_request_port,
  306. };
  307. static struct uart_port s3c2410_ports[UART_NR] = {
  308.   {
  309. iobase: (unsigned long)(UART0_CTL_BASE),
  310. iotype: SERIAL_IO_PORT,
  311. irq: IRQ_RXD0,
  312. uartclk: 130252800,
  313. fifosize: 16,
  314. ops: &s3c2410_pops,
  315. type: PORT_S3C2410,
  316. flags: ASYNC_BOOT_AUTOCONF,
  317.   }, {
  318. iobase: (unsigned long)(UART1_CTL_BASE),
  319. iotype: SERIAL_IO_PORT,
  320. irq: IRQ_RXD1,
  321. uartclk: 130252800,
  322. fifosize: 16,
  323. ops: &s3c2410_pops,
  324. type: PORT_S3C2410,
  325. flags: ASYNC_BOOT_AUTOCONF,
  326.   }, {
  327. iobase: (unsigned long)(UART2_CTL_BASE),
  328. iotype: SERIAL_IO_PORT,
  329. irq: IRQ_RXD2,
  330. uartclk: 130252800,
  331. fifosize: 16,
  332. ops: &s3c2410_pops,
  333. type: PORT_S3C2410,
  334. flags: ASYNC_BOOT_AUTOCONF,
  335.   }
  336. };
  337. void __init s3c2410_register_uart(int idx, int port)
  338. {
  339.         if (idx >= UART_NR) {
  340.                 printk(KERN_ERR "%s: bad index number %dn", __FUNCTION__, idx);
  341.                 return;
  342.         }
  343. s3c2410_ports[idx].uartclk = s3c2410_get_bus_clk(GET_PCLK);
  344.         switch (port) {
  345.         case 0:
  346.   s3c2410_ports[idx].iobase = (unsigned long)(UART0_CTL_BASE);
  347.   s3c2410_ports[idx].irq  = IRQ_RXD0;
  348.   CLKCON |= CLKCON_UART0;
  349.   break;
  350.         case 1:
  351.   s3c2410_ports[idx].iobase = (unsigned long)(UART1_CTL_BASE);
  352.   s3c2410_ports[idx].irq  = IRQ_RXD1;
  353.   CLKCON |= CLKCON_UART1;
  354.   break;
  355.         case 2:
  356.   s3c2410_ports[idx].iobase = (unsigned long)(UART2_CTL_BASE);
  357.   s3c2410_ports[idx].irq  = IRQ_RXD2;
  358.   CLKCON |= CLKCON_UART2;
  359.   break;
  360.         default:
  361.   printk(KERN_ERR "%s : bad port number %dn", __FUNCTION__, port);
  362.         }
  363. }
  364. #ifdef CONFIG_SERIAL_S3C2410_CONSOLE
  365. static void s3c2410_console_write(struct console *co, const char *s, u_int count)
  366. {
  367.     int i;
  368.     struct uart_port *port = s3c2410_ports + co->index;
  369.     for (i = 0; i < count; i++) {
  370. while (!(UART_UTRSTAT(port) & UTRSTAT_TX_EMP));
  371. UART_UTXH(port) = s[i];
  372. if (s[i] == 'n') {
  373.     while (!(UART_UTRSTAT(port) & UTRSTAT_TX_EMP));
  374.      UART_UTXH(port) = 'r';
  375. }
  376.     }
  377. }
  378. static int s3c2410_console_wait_key(struct console *co)
  379. {
  380.     int c;
  381.     struct uart_port *port = s3c2410_ports + co->index;
  382.     while (!(UART_UTRSTAT(port) & UTRSTAT_RX_RDY));
  383.      c = UART_URXH(port);
  384.     return c;
  385. }
  386. static kdev_t s3c2410_console_device(struct console *co)
  387. {
  388. return MKDEV(SERIAL_S3C2410_MAJOR, MINOR_START + co->index);
  389. }
  390. static int __init s3c2410_console_setup(struct console *co, char *options)
  391. {
  392. struct uart_port *port;
  393. int baud = 115200;
  394. int bits = 8;
  395. int parity = 'n';
  396. int flow = 'n';
  397. port = uart_get_console(s3c2410_ports, UART_NR, co);
  398. if (options)
  399. uart_parse_options(options, &baud, &parity, &bits, &flow);
  400. return uart_set_options(port, co, baud, parity, bits, flow);
  401. }
  402. static struct console s3c2410_cons = {
  403. name: "ttyS",
  404. write: s3c2410_console_write,
  405. device: s3c2410_console_device,
  406. wait_key: s3c2410_console_wait_key,
  407. setup: s3c2410_console_setup,
  408. flags: CON_PRINTBUFFER,
  409. index: -1,
  410. };
  411. void __init s3c2410_console_init(void)
  412. {
  413. register_console(&s3c2410_cons);
  414. }
  415. #define S3C2410_CONSOLE &s3c2410_cons
  416. #else /* CONFIG_SERIAL_S3C2410_CONSOLE */
  417. #define S3C2410_CONSOLE NULL
  418. #endif /* CONFIG_SERIAL_S3C2410_CONSOLE */
  419. static struct uart_driver s3c2410_reg = {
  420. owner: THIS_MODULE,
  421. normal_major: SERIAL_S3C2410_MAJOR,
  422. #ifdef CONFIG_DEVFS_FS
  423. normal_name: "ttyS%d",
  424. callout_name: "cua%d",
  425. #else
  426. normal_name: "ttyS",
  427. callout_name: "cua",
  428. #endif
  429. normal_driver: &normal,
  430. callout_major: CALLOUT_S3C2410_MAJOR,
  431. callout_driver: &callout,
  432. table: s3c2410_table,
  433. termios: s3c2410_termios,
  434. termios_locked: s3c2410_termios_locked,
  435. minor: MINOR_START,
  436. nr: UART_NR,
  437. port: s3c2410_ports,
  438. cons: S3C2410_CONSOLE,
  439. };
  440. static int __init s3c2410uart_init(void)
  441. {
  442. return uart_register_driver(&s3c2410_reg);
  443. }
  444. static void __exit s3c2410uart_exit(void)
  445. {
  446. uart_unregister_driver(&s3c2410_reg);
  447. }
  448. module_init(s3c2410uart_init);
  449. module_exit(s3c2410uart_exit);
  450. EXPORT_NO_SYMBOLS;
  451. MODULE_AUTHOR("MIZI Research Inc");
  452. MODULE_DESCRIPTION("S3C2410 generic serial port driver");
  453. MODULE_LICENSE("GPL");