Changeset 29a73d8 in rtems


Ignore:
Timestamp:
Jul 17, 2020, 5:54:44 AM (2 months ago)
Author:
Christian Mauderer <christian.mauderer@…>
Branches:
master
Children:
02c9eb85
Parents:
0f4b911c
git-author:
Christian Mauderer <christian.mauderer@…> (07/17/20 05:54:44)
git-committer:
Christian Mauderer <christian.mauderer@…> (07/31/20 06:26:14)
Message:

bsp/imx: Use GPIOs for SPI CS

The chip select lines of the iMX SPI module doesn't work well for a
generic API like the one RTEMS uses. The existing solution only worked
in some special cases and had odd bugs when trying transfers of
different sizes (like deselecting between each byte for lengths that are
not dividable by 4).

With this patch the same approach like on FreeBSD or Linux is used:
Treat the CS lines as GPIOs.

Update 3869

File:
1 edited

Legend:

Unmodified
Added
Removed
  • bsps/arm/imx/spi/imx-ecspi.c

    r0f4b911c r29a73d8  
    1515#include <bsp.h>
    1616#include <bsp/fdt.h>
     17#include <bsp/imx-gpio.h>
    1718#include <libfdt.h>
    1819#include <arm/freescale/imx/imx_ccmvar.h>
     
    2425
    2526#define IMX_ECSPI_FIFO_SIZE 64
     27#define IMX_ECSPI_MAX_CHIPSELECTS 4
     28#define IMX_ECSPI_CS_NONE IMX_ECSPI_MAX_CHIPSELECTS
    2629
    2730typedef struct imx_ecspi_bus imx_ecspi_bus;
     
    4548  rtems_id task_id;
    4649  rtems_vector_number irq;
     50  struct {
     51    struct imx_gpio_pin pin;
     52    bool valid;
     53  } cspins[IMX_ECSPI_MAX_CHIPSELECTS];
    4754};
    4855
     
    127134    (*bus->push)(bus, regs);
    128135    ++bus->in_transfer;
     136  }
     137}
     138
     139/* Call with IMX_ECSPI_CS_NONE for @a cs to set all to idle */
     140static void
     141imx_ecspi_set_chipsel(imx_ecspi_bus *bus, uint32_t cs)
     142{
     143  size_t i;
     144
     145  /* Currently this is fixed active low */
     146  static const uint32_t idle = 1;
     147  static const uint32_t select = 0;
     148
     149  for (i = 0; i < IMX_ECSPI_MAX_CHIPSELECTS; ++i) {
     150    if (bus->cspins[i].valid) {
     151      if (i != cs) {
     152        imx_gpio_set_output(&bus->cspins[i].pin, idle);
     153      } else {
     154        imx_gpio_set_output(&bus->cspins[cs].pin, select);
     155      }
     156    }
    129157  }
    130158}
     
    287315      );
    288316    }
     317    if ((msg->mode & SPI_NO_CS) != 0) {
     318      imx_ecspi_set_chipsel(bus, IMX_ECSPI_CS_NONE);
     319    } else {
     320      imx_ecspi_set_chipsel(bus, msg->cs);
     321    }
    289322
    290323    bus->todo = msg->len;
     
    324357}
    325358
     359static int imx_ecspi_check_messages(
     360  imx_ecspi_bus *bus,
     361  const spi_ioc_transfer *msg,
     362  uint32_t size)
     363{
     364  while(size > 0) {
     365    if (msg->delay_usecs != 0) {
     366      return -EINVAL;
     367    }
     368    if (msg->bits_per_word > 32) {
     369      return -EINVAL;
     370    }
     371    if ((msg->mode &
     372        ~(SPI_CPHA | SPI_CPOL | SPI_LOOP | SPI_NO_CS)) != 0) {
     373      return -EINVAL;
     374    }
     375    if ((msg->mode & SPI_NO_CS) == 0 &&
     376        (msg->cs > IMX_ECSPI_MAX_CHIPSELECTS || !bus->cspins[msg->cs].valid)) {
     377      return -EINVAL;
     378    }
     379    if (msg->cs_change != 0) {
     380      return -EINVAL;
     381    }
     382
     383    ++msg;
     384    --size;
     385  }
     386
     387  return 0;
     388}
     389
    326390static int imx_ecspi_transfer(
    327391  spi_bus *base,
     
    331395{
    332396  imx_ecspi_bus *bus;
     397  int rv;
    333398
    334399  bus = (imx_ecspi_bus *) base;
    335400
    336   bus->msg_todo = n;
    337   bus->msg = &msgs[0];
    338   bus->task_id = rtems_task_self();
    339 
    340   imx_ecspi_next_msg(bus, bus->regs);
    341   rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    342   return 0;
     401  rv = imx_ecspi_check_messages(bus, msgs, n);
     402
     403  if (rv == 0) {
     404    bus->msg_todo = n;
     405    bus->msg = &msgs[0];
     406    bus->task_id = rtems_task_self();
     407
     408    imx_ecspi_next_msg(bus, bus->regs);
     409    rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     410    imx_ecspi_set_chipsel(bus, IMX_ECSPI_CS_NONE);
     411  }
     412  return rv;
    343413}
    344414
     
    357427  int len;
    358428  const uint32_t *val;
     429  size_t i;
     430
     431  for (i = 0; i < IMX_ECSPI_MAX_CHIPSELECTS; ++i) {
     432    rtems_status_code sc_gpio = imx_gpio_init_from_fdt_property(
     433        &bus->cspins[i].pin, node, "cs-gpios", IMX_GPIO_MODE_OUTPUT, i);
     434    bus->cspins[i].valid = (sc_gpio == RTEMS_SUCCESSFUL);
     435  }
     436  imx_ecspi_set_chipsel(bus, IMX_ECSPI_CS_NONE);
    359437
    360438  imx_ecspi_config(
     
    437515
    438516  bus->base.max_speed_hz = imx_ccm_ecspi_hz();
    439   bus->base.delay_usecs = 1;
     517  bus->base.delay_usecs = 0;
    440518  bus->regs = imx_get_reg_of_node(fdt, node);
    441519  bus->irq = imx_get_irq_of_node(fdt, node, 0);
Note: See TracChangeset for help on using the changeset viewer.