Chinaunix首页 | 论坛 | 博客
  • 博客访问: 402845
  • 博文数量: 62
  • 博客积分: 1483
  • 博客等级: 上尉
  • 技术积分: 779
  • 用 户 组: 普通用户
  • 注册时间: 2009-02-24 12:25
文章分类

全部博文(62)

文章存档

2012年(2)

2011年(6)

2010年(6)

2009年(48)

我的朋友

分类: LINUX

2009-10-16 17:15:17

//只是根据touchscreen和led驱动改的而已,呵呵。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define DEVICE_NAME    "adc"
#define ADC_MAJOR 238

struct s3c2410_ts_mach_info {
       int             delay;
       int             presc;
       int             oversampling_shift;
}adc_info = {0xff,19};

static void __iomem *base_addr;

static inline void init_adc_gpio(void)
{
/*
    for (i = 0; i < 4; i++) {
        s3c2410_gpio_cfgpin(adc_table[i], adc_cfg_table[i]);
    }
   如果是触摸屏的话,要配置相应的gpio12,13,14,15为对应的功能,而adc0,1,2,3无须配置。
*    s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);
*    s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);
*    s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);
*    s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);
*/
}

/* ADCCON Register Bits */
#define S3C2410_ADCCON_ECFLG        (1<<15)
#define S3C2410_ADCCON_PRSCEN        (1<<14)
#define S3C2410_ADCCON_PRSCVL(x)    (((x)&0xFF)<<6)
#define S3C2410_ADCCON_PRSCVLMASK    (0xFF<<6)
#define S3C2410_ADCCON_SELMUX(x)    (((x)&0x7)<<3)
#define S3C2410_ADCCON_MUXMASK        (0x7<<3)
#define S3C2410_ADCCON_STDBM        (1<<2)
#define S3C2410_ADCCON_READ_START    (1<<1)
#define S3C2410_ADCCON_ENABLE_START    (1<<0)
#define S3C2410_ADCCON_STARTMASK    (0x3<<0)

#define CMD_ADC_START_AND_GET     1
#define CMD_SEL_MUX   2

#define S3C2410_ADCDAT0_MASK    (0x03FF)
static int my_adc_ioctl(
    struct inode *inode,
    struct file *file,
    unsigned int cmd,
    unsigned long arg)
{
    unsigned long val;

    switch(cmd) {
    case CMD_ADC_START_AND_GET:

//把对adc读取数据的过程当作临界区,加上这条语句,adc的输出数据好多了(连续的输出正确的数据)
//原来输出很多错误的数据,现在也偶尔有错误数据输出。
        local_irq_disable();
        val = readl(base_addr + S3C2410_ADCCON);
        writel(val | S3C2410_ADCCON_ENABLE_START,base_addr + S3C2410_ADCCON); //开始转换

        val = readl(base_addr + S3C2410_ADCCON);
        while(val & S3C2410_ADCCON_ENABLE_START){
            val = readl(base_addr + S3C2410_ADCCON);
        };

        val = readl(base_addr + S3C2410_ADCCON);
        while(!(val | S3C2410_ADCCON_ECFLG)){
            val = readl(base_addr + S3C2410_ADCCON);
        };

        val = readl(base_addr + S3C2410_ADCDAT0);
        val &= S3C2410_ADCDAT0_MASK;
        local_irq_enable();
        return val;
    case CMD_SEL_MUX:
        if (arg > 7) { //只能选择0~7八个通道之一
            return -EINVAL;
        }
        val = readl(base_addr+S3C2410_ADCCON);
        val &= ~S3C2410_ADCCON_MUXMASK;
        val |= S3C2410_ADCCON_SELMUX(arg);
        writel(val,base_addr+S3C2410_ADCCON);
//        printk(DEVICE_NAME "ADCCON:%x\n",val);
        return 0;
    default:
        return -EINVAL;
    }
}

static struct file_operations my_adc_fops = {
    .owner    =    THIS_MODULE,
    .ioctl    =    my_adc_ioctl,
};

static struct clk    *adc_clock;

static int __init my_adc_init(void)
{
    int ret;
    int val;

    struct s3c2410_ts_mach_info *info = &adc_info;

    ret = register_chrdev(ADC_MAJOR, DEVICE_NAME, &my_adc_fops);
    if (ret < 0) {
      printk(DEVICE_NAME "adc:can't register major number\n");
      return ret;
    }

    devfs_mk_cdev(MKDEV(ADC_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEVICE_NAME);
    
    init_adc_gpio();


//打开adc的时钟
    adc_clock = clk_get(NULL, "adc");
    if (!adc_clock) {
        printk(KERN_ERR "failed to get adc clock source\n");
        return -ENOENT;
    }
    clk_use(adc_clock);
    clk_enable(adc_clock);

/*    base_addr=ioremap(S3C2410_PA_ADC,0x20);
 *  在第2部分io映射的时候,已经映射了adc的io内存了,
 *  所以这里的ioremap是可有可无的。
 */
    base_addr = S3C24XX_VA_ADC;
   
    if ((info->presc&0xff) > 0)
        writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(info->presc&0xFF),\
                 base_addr+S3C2410_ADCCON);
    else
        writel(0,base_addr+S3C2410_ADCCON);

//选择normal模式,而不是stadby模式
    val = readl(base_addr+S3C2410_ADCCON);
    val &= ~S3C2410_ADCCON_STDBM;
    writel(val,base_addr+S3C2410_ADCCON);

//不使用touchscreen
    val = readl(base_addr+S3C2410_ADCTSC);
    val &= (1<<2);
    writel(val,base_addr+S3C2410_ADCTSC);

    printk(DEVICE_NAME " initialized\n");
    return 0;
}

static void __exit my_adc_exit(void)
{
    devfs_remove(DEVICE_NAME);
    unregister_chrdev(ADC_MAJOR, DEVICE_NAME);
    printk(DEVICE_NAME " uninstall\n");
}

module_init(my_adc_init);
module_exit(my_adc_exit);
MODULE_AUTHOR("lzd");
MODULE_DESCRIPTION("s3c2410 adc driver");
MODULE_LICENSE("GPL");

阅读(1605) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~