Chinaunix首页 | 论坛 | 博客
  • 博客访问: 175365
  • 博文数量: 32
  • 博客积分: 1910
  • 博客等级: 上尉
  • 技术积分: 495
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-31 21:28
文章存档

2009年(3)

2008年(29)

我的朋友

分类: LINUX

2008-12-05 15:17:58

Linux2.6内核2410 adc驱动程序

1、驱动程序,代码不是很多,直接贴出来了!

/*

 * s3c2410-adc.c

 *

 * S3C2410 ADC

 *  exclusive with s3c2410-ts.c

 *

 * Author: SeonKon Choi

 * Date  : $Date: 2003/01/20 14:24:49 $

 *

 * $Revision: 1.1.2.6 $

 *

       2008-6-14 add a device by lyj_uptech

 

   Fri Dec 03 2002 SeonKon Choi

   - initial

 

 *

 * This file is subject to the terms and conditions of the GNU General Public

 * License.  See the file COPYING in the main directory of this archive

 * for more details.

 */

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include 3c/regs-adc.h>

#include

 

#include

#include

#include

#include

#include

#include

#include

 

#include "s3c2410-adc.h"

MODULE_LICENSE("Dual BSD/GPL");

 

int adc_major;

int adc_minor;

 

struct cdev adc_cdev;

static void __iomem *base_addr;

struct clk *clk;

static int ch;

 

int adc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

{

        printk(KERN_ERR "cmd %d\n",cmd);

       ch=cmd; //set up channel

       return 0;

}

 

 

ssize_t s3c2410_adc_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos)

{

       int i,LOOP=10000;

 

 

       clk_enable(clk); //enable clk

 

       writel((1<<14)|S3C2410_ADCCON_PRSCVL(49)|(ch<<3)|(0<<1)|(0<<0),base_addr+S3C2410_ADCCON); //setup channel

 

       for(i=0;i

 

 

       writel((readl(base_addr+S3C2410_ADCCON)|0x1),base_addr+S3C2410_ADCCON); //start ADC

       while((readl(base_addr+S3C2410_ADCCON) & 0x1)); //check if enable start flag is low

       while(!(readl(base_addr+S3C2410_ADCCON) & 0x8000)); //check if EC(End of Conversion) flag is high

 

       writel(0,base_addr+S3C2410_ADCCON); //stop ADC

       i=readl(base_addr+S3C2410_ADCDAT0);

       i= i & 0x3ff;

       copy_to_user(buf, &i, sizeof i);

       return sizeof i;

}

 

static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)

{

        int data;

 

        if(count!=sizeof(data)){

                printk("the size of  input data must be %d\n", sizeof(data));

                return 0;

        }

 

        copy_from_user(&data, buffer, count);

        ch=ADC_WRITE_GETCH(data);

 

 

        return count;

}

 

 

struct file_operations adc_fops = {

       .owner = THIS_MODULE,

       .ioctl = adc_ioctl,

       .read = s3c2410_adc_read,

       .write = s3c2410_adc_write,

};

 

int S3C2410adc_init(void)

{

       int result,err;

       dev_t dev =0;

       result=alloc_chrdev_region(&dev,adc_minor,0,"2410adc");

       adc_major = MAJOR(dev);

       adc_minor = MINOR(dev);

       if(result < 0)

              printk(KERN_ERR "can't get major %d\n",adc_major);

       else

              printk("adc_major: %d\n",adc_major);

       cdev_init(&adc_cdev,&adc_fops);

       adc_cdev.owner=THIS_MODULE;

       adc_cdev.ops=&adc_fops;

       err=cdev_add(&adc_cdev,dev,1);

       if (err < 0)

              printk(KERN_ERR "can't add 2410_adc");

 

 

       base_addr = ioremap(0x58000000, 0x20);

       if (base_addr == NULL) {

              printk(KERN_ERR "Failed to remap register block\n");

              return -ENOMEM;

       }

 

       /* get our clock */

       clk = clk_get(NULL, "adc");

 

       if (IS_ERR(clk) || clk == NULL) {

              printk(KERN_ERR "ADC clk_get err!!!!!!!!!!!!!\n");

       }

 

       /* only enable the clock when we are actually using the adc */

 

       printk(KERN_ERR "add 2410_adc ok!!!!!!!!!!!!\n");

 

       return 0;

}

void S3C2410adc_exit(void)

{

       dev_t dev=MKDEV(adc_major,adc_minor);

       cdev_del(&adc_cdev);

       iounmap(base_addr);

       unregister_chrdev_region(dev,1);

}

module_init(S3C2410adc_init);

module_exit(S3C2410adc_exit);

2、驱动的头文件定义

 

#ifndef _S3C2410_ADC_H_

#define _S3C2410_ADC_H_

 

#define ADC_WRITE(ch, prescale)      ((ch)<<16|(prescale))

 

#define ADC_WRITE_GETCH(data)    (((data)>>16)&0x7)

#define ADC_WRITE_GETPRE(data)  ((data)&0xff)

 

#endif /* _S3C2410_ADC_H_ */

 

3、应用程序就不多说了,按照原来linux2.4的内核使用就可以了,不用做任何的改动。

4、需要注意的就是,这个驱动程序不能和触摸屏驱动一起使用。原来在linux2.4.18内核里面写过一个驱动程序把ad和触摸屏写在一起了,但是总感觉这种方法很蹩脚,所以在linux2.6里面我就没有再尝试。如果有需要的时候再做吧!也不是很难!

 

2008-12-5

于北京

MSN:liuyingjie201000@hotmail.com

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