首页 > 技术文章 > linux驱动基础系列--linux spi驱动框架分析(续)

rongpmcu 2017-10-14 10:17 原文

前言

  这篇文章是对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月

推荐阅读