3.0.35 SPI主机控制器驱动和外设驱动

SPI(同步外设接口)是由motorola开发的全双工同步串行总线,其接口由MISO(串行数据输入),MOSI(串行数据输出),SCK(串行移位时钟)

SS(从使能信号)4种信号构成。SS决定了惟一的与主设备通信的从设备,主设备通过产生移位时钟来发起通信。

 

在3.0.35 内核中,用spi_master 结构体来描述一个spi 主机控制器驱动,如下定义(include/linux/spi/spi.h):

/**
 * struct spi_master - interface to SPI master controller
 * @dev: device interface to this driver
 * @list: link with the global spi_master list
 * @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.
 * @dma_alignment: SPI controller constraint on DMA buffers alignment.
 * @mode_bits: flags understood by this controller driver
 * @flags: other constraints relevant to this driver
 * @bus_lock_spinlock: spinlock for SPI bus locking
 * @bus_lock_mutex: mutex for SPI bus locking
 * @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
 * @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;

    struct list_head list;

    /* 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;

    /* some SPI controllers pose alignment requirements on DMAable
     * buffers; let protocol drivers know about these requirements.
     */
    u16            dma_alignment;

    /* spi_device.mode flags understood by this controller driver */
    u16            mode_bits;

    /* other constraints relevant to this driver */
    u16            flags;
#define SPI_MASTER_HALF_DUPLEX    BIT(0)        /* can't do full duplex */
#define SPI_MASTER_NO_RX    BIT(1)        /* can't do buffer read */
#define SPI_MASTER_NO_TX    BIT(2)        /* can't do buffer write */

    /* lock and mutex for SPI bus locking */
    spinlock_t        bus_lock_spinlock;
    struct mutex        bus_lock_mutex;

    /* flag indicating that the SPI bus is locked for exclusive use */
    bool            bus_lock_flag;

    /* Setup mode and clock, etc (spi driver may call many times).  
     *
     * IMPORTANT:  this may be called when transfers to another
     * device are active.  DO NOT UPDATE SHARED REGISTERS in ways
     * which could break those transfers.
     */
    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);
};

 

分配、注册和注销SPI主控制器的API由SPI核心层提供(drivers/spi/spi.c):

struct spi_master *spi_alloc_master(struct device *dev, unsigned size);
int spi_register_master(struct spi_master *master);
void spi_unregister_master(struct spi_master *master);

 

在3.0.35 内核中使用 spi_driver 结构体来描述一个SPI外设驱动,可以认为是spi_master 的 client 驱动

spi_driver 结构体定义(include/linux/spi/spi.h)如下:

/**
 * struct spi_driver - Host side "protocol" driver
 * @id_table: List of SPI devices supported by this 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 {
    const struct spi_device_id *id_table;
    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;
};

可以看出,spi_driver 结构体和 platform_driver 结构体有极大的相似性,都有 probe(), remove(), shutdown(), suspend(), resume()这样

的接口。这几乎是一切client 端驱动的习惯模板。

 

在SPI 外设驱动中,当透过SPI总线进行数据传输的时候,使用了一套与CPU无关的统一接口。这套接口的第一个关键数据结构就是spi_transfer,

它用于描述SPI传输,如下示:(include/linux/spi/spi.h)

/*
 * I/O INTERFACE between SPI controller and protocol drivers
 *
 * Protocol drivers use a queue of spi_messages, each transferring data
 * between the controller and memory buffers.
 *
 * The spi_messages themselves consist of a series of read+write transfer
 * segments.  Those segments always read the same number of bits as they
 * write; but one or the other is easily ignored by passing a null buffer
 * pointer.  (This is unlike most types of I/O API, because SPI hardware
 * is full duplex.)
 *
 * NOTE:  Allocation of spi_transfer and spi_message memory is entirely
 * up to the protocol driver, which guarantees the integrity of both (as
 * well as the data buffers) for as long as the message is queued.
 */
struct spi_transfer {
    /* it's ok if tx_buf == rx_buf (right?)
     * for MicroWire, one buffer must be null
     * buffers must work with dma_*map_single() calls, unless
     *   spi_message.is_dma_mapped reports a pre-existing mapping
     */
    const void    *tx_buf;
    void        *rx_buf;
    unsigned    len;

    dma_addr_t    tx_dma;
    dma_addr_t    rx_dma;

    unsigned    cs_change:1;
    u8        bits_per_word;
    u16        delay_usecs;
    u32        speed_hz;

    struct list_head transfer_list;
};

而一次完整的SPI传输流程可能不只包含一次spi_transfer,它可能包含一个或多个spi_transfer, 这些 spi_transfer 最终通过spi_message 组织在一起

其定义如下(include/linux/spi/spi.h):

struct spi_message {
    struct list_head    transfers;

    struct spi_device    *spi;

    unsigned        is_dma_mapped:1;

    /* REVISIT:  we might want a flag affecting the behavior of the
     * last transfer ... allowing things like "read 16 bit length L"
     * immediately followed by "read L bytes".  Basically imposing
     * a specific message scheduling algorithm.
     *
     * Some controller drivers (message-at-a-time queue processing)
     * could provide that as their default scheduling algorithm.  But
     * others (with multi-message pipelines) could need a flag to
     * tell them about such special cases.
     */

    /* completion is reported through a callback */
    void            (*complete)(void *context);
    void            *context;
    unsigned        actual_length;
    int            status;

    /* for optional use by whatever driver currently owns the
     * spi_message ...  between calls to spi_async and then later
     * complete(), that's the spi_master controller driver.
     */
    struct list_head    queue;
    void            *state;
};

通过spi_message_init() 可以初始化spi_message,而将 spi_transfer 添加到 spi_message 的法则是:

static inline void
spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
{
    list_add_tail(&t->transfer_list, &m->transfers);
}

发起一次spi_message 的传输有同步和异步两种方式,使用同步API时,会阻塞等待这个消息被处理完,同步操作时,使用的API如下:

int spi_sync(struct spi_device *spi, struct spi_message *message);

使用异步API时,不会阻塞等待这个消息被处理完,但是可以在spi_message 的complete 字段挂载一个回调函数,当消息被处理完成后

该函数会被自动调用。异步操作时使用的API如下:

int spi_async(struct spi_device *spi, struct spi_message *message);

 

如下是一个典型的初始化spi_transfer, spi_message, 并进行spi数据传输的例子,同时它也是SPI核心层的一个通用API,

在SPI外设驱动中可以直接调用它进行读写操作。

/**
 * spi_write_then_read - SPI synchronous write followed by read
 * @spi: device with which data will be exchanged
 * @txbuf: data to be written (need not be dma-safe)
 * @n_tx: size of txbuf, in bytes
 * @rxbuf: buffer into which data will be read (need not be dma-safe)
 * @n_rx: size of rxbuf, in bytes
 * Context: can sleep
 *
 * This performs a half duplex MicroWire style transaction with the
 * device, sending txbuf and then reading rxbuf.  The return value
 * is zero for success, else a negative errno status code.
 * This call may only be used from a context that may sleep.
 *
 * Parameters to this routine are always copied using a small buffer;
 * portable code should never use this for more than 32 bytes.
 * Performance-sensitive or bulk transfer code should instead use
 * spi_{async,sync}() calls with dma-safe buffers.
 */
int spi_write_then_read(struct spi_device *spi,
        const void *txbuf, unsigned n_tx,
        void *rxbuf, unsigned n_rx)
{
    static DEFINE_MUTEX(lock);

    int            status;
    struct spi_message    message;
    struct spi_transfer    x[2];
    u8            *local_buf;

    /* Use preallocated DMA-safe buffer.  We can't avoid copying here,
     * (as a pure convenience thing), but we can keep heap costs
     * out of the hot path ...
     */
    if ((n_tx + n_rx) > SPI_BUFSIZ)
        return -EINVAL;

    spi_message_init(&message);
    memset(x, 0, sizeof x);
    if (n_tx) {
        x[0].len = n_tx;
        spi_message_add_tail(&x[0], &message);
    }
    if (n_rx) {
        x[1].len = n_rx;
        spi_message_add_tail(&x[1], &message);
    }

    /* ... unless someone else is using the pre-allocated buffer */
    if (!mutex_trylock(&lock)) {
        local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
        if (!local_buf)
            return -ENOMEM;
    } else
        local_buf = buf;

    memcpy(local_buf, txbuf, n_tx);
    x[0].tx_buf = local_buf;
    x[1].rx_buf = local_buf + n_tx;

    /* do the i/o */
    status = spi_sync(spi, &message);
    if (status == 0)
        memcpy(rxbuf, x[1].rx_buf, n_rx);

    if (x[0].tx_buf == buf)
        mutex_unlock(&lock);
    else
        kfree(local_buf);

    return status;
}
EXPORT_SYMBOL_GPL(spi_write_then_read);

 

SPI只是一种总线,spi_driver 有作用只是将spi外设挂接在该总线上,因此在spi_driver 的probe() 成员函数中,将注册SPI外设本身所属设备的驱动类型。

和platform_driver 对应着一个platform_device一样,spi_driver也对应一个spi_device,platform_device需要在BSP的板文件中添加板信息数据,而

spi_device也同样需要。spi_device 的板信息用 spi_board_info 结构体描述,定义如下(include/linux/spi/spi.h):

struct spi_board_info {
    /* the device name and module name are coupled, like platform_bus;
     * "modalias" is normally the driver name.
     *
     * platform_data goes to spi_device.dev.platform_data,
     * controller_data goes to spi_device.controller_data,
     * irq is copied too
     */
    char        modalias[SPI_NAME_SIZE];
    const void    *platform_data;
    void        *controller_data;
    int        irq;

    /* slower signaling on noisy or low voltage boards */
    u32        max_speed_hz;


    /* bus_num is board specific and matches the bus_num of some
     * spi_master that will probably be registered later.
     *
     * chip_select reflects how this chip is wired to that master;
     * it's less than num_chipselect.
     */
    u16        bus_num;
    u16        chip_select;

    /* mode becomes spi_device.mode, and is essential for chips
     * where the default of SPI_CS_HIGH = 0 is wrong.
     */
    u8        mode;

    /* ... may need additional spi_device chip config data here.
     * avoid stuff protocol drivers can set; but include stuff
     * needed to behave without being bound to a driver:
     *  - quirks like clock rate mattering when not selected
     */
};

该结构体描述了SPI外设使用的主机控制器序号,片选序号,数据比特率,SPI传输模式。

posted @ 2015-03-21 14:37  阿青1987  阅读(321)  评论(0编辑  收藏