| 
 | 
 
各位大侠帮忙解决一下,我现在想用AD的第2路作为电压采集,第3路作为电流采集,我将天嵌上的ADC驱动更改了一下,当然adc_test也改了,我知道第2路和第3路是不能同时采集的,我现在是交替采集的,但采集出来的数据很漂,非常不稳当。下面是驱动程序: 
/************************************* 
 
NAME:EmbedSky_hello.c 
COPYRIGHT:www.embedsky.net 
 
*************************************/ 
 
#include <linux/errno.h> 
#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/slab.h> 
#include <linux/input.h> 
#include <linux/init.h> 
#include <linux/serio.h> 
#include <linux/delay.h> 
#include <linux/clk.h> 
#include <asm/io.h> 
#include <asm/irq.h> 
#include <asm/uaccess.h> 
#include <mach/regs-clock.h> 
#include <plat/regs-timer.h> 
          
#include <plat/regs-adc.h> 
#include <mach/regs-gpio.h> 
#include <linux/cdev.h> 
#include <linux/miscdevice.h> 
 
#include "tq2440_adc.h" 
 
#undef DEBUG 
//#define DEBUG 
#ifdef DEBUG 
#define DPRINTK(x...) {printk(KERN_DEBUG "EmbedSky_adc: " x);} 
#else 
#define DPRINTK(x...) (void)(0) 
#endif 
 
#define DEVICE_NAME        "adc" 
 
static void __iomem *base_addr; 
 
typedef struct 
{ 
        wait_queue_head_t wait; 
        int channel; 
        int prescale; 
}ADC_DEV; 
 
DECLARE_MUTEX(ADC_LOCK); 
static int ADC_enable = 0; 
 
static ADC_DEV adcdev; 
static volatile int ev_adc = 0; 
static int adc_data; 
 
static struct clk        *adc_clock; 
 
#define ADCCON                (*(volatile unsigned long *)(base_addr + S3C2410_ADCCON))        //ADC control 
#define ADCTSC                (*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC))        //ADC touch screen control 
#define ADCDLY                (*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY))        //ADC start or Interval Delay 
#define ADCDAT0                (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0))        //ADC conversion data 0 
#define ADCDAT1                (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1))        //ADC conversion data 1 
#define ADCUPDN                (*(volatile unsigned long *)(base_addr + 0x14))                        //Stylus Up/Down interrupt status 
 
#define PRESCALE_DIS                (0 << 14) 
#define PRESCALE_EN                (1 << 14) 
#define PRSCVL(x)                ((x) << 6) 
#define ADC_INPUT(x)                ((x) << 3) 
#define ADC_START                (1 << 0) 
#define ADC_ENDCVT                (1 << 15) 
 
#define START_ADC_AIN(ch, prescale) \ 
        do{         ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \ 
                ADCCON |= ADC_START; \ 
        }while(0) 
 
 
static irqreturn_t adcdone_int_handler(int irq, void *dev_id) 
{ 
        if (ADC_enable) 
        { 
                adc_data = ADCDAT0 & 0x3ff; 
 
                ev_adc = 1; 
                wake_up_interruptible(&adcdev.wait); 
        } 
 
        return IRQ_HANDLED; 
} 
 
static ssize_t tq2440_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) 
{ 
        char str[20]; 
        int value; 
        size_t len; 
        if (down_trylock(&ADC_LOCK) == 0) 
        { 
                ADC_enable = 1; 
                START_ADC_AIN(adcdev.channel, adcdev.prescale); 
                wait_event_interruptible(adcdev.wait, ev_adc); 
 
                ev_adc = 0; 
 
                DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ((ADCCON & 0x80) ? 1:0)); 
 
                value = adc_data; 
                sprintf(str,"%5d", adc_data); 
                copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data)); 
 
                ADC_enable = 0; 
                up(&ADC_LOCK); 
        } 
        else 
        { 
                value = -1; 
        } 
 
        len = sprintf(str, "%d\n", value); 
        if (count >= len) 
        { 
                int r = copy_to_user(buffer, str, len); 
                return r ? r : len; 
        } 
        else 
        { 
                return -EINVAL; 
        } 
} 
 
static int tq2440_adc_open(struct inode *inode, struct file *filp) 
{ 
        init_waitqueue_head(&(adcdev.wait)); 
 
        //adcdev.channel=2;        //设置ADC的通道 
        adcdev.prescale=0xff; 
 
        DPRINTK( "ADC opened\n"); 
        return 0; 
} 
static int tq2440_adc_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg) 
{ 
        if (cmd<=0) 
        { 
                 
                return -EINVAL; 
        } 
        else 
        { 
         
        adcdev.channel=arg;         
        //adcdev.prescale=0xff; 
         
        return 0; 
        } 
} 
static int tq2440_adc_release(struct inode *inode, struct file *filp) 
{ 
        DPRINTK( "ADC closed\n"); 
        return 0; 
} 
 
 
static struct file_operations dev_fops = { 
        owner:        THIS_MODULE, 
        open:        tq2440_adc_open, 
        ioctl:  tq2440_adc_ioctl,         
                read:        tq2440_adc_read,         
        release:        tq2440_adc_release, 
}; 
 
static struct miscdevice misc = { 
        .minor = MISC_DYNAMIC_MINOR, 
        .name = DEVICE_NAME, 
        .fops = &dev_fops, 
}; 
 
static int __init dev_init(void) 
{ 
        int ret; 
 
        base_addr=ioremap(S3C2410_PA_ADC,0x20); 
        if (base_addr == NULL) 
        { 
                printk(KERN_ERR "failed to remap register block\n"); 
                return -ENOMEM; 
        } 
 
        adc_clock = clk_get(NULL, "adc"); 
        if (!adc_clock) 
        { 
                printk(KERN_ERR "failed to get adc clock source\n"); 
                return -ENOENT; 
        } 
        clk_enable(adc_clock); 
         
        ADCTSC = 0; 
 
        ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev); 
        if (ret) 
        { 
                iounmap(base_addr); 
                return ret; 
        } 
 
        ret = misc_register(&misc); 
 
        printk (DEVICE_NAME" initialized\n"); 
        return ret; 
} 
 
static void __exit dev_exit(void) 
{ 
        free_irq(IRQ_ADC, &adcdev); 
        iounmap(base_addr); 
 
        if (adc_clock) 
        { 
                clk_disable(adc_clock); 
                clk_put(adc_clock); 
                adc_clock = NULL; 
        } 
 
        misc_deregister(&misc); 
} 
 
EXPORT_SYMBOL(ADC_LOCK); 
module_init(dev_init); 
module_exit(dev_exit); 
 
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("www.embedsky.net"); 
MODULE_DESCRIPTION("ADC Drivers for EmbedSky SKY2440/TQ2440 Board and support touch"); |   
 
 
 
 |