linux驱动基础系列--linux spi驱动框架分析(续)

时间:2022-12-16 16:47:15

前言

  这篇文章是对linux驱动基础系列--linux spi驱动框架分析的补充,主要是添加了最新的linux内核里设备树相关内容。

spi设备树相关信息

  如之前的文章里所述,控制器的device和spi device都是通过platform_add_devicespi_register_board_info注册到内核的驱动模式中的。而最新的方式是通过设备树来实现的。以arm为例,设备树文件一般存放在arch/arm/boot/dts下,不同的平台对应不同的文件,以xilinx zynq平台为例,最顶层的文件为zynq-zturn.dts,它包含了zynq-7000.dtsi。在zynq-7000.dtsi中,有两个节点用于对该soc的spi控制器的描述:

spi0: spi@e0006000 {
compatible = "xlnx,zynq-spi-r1p6";
reg = <0xe0006000 0x1000>;
status = "disabled";
interrupt-parent = <&intc>;
interrupts = <0 26 4>;
clocks = <&clkc 25>, <&clkc 34>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;
}; spi1: spi@e0007000 {
compatible = "xlnx,zynq-spi-r1p6";
reg = <0xe0007000 0x1000>;
status = "disabled";
interrupt-parent = <&intc>;
interrupts = <0 49 4>;
clocks = <&clkc 26>, <&clkc 35>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;
};

当我们项目中用到spi1控制器时,我们只需要在zynq-7000.dtsi中添加节点:

&spi1 {
status = "okay";
num-cs = <4>;
xxx@0 {
compatible = "yyy";
reg = <0x0>;
spi-max-frequency = <50000000>;
spi-cpol;
spi-cpha;
spi-cs-high;
};
};

然后在aliases节点中添加alias,如

aliases {
ethernet0 = &gem0;
serial0 = &uart1;
serial1 = &uart0;
spi1 = &spi1;
};

上面的status = "okay"用于使能该控制器,num-cs = <4>;用于指定最多支持4个片选,xxx可以修改为自己期望的名字,compatible字段的yyy需要替换成spi驱动对应的字串,spi-max-frequency用于设置支持的最大频率,reg用于设置该spi设备对应的片选,这个和硬件有关,spi-cpol和spi-cpha字段用于设置时钟极性和时钟相位,更加详细的意思参考Documentation/devicetree/bindings/spi/spi-bus.txt。spi-bus.txt里所描述的属性的解析位于drivers/spi/spi.c中,在控制器驱动调用spi_register_master注册的时候处理。下面以为什么需要在aliases中添加spi1=&spi1为例子说明下解析的过程。

spi_register_master中,如果检测到master->bus_num < 0spi_alloc_master分配的时候就设置为-1了)且存在设备节点,那么就用of_alias_get_id从alias节点中提取该spi节点对应的编号作为总线号,也就是说,上面的添加会导致该控制器对应的spi总线号为1了,如果不加,那么内核通过atomic_dec_return(&dyn_bus_id)自动分配一个。

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

最后再讲下spi-cs-high属性,在spi-bus.txt中描述如下:

- spi-cs-high     - (optional) Empty property indicating device requires
chip select active high

如果设置了该属性,那么在每次需要读写spi前,控制器的回调set_cs参数enable为true,读写spi完成后,控制器的回调set_cs参数enable为false,否则反之。

完!

2016年10月