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传输模式。