前言
我的上一篇文章中谈到,如何使能mt7620的第二个spi接口.既然第二个spi接口已经开放成功,那么,可否接着添加第三个、第四个spi接口呢?熟悉mt7620硬件的朋友一定会第一时间站出来反对我:怎么可能!?mt7620总共才两个spi接口,怎么可能添加更多呢?除非在硬件上想办法.然而我总是善于将不可能变为可能^_^,今天我就要和大家分享一下,如何不改动任何硬件,通过修改驱动的方法,实现多个spi接口.注意,我这里实现的spi,并非用gpio口模拟的bitbang伪spi,而是基于硬件spi的真实接口.
背景知识
总所周知,mt7620有两个独立的硬件spi接口,且对应的片选cs为cs0与cs1.如果读者朋友对spi总线的通讯协议略懂的话,会发现:spi的通讯是按照message的方式来进行的,一次通讯过程是通过transfer_one_message的方法来实现.实际上是对spi硬件接口的分时复用.如果我们能够找到办法,扩充一下cs片选信号,且保留对spi硬件的分时复用,不就可以完美实现我们的目标了?那么问题来了:如何扩充cs片选?如何让spi硬件不产生冲突?具体如何实现?各位看官莫急,且听我慢慢道来.
实现过程
dts文件的奥秘
dts文件中有很多隐藏关卡(不要问我为神马知道这么多,因为我喜欢看驱动源码,嘿嘿^_^),通过简单的改动,就可以让spi凭空多出cs片选来.
[email protected] {
compatible = "ralink,rt5350-spi";
status = "okay";
cs-gpios = <0>, <0>, <&gpio3 0 1>;
...
};
怎么样?就这么简(REN)单(XING),就能为spi总线添加一个用gpio口线实现的片选cs2(这个处理过程,实际上是在spi.c中完成的,读者朋友花点时间看看这个文件便能豁然开朗).在进行下面的讲解之前,让我再啰嗦几句,cs-gpio前面的<0>,<0>表示使用系统默认的cs0,与cs1,而cs2则绑定到gpio72.接下来,我们就要对驱动进行相应的修改,使之能够配合我们新指定的cs.
修改spi-rt2880.c
添加头文件
由于要用到gpio口,所以需要在文件开头
#include <linux/gpio.h>
修改宏定义
让mt7620的第二个spi成为分时复用的硬件接口,修改如下:
// manfeel, try to add more cs pins(>2)
#define M(cs) (cs ? 1 : cs)
#define RAMIPS_SPI_STAT(cs) (0x00 + (M(cs) * RAMIPS_SPI_DEV_OFFSET))
#define RAMIPS_SPI_CFG(cs) (0x10 + (M(cs) * RAMIPS_SPI_DEV_OFFSET))
#define RAMIPS_SPI_CTL(cs) (0x14 + (M(cs) * RAMIPS_SPI_DEV_OFFSET))
#define RAMIPS_SPI_DATA(cs) (0x20 + (M(cs) * RAMIPS_SPI_DEV_OFFSET))
#define RAMIPS_SPI_FIFO_STAT(cs) (0x38 + (M(cs) * RAMIPS_SPI_DEV_OFFSET))
也就是说,当cs>=1的时候,第二个spi接口负责所有的通讯工作.
改动rt2880_spi_setup
static int rt2880_spi_setup(struct spi_device *spi)
{
struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
int status = 0;
if ((spi->max_speed_hz == 0) ||
(spi->max_speed_hz > (rs->sys_freq / 2)))
spi->max_speed_hz = (rs->sys_freq / 2);
if (spi->max_speed_hz < (rs->sys_freq / 128)) {
dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n",
spi->max_speed_hz);
return -EINVAL;
}
// manfeel, set cs_gpio
int cs = spi->cs_gpio;
if (cs >= 0) {
status = gpio_request(cs, dev_name(&spi->dev));
dev_info(spi->master->dev.parent, "in %s, cs_gpio = %d, status = %d\n",__func__, cs, status);
if (status)
return status;
status = gpio_direction_output(cs, !(spi->mode & SPI_CS_HIGH));
}
/*
* baudrate & width will be set rt2880_spi_setup_transfer
*/
return status;
}
注意spi->cs_gpio
,与dts中的cs-gpios
对应,其值分别为-2,-2,72
.-2表示没有对应的gpio(由系统硬件实现片选).
修改rt2880_spi_set_cs
static void rt2880_spi_set_cs(struct spi_device *spi, int enable)
{
struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
int cs = spi->chip_select;
// manfeel, deal cs_gpio first
if (spi->cs_gpio >= 0) {
/* SPI is normally active-low */
gpio_set_value_cansleep(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ? enable : !enable);
} else {
if (enable)
rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL(cs), SPICTL_SPIENA);
else
rt2880_spi_setbits(rs, RAMIPS_SPI_CTL(cs), SPICTL_SPIENA);
}
}
总共添加不到20行代码,就实现了N个spi接口!
实验
将三个不同的spi flash同时连接到开发板上:
cs0连接w25q256
cs1连接s25sl032p
cs2(gpio72,亦即WLED_GPIO)连接en25p64
上电开机,观察TTL输出,能够看到如下内容:
[ 0.570000] m25p80 spi32766.0: r=0, sreg3=0
[ 0.570000] m25p80 spi32766.0: w25q256 (32768 Kbytes)
[ 0.580000] 4 ofpart partitions found on MTD device spi32766.0
[ 0.600000] Creating 4 MTD partitions on "spi32766.0":
[ 0.600000] 0x000000000000-0x000000030000 : "u-boot"
[ 0.620000] 0x000000030000-0x000000040000 : "u-boot-env"
[ 0.620000] 0x000000040000-0x000000050000 : "factory"
[ 0.640000] 0x000000050000-0x000002000000 : "firmware"
[ 0.740000] 2 uimage-fw partitions found on MTD device firmware
[ 0.760000] 0x000000050000-0x0000001de092 : "kernel"
[ 0.760000] mtd: partition "kernel" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only
[ 0.760000] 0x0000001de092-0x000002000000 : "rootfs"
[ 0.760000] mtd: partition "rootfs" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only
[ 0.760000] mtd: device 5 (rootfs) set to be root filesystem
[ 0.760000] 1 squashfs-split partitions found on MTD device rootfs
[ 0.760000] 0x000000470000-0x000002000000 : "rootfs_data"
[ 0.760000] m25p80 spi32766.1: r=0, sreg3=0
[ 0.760000] m25p80 spi32766.1: found s25sl032p, expected w25q256
[ 0.760000] m25p80 spi32766.1: s25sl032p (4096 Kbytes)
[ 0.760000] 1 ofpart partitions found on MTD device spi32766.1
[ 0.760000] Creating 1 MTD partitions on "spi32766.1":
[ 0.760000] 0x000000000000-0x000002000000 : "edisk1"
[ 0.760000] mtd: partition "edisk1" extends beyond the end of device "spi32766.1" -- size truncated to 0x400000
[ 0.760000] spi-rt2880 10000b00.spi: in rt2880_spi_setup, cs_gpio = 72, status = 0
[ 0.760000] m25p80 spi32766.2: r=0, sreg3=0
[ 0.760000] m25p80 spi32766.2: found en25p64, expected w25q256
[ 0.760000] m25p80 spi32766.2: en25p64 (8192 Kbytes)
[ 0.760000] 1 ofpart partitions found on MTD device spi32766.2
[ 0.760000] Creating 1 MTD partitions on "spi32766.2":
[ 0.760000] 0x000000000000-0x000002000000 : "edisk2"
[ 0.760000] mtd: partition "edisk2" extends beyond the end of device "spi32766.2" -- size truncated to 0x800000
总结
通过添加cs-gpios
的方式实现了N个spi接口,鉴于spi接口的简单高效与灵活,大大加强了mt7620芯片的战斗力.以后,可以在mt7620上添加spi接口的各种设备,而不需要有spi接口不够的顾虑了.
ps:本文用CSDN提供的mdeditor完成.