SPI驱动分析之三

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 */
#define    SPI_NO_CS    0x40            /* 1 dev/bus, no chipselect */
#define    SPI_READY    0x80            /* slave pulls low to pause */
    u8            bits_per_word;
    int            irq;
    void            *controller_state;
    void            *controller_data;
    char            modalias[SPI_NAME_SIZE];

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

};

static inline struct spi_device *to_spi_device(struct device *dev)
{
    return dev ? container_of(dev, struct spi_device, dev) : NULL;
}

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;
};

static inline struct spi_driver *to_spi_driver(struct device_driver *drv)
{
    return drv ? container_of(drv, struct spi_driver, driver) : NULL;
}

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);
};
 

static inline struct spi_master *spi_master_get(struct spi_master *master)
{
    if (!master || !get_device(&master->dev))
        return NULL;
    return master;
}

static inline void spi_master_put(struct spi_master *master)
{
    if (master)
        put_device(&master->dev);
}

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;
};

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;
};

static inline void spi_message_init(struct spi_message *m)
{
    memset(m, 0, sizeof *m);
    INIT_LIST_HEAD(&m->transfers);
}

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

static inline void
spi_transfer_del(struct spi_transfer *t)
{
    list_del(&t->transfer_list);
}

static inline struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags)
{
    struct spi_message *m;

    m = kzalloc(sizeof(struct spi_message)
            + ntrans * sizeof(struct spi_transfer),
            flags);
    if (m) {
        int i;
        struct spi_transfer *t = (struct spi_transfer *)(m + 1);

        INIT_LIST_HEAD(&m->transfers);
        for (i = 0; i < ntrans; i++, t++)
            spi_message_add_tail(t, m);
    }
    return m;
}

static inline void spi_message_free(struct spi_message *m)
{
    kfree(m);
}

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

#ifdef    CONFIG_SPI
extern int
spi_register_board_info(struct spi_board_info const *info, unsigned n);
#else
/* board init code may ignore whether SPI is configured or not */
static inline int
spi_register_board_info(struct spi_board_info const *info, unsigned n)
    { return 0; }
#endif

extern struct spi_device *
spi_alloc_device(struct spi_master *master);

extern int
spi_add_device(struct spi_device *spi);

extern struct spi_device *
spi_new_device(struct spi_master *, struct spi_board_info *);

static inline void
spi_unregister_device(struct spi_device *spi)
{
    if (spi)
        device_unregister(&spi->dev);
}

extern const struct spi_device_id *
spi_get_device_id(const struct spi_device *sdev);

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值