为MT7688 SPI添加N个SPI接口

时间:2022-10-10 23:24:38

要为SPI控制器中添加设备,以前的方法是在BSP文件中添加,这种方法过于麻烦,现在都使用设备树dts进行外设的描述.

要想让SPI控制器能够在加载驱动时添加你的设备,需要在dts中添加设备节点,如下:

MT7688的设备树在openwrt_widora-master/target/linux/ramips/dts/ 目录下面: Widora.dts

下面添加树节点到SPI驱动器节点下面:

     palmbus@10000000 {
68 spi@b00 {
69 status = "okay";
70
71 pinctrl-names = "default";
72
73
74 pinctrl-0 = <&spi_pins>, <&spi_cs1_pins>;
75
76 m25p80@0 {
77 #address-cells = <1>;
78 #size-cells = <1>;
79 compatible = "w25q128";
80 reg = <0 0>;
81 linux,modalias = "m25p80", "w25q128";
82 spi-max-frequency = <40000000>;
83 m25p,chunked-io = <31>;
84
85 partition@0 {
86 label = "u-boot";
87 reg = <0x0 0x30000>;
88 read-only;
89 };
90
91 partition@30000 {
92 label = "u-boot-env";
93 reg = <0x30000 0x10000>;
94 };
95
96 factory: partition@40000 {
97 label = "factory";
98 reg = <0x40000 0x10000>;
99 read-only;
100 };
101
102 partition@50000 {
103 label = "firmware";
104 reg = <0x50000 0x0fb0000>;
105 };
106 };
107 /*
108 spidev@1 {
109 #address-cells = <1>;
110 #size-cells = <1>;
111 compatible = "spidev";
112 reg = <1 0>;
113 spi-max-frequency = <40000000>;
114 };
115 */
116 bpeer@1 {
117 #address-cells = <1>;
118 #size-cells = <1>;
119 compatible = "bpeer,tft0";
120 reg= <1 0>;
  spi-max-frequency = <60000000>;
122                                 spi-cpol = <1>;
123                                 spi-cpha = <1>;
124                         };
bpeer@2 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "bpeer,tft0";
reg= <2 0>;
spi-max-frequency = <60000000>;
 spi-cpha = <1>;
spi-cpol = <1>;
};
125                 }




bpeer@1这个是我的设备节点, @前面名字可以根据自己的爱好随意命名,@后面的数字代表使用的是几号片选,我使用的是CS1,故为1, 

.compatible.这里的属性必须与驱动中的结构体: struct of_device_id 中的成员.compatible保持一致,

reg:此处与bpeer@1保持一致,本例子设为:<1 0>

spi-max-frequency :此处设置spi使用的最高频率.
spi-cpol,spi-cpha:SPI 的工作模式在此设置,本例所用的SPI工作模式为SPI_MODE_3

为MT7688 SPI添加N个SPI接口

我在这里加了两个设备节点因为我有两个类型相同的设备,所以公用的同一个驱动,不同之处在于它们的片选不同,一个是CS1,另一个是CS2,

这里估计就疑惑了吧,哪里来的CS2,别急,咱们这就加,

在这之前,要先了解一下设备树是如何被驱动使用的,众所周知,当控制器驱动注册到系统后,spi驱动会扫描控制器节点下面的子节点,也就是看有几个设备,

调用过程如下,首先在spi-mt7621.c的   static int mt7621_spi_probe(struct platform_device *pdev)  函数的结尾,注册了控制器驱动到系统,

472         spin_lock_irqsave(&rs->lock, flags);
473
474 device_reset(&pdev->dev);
475
476 mt7621_spi_reset(rs, 0);
477
478 return spi_register_master(master);
spi_register_master(master)函数会扫描有多少个设备
在spi/spi.c中有对此函数的定义,只关心咱们要分析的如下:

1675         list_for_each_entry(bi, &board_list, list)
1676 spi_match_master_to_boardinfo(master, &bi->board_info);
1677 mutex_unlock(&board_lock);
1678
1679 /* Register devices from the device tree and ACPI */
1680 of_register_spi_devices(master);
1681 acpi_register_spi_devices(master);
of_register_spi_devices(master);会注册所有的设备,它会根据设备树填充一个struct spi_device 结构体代表一个设备:

 852                 /* Device address */
853 prop = of_get_property(nc, "reg", &len);
854 if (!prop || len < sizeof(*prop)) {
855 dev_err(&master->dev, "%s has no 'reg' property\n",
856 nc->full_name);
857 spi_dev_put(spi);
858 continue;
859 }
860 spi->chip_select = be32_to_cpup(prop);
861
862 /* Mode (clock phase/polarity/etc.) */
863 if (of_find_property(nc, "spi-cpha", NULL))
864 spi->mode |= SPI_CPHA;
865 if (of_find_property(nc, "spi-cpol", NULL))
866 spi->mode |= SPI_CPOL;
867 if (of_find_property(nc, "spi-cs-high", NULL))
868 spi->mode |= SPI_CS_HIGH;
869 if (of_find_property(nc, "spi-3wire", NULL))
870 spi->mode |= SPI_3WIRE;
871
872 /* Device speed */
873 prop = of_get_property(nc, "spi-max-frequency", &len);
874 if (!prop || len < sizeof(*prop)) {
875 dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n",
876 nc->full_name);
877 spi_dev_put(spi);
878 continue;
879 }
880 spi->max_speed_hz = be32_to_cpup(prop);
设备树里面的它都会读到并且填充到struct spi_device 结构体中作为一个设备,注意第860行,它会读取reg属性字段,并填充到spi->chip_select中作为几号片选,这里就OK了

了解完这些后我们就利用一个GPIO来作为片选2来使用,

方法就是,在SPI控制器驱动的mt7621_spi_setup(struct spi_device *spi)中添加对GPIO的申请及配置,注意头文件中要包含#include<linux/gpio.h>,修改如下:

static int mt7621_spi_setup(struct spi_device *spi)
382 {
383 struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
384 int status = 0;
385 if ((spi->max_speed_hz == 0) ||
386 (spi->max_speed_hz > (rs->sys_freq / 2)))
387 spi->max_speed_hz = (rs->sys_freq / 2);
388
389 if (spi->max_speed_hz < (rs->sys_freq / 4097)) {
390 dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n",
391 spi->max_speed_hz);
392 return -EINVAL;
393 }
394 /**************************************************************
395 * Modefiy Liuchen on here
396 ***************************************************************/
397 // int cs = spi->cs_gpio;
398 int cs = spi->chip_select;
399 if( cs >= 2 )
400 {
401 status = gpio_request( 42, dev_name( &spi->dev ) );
402 dev_info( spi->master->dev.parent,"in %s,cs_gpio =%d, status =%d\n", __func__, cs, status );
403 if( status ) return status;
404 status = gpio_direction_output( 42, 1);
405 }
406 return status;
407 }

该函数会在static void of_register_spi_devices(struct spi_master *master)中被调用.

接下来添加GPIO作为CS来操作,修改另外一个函数 mt7621_spi_set_cs(struct spi_device *spi, int enable),此函数用来设置CS片选信号的拉低及拉高,修改如下:

102 static void mt7621_spi_set_cs(struct spi_device *spi, int enable)
103 {
104 struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
105 int cs = spi->chip_select;
106 u32 polar = 0;
107
108 mt7621_spi_reset(rs, cs);
109 if(cs == 2)
110 {
111 //printk("enable = %d\n",enable);
112 //gpio_set_value_cansleep( 42, enable );
113 gpio_set_value_cansleep( 42, (spi->mode&SPI_CS_HIGH)?enable: !enable );
114 }else
115 {
116 if (enable)
117 polar = BIT(cs);
118 mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
119 }
120 }

至此已经添加完毕,重新编译内核就0K了.还有一种方式是在dts中直接添加,再此忽略了哦,没时间去搞了.........