ARM-Linux驅(qū)動--ADC驅(qū)動(中斷方式)
內(nèi)核版本:2.6.28
本文引用地址:http://m.butianyuan.cn/article/201611/318862.htm主機(jī)平臺:Ubuntu 11.04
內(nèi)核版本:2.6.39
原創(chuàng)作品,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/yming0221/archive/2011/06/26/6568937.aspx
這個驅(qū)動寫了好久,因為原來的Linux內(nèi)核編譯的時候?qū)?strong>觸摸屏驅(qū)動編譯進(jìn)內(nèi)核了,而觸摸屏驅(qū)動里的ADC中斷在注冊的時候類型選擇的是
IRQF_SAMPLE_RANDOM,不是共享類型,所以,自己寫的ADC驅(qū)動在每次open的時候,總提示ADC中斷注冊失敗。
解決方案:
重新配置內(nèi)核,選擇觸摸屏驅(qū)動以模塊的形式編譯,而不是直接編譯進(jìn)內(nèi)核,這樣Linux在啟動的時候不會自動加載觸摸屏驅(qū)動,當(dāng)然,IRQ_ADC中斷號不會被占用。這樣可以測試自己寫的ADC驅(qū)動了。
以下是驅(qū)動源代碼:
- #include
- #include
- #include
- #include
/*創(chuàng)建設(shè)備節(jié)點(diǎn)*/ - #include
- #include
/*定義DECLARE_WAIT_QUEUE_HEAD*/ - #include
/*定義了irqreturn_t等*/ - #include
interrupt.h>/*request_irqdisable_irqenable_irq*/ - #include
- #include
- #include/*其中包含了#include"mach/irqs.h"*/
- #include
adc.h> - #include
- #defineADC_MAJOR102
- #defineADC_NAME"my_adc"
- #defineSUCCESS0
- staticintadc_open(structinode*,structfile*);
- staticintadc_release(structinode*,structfile*);
- staticint__initadc_init(void);
- staticint__exitadc_exit(void);
- staticssize_tadc_read(structfile*,char*,size_t,loff_t*);
- volatileunsignedlongadc_con;
- unsignedlongadc_dat0;
- intflag;//等待任務(wù)完成標(biāo)志
- unsignedlongbuf;//存放轉(zhuǎn)換完成的數(shù)據(jù)
- //聲明等待隊列
- DECLARE_WAIT_QUEUE_HEAD(adc_wait);
- structclk*adc_clk;
- staticirqreturn_tadc_interrupt(intirq,void*dev_id)//中斷處理程序
- {
- if(flag==0)
- {
- buf=(readw(adc_dat0)&0x3ff);//讀取轉(zhuǎn)換完成的數(shù)據(jù)
- flag=1;
- wake_up_interruptible(&adc_wait);//喚醒等待其上的進(jìn)程
- printk("Readvalueis%ld/n",buf);
- }
- returnIRQ_HANDLED;
- }
- structfile_operationsadc_ops=
- {
- .owner=THIS_MODULE,
- .read=adc_read,
- .open=adc_open,
- .release=adc_release,
- };
- staticint__initadc_init(void)
- {
- intret;
- adc_clk=clk_get(NULL,"adc");//獲取時鐘
- clk_enable(adc_clk);//使能時鐘
- ret=register_chrdev(ADC_MAJOR,ADC_NAME,&adc_ops);//注冊設(shè)備
- if(ret<0)
- {
- printk("registerdevicefail/n");
- returnret;
- }
- adc_con=(unsignedlong)ioremap(0x58000000,4);
- adc_dat0=(volatileunsignedlong)ioremap(0x58000000+S3C2410_ADCDAT0,4);
- if(!(adc_con&adc_dat0))
- {
- printk("Failedtoioremap/n");
- gotohandle;
- }
- printk("Initialized.../n");
- returnSUCCESS;
- handle:
- unregister_chrdev(ADC_MAJOR,ADC_NAME);
- return-1;
- }
- staticintadc_open(structinode*inode,structfile*file)//打開設(shè)備函數(shù)
- {
- //注冊中斷
- intret;
- //disable_irq(IRQ_ADC);
- //enable_irq(IRQ_ADC);
- ret=request_irq(IRQ_ADC,adc_interrupt,IRQF_SHARED,ADC_NAME,1);//注冊中斷IRQ_ADC在mach/irqs.h中定義
- if(ret<0)
- {
- printk("IRQ%dcannotrequest/n",IRQ_ADC);
- returnret;
- }
- returnSUCCESS;
- }
- staticintadc_release(structinode*inode,structfile*file)//關(guān)閉設(shè)備函數(shù)
- {
- free_irq(IRQ_ADC,1);//釋放中斷
- returnSUCCESS;
- }
- staticssize_tadc_read(structfile*file,
- char*buffer,
- size_tlength,
- loff_t*offset)//設(shè)備讀取函數(shù)
- {
- writew((1<<14)|(0x31<<6),adc_con);//設(shè)置ADCCON
- writew((readw(adc_con)|0x1),adc_con);//啟動AD轉(zhuǎn)換
- wait_event_interruptible(adc_wait,flag);
- flag=0;
- }
- staticint__exitadc_exit(void)//驅(qū)動卸載函數(shù)
- {
- iounmap(adc_con);
- iounmap(adc_dat0);
- unregister_chrdev(ADC_MAJOR,ADC_NAME);
- clk_disable(adc_clk);
- clk_put(adc_clk);
- printk("Theadcisunintialized/n");
- returnSUCCESS;
- }
- module_init(adc_init);
- module_exit(adc_exit);
- MODULE_LICENSE("GPL");
Makefile文件:
- obj-m:=adc.o
- KERNELDIR?=/arm/linux-2.6.28.7-2440
- PWD:=$(shellpwd)
- default:
- $(MAKE)-C$(KERNELDIR)M=$(PWD)modules
- clean:
- rm-f*.o*.ko*.order*.symversread
- read:
- arm-linux-gcc-oreadread_adc.c
以下是測試代碼:
- #include
- #include
- #include
- #defineADC_DEVICE"/dev/my_adc"
- intmain()
- {
- intret;
- unsignedintdata;
- ret=open(ADC_DEVICE,0);
- if(ret<0)
- {
- printf("Openadcfail/n");
- returnret;
- }
- for(;;)
- {
- //printf("cnt=%d/n",cnt);
- read(ret,&data,sizeof(data));
- //printf("Thevalueis%d/n",data);
- }
- close(ret);
- return0;
- }
首先新建設(shè)備:
mknod /dev/my_adc c 102 32
然后插入驅(qū)動 insmod adc.ko
運(yùn)行測試程序./read
結(jié)果如下:
可以看出,調(diào)節(jié)ad轉(zhuǎn)換器上的旋鈕,看到AD轉(zhuǎn)換值的變化,說明驅(qū)動工作正常。
評論