ad7928驱动代码_amd芯片组驱动程序

(4) 2024-07-30 20:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
ad7928驱动代码_amd芯片组驱动程序,希望能够帮助你!!!。

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); } } 

参考博客:AD7705驱动代码 -- Linux SPI设备驱动

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复