查看cananl是否启动_SPI 总线协议和驱动

SPI是一种全双工串行通信接口,采用主从模式,适用于高速传输。协议包括四种时钟工作模式,依赖于CPOL和CPHA的组合。SPI总线有4条信号线,工作原理为主设备控制时钟和片选,传输数据。内核中,SPI总线框架类似于I2C,主要数据结构包括spi_master、spi_device等。在驱动注册时,会调用setup方法配置传输参数,并使用bitbang模拟SPI通信。 spi_gpio驱动展示了如何通过GPIO模拟SPI通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

协议介绍

SPI(Serial Peripheral Interface),即串行外设接口,是一种串口通信接口协议。SPI遵循主从模式框架设计架构,但只能有一个主设备。SPI总线有4条信号线,CS(片选信号线),SCLK(时钟信号线),MOSI(主出从入信号线)和MISO(主入从出信号线),因此SPI是全双工总线。SPI的工作原理比较简单,主设备控制片选和时钟输出,输出数据到从设备及读取从设备输入的数据。

SPI协议有四种时钟工作模式(Mode0,Mode1,Mode2和Mode3),要求主从设备工作模式一致。从设备在出厂之后,时钟工作模式已经固定,一般通过修改主设备的时钟工作模式来匹配从设备时钟模式。SPI的四种工作模式取决于时钟极性(CPOL)和时钟相位(CPHA)的组合,时钟极性CPOL用来配置SCLK的电平处于哪种状态时是空闲态或者工作态,而时钟相位CPHA用来配置数据采样在哪个时钟沿:

(1)CPOL=0,表示SCLK低电平时是空闲态,也就是SCLK高电平时是工作态

(2)CPOL=1,表示SCLK高电平时是工作态,也就是SCLK低电平时是工作态

(3)CPHA=0,表示数据采样在第一个时钟沿,数据发送在第二个时钟沿

(4)CPHA=1,表示数据采样在第二个时钟沿,数据发送在第一个时钟沿

协议工作时序图如下(图片来源于网络):

SPI总线具有传输速率快,全双工和硬件电路简单等有点,但是有个缺点:没有类似于I2C总线的应答机制。

内核框架

内核中SPI总线协议框架类似于I2C的总线框架。核心层提供spi_master,spi_device,spi_driver,spi_message和spi_transfer核心数据结构和API接口,供上层系统注册主设备驱动,从设备以及从设备驱动。

1,数据结构:

(1)struct spi_master:主设备和驱动。spi_master结构包含主设备速率,工作模式,统计相关信息。采用了kernel workqueue的工作模式,提供了数据传输相关的回调接口:transfer()接口用于将spi_message加入消息队列,workqueue从消息队列中取出spi_message,通过transfer_one_message()接口发送一个spi_message,每个spi_message包含多个spi_transfer,最终通过transfer_one()接口发送一个spi_transfer。

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;

/* bitmask of supported bits_per_word for transfers */

u32            bits_per_word_mask;    // 一个transfer的bit数掩码

#define SPI_BPW_MASK(bits) BIT((bits) - 1)

#define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1))

#define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1))

/* limits on transfer speed */

u32            min_speed_hz;    // 支持的最小传输速率

u32            max_speed_hz;    // 支持的最大传输速率

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

#define SPI_MASTER_MUST_RX      BIT(3)        /* requires rx */

#define SPI_MASTER_MUST_TX      BIT(4)        /* requires tx */

/* 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);    // 每个transfer传输之前由 spi_driver调用,用于配置传输参数(不同从设备在速率和时钟模式上都可能不同,因此每个transfer都需要重新配置)

/* 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);    // spi_async() / spi_sync() 接口调用该方法将spi_message消息加入队列

/* called on release() to free memory provided by spi_master */

void            (*cleanup)(struct spi_device *spi);

/*

* Used to enable core support for DMA handling, if can_dma()

* exists and returns true then the transfer will be mapped

* prior to transfer_one() being called.  The driver should

* not modify or store xfer and dma_tx and dma_rx must be set

* while the device is prepared.

*/

bool            (*can_dma)(struct spi_master *master,

struct spi_device *spi,

struct spi_transfer *xfer);

/*

* These hooks are for drivers that want to use the generic

* master transfer queueing mechanism. If these are used, the

* transfer() function above must NOT be specified by the driver.

* Over time we expect SPI drivers to be phased over to this API.

*/

bool                queued;

struct kthread_worker        kworker;

struct task_struct        *kworker_task;

struct kthread_work        pump_messages;    // work queue,用于处理队列中的spi_message

spinlock_t            queue_lock;

struct list_head        queue;

struct spi_message        *cur_msg;

bool                idling;

bool                busy;

bool                running;

bool                rt;

bool                auto_runtime_pm;

bool                            cur_msg_prepared;

bool                cur_msg_mapped;

struct completion               xfer_completion;

size_t                max_dma_len;

int (*prepare_transfer_hardware)(struct spi_master *master);      // 准备好硬件,用于实际数据传输

int (*transfer_one_message)(struct spi_master *master,

struct spi_message *mesg);                                            // 发送一个spi_message

int (*unprepare_transfer_hardware)(struct spi_master *master);

int (*prepare_message)(struct spi_master *master,

struct spi_message *message);

int (*unprepare_message)(struct spi_master *master,

struct spi_message *message);

/*

* These hooks are for drivers that use a generic implementation

* of transfer_one_message() provied by the core.

*/

void (*set_cs)(struct spi_device *spi, bool enable);    // 每次传输前,设置片选信号

int (*transfer_one)(struct spi_master *master, struct spi_device *spi,

struct spi_transfer *transfer);                          // 发送一个 spi_transfer

void (*handle_err)(struct spi_master *master,

struct spi_message *message);

/* gpio chip select */

int            *cs_gpios;

/* statistics */

struct spi_statistics    statistics;

/* DMA channels for use with core dmaengine helpers */

struct dma_chan        *dma_tx;

struct dma_chan        *dma_rx;

/* dummy data for full duplex devices */

void            *dummy_rx;

void            *dummy_tx;

};

(2)struct spi_device:spi_device用于描述一个spi从设备,一般在主设备注册时,通过平台相关代码配置或者设备树配置自动创建并注册。

struct spi_device {

struct device        dev;

struct spi_master    *master;

u32            max_speed_hz;    // 支持的最大传输速率

u8            chip_select;    // 片选

u8            bits_per_word;    // 单位传输bit数

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

#define    SPI_TX_DUAL    0x100            /* transmit with 2 wires */

#define    SPI_TX_QUAD    0x200            /* transmit with 4 wires */

#define    SPI_RX_DUAL    0x400            /* receive with 2 wires */

#define    SPI_RX_QUAD    0x800            /* receive with 4 wires */

int            irq;

void            *controller_state;

void            *controller_data;

char            modalias[SPI_NAME_SIZE];

int            cs_gpio;    /* chip select gpio */

/* the statistics */

struct spi_statistics    statistics;

/*

* 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

*  - ...

*/

};

(3)struct spi_driver:从设备驱动

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

struct device_driver    driver;

};

(4)struct spi_message:spi消息结构

struct spi_message {

struct list_head    transfers;    // 包含的spi_transfer列表

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

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;

};

(5)spi_transfer:包含在spi_message中的spi_transfer

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;    // 发送buffer

void        *rx_buf;    // 接收buffer

unsigned    len;    // buffer长度

dma_addr_t    tx_dma;

dma_addr_t    rx_dma;

struct sg_table tx_sg;

struct sg_table rx_sg;

unsigned    cs_change:1;

unsigned    tx_nbits:3;

unsigned    rx_nbits:3;

#define    SPI_NBITS_SINGLE    0x01 /* 1bit transfer */

#define    SPI_NBITS_DUAL        0x02 /* 2bits transfer */

#define    SPI_NBITS_QUAD        0x04 /* 4bits transfer */

u8        bits_per_word;

u16        delay_usecs;

u32        speed_hz;

struct list_head transfer_list;

};

2,框架接口:

(1)spi_master注册接口:int spi_register_master(struct spi_master *master);

int spi_register_master(struct spi_master *master)

{

static atomic_t        dyn_bus_id = ATOMIC_INIT((1<<15) - 1);

struct device        *dev = master->dev.parent;

struct boardinfo    *bi;

int            status = -ENODEV;

int            dynamic = 0;

if (!dev)

return -ENODEV;

status = of_spi_register_master(master);    // 从设备树配置中获取片选个数,和片选gpio编号

if (status)

return status;

/* even if it's just one always-selected device, there must

* be at least one chipselect

*/

if (master->num_chipselect == 0)

return -EINVAL;

if ((master->bus_num < 0) && master->dev.of_node)

master->bus_num = of_alias_get_id(master->dev.of_node, "spi");

/* convention:  dynamically assigned bus IDs count down from the max */

if (master->bus_num < 0) {

/* FIXME switch to an IDR based scheme, something like

* I2C now uses, so we can't run out of "dynamic" IDs

*/

master->bus_num = atomic_dec_return(&dyn_bus_id);

dynamic = 1;

}

INIT_LIST_HEAD(&master->queue);

spin_lock_init(&master->queue_lock);

spin_lock_init(&master->bus_lock_spinlock);

mutex_init(&master->bus_lock_mutex);

master->bus_lock_flag = 0;

init_completion(&master->xfer_completion);

if (!master->max_dma_len)

master->max_dma_len = INT_MAX;

/* register the device, then userspace will see it.

* registration fails if the bus ID is in use.

*/

dev_set_name(&master->dev, "spi%u", master->bus_num);

status = device_add(&master->dev);    // 注册master到kernel设备驱动框架

if (status < 0)

goto done;

dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),

dynamic ? " (dynamic)" : "");

/* If we're using a queued driver, start the queue */

if (master->transfer)

dev_info(dev, "master is unqueued, this is deprecated\n");

else {

status = spi_master_initialize_queue(master);    // 初始化主设备消息队列处理机制,workqueue

if (status) {

device_del(&master->dev);

goto done;

}

}

/* add statistics */

spin_lock_init(&master->statistics.lock);

mutex_lock(&board_lock);

list_add_tail(&master->list, &spi_master_list);    // 将master加入 spi_master_list 列表中

list_for_each_entry(bi, &board_list, list)

spi_match_master_to_boardinfo(master, &bi->board_info);    // 从预配置的board_list中创建匹配的spi_device

mutex_unlock(&board_lock);

/* Register devices from the device tree and ACPI */

of_register_spi_devices(master);    // 从设备树配置中创建并注册所有的spi_device

acpi_register_spi_devices(master);

done:

return status;

}

static int spi_master_initialize_queue(struct spi_master *master)

{

int ret;

master->transfer = spi_queued_transfer;    // 设置transfer方法为 spi_queued_transfer(),该方法将spi_message加入master的message                                                                                           queue

if (!master->transfer_one_message)

master->transfer_one_message = spi_transfer_one_message;    // spi_transfer_one_message用来轮询message中的所有spi_transfer,调                                                                                                                          用 master中的transfer_one来一个个传输spi_transfer

/* Initialize and start queue */

ret = spi_init_queue(master);    // 初始化workqueue线程

if (ret) {

dev_err(&master->dev, "problem initializing queue\n");

goto err_init_queue;

}

master->queued = true;

ret = spi_start_queue(master);    // 启动workqueue线程,执行spi_pump_messages()方法从消息队列获取spi_message进行传输

if (ret) {

dev_err(&master->dev, "problem starting queue\n");

goto err_start_queue;

}

return 0;

err_start_queue:

spi_destroy_queue(master);

err_init_queue:

return ret;

}

static void of_register_spi_devices(struct spi_master *master)

{

struct spi_device *spi;

struct device_node *nc;

if (!master->dev.of_node)

return;

for_each_available_child_of_node(master->dev.of_node, nc) {

spi = of_register_spi_device(master, nc);    // 轮询注册每个spi_device

if (IS_ERR(spi))

dev_warn(&master->dev, "Failed to create SPI device for %s\n",

nc->full_name);

}

}

of_register_spi_device(struct spi_master *master, struct device_node *nc)

{

struct spi_device *spi;

int rc;

u32 value;

/* Alloc an spi_device */

spi = spi_alloc_device(master);    // 分配spi_device结构

if (!spi) {

dev_err(&master->dev, "spi_device alloc error for %s\n",

nc->full_name);

rc = -ENOMEM;

goto err_out;

}

/* Select device driver */

rc = of_modalias_node(nc, spi->modalias,

sizeof(spi->modalias));

if (rc < 0) {

dev_err(&master->dev, "cannot find modalias for %s\n",

nc->full_name);

goto err_out;

}

/* Device address */

rc = of_property_read_u32(nc, "reg", &value);

if (rc) {

dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",

nc->full_name, rc);

goto err_out;

}

spi->chip_select = value;    // 配置片选编号

/* Mode (clock phase/polarity/etc.) */

if (of_find_property(nc, "spi-cpha", NULL))

spi->mode |= SPI_CPHA;

if (of_find_property(nc, "spi-cpol", NULL))

spi->mode |= SPI_CPOL;

if (of_find_property(nc, "spi-cs-high", NULL))

spi->mode |= SPI_CS_HIGH;

if (of_find_property(nc, "spi-3wire", NULL))

spi->mode |= SPI_3WIRE;

if (of_find_property(nc, "spi-lsb-first", NULL))

spi->mode |= SPI_LSB_FIRST;

/* Device DUAL/QUAD mode */

if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {

switch (value) {

case 1:

break;

case 2:

spi->mode |= SPI_TX_DUAL;

break;

case 4:

spi->mode |= SPI_TX_QUAD;

break;

default:

dev_warn(&master->dev,

"spi-tx-bus-width %d not supported\n",

value);

break;

}

}

if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {

switch (value) {

case 1:

break;

case 2:

spi->mode |= SPI_RX_DUAL;

break;

case 4:

spi->mode |= SPI_RX_QUAD;

break;

default:

dev_warn(&master->dev,

"spi-rx-bus-width %d not supported\n",

value);

break;

}

}

/* Device speed */

rc = of_property_read_u32(nc, "spi-max-frequency", &value);

if (rc) {

dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",

nc->full_name, rc);

goto err_out;

}

spi->max_speed_hz = value;

/* Store a pointer to the node in the device structure */

of_node_get(nc);

spi->dev.of_node = nc;

/* Register the new device */

rc = spi_add_device(spi);    // 注册spi_device到spi_bus_type中

if (rc) {

dev_err(&master->dev, "spi_device register error %s\n",

nc->full_name);

goto err_out;

}

return spi;

err_out:

spi_dev_put(spi);

return ERR_PTR(rc);

}

int spi_add_device(struct spi_device *spi)

{

static DEFINE_MUTEX(spi_add_lock);

struct spi_master *master = spi->master;

struct device *dev = master->dev.parent;

int status;

/* Chipselects are numbered 0..max; validate. */

if (spi->chip_select >= master->num_chipselect) {

dev_err(dev, "cs%d >= max %d\n",

spi->chip_select,

master->num_chipselect);

return -EINVAL;

}

/* Set the bus ID string */

spi_dev_set_name(spi);

/* We need to make sure there's no other device with this

* chipselect **BEFORE** we call setup(), else we'll trash

* its configuration.  Lock against concurrent add() calls.

*/

mutex_lock(&spi_add_lock);

status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);

if (status) {

dev_err(dev, "chipselect %d already in use\n",

spi->chip_select);

goto done;

}

if (master->cs_gpios)

spi->cs_gpio = master->cs_gpios[spi->chip_select];    // 获取片选gpio

/* Drivers may modify this initial i/o setup, but will

* normally rely on the device being setup.  Devices

* using SPI_CS_HIGH can't coexist well otherwise...

*/

status = spi_setup(spi);    // 内部调用master->setup设置传输参数

if (status < 0) {

dev_err(dev, "can't setup %s, status %d\n",

dev_name(&spi->dev), status);

goto done;

}

/* Device may be bound to an active driver when this returns */

status = device_add(&spi->dev);    // 将spi_device注册进设备驱动框架

if (status < 0)

dev_err(dev, "can't add %s, status %d\n",

dev_name(&spi->dev), status);

else

dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));

done:

mutex_unlock(&spi_add_lock);

return status;

}

int spi_setup(struct spi_device *spi)

{

unsigned    bad_bits, ugly_bits;

int        status;

/* check mode to prevent that DUAL and QUAD set at the same time

*/

if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) ||

((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) {

dev_err(&spi->dev,

"setup: can not select dual and quad at the same time\n");

return -EINVAL;

}

/* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden

*/

if ((spi->mode & SPI_3WIRE) && (spi->mode &

(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)))

return -EINVAL;

/* help drivers fail *cleanly* when they need options

* that aren't supported with their current master

*/

bad_bits = spi->mode & ~spi->master->mode_bits;

ugly_bits = bad_bits &

(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);

if (ugly_bits) {

dev_warn(&spi->dev,

"setup: ignoring unsupported mode bits %x\n",

ugly_bits);

spi->mode &= ~ugly_bits;

bad_bits &= ~ugly_bits;

}

if (bad_bits) {

dev_err(&spi->dev, "setup: unsupported mode bits %x\n",

bad_bits);

return -EINVAL;

}

if (!spi->bits_per_word)

spi->bits_per_word = 8;

status = __spi_validate_bits_per_word(spi->master, spi->bits_per_word);

if (status)

return status;

if (!spi->max_speed_hz)

spi->max_speed_hz = spi->master->max_speed_hz;

if (spi->master->setup)

status = spi->master->setup(spi);    // 调用master->setup()

spi_set_cs(spi, false);    // 先禁止片选

dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",

(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),

(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",

(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",

(spi->mode & SPI_3WIRE) ? "3wire, " : "",

(spi->mode & SPI_LOOP) ? "loopback, " : "",

spi->bits_per_word, spi->max_speed_hz,

status);

return status;

}

static void spi_set_cs(struct spi_device *spi, bool enable)

{

if (spi->mode & SPI_CS_HIGH)

enable = !enable;

if (gpio_is_valid(spi->cs_gpio))

gpio_set_value(spi->cs_gpio, !enable);    // 优先设置gpio片选信号

else if (spi->master->set_cs)

spi->master->set_cs(spi, !enable);    // 否则调用master->set_cs()

}

(2)数据传输(异步传输):int spi_async(struct spi_device *spi, struct spi_message *message)

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

{

struct spi_master *master = spi->master;

int ret;

unsigned long flags;

ret = __spi_validate(spi, message);

if (ret != 0)

return ret;

spin_lock_irqsave(&master->bus_lock_spinlock, flags);

if (master->bus_lock_flag)

ret = -EBUSY;

else

ret = __spi_async(spi, message);     // 调用无锁版本

spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);

return ret;

}

static int __spi_async(struct spi_device *spi, struct spi_message *message)

{

struct spi_master *master = spi->master;

message->spi = spi;

SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_async);

SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_async);    // 更新统计信息

trace_spi_message_submit(message);

return master->transfer(spi, message);    // 调用master->transfer,即spi_queued_transfer(),将spi_message加入消息队列

}

static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)

{

return __spi_queued_transfer(spi, msg, true);    // true表示消息加入队列后,需要启动workqueue线程去处理队列中的消息,因为这个方法只会被异步传输方法调用。

}

static int __spi_queued_transfer(struct spi_device *spi,

struct spi_message *msg,

bool need_pump)

{

struct spi_master *master = spi->master;

unsigned long flags;

spin_lock_irqsave(&master->queue_lock, flags);

if (!master->running) {

spin_unlock_irqrestore(&master->queue_lock, flags);

return -ESHUTDOWN;

}

msg->actual_length = 0;

msg->status = -EINPROGRESS;

list_add_tail(&msg->queue, &master->queue);    // spi_message加入master消息队列

if (!master->busy && need_pump)

queue_kthread_work(&master->kworker, &master->pump_messages);    // need_pump为true,启动workqueue线程处理消息。其中master->pump_message方法为spi_pump_messages()方法

spin_unlock_irqrestore(&master->queue_lock, flags);

return 0;

}

// spi_pump_messages()运行于workqueue线程

static void spi_pump_messages(struct kthread_work *work)

{

struct spi_master *master =

container_of(work, struct spi_master, pump_messages);

__spi_pump_messages(master, true);    // 执行实际的数据处理

}

static void __spi_pump_messages(struct spi_master *master, bool in_kthread)

{

unsigned long flags;

bool was_busy = false;

int ret;

/* Lock queue */

spin_lock_irqsave(&master->queue_lock, flags);

/* Make sure we are not already running a message */

if (master->cur_msg) {

spin_unlock_irqrestore(&master->queue_lock, flags);

return;

}

/* If another context is idling the device then defer */

if (master->idling) {

queue_kthread_work(&master->kworker, &master->pump_messages);

spin_unlock_irqrestore(&master->queue_lock, flags);

return;

}

/* Check if the queue is idle */

if (list_empty(&master->queue) || !master->running) {

if (!master->busy) {

spin_unlock_irqrestore(&master->queue_lock, flags);

return;

}

/* Only do teardown in the thread */

if (!in_kthread) {

queue_kthread_work(&master->kworker,

&master->pump_messages);

spin_unlock_irqrestore(&master->queue_lock, flags);

return;

}

master->busy = false;

master->idling = true;

spin_unlock_irqrestore(&master->queue_lock, flags);

kfree(master->dummy_rx);

master->dummy_rx = NULL;

kfree(master->dummy_tx);

master->dummy_tx = NULL;

if (master->unprepare_transfer_hardware &&

master->unprepare_transfer_hardware(master))    // 调用master->unprepare_transfer_hardware结束上一次硬件传输

dev_err(&master->dev,

"failed to unprepare transfer hardware\n");

if (master->auto_runtime_pm) {

pm_runtime_mark_last_busy(master->dev.parent);

pm_runtime_put_autosuspend(master->dev.parent);

}

trace_spi_master_idle(master);

spin_lock_irqsave(&master->queue_lock, flags);

master->idling = false;

spin_unlock_irqrestore(&master->queue_lock, flags);

return;

}

/* Extract head of queue */

master->cur_msg =

list_first_entry(&master->queue, struct spi_message, queue);    // 从消息队列头获取一个message

list_del_init(&master->cur_msg->queue);

if (master->busy)

was_busy = true;

else

master->busy = true;

spin_unlock_irqrestore(&master->queue_lock, flags);

if (!was_busy && master->auto_runtime_pm) {

ret = pm_runtime_get_sync(master->dev.parent);

if (ret < 0) {

dev_err(&master->dev, "Failed to power device: %d\n",

ret);

return;

}

}

if (!was_busy)

trace_spi_master_busy(master);

if (!was_busy && master->prepare_transfer_hardware) {

ret = master->prepare_transfer_hardware(master);    // 准备好新的传输硬件条件

if (ret) {

dev_err(&master->dev,

"failed to prepare transfer hardware\n");

if (master->auto_runtime_pm)

pm_runtime_put(master->dev.parent);

return;

}

}

trace_spi_message_start(master->cur_msg);

if (master->prepare_message) {

ret = master->prepare_message(master, master->cur_msg);    // 如果有传输消息准备方法,就调用

if (ret) {

dev_err(&master->dev,

"failed to prepare message: %d\n", ret);

master->cur_msg->status = ret;

spi_finalize_current_message(master);

return;

}

master->cur_msg_prepared = true;

}

ret = spi_map_msg(master, master->cur_msg);

if (ret) {

master->cur_msg->status = ret;

spi_finalize_current_message(master);

return;

}

ret = master->transfer_one_message(master, master->cur_msg);    // 传输一个spi_message,即spi_transfer_one_message()

if (ret) {

dev_err(&master->dev,

"failed to transfer one message from queue\n");

return;

}

}

static int spi_transfer_one_message(struct spi_master *master,

struct spi_message *msg)

{

struct spi_transfer *xfer;

bool keep_cs = false;

int ret = 0;

unsigned long ms = 1;

struct spi_statistics *statm = &master->statistics;

struct spi_statistics *stats = &msg->spi->statistics;

spi_set_cs(msg->spi, true);

SPI_STATISTICS_INCREMENT_FIELD(statm, messages);

SPI_STATISTICS_INCREMENT_FIELD(stats, messages);

list_for_each_entry(xfer, &msg->transfers, transfer_list) {    // 轮询message下的所有transfer

trace_spi_transfer_start(msg, xfer);

spi_statistics_add_transfer_stats(statm, xfer, master);

spi_statistics_add_transfer_stats(stats, xfer, master);

if (xfer->tx_buf || xfer->rx_buf) {

reinit_completion(&master->xfer_completion);

ret = master->transfer_one(master, msg->spi, xfer);    // 调用master->transfer_one()传输spi_transfer

if (ret < 0) {

SPI_STATISTICS_INCREMENT_FIELD(statm,

errors);

SPI_STATISTICS_INCREMENT_FIELD(stats,

errors);

dev_err(&msg->spi->dev,

"SPI transfer failed: %d\n", ret);

goto out;

}

if (ret > 0) {

ret = 0;

ms = xfer->len * 8 * 1000 / xfer->speed_hz;

ms += ms + 100; /* some tolerance */

ms = wait_for_completion_timeout(&master->xfer_completion,

msecs_to_jiffies(ms));    // 当前线程加入传输完成队列,传输完成时中断处理函数会唤醒当前线程,或者超时唤醒

}

if (ms == 0) {

SPI_STATISTICS_INCREMENT_FIELD(statm,

timedout);

SPI_STATISTICS_INCREMENT_FIELD(stats,

timedout);

dev_err(&msg->spi->dev,

"SPI transfer timed out\n");

msg->status = -ETIMEDOUT;

}

} else {

if (xfer->len)

dev_err(&msg->spi->dev,

"Bufferless transfer has length %u\n",

xfer->len);

}

trace_spi_transfer_stop(msg, xfer);

if (msg->status != -EINPROGRESS)

goto out;

if (xfer->delay_usecs)

udelay(xfer->delay_usecs);

if (xfer->cs_change) {

if (list_is_last(&xfer->transfer_list,

&msg->transfers)) {

keep_cs = true;

} else {

spi_set_cs(msg->spi, false);

udelay(10);

spi_set_cs(msg->spi, true);

}

}

msg->actual_length += xfer->len;    // 更新实际传输长度

}

out:

if (ret != 0 || !keep_cs)

spi_set_cs(msg->spi, false);

if (msg->status == -EINPROGRESS)

msg->status = ret;

if (msg->status && master->handle_err)

master->handle_err(master, msg);

spi_finalize_current_message(master); //结束当前消息

return ret;

}

注意,master->transter_one由实际spi主设备驱动实现,用来完成实际的传输协议(在后面SPI bitbang中解释)。

(3)数据传输(同步传输):int spi_sync(struct spi_device *spi, struct spi_message *message)

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

{

return __spi_sync(spi, message, 0);    // 同步数据传输

}

static int __spi_sync(struct spi_device *spi, struct spi_message *message,

int bus_locked)

{

DECLARE_COMPLETION_ONSTACK(done);

int status;

struct spi_master *master = spi->master;

unsigned long flags;

status = __spi_validate(spi, message);

if (status != 0)

return status;

message->complete = spi_complete;

message->context = &done;

message->spi = spi;

SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync);

SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);

if (!bus_locked)

mutex_lock(&master->bus_lock_mutex);

/* If we're not using the legacy transfer method then we will

* try to transfer in the calling context so special case.

* This code would be less tricky if we could remove the

* support for driver implemented message queues.

*/

if (master->transfer == spi_queued_transfer) {

spin_lock_irqsave(&master->bus_lock_spinlock, flags);

trace_spi_message_submit(message);

status = __spi_queued_transfer(spi, message, false);    // false表示将spi_message放进消息队列,但是不启动workqueue线程处理

spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);

} else {

status = spi_async_locked(spi, message);

}

if (!bus_locked)

mutex_unlock(&master->bus_lock_mutex);

if (status == 0) {

/* Push out the messages in the calling context if we

* can.

*/

if (master->transfer == spi_queued_transfer) {

SPI_STATISTICS_INCREMENT_FIELD(&master->statistics,

spi_sync_immediate);

SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,

spi_sync_immediate);

__spi_pump_messages(master, false);    // 在当前线程中取出消息队列中的消息,同步处理。

}

wait_for_completion(&done);

status = message->status;

}

message->context = NULL;

return status;

}

SPI master驱动分析:SPI bitbang

spi bitbang是软件模拟的spi主设备驱动。当硬件上没有spi总线主控设备时,可以在软件上模拟spi主控设备,通过gpio信号线同从设备通信。spi bitbang依赖于gpio模拟spi的四根信号线,所以bitbang相关的代码依赖spi-gpio驱动。直接看源码:

static struct platform_driver spi_gpio_driver = {

.driver = {

.name    = DRIVER_NAME,

.of_match_table = of_match_ptr(spi_gpio_dt_ids),

},

.probe        = spi_gpio_probe,    // spi-gpio探测函数

.remove        = spi_gpio_remove,

};

static int spi_gpio_probe(struct platform_device *pdev)

{

int                status;

struct spi_master        *master;

struct spi_gpio            *spi_gpio;

struct spi_gpio_platform_data    *pdata;

u16 master_flags = 0;

bool use_of = 0;

int num_devices;

status = spi_gpio_probe_dt(pdev);    // 从设备树配置中获取spi相关配置信息: MOSI,MISO,SCLK等gpio信息

if (status < 0)

return status;

if (status > 0)

use_of = 1;

pdata = dev_get_platdata(&pdev->dev);

#ifdef GENERIC_BITBANG

if (!pdata || (!use_of && !pdata->num_chipselect))

return -ENODEV;

#endif

if (use_of && !SPI_N_CHIPSEL)

num_devices = 1;

else

num_devices = SPI_N_CHIPSEL;

status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);    // 请求MOSI,MISO,SCLK等gpio信息

if (status < 0)

return status;

master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) +

(sizeof(unsigned long) * num_devices));    // 分配spi_master结构对象

if (!master) {

status = -ENOMEM;

goto gpio_free;

}

spi_gpio = spi_master_get_devdata(master);

platform_set_drvdata(pdev, spi_gpio);

spi_gpio->pdev = pdev;

if (pdata)

spi_gpio->pdata = *pdata;

master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);

master->flags = master_flags;

master->bus_num = pdev->id;

master->num_chipselect = num_devices;

master->setup = spi_gpio_setup;

master->cleanup = spi_gpio_cleanup;    // 设置setup和cleanup方法

#ifdef CONFIG_OF

master->dev.of_node = pdev->dev.of_node;

if (use_of) {

int i;

struct device_node *np = pdev->dev.of_node;

/*

* In DT environments, take the CS GPIO from the "cs-gpios"

* property of the node.

*/

if (!SPI_N_CHIPSEL)

spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT;

else

for (i = 0; i < SPI_N_CHIPSEL; i++) {

status = of_get_named_gpio(np, "cs-gpios", i);

if (status < 0) {

dev_err(&pdev->dev,

"invalid cs-gpios property\n");

goto gpio_free;

}

spi_gpio->cs_gpios[i] = status;

}

}

#endif

spi_gpio->bitbang.master = master;

spi_gpio->bitbang.chipselect = spi_gpio_chipselect;    // 设置spi bitbang的片选方法

// 初始化4种时钟模式下的传输方法

if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {

spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;

spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;

spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;

spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;

} else {

spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;

spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;

spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;

spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3;

}

spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;    //设置bitbang的setup_transfer函数

spi_gpio->bitbang.flags = SPI_CS_HIGH;    // 片选信号,高电平有效

status = spi_bitbang_start(&spi_gpio->bitbang);    // 启动bitbang,并注册master

if (status < 0) {

gpio_free:

if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)

gpio_free(SPI_MISO_GPIO);

if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)

gpio_free(SPI_MOSI_GPIO);

gpio_free(SPI_SCK_GPIO);

spi_master_put(master);

}

return status;

}

int spi_bitbang_start(struct spi_bitbang *bitbang)

{

struct spi_master *master = bitbang->master;

int ret;

if (!master || !bitbang->chipselect)

return -EINVAL;

mutex_init(&bitbang->lock);

if (!master->mode_bits)

master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;

if (master->transfer || master->transfer_one_message)

return -EINVAL;

master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;

master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;

master->transfer_one = spi_bitbang_transfer_one;

master->set_cs = spi_bitbang_set_cs;    // 设置bitbang硬件准备相关的函数,设置片选函数和spi_transfer传输函数

if (!bitbang->txrx_bufs) {

bitbang->use_dma = 0;

bitbang->txrx_bufs = spi_bitbang_bufs;

if (!master->setup) {

if (!bitbang->setup_transfer)

bitbang->setup_transfer =

spi_bitbang_setup_transfer;

master->setup = spi_bitbang_setup;    // 注册时调用bitbang_setup函数

master->cleanup = spi_bitbang_cleanup;

}

}

/* driver may get busy before register() returns, especially

* if someone registered boardinfo for devices

*/

ret = spi_register_master(spi_master_get(master));    // 注册bitbang master

if (ret)

spi_master_put(master);

return 0;

}

(1)注册master加载每个spi_devices时,调用master->setup,即spi_bitbang_setup:

int spi_bitbang_setup(struct spi_device *spi)

{

struct spi_bitbang_cs    *cs = spi->controller_state;

struct spi_bitbang    *bitbang;

bitbang = spi_master_get_devdata(spi->master);

if (!cs) {

cs = kzalloc(sizeof(*cs), GFP_KERNEL);

if (!cs)

return -ENOMEM;

spi->controller_state = cs;

}

/* per-word shift register access, in hardware or bitbanging */

cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];    // 根据每个spi_device设备支持的模式选择不同的传输函数

if (!cs->txrx_word)

return -EINVAL;

if (bitbang->setup_transfer) {

int retval = bitbang->setup_transfer(spi, NULL);    // NULL表示,调用spi_bitbang_setup_transfer()设置spi_device的默认传输函数和速率

if (retval < 0)

return retval;

}

dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);

/* NOTE we _need_ to call chipselect() early, ideally with adapter

* setup, unless the hardware defaults cooperate to avoid confusion

* between normal (active low) and inverted chipselects.

*/

/* deselect chip (low or high) */

mutex_lock(&bitbang->lock);

if (!bitbang->busy) {

bitbang->chipselect(spi, BITBANG_CS_INACTIVE);    // 调用spi_gpio_chipselect()

ndelay(cs->nsecs);

}

mutex_unlock(&bitbang->lock);

return 0;

}

int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)

{

struct spi_bitbang_cs    *cs = spi->controller_state;

u8            bits_per_word;

u32            hz;

if (t) {

bits_per_word = t->bits_per_word;

hz = t->speed_hz;

} else {

bits_per_word = 0;

hz = 0;

}

/* spi_transfer level calls that work per-word */

if (!bits_per_word)

bits_per_word = spi->bits_per_word;

// 设置spi_device各位宽传输函数

if (bits_per_word <= 8)

cs->txrx_bufs = bitbang_txrx_8;

else if (bits_per_word <= 16)

cs->txrx_bufs = bitbang_txrx_16;

else if (bits_per_word <= 32)

cs->txrx_bufs = bitbang_txrx_32;

else

return -EINVAL;

/* nsecs = (clock period)/2 */

// 设置spi_device的传输速率

if (!hz)

hz = spi->max_speed_hz;

if (hz) {

cs->nsecs = (1000000000/2) / hz;

if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))

return -EINVAL;

}

return 0;

}

static void spi_gpio_chipselect(struct spi_device *spi, int is_active)

{

struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);

unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];

/* set initial clock polarity */

if (is_active)

setsck(spi, spi->mode & SPI_CPOL);

if (cs != SPI_GPIO_NO_CHIPSELECT) {

/* SPI is normally active-low */

gpio_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);    // 设置片选信号

}

}

(2)数据传输过程到master->transfer_one,即调用spi_bitbang_transfer_one:

static int spi_bitbang_transfer_one(struct spi_master *master,

struct spi_device *spi,

struct spi_transfer *transfer)

{

struct spi_bitbang *bitbang = spi_master_get_devdata(master);

int status = 0;

if (bitbang->setup_transfer) {

status = bitbang->setup_transfer(spi, transfer);    // 先设置spi的传输函数和传输速率

if (status < 0)

goto out;

}

if (transfer->len)

status = bitbang->txrx_bufs(spi, transfer);    // 调用实际的传输函数,即spi_bitbang_bufs

if (status == transfer->len)

status = 0;

else if (status >= 0)

status = -EREMOTEIO;

out:

spi_finalize_current_transfer(master);

return status;

}

static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)

{

struct spi_bitbang_cs    *cs = spi->controller_state;

unsigned        nsecs = cs->nsecs;

return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);    // 根据spi_device的片选传输字长选取不同的传输函数

}

以8bit传输函数为例:

static unsigned bitbang_txrx_8(

struct spi_device    *spi,

u32            (*txrx_word)(struct spi_device *spi,

unsigned nsecs,

u32 word, u8 bits),

unsigned        ns,

struct spi_transfer    *t

) {

unsigned        bits = t->bits_per_word;

unsigned        count = t->len;

const u8        *tx = t->tx_buf;

u8            *rx = t->rx_buf;

while (likely(count > 0)) {

u8        word = 0;

if (tx)

word = *tx++;

word = txrx_word(spi, ns, word, bits);    // 调用实际传输函数spi_gpio_txrx_word_modex

if (rx)

*rx++ = word;

count -= 1;

}

return t->len - count;

}

以spi_gpio_txrx_word_mode0为例,

static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,

unsigned nsecs, u32 word, u8 bits)

{

return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);    // 调用bitbang模拟收发函数

}

// 软件模拟SCLK,MISO和MOSI信号实现数据收发

static inline u32

bitbang_txrx_be_cpha0(struct spi_device *spi,

unsigned nsecs, unsigned cpol, unsigned flags,

u32 word, u8 bits)

{

/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */

u32 oldbit = (!(word & (1<

/* clock starts at inactive polarity */

for (word <<= (32 - bits); likely(bits); bits--) {

/* setup MSB (to slave) on trailing edge */

if ((flags & SPI_MASTER_NO_TX) == 0) {

if ((word & (1 << 31)) != oldbit) {

setmosi(spi, word & (1 << 31));

oldbit = word & (1 << 31);

}

}

spidelay(nsecs);    /* T(setup) */

setsck(spi, !cpol);

spidelay(nsecs);

/* sample MSB (from slave) on leading edge */

word <<= 1;

if ((flags & SPI_MASTER_NO_RX) == 0)

word |= getmiso(spi);

setsck(spi, cpol);

}

return word;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值