硬件描述:
S3c2440有一個10-bit的CMOS ADC 模數轉換器,支持8個模擬通道輸入,10位的分辨率,最高速度可達500KSPS(500 千次/每秒)。
從圖中可知:模擬ADC,包含了2部分功能,一部分是觸屏功能,另一部分就是普通ADC功能,分別可以產生INT_TC和INT_ADC 兩個中斷。8個AIN模擬輸入(A[3:0],YM,YP,XM,XP)通過一個8路模擬開關MUX進行通道片選。 ADC模塊共有20個寄存器。對於普通ADC轉換,使用ADCCON 和 ADCDAT0即可完成控制。ADCCON用於控制設置,ADCDAT0保存了轉換結果。
驅動程序ADC_DEV.ko:
[cpp]
- #include <linux/errno.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/clk.h>
- #include <asm/io.h>
- #include <asm/irq.h>
- #include <linux/interrupt.h>
- #include <mach/regs-clock.h>
- #include <plat/regs-adc.h>
- #include <linux/miscdevice.h>
- #include <linux/fs.h>
- #include <linux/uaccess.h>
-
- #define DEVICE_NAME "ADC_DEV"
-
- struct ADC_DEV {
- wait_queue_head_t wait;
- int ch;
- int pres;
- int data;
- int flag;
- };
-
- static struct ADC_DEV adc_dev;
-
- static void __iomem *ADC_REG_BASE;
- static struct clk *adc_clk;
-
- #define ADCCON (*(volatile unsigned long *)(ADC_REG_BASE + S3C2410_ADCCON))
- #define ADCDAT0 (*(volatile unsigned long *)(ADC_REG_BASE + S3C2410_ADCDAT0))
- #define START_ADC(ch,pres) ADCCON = (0x01 | 0x01<<14 | ch<<3 | pres<<6)
-
-
- static ssize_t adc_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
- {
- START_ADC(adc_dev.ch, adc_dev.pres); //啟動ADC轉換
- wait_event_interruptible(adc_dev.wait,adc_dev.flag); //等待ADC轉換完成
- adc_dev.flag = 0;
-
- copy_to_user(buf,(char*)&adc_dev.data,sizeof(adc_dev.data));
-
- return (sizeof(adc_dev.data));
- }
- static int adc_open(struct inode *in, struct file *fp)
- {
- adc_dev.ch = 0x02; //輸入通道2
- adc_dev.pres = 0xff; //prescale : 0 ~255 可選
- adc_dev.data = 0;
- adc_dev.flag = 0;
- init_waitqueue_head(&(adc_dev.wait));
-
- return 0;
- }
- static irqreturn_t adc_done_handler(int irq, void *dev_id)
- {
- adc_dev.data = ADCDAT0 & 0x3ff;
- adc_dev.flag = 1;
- wake_up_interruptible(&adc_dev.wait); //喚醒等待事件
-
- return IRQ_HANDLED;
- }
-
- static struct file_operations dev_fops = {
- .owner = THIS_MODULE,
- .open = adc_open,
- .read = adc_read,
- };
-
- static struct miscdevice misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = DEVICE_NAME,
- .fops = &dev_fops,
- };
-
- static int __init dev_init(void)
- {
- int ret;
-
- ADC_REG_BASE = ioremap(S3C2410_PA_ADC,0x14); //物理地址映射
- adc_clk = clk_get(NULL,"adc");
- if (!adc_clk) {
- return -ENOENT;
- }
- clk_enable(adc_clk); //開啟adc 時鐘,系統開機時默認是關閉的
-
- ret = request_irq(IRQ_ADC,adc_done_handler,IRQF_SHARED,DEVICE_NAME,&adc_dev); //分配中斷線
- if (ret) {
- iounmap(ADC_REG_BASE);
- return ret;
- }
-
- ret = misc_register(&misc); //注冊設備
-
- return ret;
- }
-
-
- static void __exit dev_exit(void)
- {
- misc_deregister(&misc);
- }
-
- module_init(dev_init);
- module_exit(dev_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("itspy");
- MODULE_DESCRIPTION("adc driver test");