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

 

posted @ 2021-08-23 17:11  闹闹爸爸  阅读(306)  评论(0编辑  收藏  举报