AM335x利用设备树dts挂载spidev0.0、spidev1.0或spidev2.0驱动

1、前言

最近使用preempt rt linux内核,没有spi驱动。之前写的spi驱动主要是通过修改 arch/arm/mach-omap2/board-am335xevm.c文件实现的,但是这个rt内核没有board-am335xevm.c文件。研究了好久,才发现它是利用设备树来配置或挂载驱动的。

本人对驱动还不甚了解,将探索过程记录如下,错误之处请各位大牛斧正!

2、设备树文件dtb和dtsi

板子的设备树文件后缀一般为dtb,其通用部分的一些设备可用dtsi文件描述,即dtb包含dtsi。

dtb和dtsi文件一般位于内核的arch/arm/boot/dts目录下。下图是我用的开发板的dts文件夹内容,主要修改的是板子对应的tq335x-coreb-v2-can.dtb,以及芯片设备树文件am33xx.dtsi。

AM335x利用设备树dts挂载spidev0.0、spidev1.0或spidev2.0驱动

3、添加spi设备

am33xx默认已经包含了spi0和spi1节点,如果只生成spidev0.0或spidev1.0,此步骤可以跳过。

如果需要生成spidev2.0驱动,需要在am33xx.dtsi再添加1个spi设备。

打开am33xx.dtsi,在aliases {中添加:

spi2 = &spi2;

如图:

AM335x利用设备树dts挂载spidev0.0、spidev1.0或spidev2.0驱动

因为实际使用的是spi1引脚,但又要生成spidev2.0,所以要将spi的地址修改为没有用到的其它设备地址(最好不要用自定义的地址,可能会导致kernel不能启动)。因为我板子上的i2c2没有用(dts文件中没有配置),所以将它的配置给spi0好了。

/*@后的地址是i2c2的地址*/
spi1: spi@4819c000 {
			compatible = "ti,omap4-mcspi";
			#address-cells = <1>;
			#size-cells = <0>;
			ti,hwmods = "i2c3";
			reg = <0x4819c000 0x1000>;
			interrupts = <30>;
			status = "disabled";
		};

然后将原来的spi1改为spi2:

spi2: spi@481a0000 {
			compatible = "ti,omap4-mcspi";
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <0x481a0000 0x400>;
			interrupts = <125>;
			ti,spi-num-cs = <2>;
			ti,hwmods = "spi1";
			dmas = <&edma 42 0
				&edma 43 0
				&edma 44 0
				&edma 45 0>;
			dma-names = "tx0", "rx0", "tx1", "rx1";
			status = "disabled";
		};

4、修改dts文件

4.1 配置spi1引脚

因为实际用到spi1,所以要配置spi1引脚。

在tq335x-coreb-v2-can.dtb的spi0_pins: pinmux_spi0_pins {……}后面添加:

spi1_pins: pinmux_spi1_pins {
       		pinctrl-single,pins = <
			0x190 (PIN_INPUT_PULLUP | MUX_MODE3) /* spi1-sclk gpio3_14*/
			0x194 (PIN_INPUT_PULLUP | MUX_MODE3) /* spi1-do gpio3_15*/
			0x198 (PIN_INPUT_PULLUP | MUX_MODE3) /* spi1-di gpio3_16*/
			0x19c (PIN_INPUT_PULLUP | MUX_MODE3) /* spi1-cs0 gpio3_17*/
		>;
	};

4.2 挂载spidev0.0驱动

修改&spi0{}的内容,如下所示,重新编译内核后,应该可以看到spidev0.0驱动了。

&spi0 {
        status = "okay"; 
        pinctrl-names = "default";
        pinctrl-0 = <&spi0_pins>;
	    ti,pindir-d0-out-d1-in;
	    spidev@0 {				
		    compatible = "rohm,dh2228fv";
		    spi-max-frequency = <48000000>;		
		    reg = <0>;
        };
};

4.3 挂载spidev1.0驱动

同spi0一样,修改&spi1{}的内容,如下所示,重新编译内核后,应该可以看到spidev0.0驱动了。

&spi1 {
        status = "okay"; 
        pinctrl-names = "default";
        pinctrl-0 = <&spi1_pins>;
	    ti,pindir-d0-out-d1-in;
	    spidev@0 {				
		    compatible = "rohm,dh2228fv";
		    spi-max-frequency = <48000000>;		
		    reg = <0>;
        };
};

注:要使用spidev1.0,应跳过第3步骤,不用修改am33xx.dtsi文件。

4.4 挂载spidev2.0

同spi0一样,增加一个&spi2{},如下所示,重新编译内核后,应该可以看到spidev2.0驱动了。

&spi2 {
        status = "okay";             /*使能设备驱动*/
        pinctrl-names = "default";
        pinctrl-0 = <&spi1_pins>;
	    ti,pindir-d0-out-d1-in;
	    spidev@0 {
            /*compatible要与driver/spi/spidev.c的匹配一致*/			
		    compatible = "rohm,dh2228fv";
		    spi-max-frequency = <48000000>;	/*最大频率*/	
		    reg = <0>;                      /*片选信号*/
        }; 
};

AM335x利用设备树dts挂载spidev0.0、spidev1.0或spidev2.0驱动

 注:spi2使用的是spi1_pins。

5、spidev驱动配置小结

这里仅为个人经验总结,错误之处,望留言指出。

1)spi驱动一般显示为:spidevX.Y,X是spi节点数量,Y是子节点数量?(尝试配置了2个以上的节点,只能显示spidevX.0和spidevX.1);

2)spi节点数量在am33xx.dtsi中配置,地址(@后的数值)不能与其它spi节点一样,但可以与其它非spi的节点一样。最好使用其它不用节点的配置,不要自己随便写。

3)dtb文件中配置spi的子节点,关键点有2个:

        ①status必须设置为“okay”,表示使能。若为disable,则不会挂载;

        ②compatible要与driver/spi/spidev.c中static const struct of_device_id spidev_dt_ids[]的compatible的其中一个的完全一致,否则不能挂载设备。其内容如下:

static const struct of_device_id spidev_dt_ids[] = {
	{ .compatible = "rohm,dh2228fv" },
	{ .compatible = "lineartechnology,ltc2488" },
	{ .compatible = "ge,achc" },
	{ .compatible = "semtech,sx1301" },
	{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);

4)compatible匹配后,在spidev.c中会对驱动命名:

static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "spidev",

……

5)在spidev.c的static int spidev_probe(struct spi_device *spi)函数中,会根据spi设备节点数显示相应数值:

if (minor < N_SPI_MINORS) {
		struct device *dev;

		spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
		dev = device_create(spidev_class, &spi->dev, spidev->devt,
				    spidev, "spidev%d.%d",        //显示spidevX.Y
				    spi->master->bus_num, spi->chip_select);
		status = PTR_ERR_OR_ZERO(dev);
	} else {
		dev_dbg(&spi->dev, "no minor number available!\n");
		status = -ENODEV;
	}

上一篇:小白自制Linux开发板 七. USB驱动配置


下一篇:LCD移植种碰到的问题(am5729)