苦逼的我又要往坑里填土了
看了新唐97x提供的iio-adc驱动之后,赶脚太脑壳疼,就自个弄了个简单的驱动,能读数了,有点进步,在这里先记录一下,(小白菜声明,借鉴网络以及官方驱动自个胡搞得,如有冒犯,请告知我大哥——晕哥)
废话少说上代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
//#include <mach/platform.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h> //copy_from_user声明
#include <linux/device.h> //设备文件的自动创建
#include <linux/clk.h>
#include <linux/kernel.h>
//#include <asm/mach/map.h>
#include "../../../arch/arm/mach-nuc970/include/mach/map.h"
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <asm/uaccess.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/cdev.h>
//寄存器地址映射
//#define adcba ioremap(NUC970_PA_ADC,(NUC970_SZ_ADC - 1))
#define CTL 0x00
#define CONF 0x04
#define IER 0x08
#define ISR 0x0C
#define DATA 0x28
//#define ADCCONF (volatile unsigned long *)0xB800A004
static struct clk *adc_clk;//定义adc时钟结构
//static int Device_Open = 0;
static int adc_init(void);
void adc_cleanup(void);
int init_module(void);
void cleanup_module(void);
struct adc_data_misc{
unsigned int data0;
unsigned int data1;
unsigned int data3;
};
struct adc_data{
unsigned int data;
int val;
};
struct adc_pag{
unsigned int buf[127];
};
//static unsigned long *adcbase;
static void adc_read(struct adc_data *adcdata){
unsigned long *adcbase;
adcbase = ioremap(NUC970_PA_ADC,(NUC970_SZ_ADC - 1));
writel(0x3<<6, adcbase + 0x01); //select AGND33 vs AVDD33
writel(1, adcbase + 0x00); //enable AD_EN, disable bandgap
writel(1, adcbase + 0x02);
writel((readl(adcbase + 0x01) | 1<<2), adcbase + 0x01); //enable NACEN
// enable channel
writel((readl(adcbase + 0x01) & ~(0x7 << 3)) | (adcdata->val << 3), adcbase + 0x01);
writel(readl(adcbase + 0x00) | 0x100, adcbase + 0x00);
writel(readl(adcbase + 0x03) | 0x001,adcbase + 0x03);
*(adcbase + 0x03) = 0x401;
//printk("adcbase + 0x03value=%lx\n",*(adcbase + 0x03));
//if(readl(adcbase + 0x03)&0x400){
adcdata->data = readl(adcbase + 0x0A);
//}
//else{
//printk("read error\n");
//}
iounmap(adcbase);
}
#define ADC_CHANNEL0 0x100000
#define ADC_CHANNEL1 0x100001
#define ADC_CHANNEL2 0x100002
#define ADC_CHANNEL3 0x100003
#define ADC_CHANNEL4 0x100004
#define ADC_CHANNEL5 0x100005
#define ADC_CHANNEL6 0x100006
#define ADC_CHANNEL7 0x100007
static long adc_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg){
struct adc_data adcdata;
struct adc_pag adcpag;
struct adc_data_misc adcdatamisc;
switch(cmd){
case ADC_CHANNEL0:
adcdata.val = 0;
adc_read(&adcdata);
copy_to_user((struct adc_data *)arg, &adcdata, sizeof(adcdata));
break;
case ADC_CHANNEL1:
adcdata.val = 1;
adc_read(&adcdata);
copy_to_user((struct adc_data *)arg, &adcdata, sizeof(adcdata));
break;
case ADC_CHANNEL2:
adcdata.val = 2;
adc_read(&adcdata);
copy_to_user((struct adc_data *)arg, &adcdata, sizeof(adcdata));
break;
case ADC_CHANNEL3:
adcdata.val = 3;
adc_read(&adcdata);
copy_to_user((struct adc_data *)arg, &adcdata, sizeof(adcdata));
break;
case ADC_CHANNEL4:
adcdata.val = 4;
adc_read(&adcdata);
copy_to_user((struct adc_data *)arg, &adcdata, sizeof(adcdata));
break;
case ADC_CHANNEL5:
adcdata.val = 5;
adc_read(&adcdata);
copy_to_user((struct adc_data *)arg, &adcdata, sizeof(adcdata));
break;
case ADC_CHANNEL6:
adcdata.val = 6;
adc_read(&adcdata);
copy_to_user((struct adc_data *)arg, &adcdata, sizeof(adcdata));
break;
case ADC_CHANNEL7:
adcdata.val = 0;
adc_read(&adcdata);
copy_to_user((struct adc_data *)arg, &adcdata, sizeof(adcdata));
break;
default:
return -1;
}
//copy_from_user(&kindex,(int *)arg,sizeof(kindex));
return 0;
}
struct file_operations adc_ops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = adc_ioctl
};
static struct cdev adc_cdev;
struct class *cls;
static dev_t dev;
static int adc_init(void){
alloc_chrdev_region(&dev, 0, 1, "xzm");
cdev_init(&adc_cdev, &adc_ops);
cdev_add(&adc_cdev, dev, 1);
cls = class_create(THIS_MODULE, "qiuqiu");
device_create(cls, NULL, dev, NULL, "myadc");
adc_clk = clk_get(NULL,"adc");
if(!adc_clk){
printk("failed to get adc clocl source \n");
return -ENOENT;
}
clk_enable(adc_clk);
printk(" initialized\n");
return 0;
}
void adc_cleanup(void){
if(adc_clk){
clk_disable(adc_clk);
clk_put(adc_clk);
adc_clk = NULL;
}
unregister_chrdev_region(dev, 1);
cdev_del(&adc_cdev);
device_destroy(cls, dev);
class_destroy(cls);
}
module_init(adc_init);
module_exit(adc_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("you");
调试程序同样上代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#define ADC_FUYONG 0x10000
#define ADC_CHANNEL0 0x100000
#define ADC_CHANNEL1 0x100001
#define ADC_CHANNEL2 0x100002
#define ADC_CHANNEL3 0x100003
#define ADC_CHANNEL4 0x100004
#define ADC_CHANNEL5 0x100005
#define ADC_CHANNEL6 0x100006
#define ADC_CHANNEL7 0x100007
struct adc_data {
unsigned int x;
};
struct adc_data_misc{
unsigned int data0;
unsigned int data1;
unsigned int data3;
};
struct adc_pag{
int buf[127];
};
int main(void)
{
int fd,i,j,cmd;
int buf[127];
struct adc_data info; //分配用户缓冲区
struct adc_data_misc miscinfo;
struct adc_pag adcpag;
info.x=1;
i = 1;
fd = open("/dev/myadc", O_RDWR);
if (fd < 0){
printf("file error\n");
return -1;
}
printf("info.x=%d\n",info.x);
printf("please input channel:\n");
// scanf("%d",&cmd);
cmd = 0;
switch(cmd){
case 0:
printf("start write\n");
for(j = 0;j < 20;j++){
ioctl(fd,ADC_CHANNEL0, &info);
//buf{i++} = info.x;
buf{ i }= info.x;
i = i + 1;
printf("%d ", info.x);
ioctl(fd,ADC_CHANNEL1, &info);
//buf{i++} = info.x;
buf {i } = info.x;
i = i + 1;
printf("%d ", info.x);
ioctl(fd, ADC_CHANNEL2, &info);
//buf{i++} = info.x;
buf{ i } = info.x;
i = i + 1;
printf("%d ", info.x);
printf("\n");
//usleep(50000);
}
break;
case 1:
while(1){
ioctl(fd,ADC_CHANNEL1, &info);
printf("%d\n", info.x);
//usleep(50000);
}
break;
case 2:
while(1){
ioctl(fd, ADC_CHANNEL2, &info);
printf("%d\n", info.x);
//usleep(50000);
}
break;
case 3:
while(1){
ioctl(fd, ADC_CHANNEL3, &info);
printf("%d\n", info.x);
//usleep(50000);
}
break;
case 4:
while(1){
ioctl(fd, ADC_CHANNEL4, &info);
printf("%d\n", info.x);
//usleep(50000);
}
break;
case 5:
while(1){
ioctl(fd, ADC_CHANNEL5, &info);
printf("%d\n", info.x);
//usleep(50000);
}
break;
case 6:
while(1){
ioctl(fd, ADC_CHANNEL6, &info);
printf("%d\n", info.x);
//usleep(50000);
}
break;
case 7:
for(i = 0;i < 15;i++){
ioctl(fd, ADC_CHANNEL7, &info);
printf("%d\n", info.x);
//usleep(50000);
}
break;
case 8:
while(1){
ioctl(fd,ADC_FUYONG,&miscinfo);
printf("ADC0=%d\n",miscinfo.data0);
printf("ADC1=%d\n",miscinfo.data1);
printf("ADC3=%d\n",miscinfo.data3);
}
default:
return -1;
}
printf("start read\n");
for(i = 1;i<64;i++){
printf("%d ",buf{i});
}
printf("\n");
close(fd);
return 0;
}
驱动代码写的比较简单,这里之所以要恬不知耻的上传,主要还是给老板(晕哥)打工没办法,大佬们,觉得辣眼睛的话,自觉忽略
驱动是有些问题的,还待完善,大佬们给下建议,用示波器抓的图会让老板上传
离线
顶楼主,我还在坑里 没爬上来呢...
离线
感谢分享,正在找ADC相关的东西
离线
看不的确脑壳疼啊,不错,正需要这方面的资料,感谢
离线
How is the driver installed? Over insmod or modprobe?
离线
感谢分享,谢谢
离线