转载于 : http://blog.rongpmcu.com/linuxqu-dong-ji-chu-xi-lie-linux-spiqu-dong-kuang-jia-fen-xi-xu/
inux驱动基础系列--linux spi驱动框架分析(续)
spi设备树相关信息
如之前的文章里所述,控制器的device和spi device都是通过platform_add_device
和spi_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 < 0
(spi_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,否则反之。