AnsweredAssumed Answered

Is it possible to use mcp2515 CAN controller with imx28 ssp in spi mode?

Question asked by Mariusz Madej on Jun 1, 2017
Latest reply on Jun 1, 2017 by igorpadykov

Recently i am working on connecting additional CAN bus device to our imx28 based platform. We use kernel in version 3.16.0. We decided to go with mcp2515 CAN controller device connected to SPI bus (Synchronous Serial Port). I started with testing SPI bus using spidev driver and connecting signals to oscilloscope and everything seems to be fine - signals was the same as expected. Then i tried to connect mcp2515 and i met following problem during drivers probe:

 

mcp251x spi32766.0: spi transfer failed: ret = -22
mcp251x: probe of spi32766.0 failed with error -22

 

And i saw on oscilloscope that there was no try to send anything on spi bus.

 

I made some investigation and here is what i found:

 

The problem occurs in this code ( red lines ):

file drivers/spi/spi.c

 

static int __spi_validate(struct spi_device *spi, struct spi_message *message)

.

.

.

if ((master->flags & SPI_MASTER_HALF_DUPLEX)
                                             || (spi->mode & SPI_3WIRE)) {
   unsigned flags = master->flags;

   list_for_each_entry(xfer, &message->transfers, transfer_list) {
      if (xfer->rx_buf && xfer->tx_buf)

         return -EINVAL;
      if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)

         return -EINVAL;
      if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
         return -EINVAL;
      }
   }

.

.

.

}

So spi driver ensures that when master has SPI_MASTER_HALF_DUPLEX flag set, there is no rx_buf and tx_buf enabled at the same time for any transfer. Then i looked up how master->flags is set in spi-mxs driver:

file drivers/spi/spi-mxs.c:

 

master->flags = SPI_MASTER_HALF_DUPLEX;

So it is half duplex. Then i looked how mcp251x driver is initializing message->transfer:

file drivers/net/can/mcp251x.c:

 

static int mcp251x_spi_trans(struct spi_device *spi, int len)
{
   struct mcp251x_priv *priv = spi_get_drvdata(spi);
   struct spi_transfer t = {
      .tx_buf = priv->spi_tx_buf,
      .rx_buf = priv->spi_rx_buf,
      .len = len,
      .cs_change = 0,
   };

.

.

.

}

So spi transer is tx_buf and rx_buf is initialized somehow - because i get the error i assume both of them are not null.

 

Does it mean i cannot use mcp251x driver with half duplex spi bus controller? Or maybe i have to make some changes in my device tree. Below i attach my current device tree entry:

&ssp3 {
   compatible = "fsl,imx28-spi";
   pinctrl-names = "default";
   pinctrl-0 = <&spi3_pins_b>;
   status = "okay";

 

   can2: can@0 {
      compatible = "microchip,mcp2515";
      reg = <0>;
      pinctrl-names = "default";
      pinctrl-0 = <&mcp2515_pins>;
      interrupt-parent = <&gpio2>;
      interrupts = <13 0>;
      clocks = <&mcp2515clk>;
      vdd-supply = <&reg_3p3v>;
      xceiver-supply = <&reg_3p3v>;
      spi-max-frequency = <1000000>;
      status = "okay";
   };
};

Outcomes