/**
* struct spi_device - Controller side proxy for an SPI slave device
* @dev: Driver model representation of the device.
* @controller: SPI controller used with the device.
* @master: Copy of controller, for backwards compatibility.
* @max_speed_hz: Maximum clock rate to be used with this chip
* (on this board); may be changed by the device's driver.
* The spi_transfer.speed_hz can override this for each transfer.
* @chip_select: Chipselect, distinguishing chips handled by @controller.
* @mode: The spi mode defines how data is clocked out and in.
* This may be changed by the device's driver.
* The "active low" default for chipselect mode can be overridden
* (by specifying SPI_CS_HIGH) as can the "MSB first" default for
* each word in a transfer (by specifying SPI_LSB_FIRST).
* @bits_per_word: Data transfers involve one or more words; word sizes
* like eight or 12 bits are common. In-memory wordsizes are
* powers of two bytes (e.g. 20 bit samples use 32 bits).
* This may be changed by the device's driver, or left at the
* default (0) indicating protocol words are eight bit bytes.
* The spi_transfer.bits_per_word can override this for each transfer.
* @irq: Negative, or the number passed to request_irq() to receive
* interrupts from this device.
* @controller_state: Controller's runtime state
* @controller_data: Board-specific definitions for controller, such as
* FIFO initialization parameters; from board_info.controller_data
* @modalias: Name of the driver to use with this device, or an alias
* for that name. This appears in the sysfs "modalias" attribute
* for driver coldplugging, and in uevents used for hotplugging
* @cs_gpio: gpio number of the chipselect line (optional, -ENOENT when
* not using a GPIO line)
*
* @statistics: statistics for the spi_device
*
* A @spi_device is used to interchange data between an SPI slave
* (usually a discrete chip) and CPU memory.
*
* In @dev, the platform_data is used to hold information about this
* device that's meaningful to the device's protocol driver, but not
* to its controller. One example might be an identifier for a chip
* variant with slightly different functionality; another might be
* information about how this particular board wires the chip's pins.
*/
struct spi_device {
struct device dev;
struct spi_controller *controller;
struct spi_controller *master; /* compatibility layer */
u32 max_speed_hz; //该设备能支持的SPI设备的最大时钟
u8 chip_select; //在spi_master下的第几个设备,在spi_master中有一个cs_gpio数组,里面存放了各个spi设备的片选引脚,
//spi_device的片选引脚就是:cs_gpios[spi_device.chip_select]
u8 bits_per_word; //每个基本的SPI传输涉及多少位,在使用spi控制器时,一般往寄存器里写入数据,SPI控制器会一位一位地发送出去。
//一个寄存器是32位,通常叫word。寄存器里有多少位会被发送出去,这取决于bits_per_word。
//扩展:bits_per_word可以大于32位,这适用于DMA突发模式
u16 mode;
#define SPI_CPHA 0x01 /* clock phase */ //采样周期,第一个周期还是第二个周期
#define SPI_CPOL 0x02 /* clock polarity */ //平时的时钟极性
#define SPI_MODE_0 (0|0) /* (original MicroWire) */ //组合起来有四种,SCK平时为低电平,第1个周期采样
#define SPI_MODE_1 (0|SPI_CPHA) //SCK为低,第2个周期采样
#define SPI_MODE_2 (SPI_CPOL|0) //SCK为高电平,第1个周期采样
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) //SCK平时为高电平,第2个周期采样
#define SPI_CS_HIGH 0x04 /* chipselect active high? */ //引脚信号高电平有效
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ //一般来说都是MSB,高位先传输。这个表示低位先传输。有些SPI设备并不支持低位传输
#define SPI_3WIRE 0x10 /* SI/SO signals shared */ //SDO、SDI共用一条线
#define SPI_LOOP 0x20 /* loopback mode */ //回环模式,SDO、SDI连接在一起
#define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */ //只有一个spi设备,没有片选,也不需要
#define SPI_READY 0x80 /* slave pulls low to pause */ //spi信号可以拉低信号,表示暂停、表示未就绪
#define SPI_TX_DUAL 0x100 /* transmit with 2 wires */ //发送数据时有2条信号线
#define SPI_TX_QUAD 0x200 /* transmit with 4 wires */ //发送数据时有4条信号线
#define SPI_RX_DUAL 0x400 /* receive with 2 wires */ //接收数据时有2条信号线
#define SPI_RX_QUAD 0x800 /* receive with 4 wires */ //接收数据时有4条信号线
int irq;
void *controller_state;
void *controller_data;
char modalias[SPI_NAME_SIZE];
int cs_gpio; /* chip select gpio */ //可选项,也可以把spi_device的片选引脚记录在这里
/* 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
* - ...
*/
};
对于SPI master,就是SPI控制器,它下面可以连接多个SPI设备。
在设备树里,使用一个节点来表示SPI Master,使用子节点来表示挂在下面的SPI设备
必须的属性:
在对应的SPI Master设备树节点下,每一个节点都对应一个SPI设备,
这些SPI Device必选的属性如下:
spi@f00 { //表示一个spi_master
#address-cells = <1>; //reg属性需要多上长度描述
#size-cells = <0>; //必须是0
compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi"; //用于匹配spi_master驱动程序
reg = <0xf00 0x20>;
interrupts = <2 13 0 2 14 0>;
interrupt-parent = <&mpc5200_pic>;
//cs-gpios = <&gpio1 0 0>, <0>, <&gpio1 1 0>, <&gpio1 2 0>; 可以定义使用多少个片选引脚
ethernet-switch@0 { //表示挂载在spi下的设备0
compatible = "micrel,ks8995m";
spi-max-frequency = <1000000>; //spi的最大频率
reg = <0>;
};
codec@1 { //表示挂载在spi下的设备1
compatible = "ti,tlv320aic26";
spi-max-frequency = <100000>;
reg = <1>;
};
};
在设备树里,会有一个节点用来表示SPI控制器
在这个SPI控制器下面,连接有哪些SPI设备?会在设备树里使用子节点来描述SPI设备
spi3{
compatible = "spi-gpio";
status = "okay";
gpio-sck = <&gpio0 5 GPIO_ACTIVE_LOW>;
gpio-mosi = <&gpio1 15 GPIO_ACTIVE_LOW>;
cs-gpio = <&gpio0 27 GPIO_ACTIVE_LOW>;
num-chipselects = <1>;
#address-cells = <1>;
#size-cells = <0>;
gpio_spi: gpio_spi@0 {
compatible = "fairchild,74hc595";
gpio-controller;
#gpio-cells = <2>;
reg = <0>;
registers-number = <1>;
spi-max-frequency = <100000>;
};
};
驱动中的调用:
//driver/spi/spi-gpio.c
//在compatible="spi-gpio"匹配后,调用probe函数
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;
status = spi_gpio_probe_dt(pdev);
//...
pdata = dev_get_platdata(&pdev->dev);
//分配一个spi_master
master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio));
//...
spi_gpio = spi_master_get_devdata(master);
spi_gpio->cs_gpios = devm_kcalloc(&pdev->dev,
pdata->num_chipselect,
sizeof(*spi_gpio->cs_gpios),
GFP_KERNEL);
//....
status = spi_gpio_request(&pdev->dev, spi_gpio,
pdata->num_chipselect, &master_flags);
//...设置spi_master
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->mode_bits = SPI_3WIRE | SPI_CPHA | SPI_CPOL;
master->flags = master_flags;
master->bus_num = pdev->id;
/* The master needs to think there is a chipselect even if not connected */
master->num_chipselect = spi_gpio->has_cs ? pdata->num_chipselect : 1;
master->setup = spi_gpio_setup;
master->cleanup = spi_gpio_cleanup;
#ifdef CONFIG_OF
master->dev.of_node = pdev->dev.of_node;
#endif
spi_gpio->bitbang.master = master;
spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction;
if ((master_flags & SPI_MASTER_NO_TX) == 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;
spi_gpio->bitbang.flags = SPI_CS_HIGH;
//这里注册spi_master
status = spi_bitbang_start(&spi_gpio->bitbang);
if (status)
spi_master_put(master);
return status;
}
int spi_bitbang_start(struct spi_bitbang *bitbang)
{
struct spi_master *master = bitbang->master;
int ret;
//....注册spi_master
ret = spi_register_master(spi_master_get(master));
//...
return 0;
}
arch/arm/boot/dts/imx6ull.dtsi
ecspi3: ecspi@02010000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6ul-ecspi","fsl,imx5l-ecspi";
reg = <0x02010000> <0x4000>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_ECSPI3>,
<&clks IMX6UL_CLK_ECSPI3>;
clock-names = "jpg", "per";
dmas = <&sdma 7 7 1>, <&sdma 8 7 2>;
dma-names = "rx", "tx";
status = "disabled";
};
arch/arm/boot/dts/100ask_imx6ull-14x14.dts
&ecspi3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi3>;
cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
status = "okay";
spidev: icm20608@0 {
compatible = "invensense,icm20608";
interrupt-parent = <&gpio1>;
interrupts = <1 1>;
spi-max-frequency = <8000000>;
reg = <0>;
};
};
arch/arm/boot/dts/stm32mp151.dtsi
spi5: spi@44009000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "st,stm32h7-spi";
reg = <0x44009000 0x400>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc SPI5_K>;
resets = <&rcc SPI5_R>;
dmas = <&dmamux1 85 0x400 0x01>,
<&dmamux1 86 0x400 0x01>;
dma-names = "rx", "tx";
power-domains = <&pd_core>;
status = "disabled";
};
arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts
&spi5 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi5_pins_a>;
pinctrl-1 = <&spi5_sleep_pins_a>;
status = "okay";
cs-gpios = <&gpioh 5 GPIO_ACTIVE_LOW>;
spidev: icm20608@0 {
compatible = "invensense,icm20608";
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpioz>;
spi-max-frequency = <8000000>;
reg = <0>;
};
};
在注册spi_master时,调用spi_register_controller
int spi_register_controller(struct spi_controller *ctlr)
{
//...注册spi_master
if (!spi_controller_is_slave(ctlr)) {
status = of_spi_register_master(ctlr);
if (status)
return status;
}
//...注册完master注册device
/* Register devices from the device tree and ACPI */
of_register_spi_devices(ctlr);
acpi_register_spi_devices(ctlr);
done:
return status;
}
内核源码:drivers/spi/spi.c
static int of_spi_register_master(struct spi_controller *ctlr)
{
int nb, i, *cs;
struct device_node *np = ctlr->dev.of_node;
if (!np)
return 0;
nb = of_gpio_named_count(np, "cs-gpios"); //解析片选引脚节点
ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect);
/* Return error only for an incorrectly formed cs-gpios property */
if (nb == 0 || nb == -ENOENT)
return 0;
else if (nb < 0)
return nb;
cs = devm_kcalloc(&ctlr->dev, ctlr->num_chipselect, sizeof(int),
GFP_KERNEL);
ctlr->cs_gpios = cs; //把片选引脚信息记录在这里
if (!ctlr->cs_gpios)
return -ENOMEM;
for (i = 0; i < ctlr->num_chipselect; i++)
cs[i] = -ENOENT;
for (i = 0; i < nb; i++)
cs[i] = of_get_named_gpio(np, "cs-gpios", i);
return 0;
}
//解析每个spi_device
static void of_register_spi_devices(struct spi_controller *ctlr)
{
//...
for_each_available_child_of_node(ctlr->dev.of_node, nc) {
if (of_node_test_and_set_flag(nc, OF_POPULATED))
continue;
spi = of_register_spi_device(ctlr, nc); //对每个节点进行解析
//...
}
}
static struct spi_device *
of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
{
struct spi_device *spi;
int rc;
/* Alloc an spi_device */
spi = spi_alloc_device(ctlr);
//...
/* Select device driver */
rc = of_modalias_node(nc, spi->modalias,
sizeof(spi->modalias));
//...
rc = of_spi_parse_dt(ctlr, spi, nc); //这里解析spi_device节点的所有属性
//...
/* 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);
//...
return spi;
//...
}