
1、AP3216簡(jiǎn)介
AP3216C 芯片集成了光強(qiáng)傳感器( ALS: Ambient Light Sensor),接近傳感器( PS: Proximity Sensor),還有一個(gè)紅外LED( IR LED)。
(資料圖片)
這個(gè)芯片設(shè)計(jì)的用途是給手機(jī)之類的使用,比如:返回當(dāng)前環(huán)境光強(qiáng)以便調(diào)整屏幕亮度;用戶接聽(tīng)電話時(shí),將手機(jī)放置在耳邊后,自動(dòng)關(guān)閉屏幕避免用戶誤觸碰 。
該芯片通過(guò) I2C接口與主控制器相連, 如:
2、IIC驅(qū)動(dòng)簡(jiǎn)介
Linux下IIC有兩種驅(qū)動(dòng)方式:一種是按照字符設(shè)備驅(qū)動(dòng)方式來(lái)驅(qū)動(dòng)IIC;另一種是走Linux下IIC的框架。按照字符設(shè)備驅(qū)動(dòng)的方式可以查閱這一篇文章:Linux IIC 字符設(shè)備 驅(qū)動(dòng)例子。
這里我們了解學(xué)習(xí)一下第二種方式,因?yàn)檎业降腁P3216的驅(qū)動(dòng)就是基于IIC驅(qū)動(dòng)框架的,哈哈。
整個(gè)IIC的驅(qū)動(dòng)框架相關(guān)代碼在driversi2c中,包含的內(nèi)容有:
IIC驅(qū)動(dòng)框架圖如(圖片來(lái)源于網(wǎng)絡(luò),鏈接見(jiàn)文末參考資料):
IIC驅(qū)動(dòng)框架可大體分為兩大部分:
① I2C 總線驅(qū)動(dòng):SOC 的 I2C 控制器驅(qū)動(dòng),也叫做 I2C 適配器驅(qū)動(dòng)。
② I2C 設(shè)備驅(qū)動(dòng):針對(duì)具體的 I2C 設(shè)備而編寫(xiě)的驅(qū)動(dòng)。
其中,訪問(wèn)抽象層與I2C核心層數(shù)據(jù)I2C 總線驅(qū)動(dòng)部分;driver驅(qū)動(dòng)層屬于I2C設(shè)備驅(qū)動(dòng)部分。
上面框圖對(duì)應(yīng)的代碼調(diào)用層次圖如:
下面的AP3216驅(qū)動(dòng)可以對(duì)照這張圖來(lái)看看。
4、AP3216實(shí)驗(yàn)
我們使用設(shè)備樹(shù)來(lái)描述AP3216設(shè)備信息,首先我們沒(méi)有在設(shè)備樹(shù)中添加AP3216相關(guān)節(jié)點(diǎn)時(shí),我們系統(tǒng)的I2C設(shè)備如:
添加I2C pinctrl,板子上AP3216接的是I2C1:
配置寄存器的值都設(shè)為0x4001b8b0,這一段是什么意思我們?cè)?strong>什么是Pinctrl子系統(tǒng)及GPIO子系統(tǒng)?這篇筆記中也有寫(xiě)到,就是幾個(gè)寄存器及其配置。
接下來(lái)在i2c1節(jié)點(diǎn)下添加ap3216節(jié)點(diǎn):
編譯設(shè)備樹(shù),傳到開(kāi)發(fā)板上,重啟。此時(shí)我們系統(tǒng)的I2C設(shè)備有:
可見(jiàn),新增的AP3216 I2C設(shè)備名就是我們?cè)O(shè)備樹(shù)里設(shè)置的。
下面編寫(xiě)AP3216驅(qū)動(dòng)(以下代碼來(lái)源于網(wǎng)絡(luò)):
ap3216.c:
#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include"ap3216creg.h"/***************************************************************文件名:ap3216c.c描述:AP3216C驅(qū)動(dòng)程序***************************************************************/#defineAP3216C_CNT1#defineAP3216C_NAME"ap3216c"structap3216c_dev{dev_tdevid;/*設(shè)備號(hào)*/structcdevcdev;/*cdev*/structclass*class;/*類*/structdevice*device;/*設(shè)備*/structdevice_node*nd;/*設(shè)備節(jié)點(diǎn)*/intmajor;/*主設(shè)備號(hào)*/void*private_data;/*私有數(shù)據(jù)*/unsignedshortir,als,ps;/*三個(gè)光傳感器數(shù)據(jù)*/};staticstructap3216c_devap3216cdev;/**@description:從ap3216c讀取多個(gè)寄存器數(shù)據(jù)*@param-dev:ap3216c設(shè)備*@param-reg:要讀取的寄存器首地址*@param-val:讀取到的數(shù)據(jù)*@param-len:要讀取的數(shù)據(jù)長(zhǎng)度*@return:操作結(jié)果*/staticintap3216c_read_regs(structap3216c_dev*dev,u8reg,void*val,intlen){intret;structi2c_msgmsg[2];structi2c_client*client=(structi2c_client*)dev->private_data;/*msg[0]為發(fā)送要讀取的首地址*/msg[0].addr=client->addr;/*ap3216c地址*/msg[0].flags=0;/*標(biāo)記為發(fā)送數(shù)據(jù)*/msg[0].buf=?/*讀取的首地址*/msg[0].len=1;/*reg長(zhǎng)度*//*msg[1]讀取數(shù)據(jù)*/msg[1].addr=client->addr;/*ap3216c地址*/msg[1].flags=I2C_M_RD;/*標(biāo)記為讀取數(shù)據(jù)*/msg[1].buf=val;/*讀取數(shù)據(jù)緩沖區(qū)*/msg[1].len=len;/*要讀取的數(shù)據(jù)長(zhǎng)度*/ret=i2c_transfer(client->adapter,msg,2);if(ret==2){ret=0;}else{printk("i2crdfailed=%dreg=%06xlen=%d",ret,reg,len);ret=-EREMOTEIO;}returnret;}/**@description:向ap3216c多個(gè)寄存器寫(xiě)入數(shù)據(jù)*@param-dev:ap3216c設(shè)備*@param-reg:要寫(xiě)入的寄存器首地址*@param-val:要寫(xiě)入的數(shù)據(jù)緩沖區(qū)*@param-len:要寫(xiě)入的數(shù)據(jù)長(zhǎng)度*@return:操作結(jié)果*/statics32ap3216c_write_regs(structap3216c_dev*dev,u8reg,u8*buf,u8len){u8b[256];structi2c_msgmsg;structi2c_client*client=(structi2c_client*)dev->private_data;b[0]=reg;/*寄存器首地址*/memcpy(&b[1],buf,len);/*將要寫(xiě)入的數(shù)據(jù)拷貝到數(shù)組b里面*/msg.addr=client->addr;/*ap3216c地址*/msg.flags=0;/*標(biāo)記為寫(xiě)數(shù)據(jù)*/msg.buf=b;/*要寫(xiě)入的數(shù)據(jù)緩沖區(qū)*/msg.len=len+1;/*要寫(xiě)入的數(shù)據(jù)長(zhǎng)度*/returni2c_transfer(client->adapter,&msg,1);}/**@description:讀取ap3216c指定寄存器值,讀取一個(gè)寄存器*@param-dev:ap3216c設(shè)備*@param-reg:要讀取的寄存器*@return:讀取到的寄存器值*/staticunsignedcharap3216c_read_reg(structap3216c_dev*dev,u8reg){u8data=0;ap3216c_read_regs(dev,reg,&data,1);returndata;#if0structi2c_client*client=(structi2c_client*)dev->private_data;returni2c_smbus_read_byte_data(client,reg);#endif}/**@description:向ap3216c指定寄存器寫(xiě)入指定的值,寫(xiě)一個(gè)寄存器*@param-dev:ap3216c設(shè)備*@param-reg:要寫(xiě)的寄存器*@param-data:要寫(xiě)入的值*@return:無(wú)*/staticvoidap3216c_write_reg(structap3216c_dev*dev,u8reg,u8data){u8buf=0;buf=data;ap3216c_write_regs(dev,reg,&buf,1);}/**@description :讀取AP3216C的數(shù)據(jù),讀取原始數(shù)據(jù),包括ALS,PS和IR, 注意!*:如果同時(shí)打開(kāi)ALS,IR+PS的話兩次數(shù)據(jù)讀取的時(shí)間間隔要大于112.5ms*@param-ir:ir數(shù)據(jù)*@param-ps:ps數(shù)據(jù)*@param-ps:als數(shù)據(jù)*@return :無(wú)。*/voidap3216c_readdata(structap3216c_dev*dev){unsignedchari=0;unsignedcharbuf[6];/*循環(huán)讀取所有傳感器數(shù)據(jù)*/for(i=0;i<6;i++){buf[i]=ap3216c_read_reg(dev,AP3216C_IRDATALOW+i);}if(buf[0]&0X80)/*IR_OF位為1,則數(shù)據(jù)無(wú)效*/dev->ir=0;else/*讀取IR傳感器的數(shù)據(jù)*/dev->ir=((unsignedshort)buf[1]<<2)|(buf[0]&0X03);dev->als=((unsignedshort)buf[3]<<8)|buf[2];/*讀取ALS傳感器的數(shù)據(jù)*/if(buf[4]&0x40)/*IR_OF位為1,則數(shù)據(jù)無(wú)效*/dev->ps=0;else/*讀取PS傳感器的數(shù)據(jù)*/dev->ps=((unsignedshort)(buf[5]&0X3F)<<4)|(buf[4]&0X0F);}/**@description:打開(kāi)設(shè)備*@param-inode:傳遞給驅(qū)動(dòng)的inode*@param-filp:設(shè)備文件,file結(jié)構(gòu)體有個(gè)叫做private_data的成員變量*一般在open的時(shí)候?qū)rivate_data指向設(shè)備結(jié)構(gòu)體。*@return:0成功;其他失敗*/staticintap3216c_open(structinode*inode,structfile*filp){filp->private_data=&ap3216cdev;/*初始化AP3216C*/ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x04);/*復(fù)位AP3216C*/mdelay(50);/*AP3216C復(fù)位最少10ms*/ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0X03);/*開(kāi)啟ALS、PS+IR*/return0;}/**@description:從設(shè)備讀取數(shù)據(jù)*@param-filp:要打開(kāi)的設(shè)備文件(文件描述符)*@param-buf:返回給用戶空間的數(shù)據(jù)緩沖區(qū)*@param-cnt:要讀取的數(shù)據(jù)長(zhǎng)度*@param-offt:相對(duì)于文件首地址的偏移*@return:讀取的字節(jié)數(shù),如果為負(fù)值,表示讀取失敗*/staticssize_tap3216c_read(structfile*filp,char__user*buf,size_tcnt,loff_t*off){shortdata[3];longerr=0;structap3216c_dev*dev=(structap3216c_dev*)filp->private_data;ap3216c_readdata(dev);data[0]=dev->ir;data[1]=dev->als;data[2]=dev->ps;err=copy_to_user(buf,data,sizeof(data));return0;}/**@description:關(guān)閉/釋放設(shè)備*@param-filp:要關(guān)閉的設(shè)備文件(文件描述符)*@return:0成功;其他失敗*/staticintap3216c_release(structinode*inode,structfile*filp){return0;}/*AP3216C操作函數(shù)*/staticconststructfile_operationsap3216c_ops={.owner=THIS_MODULE,.open=ap3216c_open,.read=ap3216c_read,.release=ap3216c_release,};/**@description:i2c驅(qū)動(dòng)的probe函數(shù),當(dāng)驅(qū)動(dòng)與*設(shè)備匹配以后此函數(shù)就會(huì)執(zhí)行*@param-client:i2c設(shè)備*@param-id:i2c設(shè)備ID*@return:0,成功;其他負(fù)值,失敗*/staticintap3216c_probe(structi2c_client*client,conststructi2c_device_id*id){/*1、構(gòu)建設(shè)備號(hào)*/if(ap3216cdev.major){ap3216cdev.devid=MKDEV(ap3216cdev.major,0);register_chrdev_region(ap3216cdev.devid,AP3216C_CNT,AP3216C_NAME);}else{alloc_chrdev_region(&ap3216cdev.devid,0,AP3216C_CNT,AP3216C_NAME);ap3216cdev.major=MAJOR(ap3216cdev.devid);}/*2、注冊(cè)設(shè)備*/cdev_init(&ap3216cdev.cdev,&ap3216c_ops);cdev_add(&ap3216cdev.cdev,ap3216cdev.devid,AP3216C_CNT);/*3、創(chuàng)建類*/ap3216cdev.class=class_create(THIS_MODULE,AP3216C_NAME);if(IS_ERR(ap3216cdev.class)){returnPTR_ERR(ap3216cdev.class);}/*4、創(chuàng)建設(shè)備*/ap3216cdev.device=device_create(ap3216cdev.class,NULL,ap3216cdev.devid,NULL,AP3216C_NAME);if(IS_ERR(ap3216cdev.device)){returnPTR_ERR(ap3216cdev.device);}ap3216cdev.private_data=client;return0;}/**@description:i2c驅(qū)動(dòng)的remove函數(shù),移除i2c驅(qū)動(dòng)的時(shí)候此函數(shù)會(huì)執(zhí)行*@param-client:i2c設(shè)備*@return:0,成功;其他負(fù)值,失敗*/staticintap3216c_remove(structi2c_client*client){/*刪除設(shè)備*/cdev_del(&ap3216cdev.cdev);unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);/*注銷掉類和設(shè)備*/device_destroy(ap3216cdev.class,ap3216cdev.devid);class_destroy(ap3216cdev.class);return0;}/*傳統(tǒng)匹配方式ID列表*/staticconststructi2c_device_idap3216c_id[]={{"iot,ap3216c",0},{}};/*設(shè)備樹(shù)匹配列表*/staticconststructof_device_idap3216c_of_match[]={{.compatible="iot,ap3216c"},{/*Sentinel*/}};/*i2c驅(qū)動(dòng)結(jié)構(gòu)體*/staticstructi2c_driverap3216c_driver={.probe=ap3216c_probe,.remove=ap3216c_remove,.driver={.owner=THIS_MODULE,.name="ap3216c",.of_match_table=ap3216c_of_match,},.id_table=ap3216c_id,};/**@description:驅(qū)動(dòng)入口函數(shù)*@param:無(wú)*@return:無(wú)*/staticint__initap3216c_init(void){intret=0;ret=i2c_add_driver(&ap3216c_driver);returnret;}/**@description:驅(qū)動(dòng)出口函數(shù)*@param:無(wú)*@return:無(wú)*/staticvoid__exitap3216c_exit(void){i2c_del_driver(&ap3216c_driver);}/*module_i2c_driver(ap3216c_driver)*/module_init(ap3216c_init);module_exit(ap3216c_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("pjw");
驅(qū)動(dòng)詳解可查閱注釋及配合上訴的I2C驅(qū)動(dòng)框架的框圖及數(shù)據(jù)手冊(cè)理解。
ap3216creg.h:
#ifndefAP3216C_H#defineAP3216C_H/***************************************************************文件名:ap3216creg.h描述:AP3216C寄存器地址描述頭文件***************************************************************/#defineAP3216C_ADDR0X1E/*AP3216C器件地址*//*AP3316C寄存器*/#defineAP3216C_SYSTEMCONG0x00/*配置寄存器*/#defineAP3216C_INTSTATUS0X01/*中斷狀態(tài)寄存器*/#defineAP3216C_INTCLEAR0X02/*中斷清除寄存器*/#defineAP3216C_IRDATALOW0x0A/*IR數(shù)據(jù)低字節(jié)*/#defineAP3216C_IRDATAHIGH0x0B/*IR數(shù)據(jù)高字節(jié)*/#defineAP3216C_ALSDATALOW0x0C/*ALS數(shù)據(jù)低字節(jié)*/#defineAP3216C_ALSDATAHIGH0X0D/*ALS數(shù)據(jù)高字節(jié)*/#defineAP3216C_PSDATALOW0X0E/*PS數(shù)據(jù)低字節(jié)*/#defineAP3216C_PSDATAHIGH0X0F/*PS數(shù)據(jù)高字節(jié)*/#endif
ap3216應(yīng)用:
ap3216cApp.c:
#include"stdio.h"#include"unistd.h"#include"sys/types.h"#include"sys/stat.h"#include"sys/ioctl.h"#include"fcntl.h"#include"stdlib.h"#include"string.h"#include#include#include#include#include/***************************************************************文件名:ap3216cApp.c描述: ap3216c設(shè)備測(cè)試APP。使用方法:./ap3216cApp /dev/ap3216c***************************************************************//**@description:main主程序*@param-argc:argv數(shù)組元素個(gè)數(shù)*@param-argv:具體參數(shù)*@return:0成功;其他失敗*/intmain(intargc,char*argv[]){intfd;char*filename;unsignedshortdatabuf[3];unsignedshortir,als,ps;intret=0;if(argc!=2){printf("ErrorUsage!");return-1;}filename=argv[1];fd=open(filename,O_RDWR);if(fd<0){printf("can"topenfile%s",filename);return-1;}while(1){ret=read(fd,databuf,sizeof(databuf));if(ret==0){/*數(shù)據(jù)讀取成功*/ir=databuf[0];/*ir傳感器數(shù)據(jù)*/als=databuf[1];/*als傳感器數(shù)據(jù)*/ps=databuf[2];/*ps傳感器數(shù)據(jù)*/printf("ir=%d,als=%d,ps=%d",ir,als,ps);}usleep(200000);/*100ms*/}close(fd);/*關(guān)閉文件*/return0;}
編寫(xiě)Makefile,從之前的文章拷貝過(guò)來(lái)修改:
KERN_DIR=/home/book/100ask_imx6ull-sdk/Linux-4.9.88all:make-C$(KERN_DIR)M=`pwd`modules$(CROSS_COMPILE)gcc-oap3216cAppap3216cApp.cclean:make-C$(KERN_DIR)M=`pwd`modulescleanrm-rfmodules.orderrm-fap3216cApp#參考內(nèi)核源碼drivers/char/ipmi/Makefile#要想把a(bǔ).c,b.c編譯成ab.ko,可以這樣指定:#ab-y:=a.ob.o#obj-m+=ab.oobj-m+=ap3216.o
編譯得到ap3216.ko及ap3216cApp,傳到板子上運(yùn)行:
以上就是本次的實(shí)驗(yàn)分享,如果文章對(duì)你有幫助,歡迎轉(zhuǎn)發(fā),謝謝!
編輯:黃飛
標(biāo)簽: