linux pnx67xx spi 总线分析

SPI总线驱动分析:

基本数据结构:

    链表queue : 为spi controller 提供 任务队列。 每个任务是一个message。

    链表transfer_list :message 中存放任务具体内容的队列, 它的内容在应用中填充


struct spi_device {
    struct device        dev;
    struct spi_master    *master;
    u32            max_speed_hz;
    u8            chip_select;
    u8            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
     *  - ...
     */
};
    任务的数据结构:
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;
};


/////////////////////////////////////////////////////////////////////////////////////////
API:
spi_message_init---------->创建message(生成“transfer”链表)
spi_message_add----------->将 t 嵌入 message(m)中的链表“transfer”
spi_sync------------------>调用 pnx_spi_transfer 将 message 嵌入到 链表“queue”中,并执行message。

example of how to use spi bus:
spi_write(struct spi_device *spi, const u8 *buf, size_t len)
{
    struct spi_transfer    t = {
            .tx_buf        = buf,
            .len        = len,
        };
    struct spi_message    m;

    spi_message_init(&m);
    spi_message_add_tail(&t, &m);
    return spi_sync(spi, &m);
}
///////////////////////////////////////////////////////////////////////////////////////////
controller functions:

pnx67xx_spi_transfer   负责 将 message 挂入 queue。
pnx67xx_next_message   执行message传输。
pnx67xx_spi_next_xfer  执行transfer传输


static void __init pnx67xx_spi_setup_master(struct platform_device *pdev,
                        struct spi_master *master)
{
    master->bus_num = pdev->id;
    master->num_chipselect = PNX_SPI_CHIP_SELECTS;
    master->setup = pnx67xx_spi_setup;
    master->transfer = pnx67xx_spi_transfer;
    master->cleanup = pnx67xx_spi_cleanup;
    platform_set_drvdata(pdev, master);
}

pnx67xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
{      1.检查消息链表是否为空
    2.检查链表中的消息是否有异常
    3.将新消息插入链表
    4。如果当前不处于传输状态,则发起传输  pnx67xx_spi_next_message(pnx_spi)
}
//---------transmit msges----------------
pnx67xx_spi_next_message(struct pnx67xx_spi *pnx_spi)
{    1.取出消息:list_entry(pnx_spi->queue.next, struct spi_message, queue);
    2.select chip if it's not still active
    3.消息传输 :pnx67xx_spi_next_xfer(pnx_spi, msg);    
}
    //-------transmit for singal msg-------------
    pnx67xx_spi_next_xfer(pnx_spi, msg);
    {

        1.pnx67xx_do_poll_transfer();// 小于 dma buffer
        2.pnx67xx_do_dma_transfer();//大于等于dma buffer-----intr--->pnx67xx_spi_transfer_done()
                           --spi_write_stat-->pnx67xx_spi_transfer_done()
    }
    pnx67xx_spi_transfer_done(struct pnx67xx_spi *pnx_spi)
    {
        1.stop dma ,update actual length
        2.如果msg传输完成,pnx67xx_spi_msg_done()
        3.如果msg没有传完,pnx67xx_spi_next_xfer()
    }

pnx67xx_spi_msg_done()
{
    1.摘除msg
    2.如果msg链表为空,进入节电模式,否则执行下一个msg  pnx67xx_spi_next_message(pnx_spi)    
}

//------------------------------------------------------------
经典:
/* compute max packetsize for polling 20us */
    pollmax = clock * 20;
    pollmax = pollmax / 1000000;
    cs->pollsize_thread = pollmax / 8;
    /* polling in it is allowed up to 5 us */
    cs->pollsize_it = pollmax / 32;
polling 一次 pollsize  需要  20 us.
当使用cpu传输时,如说所传时间大于20us,则使用中断同步,否则使用轮寻机制。
20us 可能等于完成一次中断响应所需要的时间。


你可能感兴趣的:(linux pnx67xx spi 总线分析)