码迷,mamicode.com
首页 > 其他好文 > 详细

无限可能!为MT7620添加N个SPI接口

时间:2015-02-11 16:37:40      阅读:3132      评论:0      收藏:0      [点我收藏+]

标签:mt7620   spi   

前言

我的上一篇文章中谈到,如何使能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片选来.

        spi@b00 {
            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完成.

无限可能!为MT7620添加N个SPI接口

标签:mt7620   spi   

原文地址:http://blog.csdn.net/manfeel/article/details/43734485

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!