为MT7688 SPI添加N个SPI接口

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

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

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

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

[csharp]  view plain  copy
  1.      palmbus@10000000 {  
  2.  68                 spi@b00 {  
  3.  69                         status = "okay";  
  4.  70   
  5.  71                         pinctrl-names = "default";  
  6.  72   
  7.  73   
  8.  74                         pinctrl-0 = <&spi_pins>, <&spi_cs1_pins>;  
  9.  75   
  10.  76                         m25p80@0 {  
  11.  77                                 #address-cells = <1>;  
  12.  78                                 #size-cells = <1>;  
  13.  79                                 compatible = "w25q128";  
  14.  80                                 reg = <0 0>;  
  15.  81                                 linux,modalias = "m25p80""w25q128";  
  16.  82                                 spi-max-frequency = <40000000>;  
  17.  83                                 m25p,chunked-io = <31>;  
  18.  84   
  19.  85                                 partition@0 {  
  20.  86                                         label = "u-boot";  
  21.  87                                         reg = <0x0 0x30000>;  
  22.  88                                         read-only;  
  23.  89                                 };  
  24.  90   
  25.  91                                 partition@30000 {  
  26.  92                                         label = "u-boot-env";  
  27.  93                                         reg = <0x30000 0x10000>;  
  28.  94                                 };  
  29.  95   
  30.  96                                 factory: partition@40000 {  
  31.  97                                         label = "factory";  
  32.  98                                         reg = <0x40000 0x10000>;  
  33.  99                                         read-only;  
  34. 100                                 };  
  35. 101   
  36. 102                                 partition@50000 {  
  37. 103                                         label = "firmware";  
  38. 104                                         reg = <0x50000 0x0fb0000>;  
  39. 105                                 };  
  40. 106                         };  
  41. 107 /* 
  42. 108                         spidev@1 { 
  43. 109                                 #address-cells = <1>; 
  44. 110                                 #size-cells = <1>; 
  45. 111                                 compatible = "spidev"; 
  46. 112                                 reg = <1 0>; 
  47. 113                                 spi-max-frequency = <40000000>; 
  48. 114                         }; 
  49. 115 */  
  50. 116                         bpeer@1 {  
  51. 117                                 #address-cells = <1>;  
  52. 118                                 #size-cells = <1>;  
  53. 119                                 compatible = "bpeer,tft0";  
  54. 120                                 reg= <1 0>;  
  55.                                     spi-max-frequency = <60000000>;  
  56. 122                                 spi-cpol = <1>;  
  57. 123                                 spi-cpha = <1>;  
  58. 124                         };  
  59.                             bpeer@2 {    
  60.                                     #address-cells = <1>;     
  61.                                     #size-cells = <1>;         
  62.                                     compatible = "bpeer,tft0";  
  63.                                     reg= <2 0>;       
  64.                                     spi-max-frequency = <60000000>;        
  65.                                     spi-cpha = <1>;                                      
  66.                                     spi-cpol = <1>;  
  67.                             };  
  68. 125                 }          
  69.                                      


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

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

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

[csharp]  view plain  copy
  1. 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)  函数的结尾,注册了控制器驱动到系统,

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

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

[csharp]  view plain  copy
  1. 852                 /* Device address */  
  2. 853                 prop = of_get_property(nc, "reg", &len);  
  3. 854                 if (!prop || len < sizeof(*prop)) {  
  4. 855                         dev_err(&master->dev, "%s has no 'reg' property\n",  
  5. 856                                 nc->full_name);  
  6. 857                         spi_dev_put(spi);  
  7. 858                         continue;  
  8. 859                 }  
  9. 860                 spi->chip_select = be32_to_cpup(prop);  
  10. 861   
  11. 862                 /* Mode (clock phase/polarity/etc.) */  
  12. 863                 if (of_find_property(nc, "spi-cpha", NULL))  
  13. 864                         spi->mode |= SPI_CPHA;  
  14. 865                 if (of_find_property(nc, "spi-cpol", NULL))  
  15. 866                         spi->mode |= SPI_CPOL;  
  16. 867                 if (of_find_property(nc, "spi-cs-high", NULL))  
  17. 868                         spi->mode |= SPI_CS_HIGH;  
  18. 869                 if (of_find_property(nc, "spi-3wire", NULL))  
  19. 870                         spi->mode |= SPI_3WIRE;  
  20. 871   
  21. 872                 /* Device speed */  
  22. 873                 prop = of_get_property(nc, "spi-max-frequency", &len);  
  23. 874                 if (!prop || len < sizeof(*prop)) {  
  24. 875                         dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n",  
  25. 876                                 nc->full_name);  
  26. 877                         spi_dev_put(spi);  
  27. 878                         continue;  
  28. 879                 }  
  29. 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,修改如下:

[csharp]  view plain  copy
  1. static int mt7621_spi_setup(struct spi_device *spi)  
  2. 382 {  
  3. 383         struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);  
  4. 384         int status = 0;  
  5. 385         if ((spi->max_speed_hz == 0) ||  
  6. 386                 (spi->max_speed_hz > (rs->sys_freq / 2)))  
  7. 387                 spi->max_speed_hz = (rs->sys_freq / 2);  
  8. 388   
  9. 389         if (spi->max_speed_hz < (rs->sys_freq / 4097)) {  
  10. 390                 dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n",  
  11. 391                         spi->max_speed_hz);  
  12. 392                 return -EINVAL;  
  13. 393         }  
  14. 394 /************************************************************** 
  15. 395 *       Modefiy Liuchen on here 
  16. 396 ***************************************************************/  
  17. 397 //      int cs = spi->cs_gpio;  
  18. 398         int cs = spi->chip_select;  
  19. 399         if( cs >= 2 )  
  20. 400         {  
  21. 401                 status = gpio_request( 42, dev_name( &spi->dev ) );  
  22. 402                 dev_info( spi->master->dev.parent,"in %s,cs_gpio =%d, status =%d\n", __func__, cs, status );  
  23. 403                 if( status ) return status;  
  24. 404                 status = gpio_direction_output( 42, 1);  
  25. 405         }  
  26. 406         return status;  
  27. 407 }  

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

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

[csharp]  view plain  copy
  1. 102 static void mt7621_spi_set_cs(struct spi_device *spi, int enable)  
  2. 103 {  
  3. 104         struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);  
  4. 105         int cs = spi->chip_select;  
  5. 106         u32 polar = 0;  
  6. 107   
  7. 108         mt7621_spi_reset(rs, cs);  
  8. 109         if(cs == 2)  
  9. 110         {  
  10. 111                 //printk("enable = %d\n",enable);  
  11. 112                 //gpio_set_value_cansleep( 42, enable );  
  12. 113                 gpio_set_value_cansleep( 42, (spi->mode&SPI_CS_HIGH)?enable: !enable );  
  13. 114         }else  
  14. 115         {  
  15. 116                 if (enable)  
  16. 117                         polar = BIT(cs);  
  17. 118                 mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);  
  18. 119         }  
  19. 120 }  

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

欢迎关注并加入物联网行业联盟,积累行业人脉和资源。



你可能感兴趣的:(为MT7688 SPI添加N个SPI接口)