要为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 }
.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 /* 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 }
接下来添加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 }