linux adc驱动(基于三星通用adc api)

嵌入式技术

1333人已加入

描述

linux adc驱动(基于三星通用adc api)

硬件平台: 基于讯为开发板itop4412 scp 1G

驱动说明:

本驱动基于三星提供的通用api函数来实现的,具体adc寄存器操作有三星公司实 现,我们要做的是调用三星公司提供的api来实现我们自己的功能。下面对相关的结构体和api函数进行解析

[cpp] view plain copy

struct s3c_adc_client {  

struct platform_device  *pdev;  

struct list_head     pend;  

wait_queue_head_t   *wait;  

unsigned int         nr_samples;  

int          result;  

unsigned char        is_ts;  

unsigned char        channel;  

void    (*select_cb)(struct s3c_adc_client *c, unsigned selected);  

void    (*convert_cb)(struct s3c_adc_client *c,  

unsigned val1, unsigned val2,  

unsigned *samples_left);  

};  

一个具体s3c_adc_client结构体来描述一个具体的客户(一个具体的驱动)


2.我们需要在驱动中构建这个驱动,并且注册到linux的内核

[cpp] view plain copy

struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,  

void (*select)(struct s3c_adc_client *client,  

unsigned int selected),  

void (*conv)(struct s3c_adc_client *client,  

unsigned d0, unsigned d1,  

unsigned *samples_left),  

unsigned int is_ts)  


例子:

[cpp] view plain copy

adcdev.client = s3c_adc_register(dev, NULL, NULL, 0);  


3.adc开始和停止转换函数 

[cpp] view plain copy

int s3c_adc_start(struct s3c_adc_client *client,  

unsigned int channel, unsigned int nr_samples)  

[csharp] view plain copy

static void s3c_adc_stop(struct s3c_adc_client *client)  

4.读取adc转换数据

[cpp] view plain copy

int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch)  

5.adc配置相关的函数
   具体的讲解可以读取博客http://blog.csdn.net/liuhaoyutz/article/details/7461268

平台文件adc设备注册

方法一:在配置文件/home/topeet/Android4.0/iTop4412_Kernel_3.0/arch/arm/mach-exynos中的mach-iTop4412.添加

[html] view plain copy

struct platform_device s3c_device_adc_ctl = {  

.name                   = "adc_ll",  

.id                             = -1,  

};  

方法二:以模块的方式注册到内核

[cpp] view plain copy

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

static struct platform_device adc_dev = {  

.name         = "adc_ll",  

.id       = -1,  

};  

static int __init adc_dev_init(void)  

{  

platform_device_register(&adc_dev);  

return 0;  

}  

static void __exit adc_dev_exit(void)  

{  

platform_device_unregister(&adc_dev);  

}  

module_init(adc_dev_init);  

module_exit(adc_dev_exit);  

MODULE_LICENSE("GPL");  


第二部分:基于杂项设备方式的设备驱动

[cpp] view plain copy

/* 

* This program is free software; you can redistribute it and/or modify 

* it under the terms of the GNU General Public License version 2 as 

* published by the Free Software Foundation. 

*/  

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#define DEVICE_NAME     "adc"  

#define DRIVER_NAME     "adc_ll"  

typedef struct {  

struct mutex lock;  

struct s3c_adc_client *client;  

int channel;  

} ADC_DEV;  

static ADC_DEV adcdev;  

static inline int exynos_adc_read_ch(void) {  

int ret;  

ret = mutex_lock_interruptible(&adcdev.lock);  

if (ret < 0)  

return ret;  

ret = s3c_adc_read(adcdev.client, adcdev.channel);  

mutex_unlock(&adcdev.lock);  

return ret;  

}  

static inline void exynos_adc_set_channel(int channel) {  

if (channel < 0 || channel > 3)  

return;  

adcdev.channel = channel;  

}  

static ssize_t exynos_adc_read(struct file *filp, char *buffer,  

size_t count, loff_t *ppos)  

{  

char str[20];  

int value;  

size_t len;  

value = exynos_adc_read_ch();  

printk("value = 0x%x ", value);  

len = sprintf(str, "%d ", value);  

if (count >= len) {  

int r = copy_to_user(buffer, str, len);  

return r ? r : len;  

} else {  

return -EINVAL;  

}  

}  

static long exynos_adc_ioctl(struct file *file,  

unsigned int cmd, unsigned long arg)  

{  

#define ADC_SET_CHANNEL     0xc000fa01  

#define ADC_SET_ADCTSC      0xc000fa02  

switch (cmd) {  

case ADC_SET_CHANNEL:  

exynos_adc_set_channel(arg);  

break;  

case ADC_SET_ADCTSC:  

/* do nothing */  

break;  

default:  

return -EINVAL;  

}  

return 0;  

}  

static int exynos_adc_open(struct inode *inode, struct file *filp)  

{  

exynos_adc_set_channel(0);  

printk("adc opened ");  

return 0;  

}  

static int exynos_adc_release(struct inode *inode, struct file *filp)  

{  

printk("adc closed ");  

return 0;  

}  

static struct file_operations adc_dev_fops = {  

owner:  THIS_MODULE,  

open:   exynos_adc_open,  

read:   exynos_adc_read,      

unlocked_ioctl: exynos_adc_ioctl,  

release:    exynos_adc_release,  

};  

static struct miscdevice misc = {  

.minor  = MISC_DYNAMIC_MINOR,  

.name   = DEVICE_NAME,  

.fops   = &adc_dev_fops,  

};  

static int __devinit exynos_adc_probe(struct platform_device *dev)  

{  

int ret;  

mutex_init(&adcdev.lock);  

printk("%s, %d ", __FUNCTION__, __LINE__);  

/* Register with the core ADC driver. */  

#if 1  

adcdev.client = s3c_adc_register(dev, NULL, NULL, 0);  

if (IS_ERR(adcdev.client)) {  

printk("itop4412_adc: cannot register adc ");  

ret = PTR_ERR(adcdev.client);  

goto err_mem;  

}  

#endif  

printk("%s, %d ", __FUNCTION__, __LINE__);  

ret = misc_register(&misc);  

printk("%s, %d ", __FUNCTION__, __LINE__);  

printk(DEVICE_NAME" initialized ");  

err_mem:  

return ret;  

}  

static int __devexit exynos_adc_remove(struct platform_device *dev)  

{  

misc_deregister(&misc);  

s3c_adc_release(adcdev.client);  

return 0;  

}  

static int itop4412_adc_ctl_suspend (struct platform_device *pdev, pm_message_t state)  

{  

printk("itop4412_led_ctl suspend:power off! ");  

return 0;  

}  

static int itop4412_adc_ctl_resume (struct platform_device *pdev)  

{  

printk("itop4412_led_ctl resume:power on! ");  

return 0;  

}  

static struct platform_driver exynos_adc_driver = {  

.probe      = exynos_adc_probe,  

.remove     = exynos_adc_remove,  

.suspend = itop4412_adc_ctl_suspend,  

.resume = itop4412_adc_ctl_resume,  

.driver = {  

.name       = DRIVER_NAME,  

.owner      = THIS_MODULE,  

},  

};  

static int __init exynos_adc_init(void)  

{  

return platform_driver_register(&exynos_adc_driver);  

}  

static void __exit exynos_adc_exit(void)  

{  

platform_driver_unregister(&exynos_adc_driver);  

}  

module_init(exynos_adc_init);  

module_exit(exynos_adc_exit);  

MODULE_LICENSE("GPL");  

MODULE_AUTHOR("TOPEET Inc.");  


测试代码

[cpp] view plain copy

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

//#include   

//#include   

int main(void){  

int fd;  

char *adc = "/dev/adc";  

char buffer[512];  

int len=0, r=0;  

memset(buffer,0,sizeof(buffer));  

printf("adc ready! ");  

if((fd = open(adc, O_RDWR|O_NOCTTY|O_NDELAY))<0)  

printf("open adc err! ");  

else{  

printf("open adc success! ");  

len=read(fd,buffer,10);   

if(len == 0)  

printf("return null ");  

else{  

r = atoi(buffer);  

r = (int)(r*10000/4095);    //Datas  transition to Res  

printf("res value is %d ",r);  

}             

}  

}  




 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分