要为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
-
-
-
-
-
-
-
-
- 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
我在这里加了两个设备节点因为我有两个类型相同的设备,所以公用的同一个驱动,不同之处在于它们的片选不同,一个是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
- 1680 of_register_spi_devices(master);
- 1681 acpi_register_spi_devices(master);
of_register_spi_devices(master);会注册所有的设备,它会根据设备树填充一个struct spi_device 结构体代表一个设备:
- 852
- 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
- 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
- 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,修改如下:
- 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
-
-
- 397
- 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
- 112
- 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中直接添加,再此忽略了哦,没时间去搞了.........
欢迎关注并加入物联网行业联盟,积累行业人脉和资源。