手把手教你寫Linux I2C設備驅動

手把手教你寫Linux I2C設備驅動
標簽:Linux 設備 驅動 詳解 i2c
原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處 、作者信息和本聲明。否則將追究法律責任。http://ticktick.blog.51cto.com/823160/760020

??? Linux I2C驅動是嵌入式Linux驅動開發人員經常需要編寫的一種驅動,因為凡是系統中使用到的I2C設備,幾乎都需要編寫相應的I2C驅動去配置和控制它,例如 RTC實時時鐘芯片、音視頻采集芯片、音視頻輸出芯片、EEROM芯片、AD/DA轉換芯片等等。

??? Linux I2C驅動涉及的知識點還是挺多的,主要分為Linux I2C的總線驅動(I2C BUS Driver)和設備驅動(I2C Clients Driver),本文主要關注如何快速地完成一個具體的I2C設備驅動(I2C Clients Driver)。關于Linux I2C驅動的整體架構、核心原理等可以在網上搜索其他相關文章學習。

? ? 注意:本系列文章的I2C設備驅動是基于Linux 2.6.18內核。

??? 本文主要參考了Linux內核源碼目錄下的 ./Documentation/i2c/writing-clients 文檔。以手頭的一款視頻采集芯片TVP5158為驅動目標,編寫Linux I2C設備驅動。

1.???i2c_driver結構體對象?????

??? 每一個I2C設備驅動,必須首先創造一個i2c_driver結構體對象,該結構體包含了I2C設備探測和注銷的一些基本方法和信息,示例如下:

  1. static?struct?i2c_driver?tvp5158_i2c_driver?=?{ ?
  2. ????????.driver?=?{ ?
  3. ????????????.name?=?"tvp5158_i2c_driver", ?
  4. ????????}, ??
  5. ????????.attach_adapter?=?&tvp5158_attach_adapter, ?
  6. ????????.detach_client??=?&tvp5158_detach_client, ?
  7. ????????.command????????=?NULL, ?
  8. }; ?

??? 其中,name字段標識本驅動的名稱(不要超過31個字符),attach_adapter和detach_client字段為函數指針,這兩個函數在I2C設備注冊的時候會自動調用,需要自己實現這兩個函數,后面將詳細講述。

2.?? i2c_client 結構體對象

??? 上面定義的i2c_driver對象,抽象為一個i2c的驅動模型,提供對i2C設備的探測和注銷方法,而i2c_client結構體則是代表著一個具體的i2c設備,該結構體有一個data指針,可以指向任何私有的設備數據,在復雜點的驅動中可能會用到。示例如下:???

  1. struct?tvp5158_obj{?????? ?
  2. ????struct?i2c_client?client;?????? ?
  3. ????int?users;?//?how?many?users?using?the?driver?? ?
  4. }; ?
  5. ?
  6. struct?tvp5158_obj*?g_tvp5158_obj;??

??? 其中,users為示例,用戶可以自己在tvp5158_obj這個結構體里面添加感興趣的字段,但是i2c_client字段不可少。具體用法后面再詳細講。

3.?? 設備注冊及探測功能

??? 這一步很關鍵,按照標準的要求來寫,則Linux系統會自動調用相關的代碼去探測你的I2C設備,并且添加到系統的I2C設備列表中以供后面訪問。

??? 我們知道,每一個I2C設備芯片,都通過硬件連接設定好了該設備的I2C設備地址。因此,I2C設備的探測一般是靠設備地址來完成的。那么,首先要在驅動代碼中聲明你要探測的I2C設備地址列表,以及一個宏。示例如下:

  1. static?unsigned?short?normal_i2c[]?=?{ ?
  2. ????????0xbc?>>?1, ?
  3. ????????0xbe?>>?1, ?
  4. ????????I2C_CLIENT_END ?
  5. }; ?
  6. I2C_CLIENT_INSMOD; ?

??? normal_i2c 數組包含了你需要探測的I2C設備地址列表,并且必須以I2C_CLIENT_END作為結尾,注意,上述代碼中的0xbc和0xbe是我在硬件上為我的tvp5158分配的地址,硬件上我支持通過跳線將該地址設置為 0xbc 或者 0xbe,所以把這兩個地址均寫入到探測列表中,讓系統進行探測。如果你的I2C設備的地址是固定的,那么,這里可以只寫你自己的I2C設備地址,注意必須向右移位1。

??? 宏 I2C_CLIENT_INSMOD 的作用網上有許多文章進行了詳細的講解,這里我就不詳細描述了,記得加上就行,我們重點關注實現。

??? 下一步就應該編寫第1步中的兩個回調函數,一個用于注冊設備,一個用于注銷設備。探測函數示例如下:

  1. static?int?tvp5158_attach_adapter(struct?i2c_adapter?*adapter) ?
  2. { ?
  3. ????return?i2c_probe(adapter,?&addr_data,?&tvp5158_detect_client); ?
  4. }?

??? 這個回調函數系統會自動調用,我們只需要按照上述代碼形式寫好就行,這里調用了系統的I2C設備探測函數,i2c_probe(),第三個參數為具體的設備探測回調函數,系統會在探測設備的時候調用這個函數,需要自己實現。示例如下:

  1. static?int?tvp5158_detect_client(struct?i2c_adapter?*adapter,int?address,int?kind) ?
  2. { ?
  3. ????struct?tvp5158_obj?*pObj; ?
  4. ????int?err?=?0; ?
  5. ?
  6. ????printk(KERN_INFO?"I2C:?tvp5158_detect_client?at?address?%x?...\n",?address); ?
  7. ?
  8. ????if(?g_tvp5158_obj?!=?NULL??)?{ ?
  9. ????????//already?allocated,inc?user?count,?and?return?the?allocated?handle ?
  10. ????????g_tvp5158_obj->users++; ?
  11. ????????return?0; ?
  12. ????} ?
  13. ?
  14. ????/*?alloc?obj?*/?
  15. ????pObj?=?kmalloc(sizeof(struct?tvp5158_obj),?GFP_KERNEL); ?
  16. ????if?(pObj==0){ ?
  17. ????????return?-ENOMEM; ?
  18. ????} ?
  19. ????memset(pObj,?0,?sizeof(struct?tvp5158_obj)); ?
  20. ????pObj->client.addr????=?address; ?
  21. ????pObj->client.adapter?=?adapter; ?
  22. ????pObj->client.driver??=?&tvp5158_i2c_driver; ?
  23. ????pObj->client.flags???=?I2C_CLIENT_ALLOW_USE; ?
  24. ????pObj->users++; ?
  25. ?
  26. ????/*?attach?i2c?client?to?sys?i2c?clients?list?*/?
  27. ????if((err?=?i2c_attach_client(&pObj->client))){ ?
  28. ????????printk(?KERN_ERR?"I2C:?ERROR:?i2c_attach_client?fail!?address=%x\n",address); ?
  29. ????????return?err; ?
  30. ????} ?
  31. ?
  32. ????//?store?the?pObj ?
  33. ????g_tvp5158_obj?=?pObj; ?
  34. ?
  35. ????printk(?KERN_ERR?"I2C:?i2c_attach_client?ok!?address=%x\n",address); ?
  36. ?
  37. ????return?0; ?
  38. }?

??? 到此為止,探測并且注冊設備的代碼已經完成,以后對該??I2C?設備的訪問均可以通過 g_tvp5158_obj 這個全局的指針進行了。

4.??? 注銷I2C設備?

??? 同理,設備注銷的回調函數也會自動被系統調用,只需要按照模板寫好設備注銷代碼,示例如下:????

  1. static?int?tvp5158_detach_client(struct?i2c_client?*client) ?
  2. { ?
  3. ????int?err; ?
  4. ?
  5. ????if(?!?client->adapter?){ ?
  6. ????????return?-ENODEV; ?
  7. ????} ?
  8. ?
  9. ????if(?(err?=?i2c_detach_client(client))?)?{ ?
  10. ????????printk(?KERN_ERR?"Client?deregistration?failed?(address=%x),?client?not?detached.\n",?client->addr); ?
  11. ????????return?err; ?
  12. ????} ?
  13. ?
  14. ????client->adapter?=?NULL; ?
  15. ?
  16. ????if(?g_tvp5158_obj?){ ?
  17. ????????kfree(g_tvp5158_obj); ?
  18. ????} ?
  19. ?
  20. ????return?0; ?
  21. }?

??? 到此為止,設備的注冊和注銷代碼已經全部完成,下面要做的就是提供讀寫I2C設備的方法。

?5.?? I2C設備的讀寫??????

??? 對I2C設備的讀寫,Linux系統提供了多種接口,可以在內核的 i2c.h 中找到,這里簡單介紹其中的兩種接口。

?? 【接口一】:

  1. extern?int?i2c_master_send(struct?i2c_client?*,const?char*?,int); ?
  2. ?
  3. extern?int?i2c_master_recv(struct?i2c_client?*,char*?,int); ?

??? 第一個參數是 i2c_client 對象指針,第二個參數是要傳輸的數據buffer指針,第三個參數為buffer的大小。

?? 【接口二】:

  1. extern?int?i2c_transfer(struct?i2c_adapter?*adap,?struct?i2c_msg?*msg,?int?num);?

??? 這個接口支持一次向I2C設備發送多個消息,每一個消息可以是讀也可以是寫,讀或者寫以及讀寫的目標地址(寄存器地址)均包含在msg消息參數里面。

??? 這些接口僅僅是最底層的讀寫方法,關于具體怎么與I2C設備交互,比如具體怎么讀芯片的某個特定寄存器的值,這需要看具體的芯片手冊,每個I2C芯片都會有具體的I2C寄存器讀寫時序圖。因此,為了在驅動中提供更好的訪問接口,還需要根據具體的時序要求對這些讀寫函數進行進一步封裝,這些內容將在后面的文章中講述。

6. ?模塊初始化及其他

? ? 下一步就是整個模塊的初始化代碼和逆初始化代碼,以及模塊聲明了。? ??

  1. static?int?__init?tvp5158_i2c_init(void)?
  2. {?
  3. ????g_tvp5158_obj?=?NULL;?
  4. ?????
  5. ????return?i2c_add_driver(&tvp5158_i2c_driver);?
  6. }?
  7. ?
  8. static?void?__exit?tvp5158_i2c_exit(void)?
  9. {?
  10. ????i2c_del_driver(&tvp5158_i2c_driver);?
  11. }?
  12. ?
  13. module_init(tvp5158_i2c_init);?
  14. module_exit(tvp5158_i2c_exit);?
  15. ?
  16. MODULE_DESCRIPTION("TVP5158?i2c?driver");?
  17. MODULE_AUTHOR("Lujun?@hust");?
  18. MODULE_LICENSE("GPL");?

? ? 在初始化的代碼里面,添加本模塊的 i2c driver 對象,在逆初始化代碼里面,刪除本模塊的 i2c driver 對象。

7.?? 總結

??? 到此為止,算是從應用的角度把編寫一個I2C的設備驅動代碼講完了,很多原理性的東西我都沒有具體分析(其實我也了解的不深),以后會慢慢更深入地學習和了解,文中有什么講述不正確的地方,歡迎留言或者來信lujun.hust@gmail.com交流。

??? 讀到最后,大家可能還有一個疑問,這個驅動寫完了怎么在用戶空間(應用層)去使用它呢?由于本文不想把代碼弄得太多太復雜,怕提高理解的難度,所以就沒有講,其實要想在用戶空間使用該I2C設備驅動,則還需要借助字符設備驅動來完成,即為這個I2C設備驅動封裝一層字符設備驅動,這樣,用戶空間就可以通過對字符設備驅動的訪問來訪問I2C設備,這個方法我會在后面的文章中講述。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253592.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253592.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253592.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HDR 成像技術學習(三)—— LOFIC

HDR 成像技術學習(一) HDR 成像技術學習(二) 我們拍攝的照片來自傳感器上的像素,它們將光處理為電信號,組合起來輸出畫面。當捕捉對象亮度過強,大量電荷擠在單個像素內,生成的圖像就會過曝。 LOFIC(Lateral Overflow Integration Capacitor,橫向溢出集合電容…

[模板]平面最近點對

實現 將平面內點按$x$坐標排序,分治$x$坐標,設$retmin(f(l,mid),f(mid1,r))$, 將$x\in[mid-ret,midret]$內的點按$y$坐標排序,算每個點與相鄰的$6$個點的距離找最優解即可. 時間復雜度:$O(nlogn)$. #define N 100005 #define INF 1e15 struct point{double x,y; }p[N]; inline …

人工智能與圖像傳感器

隨著人工智能時代的來臨,相應的芯片產品和行業也產生了相應的新方向。 在人工智能的各個分支中,機器視覺無疑是應用最廣泛的方向,它支撐著諸如人臉檢測、工業異常檢測、手勢識別等諸多重要的應用。顧名思義,機器視覺是使用機器學習/人工智能的方法來分析視覺信號,并且通過…

用戶空間訪問I2C設備驅動

2012-01-11 15:33:43標簽:Linux I2C 字符設備 設備驅動 用戶空間 原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處 、作者信息和本聲明。否則將追究法律責任。http://ticktick.blog.51cto.com/823160/761830 關于Linux下如何編…

097實戰 關于ETL的幾種運行方式

一:代碼部分 1.新建maven項目 2.添加需要的java代碼   3.書寫mapper類 4.書寫runner類 二:運行方式 1.本地運行 2.集群運行 3.本地提交集群運行 三:本地運行方式 1.解壓hadoop到本地 2.修改配置文件HADOOP_HOME 3.解壓common的壓縮包 4.將壓…

模擬ssh, hashlib模塊, struct模塊, subprocess模塊

一. 模擬ssh # 服務器端 import socket import subprocess # 系統操作server socket.socket()server.bind((127.0.0.1,8008))server.listen(5)while True:print("server is working.....")conn,addr server.accept()# 字節類型while True:# 針對window系統try:…

使用pssh進行并行批量操作

假如同時給上千臺服務器執行一個命令,拷貝一個文件,殺一個進程等,有什么簡化運維管理的工具呢?在小型使用中我都是使用for循 環,數量巨大,一方面不確定操作是否成功,一方面for循環語句性能不好估計且是不是同步并行執行.,這類工具比如 pdsh,mussh&#…

圖像清晰度評價函數

概述 圖像清晰度是用來指導調焦機構找到正焦位置的評價函數。理想的清晰度評價曲線如下圖所示,其中P 是評價函數最大值的位置,其對應正焦位置,P1 和P2 為正焦位置焦前和焦后采集到圖像的清晰度評價結果。 為了指導調焦機構找到正焦位置,清晰度曲線須具有以下特點: 單…

Linux下讀寫芯片的I2C寄存器

Linux下讀寫芯片的I2C寄存器 2012-01-10 11:40:18 標簽:Linux 寄存器 驅動 讀寫 I2C 原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處 、作者信息和本聲明。否則將追究法律責任。http://ticktick.blog.51cto.com/823160/76096…

列表和表格---學習筆記02

第7章 列表和表格 7.1 有序列表<ol type"A"><li>這里是第1個li</li><li>這里是第2個li</li><li>這里是第3個li</li></ol> ol屬性&#xff1a;type : 數字(1),大小寫字母(A,a),大小寫羅馬數字(I,i)start: "起始…

(下)挖掘傳統行業日志大數據的無限價值

&#xfffc;8 月 27 日晚上八點&#xff0c;七牛云高級解決方案架構師程雪松在 IT 大咖說進行了題為《挖掘傳統行業日志大數據的無限價值》的直播&#xff0c;對傳統行業運維常見困境和統一日志管理的必要性進行了深入解析&#xff0c;并通過 Pandora 的一些真實用戶案例和大家…

CMOS圖像傳感器 —— ISOCELL

最近,外媒曝光了三星最新的CIS傳感器路線圖,路線圖顯示,三星在2億像素之外已經規劃2025年推出576MP像素的傳感器,也就是5億7千6百萬像素。 若5.76億像素的傳感器推出,意味著手機傳感器可媲美中高端單反水平了。三星沒有提及這個5.76億像素的傳感器是怎樣實現的。因…

LeetCode 153. Find Minimum in Rotated Sorted Array (在旋轉有序數組中找到最小值)

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). Find the minimum element. You may assume no duplicate exists in the array. 題目標簽&#xff1a;Array, Binary Se…

YUV圖像

YUV420P&#xff0c;Y&#xff0c;U&#xff0c;V三個分量都是平面格式&#xff0c;分為 I420 和 YV12 。 I420 格式和 YV12 格式的不同處在U平面和V平面的位置不同。在I420格式中&#xff0c;U平面緊跟在Y平面之后&#xff0c;然后才是V平面&#xff08;即&#xff1a;YUV&…

色調映射(Tone Mapping)

一、概述 雖然HDR 圖像有較大的動態范圍,能更細致地反映真實場景,但他的缺點也很明顯。一是同尺寸的數據比低動態范圍圖像大,需要更大的存儲空間與傳輸帶寬。二是難以輸出,目前大多數顯示器、打印機等圖形輸出設備的動態范圍要比普通的高動態范圍圖像小得多。。因此,色調映…

實用軟件工具

1.突破百度網盤下載速度現在&#xff0c;使用 Aria2下載 Aria2-不限速全平臺下載利器但是百度網盤賬號會被限速 &#xff0c;沖會員解除正常限制網速2.Safari 預覽&#xff0c;將網頁轉化為自定義尺寸 PDF 3.清除Xcode 緩存 刪除模擬器運行緩存&#xff0c;找到Developer->…

[原創]Toolbar setNavigationIcon無效

最近在做一個Toolbar&#xff0c;setNavigationIcon()這個方法一直無效&#xff0c;說什么的都有&#xff0c;什么getSupportActionBar().setNavigationIcon()的&#xff0c;說設置style的&#xff0c;說放到setSupportActionBar()之后的。 其實沒有說全&#xff0c;還應該放到…

YUV格式詳解

分類&#xff1a; H.264 MPEG TV 2008-05-14 09:24 16181人閱讀 評論(21) 收藏 舉報 YUV是指亮度參量和色度參量分開表示的像素格式&#xff0c;而這樣分開的好處就是不但可以避免相互干擾&#xff0c;還可以降低色度的采樣率而不會對圖像質量影響太大。YUV是一個比較籠統地說…

KVM安裝、鏡像創建(一)

環境準備 VMware Workstation Pro啟動虛擬化 查看啟動的系統是否支持vmx或svm grep -E (vmx|svm) /proc/cpuinfo 備注&#xff1a;操作系統centos 7 KVM安裝 1、yum查看kvm安裝包 yum list |grep kvm 2、安裝 yum install -y qemu-kvm qemu-kvm-tools libvirt3、啟動libvirtd s…

Sensor 結構——前照、背照、堆棧

優異的工藝和技術可以使得即便不使用更新結構的CMOS,同樣擁有更好的量子效率、固有熱噪聲、增益、滿阱電荷、寬容度、靈敏度等關鍵型指標。在相同技術和工藝下,底大一級的確壓死人(全畫幅和aps-c)。人類的進步就是在不斷發現問題,解決問題。背照式以及堆棧式CMOS的出現,也…