1. 程式人生 > >6410 實現 linux 串列埠驅動詳解

6410 實現 linux 串列埠驅動詳解

為了實現串列埠通訊,需要在嵌入式linux下編寫相應的驅動程式。在嵌入式系統中,串列埠被看做終端裝置tty。終端裝置是unix體系中一個非常重要的物件,內容非常複雜,它是整個unix人機互動的基礎,其地位並不亞於檔案系統在作業系統中的作用。筆者muge0913在此對uart驅動進行整理。

一、串列埠概述

     串列埠分為:同步傳輸(usrt)和非同步傳輸(uart),其中非同步傳輸是嵌入系統中最長用的通訊裝置,串列埠常被當做控制檯使用。

①同步傳輸:傳送端和接收端使用同一個時鐘。其時序如下:

②非同步傳輸:在資料傳輸過程中,接收時鐘和傳送時鐘是不同步的,即在序列總線上並沒有時鐘線。

傳輸前有相應的起始位,然後緊接著傳送資料位(5~8位有使用者定義),最後是奇偶校驗位和停止位。如圖:

二、串列埠物理層連線問題

   因為串列埠電纜有交叉和直連線之分,其介面有公頭和母頭之分,所以其連線有6中連線方式:

   ①兩頭公頭的直線電纜

   ②兩頭母頭的交叉線

   ③兩頭公頭的交叉線

   ④兩個母頭的直線電纜

   ⑤一公頭一母頭的直線電纜

   ⑥一公頭一母頭的交叉線

   在大多數的非同步通訊中不需要流的控制,所以3根線就能滿座嵌入式裝置通訊的要求,但是為了保持相容常常使用下面的連線方法:

三、arm11中的uart

①概述:

    S3C6410X的UART提供四個獨立的非同步序列I / O(SIO)埠。非同步序列I / O(SIO)埠,每個都可以在基於中斷或基於DMA模式。換句話說,UART可以產生中斷或DMA請求MEM和UART之間的資料傳輸。UART也可支援最大3Mbps的位元率。每個UART通道包含兩個64位元組的FIFO的接收和傳輸的。

②特點


四、暫存器配置略請開發者閱讀晶片資料和參考下列程式碼中的註釋

五、驅動原始碼:

[cpp] view plaincopyprint?
  1. #include <linux/module.h>
  2. #include <linux/ioport.h>
  3. #include <linux/io.h>
  4. #include <linux/platform_device.h>
  5. #include <linux/init.h>
  6. #include <linux/serial_core.h>
  7. #include <linux/serial.h>
  8. #include <asm/irq.h>
  9. #include <mach/hardware.h>
  10. #include <plat/regs-serial.h>
  11. #include "samsung.h"
  12. staticint s3c6400_serial_setsource(struct uart_port *port,  
  13.                     struct s3c24xx_uart_clksrc *clk)  
  14. {  
  15.     unsigned long ucon = rd_regl(port, S3C2410_UCON);  
  16.     if (strcmp(clk->name, "uclk0") == 0) {  
  17.         ucon &= ~S3C6400_UCON_CLKMASK;  
  18.         ucon |= S3C6400_UCON_UCLK0;  
  19.     } elseif (strcmp(clk->name, "uclk1") == 0)  
  20.         ucon |= S3C6400_UCON_UCLK1;  
  21.     elseif (strcmp(clk->name, "pclk") == 0) {  
  22.         /* See notes about transitioning from UCLK to PCLK */
  23.         ucon &= ~S3C6400_UCON_UCLK0;  
  24.     } else {  
  25.         printk(KERN_ERR "unknown clock source %s\n", clk->name);  
  26.         return -EINVAL;  
  27.     }  
  28.     wr_regl(port, S3C2410_UCON, ucon);  
  29.     return 0;  
  30. }  
  31. staticint s3c6400_serial_getsource(struct uart_port *port,  
  32.                     struct s3c24xx_uart_clksrc *clk)  
  33. {  
  34.     u32 ucon = rd_regl(port, S3C2410_UCON);  
  35.     clk->divisor = 1;  
  36.     switch (ucon & S3C6400_UCON_CLKMASK) {  
  37.     case S3C6400_UCON_UCLK0:  
  38.         clk->name = "uclk0";  
  39.         break;  
  40.     case S3C6400_UCON_UCLK1:  
  41.         clk->name = "uclk1";  
  42.         break;  
  43.     case S3C6400_UCON_PCLK:  
  44.     case S3C6400_UCON_PCLK2:  
  45.         clk->name = "pclk";  
  46.         break;  
  47.     }  
  48.     return 0;  
  49. }  
  50. staticint s3c6400_serial_resetport(struct uart_port *port,  
  51.                     struct s3c2410_uartcfg *cfg)  
  52. {  
  53.     unsigned long ucon = rd_regl(port, S3C2410_UCON);  
  54.     dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n",  
  55.         port, port->mapbase, cfg);  
  56.     /* ensure we don't change the clock settings... */
  57.     ucon &= S3C6400_UCON_CLKMASK;  
  58.     wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);  
  59.     wr_regl(port, S3C2410_ULCON, cfg->ulcon);  
  60.     /* reset both fifos */
  61.     wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);  
  62.     wr_regl(port, S3C2410_UFCON, cfg->ufcon);  
  63.     return 0;  
  64. }  
  65. staticstruct s3c24xx_uart_info s3c6400_uart_inf = {  
  66.     .name       = "Samsung S3C6400 UART",  
  67.     .type       = PORT_S3C6400,  
  68.     .fifosize   = 64,  
  69.     .has_divslot    = 1,  
  70.     .rx_fifomask    = S3C2440_UFSTAT_RXMASK,  
  71.     .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,  
  72.     .rx_fifofull    = S3C2440_UFSTAT_RXFULL,  
  73.     .tx_fifofull    = S3C2440_UFSTAT_TXFULL,  
  74.     .tx_fifomask    = S3C2440_UFSTAT_TXMASK,  
  75.     .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,  
  76.     .get_clksrc = s3c6400_serial_getsource,  
  77.     .set_clksrc = s3c6400_serial_setsource,  
  78.     .reset_port = s3c6400_serial_resetport,  
  79. };  
  80. /* device management */
  81. staticint s3c6400_serial_probe(struct platform_device *dev)  
  82. {  
  83.     dbg("s3c6400_serial_probe: dev=%p\n", dev);  
  84.     return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);  
  85. }  
  86. staticstruct platform_driver s3c6400_serial_driver = {  
  87.     .probe      = s3c6400_serial_probe,  
  88.     .remove     = __devexit_p(s3c24xx_serial_remove),  
  89.     .driver     = {  
  90.         .name   = "s3c6400-uart",  
  91.         .owner  = THIS_MODULE,  
  92.     },  
  93. };  
  94. s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf);  
  95. staticint __init s3c6400_serial_init(void)  
  96. {  
  97.     return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf);  
  98. }  
  99. staticvoid __exit s3c6400_serial_exit(void)  
  100. {  
  101.     platform_driver_unregister(&s3c6400_serial_driver);  
  102. }  
  103. module_init(s3c6400_serial_init);  
  104. module_exit(s3c6400_serial_exit);  
  105. MODULE_AUTHOR("muge0913");  
  106. MODULE_LICENSE("GPL v2");  
  107. MODULE_ALIAS("platform:s3c6400-uart");