具體ADC硬件知識(shí)及裸機(jī)驅(qū)動(dòng)請(qǐng)看: Exynos4412裸機(jī)開發(fā) —— A/D轉(zhuǎn)換器
1、原理圖如下:
2、相關(guān)寄存器信息
ADC_BASE 0x126C0000
ADCCON 0x0000 1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6
ADCDLY 0x0008
ADCDAT 0x000C &0XFFF
CLRINTADC 0x0018
ADCMUX 0x001C
3、大體驅(qū)動(dòng)編寫流程如下
read()
{
1、向adc設(shè)備發(fā)送要讀取的命令
ADCCON 1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6
2、讀取不到數(shù)據(jù)就休眠
wait_event_interruptible();
3、等待被喚醒讀數(shù)據(jù)
havedata = 0;
}
adc_handler()
{
1、清中斷 ADC使用中斷來通知轉(zhuǎn)換數(shù)據(jù)完畢的
2、狀態(tài)位置位;
havedata=1;
3、喚醒阻塞進(jìn)程
wake_up()
}
probe()
{
1、 讀取中斷號(hào),注冊(cè)中斷處理函數(shù)
2、讀取寄存器的地址,ioremap
3、字符設(shè)備的操作
}
|
4、設(shè)備樹中的節(jié)點(diǎn)編寫
- fs4412-adc{
- compatible = "fs4412,adc";
- reg = <0x126C0000 0x20>;
- interrupt-parent = <&combiner>;
- interrupts = <10 3>;
- };
5、驅(qū)動(dòng)編寫
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);
- }
|