AD7705驱动代码 -- Linux SPI设备驱动

AD7705设备驱动代码,开发板:iTOP4412精英版,内核版本:Linux3.0.15,结果会比实际值偏移一位,正在查找原因,随时更新,欢迎讨论!

(1)在内核平台文件中spi2_board_info[]添加设备信息如下:

#ifdef CONFIG_AD7705_CTL    //direct use spi2, or use spi-gpio
         {                           
                 .modalias = "AD7705",
                 .platform_data = NULL,
                 .max_speed_hz = 1*1000*1000,
                 .bus_num = 2,                   //spi2总线
                 .chip_select =0,    
                 .mode = SPI_MODE_3,             //采用SPI mode3工作模式
                 .controller_data = &spi2_csi[0],
         },                          
#endif 

(2)在内核源码中drives/spi目录下配置Kconfig:

config AD7705_CTL          
    tristate "AD7705 Module driver support"
        depends on EXPERIMENTAL
        help               
          This supports AD7705 Module drivers.

(3)并在对应Makefile中添加编译选项:

obj-$(CONFIG_AD7705_CTL)    += ad7705.o

(4)驱动源码:

#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/init.h>  
#include <linux/platform_device.h>  
#include <linux/interrupt.h>  
#include <linux/err.h>  
#include <linux/miscdevice.h>  
#include <linux/gpio.h>  
#include <linux/delay.h>  
#include <linux/signal.h>  
#include <linux/sched.h>  
#include <linux/fs.h>  
#include <linux/time.h>  
#include <linux/errno.h>  
#include <linux/clk.h> 
#include <linux/compat.h>
#include <asm/uaccess.h>
#include <linux/mutex.h>  
#include <linux/kfifo.h>  
#include <linux/spi/spi.h> 
#include <linux/spi/spidev.h>
#include <linux/slab.h>  
#include <linux/device.h> 
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio-exynos4.h>
 
/*
*********************************************************************************************************
*	所有的寄存器(包括通信寄存器本身和输出数据寄存器)进行读操作之前,
*	必须先写通信寄存器,然后才能读选定的寄存器。 
*********************************************************************************************************
*/
enum   
{  
    AD7705_REG_COMM         = (0 << 4),  		//8bits
    AD7705_REG_SETUP        = (1 << 4),  		//8bits
    AD7705_REG_CLOCK        = (2 << 4), 		//8bits
    AD7705_REG_DATA         = (3 << 4), 		//16bits
    AD7705_REG_TEST         = (4 << 4), 		//8bits
    AD7705_REG_OFFSET       = (6 << 4),  		//24bits
    AD7705_REG_GAIN         = (7 << 4),  		//24bits
      
    AD7705_WRITE            = (0 << 3),
    AD7705_READ             = (1 << 3), 
  
    AD7705_CH_1             = 0,   		 		// AIN1+  AIN1-  
    AD7705_CH_2             = 1,    			// AIN2+  AIN2-  
    AD7705_CH_3             = 2,    			// AIN1-  AIN1-  
    AD7705_CH_4             = 3     			// AIN1-  AIN2-  
};  
  
enum  
{  
    AD7705_MD_NORMAL        = (0 << 6),   		//正常模式
    AD7705_MD_CAL_SELF      = (1 << 6),   		//自校准
    AD7705_MD_CAL_ZERO      = (2 << 6),   		//零标度系统校准
    AD7705_MD_CAL_FULL      = (3 << 6),   		//满标度系统校准
  
    AD7705_GAIN_1           = (0 << 3),  
    AD7705_GAIN_2           = (1 << 3),   
    AD7705_GAIN_4           = (2 << 3),   
    AD7705_GAIN_8           = (3 << 3),   
    AD7705_GAIN_16          = (4 << 3),     
    AD7705_GAIN_32          = (5 << 3),  
    AD7705_GAIN_64          = (6 << 3),    
    AD7705_GAIN_128         = (7 << 3),  
  
    AD7705_BIPOLAR          = (0 << 2),    		//双极性工作
    AD7705_UNIPOLAR         = (1 << 2),   		//单极性工作
  
    AD7705_BUF_NO           = (0 << 1),   		//缓冲器控制
    AD7705_BUF_EN           = (1 << 1),   
  
    AD7705_FSYNC_0          = 0,     			//滤波器同步控制
    AD7705_FSYNC_1          = 1    
};  
  
enum  
{  
    AD7705_CLKDIS_0         = (0 << 4),      	//主时钟禁止位
    AD7705_CLKDIS_1         = (1 << 4),      
  
    AD7705_CLKDIV_0         = (0 << 3),     	//2.4576MHz	(CLKDIV=0 )
    AD7705_CLKDIV_1         = (1 << 3),      	//4.9152MHz (CLKDIV=1 )
  
    AD7705_CLK_0            = (0 << 2),    		//时钟位,主时钟频率为2.4576MHz(CLKDIV=0)或为4.9152MHz(CLKDIV=1),CLK应置“0”,主时钟频率为1MHz(CLKDIV=0)或2MHz(CLKDIV=1),CLK应置“1”
    AD7705_CLK_1            = (1 << 2),    
  
    AD7705_UPDATE_20        = (0),  			//输出更新速度,不同于AD采样速率
    AD7705_UPDATE_25        = (1),  			
    AD7705_UPDATE_100       = (2),  
    AD7705_UPDATE_200       = (3),  
    
    AD7705_UPDATE_50        = (0),  
    AD7705_UPDATE_60        = (1),  
    AD7705_UPDATE_250       = (2),  
    AD7705_UPDATE_500       = (3)  
};  
   
#define SPIDEV_MAJOR			153						// 主设备号
#define N_SPI_MINORS			123						// 次设备号
  
#define AD7705_CHANNEL_NUM      (2)     

#define AD7705_DRDY_PIN         (EXYNOS4_GPA1(4))  	 //BUF_GPS_TXD AD7705的引脚DRDY   ,配置为输入引脚
#define AD7705_RESET_PIN        (EXYNOS4_GPA1(5))    //BUF_GPS_RXD AD7705的引脚RESET  ,配置为输出引脚
#define AD7705_MISO_PIN			(EXYNOS4_GPC1(3))	
#define AD7705_MOSI_PIN			(EXYNOS4_GPC1(4))
#define AD7705_SCLK_PIN			(EXYNOS4_GPC1(1)) 
#define AD7705_NSS_PIN			(EXYNOS4_GPC1(2)) 
	
#define AD7705_BUFFER 			2048    
   
static struct class *AD7705_class = NULL;  
  
struct AD7705_spidata { 
	struct spi_device *spi_dev;			
	dev_t major_num;		//主设备号
	dev_t minor_num;		//次设备号
	dev_t cdev_num;			//设备号
    u16 val; 				
	struct cdev *AD7705_cdev;	//字符设备
	unsigned char *buffer;
};   
  
static struct AD7705_spidata *AD7705 = NULL;		//私有数据

/*
*********************************************************************************************************
*	函 数 名: AD7705_request_gpio
*	功能说明: 申请GPIO引脚,并配置引脚功能
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/ 
static void AD7705_request_gpio(void)
{ 
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	  
	if (gpio_request(AD7705_MISO_PIN, "MISO"))  
    {  
        printk(KERN_EMERG"[%s][%d]: gpio_request(AD7705_MISO_PIN) fail.\n", __FUNCTION__, __LINE__);   
    }  
	if (gpio_request(AD7705_MOSI_PIN, "MOSI"))  
    {  
        printk(KERN_EMERG"[%s][%d]: gpio_request(AD7705_MOSI_PIN) fail.\n", __FUNCTION__, __LINE__);   
    }  
	if (gpio_request(AD7705_SCLK_PIN, "SCLK"))  
    {  
        printk(KERN_EMERG"[%s][%d]: gpio_request(AD7705_SCLK_PIN) fail.\n", __FUNCTION__, __LINE__);   
    } 
	
	if((s3c_gpio_cfgpin(AD7705_MISO_PIN, S3C_GPIO_SFN(0x5))) < 0  
		|| (s3c_gpio_cfgpin(AD7705_MOSI_PIN, S3C_GPIO_SFN(0x5))) < 0 
		|| (s3c_gpio_cfgpin(AD7705_SCLK_PIN, S3C_GPIO_SFN(0x5))) < 0
		|| (s3c_gpio_cfgpin(AD7705_NSS_PIN, S3C_GPIO_SFN(0x5))) < 0)
	{
		printk(KERN_DEBUG"[%s][%d]: s3c_gpio_cfgpin faild", __FUNCTION__, __LINE__); 
	}
	
	if(gpio_request(AD7705_DRDY_PIN, "AD7705 DRDY"))
    {
        gpio_free(AD7705_DRDY_PIN);
        printk(KERN_EMERG"gpio request drdy pin faild!\n");
    }
    if(s3c_gpio_cfgpin(AD7705_DRDY_PIN, S3C_GPIO_INPUT) < 0)
    {
        printk(KERN_EMERG"AD7705_DRDY_PIN error!\n");
    }  
 
    if(gpio_request(AD7705_RESET_PIN, "AD7705 RESET"))
    {
        gpio_free(AD7705_RESET_PIN);
        printk(KERN_EMERG"gpio request reset pin faild!\n");
    }
    if(s3c_gpio_cfgpin(AD7705_RESET_PIN, S3C_GPIO_OUTPUT) < 0)
    {
        printk(KERN_EMERG"AD7705_RESET_PIN error!\n");
    } 
	s3c_gpio_setpull(AD7705_RESET_PIN, S3C_GPIO_PULL_UP);
    gpio_set_value(AD7705_RESET_PIN, 1);
	 
	return ;
}

/*
*********************************************************************************************************
*	函 数 名: AD7705_free_gpio
*	功能说明: 释放申请的GPIO
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/ 
static void AD7705_free_gpio(void)
{ 
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
	gpio_free(AD7705_MISO_PIN);
	gpio_free(AD7705_MOSI_PIN);
	gpio_free(AD7705_SCLK_PIN);
	gpio_free(AD7705_NSS_PIN);
	gpio_free(AD7705_RESET_PIN);
	gpio_free(AD7705_DRDY_PIN); 
	
	return ;
} 

/*
*********************************************************************************************************
*	函 数 名: AD7705_reset
*	功能说明: 复位 AD7705芯片
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/ 
static void AD7705_reset(void)  
{  
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
    gpio_set_value(AD7705_RESET_PIN, 1);
    msleep(1);  
    gpio_set_value(AD7705_RESET_PIN, 0);
    msleep(5);  
    gpio_set_value(AD7705_RESET_PIN, 1);
    msleep(1);  
  
    return ;  
}  

/*
*********************************************************************************************************
*	函 数 名: AD7705_sync_spi
*	功能说明: 同步AD7705芯片SPI接口时序
*	形    参: 
*	返 回 值: 无
*********************************************************************************************************
*/
static void AD7705_sync_spi(struct spi_device *spi_dev)  
{  
    u8 tx_buf[4] = {0xFF,0xFF,0xFF,0xFF};  
    
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
	// 至少32个串行时钟内向AD7705的DIN线写入逻辑"1" 
    spi_write(spi_dev, tx_buf, sizeof(tx_buf));  
}  
  
/*
*********************************************************************************************************
*	函 数 名: AD7705_wait_DRDY
*	功能说明: 等待内部操作完成。 自校准时间较长,需要等待。
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/   
static int AD7705_wait_DRDY(void)  
{  
    int i = 0;  
    uint32_t time_cnt = 500;  		//超时1s	
  
	// printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
    for (i=0; i<time_cnt; i++)  
    {  
        if (0 == gpio_get_value(AD7705_DRDY_PIN))  
        {  
            break;  
        }  
        msleep(1);  
    }  
  
    if (i >= time_cnt)  		
    {  
		printk(KERN_EMERG"[%s][%d]: AD7705_wait_DRDY Time Out ...\r\n", __FUNCTION__, __LINE__);
        return -1;  
    }  
  
    return 0;  
}  

/*
*********************************************************************************************************
*	函 数 名: AD7705_calibZero_self
*	功能说明: 启动自校准. 内部自动短接AIN+ AIN-校准0位,内部短接到Vref 校准满位。此函数执行过程较长 
*			  实测约 180ms
*	形    参:  channel : ADC通道,1或2
*	返 回 值: 无
*********************************************************************************************************
*/
static void AD7705_systemcalib_self(struct spi_device *spi_dev, u8 channel)  
{   
    u8 tx_buf[2] = {0};   
    u8 rx_buf[1] = {0};
  
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
    tx_buf[0] = AD7705_REG_SETUP | AD7705_WRITE | channel;  	// 写设置寄存器 
    tx_buf[1] = AD7705_MD_CAL_SELF | AD7705_GAIN_1 | AD7705_UNIPOLAR | AD7705_BUF_EN | AD7705_FSYNC_0;  
	//配置通道channel(0x46):激活自校准,增益为1,单极性工作,允许输入缓冲,滤波器同步设置为0
	printk(KERN_EMERG"[%s][%d]: Write SETUP Register: 0x%x\r\n", __FUNCTION__, __LINE__, tx_buf[1]); 
    spi_write(spi_dev, tx_buf, sizeof(tx_buf));   
	
    msleep(250); 		/* 等待内部操作完成 --- 时间较长,约180ms*/  
	 
/**********************************读寄存器写入的数据,用作调试****************************************/
	AD7705_wait_DRDY(); 
	memset(rx_buf, 0, sizeof(rx_buf));
    tx_buf[0] = AD7705_REG_SETUP | AD7705_READ | channel;  	//(0x46) 读设置寄存器 , 用作调试  
	rx_buf[0] = spi_w8r8(spi_dev, tx_buf[0]); 
	if(rx_buf[0] < 0)
	{
		printk(KERN_EMERG"[%s][%d]: Read SETUP Register faild.\r\n", __FUNCTION__, __LINE__);
	}else{
		printk(KERN_EMERG"[%s][%d]: Read SETUP Register: 0x%x\r\n", __FUNCTION__, __LINE__, rx_buf[0]); 
	}  
	
	AD7705_wait_DRDY();	 
	memset(rx_buf, 0, sizeof(rx_buf));
    tx_buf[0] = AD7705_REG_CLOCK | AD7705_READ | channel;  	//(0x8) 读时钟寄存器 , 用作调试  
	rx_buf[0] = spi_w8r8(spi_dev, tx_buf[0]); 
	if(rx_buf[0] < 0)
	{
		printk(KERN_EMERG"[%s][%d]: Read CLOCK Register faild.\r\n", __FUNCTION__, __LINE__);
	}else{
		printk(KERN_EMERG"[%s][%d]: Read CLOCK Register: 0x%x\r\n", __FUNCTION__, __LINE__, rx_buf[0]); 
	}	 
	
/***********************************************************************************************************/	 
    return ;  
}  

/*
*********************************************************************************************************
*	函 数 名: AD7705_calibZero_self
*	功能说明: 启动系统校准零位. 请将AIN+ AIN-短接后,执行该函数。校准应该由主程序控制并保存校准参数。
*			 执行完毕后。可以通过 AD7705_ReadReg(REG_ZERO_CH1) 和  AD7705_ReadReg(REG_ZERO_CH2) 读取校准参数。
*	形    参: channel : ADC通道,1或2
*	返 回 值: 无
*********************************************************************************************************
*/
static void AD7705_calibZero_self(struct spi_device *spi_dev, u8 channel) 
{
    u8 tx_buf[2] = {0};  
  
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
    tx_buf[0] = AD7705_REG_SETUP | AD7705_WRITE | channel;  	// 写设置寄存器 
    tx_buf[1] = AD7705_MD_CAL_ZERO | AD7705_GAIN_1 | AD7705_UNIPOLAR | AD7705_BUF_EN | AD7705_FSYNC_0;  	//配置通道channel:激活零标度系统校准,增益为1,单极性工作,允许输入缓冲,滤波器同步设置为0
    spi_write(spi_dev, tx_buf, sizeof(tx_buf));  
  
    msleep(200);   
      
    return ;  
}

/*
*********************************************************************************************************
*	函 数 名: AD7705_calibFull_self
*	功能说明: 启动系统校准满位. 请将AIN+ AIN-接最大输入电压源,执行该函数。校准应该由主程序控制并保存校准参数。
*			 执行完毕后。可以通过 AD7705_ReadReg(REG_FULL_CH1) 和  AD7705_ReadReg(REG_FULL_CH2) 读取校准参数。
*	形    参:  channel : ADC通道,1或2
*	返 回 值: 无
*********************************************************************************************************
*/
static void AD7705_calibFull_self(struct spi_device *spi_dev, u8 channel)  
{  
    u8 tx_buf[2] = {0};  
  
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
    tx_buf[0] = AD7705_REG_SETUP | AD7705_WRITE | channel;  	// 写设置寄存器 
    tx_buf[1] = AD7705_MD_CAL_FULL | AD7705_GAIN_1 | AD7705_UNIPOLAR  | AD7705_BUF_EN | AD7705_FSYNC_0;  //配置通道channel(0x46):激活满标度系统校准,增益为1,单极性工作,允许输入缓冲,滤波器同步设置为0
    spi_write(spi_dev, tx_buf, sizeof(tx_buf));  
   
    msleep(200);  
      
    return ;  
} 
 
/*
*********************************************************************************************************
*	函 数 名: AD7705_config_channel
*	功能说明: 配置AD7705的指定通道  
*	形    参: channel : ADC通道,1或2
*	返 回 值: 无
*********************************************************************************************************
*/  
static void AD7705_config_channel(struct spi_device *spi_dev, u8 channel)  
{  
    u8 tx_buf[2] = {0}; 
  
	// printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
    tx_buf[0] = AD7705_REG_CLOCK | AD7705_WRITE | channel;  	// 写时钟寄存器 
    tx_buf[1] = AD7705_CLKDIS_0 | AD7705_CLKDIV_1 | AD7705_CLK_0 | AD7705_UPDATE_50;  	 
	//配置通道channel(0x8):允许主时钟输出,时钟分频,CLK为4.9152MHz,输出更新速率为50Hz 
	printk(KERN_EMERG"[%s][%d]: Write CLOCK Register: 0x%x\r\n", __FUNCTION__, __LINE__, tx_buf[1]); 
    spi_write(spi_dev, tx_buf, sizeof(tx_buf));  
  
    AD7705_systemcalib_self(spi_dev, channel);  		//内部自校准通道channel
  
    return ;  
}  
 
/*
*********************************************************************************************************
*	函 数 名: AD7705_config_channel
*	功能说明: 初始化AD7705, 复位AD7705并重新配置  
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/  
static void AD7705_reset_and_reconfig(struct spi_device *spi_dev)  
{  
	// printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
    AD7705_reset();  		//复位AD7705 
    msleep(1);   
    AD7705_sync_spi(spi_dev);  	//同步SPI接口时序, AD7705串行接口失步后将其复位。复位后要延时500us再访问 
    msleep(1);   
    AD7705_config_channel(spi_dev, AD7705_CH_1);   
    
    return ;  
}  

/*
*********************************************************************************************************
*	函 数 名: AD7705_read_channel
*	功能说明: 读AD7705  
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/  
static int AD7705_read_channel(struct spi_device *spi_dev, u8 channel, u16 *ad)  
{    
    int ret = -1;   
    u16 value = 0xffff;  
    u8 tx_buf[1] = {0};   
    u8 rx_buf[2] = {0};  
   
	// printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__); 
    AD7705_wait_DRDY();  									// 等待转换完成  
	 
    tx_buf[0] = AD7705_REG_DATA | AD7705_READ | channel;  	//(0x38)下一步对数据寄存器进行读操作 
    ret = spi_write_then_read(spi_dev, tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf));  		//每次读的都是上一次转换结果
    value = (rx_buf[0]<<8) | rx_buf[1];  
	//value = value << 1;    								//读出数据会比真实数据向右偏移一位,比如实际数据0xc,可能读出0x8006,且最高位总为1,正在查找原因 !!!!!!!!!!!!!!!
    if (ret < 0)    
    {  
        printk(KERN_EMERG "[%s][%d]: AD7705_read_byte() faild. ret=%d \n", __FUNCTION__, __LINE__, ret);  
        goto fail;  
    }  
	 
	if (0xffff == value)  									//接口迷失, // AD7705上电一段时间后,可能会出现读到的值一直是0xfff的情况  
	{      
        printk(KERN_EMERG "Error: [%s][%d]: value = 0xffff \n", __FUNCTION__, __LINE__);  
		ret = -1; 
		goto fail;
	} 
       
    *ad = value;   
  
fail:   
    return ret;  
}  
 
/*
*********************************************************************************************************
*	函 数 名: AD7705_get_value
*	功能说明: 获取AD7705的读数值 
*	形    参: channel : ADC通道,1或2;  val: AD7705转换结果,传入参数地址
*	返 回 值: 无
*********************************************************************************************************
*/ 
static ssize_t AD7705_get_value(struct spi_device *spi_dev, u8 channel, u16 *val)  
{    
    int ret = 0;   
	int i=0;
	// printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
 /* 
 * 为了避免通道切换造成读数失效,读2次 
 * 实际上每次读到的是上一次采集的结果(可以两个通道交替采集就能看到效果) 
 */ 
	for(i=0; i<2; i++)
	{
		ret = AD7705_read_channel(spi_dev, channel, val);  
		if (ret < 0)  
		{  
			/*失败,重启AD7705并重新配置*/
			AD7705_reset_and_reconfig(spi_dev);   
			printk(KERN_EMERG "Error: [%s][%d]: AD7705_reset_and_reconfig...\n", __FUNCTION__, __LINE__);  
			return ret;  
		}  
		msleep(5);	//防止读数频率过快 
	}		
	
    return ret;  
} 
 
	
static ssize_t AD7705_read(struct file *filp, char __user *buf, size_t len, loff_t *lft)
{   
	struct AD7705_spidata *adc; 
    unsigned long missing;   
	unsigned char *tmp = NULL; 	//分配4个字节缓冲区
	
	// printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
	if((!(tmp = kmalloc(4, GFP_KERNEL))) || (!(adc = kmalloc(sizeof(struct AD7705_spidata), GFP_KERNEL))))
    {
        printk(KERN_EMERG"[%s][%d]: kmalloc error, Kernel read faild!\n", __FUNCTION__, __LINE__); 
		return -1;
    }
    memset(adc, 0, sizeof(struct AD7705_spidata));
	
	adc = (struct AD7705_spidata *) filp->private_data; 
	adc -> val = 0x0;
	
    AD7705_get_value(adc->spi_dev, AD7705_CH_1, &adc->val);
	printk(KERN_EMERG"[%s][%d]: AD7705 value = 0x%x\r\n", __FUNCTION__, __LINE__, adc->val);
	
	sprintf(tmp, " %u" , adc->val);   					// 将ad值传递给用户程序 
    missing = copy_to_user(buf, tmp, strlen(tmp));

    if(missing)
    {
		printk(KERN_EMERG"missing data %ld Bytes.\n", missing);
    }  

	kfree(tmp);
	
    return 0; 
}

static int AD7705_open(struct inode *node, struct file *filp)
{ 
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
	if(!(AD7705 -> buffer = (unsigned char *) kmalloc(AD7705_BUFFER, GFP_KERNEL)))
	{
		printk(KERN_EMERG"AD7705 -> buffer error!\n");
	}
	
	filp -> private_data = AD7705;								//获得私有数据结构 

    return 0;
}

static int AD7705_close(struct inode *inode, struct file *filp)
{
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	  
    return 0;
}


static ssize_t AD7705_write(struct file *filp, const char __user *buf, size_t len, loff_t *lft)
{
	// printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	  
    return 0;
}

static long AD7705_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	// printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
    return 0;
}

static struct file_operations AD7705_fops = {
    .owner = THIS_MODULE,
    .open = AD7705_open,
    .release = AD7705_close,
    .read = AD7705_read,
    .write = AD7705_write,
    .unlocked_ioctl = AD7705_ioctl,
}; 

static int __devinit AD7705_probe(struct spi_device *spi_dev)
{     
	int status = -1;
	
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	  
	if(!(AD7705 = kmalloc(sizeof(struct AD7705_spidata), GFP_KERNEL)))
    {
        printk(KERN_EMERG"kmalloc faild!\n"); 
    }
    memset(AD7705, 0, sizeof(struct AD7705_spidata)); 
	
	BUILD_BUG_ON(N_SPI_MINORS > 256); 
	AD7705 -> spi_dev = spi_dev; 
	AD7705 -> major_num = SPIDEV_MAJOR;			//申请设备号,SPI设备固定主设备号为153
	AD7705 -> minor_num = N_SPI_MINORS; 
	
    if(AD7705 -> major_num || AD7705 -> minor_num)
    {
        AD7705 -> cdev_num = MKDEV(AD7705 -> major_num, AD7705 -> minor_num);
        status = register_chrdev_region(AD7705 -> cdev_num, 1, "AD7705"); 					//申请设备号
		if(status < 0)
		{ 
			printk(KERN_EMERG"[%s][%d]: register_chrdev_region faild ! Now alloc_chrdev_region\r\n", __FUNCTION__, __LINE__);
			alloc_chrdev_region(&AD7705 -> cdev_num, AD7705 -> minor_num, 1, "AD7705"); 
		}
    }else{
        alloc_chrdev_region(&AD7705 -> cdev_num, AD7705 -> minor_num, 1, "AD7705"); 
	}

    AD7705 -> major_num = MAJOR(AD7705 -> cdev_num);
    AD7705 -> minor_num = MINOR(AD7705 -> cdev_num);
    printk(KERN_EMERG"[%s][%d]: major_num is %d, minor_num is %d\n", __FUNCTION__, __LINE__, AD7705 -> major_num, AD7705 -> minor_num);

    if(!(AD7705 -> AD7705_cdev = kmalloc(sizeof(struct cdev), GFP_KERNEL)))
    {
        printk(KERN_EMERG"kmalloc faild!\n");
        goto faild;
    }
    memset(AD7705->AD7705_cdev, 0, sizeof(struct cdev));

    AD7705->AD7705_cdev -> owner = THIS_MODULE;
    AD7705->AD7705_cdev -> ops = &AD7705_fops;
    cdev_init(AD7705->AD7705_cdev, &AD7705_fops);

    if(cdev_add(AD7705 -> AD7705_cdev, AD7705 -> cdev_num, 1) < 0)
    {
        printk(KERN_EMERG"[%s][%d]: cdev_add faild!\n", __FUNCTION__, __LINE__);
        goto faild;
    }

    if(!(AD7705_class = class_create(THIS_MODULE, "AD7705_Class")))
    {
        printk(KERN_EMERG"[%s][%d]: class_create faild!\n", __FUNCTION__, __LINE__);
        goto faild;
    } 
	
	device_create(AD7705_class, NULL, AD7705 -> cdev_num, NULL, "AD7705"); 		//创建设备节点
	
	AD7705_request_gpio();
	 
    AD7705_reset_and_reconfig(AD7705 -> spi_dev);									//初始化AD7705
  
    return 0; 
	 
faild:
    printk(KERN_EMERG"AD7705 module init faild!\n");
    unregister_chrdev_region(AD7705 -> cdev_num, 1);
    kfree(AD7705 -> AD7705_cdev);
	
    return -1; 
}

static int __devexit AD7705_remove(struct spi_device *spi_dev)
{
	printk(KERN_EMERG"[%s][%d]\r\n", __FUNCTION__, __LINE__);
	 
    AD7705_free_gpio();

    device_destroy(AD7705_class, AD7705 -> cdev_num);
    class_destroy(AD7705_class);
    cdev_del(AD7705 -> AD7705_cdev);
	
	kfree(AD7705);
	
    unregister_chrdev_region(AD7705 -> cdev_num, 1);
	
    return 0;
}

static struct spi_driver AD7705_driver = {
    .driver = {
        .name 	= "AD7705",   			//驱动名称,需要与设备名称匹配 
        .owner 	= THIS_MODULE,
    },
    .probe = AD7705_probe,
    .remove = __devexit_p(AD7705_remove),
};

static int __init init_AD7705(void)  
{ 
    if(spi_register_driver(&AD7705_driver) < 0)
    {
        printk(KERN_EMERG"[%s][%d]: spi_register_driver faild!\n", __FUNCTION__, __LINE__);
        spi_unregister_driver(&AD7705_driver); 
		return -1;
    }
    
    printk(KERN_EMERG"[%s][%d]: AD7705 module init success!\n", __FUNCTION__, __LINE__);
	
    return 0;
}  
  
  
static void __exit exit_AD7705(void)  
{ 
    spi_unregister_driver(&AD7705_driver);  

    printk(KERN_EMERG"[%s][%d]: AD7705 module exit success!\n", __FUNCTION__, __LINE__);
}  
   
module_init(init_AD7705);  
module_exit(exit_AD7705);  
    
MODULE_LICENSE("Dual BSD/GPL");  
MODULE_AUTHOR("YANG");  
MODULE_DESCRIPTION("AD7705 Linux driver");    


(5)应用测试源码

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
  
  
void read_channel(char *dev_file_path)  
{  
	int fd = 0;  
	int ret = 0;  
	unsigned int buff[128] = {0};  
	  
	fd = open(dev_file_path, O_RDONLY);  
	if (-1 == fd)  
	{  
		printf("[%s] open device file fail.\n", __FUNCTION__);  
		return ;  
	}  
	  
	memset(buff, 0, 128);  
	ret = read(fd, buff, 128);  
	if (0 > ret)  
	{  
		printf("[%s] not read data. ret=%d\n", __FUNCTION__, ret);  
	}  
	printf("[%s] buff=%s\n\n", __FUNCTION__, buff);  
  
	close(fd);  
  
	return ;  
}  
  
  
int main(void)  
{  
	char dev_path[] = {"/dev/AD7705"};   
  
	while(1)  
	{  
		read_channel(dev_path);  
		sleep(1);   
	}  
} 



参考博客:https://blog.csdn.net/caogos/article/details/53034196




评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值