- 论坛徽章:
- 0
|
回复 #9 Tim_tsang 的帖子
我贴下代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/bcd.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <asm/arch-s3c2410/regs-adc.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <linux/sched.h>
#include <asm/irq.h>
#include <asm/semaphore.h>
#include <asm/arch/regs-gpio.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include "adc123.h"
MODULE_LICENSE("Dual BSD/GPL");
int adc_major;
int adc_minor;
static int zeng;
struct cdev adc_cdev;
static void __iomem *base_addr;
struct clk *clk;
static int ch;
wait_queue_head_t wait; //zenglei
static irqreturn_t adcdone_int_handler(int irq,void *dev_id)
{
zeng=readl(base_addr+S3C2410_ADCDAT0);
zeng=zeng & 0x3ff;
wake_up_interruptible(&wait);
//interruptible_sleep_on(&wait);
//printk(KERN_ERR "zenglei\n");
return IRQ_HANDLED ;
}
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,ret,LOOP=100;
clk_enable(clk); //enable clk
writel((1<<14)|S3C2410_ADCCON_PRSCVL(19)|(ch<<3)|(0<<1)|(0<<0),base_addr+S3C2410_ADCCON); //setup channel
//for(i=0;i<LOOP;i++); //delay to set up the next channel
writel((readl(base_addr+S3C2410_ADCCON)|0x1),base_addr+S3C2410_ADCCON); //start ADC
//wake_up(&wait);
interruptible_sleep_on(&wait); //zenglei
//writel(0,base_addr+S3C2410_ADCCON); //stop ADC
//i=readl(base_addr+S3C2410_ADCDAT0);
//i= i & 0x3ff;
writel(0,base_addr+S3C2410_ADCCON);
ret=copy_to_user(buf, &zeng, sizeof zeng);
return sizeof zeng;
}
static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
int data,ret;
if(count!=sizeof(data)){
printk("the size of input data must be %d\n", sizeof(data));
return 0;
}
ret=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 S3C2410_adc_init(void)
{
int result,err,ret;
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");
//zenglei
ret = request_irq(IRQ_ADC, adcdone_int_handler, SA_INTERRUPT,"adc", NULL);
if (ret) {
return ret;
}
init_waitqueue_head(&wait);//zenglei
printk(KERN_ERR "hahaha\n");
return 0;
}
void S3C2410_adc_exit(void)
{
dev_t dev=MKDEV(adc_major,adc_minor);
cdev_del(&adc_cdev);
iounmap(base_addr);
unregister_chrdev_region(dev,1);
free_irq(IRQ_ADC,NULL);
}
module_init(S3C2410_adc_init);
module_exit(S3C2410_adc_exit); |
|