📄 ad_driver.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 + -