linux驱动程序开发-第八节:ADC设备驱动(模数转换)

S5P6818 ADC 的使用(三星芯片6818型号)

视频讲解及资料链接:链接:https://pan.baidu.com/s/1rPjq2goHFZf2ArBuo99Ehg      提取码:fdqk 
 


#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>

#include <linux/io.h>
#include <linux/gpio.h>
#include <cfg_type.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>

//------------------------------------------------
#define GEC6818_ADC_IN0		_IOR('A',  1, unsigned long)
#define GEC6818_ADC_IN1		_IOR('A',  2, unsigned long)

static void __iomem		*adc_base_va;		//adc的虚拟地址基址
static void __iomem		*adccon_va;		
static void __iomem		*adcdat_va;	
static void __iomem		*prescalercon_va;
//---------------------------------------------

static int  gec6818_adc_open (struct inode * inode, struct file *file)
{
	printk("gec6818_adc_open \n");
	
	return 0;
}

static int  gec6818_adc_release (struct inode * inode, struct file *file)
{
	printk("gec6818_adc_release \n");
	
	return 0;
}


static long gec6818_adc_ioctl (struct file *filp, unsigned int cmd, unsigned long args)
{
	unsigned long adc_val=0,adc_vol=0; 
	
	int rt=0;
	//adc通道选择
	switch(cmd)
	{
		case GEC6818_ADC_IN0:
				iowrite32(ioread32(adccon_va)&(~(7<<3)),adccon_va);
		break;
		
		
		case GEC6818_ADC_IN1:
		{
				iowrite32(ioread32(adccon_va)&(~(7<<3)),adccon_va);
				iowrite32(ioread32(adccon_va)|(1<<3),adccon_va);
		}break;		
		
		default:
			printk("IOCTLCMD failed\n");
			return -ENOIOCTLCMD;
	}
	
	//将电源开启
	iowrite32(ioread32(adccon_va)&(~(1<<2)),adccon_va);
	
	//预分频值=199+1,ADC的工作频率=200MHz/(199+1)=1MHz
	iowrite32(ioread32(prescalercon_va)&(~(0x3FF<<0)),prescalercon_va);
	iowrite32(ioread32(prescalercon_va)|(199<<0),prescalercon_va);
	
	//预分频值使能
	iowrite32(ioread32(prescalercon_va)|(1<<15),prescalercon_va);
	
	//ADC使能
	//iowrite32(ioread32(adccon_va)&(~(1<<0)),adccon_va);
	iowrite32(ioread32(adccon_va)|(1<<0),adccon_va);
	
	//等待AD转换结束
	while(ioread32(adccon_va)&(1<<0));
	
	//读取12bit数据
	adc_val = ioread32(adcdat_va)&0xFFF;
	
	//关闭CLKIN时钟输入
	iowrite32(ioread32(prescalercon_va)&(~(1<<15)),prescalercon_va);
	
	//关闭ADC电源
	iowrite32(ioread32(adccon_va)|(1<<2),adccon_va);
	
	//将AD转换的结果值 换算为 电压值
	adc_vol = adc_val*1800/4095;
	
	rt = copy_to_user((void *)args,&adc_vol,4);
	
	if(rt != 0)
		return -EFAULT;
	return 0;
}

static ssize_t gec6818_adc_read (struct file *file, char __user *buf, size_t len, loff_t * offs)
{
	return 0;
}

static const struct file_operations gec6818_adc_fops = {
 	.owner 			= THIS_MODULE,
	.unlocked_ioctl = gec6818_adc_ioctl,
	.open 			= gec6818_adc_open,
	.release 		= gec6818_adc_release,
	.read 			= gec6818_adc_read,
};


static struct miscdevice gec6818_adc_miscdev = {
	.minor		= MISC_DYNAMIC_MINOR,	//MISC_DYNAMIC_MINOR,动态分配次设备号
	.name		= "adc_drv",		//设备名称,/dev/adc_drv	
	.fops		= &gec6818_adc_fops,	//文件操作集
};

//入口函数
static int __init gec6818_adc_init(void)
{
	int rt=0;
	
	struct resource *adc_res=NULL;
	
	//混杂设备的注册
	rt = misc_register(&gec6818_adc_miscdev);
	
	if (rt) 
	{
		printk("misc_register fail\n");
		return rt;
	}
//-------------------------------------------------------------	
	//IO内存动态映射,得到物理地址相应的虚拟地址
	adc_base_va = ioremap(0xC0053000,0x14);
	
	if(adc_base_va == NULL)
	{
		
		printk("ioremap 0xC0053000,0x14 fail\n");
		
		goto fail_ioremap_adc;		
		
	}	
	
	//得到每个寄存器的虚拟地址
	adccon_va 		= adc_base_va+0x00;
	adcdat_va 		= adc_base_va+0x04;	
	
	prescalercon_va = adc_base_va+0x10;	
	
	printk("gec6818 adc init\n");
//------------------------------------------------------------	
	return 0;
	
fail_ioremap_adc:

	misc_deregister(&gec6818_adc_miscdev);
	
	return rt;
}


//出口函数
static void __exit gec6818_adc_exit(void)
{	
	iounmap(adc_base_va);

	
	misc_deregister(&gec6818_adc_miscdev);
	
	printk("gec6818 adc exit\n");
}

//驱动程序的入口:insmod led_drv.ko调用module_init,module_init又会去调用gec6818_adc_init。
module_init(gec6818_adc_init);

//驱动程序的出口:rmsmod led_drv调用module_exit,module_exit又会去调用gec6818_adc_exit。
module_exit(gec6818_adc_exit)


//模块描述
MODULE_AUTHOR("[email protected]");			//作者信息
MODULE_DESCRIPTION("gec6818 adc driver");		//模块功能说明
MODULE_LICENSE("GPL");							//许可证:驱动遵循GPL协议
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>

#define GEC6818_ADC_IN0		_IOR('A',  1, unsigned long)
#define GEC6818_ADC_IN1		_IOR('A',  2, unsigned long)

int main(int argc, char **argv)
{
	int fd=-1;

	int rt;

	int i=0;
	
	unsigned long adc_vol = 0;
	
	//打开adc设备
	fd = open("/dev/adc_drv",O_RDWR);
	
	if(fd < 0)
	{
		perror("open /dev/adc_drv:");
		
		return fd;
		
	}
	
	
	while(1)
	{
		//读取ADC通道0的电压值
		rt=ioctl(fd,GEC6818_ADC_IN0,&adc_vol);
		
		if(rt != 0)
		{
			printf("adc in0 read filed\r\n");
			
			usleep(50*1000);
			
			continue;
		}
		
		printf("adc in0 vol: %lu=mv\r\n",adc_vol);

		sleep(1);
	}
	
	close(fd);
	
	
	return 0;
}

程序文件结构
 

猜你喜欢

转载自blog.csdn.net/wghkemo123/article/details/86483717