#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/kdev_t.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/wait.h> #include <linux/timer.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/uaccess.h> //copy_to_user #include <asm/io.h> #include <linux/clk.h> //ADC的一些地址的定义 #define S3C2440_ADC_BASE 0x58000000 #define IO_REMAP_SIZE 0x20 //IO映射地址大小 #define S3C2440_ADCCON 0 #define S3C2440_ADCDLY 0x8 #define S3C2440_ADCDAT0 0xC /*预分频值39,AIN0通道,正常转换,禁止读启动,无操作*/ #define ADCCON_CONFIG_VALUE ((1<<14)|(39<<6)|(0<<3)|(0<<2)|(0<<1)|(0)) #define ADC_START (ADCCON_CONFIG_VALUE | 0x1) #define ADCDLY_VALUE 0xff /*保存从平台时钟队列中获取ADC的时钟*/ static struct clk *adc_clk; #define DEV_NAME "fl2440_adc" #define DEV_COUNT 1 void *adc_base_addr=NULL; DECLARE_MUTEX(dev_sem_lock); struct DEV_STRUCT { int dev_major; //主设备号 struct cdev cdev; }dev_struct; //初始化ADC void init_adc(void) { writel(ADCCON_CONFIG_VALUE,adc_base_addr+S3C2440_ADCCON); writel(ADCDLY_VALUE,adc_base_addr+S3C2440_ADCDLY); } //启动ADC void start_adc(void) { writel(ADC_START,adc_base_addr+S3C2440_ADCCON); } //等待转换开始并完成 void wait_conv(void) { unsigned long i; do{ i=readl(adc_base_addr+S3C2440_ADCCON); }while(i & 0x1); do{ i=readl(adc_base_addr+S3C2440_ADCCON); }while(!(i & 0x8000)); } static int dev_open(struct inode* inode,struct file *filp) { return 0; } static int dev_release(struct inode *inode,struct file *filp) { return 0; } ssize_t dev_read(struct file *filp,char __user *userp,size_t count,loff_t *offp) { int data=0; if(down_trylock(&dev_sem_lock)) { if(filp->f_flags & O_NONBLOCK) return -EAGAIN; } start_adc(); wait_conv(); data=readl(adc_base_addr+S3C2440_ADCDAT0) & 0x3ff; copy_to_user(userp,(void*)&data,4); up(&dev_sem_lock); return count; } struct file_operations fops= { .owner=THIS_MODULE, .open=dev_open, .release=dev_release, .read=dev_read, }; static int __init dev_init(void) { dev_t dev_id; int err; dev_struct.dev_major=0; err=alloc_chrdev_region(&dev_id,0,DEV_COUNT,DEV_NAME); if(err) goto error0; dev_struct.dev_major=MAJOR(dev_id); cdev_init(&dev_struct.cdev,&fops); dev_struct.cdev.owner=THIS_MODULE; err=cdev_add(&dev_struct.cdev,dev_id,DEV_COUNT); if(err) goto error2; adc_clk = clk_get(NULL, "adc"); if (!adc_clk) { /*错误处理*/ printk(KERN_ERR "failed to find adc clock source/n"); return -ENOENT; } /*时钟获取后要使能后才可以使用,clk_enable定义在arch/arm/plat-s3c/clock.c中*/ clk_enable(adc_clk); adc_base_addr=ioremap(S3C2440_ADC_BASE,IO_REMAP_SIZE);//映射IO到内存区 if(IS_ERR(adc_base_addr)) goto error2; init_adc();// 初始化ADC printk("init module successful!/n"); return 0; error2: cdev_del(&dev_struct.cdev); unregister_chrdev_region(dev_id,DEV_COUNT); error0: return err; } static void __exit dev_exit(void) { cdev_del(&dev_struct.cdev); iounmap(adc_base_addr); unregister_chrdev_region(MKDEV(dev_struct.dev_major,0),DEV_COUNT); if (adc_clk) /*屏蔽和销毁时钟*/ { clk_disable(adc_clk); clk_put(adc_clk); adc_clk = NULL; } printk("exit module!/n"); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL");