打印

OMAP3630下的Linux SPI总线驱动分析(1)

[复制链接]
2604|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
风的样子|  楼主 | 2015-7-21 13:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1 SPI概述
      SPI是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口,是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。
      SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要4根线,事实上3根也可以。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCLK(时钟),CS(片选)。
      MOSI(SDO):主器件数据输出,从器件数据输入。
      MISO(SDI):主器件数据输入,从器件数据输出。
      SCLK :时钟信号,由主器件产生。
      CS:从器件使能信号,由主器件控制。
      其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效,这就允许在同一总线上连接多个SPI设备成为可能。需要注意的是,在具体的应用中,当一条SPI总线上连接有多个设备时,SPI本身的CS有可能被其他的GPIO脚代替,即每个设备的CS脚被连接到处理器端不同的GPIO,通过操作不同的GPIO口来控制具体的需要操作的SPI设备,减少各个SPI设备间的干扰。
      SPI是串行通讯协议,也就是说数据是一位一位从MSB或者LSB开始传输的,这就是SCK时钟线存在的原因,由SCK提供时钟脉冲,MISO、MOSI则基于此脉冲完成数据传输。 SPI支持4-32bits的串行数据传输,支持MSB和LSB,每次数据传输时当从设备的大小端发生变化时需要重新设置SPI Master的大小端。


2 Linux SPI驱动总体架构
      在2.6的linux内核中,SPI的驱动架构可以分为如下三个层次:SPI 核心层、SPI控制器驱动层和SPI设备驱动层。
      Linux 中SPI驱动代码位于drivers/spi目录。
2.1 SPI核心层
      SPI核心层是Linux的SPI核心部分,提供了核心数据结构的定义、SPI控制器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线控制器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便SPI设备驱动通过总线控制器进行数据收发。
      Linux中,SPI核心层的代码位于driver/spi/ spi.c。由于该层是平台无关层,本文将不再叙述,有兴趣可以查阅相关资料。
2.2 SPI控制器驱动层
      SPI控制器驱动层,每种处理器平台都有自己的控制器驱动,属于平台移植相关层。它的职责是为系统中每条SPI总线实现相应的读写方法。在物理上,每个SPI控制器可以连接若干个SPI从设备。
      在系统开机时,SPI控制器驱动被首先装载。一个控制器驱动用于支持一条特定的SPI总线的读写。一个控制器驱动可以用数据结构struct spi_master来描述。
      在include/liunx/spi/spi.h文件中,在数据结构struct spi_master定义如下:
    /** 
     * struct spi_master - interface to SPI master controller
     * @dev: device interface to this driver
     * @bus_num: board-specific (and often SOC-specific) identifier for a
     *  given SPI controller.
     * @num_chipselect: chipselects are used to distinguish individual
     *  SPI slaves, and are numbered from zero to num_chipselects.
     *  each slave has a chipselect signal, but it's common that not
     *  every chipselect is connected to a slave.
     * @setup: updates the device mode and clocking records used by a
     *  device's SPI controller; protocol code may call this.  This
     *  must fail if an unrecognized or unsupported mode is requested.
     *  It's always safe to call this unless transfers are pending on
     *  the device whose settings are being modified.
     * @transfer: adds a message to the controller's transfer queue.
     * @cleanup: frees controller-specific state
     *
     * Each SPI master controller can communicate with one or more @spi_device
     * children.  These make a small bus, sharing MOSI, MISO and SCK signals
     * but not chip select signals.  Each device may be configured to use a
     * different clock rate, since those shared signals are ignored unless
     * the chip is selected.
     *
     * The driver for an SPI controller manages access to those devices through
     * a queue of spi_message transactions, copying data between CPU memory and
     * an SPI slave device.  For each such message it queues, it calls the
     * message's completion function when the transaction completes.
     */  
    struct spi_master {  
        struct device   dev;  
      
        /* other than negative (== assign one dynamically), bus_num is fully
         * board-specific.  usually that simplifies to being SOC-specific.
         * example:  one SOC has three SPI controllers, numbered 0..2,
         * and one board's schematics might show it using SPI-2.  software
         * would normally use bus_num=2 for that controller.
         */  
        s16         bus_num;  
      
        /* chipselects will be integral to many controllers; some others
         * might use board-specific GPIOs.
         */  
        u16         num_chipselect;  
      
        /* setup mode and clock, etc (spi driver may call many times) */  
        int         (*setup)(struct spi_device *spi);  
      
        /* bidirectional bulk transfers
         *
         * + The transfer() method may not sleep; its main role is
         *   just to add the message to the queue.
         * + For now there's no remove-from-queue operation, or
         *   any other request management
         * + To a given spi_device, message queueing is pure fifo
         *
         * + The master's main job is to process its message queue,
         *   selecting a chip then transferring data
         * + If there are multiple spi_device children, the i/o queue
         *   arbitration algorithm is unspecified (round robin, fifo,
         *   priority, reservations, preemption, etc)
         *
         * + Chipselect stays active during the entire message
         *   (unless modified by spi_transfer.cs_change != 0).
         * + The message transfers use clock and SPI mode parameters
         *   previously established by setup() for this device
         */  
        int         (*transfer)(struct spi_device *spi,  
                            struct spi_message *mesg);  
      
        /* called on release() to free memory provided by spi_master */  
        void            (*cleanup)(struct spi_device *spi);  
    };  



相关帖子

沙发
风的样子|  楼主 | 2015-7-21 13:02 | 只看该作者
bus_num为该控制器对应的SPI总线号。
      num_chipselect为该总线的对应的设备编号。
      Setup函数是设置SPI总线的模式,时钟等的初始化函数。
      Transfer函数是实现SPI总线读写方法的函数。
2.3 SPI设备驱动层
      SPI设备驱动层为用户接口层,其为用户提供了通过SPI总线访问具体设备的接口。
      SPI设备驱动层可以用两个模块来描述,struct spi_driver和struct spi_device。
      相关的数据结构如下:
/** 
* struct spi_driver - Host side "protocol" driver
* @probe: Binds this driver to the spi device.  Drivers can verify
*  that the device is actually present, and may need to configure
*  characteristics (such as bits_per_word) which weren't needed for
*  the initial configuration done during system setup.
* @remove: Unbinds this driver from the spi device
* @shutdown: Standard shutdown callback used during system state
*  transitions such as powerdown/halt and kexec
* @suspend: Standard suspend callback used during system state transitions
* @resume: Standard resume callback used during system state transitions
* @driver: SPI device drivers should initialize the name and owner
*  field of this structure.
*
* This represents the kind of device driver that uses SPI messages to
* interact with the hardware at the other end of a SPI link.  It's called
* a "protocol" driver because it works through messages rather than talking
* directly to SPI hardware (which is what the underlying SPI controller
* driver does to pass those messages).  These protocols are defined in the
* specification for the device(s) supported by the driver.
*
* As a rule, those device protocols represent the lowest level interface
* supported by a driver, and it will support upper level interfaces too.
* Examples of such upper levels include frameworks like MTD, networking,
* MMC, RTC, filesystem character device nodes, and hardware monitoring.
*/  
struct spi_driver {  
    int         (*probe)(struct spi_device *spi);  
    int         (*remove)(struct spi_device *spi);  
    void            (*shutdown)(struct spi_device *spi);  
    int         (*suspend)(struct spi_device *spi, pm_message_t mesg);  
    int         (*resume)(struct spi_device *spi);  
    struct device_driver    driver;  
};



使用特权

评论回复
板凳
风的样子|  楼主 | 2015-7-21 13:02 | 只看该作者
Driver是为device服务的,spi_driver注册时会扫描SPI bus上的设备,进行驱动和设备的绑定,probe函数用于驱动和设备匹配时被调用。从上面的结构体注释中我们可以知道,SPI的通信是通过消息队列机制,而不是像I2C那样通过与从设备进行对话的方式。
    /** 
     * struct spi_device - Master side proxy for an SPI slave device
     * @dev: Driver model representation of the device.
     * @master: SPI controller used with the device.
     * @max_speed_hz: Maximum clock rate to be used with this chip
     *  (on this board); may be changed by the device's driver.
     *  The spi_transfer.speed_hz can override this for each transfer.
     * @chip_select: Chipselect, distinguishing chips handled by @master.
     * @mode: The spi mode defines how data is clocked out and in.
     *  This may be changed by the device's driver.
     *  The "active low" default for chipselect mode can be overridden
     *  (by specifying SPI_CS_HIGH) as can the "MSB first" default for
     *  each word in a transfer (by specifying SPI_LSB_FIRST).
     * @bits_per_word: Data transfers involve one or more words; word sizes
     *  like eight or 12 bits are common.  In-memory wordsizes are
     *  powers of two bytes (e.g. 20 bit samples use 32 bits).
     *  This may be changed by the device's driver, or left at the
     *  default (0) indicating protocol words are eight bit bytes.
     *  The spi_transfer.bits_per_word can override this for each transfer.
     * @irq: Negative, or the number passed to request_irq() to receive
     *  interrupts from this device.
     * @controller_state: Controller's runtime state
     * @controller_data: Board-specific definitions for controller, such as
     *  FIFO initialization parameters; from board_info.controller_data
     * @modalias: Name of the driver to use with this device, or an alias
     *  for that name.  This appears in the sysfs "modalias" attribute
     *  for driver coldplugging, and in uevents used for hotplugging
     *
     * A @spi_device is used to interchange data between an SPI slave
     * (usually a discrete chip) and CPU memory.
     *
     * In @dev, the platform_data is used to hold information about this
     * device that's meaningful to the device's protocol driver, but not
     * to its controller.  One example might be an identifier for a chip
     * variant with slightly different functionality; another might be
     * information about how this particular board wires the chip's pins.
     */  
    struct spi_device {  
        struct device       dev;  
        struct spi_master   *master;  
        u32         max_speed_hz;  
        u8          chip_select;  
        u8          mode;  
    #define SPI_CPHA    0x01            /* clock phase */  
    #define SPI_CPOL    0x02            /* clock polarity */  
    #define SPI_MODE_0  (0|0)           /* (original MicroWire) */  
    #define SPI_MODE_1  (0|SPI_CPHA)  
    #define SPI_MODE_2  (SPI_CPOL|0)  
    #define SPI_MODE_3  (SPI_CPOL|SPI_CPHA)  
    #define SPI_CS_HIGH 0x04            /* chipselect active high? */  
    #define SPI_LSB_FIRST   0x08            /* per-word bits-on-wire */  
    #define SPI_3WIRE   0x10            /* SI/SO signals shared */  
    #define SPI_LOOP    0x20            /* loopback mode */  
        u8          bits_per_word;  
        int         irq;  
        void            *controller_state;  
        void            *controller_data;  
        char            modalias[32];  
      
        /*
         * likely need more hooks for more protocol options affecting how
         * the controller talks to each chip, like:
         *  - memory packing (12 bit samples into low bits, others zeroed)
         *  - priority
         *  - drop chipselect after each word
         *  - chipselect delays
         *  - ...
         */  
    };  
通常来说spi_device对应着SPI总线上某个特定的slave。


使用特权

评论回复
地板
风的样子|  楼主 | 2015-7-21 13:03 | 只看该作者
3 OMAP3630 SPI控制器
      OMAP3630上SPI是一个主/从的同步串行总线,这边有4个独立的SPI模块(SPI1,SPI2,SPI3,SPI4),各个模块之间的区别在于SPI1支持多达4个SPI设备,SPI2和SPI3支持2个SPI设备,而SPI4只支持1个SPI设备。
      OMAP3630的SPI控制器模块图如下:

图3.1 OMAP3630 SPI控制器模块图


    SPI控制器具有以下特征:
   1.可编程的串行时钟,包括频率,相位,极性。
   2.支持4到32位数据传输
   3.支持4通道或者单通道的从模式
   4.支持主的多通道模式
    4.1全双工/半双工
    4.2只发送/只接收/收发都支持模式
    4.3灵活的I/O端口控制
    4.4每个通道都支持DMA读写
   5.支持多个中断源的中断时间
   6.支持wake-up的电源管理
   7.内置64字节的FIFO

使用特权

评论回复
5
quray1985| | 2015-7-21 20:31 | 只看该作者
资料很详细,谢谢楼主的热心分享

使用特权

评论回复
6
baimiaocun2015| | 2015-7-21 22:26 | 只看该作者
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要4根线,事实上3根也可以。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCLK(时钟),CS(片选)。

使用特权

评论回复
7
豆腐块| | 2015-7-25 10:28 | 只看该作者
3线是少了哪条

使用特权

评论回复
8
Thor9| | 2015-7-25 11:17 | 只看该作者
SPI支持4-32bits的串行数据传输,支持MSB和LSB

使用特权

评论回复
9
冰河w| | 2015-7-26 14:20 | 只看该作者
Linux的 SPI总线,还没了解过,看看先

使用特权

评论回复
10
可可球| | 2015-7-26 19:34 | 只看该作者
Linux中,SPI核心层的代码位于driver/spi/ spi.c

使用特权

评论回复
11
zhangbo1985| | 2015-7-26 23:18 | 只看该作者
SPI是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口,是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

使用特权

评论回复
12
伊逸zy| | 2015-12-5 23:43 | 只看该作者
请问有源码吗》》我急需

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

25

主题

247

帖子

1

粉丝