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 = <®_3p3v>;
xceiver-supply = <®_3p3v>;
spi-max-frequency = <1000000>;
status = "okay";
};
};
Hi Mariusz
according to sect.17.5.1 SPI DMA Mode i.MX28 Reference Manual
The SPI bus is inherently a full-duplex bidirectional interface. However, as most
applications only require half-duplex data transmission, the i.MX28 has a single DMA
channel for the SSP. It can be configured for either transmit or receive.
http://cache.freescale.com/files/dsp/doc/ref_manual/MCIMX28RM.pdf
I am not familiar with mcp251x capabilities, this can be posted on its vendor support.
http://www.microchip.com/support/hottopics.aspx
Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------