题外话:面对成功和失败,一个人有没有“冠军之心”,直接影响他的表现。

几周前剖析了Linux SPI 驱动框架,算是明白个所以然,对于这么一个庞大的框架,并不是每一行代码都要自己去敲,因为前人已经把这个框架搭建好了,作为驱动开发者的我们只需要搞清楚哪一部分是需要自己修改或重新编写就OK了。

结合Linux内核面向对象的设计思想,SPI总的设计思路大概是这样的:

第①处:内核中抽象了SPI控制器,让spi_master成为他的象征,他的实例化对象就是与硬生生的SPI控制器对应的,在Linux内核中习惯将集成到SOC上的控制器用假想的platform总线来进行管理,于是乎spi_master的实例化就得依靠platform_device和platform_driver来联手完成了。

细嚼慢咽:这里的platform_device就相当于是spi_master的静态描述:包括几号控制器、寄存器地址、引脚配置等等,把这些信息以“资源”的形式挂在platform_device上,等platform_driver找到命中注定的那个他之后就可以获得这个(静态描述)资源,probe中用这些资源就生出了spi_master实例对象。这一系列流程前辈们都已经做好了,我们要做的就是将这静态描述platform_device修改成和自己SOC中的spi控制器一致的特性即可。即:适当修改arch/arm/mach-s5pv210/dev-spi.c中platform_device涉及的成员。

 // SPI0的寄存器地址
static struct resource s5pv210_spi0_resource[] = {
[] = {
.start = S5PV210_PA_SPI0,
.end = S5PV210_PA_SPI0 + 0x100 - ,
.flags = IORESOURCE_MEM,
},
[] = {
.start = DMACH_SPI0_TX,
.end = DMACH_SPI0_TX,
.flags = IORESOURCE_DMA,
},
[] = {
.start = DMACH_SPI0_RX,
.end = DMACH_SPI0_RX,
.flags = IORESOURCE_DMA,
},
[] = {
.start = IRQ_SPI0,
.end = IRQ_SPI0,
.flags = IORESOURCE_IRQ,
},
}; /**
* struct s3c64xx_spi_info - SPI Controller defining structure
* @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field.
* @src_clk_name: Platform name of the corresponding clock.
* @clk_from_cmu: If the SPI clock/prescalar control block is present
* by the platform's clock-management-unit and not in SPI controller.
* @num_cs: Number of CS this controller emulates.
* @cfg_gpio: Configure pins for this SPI controller.
* @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
* @rx_lvl_offset: Depends on tx fifo_lvl field and bus number
* @high_speed: If the controller supports HIGH_SPEED_EN bit
* @tx_st_done: Depends on tx fifo_lvl field
*/
static struct s3c64xx_spi_info s5pv210_spi0_pdata = {
.cfg_gpio = s5pv210_spi_cfg_gpio, //将GPIO配置成SPI0引脚的函数
.fifo_lvl_mask = 0x1ff,
.rx_lvl_offset = ,
.high_speed = , //看s5pv210的使用手册P901可知:这是用来配置CH_CFG寄存器的,主要是210用于从设备时......
.tx_st_done = ,
}; static u64 spi_dmamask = DMA_BIT_MASK(); struct platform_device s5pv210_device_spi0 = {
.name = "s3c64xx-spi",
.id = ,
.num_resources = ARRAY_SIZE(s5pv210_spi0_resource),
.resource = s5pv210_spi0_resource,
.dev = {
.dma_mask = &spi_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(),
.platform_data = &s5pv210_spi0_pdata,//特殊的spi_master数据
},
};

platform_device

第②处:添加/修改SPI外设“静态描述”的结构。在arch/arm/mach-s5pv210/mach-smdkv210.c文件中添加/修改SPI外设信息。这个结构被spi_register_board_info()函数挂在boardlist上,这个结构就是外设相关的,也即是说驱动编写的内容之一。内核在注册了spi_master之后就开始在boardlist中搜索spi外设,然后向spi总线中注册spi_device,这个结构就是用spi_board_info来初始化的,这些过程也是前人做好的。

 /*
* 以MMC SPI外设为例
*/
static struct s3c64xx_spi_csinfo smdk_spi0_csi[] = {
[SMDK_MMCSPI_CS] = {
.line = S5PV210_GPB(),
.set_level = gpio_set_value,
.fb_delay = 0x2,
},
};
static struct s3c64xx_spi_csinfo smdk_spi1_csi[] = {
[SMDK_MMCSPI_CS] = {
.line = S5PV210_GPB(),
.set_level = gpio_set_value,
.fb_delay = 0x2,
},
};
//在这个结构中根据具体的外设来修改内容:这个要依靠外设的使用手册来进行
static struct spi_board_info s5pv210_spi_devs[] __initdata = {
{
.modalias = "spidev", /* MMC SPI ,mod别名*/
.mode = SPI_MODE_0, /* CPOL=0, CPHA=0 */
.max_speed_hz = ,
/* Connected to SPI-0 as 1st Slave */
.bus_num = , //挂接在SPI0总线上
.chip_select = ,
.controller_data = &smdk_spi0_csi[SMDK_MMCSPI_CS],
},
{
.modalias = "spidev", /* MMC SPI */
.mode = SPI_MODE_0, /* CPOL=0, CPHA=0 */
.max_speed_hz = ,
/* Connected to SPI-1 as 1st Slave */
.bus_num = , //挂接在SPI1总线上
.chip_select = ,
.controller_data = &smdk_spi1_csi[SMDK_MMCSPI_CS],
},
};

spi_board_info

第③处:spi_master有了,spi_device也有了,接下来就是SPI驱动编写的重头任务了!编写spi_driver驱动,就是要针对具体的外设编写具体的操作“策略”。在内核源码中有参考例程就是drivers/spi/spidev.c,总体的思路和之前学习的字符设备一样:构建spi_driver结构体,然后将它注册到spi总线中,构建spi的file_operations结构体然后创建spi字符设备,spi_driver找到spi_device就在probe中创建字符设备节点提供给应用层。

Linux驱动:SPI驱动编写要点的更多相关文章

  1. Linux驱动 - SPI驱动 之三 SPI控制器驱动

    通过第一篇文章,我们已经知道,整个SPI驱动架构可以分为协议驱动.通用接口层和控制器驱动三大部分.其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能:1. ...

  2. [转载]Linux驱动-SPI驱动 之二:SPI通用接口层

    通过上一篇文章的介绍,我们知道,SPI通用接口层用于把具体SPI设备的协议驱动和SPI控制器驱动联接在一起,通用接口层除了为协议驱动和控制器驱动提供一系列的标准接口API,同时还为这些接口API定义了 ...

  3. [转载]Linux驱动-SPI驱动-概述

    转载地址http://blog.csdn.net/droidphone SPI是"Serial Peripheral Interface" 的缩写,是一种四线制的同步串行通信接口, ...

  4. Linux驱动 - SPI驱动 之四 SPI数据传输的队列化

    我们知道,SPI数据传输可以有两种方式:同步方式和异步方式.所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返 ...

  5. [DM8168]Linux下SPI驱动测试

    1.内核自带的SPI相关的驱动文件 项目中有CPU与FPGA进行通信,用到SPI接口: SPI头文件在: linux-kernel/include/linux/spi.h SPI实现在: linux- ...

  6. linux内核SPI总线驱动分析(一)(转)

    linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...

  7. linux驱动基础系列--linux spi驱动框架分析

    前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...

  8. Linux Spi驱动移植小结

    2012-01-07 22:21:29 效果图: 理论学习后,主要是linux中spi子系统设备框架的了解后,主控制器与设备分离的思想,那么我要开始动手了. 1,  make menuconfig添加 ...

  9. 4412 SPI驱动

    1.Linux主机驱动和外设驱动分离思想(I2C驱动里有) SPI驱动总线架构:SPI核心层(x),SPI控制器驱动层(x),SPI设备驱动层(√).前面两个设备驱动搞明白了可以去看 2.教程中介绍: ...

随机推荐

  1. 将Excel导入DataGridView 中的"select * from [Sheet1$]"中[ ]里面表单名的动态获取

    Sheet1$是Excel默认的第一个表名,如果改动:select * from [Sheet1$]"将查询失败,因此应根据选择自动获取excel表名: OpenFileDialog ofd ...

  2. @media screen

    参考地址: http://www.swordair.com/blog/2010/08/431/ http://ashaochangfu.blog.163.com/blog/static/1042517 ...

  3. webuploader 文件上传总结

    $(function() { /** * 初始化Web Uploader */ var uploader = WebUploader.create({ swf : '../mobile/Uploade ...

  4. *C语言的小技巧

    计算数组长度 ,,,,}; int Length=sizeof(a)/sizeof(int); 交换a和b的值,不借用辅助变量 a=a+b; b=a-b; a=a-b; 将0-9的字符转化为整数 '; ...

  5. error: libXpm.(a|so)

    centos 6.5 安装php时老是报错,找了很久答案都是千篇一律且不起作用,最后找到一个答案,特记录在此 脚本: tar zxvf php-5.3.28.tar.gz && cd ...

  6. 洛谷P2633 Count on a tree(主席树上树)

    题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个 ...

  7. Java设计模式の单利模式

    单利模式:确保一个类最多只有一个实例,并提供一个全局访问点. 经典单利模式创建对象代码 public class Singleton { private static Singleton unique ...

  8. Hyper-V启动虚拟机,消耗C盘大量磁盘空间

    问题描述 经常使用Hyper-V虚拟机的朋友,可能会碰到这样的现象,当启动某些虚拟机的是否,发现C盘的空间突然减少,减少的空间与虚拟机的内存一样大少. 通过分析C盘空间的磁盘文件,发现在Hyper-V ...

  9. 纸壳CMS可视化建站系统搭建多语言网站

    纸壳CMS是可视化建站系统,现已经从架构上支持多语言.但是多语言功能默认是没有开启的.您可以从设置中开启多语言,或者随时关闭它,您可以随时进行切换. 开启多语言 如果您没有在系统设置中看到多语言设置菜 ...

  10. T-SQL判断是否存在表、临时表

    利用SQL SERVER的系统函数 object_id() 可以判断是否存在表.临时表, object_id() 的作用是返回架构范围内对象的数据库对象标识.(即返回系统视图  sys.objects ...