为MT7688 SPI添加N个SPI接口

驱动开发 同时被 2 个专栏收录
6 篇文章 0 订阅
3 篇文章 0 订阅

要为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

SPI work.jpg

我在这里加了两个设备节点因为我有两个类型相同的设备,所以公用的同一个驱动,不同之处在于它们的片选不同,一个是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中直接添加,再此忽略了哦,没时间去搞了.........



  • 5
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值