zoukankan      html  css  js  c++  java
  • linux驱动基础系列--linux spi驱动框架分析(续)

    前言

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

  • 相关阅读:
    24. Swap Nodes in Pairs
    2. Add Two Numbers
    【设计模式】结构型模式
    【设计模式】创建型模式
    【设计模式】初识
    【自考总结】走过的弯路,都是你成长的旅途
    【VMware vSphere】再谈VMware vSphere
    评估网站性能的专业术语
    C/S与B/S之辩
    【VMware vSphere】Veeam备份
  • 原文地址:https://www.cnblogs.com/rongpmcu/p/7662804.html
Copyright © 2011-2022 走看看