s3c2410_adc中斷方式實(shí)現(xiàn)
/*
* HLG442-S3C2410-ADC_DRV
*/26/03/2008 AUTHOR "machuanlong"
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include ccess.h>
#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 adc.h>
#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 closedn");
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 %dn", 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 %dn", adc_major);
return 0;
}
static void adc_cleanup(void)
{
cdev_del(&AdcDevs);
unregister_chrdev_region(MKDEV(adc_major, 0), 1);
printk("adc device uninstalledn");
}
module_init(adc_init);
module_exit(adc_cleanup);
MODULE_AUTHOR("Machuanlong");
MODULE_LICENSE("Dual BSD/GPL");
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
Makefile(驅(qū)動(dòng)的)
///////////////////////////////////////////////////////////////////////////////////
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_ */
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
測(cè)試程序:
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 devicen", ADC_DEV);
return -1;
}
while(1){
d=((float)GetADresult()*3.3)/1024.0;
printf("a%d=%8.4ft",0,d);
printf("n");
sleep(1);
printf("r");
}
close(adc_fd);
return 0;
}
這兩個(gè)都是字符型驅(qū)動(dòng)希望對(duì)初學(xué)者用所幫助