您的位置:首页 > 其它

s3c2410 A/D驱动

2012-03-05 13:37 155 查看
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/sched.h>

#define DEVICE_NAME "adc_driver"

#define pADCCON 0x58000000
#define pADCDAT0 0x5800000C

MODULE_LICENSE ("GPL");

unsigned long *vADCCON; /*ADC控制寄存器地址*/
unsigned long *vADCDAT0;/*ADCDAT0寄存器地址*/

int major = 250;
int minor = 0;
struct class *my_class;
wait_queue_head_t my_queue;

int sleep_flag = 0;
int number_of_devices = 1;

struct cdev cdev;
dev_t devno = 0;

/* open 打开设备 */
static int adc_driver_open(struct inode *inode, struct file *file)
{
struct clk *adc_clock = clk_get(NULL, "adc"); /*获得adc时钟*/
if (adc_clock == NULL) {
printk(KERN_WARNING "clk_get failed");
return -ENOENT;
}
clk_enable(adc_clock); /*时能ADC时钟,打开ADC*/

writel((1<<14)|(49<<6)|(0x00),vADCCON);
printk (KERN_INFO "adc_driver is open");

return 0;
}

static int adc_driver_release(struct inode *inode, struct file *file)
{
struct clk *adc_clock = clk_get(NULL, "adc");
clk_disable(adc_clock);

return 0;
}
/*中断处理函数(ADC 可以使用中断方式和轮询方式获得转换好的数据)*/
irqreturn_t interrupt_adc(int irq, void *dev_id)
{
sleep_flag = 1;
wake_up_interruptible(&my_queue);

return IRQ_HANDLED;
}
/*阻塞读*/
static ssize_t adc_driver_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned int num, ret;

writel((readl(vADCCON) & ~(0x3)) | (0x1),vADCCON);
wait_event_interruptible(my_queue, (sleep_flag == 1));
sleep_flag = 0;

num = readl(vADCDAT0) & (0x3FF);
ret = copy_to_user(buf, &num, sizeof(unsigned int));
if (ret < 0)
printk (KERN_WARNING "copy_to_user failed");
return ret;
}

struct file_operations adc_fops = {
.owner = THIS_MODULE,
.open = adc_driver_open,
.release = adc_driver_release,
.read = adc_driver_read,
};

static void char_reg_setup_cdev (void)
{
int error;
cdev_init (&cdev, &adc_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &adc_fops;
error = cdev_add (&cdev, devno , 1);
if (error)
printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev\n", error);
}

static int __init adc_driver_init (void)
{
int result;

if (major) {
devno = MKDEV(major,0);
result = register_chrdev_region(devno,number_of_devices,DEVICE_NAME);
}
else
result = alloc_chrdev_region(&devno, 0, number_of_devices, DEVICE_NAME);
if (result < 0) {
printk(KERN_WARNING "adc_driver: can't get major number %d\n", major);
return result;
}

vADCCON = ioremap(pADCCON, 4);
if (vADCCON == NULL) {
printk("ioremap vADCCON failed");
return -1;
}
vADCDAT0 = ioremap(pADCDAT0, 4);
if (vADCDAT0 == NULL) {
printk("ioremap vADCDAT0 failed");
goto err0;
}

init_waitqueue_head(&my_queue);

result = request_irq(IRQ_ADC, interrupt_adc, IRQF_DISABLED, "adc", NULL);
if (result < 0) {
printk (KERN_WARNING "request irq interrupt_adc failed\n");
}

my_class = class_create( THIS_MODULE, "adc_class" );
if(IS_ERR(my_class)) {
printk("Err: failed to create class.\n");
return -1;
}
device_create( my_class, NULL, devno, NULL, "adc_device");

char_reg_setup_cdev ();

printk (KERN_INFO "char device registered\n");
return 0;

err0:
iounmap(vADCDAT0);
return -1;

}

static void __exit adc_driver_exit (void)
{
iounmap(vADCCON);
iounmap(vADCDAT0);

free_irq(IRQ_ADC, NULL);

device_destroy(my_class, devno);
class_destroy(my_class);

cdev_del (&cdev);

unregister_chrdev_region (devno, number_of_devices);
printk (KERN_INFO "adc_driver is clean up\n");

}

module_init (adc_driver_init);
module_exit (adc_driver_exit);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: