S3C2440 ADC驱动实例开发讲解(源代码) --经测试完全可以运行
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define
DEVICE_NAME "adc_driver"
static void __iomem *adc_base; static struct clk *adc_clk;
DECLARE_MUTEX(ADC_LOCK); static DECLARE_WAIT_QUEUE_HEAD(adc_waitq);
static volatile int ev_adc = 0; //
static int adc_data;
static irqreturn_t adc_irq(int irq, void *dev_id)
{
if(!ev_adc)
{
adc_data = readl(adc_base +
S3C2410_ADCDAT0) & 0x3ff;
ev_adc = 1;
//将可读标识为1,并唤醒等待队列
wake_up_interruptible(&adc_waitq);
}
return
IRQ_HANDLED;
}
static int adc_open(struct inode *inode, struct file *file)
{
int ret;
ret = request_irq(IRQ_ADC, adc_irq, IRQF_SHARED,
DEVICE_NAME, 1);
if (ret)
{
printk(KERN_ERR "IRQ%d error
%d\n", IRQ_ADC, ret);
return -EINVAL;
}
return
0;
}
static void start_adc(void)
{
unsigned int tmp;
tmp = (1 << 14)
| (255 << 6) | (0
<< 3);
writel(tmp, adc_base + S3C2410_ADCCON);
tmp = readl(adc_base + S3C2410_ADCCON);
tmp = tmp | (1 <<
0); writel(tmp, adc_base + S3C2410_ADCCON);
}
static ssize_t adc_read(struct file *filp, char *buffer, size_t
count, loff_t *ppos)
{
if
(down_trylock(&ADC_LOCK))
{
return -EBUSY;
}
if(!ev_adc)
{
if(filp->f_flags
& O_NONBLOCK) //应用程序若采用非阻塞方式读取则返回错误
{
return
-EAGAIN;
}
else
{
start_adc(); wait_event_interruptible(adc_waitq,
ev_adc);
}
}
ev_adc = 0;
copy_to_user(buffer, (char
*)&adc_data, sizeof(adc_data));
up(&ADC_LOCK);
return sizeof(adc_data);
}
static int adc_release(struct inode *inode, struct file
*filp)
{
return
0;
}
static struct file_operations adc_fops =
{
.owner = THIS_MODULE,
.open = adc_open,
.read =
adc_read, .release = adc_release,
};
static struct miscdevice adc_miscdev =
{
.minor =
MISC_DYNAMIC_MINOR,
.name =
DEVICE_NAME, .fops =
&adc_fops, };
static int __init adc_init(void)
{
int ret; adc_clk =
clk_get(NULL, "adc");
if (!adc_clk)
{
printk(KERN_ERR "failed to find
adc clock source\n");
return -ENOENT;
}
clk_enable(adc_clk);
adc_base =
ioremap(S3C2410_PA_ADC, 0x20);
if (adc_base == NULL)
{
printk(KERN_ERR "Failed to
remap register block\n");
ret =
-EINVAL;
goto err_noclk;
}
ret =
misc_register(&adc_miscdev);
if (ret)
{
printk(KERN_ERR "cannot
register miscdev on minor=%d (%d)\n",
MISC_DYNAMIC_MINOR, ret);
goto err_nomap;
}
printk(DEVICE_NAME "
initialized!\n");
return
0;
//以下是上面错误处理的跳转点
err_noclk:
clk_disable(adc_clk);
clk_put(adc_clk);
err_nomap:
iounmap(adc_base);
return
ret;
}
static void __exit adc_exit(void)
{
free_irq(IRQ_ADC, 1);
iounmap(adc_base);
if (adc_clk)
{
clk_disable(adc_clk); clk_put(adc_clk);
adc_clk = NULL;
}
misc_deregister(&adc_miscdev);
}
//EXPORT_SYMBOL(ADC_LOCK);
module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("youshaohui 2012.10.31 in ruanjianyuan");
MODULE_DESCRIPTION("s3c2440 ADC Driver");
//==========================================================
//应用程序测试代码如下:
#include
#include
#include
#include
#include
#include
#define MYADC "/dev/adc_driver"
void Delay_MS( unsigned int time) //50
ns
{
unsigned int i,j;
for ( i=0; i
{
for(j=0;j<30000;j++)
{
} } }
//adc可调电阻
int main(void)
{
int fd;
int i=0;
unsigned int value = -1;
char buf[30]={0};
fd = open(MYADC,O_RDWR,0666);
if (fd < 0)
{
perror("open device adc_driver
error\n");
exit(1);
}
printf("open /dev/adc_driver success!\n");
while(1)
{
read(fd,&value,4);
printf("result
value=%d\n",value);
Delay_MS(1000);
}
if(close(fd)<0)
{
perror("close error\n");
exit(1);
}
return 0;
}