zoukankan      html  css  js  c++  java
  • PXA2xx SPI on SSP driver HOWTO

    这是一个关于pxa2xx_spi驱动程序的迷你HOWTO。驱动程序将PXA2xx同步串行端口转换为SPI主控制器。该驱动程序具有以下特点:

    • 支持任何PXA2xx和兼容SSP。
    • SSP PIO和SSP DMA数据传输。
    • 外部和内部(SSPFRM)芯片选择。
    • 每个从设备(芯片)配置。
    • 完全暂停,冻结,恢复支持。

    驱动程序是围绕一个由内核线程服务的&struct spi_message FIFO构建的。内核线程spi_pump_messages()驱动消息FIFO,并负责对SPI事务进行排队,设置和启动DMA或中断驱动的传输。

    声明 PXA2xx 主控制器

    通常,对于传统平台,SPI主机在arch/…/mach-/board-.c中被定义为“平台设备”。主配置通过include/linux/spi/pxa2xx_spi.h中的表传递给驱动程序:

    struct pxa2xx_spi_controller {
          u16 num_chipselect;
          u8 enable_dma;
          ...
    };

    “pxa2xx_spi_controller.num_chipselect”字段用于确定附加到这个SPI主机的从设备(芯片)号。

    “pxa2xx_spi_controller.enable_dma "字段告知驱动程序应该使用SSP DMA。这导致驱动程序获取两个DMA通道:Rx通道和Tx通道。Rx通道的DMA服务优先级高于Tx通道。参见“PXA2xx开发人员手册”“DMA控制器”一节。

    对于新平台,控制器和外围设备的描述来自设备树或ACPI。

    NSSP MASTER SAMPLE

    下面是一个使用PXA255 NSSP的遗留平台的配置示例:

    static struct resource pxa_spi_nssp_resources[] = {
          [0] = {
                  .start  = __PREG(SSCR0_P(2)), /* Start address of NSSP */
                  .end    = __PREG(SSCR0_P(2)) + 0x2c, /* Range of registers */
                  .flags  = IORESOURCE_MEM,
          },
          [1] = {
                  .start  = IRQ_NSSP, /* NSSP IRQ */
                  .end    = IRQ_NSSP,
                  .flags  = IORESOURCE_IRQ,
          },
    };
    
    static struct pxa2xx_spi_controller pxa_nssp_master_info = {
          .num_chipselect = 1, /* Matches the number of chips attached to NSSP */
          .enable_dma = 1, /* Enables NSSP DMA */
    };
    
    static struct platform_device pxa_spi_nssp = {
          .name = "pxa2xx-spi", /* MUST BE THIS VALUE, so device match driver */
          .id = 2, /* Bus number, MUST MATCH SSP number 1..n */
          .resource = pxa_spi_nssp_resources,
          .num_resources = ARRAY_SIZE(pxa_spi_nssp_resources),
          .dev = {
                  .platform_data = &pxa_nssp_master_info, /* Passed to driver */
          },
    };
    
    static struct platform_device *devices[] __initdata = {
          &pxa_spi_nssp,
    };
    
    static void __init board_init(void)
    {
          (void)platform_add_device(devices, ARRAY_SIZE(devices));
    }

    Declaring Slave Devices

    通常,对于一个遗留平台,每个SPI从(芯片)在arch/…/mach-/board-.c中定义,使用“linux/spi/spi.h”中的“spi_board_info”结构。

    每个连接到PXA的从设备必须通过“include/linux/spi/pxa2xx_spi.h"里的 pxa2xx_spi_chip 结构提供从设备特定的配置信息。pxa2xx_spi主控制器驱动程序将在驱动程序与从设备通信时使用该配置。所有字段都是可选的。

    struct pxa2xx_spi_chip {
          u8 tx_threshold;
          u8 rx_threshold;
          u8 dma_burst_size;
          u32 timeout;
          u8 enable_loopback;
          void (*cs_control)(u32 command);
    };

    “pxa2xx_spi_chip.tx_threshold” 和 “pxa2xx_spi_chip.rx_threshold”字段用于配置SSP硬件FIFO。这些字段对pxa2xx_spi驱动程序的性能至关重要,错误配置将导致rx FIFO溢出(特别是在PIO模式传输中)。好的默认值是:

    .tx_threshold = 8,
    .rx_threshold = 8,

    取值范围为1 ~ 16,其中0表示“使用default”。

    “pxa2xx_spi_chip.dma_burst_size”字段用于配置PXA2xx DMA引擎 并且与“spi_device.bits_per_word”字段相关。阅读和理解PXA2xx“开发人员手册”部分的DMA控制器和SSP控制器,以确定正确的值。配置为字节范围传输的SSP将使用值8。如果dma_burst_size == 0,驱动程序将确定一个合理的默认值。

    “pxa2xx_spi_chip.timeout“字段被用来有效地处理SSP接收器FIFO中的尾随字节。该字段的正确值取决于SPI总线速度(“spi_board_info.max_speed_hz”)和特定的从设备。请注意,PXA2xx SSP 1不支持尾随字节超时,必须忙碌等待任何尾随字节。

    “pxa2xx_spi_chip.enable_loopback "字段用于将SSP移植到内部环回模式。在这种模式下,SSP控制器内部连接SSPTX引脚到SSPRX引脚。这对于初始设置测试很有用。

    “pxa2xx_spi_chip.cs_control”字段用于指向一个单板特定的函数,用于asserting/deasserting从设备芯片选择。如果该字段为NULL, pxa2xx_spi主控制器驱动程序假设SSP端口被配置为使用GPIO或SSPFRM。

    注意:如果使用SSPFRM, SPI驱动程序不能控制芯片选择,所以每次spi_transfer之后,chipselect被丢弃。大多数设备都需要在完整的消息周围进行芯片选择。使用SSPFRM作为GPIO(通过描述符)来适应这些芯片。

    NSSP SLAVE SAMPLE

    对于遗留平台或在其他情况下,pxa2xx_spi_chip结构被传递到pxa2xx_spi驱动程序中的“spi_board_info.controller_data”字段。下面是使用PXA255 NSSP的配置示例。

    /* Chip Select control for the CS8415A SPI slave device */
    static void cs8415a_cs_control(u32 command)
    {
          if (command & PXA2XX_CS_ASSERT)
                  GPCR(2) = GPIO_bit(2);
          else
                  GPSR(2) = GPIO_bit(2);
    }
    
    /* Chip Select control for the CS8405A SPI slave device */
    static void cs8405a_cs_control(u32 command)
    {
          if (command & PXA2XX_CS_ASSERT)
                  GPCR(3) = GPIO_bit(3);
          else
                  GPSR(3) = GPIO_bit(3);
    }
    
    static struct pxa2xx_spi_chip cs8415a_chip_info = {
          .tx_threshold = 8, /* SSP hardward FIFO threshold */
          .rx_threshold = 8, /* SSP hardward FIFO threshold */
          .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
          .timeout = 235, /* See Intel documentation */
          .cs_control = cs8415a_cs_control, /* Use external chip select */
    };
    
    static struct pxa2xx_spi_chip cs8405a_chip_info = {
          .tx_threshold = 8, /* SSP hardward FIFO threshold */
          .rx_threshold = 8, /* SSP hardward FIFO threshold */
          .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
          .timeout = 235, /* See Intel documentation */
          .cs_control = cs8405a_cs_control, /* Use external chip select */
    };
    
    static struct spi_board_info streetracer_spi_board_info[] __initdata = {
          {
                  .modalias = "cs8415a", /* Name of spi_driver for this device */
                  .max_speed_hz = 3686400, /* Run SSP as fast a possbile */
                  .bus_num = 2, /* Framework bus number */
                  .chip_select = 0, /* Framework chip select */
                  .platform_data = NULL; /* No spi_driver specific config */
                  .controller_data = &cs8415a_chip_info, /* Master chip config */
                  .irq = STREETRACER_APCI_IRQ, /* Slave device interrupt */
          },
          {
                  .modalias = "cs8405a", /* Name of spi_driver for this device */
                  .max_speed_hz = 3686400, /* Run SSP as fast a possbile */
                  .bus_num = 2, /* Framework bus number */
                  .chip_select = 1, /* Framework chip select */
                  .controller_data = &cs8405a_chip_info, /* Master chip config */
                  .irq = STREETRACER_APCI_IRQ, /* Slave device interrupt */
          },
    };
    
    static void __init streetracer_init(void)
    {
          spi_register_board_info(streetracer_spi_board_info,
                                  ARRAY_SIZE(streetracer_spi_board_info));
    }

    DMA and PIO I/O Support

    pxa2xx_spi驱动程序支持DMA和中断驱动PIO消息传输。驱动程序默认为PIO模式,必须通过在“pxa2xx_spi_controller”结构中设置“enable_dma”标志来启用DMA传输。对于已知支持DMA的较新的平台,驱动程序将自动启用它,并首先尝试它,并可能回退到PIO。DMA模式既支持一致性DMA映射,也支持流式DMA映射。

    下面的逻辑用于确定在每个“spi_transfer”基础上使用的I/O类型:

    if !enable_dma then
          always use PIO transfers
    
    if spi_message.len > 8191 then
          print "rate limited" warning
          use PIO transfers
    
    if spi_message.is_dma_mapped and rx_dma_buf != 0 and tx_dma_buf != 0 then
          use coherent DMA mode
    
    if rx_buf and tx_buf are aligned on 8 byte boundary then
          use streaming DMA mode
    
    otherwise
          use PIO transfer

    本文来自博客园,作者:王楼小子,转载请注明原文链接:https://www.cnblogs.com/wanglouxiaozi/p/15176764.html

  • 相关阅读:
    自学Aruba6.3-账号管理(web页面配置)
    自学Aruba6.2-控制器基本维护操作(web页面配置)
    自学Aruba6.1-基本网络参数配置(web页面配置)
    自学Aruba5.1.2-带宽限制
    自学Aruba5.1.1-基于时间的Role定义
    自学Linux Shell19.2-gawk程序高级特性
    自学Linux Shell19.1-gawk程序基础特性
    自学Linux Shell18.3-sed实用工具
    自学Linux Shell18.2-sed编辑器高级特性
    js 数组API之every、some用法
  • 原文地址:https://www.cnblogs.com/wanglouxiaozi/p/15176764.html
Copyright © 2011-2022 走看看