使能MT7620的第二个SPI接口(cs1)——兼谈pinmux与pinctrl驱动

前言

根据MT7620的数据手册,该芯片支持两个独立的spi接口,由于驱动不完善等种种原因,一直没能顺利的使用第二个spi接口.近日对mt7620的spi好好研究了一下,终于使能了第二个spi接口,将过程记录成文.

实现过程

spi驱动的诡异之处

mt7620的spi驱动位于:drivers/spi/spi-rt2880.c,里面有关spi cs1的代码非常诡异,因为7620与5350使用的是同一个spi控制芯片,而该驱动却区别对待,7620只有一个spi,5350有两个.

   1: static struct rt2880_spi_ops spi_ops[] = {
   2:     {
   3:         .init_hw = rt2880_spi_reset,
   4:         .num_cs = 1,
   5:     }, {
   6:         .init_hw = rt5350_spi_reset,
   7:         .num_cs = 2,
   8:     }, 
   9: };
  10:  
  11: static const struct of_device_id rt2880_spi_match[] = {
  12:     { .compatible = "ralink,rt2880-spi", .data = &spi_ops[0]},
  13:     { .compatible = "ralink,rt5350-spi", .data = &spi_ops[1]},
  14:     {},
  15: };

因此,第一个修改便是,将dts文件中对应的compatible修改为5350的版本.重新编译之后,驱动成功加载,然而,问题还远没有解决.

cs1没有输出信号

在第二个spi接口上连接一个spi flash芯片作为测试,始终无法probe到芯片.觉得很奇怪,于是用示波器来观察cs1上的信号,居然没有任何信号输出!仔细阅读7620的编程手册,发现了一个关键的内容:

spi_cs1在系统上电默认状态下是用作reference clock的!很显然,该引脚必须设置为normal spi mode.那么问题来了:如何设置这个引脚的功能呢?答案就在pinmux驱动中.

pinmux寻踪

很多嵌入式设备都有管脚复用功能,7620也不例外.pinmux数据在arch/mips/ralink/mt7620.c中定义:

   1: static struct rt2880_pmx_func i2c_grp[] =  { FUNC("i2c", 0, 1, 2) };
   2: static struct rt2880_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) };
   3: static struct rt2880_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) };
   4: static struct rt2880_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) };
   5: static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) };
   6: static struct rt2880_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) };
   7: static struct rt2880_pmx_func ephy_grp[] = { FUNC("ephy", 0, 40, 5) };
   8: static struct rt2880_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 60, 12) };
   9: static struct rt2880_pmx_func wled_grp[] = { FUNC("wled", 0, 72, 1) };
  10: static struct rt2880_pmx_func pa_grp[] = { FUNC("pa", 0, 18, 4) };
  11:  
  12: static struct rt2880_pmx_group mt7620a_pinmux_data[] = {
  13:     GRP("i2c", i2c_grp, 1, MT7620_GPIO_MODE_I2C),
  14:     GRP("uartf", uartf_grp, MT7620_GPIO_MODE_UART0_MASK,
  15:         MT7620_GPIO_MODE_UART0_SHIFT),
  16:     GRP("spi", spi_grp, 1, MT7620_GPIO_MODE_SPI),
  17:     GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1),
  18:     GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK,
  19:         MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT),
  20:     GRP("mdio", mdio_grp, 1, MT7620_GPIO_MODE_MDIO),
  21:     GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1),
  22:     GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK),
  23:     GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK,
  24:         MT7620_GPIO_MODE_PCIE_GPIO, MT7620_GPIO_MODE_PCIE_SHIFT),
  25:     GRP_G("nd_sd", nd_sd_grp, MT7620_GPIO_MODE_ND_SD_MASK,
  26:         MT7620_GPIO_MODE_ND_SD_GPIO, MT7620_GPIO_MODE_ND_SD_SHIFT),
  27:     GRP("rgmii2", rgmii2_grp, 1, MT7620_GPIO_MODE_RGMII2),
  28:     GRP("wled", wled_grp, 1, MT7620_GPIO_MODE_WLED),
  29:     GRP("ephy", ephy_grp, 1, MT7620_GPIO_MODE_EPHY),
  30:     GRP("pa", pa_grp, 1, MT7620_GPIO_MODE_PA),
  31:     { 0 }
  32: };

如何使能这些复用功能,则由dts与pinmux驱动协同完成,为了能够仔细分析pinmux实现机理,在drivers/pinctrl/pinctrl-rt2880.c的关键函数rt2880_pmx_group_enable中加入诊断代码:

   1: static int rt2880_pmx_group_enable(struct pinctrl_dev *pctrldev,
   2:                 unsigned func,
   3:                 unsigned group)
   4: {
   5:     struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
   6:         u32 mode = 0;
   7:     int i;
   8:  
   9:     /* dont allow double use */
  10:     if (p->groups[group].enabled) {
  11:         dev_err(p->dev, "%s is already enabled\n", p->groups[group].name);
  12:         return -EBUSY;
  13:     }
  14:  
  15:     p->groups[group].enabled = 1;
  16:     p->func[func]->enabled = 1;
  17:  
  18:     mode = rt_sysc_r32(SYSC_REG_GPIO_MODE);
  19:     mode &= ~(p->groups[group].mask << p->groups[group].shift);
  20:  
  21:     /* mark the pins as gpio */
  22:     for (i = 0; i < p->groups[group].func[0].pin_count; i++)
  23:         p->gpio[p->groups[group].func[0].pins[i]] = 1;
  24:  
  25:     /* function 0 is gpio and needs special handling */
  26:     if (func == 0) {
  27:         mode |= p->groups[group].gpio << p->groups[group].shift;
  28:     } else {
  29:         for (i = 0; i < p->func[func]->pin_count; i++)
  30:             p->gpio[p->func[func]->pins[i]] = 0;
  31:         mode |= p->func[func]->value << p->groups[group].shift;
  32:     }
  33:     rt_sysc_w32(mode, SYSC_REG_GPIO_MODE);
  34:  
  35:     // manfeel, add debug info
  36:     
  37:     dev_info(p->dev, "%s(%d),%s(%d)\t\t= %x\n", p->groups[group].name, group, p->func[func]->name, func, mode);
  38:  
  39:     return 0;
  40: }

在TTL控制台中,能观察到这些信息:

   1: [    0.080000] rt2880-pinmux pinctrl.1: ephy(12),gpio(0)                = ab11d
   2: [    0.080000] rt2880-pinmux pinctrl.1: wled(11),gpio(0)                = ab11d
   3: [    0.090000] rt2880-pinmux pinctrl.1: pa(13),gpio(0)          = 1ab11d
   4: [    0.090000] rt2880-pinmux pinctrl.1: wdt(4),gpio(0)          = 5ab11d
   5: [    0.100000] rt2880-pinmux pinctrl.1: uartf(1),gpio(0)                = 5ab11d
   6: [    0.100000] rt2880-pinmux pinctrl.1: mdio(5),gpio(0)         = 5ab11d
   7: [    0.110000] bio: create slab <bio-0> at 0
   8: [    0.120000] rt2880_gpio 10000600.gpio: registering 24 gpios
   9: [    0.120000] rt2880_gpio 10000600.gpio: registering 24 irq handlers
  10: [    0.130000] rt2880_gpio 10000638.gpio: registering 16 gpios
  11: [    0.130000] rt2880_gpio 10000638.gpio: registering 16 irq handlers
  12: [    0.140000] rt2880_gpio 10000660.gpio: registering 32 gpios
  13: [    0.140000] rt2880_gpio 10000660.gpio: registering 32 irq handlers
  14: [    0.150000] rt2880_gpio 10000688.gpio: registering 1 gpios
  15: [    0.150000] rt2880_gpio 10000688.gpio: registering 1 irq handlers
  16: ... ...
  17: [    0.160000] rt2880-pinmux pinctrl.1: i2c(0),i2c(1)           = 5ab11c
  18: [    0.170000] i2c-ralink 10000900.i2c: loaded
  19: ... ...
  20: [    0.410000] rt2880-pinmux pinctrl.1: uartlite(3),uartlite(10)                = 5ab11c
  21: [    0.410000] 10000c00.uartlite: ttyS0 at MMIO 0x10000c00 (irq = 20, base_baud = 2500000) is a 16550A
  22: ... ...
  23: [    0.470000] rt2880-pinmux pinctrl.1: spi(2),spi(9)           = 5ab11c
  24: [    0.500000] m25p80 spi32766.0: found en25p64, expected w25q256
  25: [    0.500000] m25p80 spi32766.0: en25p64 (8192 Kbytes)

结合dts文件,能够理解得更加透彻(用I2C来分析):

   1: [email protected] {
   2:     compatible = "link,mt7620a-i2c", "ralink,rt2880-i2c";
   3:     reg = <0x900 0x100>;
   4:  
   5:     resets = <&rstctrl 16>;
   6:     reset-names = "i2c";
   7:  
   8:     #address-cells = <1>;
   9:     #size-cells = <0>;
  10:  
  11:     status = "disabled";
  12:  
  13:     pinctrl-names = "default";
  14:     pinctrl-0 = <&i2c_pins>;
  15: };
  16: ... ...
  17: pinctrl {
  18:     compatible = "ralink,rt2880-pinmux";
  19:     pinctrl-names = "default";
  20:     pinctrl-0 = <&state_default>;
  21:     
  22:     i2c_pins: i2c {
  23:         i2c {
  24:             ralink,group = "i2c";
  25:             ralink,function = "i2c";
  26:         };
  27:     };
  28: };

dts中,每一个设备节点可能需要用到一些复用管脚,该机制通过pinctrl-0来指定,如i2c中的i2c_pins.我们再来看看spi设备节点中的数据:

   1: [email protected] {
   2:     compatible = "ralink,mt7620a-spi", "ralink,rt2880-spi";
   3:     reg = <0xb00 0x100>;
   4:  
   5:     resets = <&rstctrl 18>;
   6:     reset-names = "spi";
   7:  
   8:     #address-cells = <1>;
   9:     #size-cells = <1>;
  10:  
  11:     status = "disabled";
  12:  
  13:     pinctrl-names = "default";
  14:     pinctrl-0 = <&spi_pins>;
  15: };

结合前面的知识,对dts修改如下:

   1: spi_pins: spi {
   2:     spi {
   3:         ralink,group = "spi";
   4:         ralink,function = "spi";
   5:     };
   6:     /* added by manfeel */    
   7:     cs1 {
   8:         ralink,group = "spi refclk";
   9:         ralink,function = "spi refclk";
  10:     };
  11: };

至此,mt7620的第二个spi终于可以使用.

总结

充分利用dts的功能,能够达到很多意想不到的效果.一句话:dts的强大超乎我们的想象!

最后一点也是最重要的一点:很多7620的开发板在设计的时候,并没有考虑要使用第二个spi接口,因此对cs1的管脚是做悬浮处理的,如果要正确使用spi的cs1,则需要对该引脚做上拉处理,否则会导致系统出现各种奇怪的问题.

时间: 2024-11-05 13:51:11

使能MT7620的第二个SPI接口(cs1)——兼谈pinmux与pinctrl驱动的相关文章

让MT7620完美支持32M SPI Flash(W25Q256) — 兼谈设备驱动中的shutdown方法

前言 OpenWrt的最新kernel(3.14.28)已经能够支持32M SPI Flash的读写以及擦除操作.然而,可能是系统考虑不周,亦或是MT7620系统的BUG,在配置了W25Q256的MT7620开发板系统上,无法soft reset!经过查阅相关资料,发现,MT7620默认支持24bit(3byte)的spi地址模式,而要支持32M以上的spi flash,则必须切换到32bit(4byte)地址模式.在soft reset的时候,spi停留在了32bit模式,没有切换回默认的24

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

前言 我的上一篇文章中谈到,如何使能mt7620的第二个spi接口.既然第二个spi接口已经开放成功,那么,可否接着添加第三个.第四个spi接口呢?熟悉mt7620硬件的朋友一定会第一时间站出来反对我:怎么可能!?mt7620总共才两个spi接口,怎么可能添加更多呢?除非在硬件上想办法.然而我总是善于将不可能变为可能^_^,今天我就要和大家分享一下,如何不改动任何硬件,通过修改驱动的方法,实现多个spi接口.注意,我这里实现的spi,并非用gpio口模拟的bitbang伪spi,而是基于硬件sp

成都自动化开发:SPI接口通信协议浅谈

沙鸥-成都 1 什么是SPISPI是串口外设接口的缩写,是一种高速的.全双工.同步的通信协议,是微处理器与外围IC之间常用的一种通讯方式.SPI是主从式的通信协议,可以一主机一从机通信,也可以一主机多从机通信. 2 SPI的优缺点SPI接口简单,一般只需要4个引脚就可以通信,分别是SCLK.MOSI.MISO.CS,假如只需要单向通信,那么最少只需要2个引脚就可以.SPI的一个缺点就是没有指定的流控制,没有应答机制确认是否接收到数据,只支持一个主机方式等. 3 SPI怎么工作的用一句话概括SPI

SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)

SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART(Universal Asynchronous Receiver Transmitter:通用异步收发器) 第二,区别在电气信号线上: SPI总线由三条信号线组成:串行时钟(SCLK).串行数据输出(SDO).串行数据输入(SDI).SPI总线可以实现多个SPI设备互相连接.提供SPI串行时钟的SPI

高通APQ8074 spi 接口配置

8074 平台含有两个BLSP(BAM Low-Speed Peripheral) , 每一个BLSP含有两个QUP, 每一个QUP可以被配置为I2C, SPI, UART, UIM接口, BLSP是高通对于低速接口的一种管理方式. 每个QUP是和特定的引脚相关的, 如下图所示,比如下面的引脚是属于BLSP8的, 也就是第二个BLSP的第二个QUP, 注意这些引脚只能被配置到第二个BLSP的第2个QUP上,可以通过继续查看高通相关资料 QUP的中断相关信息 得到这些信息后,如果只是要将SPI配置

嵌入式物联网之SPI接口原理与配置

本实验采用W25Q64芯片 W25Q64是华邦公司推出的大容量SPI FLASH产品,其容量为64Mb.该25Q系列的器件在灵活性和性能方面远远超过普通的串行闪存器件.W25Q64将8M字节的容量分为128个块,每个块大小为64K字节,每个块又分为16个扇区,每个扇区4K个字节.W25Q64的最小擦除单位为一个扇区,也就是每次必须擦除4K个字节.所以,这需要给W25Q64开辟一个至少4K的缓存区,这样必须要求芯片有4K以上的SRAM才能有很好的操作. W25Q64的擦写周期多达10W次,可将数据

STC8A8K64S4A12通过SPI接口操作基于ST7920的LCD12864液晶模块

文章地址:https://www.cnblogs.com/jqdy/p/12665430.html 1. 硬件连接 1.1 64引脚的STC8A8K64S4A12 使用的是最小核心板,所以引脚皆引出可供使用.其他接口只有USB口,起到供电及下载烧写的作用. 1.2 12864液晶模块 店家提供的使用说明较为杂乱,后续除模块信息外,关于控制芯片的内容均参考ST7920手册. 显示控制芯片使用的是ST7920 模块有20个外接引脚(见图2) PCB背板有选择串口和并口的两组焊点,短接后可分别选择串口

STM32——SPI接口

STM32--SPI接口 宗旨:技术的学习是有限的,分享的精神的无限的. 一.SPI协议[SerialPeripheral Interface] 串行外围设备接口,是一种高速全双工的通信总线.在ADC/LCD等与MCU间通信. 1.SPI信号线 SPI 包含 4 条总线,SPI 总线包含 4 条总线,分别为SS .SCK.MOSI.MISO. (1)SS(SlaveSelect):片选信号线,当有多个 SPI 设备与 MCU 相连时,每个设备的这个片选信号线是与 MCU 单独的引脚相连的,而其他

如何从Cortex-m向STM32移植使用SPI接口协议

/***************************************************************************************************** * @brief: LDC1000应用程序 * _____________ _______________ * |PB4(SSI2CLK) ----> SCLK| * |PB5(SSI2FSS) ----> CSB | * |PB6(SSI2RX)    <----       SDO