S3C-XXXX 通用ADC驱模板

本文详细介绍了S3C-XXXX系列处理器的ADC驱动程序设计原理及其实现过程,包括中断处理、文件操作接口、共享中断管理等关键技术点。

    ADC驱动。。。就是应用程序去读取ADC的值,具体来讲是读取ADC寄存器的值,那就是典型的字符驱动了,当然用作Input子系统的ADC驱动还是与普通的字符驱动有很大差别的。

/*                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
* S3C-XXXX ADC驱动程序                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
*                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
*/                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
include<linux/kernel.h> 	/* 提供prink等内核特有属性 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
include<linux/module.h> 	 /* 提供如MODULE_LICENSE()、EXPORT_SYMBOL() */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
include<linux/init.h> 		 /* 设置段,如_init、_exit,设置初始化优先级,如__initcall */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
include<linux/wait.h> 		 /* 等待队列wait_queue */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
include<linux/interrupt.h>   /* 中断方式,如IRQF_SHARED */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
include<linux/fs.h> 		 /* file_operations操作接口等 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
include<linux/clk.h> 		 /* 时钟控制接口,如struct clk */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
include<linux/miscdevice.h>  /* 杂项设备 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
include<asm/io.h> 			 /* 提供readl、writel */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
include<asm/irq.h> 			 /* 提供中断号,中断类型等,如IRQ_ADC中断号 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
include<asm/arch/regs-adc.h> /* 提供控制器的寄存器操作,如S3C2410_ADCCON */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
include<asm/uaccess.h> 		 /* 提供copy_to_user等存储接口 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* 定义设备名称,用户访问接口/dev/adc */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
#define	DEVICE_NAME "adc"                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* 定义adc时钟,通过adc_clock接口获得adc输入时钟,adc转换器需要 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
static struct clk *adc_clock;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* 定义虚拟地址访问硬件寄存器,__iomem只是用于表示指针将指向I/O内存 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
static void __iomem *base_addr;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* 定义并初始化一个等待队列adc_waitqueue,对ADC资源进行阻塞访问 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
static wait_queue_head_t adc_waitqueue;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* 定义并初始化信号量adc_lock,用于控制共享中断IRQ_ADC资源的使用 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
ECLARE_MUTEX(adc_lock);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
XPORT_SYMBOL(adc_lock);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* 定义等待队列的条件,当is_read_ok=1时,ADC转换完毕,数据可读 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
static volatile int is_read_ok = 0;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* 定义ADC转换的数据内容 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
static volatile int adc_data;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
static int adc_open(struct inode *inode, struct file *file);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
static ssize_t adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
static int adc_close(struct inode *inode, struct file *filp);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* 实现字符设备操作接口 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
static struct file_operations adc_fops =                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
   .owner   = THIS_MODULE,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
   .open    = adc_open,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
   .read    = adc_read,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
   .release = adc_close,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* 实现misc杂项设备操作接口 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
static struct miscdevice adc_miscdev =                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
   .minor  = MISC_DYNAMIC_MINOR, /* 动态获取杂项设备的次设备号 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
   .name   = DEVICE_NAME,        /* 杂项设备的设备名称,这里为adc */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
   .fops   = &adc_fops,          /* 杂项设备子系统接口,指向adc_fops操作接口 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* ADC中断服务程序,获取ADC转换后的数据 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
static irqreturn_t adc_irq(int irq, void *dev_id)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
   /* 仅当is_read_ok=0时才进行转换,防止多次中断 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
   if(!is_read_ok)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
   {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
       /* 读取ADCCON[9:0]的值,0x3ff为只获取[9:0]位,ADCCON为转换后的数据 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
       adc_data = readl(base_addr +S3C2410_ADCDAT0) & 0x3ff;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
       /* 设置标识为1,唤醒读等待进程可以拷贝数据给用户空间了 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
       is_read_ok = 1;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
      wake_up_interruptible(&adc_waitqueue);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
   }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
   return IRQ_RETVAL(IRQ_HANDLED);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/* ADC设备打开,并注册IRQ_ADC中断处理函数 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
static int adc_open(struct inode *inode, struct file *file)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
   int ret;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
   /* 由于IRQ_ADC为共享中断,因此中断类型选择IRQF_SHARED,最后一个参数需要设置NULL以外的值 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
   ret = request_irq(IRQ_ADC, adc_irq,IRQF_SHARED, DEVICE_NAME, (void *)1);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
   if (ret)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
   {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
       printk(KERN_ERR "Could not allocate ts IRQ_ADC !\n");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
       return -EBUSY;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
   }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
   return 0;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/*设置ADC控制寄存器,开启AD转换*/                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
static void adc_run(void)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
{                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    volatile unsigned int adccon;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* ADCCON的位[14]=1为使能A/D预分频器,位[13:6]=32表示设置的分频值,ADC的转换频率需要在2.5MHZ以下                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
     * 我们使用的ADC输入时钟为PCLK=50MHZ,50MHZ/32<2.5MHZ,满足条件                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
     * 位[5:3]=000,表示模拟输入通道选择AIN0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
     */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
    adccon = (1 << 14) | (64 << 6);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
    writel(adccon, base_addr + S3C2410_ADCCON);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 位[0]=1表示使能ADC转换,当转换完毕后此位被ADC控制器自动清0 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
    adccon = readl(base_addr + S3C2410_ADCCON)| (1 << 0);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
    writel(adccon, base_addr + S3C2410_ADCCON);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/*ADC设备驱动读函数 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
static ssize_t adc_read(struct file *filp, char *buff, size_t count, loff_t *offp)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
{                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
    int err;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 获取信号量,如果被占用,睡眠等待持有者调用up唤醒                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
     * 这样做的原因是,有可能其他进程抢占执行或是触摸屏驱动抢占执行                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
     */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
    down_interruptible(&adc_lock);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 启动adc转换,调用中断处理函数adc_irq*/                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
    adc_run();                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 如果is_read_ok为假,则睡眠等待条件为真,由中断处理函数唤醒 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
    wait_event_interruptible(adc_waitqueue,is_read_ok);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 执行到此说明中断处理程序获得了ADC转换后的值,清除为0等待下一次的读 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
    is_read_ok = 0;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 将转换后的数据adc_data提交给用户 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
    err = copy_to_user(buff, (char*)&adc_data, min(sizeof(adc_data),count));                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 释放信号量,并唤醒因adc_lock而睡眠的进程 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
    up(&adc_lock);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    return err ? -EFAULT : sizeof(adc_data);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
/*ADC设备关闭函数 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
static int adc_close(struct inode *inode, struct file *filp)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
{                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
    /*释放中断*/                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    free_irq(IRQ_ADC, (void *)1);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
    return 0;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
static int __init adc_init(void)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
{                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
    int ret;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 获得adc的时钟源,通过arch/arm/mach-s3c2410/clock.c获得提供的时钟源为PCLK */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
    adc_clock = clk_get(NULL, "adc");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    if (!adc_clock)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
    {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
        printk(KERN_ERR "failed to get adcclock source\n");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
        return -ENOENT;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
    }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 在时钟控制器中给adc提供输入时钟,ADC转换需要输入时钟 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
    clk_enable(adc_clock);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 使用ioremap获得操作ADC控制器的虚拟地址                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
     * S3C2410_PA_ADC=ADCCON,是ADC控制器的基地址,寄存器组的长度=0x1c                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
     */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
    base_addr = ioremap(S3C2410_PA_ADC, 0x1c);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
    if (base_addr == NULL)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
    {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
        printk(KERN_ERR "Failed to remapregister block\n");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
        return -ENOMEM;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
        goto fail1;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
    }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 初始化等待队列 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
    init_waitqueue_head(&adc_waitqueue);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 注册杂项设备 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    ret = misc_register(&adc_miscdev);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    if (ret)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
    {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
        printk(KERN_ERR "Failed toregister miscdev\n");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
        goto fail2;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
    }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    printk(DEVICE_NAME "initialized!\n");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    return 0;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
fail2:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    iounmap(base_addr);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
fail1:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    clk_disable(adc_clock);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
    clk_put(adc_clock);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    return ret;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
static void __exit adc_exit(void)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
{                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
    /* 释放虚拟地址 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    iounmap(base_addr);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /* 禁止ADC的时钟源 */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
    if (adc_clock)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
    {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
        clk_disable(adc_clock);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
        clk_put(adc_clock);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
        adc_clock = NULL;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
    }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    /*注销misc设备*/                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
    misc_deregister(&adc_miscdev);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
module_init(adc_init);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
module_exit(adc_exit);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
MODULE_LICENSE("GPL");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值