AD7490 SPI DRIVER

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/spi/spi.h>
#include <asm/uaccess.h>

#define AD7490_IOCTL_READ_AD  _IOR(0, 1, int)

static struct {
 struct spi_device *spi;
 struct class   *ad7490_class;
 int     major;
 struct mutex  lock;
} ad7490_data;

/*
 * This function initializes the SPI device parameters.
 */
static inline int spi_nor_setup(struct spi_device *spi, u8 bst_len)
{
 spi->bits_per_word = bst_len << 3;

 return spi_setup(spi);
}

#define SPI_FIFOSIZE  24 /* Bust size in bytes */
/*
 * This function perform spi read/write transfer.
 */
static int spi_read_write(struct spi_device *spi, u8 * buf, u32 len)
{
 struct spi_message m;
 struct spi_transfer t;

 if (len > SPI_FIFOSIZE || len <= 0)
  return -1;

 spi_nor_setup(spi, len);

 spi_message_init(&m);
 memset(&t, 0, sizeof t);

 t.tx_buf = buf;
 t.rx_buf = buf;
 t.len = (len + 3) / 4;

 spi_message_add_tail(&t, &m);

 if (spi_sync(spi, &m) != 0) {
  printk(KERN_ERR "%s: error\n", __func__);
  return -1;
 }

 dev_dbg(&spi->dev, "%s: len: 0x%x success\n", __func__, len);

 return 0;
}

static ssize_t ad7490_read(struct file *file, char __user *buf, size_t len,
                                  loff_t *ppos)
{
 return 0;
}

static ssize_t ad7490_write(struct file *file, const char __user *data,
                                   size_t len, loff_t *ppos)
{
 return 0;
}

static int ad7490_open(struct inode *inode, struct file *file)
{
 return 0;
}

static int ad7490_release(struct inode *inode, struct file *file)
{
 return 0;
}

/*
 * Input: arg is a pointer to channel
 * Output: arg is a pointer to AD value
 */
static int ad7490_ioctl(struct inode *inode, struct file *file,
       unsigned int cmd, unsigned long arg)
{
 u8 command[2];
 int ret = 0, i, channel, value;
 int __user *argp = (int __user *)arg;

 pr_debug("ioctl cmd %d is issued...\n", cmd);

 switch (cmd) {
 case AD7490_IOCTL_READ_AD:
  if (copy_from_user(&channel, argp, sizeof(int)))
   return -EFAULT;

  if ((channel < 0) || (channel > 15))
   return -EINVAL;

  mutex_lock(&ad7490_data.lock);//获取信号量锁存

  for (i = 0; i < 2; i++) {
   command[1] = 0x83 | (channel << 2);//add channel request to 'conctrl'
   command[0] = 0x70;
   ret = spi_read_write(ad7490_data.spi, command, 2);
   if (ret)
    break;
  }
  mutex_unlock(&ad7490_data.lock);//释放锁存信号量

  if (ret)
   return -EIO;

  if (channel != (command[1] >> 4)) {
   dev_err(&ad7490_data.spi->dev, "AD7490: channel not match, %d -> %d\n", channel, command[1] >> 4);
   return -EINVAL;
  }

  value = ((command[1] & 0xf) << 8) | command[0];

  if (copy_to_user(argp, &value, sizeof(value)))
   return -EFAULT;

  break;
 default:
  ret = -EINVAL;
  break;
 }

 return ret;
}
//设备文件访问操作接口
static const struct file_operations ad7490_fops = {
 .owner  = THIS_MODULE,
 .read  = ad7490_read,
 .write  = ad7490_write,
 .open  = ad7490_open,
 .release = ad7490_release,
 .ioctl  = ad7490_ioctl,
};

static int ad7490_probe(struct spi_device *spi) //监测系统是否有AD7490设备,并进行设备注册
{
 int ret = 0;
 struct device *dev;

 mutex_init(&ad7490_data.lock); //初始化lock信号量
 ad7490_data.spi = spi_dev_get(spi); //获取SPI设备
 ad7490_data.major = 0; //定义主设备号

 ret = register_chrdev(ad7490_data.major, "ad7490", &ad7490_fops);//注册字符设备
 if (ret < 0)
  return ret;

 if (ad7490_data.major == 0) {
  ad7490_data.major = ret;
  printk(KERN_INFO "AD7490: major number %d\n", ad7490_data.major);
 }
 /* create class and device for udev information */
 ad7490_data.ad7490_class = class_create(THIS_MODULE, "ad7490");//创建ad7490设备类
 if (IS_ERR(ad7490_data.ad7490_class)) {
  dev_err(&ad7490_data.spi->dev, "AD7490: failed to create ad7490 class\n");
  goto char_dev_remove;
 }

 dev = device_create(ad7490_data.ad7490_class, NULL,
       MKDEV(ad7490_data.major, 0), NULL, "ad7490");//创建设备节点
 if (IS_ERR(dev)) {
  dev_err(&ad7490_data.spi->dev,
   "AD7490: failed to create class device\n");
  goto class_remove;
 }
 return 0;

class_remove:
 class_destroy(ad7490_data.ad7490_class);
char_dev_remove:
 unregister_chrdev(ad7490_data.major, "ad7490");//注销字符设备
 return -ENODEV;
}

static int __devexit ad7490_remove(struct spi_device *spi)
{
 device_destroy(ad7490_data.ad7490_class, MKDEV(ad7490_data.major, 0));
 class_destroy(ad7490_data.ad7490_class);
 unregister_chrdev(ad7490_data.major, "ad7490");

 return 0;
}

static struct spi_driver ad7490_driver = {
 .driver = {
  .name  = "ad7490",
  .owner  = THIS_MODULE,
 },
 .probe  = ad7490_probe,
 .remove  = __devexit_p(ad7490_remove),
};

static int __init ad7490_init(void)
{
 return spi_register_driver(&ad7490_driver);
}
module_init(ad7490_init);

static void __exit ad7490_exit(void)
{
 spi_unregister_driver(&ad7490_driver);
}
module_exit(ad7490_exit);

MODULE_DESCRIPTION("Driver for AD7490");
MODULE_AUTHOR("Electronics, Inc");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ad7490");

AD7606是ADI公司的一款高精度、高速率的12位模数转换器。AD7606与微处理器之间的通信采用SPI接口,需要通过驱动程序来实现对AD7606的控制和数据传输。 AD7606 SPI驱动程序一般分为两个部分:硬件配置和软件编程。硬件配置主要包括对SPI总线的初始化和对AD7606片选引脚的配置。软件编程主要包括对SPI读写操作的封装和对AD7606控制命令的发送。 下面是一个简单的AD7606 SPI驱动程序代码示例: ``` #include <linux/spi/spi.h> #define AD7606_SPI_SPEED_HZ 5000000 // SPI时钟频率 #define AD7606_DEV_NAME "ad7606" // 设备名称 static struct spi_device *ad7606_spi_device; // AD7606 SPI设备结构体 static int ad7606_spi_probe(struct spi_device *spi) { // 初始化SPI设备 spi->max_speed_hz = AD7606_SPI_SPEED_HZ; spi->mode = SPI_MODE_3; spi_setup(spi); // 保存SPI设备结构体 ad7606_spi_device = spi; // TODO: 配置AD7606片选引脚 return 0; } static int ad7606_spi_remove(struct spi_device *spi) { // TODO: 释放AD7606片选引脚 return 0; } static struct spi_driver ad7606_spi_driver = { .probe = ad7606_spi_probe, .remove = ad7606_spi_remove, .driver = { .name = AD7606_DEV_NAME, .owner = THIS_MODULE, }, }; static int ad7606_spi_read_reg(u8 reg, u8 *buf, int len) { struct spi_message msg; struct spi_transfer xfer; u8 tx_buf = {reg, 0xFF}; // 第一个字节是寄存器地址,第二个字节可以是任意值 int ret; // 初始化SPI传输结构体 memset(&xfer, 0, sizeof(xfer)); xfer.tx_buf = tx_buf; xfer.rx_buf = buf; xfer.len = len; xfer.cs_change = 1; // 每次传输后自动取消片选 // 初始化SPI消息结构体 memset(&msg, 0, sizeof(msg)); msg.spi = ad7606_spi_device; msg.tx_buf = tx_buf; msg.rx_buf = buf; msg.len = len; // 发送SPI消息 ret = spi_sync_transfer(&msg); if (ret < 0) { printk(KERN_ERR "ad7606: failed to read register %02x\n", reg); return ret; } return 0; } // TODO: 实现其他AD7606控制命令的发送和数据读取函数 static int __init ad7606_init(void) { int ret; // 注册SPI驱动程序 ret = spi_register_driver(&ad7606_spi_driver); if (ret < 0) { printk(KERN_ERR "ad7606: failed to register SPI driver\n"); return ret; } return 0; } static void __exit ad7606_exit(void) { // 注销SPI驱动程序 spi_unregister_driver(&ad7606_spi_driver); } module_init(ad7606_init); module_exit(ad7606_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("AD7606 SPI driver"); ``` 相关问题: 1. AD7606是什么? 2. AD7606 SPI驱动程序的工作原理是什么? 3. AD7606控制命令有哪些? 4. 如何实现对AD7606数据的读取?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值