CHOI HYONGEUN

Control SPI SS_CTL for single burst operation.

Discussion created by CHOI HYONGEUN on Jun 29, 2011
Latest reply on Jul 18, 2017 by Yuri Muhin

Hi, all.

Please understand that my english is not good enough.

I'm currently working with the i.MX53 EVK.

I'm having some trouble with the ECSPI.

My SPI device requires the CS/SS pin to be held low for the length of the SPI burst.

I thought that it is not a proper way to change bits_per_word value,

because normal burst read size is more than 32-bits.

I found a way to control SS waveform in ECSPI config register.

So, i comment out the code to set ss_ctl bit, as shown below.

/* mxc_spi.c */

void mxc_spi_chipselect(struct spi_device *spi, int is_active)

{

  .....

  if (spi_ver_def == &spi_ver_2_3) {

    .....

    if (spi->mode & SPI_CS_HIGH) {

      config_reg |=

        ((((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &

          spi_ver_def->mode_mask) | cs_value) << spi_ver_def->ss_pol_shift);

    } else

      config_reg |=

        ((~((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &

          spi_ver_def->mode_mask) & cs_value) << spi_ver_def->ss_pol_shift);

#if 0 /* single burst transfer */

    config_reg |=

      (((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &

        spi_ver_def->mode_mask) << spi_ver_def->ss_ctrl_shift);

#endif

    __raw_writel(0, master_drv_data->base + MXC_CSPICTRL);

    __raw_writel(ctrl_reg, master_drv_data->base + MXC_CSPICTRL);

    __raw_writel(config_reg, MXC_CSPICONFIG + master_drv_data->ctrl_addr);

    .....

 

This is the code for SPI burst read in my SPI device driver. (master mode, bits_per_word:8)

/* my_spi.c */

void my_spi_read_burst(unsigned char reg, unsigned char *buf, int size)

{

  int ret;

  u8 tmp_buf[2];

  struct spi_message msg;

  struct spi_transfer msg_xfer;

 

  spi_message_init(&msg);

  memset(&msg_xfer, 0, sizeof(msg_xfer));

 

  msg_xfer.tx_buf = tmp_buf;

  msg_xfer.len = 2;

 

  tmp_buf[0] = MY_SPI_CHIP_ADDR;

  tmp_buf[1] = reg;

  spi_message_add_tail(&msg_xfer, &msg);


  ret = spi_sync(my_spi_ptr->spi_ptr, &msg);

  if (ret)

    printk("spi_sync error\n");

 

  spi_message_init(&msg);

  memset(&msg_xfer, 0, sizeof(msg_xfer));

 

  msg_xfer.tx_buf = buf;

  msg_xfer.rx_buf = buf;

  msg_xfer.len = size;

 

  buf[0] = (MY_SPI_CHIP_ADDR | 0x1);

  spi_message_add_tail(&msg_xfer, &msg);

 

  ret = spi_sync(my_spi_ptr->spi_ptr, &msg);

  if (ret)

    printk("spi_sync error\n");}

 

Unfortunately it does not work. Am I missing something?

Read operation is infinitely waiting for transfer completion in mxc_spi_transfer function.

The reason is as shown below.

static irqreturn_t mxc_spi_isr(int irq, void *dev_id)

{

  struct mxc_spi *master_drv_data = dev_id;

  irqreturn_t ret = IRQ_NONE;

  unsigned int status;

  int fifo_size;

  unsigned int pass_counter;

 

  fifo_size = master_drv_data->spi_ver_def->fifo_size;

  pass_counter = fifo_size;

 

  /* Read the interrupt status register to determine the source */

  status = __raw_readl(master_drv_data->stat_addr);

  do {

    u32 rx_tmp =  __raw_readl(master_drv_data->base + MXC_CSPIRXDATA);

 

    if (master_drv_data->transfer.rx_buf)

      master_drv_data->transfer.rx_get(master_drv_data, rx_tmp);

 

    (master_drv_data->transfer.count)--;

    (master_drv_data->transfer.rx_count)--;  <-------- rx_count is 386

    ret = IRQ_HANDLED;

    if (pass_counter-- == 0) {

      break;

    }

    status = __raw_readl(master_drv_data->stat_addr);  <-------- status is 0x80 (RR is 0),                                                                                  exit a while loop immediately

  } while (status &

             (1 << (MXC_CSPISTAT_RR + master_drv_data->spi_ver_def->int_status_dif)));

 

  if (master_drv_data->transfer.rx_count)

    return ret;  <-------- rx_count is 385, return from the function and no more interrupt.

 

  if (master_drv_data->transfer.count) {

    if (master_drv_data->transfer.tx_buf) {

      u32 count = (master_drv_data->transfer.count > fifo_size) ?

                      fifo_size : master_drv_data->transfer.count;

      master_drv_data->transfer.rx_count = count;

      spi_put_tx_data(master_drv_data->base, count, master_drv_data);

    }

  } else {

    complete(&master_drv_data->xfer_done);  <-------- Never reached

  }

  return ret;

}

Please advise me.

Thanks.

Outcomes