基于fl2440内核linux-3.0移植----添加adc驱动
2014-08-27 08:27
288 查看
一、开发环境
内核版本:linux-3.0
开发板:FL2440(nandflash:K9F1G08 128M)
编译器:arm-linux-gcc 4.3.2
二、原理分析
1. 硬件原理图分析。由原理图得知:处理器S3C2440 提供了8 通道10 位模数转换接口(其中有四个通道用于触摸屏),其微分
线性误差(Differential Linearity Error)可达±1.0 LSB,积分线性误差(Integral LinearityError)可达±2.0 LSB,FL2440 开发板引出其中一路接1 个可调电阻,可做AD 模数转换测试,其硬件电路如下:
三、配置内核
make menuconfig来配置内核,因为我用的内核是linux-3.0版本,其对ADC是默认选项的(不可选择),
System Type --->
-*- ADC common driver support
如果用的内核版本是不可选择的,那个可以直接创建设备节点,然后运行测试程序。如果不是默认选上的话,那么在内核就不要选上,然后编译内核下载到开发板上。
下面是自己写驱动加载的过程:
四、写驱动和测试程序:
编写适合fl2440开发板的adc驱动,文件名称:dev_adc.c(代码在后面),编译生成dev_adc.ko文件,并下载到开发板/目录下面。
编写适合自己驱动的adc测试程序,文件名称:s3c_adc.c(代码在后面),并有gcc工具编译生成可执行文件,并下载到开发板/usr/sbin目录下。
五、加载和测试adc驱动
[root@root /]# ls
apps dev_adc init mnt sys var
bin dev_adc.ko jbs.mp3 proc tmp vim_conf.bin
data etc lib root tslib yw.mp3
dev info linuxrc sbin usr
[root@root /]# insmod dev_adc.ko
[root@root /]# cat proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
[root@root /]# mknod dev/adc c 10 59
[root@root /]# s3c_adc
adc default channel value : 0
adc channel 0 value : 0
adc channel 1 value : 0
adc channel 2 value : 0
adc channel 3 value : 0
至此adc驱动添加就成功了,注意的是如果内核已经选上了System Type ---> -*- ADC common driver support ,直接创建设备节点就好了,运行测试程序就好。添加驱动会不成功,显示insmod: can't
insert 'dev_adc.ko': invalid parameter,我估计是中断号被内核支持的ADC占用。
以下是驱动和测试程序:
/***************************dev_adc.c***********************************************/
#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/wait.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
static void __iomem *adc_base;
static struct clk *adc_clk;
int dev_id = 1;
DEFINE_MUTEX(ADC_LOCK);
#define DEVICE_NAME "adc"
static DECLARE_WAIT_QUEUE_HEAD(adc_waitq);
static volatile int ev_adc = 0;
static int adc_data;
static void start_adc(void)
{
unsigned int tmp;
tmp = (1 << 14) | (255 << 6) | (0 << 3); /* 0 1 00000011 000 0 0 0 */
writel(tmp, adc_base + S3C2410_ADCCON);
tmp = readl(adc_base + S3C2410_ADCCON);
tmp = tmp | (1 << 0); /* 0 1 00000011 000 0 0 1 */
writel(tmp, adc_base + S3C2410_ADCCON);
}
static irqreturn_t adc_irq(int irq, void *dev_id)
{
if (!ev_adc)
{
adc_data = readl(adc_base + S3C2410_ADCDAT0) & 0x3ff;
ev_adc = 1;
wake_up_interruptible(&adc_waitq);
}
return IRQ_HANDLED;
}
static int adc_open(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t adc_read(struct file *filp, char *buffer, size_t count, loff_t * ppos)
{
mutex_lock(&ADC_LOCK);
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));
mutex_unlock(&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;
ret = request_irq(IRQ_ADC, adc_irq, IRQF_SHARED, DEVICE_NAME, &dev_id);
{
printk(KERN_ERR "IRQ%d error %d\n", IRQ_ADC, ret);
return -EINVAL;
}
adc_base = ioremap(S3C2410_PA_ADC, 0x20);
if (adc_base == NULL)
{
printk(KERN_ERR "Failed to remap register block\n");
ret = -EINVAL;
goto err_nomap;
}
adc_clk = clk_get(NULL, "adc");
if (!adc_clk)
{
printk(KERN_ERR "failed to find adc clock source\n");
goto err_irq;
return -ENOENT;
}
clk_enable(adc_clk);
if (ret)
{
printk(KERN_ERR "cannot register miscdev on minor=%d (%d)\n", MISC_DYNAMIC_MINOR, ret);
goto err_noclk;
}
printk(DEVICE_NAME " initialized!\n");
return 0;
err_nomap:
iounmap(adc_base);
err_noclk:
clk_disable(adc_clk);
clk_put(adc_clk);
err_irq:
free_irq(IRQ_ADC, &dev_id);
return ret;
}
static void __exit adc_exit(void)
{
free_irq(IRQ_ADC, &dev_id);
iounmap(adc_base);
if (adc_clk)
{
clk_disable(adc_clk);
clk_put(adc_clk);
adc_clk = NULL;
}
misc_deregister(&adc_miscdev);
}
module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");
/**********************s3c_adc.c**********************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
int main(void)
{
int adc_fd;
int adc_value, adc_size;
int i;
adc_fd = open("/dev/adc", O_RDONLY);
if (adc_fd < 0)
{
perror("open device adc");
exit(1);
}
adc_size = read(adc_fd, &adc_value, sizeof(adc_value));
printf("adc default channel value : %d\n", adc_value);
for (i = 0; i < 4; i++)
{
adc_size = read(adc_fd, &adc_value, sizeof(adc_value));
printf("adc channel %d value : %d\n", i, adc_value);
}
close(adc_fd);
return 0;
}
内核版本:linux-3.0
开发板:FL2440(nandflash:K9F1G08 128M)
编译器:arm-linux-gcc 4.3.2
二、原理分析
1. 硬件原理图分析。由原理图得知:处理器S3C2440 提供了8 通道10 位模数转换接口(其中有四个通道用于触摸屏),其微分
线性误差(Differential Linearity Error)可达±1.0 LSB,积分线性误差(Integral LinearityError)可达±2.0 LSB,FL2440 开发板引出其中一路接1 个可调电阻,可做AD 模数转换测试,其硬件电路如下:
三、配置内核
make menuconfig来配置内核,因为我用的内核是linux-3.0版本,其对ADC是默认选项的(不可选择),
System Type --->
-*- ADC common driver support
如果用的内核版本是不可选择的,那个可以直接创建设备节点,然后运行测试程序。如果不是默认选上的话,那么在内核就不要选上,然后编译内核下载到开发板上。
下面是自己写驱动加载的过程:
四、写驱动和测试程序:
编写适合fl2440开发板的adc驱动,文件名称:dev_adc.c(代码在后面),编译生成dev_adc.ko文件,并下载到开发板/目录下面。
编写适合自己驱动的adc测试程序,文件名称:s3c_adc.c(代码在后面),并有gcc工具编译生成可执行文件,并下载到开发板/usr/sbin目录下。
五、加载和测试adc驱动
[root@root /]# ls
apps dev_adc init mnt sys var
bin dev_adc.ko jbs.mp3 proc tmp vim_conf.bin
data etc lib root tslib yw.mp3
dev info linuxrc sbin usr
[root@root /]# insmod dev_adc.ko
[root@root /]# cat proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
[root@root /]# mknod dev/adc c 10 59
[root@root /]# s3c_adc
adc default channel value : 0
adc channel 0 value : 0
adc channel 1 value : 0
adc channel 2 value : 0
adc channel 3 value : 0
至此adc驱动添加就成功了,注意的是如果内核已经选上了System Type ---> -*- ADC common driver support ,直接创建设备节点就好了,运行测试程序就好。添加驱动会不成功,显示insmod: can't
insert 'dev_adc.ko': invalid parameter,我估计是中断号被内核支持的ADC占用。
以下是驱动和测试程序:
/***************************dev_adc.c***********************************************/
#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/wait.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
static void __iomem *adc_base;
static struct clk *adc_clk;
int dev_id = 1;
DEFINE_MUTEX(ADC_LOCK);
#define DEVICE_NAME "adc"
static DECLARE_WAIT_QUEUE_HEAD(adc_waitq);
static volatile int ev_adc = 0;
static int adc_data;
static void start_adc(void)
{
unsigned int tmp;
tmp = (1 << 14) | (255 << 6) | (0 << 3); /* 0 1 00000011 000 0 0 0 */
writel(tmp, adc_base + S3C2410_ADCCON);
tmp = readl(adc_base + S3C2410_ADCCON);
tmp = tmp | (1 << 0); /* 0 1 00000011 000 0 0 1 */
writel(tmp, adc_base + S3C2410_ADCCON);
}
static irqreturn_t adc_irq(int irq, void *dev_id)
{
if (!ev_adc)
{
adc_data = readl(adc_base + S3C2410_ADCDAT0) & 0x3ff;
ev_adc = 1;
wake_up_interruptible(&adc_waitq);
}
return IRQ_HANDLED;
}
static int adc_open(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t adc_read(struct file *filp, char *buffer, size_t count, loff_t * ppos)
{
mutex_lock(&ADC_LOCK);
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));
mutex_unlock(&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;
ret = request_irq(IRQ_ADC, adc_irq, IRQF_SHARED, DEVICE_NAME, &dev_id);
{
printk(KERN_ERR "IRQ%d error %d\n", IRQ_ADC, ret);
return -EINVAL;
}
adc_base = ioremap(S3C2410_PA_ADC, 0x20);
if (adc_base == NULL)
{
printk(KERN_ERR "Failed to remap register block\n");
ret = -EINVAL;
goto err_nomap;
}
adc_clk = clk_get(NULL, "adc");
if (!adc_clk)
{
printk(KERN_ERR "failed to find adc clock source\n");
goto err_irq;
return -ENOENT;
}
clk_enable(adc_clk);
if (ret)
{
printk(KERN_ERR "cannot register miscdev on minor=%d (%d)\n", MISC_DYNAMIC_MINOR, ret);
goto err_noclk;
}
printk(DEVICE_NAME " initialized!\n");
return 0;
err_nomap:
iounmap(adc_base);
err_noclk:
clk_disable(adc_clk);
clk_put(adc_clk);
err_irq:
free_irq(IRQ_ADC, &dev_id);
return ret;
}
static void __exit adc_exit(void)
{
free_irq(IRQ_ADC, &dev_id);
iounmap(adc_base);
if (adc_clk)
{
clk_disable(adc_clk);
clk_put(adc_clk);
adc_clk = NULL;
}
misc_deregister(&adc_miscdev);
}
module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");
/**********************s3c_adc.c**********************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
int main(void)
{
int adc_fd;
int adc_value, adc_size;
int i;
adc_fd = open("/dev/adc", O_RDONLY);
if (adc_fd < 0)
{
perror("open device adc");
exit(1);
}
adc_size = read(adc_fd, &adc_value, sizeof(adc_value));
printf("adc default channel value : %d\n", adc_value);
for (i = 0; i < 4; i++)
{
adc_size = read(adc_fd, &adc_value, sizeof(adc_value));
printf("adc channel %d value : %d\n", i, adc_value);
}
close(adc_fd);
return 0;
}
相关文章推荐
- 基于fl2440内核linux-3.0移植----添加按键驱动
- fl2440内核linux-3.0移植-----添加led驱动
- Linux-2.6.32.2内核在mini2440上的移植(八)---添加ADC驱动
- fl2440内核linux 3.0移植-----UDA1341音频驱动和mp3播放
- 【引用】Linux-2.6.32.2内核在mini2440上的移植(八)---添加ADC驱动
- Linux-2.6.32.2内核在mini2440上的移植(八)---添加ADC驱动
- ARM9开发板FL2440移植Linux-3.0内核————添加USB驱动
- S3c6410 linux内核移植(8)---添加adc驱动、电池电量检测之原理
- 内核linux-3.0移植到fl2440-----添加U盘,MMC和LCD驱动
- 基于fl2440内核linux-3.0移植----加载含参数模块示例
- 基于fl2440内核linux-3.0移植----触摸屏移植
- fl2440内核linux-3.0移植-----添加SD卡支持
- S3c6410 linux内核移植(8)---添加adc驱动、电池电量检测之原理
- S3c6410 linux内核移植(9)---添加adc驱动、电池电量检测之文件修改
- Linux-2.6.32.2内核在mini2440上的移植(七)---添加ADC驱动
- S3c6410 linux内核移植(8)---添加adc驱动、电池电量检测之原理
- 基于arm/Linux平台USB无线网卡的wifi驱动移植
- 基于arm/Linux平台USB无线网卡的wifi驱动移植
- 基于ARM的嵌入式Linux移植真实体验(4)――设备驱动
- 升级基于ATL3.0的项目到ATL7.0(VC6.0 to VS2008)[移植变更点]