Exynos4412 ADC 设备驱动开发

时间:2021-03-28 17:54:32

       具体ADC硬件知识及裸机驱动请看: Exynos4412裸机开发 —— A/D转换器

1、原理图如下:

Exynos4412 ADC 设备驱动开发

2、相关寄存器信息

ADC_BASE      0x126C0000 ADCCON        0x0000               1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6 ADCDLY          0x0008               
ADCDAT         0x000C              &0XFFF
CLRINTADC    0x0018
ADCMUX        0x001C

3、大体驱动编写流程如下

read(){       1、向adc设备发送要读取的命令          ADCCON    1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6

       2、读取不到数据就休眠            wait_event_interruptible();
       3、等待被唤醒读数据          havedata = 0;
}
adc_handler(){       1、清中断 ADC使用中断来通知转换数据完毕的             2、状态位置位;            havedata=1;
       3、唤醒阻塞进程            wake_up()}
probe(){      1、 读取中断号,注册中断处理函数
      2、读取寄存器的地址,ioremap
      3、字符设备的操作}

4、设备树中的节点编写

fs4412-adc{
compatible = "fs4412,adc";
reg = <0x126C0000 0x20>;
interrupt-parent = <&combiner>;
interrupts = <10 3>;
};

5、驱动编写

driver.c

#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/io.h>
static int major = 250;


static wait_queue_head_t wq;
static int have_data = 0;
static int adc;
static struct resource *res1;
static struct resource *res2;
static void *adc_base;

#define ADCCON 0x0000
#define ADCDLY 0x0008
#define ADCDAT 0x000C
#define CLRINTADC 0x0018
#define ADCMUX 0x001C


static irqreturn_t adc_handler(int irqno, void *dev)
{
have_data = 1;

printk("11111\n");
/*清中断*/
writel(0x12,adc_base + CLRINTADC);
wake_up_interruptible(&wq);
return IRQ_HANDLED;
}
static int adc_open (struct inode *inod, struct file *filep)
{

return 0;
}
static ssize_t adc_read(struct file *filep, char __user *buf, size_t len, loff_t *pos)
{
writel(0x3,adc_base + ADCMUX);
writel(1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6 ,adc_base +ADCCON );

wait_event_interruptible(wq, have_data==1);

/*read data*/
adc = readl(adc_base+ADCDAT)&0xfff;

if(copy_to_user(buf,&adc,sizeof(int)))
{
return -EFAULT;
}
have_data = 0;
return len;
}
static int adc_release(struct inode *inode, struct file *filep)
{
return 0;
}
static struct file_operations adc_ops =
{
.open = adc_open,
.release = adc_release,
.read = adc_read,
};


static int hello_probe(struct platform_device *pdev)
{
int ret;
printk("match 0k \n");

res1 = platform_get_resource(pdev,IORESOURCE_IRQ, 0);
res2 = platform_get_resource(pdev,IORESOURCE_MEM, 0);

ret = request_irq(res1->start,adc_handler,IRQF_DISABLED,"adc1",NULL);
adc_base = ioremap(res2->start,res2->end-res2->start);

register_chrdev( major, "adc", &adc_ops);
init_waitqueue_head(&wq);

return 0;
}
static int hello_remove(struct platform_device *pdev)
{
free_irq(res1->start,NULL);
free_irq(res2->start,NULL);
unregister_chrdev( major, "adc");
return 0;
}

static struct of_device_id adc_id[]=
{
{.compatible = "fs4412,adc" },
};

static struct platform_driver hello_driver=
{

.probe = hello_probe,
.remove = hello_remove,
.driver ={
.name = "bigbang",
.of_match_table = adc_id,
},
};

static int hello_init(void)
{
printk("hello_init");
return platform_driver_register(&hello_driver);
}
static void hello_exit(void)
{
platform_driver_unregister(&hello_driver);
printk("hello_exit \n");
return;
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);

test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>


main()
{
int fd,len;
int adc;
fd = open("/dev/hello",O_RDWR);
if(fd<0)
{
perror("open fail \n");
return ;
}

while(1)
{
read(fd,&adc,4);
printf("adc%0.2f V \n",(1.8*adc)/4096);
}

close(fd);
}