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 EXPERIMENTALhelp               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),       //8bitsAD7705_REG_SETUP        = (1 << 4),       //8bitsAD7705_REG_CLOCK        = (2 << 4),       //8bitsAD7705_REG_DATA         = (3 << 4),       //16bitsAD7705_REG_TEST         = (4 << 4),      //8bitsAD7705_REG_OFFSET       = (6 << 4),       //24bitsAD7705_REG_GAIN         = (7 << 4),          //24bitsAD7705_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,单极性工作,允许输入缓冲,滤波器同步设置为0printk(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,单极性工作,允许输入缓冲,滤波器同步设置为0spi_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,单极性工作,允许输入缓冲,滤波器同步设置为0spi_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);       //内部自校准通道channelreturn ;
}  /*
*********************************************************************************************************
*   函 数 名: 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设备固定主设备号为153AD7705 -> 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);                                  //初始化AD7705return 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

AD7705驱动代码 -- Linux SPI设备驱动相关推荐

  1. STM32MP157驱动开发——Linux块设备驱动

    STM32MP157驱动开发--Linux块设备驱动 一.简介 二.驱动开发 1.使用请求队列的方式 2.测试① 3.不使用请求队列的方式 4.测试② 参考文章:[正点原子]I.MX6U嵌入式Linu ...

  2. Linux SPI设备驱动

    实现了SPI OLED外设驱动,OLED型号为SH1106. 1.主机驱动与外设驱动分离 Linux中的I2C.SPI.USB等总线驱动,都采用了主机(控制器)驱动与外设(设备)驱动分离的思想.主机端 ...

  3. linux spi屏驱动程序,65 linux spi设备驱动之spi LCD屏驱动

    SPI的控制器驱动由平台设备与平台驱动来实现. 驱动后用spi_master对象来描述.在设备驱动中就可以通过函数spi_write, spi_read, spi_w8r16, spi_w8r8等函数 ...

  4. Linux spi驱动分析(四)----SPI设备驱动(W25Q32BV)

    一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它采用SPI接口和CPU通信,本文使用的W25Q32BV容量为32M,具体特性如下: 1.1.基本特性 该芯片最大支持10 ...

  5. LINUX SPI设备驱动模型分析之二 SPI总线模块分析

    上一篇文章我们简要介绍了SPI驱动模块,本章我们详细说明一下spi总线.设备.驱动模块的注册.注销以及这几个模块之间的关联. SPI总线的注册 spi模块也是基于LINUX设备-总线-驱动模型进行开发 ...

  6. linux probe函数调用,linux spi设备驱动中probe函数何时被调用

    这两天被设备文件快搞疯了,也怪自己学东西一知半解吧,弄了几天总算能把设备注册理清楚一点点了.就以spi子设备的注册为例总结一下,免得自己忘记. 首先以注册一个spidev的设备为例: static s ...

  7. linux usb驱动 probe,linux USB设备驱动之2:usb设备的probe全过程

    本文将详细讲述2.6.22下的一个USB设备插上linux系统的PC后是如何一步一步调到我们的usb设备驱动的probe函数的,我们知道我们的USB驱动的probe函数中的一个参数是interface ...

  8. linux驱动内核,Linux内核设备驱动之Linux内核基础笔记整理

    1. Linux内核驱动模块机制 静态加载, 把驱动模块编进内核, 在内核启动时加载 动态加载, 把驱动模块编为ko, 在内核启动后,需要用时加载 2. 编写内核驱动 #include #includ ...

  9. linux 编译字符设备驱动错误,linux字符设备驱动框架及编写流程

    流程: init { } exit { } 申请设备号 (动态注册/静态注册) 创建一个字符设备 cdev_alloc 初始化字符设备 cdev_init 设备号和字符设备关联 cdev_add 销毁 ...

  10. Linux内核驱动调试,Linux内核设备驱动之内核的调试技术笔记整理

    /****************** * 内核的调试技术 ******************/ (1)内核源代码中的一些与调试相关的配置选项 内核的配置选项中包含了一些与内核调试相关的选项,都集中 ...

最新文章

  1. 街篮最新服务器,《街篮》全新两组服务器开启 与你一起迎新年!
  2. 职场女人的心理问题提醒
  3. [译文]Domain Driven Design Reference(三)—— 模型驱动设计的构建模块
  4. 堆化 二叉堆一般用数组来表示。typedef struct _minHeapNodetypedef struct _otherInfo-icoding-C-数据结构
  5. 光端机怎样使用?光端机怎么和交换机连接?
  6. SPI和RAM IP核
  7. [css] 固定的外框尺寸,里面的图片尺寸不固定,如何让图像自适应外框呢?
  8. c语言蓝牙接收6,终于搞定了通过两路蓝牙接收数据
  9. DQL、DML、DDL、DCL的概念与区别
  10. oracle13001,安装oracle11g 遇到INS-13001环境不知足最低要求 解决方法
  11. mysql单表大小限制
  12. Servlet和JSP的区别与MVC模式
  13. 如何利用FL Studio进行听湿录干的声音录制
  14. 图论复习(二)-——哈密顿图及其应用
  15. Linux-DHCP服务器
  16. max30102c语言程序,STM32驱动MAX30102源码
  17. 梦幻西游跑商脚本教程
  18. 【16.8】苹果四代蓝牙耳机+吉萌兔保温杯+小红杯拿铁黑咖啡+公务员教材真题
  19. 解决Android模拟器不显示问题
  20. APP热更新方案(转)

热门文章

  1. dpdk LRO功能总结
  2. 如何解决CF安全数据上报异常 16-2
  3. Cmd命令检测电脑配置:
  4. DVWA-SQL Injection
  5. pandas——数据透视表
  6. Android Wi-Fi源码分析之wpa_supplicant初始化(三):wpa_supplicant_add_iface函数分析
  7. 计算机打印怎么取消,打印机如何取消打印作业?如何删除打印作业?
  8. android系统无法识别u盘,OTG无法识别U盘怎么办 OTG无法识别解决方法
  9. 华为无线网卡无服务器,联通华为无线上网卡连接时连接被终止解决方法 - 小众知识...
  10. 打孔式计算机,矩阵式打孔计算机3005-D型