S3C2440 平台的spi ad7888驱动程序

 

首先定义一个struct ad7888 {
struct cdev cdev;
struct spi_device *spi;

struct semaphore lock;
};
来描述我的设备附加信息
先理下逻辑:
[1]module_init(spi_ad7888_init);


[2]static int __init spi_ad7888_init(void) {}(在这个函数里应实现 初始化主设备号及字符设备注册最后调用平台设备注册函数spi_register_driver(spi_ad7888_driver))

[3]关于struct spi_driver spi_ad7888_driver这个结构体,需要填写的项有.probe .remove .driver其中.driver 又包含.name  .owner 等等。其中.name这个是关键,平台设备驱动程序的匹配就是根据这个name和device里面的.name作比较,当然,这里有点不同,spi的match会调到后面讲的spi_board_info中的.modalias做比较。

[4]接着填写probe和remove函数,我在spi_ad7888_driver结构体中,将.probe=spi_ad7888_probe。那么spi_ad7888_probe中实现的功能有:
分配一个struct ad7888结构体空间,这个结构体在上面定义
注:以下省略了所有的出错处理~实际应用中不能缺少。
static int __devinit spi_ad7888_probe(struct spi_device *spi) {
struct * chip;
chip =kmalloc(sizeof(struct ad7888),GFP_KERNEL);
dev_set_drvdata(&spi->dev,chip);//设置这里的指针是为了后面调用方面
chip->spi = spi;
init_MUTEX(&chip->lock);//初始化信号量
cdev_init(&chip->cdev,&ad_fop) ;
cdev_add(&chip->cdev,devno,1);//这里的devno为MKDEV(100,0);
}
至此probe的函数实现完了,应该要填写struct file_operations ad_fop这个结构体了,和所有字符设备一样
这里还是那些open ,read,write,ioctl,release这几个基本操作~接合实际硬件,对于这个spi ad 7888多通道的芯片来说,write的功能的实现还不如去实现ioctl,所以我这里省去了write的实现。

[5]struct file_operations ad_fop={
.owner = THIS_MODULE,
.ioctl = ad_ioctl,
.read = ad_rd,
.write = ad_wr,
.open = ad_op,
.release = ad_ex,
};
先看看open函数
static int ad_op(struct inode *inode,struct file *filp)
{
struct ad7888 *chip = container_of(inode->i_cdev,struct ad7888,cdev);
struct spi_device *spi = chip->spi;

filp->private_data=chip;//这里设置了为了read能找到ad7888这个结构,很重要哦!

return 0;
}
接下来要一个一个填写,其他的功能函数我就省略了,只实现一个read函数,其他依次类推,应该很容易弄出来。
[6]static int ad_rd(struct file *filp,int __user *buf,size_t count,loff_t *offset){
struct ad7888 *chip=filp->private_data;//还记得前面那个open函数里说明的吗?

if(down_interruptible(&chip->lock))//控制并发,互斥。如果没其他应用程序调用,其实也可以省去,毕竟现在的目的只是要让芯片简单地工作起来
return -ERESTARTSYS;

spi_read_buf[0]=0;
spi_read_buf[1]=0;
spi_write_then_read(chip->spi,spi_transfer_buf,2,spi_read_buf,2);//为什么发两个字节过去?
//看过2440 spi data寄存的朋友都知道,它只有8字节的单位,现在我们的ad7888采集回来的精度是12位,一次传送肯定不够的~发送两个字节过去,spi_write_then_read会将12位的长度截成两个字节~到后来还得拼回去,我在驱动层没做~在应用层调用的时候,我是用tmp|=buf[0];tmp|=buf[1];或了两次拼回去。
if(copy_to_user(buf,spi_read_buf,sizeof(spi_read_buf)))
{
//up(&chip->rdlock);
up(&chip->lock);
return -EFAULT;
}
up(&chip->lock);
return 0;

}

好了,驱动程序写完了,编译完成后~就能用了吗?当然不行了~还有一件重要的事情没做~就是spi_device是什么时候生成的啊?
上面的函数里面只有struct *spi_device 连 struct ad7888这个自定义的函数里面也只有struct *spi_device 并没有分配它的空间,那么它在哪里实现?


linux的设备管理模型是很巧妙的~
linux-2.6.24/arch/arm/mach-s3c2440/ 的mach-smdk2440.c

有这么一段:static struct spi_board_info spi_board_info[] __initdata =
{
{
.modalias               = "ad7888",//你注意到了没?这就是前面我说dirver中.name要设置相同的地方
.chip_select    = 0,
/*.controller_data =AT91_PIN_PA3 ,*/
//.max_speed_hz = 5000*24, /*(4700 * 26)-125000 * 26, (max sample rate @ 3V) * (cmd + data + overhead) */
.max_speed_hz   = 120000, /*(4700 * 26)-125000 * 26, (max sample rate @ 3V) * (cmd + data + overhead) */
.bus_num                = 0,

},
};
OK再在static void __init smdk2440_machine_init(void)
{
……
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));//把这句话加上,系统在启动时自动分配一个device
/*spi控制器初始化的时候,会使用spi_board_info生成spi_device
sslspi_probe()        
spi_register_master()
scan_boardinfo()   // 使用spi_board_info信息生成新的spi_device
spi_new_device()
*/
……
}
好了,到这里~如果你的内核中打开了spi master控制器的话,编译驱动添加到内核,就可以实现读取spi的驱动了。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值