DeviceTree

spi0: spi@f0020000 {
	compatible = "snps,designware-spi";
	#address-cells = <1>;
	#size-cells = <0>;
	reg = <0xf0020000 0x100>;
	interrupts = <40 1>;
        pinctrl-0 = <&spi2_default>;
        pinctrl-1 = <&spi2_sleep>;
        pinctrl-names = "default", "sleep";
	fifo-depth = <32>; // 必须参数
	clocks = <&sysclk>; // 和下面clock-frequency二选一,优先从&sysclk中获取clock-frequency
	clock-frequency = <200000000>;
        cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; // 用gpio代替cs,可选参数
	status = "disabled";

	slow@0 { // spi设备
		compatible = "test-spi-loopback-slow";
		reg = <0>;
		spi-max-frequency = <500000>;
	};
	fast@0 { // @x 是指第几根片选
		compatible = "test-spi-loopback-fast";
		reg = <0>; // 0表示spi master controller,1表示spi slave controller
		spi-max-frequency = <1000000>;
	};
};

Consumer(应用层和其他driver如何调用spi接口)

方法1:

设备树API

参考zephyr/tests/drivers/spi/spi_loopback/src/spi.c

// 获取spi device node id
#define SPI_DEV	DT_COMPAT_GET_ANY_STATUS_OKAY(test_spi_loopback) //这里注意是spi device的compatible,不是bus

// 定义spi controller属性
#define SPI_OP(frame_size) SPI_OP_MODE_MASTER | SPI_MODE_CPOL | MODE_LOOP | \
	       SPI_MODE_CPHA | SPI_WORD_SET(frame_size) | SPI_LINES_SINGLE

//传入spi device node id和config,通过SPI_DT_SPEC_GET宏从设备树获得spi_dt_spec结构体
struct spi_dt_spec {
	const struct device *bus;
	struct spi_config config;
};

#define SPI_DT_SPEC_GET(node_id, operation_, delay_)		     \
	{							     \
		.bus = DEVICE_DT_GET(DT_BUS(node_id)),		     \
		.config = SPI_CONFIG_DT(node_id, operation_, delay_) \
	}

static struct spi_dt_spec spi = SPI_DT_SPEC_GET(SPI_DEV, SPI_OP(FRAME_SIZE), 0);

接着需要初始化spi_buf_set *tx_bufsspi_buf_set *rx_bufs

const struct spi_buf tx_bufs[] = {
	{
		.buf = buffer_tx,
		.len = BUF_SIZE,
	},
};
const struct spi_buf rx_bufs[] = {
	{
		.buf = buffer_rx,
		.len = BUF_SIZE,
	},
};
const struct spi_buf_set tx = {
	.buffers = tx_bufs,
	.count = ARRAY_SIZE(tx_bufs)
};
const struct spi_buf_set rx = {
	.buffers = rx_bufs,
	.count = ARRAY_SIZE(rx_bufs)
};

最后可以调用spi_transceive_dt进行spi传输了。

static inline int spi_transceive_dt(const struct spi_dt_spec *spec,
				    const struct spi_buf_set *tx_bufs,
				    const struct spi_buf_set *rx_bufs)

结束spi传输后需要调用spi_release_dt来做收尾工作。

方法2:
直接调用spi_transceive,这时候dev, config参数需要我们自己准备了。

不过这两个函数是`__syscall`,而上面devicetree的API不是,是否意味着user space只能调用下面这两个函数?

__syscall int spi_transceive(const struct device *dev,
			     const struct spi_config *config,
			     const struct spi_buf_set *tx_bufs,
			     const struct spi_buf_set *rx_bufs);

__syscall int spi_release(const struct device *dev,
			  const struct spi_config *config);

Provider(SSI driver)

SSI Master Flow:

// spi_dw_init
write_imr(info, DW_SPI_IMR_MASK); // SSI_IMR(0x2C) write 0
clear_bit_ssienr(info); // SSI_ENR(0x08) write 0

// spi_dw_configure
write_ctrlr0(info, ctrlr0); // SSI_CTRLR0(0x00) 写入上层指定的config,包括bit0-3,6,7,11。
write_baudr(info, SPI_DW_CLK_DIVIDER(info->clock_frequency, config->frequency)) // SSI_BAUDR(0x14) baud rate
write_ser(info, 1 << config->slave); // SSI_SER(0x10) write 0

// transceive
write_ctrlr1(info, reg_data); or write_ctrlr1(info, 0); // SSI_CTRLR1(0x04) rx mode write NDF
write_ctrlr0(info, reg_data); // SSI_CTRLR0(0x00) update TMOD bit8~9
spi_dw_update_txftlr(info, spi); // SSI_TXFTLR(0x18) Set Tx threshold is half of the fifo
write_rxftlr(info, reg_data); // SSI_RXFTLR(0x1C) Ser Rx threshold, default is (info->fifo_depth * 5) / 8
write_imr(info, reg_data); // SSI_IMR(0x2C) enable interrupt
spi_context_cs_control(&spi->ctx, true); // cs toggle low
set_bit_ssienr(info); // SSI_ENR(0x08) enable controller

// spi_dw_isr
// rx interrupt -> pull_data
read_rxflr(info); // SSI_RXFLR(0x24) number of valid data
read_dr(info);    // SSI_DR(0x60) read data out
// tx interrupt -> push_data
read_txflr(info) // SSI_RXFLR(0x20) number of valid data
write_dr(info, data); // SSI_DR(0x60) write data in

clear_interrupts(info); // SSI_ICR(0x48) clear interrupt
test_bit_sr_busy(info); // SSI_SR(0x28) bit0 wait busy
write_imr(info, DW_SPI_IMR_MASK); // SSI_IMR(0x2C) disable interrupt
clear_bit_ssienr(info); // SSI_ENR(0x08) write 0
spi_context_cs_control(&spi->ctx, false); // cs toggle high

CONFIG_SPI_STATS开关

看看打开这个对debug有没有帮助