Linux I2C匯流排控制器驅動(S3C2440)

来源:http://www.cnblogs.com/blogs-of-lxl/archive/2016/03/19/5295149.html
-Advertisement-
Play Games

s3c2440的i2c控制器驅動(精簡DIY),直接上代碼,註釋很詳細: 附一份測試程式: Make File:


 s3c2440的i2c控制器驅動(精簡DIY),直接上代碼,註釋很詳細:

  1 #include <linux/kernel.h>
  2 #include <linux/module.h>
  3 
  4 #include <linux/i2c.h>
  5 #include <linux/init.h>
  6 #include <linux/time.h>
  7 #include <linux/interrupt.h>
  8 #include <linux/delay.h>
  9 #include <linux/errno.h>
 10 #include <linux/err.h>
 11 #include <linux/platform_device.h>
 12 #include <linux/pm_runtime.h>
 13 #include <linux/clk.h>
 14 #include <linux/cpufreq.h>
 15 #include <linux/slab.h>
 16 #include <linux/io.h>
 17 #include <linux/of_i2c.h>
 18 #include <linux/of_gpio.h>
 19 #include <plat/gpio-cfg.h>
 20 #include <mach/regs-gpio.h>
 21 
 22 #include <asm/irq.h>
 23 
 24 #include <plat/regs-iic.h>
 25 #include <plat/iic.h>
 26 
 27 //#define PRINTK printk
 28 #define PRINTK(...) 
 29 
 30 enum s3c24xx_i2c_state {
 31     STATE_IDLE,
 32     STATE_START,
 33     STATE_READ,
 34     STATE_WRITE,
 35     STATE_STOP
 36 };
 37 
 38 //i2c控制器寄存器
 39 struct s3c2440_i2c_regs {
 40     unsigned int iiccon;
 41     unsigned int iicstat;
 42     unsigned int iicadd;
 43     unsigned int iicds;
 44     unsigned int iiclc;
 45 };
 46 
 47 //i2c數據傳輸載體
 48 struct s3c2440_i2c_xfer_data {
 49     struct i2c_msg *msgs;
 50     int msn_num;
 51     int cur_msg;
 52     int cur_ptr;
 53     int state;
 54     int err;
 55     wait_queue_head_t wait;
 56 };
 57 
 58 static struct s3c2440_i2c_xfer_data s3c2440_i2c_xfer_data;
 59 
 60 
 61 static struct s3c2440_i2c_regs *s3c2440_i2c_regs;
 62 
 63 
 64 static void s3c2440_i2c_start(void)
 65 {
 66     s3c2440_i2c_xfer_data.state = STATE_START;
 67     
 68     if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /**/
 69     {
 70         s3c2440_i2c_regs->iicds         = s3c2440_i2c_xfer_data.msgs->addr << 1; 
 71         s3c2440_i2c_regs->iicstat      = 0xb0;    // 主機接收,啟動
 72     }
 73     else /**/
 74     {
 75         s3c2440_i2c_regs->iicds         = s3c2440_i2c_xfer_data.msgs->addr << 1;
 76         s3c2440_i2c_regs->iicstat    = 0xf0;         // 主機發送,啟動
 77     }
 78 }
 79 
 80 static void s3c2440_i2c_stop(int err)
 81 {
 82     s3c2440_i2c_xfer_data.state = STATE_STOP;
 83     s3c2440_i2c_xfer_data.err   = err;
 84 
 85     PRINTK("STATE_STOP, err = %d\n", err);
 86 
 87 
 88     if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /**/
 89     {
 90         // 下麵兩行恢復I2C操作,發出P信號
 91         s3c2440_i2c_regs->iicstat = 0x90;
 92         s3c2440_i2c_regs->iiccon  = 0xaf;
 93         ndelay(50);  // 等待一段時間以便P信號已經發出
 94     }
 95     else /**/
 96     {
 97         // 下麵兩行用來恢復I2C操作,發出P信號
 98         s3c2440_i2c_regs->iicstat = 0xd0;
 99         s3c2440_i2c_regs->iiccon  = 0xaf;
100         ndelay(50);  // 等待一段時間以便P信號已經發出
101     }
102 
103     /* 喚醒 */
104     wake_up(&s3c2440_i2c_xfer_data.wait);
105     
106 }
107 
108 //i2c匯流排數據傳輸處理函數
109 static int s3c2440_i2c_xfer(struct i2c_adapter *adap,
110             struct i2c_msg *msgs, int num)
111 {
112     unsigned long timeout;
113     
114     /* 把num個msg的I2C數據發送出去/讀進來 */
115     s3c2440_i2c_xfer_data.msgs    = msgs;
116     s3c2440_i2c_xfer_data.msn_num = num;
117     s3c2440_i2c_xfer_data.cur_msg = 0;
118     s3c2440_i2c_xfer_data.cur_ptr = 0;
119     s3c2440_i2c_xfer_data.err     = -ENODEV; //確認是否有ack應答
120 
121     s3c2440_i2c_start(); //發出start信號,判斷read or write
122 
123     /* 休眠-等待i2c讀寫狀態改變 */
124     timeout = wait_event_timeout(s3c2440_i2c_xfer_data.wait, (s3c2440_i2c_xfer_data.state == STATE_STOP), HZ * 5); //等待狀態成立或5s
125     if (0 == timeout)
126     {
127         printk("s3c2440_i2c_xfer time out\n");
128         return -ETIMEDOUT;
129     }
130     else
131     {
132         return s3c2440_i2c_xfer_data.err;
133     }
134 }
135 
136 static u32 s3c2440_i2c_func(struct i2c_adapter *adap)
137 {
138     return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
139 }
140 
141 
142 static const struct i2c_algorithm s3c2440_i2c_algo = {
143 //    .smbus_xfer     = ,   //smbus是i2c傳輸的一個子集,支持的話可以在這裡指定處理函數
144     .master_xfer    = s3c2440_i2c_xfer, //傳輸函數
145     .functionality    = s3c2440_i2c_func,
146 };
147 
148 /* 1. 分配/設置i2c_adapter
149  */
150 static struct i2c_adapter s3c2440_i2c_adapter = {
151  .name             = "s3c2440_sheldon",
152  .algo             = &s3c2440_i2c_algo, //演算法函數
153  .owner          = THIS_MODULE,
154 };
155 
156 static int isLastMsg(void)
157 {
158     return (s3c2440_i2c_xfer_data.cur_msg == s3c2440_i2c_xfer_data.msn_num - 1);
159 }
160 
161 static int isEndData(void)
162 {
163     return (s3c2440_i2c_xfer_data.cur_ptr >= s3c2440_i2c_xfer_data.msgs->len);
164 }
165 
166 static int isLastData(void)
167 {
168     return (s3c2440_i2c_xfer_data.cur_ptr == s3c2440_i2c_xfer_data.msgs->len - 1);
169 }
170 
171 static irqreturn_t s3c2440_i2c_xfer_irq(int irq, void *dev_id)
172 {
173     unsigned int iicSt;
174         
175      iicSt  = s3c2440_i2c_regs->iicstat;  //讀取i2c控制器的狀態寄存器,判斷是否讀寫成功
176 
177     if(iicSt & 0x8){ printk("Bus arbitration failed\n\r"); }
178 
179     switch (s3c2440_i2c_xfer_data.state)
180     {
181         case STATE_START : /* 發出S和設備地址後,產生中斷 */
182         {
183             PRINTK("Start\n");
184             /* 如果沒有ACK, 返回錯誤 */
185             if (iicSt & S3C2410_IICSTAT_LASTBIT)
186             {
187                 s3c2440_i2c_stop(-ENODEV);
188                 break;
189             }
190 
191             if (isLastMsg() && isEndData())
192             {
193                 s3c2440_i2c_stop(0);
194                 break;
195             }
196 
197             /* 進入下一個狀態 */
198             if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /**/
199             {
200                 s3c2440_i2c_xfer_data.state = STATE_READ;
201                 goto next_read;
202             }
203             else
204             {
205                 s3c2440_i2c_xfer_data.state = STATE_WRITE;
206             }    
207         }
208 
209         case STATE_WRITE:
210         {
211             PRINTK("STATE_WRITE\n");
212             /* 如果沒有ACK, 返回錯誤 */
213             if (iicSt & S3C2410_IICSTAT_LASTBIT)
214             {
215                 s3c2440_i2c_stop(-ENODEV);
216                 break;
217             }
218 
219             if (!isEndData())  /* 如果當前msg還有數據要發送 */
220             {
221                 s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr];
222                 s3c2440_i2c_xfer_data.cur_ptr++;
223                 
224                 // 將數據寫入IICDS後,需要一段時間才能出現在SDA線上
225                 ndelay(50);    
226                 
227                 s3c2440_i2c_regs->iiccon = 0xaf;        // 恢復I2C傳輸
228                 break;                
229             }
230             else if (!isLastMsg())
231             {
232                 /* 開始處理下一個消息 */
233                 s3c2440_i2c_xfer_data.msgs++;
234                 s3c2440_i2c_xfer_data.cur_msg++;
235                 s3c2440_i2c_xfer_data.cur_ptr = 0;
236                 s3c2440_i2c_xfer_data.state = STATE_START;
237                 /* 發出START信號和發出設備地址 */
238                 s3c2440_i2c_start();
239                 break;
240             }
241             else
242             {
243                 /* 是最後一個消息的最後一個數據 */
244                 s3c2440_i2c_stop(0);
245                 break;                
246             }
247 
248             break;
249         }
250 
251         case STATE_READ:
252         {
253             PRINTK("STATE_READ\n");
254             /* 讀出數據 */
255             s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr] = s3c2440_i2c_regs->iicds;            
256             s3c2440_i2c_xfer_data.cur_ptr++;
257 next_read:
258             if (!isEndData()) /* 如果數據沒讀寫, 繼續發起讀操作 */
259             {
260                 if (isLastData())  /* 如果即將讀的數據是最後一個, 不發ack */
261                 {
262                     s3c2440_i2c_regs->iiccon = 0x2f;   // 恢復I2C傳輸,接收到下一數據時無ACK
263                 }
264                 else
265                 {
266                     s3c2440_i2c_regs->iiccon = 0xaf;   // 恢復I2C傳輸,接收到下一數據時發出ACK
267                 }                
268                 break;
269             }
270             else if (!isLastMsg())
271             {
272                 /* 開始處理下一個消息 */
273                 s3c2440_i2c_xfer_data.msgs++;
274                 s3c2440_i2c_xfer_data.cur_msg++;
275                 s3c2440_i2c_xfer_data.cur_ptr = 0;
276                 s3c2440_i2c_xfer_data.state = STATE_START;
277                 /* 發出START信號和發出設備地址 */
278                 s3c2440_i2c_start();
279                 break;
280             }
281             else
282             {
283                 /* 是最後一個消息的最後一個數據 */
284                 s3c2440_i2c_stop(0);
285                 break;                                
286             }
287             break;
288         }
289 
290         default: break;
291     }
292 
293     /* 清中斷 */
294     s3c2440_i2c_regs->iiccon &= ~(S3C2410_IICCON_IRQPEND);
295 
296     return IRQ_HANDLED;    
297 }
298 
299 
300 /*
301  * I2C初始化
302  */
303 static void s3c2440_i2c_init(void)
304 {
305     struct clk *clk;
306 
307     clk = clk_get(NULL, "i2c");
308     clk_enable(clk);
309     
310     // 選擇引腳功能:GPE15:IICSDA, GPE14:IICSCL
311         s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
312     s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
313 
314     /* bit[7] = 1, 使能ACK
315      * bit[6] = 0, IICCLK = PCLK/16
316      * bit[5] = 1, 使能中斷
317      * bit[3:0] = 0xf, Tx clock = IICCLK/16
318      * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz
319      */
320     s3c2440_i2c_regs->iiccon = (1<<7) | (0<<6) | (1<<5) | (0xf);  // 0xaf
321 
322     s3c2440_i2c_regs->iicadd  = 0x10;     // S3C24xx slave address = [7:1]
323     s3c2440_i2c_regs->iicstat = 0x10;     // I2C串列輸出使能(Rx/Tx)
324 }
325 
326 static int i2c_bus_s3c2440_init(void)
327 {
328     /* 2. 硬體相關的設置 */
329     s3c2440_i2c_regs = ioremap(0x54000000, sizeof(struct s3c2440_i2c_regs));//映射功能寄存器
330     
331     s3c2440_i2c_init(); //初始化i2c控制器
332 
333     request_irq(IRQ_IIC, s3c2440_i2c_xfer_irq, 0, "s3c2440-i2c", NULL); //申請中斷源,載入中斷處理函數-s3c2440_i2c_xfer_irq
334 
335     init_waitqueue_head(&s3c2440_i2c_xfer_data.wait); //初始化一個等待隊列頭
336     
337     /* 3. 註冊i2c_adapter */
338     i2c_add_adapter(&s3c2440_i2c_adapter);
339     
340     return 0;
341 }
342 
343 static void i2c_bus_s3c2440_exit(void)
344 {
345     i2c_del_adapter(&s3c2440_i2c_adapter);    
346     free_irq(IRQ_IIC, NULL);
347     iounmap(s3c2440_i2c_regs);
348 }
349 
350 module_init(i2c_bus_s3c2440_init);
351 module_exit(i2c_bus_s3c2440_exit);
352 MODULE_LICENSE("GPL");

附一份測試程式:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <sys/types.h>
 5 #include <sys/stat.h>
 6 #include <fcntl.h>
 7 #include "i2c-dev.h"
 8 
 9 
10 /* i2c_usr_test </dev/i2c-0> <dev_addr> r addr
11  * i2c_usr_test </dev/i2c-0> <dev_addr> w addr val
12  */
13 
14 void print_usage(char *file)
15 {
16     printf("%s </dev/i2c-0> <dev_addr> r addr\n", file);
17     printf("%s </dev/i2c-0> <dev_addr> w addr val\n", file);
18 }
19 
20 int main(int argc, char **argv)
21 {
22     int fd;
23     unsigned char addr, data;
24     int dev_addr;
25     
26     if ((argc != 5) && (argc != 6))
27     {
28         print_usage(argv[0]);
29         return -1;
30     }
31 
32     fd = open(argv[1], O_RDWR);
33     if (fd < 0)
34     {
35         printf("can't open %s\n", argv[1]);
36         return -1;
37     }
38 
39     dev_addr = strtoul(argv[2], NULL, 0);
40     if (ioctl(fd, I2C_SLAVE, dev_addr) < 0)
41     {    
42         /* ERROR HANDLING; you can check errno to see what went wrong */    
43         printf("set addr error!\n");
44         return -1;
45     }
46 
47     if (strcmp(argv[3], "r") == 0)
48     {
49         addr = strtoul(argv[4], NULL, 0);
50         
51         data = i2c_smbus_read_word_data(fd, addr);
52             
53         printf("data: %c, %d, 0x%2x\n", data, data, data);
54     }
55     else if ((strcmp(argv[3], "w") == 0) && (argc == 6))
56     {
57         addr = strtoul(argv[4], NULL, 0);
58         data = strtoul(argv[5], NULL, 0);
59         i2c_smbus_write_byte_data(fd, addr, data);        
60     }
61     else
62     {
63         print_usage(argv[0]);
64         return -1;
65     }
66     
67     return 0;
68 }

Make File:

KERN_DIR = /work/system/linux-3.4.2

all:
    make -C $(KERN_DIR) M=`pwd` modules

clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
    rm -rf modules.order

obj-m    += i2c_bus_s3c2440.o

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 兩個NSDate之間是可以進行比較的。 有了NSCalendar比較兩個日期就易如反掌 /** 1.今年 1> 今天 * 1分內: 剛剛 * 1分~59分內:xx分鐘前 * 大於60分鐘:xx小時前 2> 昨天 * 昨天 xx:xx 3> 其他 * xx-xx xx:xx 2.非今年 1> xxxx
  • XML解析之SAX詳解 本文屬於作者原創 http://www.cnblogs.com/ldnh/ XML解析的五個步驟 1、打開文檔 (void)parserDidStartDocument:(NSXMLParser )parser ; 2、開始查找起始標簽 (void)parser:(NSXML
  • 修改表欄位時的註意事項: 1:儘量不修改欄位類型。2:欄位長度儘量不要減少。3:修改後的欄位,只對新插入的數據產生影響,修改欄位前的所有數據不影響。 INSERT語句是向表中插入數據INSERT語句指定的列對應的值會被插入到表中沒有列舉的列會插入NULL,但是,若該列有設置預設值(DEFAULT關鍵
  • 1.關掉mysql服務,打開系統設置最後的mysql,然後將mysql先關掉 2.生成一個文件命名mysql-init,文件中放入:一句話,這句話不同版本不一樣,如下:(括弧裡面不包含) alter user ‘root’@‘localhost’ identified by ‘新密碼’;(MySQL
  • 參照Hadoop.The.Definitive.Guide.4th的例子,執行SortDataPreprocessor作業時失敗,輸出的錯誤信息 SequenceFile doesn't work with GzipCodec without native-hadoop code! 根據提示初步猜測
  • J-Link RTT的實現
  • 一、操作系統級環境及軟體版本 操作系統:CentOS release 6.5 (Final)minimal 內核版本:2.6.32-431.el6.x86_64 MySQL版本:MySQL-5.6.28 nginx版本:nginx-1.8.1 php版本:php-5.6.19 二、安裝MySQL-5
  • 問題表現: 在明明引用了頭文件的情況下,出現“undefined reference to `…'”的情況,例如下圖: 解決方法: 在左邊的數據目錄定位到“system\src\stm32f0-stdperiph”,然後找到需要的“*.c”文件,包括進去即可。
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...