linux驱动之i2c子系统mpu6050设备驱动
以下是mpu6050簡(jiǎn)單的驅(qū)動(dòng)實(shí)現(xiàn),mpu6050是I2C接口的6軸傳感器,可以作為字符設(shè)備注冊(cè)到內(nèi)核,本代碼運(yùn)行環(huán)境是3.4.2內(nèi)核,4.3.2版本的編譯鏈,12.04版本的Ubuntu,硬件環(huán)境是jz2440開發(fā)板;
?
按照之前分析的I2C驅(qū)動(dòng)框架,mpu6050驅(qū)動(dòng)主要是實(shí)現(xiàn)外設(shè)端的驅(qū)動(dòng),主要是注冊(cè)外設(shè)到I2C總線,而外設(shè)端注冊(cè)到I2C總線包括device及driver兩個(gè)部分注冊(cè)到I2C總線,采用分離的設(shè)計(jì)思想,詳情見代碼:
?
device注冊(cè)到I2C總線:
?
#include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/err.h> #include <linux/regmap.h> #include <linux/slab.h>static const unsigned short addr_list[] = { 0x50,0x68, I2C_CLIENT_END }; static struct i2c_board_info mpu6050_info = {.type = "mpu6050", }; static struct i2c_client *mpu6050_client;static int mpu6050dev_init ( void ) {struct i2c_adapter *i2c_adap;i2c_adap = i2c_get_adapter ( 0 );mpu6050_client = i2c_new_probed_device ( i2c_adap, &mpu6050_info, addr_list, NULL );i2c_put_adapter ( i2c_adap );if ( mpu6050_client )return 0;elsereturn -ENODEV; } static void mpu6050dev_exit ( void ) {i2c_unregister_device ( mpu6050_client );}module_init ( mpu6050dev_init ); module_exit ( mpu6050dev_exit ); MODULE_LICENSE ( "GPL" );
?
注:為實(shí)現(xiàn)動(dòng)態(tài)加載驅(qū)動(dòng)模塊,使用了?i2c_new_probed_device ?函數(shù),該函數(shù)的關(guān)鍵作用是在把設(shè)備注冊(cè)到總線之前,會(huì)判斷該設(shè)備的地址是否真實(shí)有效,或者也可以說是該設(shè)備是否真實(shí)存在;另外也可以使用i2c_new_device函數(shù)來加載一個(gè)設(shè)備到總線,但是該函數(shù)類似I2C總線總force屬性,會(huì)強(qiáng)制認(rèn)為加載的設(shè)備地址真實(shí)有效,或者是強(qiáng)制認(rèn)為當(dāng)前的設(shè)備真實(shí)存在, ?另外在把mpu6050關(guān)聯(lián)到I2C適配器上時(shí),調(diào)用了?i2c_get_adapter ( 0 ) 函數(shù),由于S3C2440只有一個(gè)I2C適配器,所以該函數(shù)的參數(shù)直接寫0,即第一個(gè)適配器;
接下來是設(shè)備驅(qū)動(dòng)加載到I2C總線:
?
#include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/err.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/fs.h> #include <asm/uaccess.h> #include <linux/cdev.h>static ssize_t mpu6050_write ( struct file *file, const char __user *buf, size_t, loff_t *offset ); static ssize_t mpu6050_read ( struct file *file, char __user *buf, size_t size, loff_t *offset ); static int mpu6050drv_probe ( struct i2c_client *i2c_client, const struct i2c_device_id *i2c_device_id ); static int mpu6050drv_remove ( struct i2c_client *i2c_client );static struct i2c_device_id mpu6050drv_id = {.name = "mpu6050",.driver_data = 0x68,};static struct i2c_driver mpu6050drv = {.driver = {.name = "mympu6050",.owner = THIS_MODULE,},.probe = mpu6050drv_probe,.remove = mpu6050drv_remove,.id_table = &mpu6050drv_id,};/* 字符設(shè)備相關(guān) */ int major = 0; static struct cdev mpu6050_cdev; static struct file_operations mpu6050ops = {.owner = THIS_MODULE,.read = mpu6050_read,.write = mpu6050_write, };static struct class *cls; static ssize_t mpu6050_read ( struct file *file, char __user *buf, size_t size, loff_t *offset ) {return 0; }static ssize_t mpu6050_write ( struct file *file, const char __user *buf, size_t size, loff_t *offset ) {return 0; } static int mpu6050drv_probe ( struct i2c_client *i2c_client, const struct i2c_device_id *i2c_device_id ) {dev_t dev = 0;printk ( "mpu6050drv_probe\r\n" ); #if 0/* 把mpu6050當(dāng)做字符設(shè)備注冊(cè)到內(nèi)核 */major = register_chrdev ( 0, "mpu6050", &mpu6050ops ); #elsealloc_chrdev_region ( &dev, 0, 2, "mpu6050_region" ); // 占用2個(gè)次設(shè)備號(hào)cdev_init ( &mpu6050_cdev, &mpu6050ops );mpu6050_cdev.owner = THIS_MODULE;cdev_add ( &mpu6050_cdev, dev, 2 ); // 占用2個(gè)次設(shè)備號(hào)#endifcls = class_create ( THIS_MODULE, "mpu6050cls" );major = MAJOR ( dev );device_create ( cls, NULL, MKDEV ( major, 0 ), NULL, "mpu6050" ); // device_create ( cls, NULL, MKDEV ( major, 1 ), NULL, "mpu6050_2" );return 0; } static int mpu6050drv_remove ( struct i2c_client *i2c_client ) {printk ( "mpu6050drv_remove\r\n" );unregister_chrdev_region ( 0, 1 );cdev_del ( &mpu6050_cdev );device_destroy ( cls, MKDEV ( major, 0 ) ); // device_destroy ( cls, MKDEV ( major, 1 ) ); class_destroy ( cls );return 0; } static int mpu6050_init ( void ) {i2c_add_driver ( &mpu6050drv );return 0; }static void mpu6050_exit ( void ) {i2c_del_driver ( &mpu6050drv );}module_init ( mpu6050_init ); module_exit ( mpu6050_exit ); MODULE_LICENSE ( "GPL" );
?
當(dāng)設(shè)備加載到I2C總線,外設(shè)驅(qū)動(dòng)也加載到總線后,I2Ccore會(huì)調(diào)用match函數(shù),匹配?mpu6050drv 結(jié)構(gòu)體總?id_table ?成員里的name是否和加載的外設(shè)名一致,如果一致就會(huì)進(jìn)行綁定,然后調(diào)用外設(shè)驅(qū)動(dòng)的probe函數(shù),這樣I2C驅(qū)動(dòng)就基本上完成了,接下來就是根據(jù)外設(shè)的具體情況去處理了,比如如果外設(shè)是mpu6050、則當(dāng)做字符設(shè)備注冊(cè)到內(nèi)核,然后編寫讀寫函數(shù),這些就已經(jīng)不是I2C驅(qū)動(dòng)框架之內(nèi)的工作了,而是字符設(shè)備驅(qū)動(dòng)的范疇了;
本驅(qū)動(dòng)沒有具體去實(shí)現(xiàn)mpu6050的讀寫過程,具體的代碼完全可以借用裸機(jī)版的代碼,本實(shí)例僅供I2C驅(qū)動(dòng)框架參考。
轉(zhuǎn)載于:https://www.cnblogs.com/weishengzhong/p/7468397.html
總結(jié)
以上是生活随笔為你收集整理的linux驱动之i2c子系统mpu6050设备驱动的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【bzoj3924】[Zjoi2015]
- 下一篇: GoF23种设计模式之行为型模式之解释器