Chinaunix首页 | 论坛 | 博客
  • 博客访问: 186185
  • 博文数量: 43
  • 博客积分: 2190
  • 博客等级: 大尉
  • 技术积分: 659
  • 用 户 组: 普通用户
  • 注册时间: 2009-02-04 16:15
文章分类
文章存档

2015年(1)

2013年(2)

2012年(1)

2011年(6)

2010年(11)

2009年(22)

分类: LINUX

2009-04-17 14:58:41

s3c2410_adc中断方式实现
 
/*
*    HLG442-S3C2410-ADC_DRV
* /26/03/2008    AUTHOR "machuanlong"
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include    /* printk() */
#include    /* kmalloc() */
#include        /* everything... */
#include     /* error codes */
#include     /* size_t */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "s3c2410-adc.h"

#include
#include
 
#define DEVICE_NAME "adc"
static int adc_major = 0;
typedef struct {
 struct semaphore lock;
 wait_queue_head_t wait;
 int channel;
 int prescale;
}ADC_DEV;
static ADC_DEV adcdev;
static irqreturn_t adcdone_int_handler(int irq,void *dev_id,struct pt_regs *regs)
{
 wake_up(&adcdev.wait);
 return IRQ_HANDLED ;
}
static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
 return 0;
}
static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
  int ret = 0;
  
 if (down_interruptible(&adcdev.lock))
  return -ERESTARTSYS;
 writel((readl(S3C2410_CLKCON) | S3C2410_CLKCON_ADC),S3C2410_CLKCON);
 writel((1<<14) | PRSCVL(adcdev.prescale) | ADC_INPUT(adcdev.channel) | 0x01 | 0x01, S3C2410_ADCCON);
 interruptible_sleep_on(&adcdev.wait);
 ret = readl(S3C2410_ADCDAT0);
 ret &= 0x3ff;
 copy_to_user(buffer, (char *)&ret, sizeof(ret));
 up(&adcdev.lock);

 return sizeof(ret);
}
static int s3c2410_adc_open(struct inode *inode, struct file *filp)

  int ret;
  ret = request_irq(IRQ_ADC, adcdone_int_handler, SA_INTERRUPT, DEVICE_NAME, NULL);
 if (ret) {
  return ret;
 }
 init_MUTEX(&adcdev.lock);
 init_waitqueue_head(&(adcdev.wait));
 adcdev.channel=0;
 adcdev.prescale=255;
 return 0;
}
static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
 free_irq(IRQ_ADC, NULL);
 printk( "adc closed\n");
 return 0;
}

static void adc_setup_cdev(struct cdev *dev, int minor,
  struct file_operations *fops)
{
 int err, devno = MKDEV(adc_major, minor);
   
 cdev_init(dev, fops);
 dev->owner = THIS_MODULE;
 dev->ops = fops;
 err = cdev_add (dev, devno, 1);
 /* Fail gracefully if need be */
 if (err)
  printk (KERN_NOTICE "Error %d adding adc %d", err, minor);
}
static struct cdev AdcDevs;
static struct file_operations adc_remap_ops = {
 .owner =THIS_MODULE,
 .open = s3c2410_adc_open,
 .read = s3c2410_adc_read, 
 .write = s3c2410_adc_write,
 .release = s3c2410_adc_release,
};

int __init adc_init(void)
{
 /* normal ADC */
 writel(0,S3C2410_ADCTSC); //XP_PST(NOP_MODE);
 int result;
 dev_t dev = MKDEV(adc_major, 0);
 /* Figure out our device number. */
 if (adc_major)
  result = register_chrdev_region(dev, 1, "adc");
 else {
  result = alloc_chrdev_region(&dev, 0, 1, "adc");
  adc_major = MAJOR(dev);
 }
 if (result < 0) {
  printk(KERN_WARNING "adc: unable to get major %d\n", adc_major);
  return result;
 }
 if (adc_major == 0)                         
  adc_major = result;
 adc_setup_cdev(&AdcDevs, 0, &adc_remap_ops);
 printk("adc device installed, with major %d\n", adc_major);
 return 0;
}
static void adc_cleanup(void)
{
 cdev_del(&AdcDevs);
 unregister_chrdev_region(MKDEV(adc_major, 0), 1);
 printk("adc device uninstalled\n");
}

module_init(adc_init);
module_exit(adc_cleanup);
MODULE_AUTHOR("Machuanlong");
MODULE_LICENSE("Dual BSD/GPL");
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
Makefile(驱动的)
///////////////////////////////////////////////////////////////////////////////////
ifeq ($(KERNELRELEASE),)
#KERNELDIR ?= /source/kernel/linux-2.6.8.1-farsight
KERNELDIR ?= /disk2/linux-2.6.14
PWD := $(shell pwd)
modules:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
 rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
    obj-m := s3c2410_adc.o
endif
 
///////////////////////////////////////////////////////////////////////////////////
s3c2410-adc.h
///////////////////////////////////////////////////////////////////////////////////
#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)
#define ADC_INPUT(x)  (x<<3)
#define PRSCVL(x)  (x<<6)
#endif /* _S3C2410_ADC_H_ */
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
测试程序:
main.c
///////////////////////////////////////////////////////////////////////////////////
/************************************************\
**HLG442 ADC-TEST
 /26/3/2008
Author machuanlong
*      *
\***********************************************/
#include
#include
#include
#include
#include
#include
#include
#include "s3c2410-adc.h"
#define ADC_DEV  "/dev/adc"
static int adc_fd=-1;
static int GetADresult()
{
 int data;
 read(adc_fd, &data, sizeof(data));
 return data;
}
static int stop=0;
int main(void)
{
 int i;
 float d;
 if((adc_fd=open(ADC_DEV, O_RDWR))<0){
  printf("Error opening %s adc device\n", ADC_DEV);
  return -1;
 }
                                                                              
 while(1){
   d=((float)GetADresult()*3.3)/1024.0;
   printf("a%d=%8.4f\t",0,d);
   printf("\n");
   sleep(1);
   printf("\r");
  
 }
 close(adc_fd);
 return 0;
}
阅读(3405) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~