一、开发环境
软件开发环境:linux-3.0
硬件开发环境:fl2440开发板
日期:2013.12.22
二、这个ADC驱动程序虽然很简单,但是我在写的时候费了很多时间,因为一开始我用中断来读数据,然而AD的中断号跟LCD的中断号共用了,用了共享中断,还是没能解决,由于能力有限,就没有用中断。下面是我写的ADC驱动的代码:
/*********************************************************************************
* Copyright: (C) 2013 Yang zheng<yangzheng@gmail.com>
* All rights reserved.
*
* Filename: fl2440_adc.c
* Description: This file
*
* Version: 1.0.0(12/17/2013~)
* Author: yangzheng <yangzheng@mail.com>
* ChangeLog: 1, Release initial version on "12/17/2013 07:14:19 PM"
*
********************************************************************************/
#include <plat/regs-adc.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/clk.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#define DEVICE_NAME "s3c-adc"
#define CON_BASE 0x58000000
#define DATA_BASE 0x5800000c
#define CON_LEN 4
#define DATA_LEN 4
#define s3c_adc_write(val, reg) __raw_writel((val), (reg))
#define s3c_adc_read(reg) __raw_readl((reg))
#define DEV_MAJOR 0
#define DESABLE 0
static void __iomem *adc_con; /* Defines a after virtual map is used to store the memory address*/
static void __iomem *adc_dat0; /* Defines a after virtual map is used to store the memory address*/
static struct clk *adc_clk; /* Save the clock in the queue for the ADC clock from the platform*/
static DEFINE_MUTEX(ADC_CLK); /* Statements and initialize a semaphore ADC_LOCK, on ADC resources for exclusive access*/
int dev_major = DEV_MAJOR;
int dev_minor = 0;
int dev_count = 1;
int debug = DESABLE;
static struct cdev *adc_cdev;
/* The opening of the ADC device driver interface function */
static int adc_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
file->private_data = (void *)minor;
printk(KERN_DEBUG "dev/fl2440_adc %d opened.\n", minor);
return 0;
}
/* The reading of the ADC device driver interface function*/
static ssize_t adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
unsigned long adc_data;
unsigned int tmp;
adc_con = ioremap(CON_BASE, CON_LEN); /* The memory mapping */
adc_dat0 = ioremap(DATA_BASE, DATA_LEN); /* The memory mapping */
tmp = s3c_adc_read(adc_con);
tmp = (0x1 << 14) | (0x5 << 6) | (0x0 << 3); /* 0100 00001 100 0000 */
s3c_adc_write(tmp, adc_con);
tmp = s3c_adc_read(adc_con);
tmp = tmp | (0x1 << 0);
s3c_adc_write(tmp, adc_con); /* Start the AD conversion*/
while (s3c_adc_read(adc_con) &0x1); /* Waiting to start a reset*/
while (!(s3c_adc_read(adc_con) & 0x8000)); /* Waiting for the AD conversion to complete*/
mutex_lock(&ADC_CLK);
adc_data = s3c_adc_read(adc_dat0);
copy_to_user (buffer, (char *)&adc_data, sizeof(adc_data));
mutex_unlock(&ADC_CLK);
return sizeof(adc_data);
}
/* The closing of the ADC device driver interface function */
static int adc_release(struct inode *inode, struct file *filp)
{
return 0;
}
/* Character device related operations */
static struct file_operations adc_fops = {
.owner = THIS_MODULE,
.open = adc_open,
.read = adc_read,
.release = adc_release,
};
/* Misc equipment structure */
//static struct miscdevice adc_miscdev = {
// .minor = MISC_DYNAMIC_MINOR, /* In the device number, defined in miscdevice. H, 255*/
// .name = DEVICE_NAME, /* Device name */
// .fops = &adc_fops, /* The ADC device file operations */
//};
static int __init adc_init(void)
{
int ret;
dev_t devno;
if (0 != dev_major)
{
devno = MKDEV(dev_major, 0);
ret = register_chrdev_region(devno, dev_count, DEVICE_NAME);
}
else
{
ret = alloc_chrdev_region(&devno, dev_minor, dev_count, DEVICE_NAME);
dev_major = MAJOR(devno);
}
if (ret < 0)
{
printk(KERN_ERR "S3C %s driver can't use major %d\n", DEVICE_NAME, dev_major);
return -ENODEV;
}
printk(KERN_DEBUG "S3C %s driver major %d\n", DEVICE_NAME, dev_major);
/* The clock in the queue for the ADC clock from the platform*/
adc_clk = clk_get(NULL, "fl2440_adc");
if (!(adc_clk = clk_get(NULL, "fl2440_adc")))
{
printk(KERN_ERR "failed to find adc clock source.\n");
goto err_irq;
return ENOENT;
}
/* The clock can get to make before you can use*/
clk_enable(adc_clk);
/* The ADC registered as misc equipment */
/* ret = misc_register(&adc_miscdev);
if (ret)
{
printk(KERN_ERR "cannot register on minor=%d (%d)", MISC_DYNAMIC_MINOR, ret);
goto err_noclk;
}*/
if(NULL == (adc_cdev=cdev_alloc()) )
{
printk(KERN_ERR "S3C %s driver can't alloc for the cdev.\n", DEVICE_NAME);
unregister_chrdev_region(devno, dev_count);
return -ENOMEM;
}
adc_cdev->owner = THIS_MODULE;
cdev_init(adc_cdev, &adc_fops);
ret = cdev_add(adc_cdev, devno, dev_count);
if (0 != ret)
{
printk(KERN_INFO "S3C %s driver can't reigster cdev: result=%d\n", DEVICE_NAME, ret);
goto ERROR;
}
printk(DEVICE_NAME "initialized.\n");
return 0;
ERROR:
printk(KERN_ERR "S3C %s driver installed failure.\n", DEVICE_NAME);
cdev_del(adc_cdev);
unregister_chrdev_region(devno, dev_count);
return ret;
err_irq:
free_irq(IRQ_ADC, (void *)1);
return ret;
}
void __exit adc_exit(void)
{
dev_t devno = MKDEV(dev_major, dev_minor);
cdev_del(adc_cdev);
unregister_chrdev_region(devno, dev_count);
iounmap(adc_con);
iounmap(adc_dat0);
if (adc_clk)
{
clk_disable(adc_clk);
clk_put(adc_clk);
adc_clk = NULL;
}
printk(KERN_ERR "S3C %s driver removed!\n", DEVICE_NAME);
return ;
}
module_init(adc_init);
module_exit(adc_exit);
module_param(debug, int, S_IRUGO);
module_param(dev_major, int, S_IRUGO);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("YangZheng");
MODULE_DESCRIPTION("FL2440 ADC Driver");
三、测试程序
/*********************************************************************************
* Copyright: (C) 2013 Yang zheng<yangzheng@gmail.com>
* All rights reserved.
*
* Filename: adc_test.c
* Description: This file
*
* Version: 1.0.0(12/18/2013~)
* Author: yangzheng <yangzheng@mail.com>
* ChangeLog: 1, Release initial version on "12/18/2013 08:28:44 PM"
*
********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/********************************************************************************
* Description:
* Input Args:
* Output Args:
* Return Value:
********************************************************************************/
int main (int argc, char **argv)
{
int fd;
fd = open("/dev/s3c-adc", 0);
if (fd < 0 )
{
printf("Open ADC device failed.\n");
exit(1);
}
for( ; ; )
{
int ret;
int data;
ret = read(fd, &data, sizeof(data));
if (sizeof(data) != ret)
{
if (errno != EAGAIN)
{
printf("Read ADC device failed.\n");
}
continue;
}
else
{
printf("ADC value is :%d\n", data);
}
sleep(1);
}
close(fd);
return 0;
} /* ----- End of main() ----- */