编写一个字符驱动程序获取ADC通道0的电压值
一、开发环境:
1、 主机:Ubuntu 10.10发行版
2目标机:FS_S5PC100平台
3目标机内核版本:2.6.35
4、交叉编译工具:arm-none-linux-gnueabi-4.5.1
二、驱动编写的注意步骤:
1) 字符驱动open函数
打开时钟
中断申请
初始化寄存器
初始化等待队列
struct clk *clk;
static int myadc_open (struct inode *inode, struct file *file)
{
int ret;
/*打开时钟*/
clk = clk_get(NULL, "adc");
clk_enable(clk);
/*中断申请*/
if ((ret = request_irq(IRQ_ADC, myadc_irq, IRQF_DISABLED, "adc", NULL)) < 0)
{
printk(KERN_INFO "ADC request_irq error\n");
return ret;
}
/*初始化寄存器*/
adccon = (unsigned int *)ioremap(0xF3000000, 4);
adcmux = (unsigned int *)ioremap(0xF300001C, 4);
adcdat = (unsigned int *)ioremap(0xF300000C, 4);
adcclrint = (unsigned int *)ioremap(0xF3000018, 4);
writel(1<<0 | 1<<14 | 65<<6 | 1<<16, adccon);
writel(0, adcmux);
writel(readl(adcdat) & ~0xFFF, adcdat);
/*初始化等待队列*/
init_waitqueue_head(&rwait);
return 0;
}
2)关闭时钟
static int myadc_release (struct inode *inode, struct file *file)
{
/*关闭时钟*/
clk_put(clk);
clk_enable(clk);
printk (KERN_INFO "myadc closed\n");
return 0;
3)从寄存器ADCDAT0中取出转换后的值
ssize_t myadc_read (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
ssize_t result = 0;
/*开始转换ADCCON 1=1<<0*/
unsigned int data;
data = readl(adccon);
data |= 1<<0;
writel(data, adccon);
/*从寄存器ADCDAT0中取出转换后的值*/
wait_event(rwait, value != 0);
data = readl(adcdat) & 0xFFF;
if (copy_to_user((void *)buf,(char __user *)&data, count))
return -EFAULT;
else
printk (KERN_INFO "read %d bytes\n", count);
result = count;
value = 0;
return result;
4)中断函数
static irqreturn_t myadc_irq(int irq, void *p)
{
/*清中断*/
writel(0, adcclrint);
value = 1;
wake_up(&rwait);
return IRQ_HANDLED;
}
5)注意事项
由上图可知,该处理器中,触摸屏和ADC中断时共享的,所以保证内核中,没有注册触摸屏驱动。验证方法:cat /proc/interrupts,没有类似“samsung-adc”的内容。
三、测试:
1、编译应用程序
$ arm-none-linux-gnueabi-gcc test.c –o test
2、拷贝驱动及应用程序到目标板上
$ cp s5pc100_adc.ko test /source/rootfs
3、启动开发板后加载模块
# insmod s5pc100_adc.ko
4、创建设备节点
# mknod /dev/adc c 250 0
5、测试
# ./test
调节变阻器,终端会打印如下信息: