⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ad_driver.c

📁 这是pxa270的ADC驱动程序
💻 C
字号:
/*** Note:*    race condition wasn't dealed, if two processes open ad/1 and ad/0, there * will be a race condition, we can solve it by add a mutex in struct MagicARM270_AD down the mutex, and then go read**/#include <asm/io.h>#include <asm/uaccess.h>#include <linux/delay.h>#include <linux/errno.h>	/* error codes */#include <linux/fs.h>		/* everything... */#include <linux/kernel.h>	/* printk() */#include <linux/module.h>#include <linux/slab.h>		/* kmalloc() */#include <linux/types.h>	/* size_t */#include <linux/cdev.h>#include <asm/arch/hardware.h>#include <asm/arch/pxa-regs.h>#include <asm/arch/pxa2xx_spi.h>#include "ad.h"static int ad_major = 0;static int ad_minor = 0;static struct cdev ad_cdev[1];static unsigned short result;static int n_port_no = -1;/* Mutual exclusion */struct semaphore sem;// #############################################################################// from huang's code for adsunsigned short  u16_adc_value;#define  LED_RUN     (1<<10)// TLC1543控制引脚宏定义。可根据实际硬件修改 #define   SCLK          (1<<22)#define   DATI          (1<<19)#define   DATO          (1<<14)#define   CS_ADC        (1<<13)// spi operations #define  SSCLK()		GPSR0 = SCLK#define  CSCLK()		GPCR0 = SCLK#define  SDATI()		GPSR0 = DATI#define  CDATI()		GPCR0 = DATI#define  SCS_ADC()		GPSR0 = CS_ADC#define  CCS_ADC()		GPCR0 = CS_ADC/** * change port no to adc address rules like: * 0x01 --> 0x10  * 0x02 --> 0x20 */#define to_adc_port(port_no) (port_no<<4)/** * get  bit returned by ADC *  * @return  */unsigned char  get_ad_ret_bit(void){	if ((GPLR0&DATO) != 0) return(1);	else return(0);}/** * Process read operation * read a ten bit ad value form tlc1543, and return its value in * a short int(16 bit) *  * no changes but defined a mocro _NOP() for delay 1 us *  * @param port   AIN0 - AIN10 *  * @return value of AIN_x, 10 bit ad value */unsigned short  read_last_val_set_new_addr(unsigned char port){  	unsigned short  adc_ret = 0;	unsigned char   i;	for (i=0; i<10; i++) udelay(1);	 // 10uS转换时间	CSCLK();		 // SCLK = 0	udelay(1);	CCS_ADC();		 // CS_ADC = 0	udelay(1);	for (i=0; i<10; i++) {		adc_ret <<= 1;		if ((port&0x80) != 0) SDATI();		else  CDATI();                		SSCLK();					  // SCLK = 1, 产生时钟脉冲		udelay(1);      		if (get_ad_ret_bit() != 0) adc_ret |= 0x01;		CSCLK();					  // SCLK = 0		udelay(1);		port <<= 1;     	}	SCS_ADC();      	udelay(10);	// after ad convertion start, we should wait at least 5us to let ad stable	// though 240 ns will be ok according to tlv1543's datasheet, 5 us is minimal by experiment	// 10 us will be safe	return(adc_ret);}/** * read a ten bit ad value form tlc1543, and return its value in a short int(16 bit) * no changes but defined a mocro _NOP() for delay 1 us *  * Note: *    we read 16 times and make an average of the value *  * @param port   AIN0 - AIN10 *  * @return value of AIN_x, 10 bit ad value */unsigned short  get_adc_val(unsigned char port){   	unsigned char i;	unsigned short ret_dat = 0;	read_last_val_set_new_addr(port);					// First set address, data received this time has no meaning	for (i=0; i<16; i++) {					// read convertion for 16 times, and then make an everage		ret_dat += read_last_val_set_new_addr(port);    	}	ret_dat >>= 4;     	return(ret_dat);}ssize_t ad_read (struct file *filp, char __user *buf, size_t count,				 loff_t *f_pos){	if (down_interruptible (&sem))		return -ERESTARTSYS;	u16_adc_value =  get_adc_val(to_adc_port(n_port_no));	result  = (u16_adc_value*3300) / 1024;	if (copy_to_user (buf, (char *)&result, sizeof(result))) {		return -EFAULT;	}	up (&sem);	return count;}int ad_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){	/* don't even decode wrong cmds: better returning  ENOTTY than EFAULT */	if (_IOC_TYPE(cmd) != AD_MAGIC)	return -ENOTTY;	if (_IOC_NR(cmd) > AD_MAXNR) return -ENOTTY;	if (arg > AD_MAX_CHANNELS) return -ENOTTY;	n_port_no = arg;	return 0;}struct file_operations fops_ad ={	.read = ad_read,	.ioctl = ad_ioctl,};static int __init ad_init(void){	int ret_alloc_dev = -1; 	dev_t dev = MKDEV(ad_major, 0);	// ######### Hardware Init GP22 GP19 GP14 GP13 #######################3	GAFR0_L = GAFR0_L & 0xC3FFFFFF;	//set gpio<14> gpio<13> to GPIO mode	GAFR0_U = GAFR0_U & 0xFFFFCF3F;	//set gpio<22> gpio<19> to  GPIO mode	GPDR0 = GPDR0 | LED_RUN | SCLK | DATI | CS_ADC; 	GPSR0 = LED_RUN | CS_ADC;   	GPDR1 = 1 << (43-32);                   	GAFR1_L = (01 << ((42-32) *2)) | (02 << ((43-32) *2)) ;	PSSR = PSSR | 0x10; 	// get dev major and minor	ret_alloc_dev = alloc_chrdev_region(&dev, 0, 1, "MagicARM270_AD");	ad_major = MAJOR(dev);	ad_minor = MINOR(dev);	printk(KERN_ALERT"MagicARM270 AD Driver Registerd: major=%d, minor=%d\n", ad_major, ad_minor);	printk(KERN_ALERT"use \"mkdir -p /dev/ad/&& rm -f /dev/ad/0 && mknod /dev/ad/0 c %d %d \" to make device node\n", ad_major, ad_minor);	// Register Ad dev 0	{   int err, devno = MKDEV(ad_major, ad_minor);		// make a char dev		cdev_init(&ad_cdev[0], &fops_ad);		ad_cdev[0].owner = THIS_MODULE;		ad_cdev[0].ops = &fops_ad;		err = cdev_add (&ad_cdev[0], devno, 1);		/* Fail gracefully if need be */		if (err)			printk(KERN_ERR "Error Creating char dev");	}	n_port_no = 0;	sema_init(&sem, 1);	return 0;}static void __exit ad_exit(void){	cdev_del(&ad_cdev[0]);	unregister_chrdev_region(MKDEV (ad_major, 0), 1);}module_init(ad_init);module_exit(ad_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -