TX1 in SPI Slave mode to an ADC.

I’m trying get TX1 to receive data from AD7764 ADC which outputs data over SPI as SPI Master, hence the TX1 has to be a SPI Slave.

The AD7764 generates a SPI Clock 20MHz and also generates a CS signal (called FSO) which frames every sample. Here is a trace of the output from a logic analyser :

I’ve connected the MOSI pins , the SCO/SCK pins, the FSI/CS pins and the GND pins of the ADC and TX1 (J21 connector)

I have been trying to use the spi-tegra114-slave.c from L4T sources with the dt based on https://devtalk.nvidia.com/default/topic/979251/jetson-tx1/tx1-spi-slave-mode/. I compiled and manually loaded (insmod) the kernel module and used the spidev_test.c to read the data out 1024 samples of 32bits each (DMA mode).

sudo ./spidev_slave_test -D /dev/spidev0.1 -H -b 32

I’m having issues with the spi-tegra114-slave driver. The driver errors out with a timeout error (after 1 sec) on dmesg when running the above test script. The actual error is :

RxDma Xfer failed

It seems that the DMA Interrupt isn’t triggering and causing a timeout (wait_status is 0). When I print out the Transfer Status Register, BLOCK_COUNT has the value of 1. I am suspecting it’s something to do with the CS input.

So here are my questions.

  1. Does the SPI CS Timing2 Register (37.3.4) affect the SPI Slave Mode ?
  2. For SPI Slave Mode, does CS have be active (held low) between two packets?
  3. Does the number of clock cycles between two packets in SPI Slave mode have to be exactly the number in the SPI CS Timing 2 Register?
  4. Can the TX1 handle an external SPI Clock of 20MHz (the slave driver has SPI Max Frequency of 25MHz)?

Apologies for the long post. I have been struggling with this for a while without much success.

-Chinmay

I managed to make this work, although I’m still having some more issues.

I changed the following things.

  1. Used the spi-tegra124-slave driver instead as mentioned by Shane from nVidia in this thread.

  2. Set a delay argument in the spidev-test command. In the driver, this delay value get’s set as the timeout for the DMA Interrupt wait_for_complete. I am guessing the timeout issue (RxDma Xfer failed) I was seeing earlier was being caused by some issue with the default timeout value.

sudo ./spidev_slave_test -D /dev/spidev0.1 -H -b 32 -d 1000

This allows me to get data in DMA Mode.

However every second attempt to request for data in this way results in another error in the driver. The attempts don’t have to be back to back.

[  544.071878] spi_master spi0: transferred[601] != requested[1024]
[  544.078453] spi_master spi0:   CMD[17f0901f]:  Sl M1 CS1 [HHHH] LSB MSb Rx  Un 32b TRANS[00ff0259]:BSY I:255 B:601
                FIFO[01400004]:RxF:2 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00110000]:    RxTr:2 TxTr:2 B:1023
[  544.098379] spi_master spi0: rx-dma-err [status:01400004]
[  544.104261] spi_master spi0:   CMD[17f0901f]:  Sl M1 CS1 [HHHH] LSB MSb Rx  Un 32b TRANS[00ff0259]:BSY I:255 B:601
                FIFO[01400004]:RxF:2 TxE:64 Err[] RxSTA[] TxSTA[E]DMA[00110000]:    RxTr:2 TxTr:2 B:1023

It seems that the ISR is called, the RDY bit is set, but the BLOCK_COUNT in the Transfer register is only 601 (this number varies) instead of 1024 when ISR runs.

Hi notthetup
We’re issue an internal discuss about this topic. However this periods are X’max holiday the response are quite slow. We will update to you once we got response. Please keep update what your doing that could be help us know more detail information.

Thank you so much ShaneCCC. I understand that it’s slower during the holidays.

I will keep working on this and posting what I learn here.

It seem that the reason every other request works, is that reseting the SPI peripheral fixes the issue. And the error (transferred[601] != requested[1024]) causes a call to reset_controller, which fixes the issue.

So I tried to test by forcing a reset at the beginning of every transfer in

static int tegra_spi_start_transfer_one(...)(

I narrowed it down to adding this bit of code of immediately after the request validation.

tegra_periph_reset_assert(tspi->clk);
wmb(); /* barrier for assert */
tegra_periph_reset_deassert(tspi->clk);
/* set CS inactive b/w packets to mask CS_INACTIVE interrupts */
if (tspi->chip_data->mask_cs_inactive_intr)
  tegra_spi_writel(tspi, 0, SPI_CS_TIMING2);

Hopefully this might give a clue on what’s causing the error.

I spent more time investigating this.

So it seems that the data acquisition is accurate. I compared the acquired data by the SPI to what I saw on the logic analyser and it is exactly the same.

However, since I’m still using the above hack (reset between each transfer request), I end up missing quite a few samples between subsequent requests.

With that the only remaining issue is the error that happens every SPI request after a previous successful request (as described above).

-Chinmay

Spent more time working on this over the weekend and yesterday. I dumped out all DMA and SPI registers before, during and after the transactions. Here are my results summarised.

– Fresh Start —

Transaction #1

  • Setup DMA + SPI (1024 Words, 32bits per word, 20MHz).
  • Enable DMA_EN bit in DMA_CTL Register.
  • SPI ISR Triggers.
  • ERR Flag in FIFO_STATUS is NOT set (No error).
  • Value of BLOCK_COUNT in TRANS_STATUS Registers matches the length of requested transfer.
  • DMA Callback.
  • Data is copied to Userspace.

Transaction #2

  • Setup DMA + SPI (1024 Words, 32bits per word, 20MHz).
  • Enable DMA_EN bit in DMA_CTL Register.
  • SPI ISR Triggers.
  • ERR Flag in FIFO_STATUS is NOT set (No error).
  • Value of BLOCK_COUNT in TRANS_STATUS Registers DOES NOT match the length of requested transfer.
  • Driver Errors out and resets SPI Controller.

In both Transactions the DMA and SPI registers are exactly the same just before enabling the DMA_EN bit. The only difference being that Transaction #2 is started after end of Transaction #1.

I am starting to suspect there might be a restriction on consecutive DMA transactions without resetting the SPI Controller, like there is for Continuous mode. Can someone from nVIDIA confirm this?

Hi notthetup
Below code can make the SPI slave mode work and verified by the loopback.

Device tree
	spi0: spi@7000d400 {
		compatible = "nvidia,tegra210-spi";
		reg = <0x0 0x7000d400 0x0 0x200>;
		interrupts = <0 59 0x04>;
		nvidia,dma-request-selector = <&apbdma 15>;
		iommus = <&smmu TEGRA_SWGROUP_PPCS>;
		#address-cells = <1>;
		#size-cells = <0>;
		dmas = <&apbdma 15>, <&apbdma 15>;
		dma-names = "rx", "tx";
		nvidia,clk-parents = "pll_p", "clk_m";
		status = "okay";
		spi0_0 {
			compatible = "spidev";
			reg = <0x0>;
			spi-max-frequency = <0x1312d00>;
		};
	};

	spi1: spi@7000d600 {
		status = "okay";
		compatible = "nvidia,tegra124-spi-slave";
		reg = <0x0 0x7000d600 0x0 0x200>;
		interrupts = <0 82 0x04>;
		nvidia,dma-request-selector = <&apbdma 16>;
		iommus = <&smmu TEGRA_SWGROUP_PPCS>;
		#address-cells = <1>;
		#size-cells = <0>;
		dmas = <&apbdma 16>, <&apbdma 16>;
		dma-names = "rx", "tx";
		nvidia,clk-parents = "pll_p", "clk_m";
		nvidia,rx-trigger-words = <0>;
		spi1_0 {
			compatible = "spidev";
			reg = <0x0>;
			spi-max-frequency = <0x1312d00>;
		};
	};



diff --git a/drivers/spi/spi-tegra124-slave.c b/drivers/spi/spi-tegra124-slave.c
index 8d749b2..9bbd9a9 100644
--- a/drivers/spi/spi-tegra124-slave.c
+++ b/drivers/spi/spi-tegra124-slave.c
@@ -1759,6 +1759,8 @@ static int tegra_spi_probe(struct platform_device *pdev)
 	tspi->dma_req_sel = pdata->dma_req_sel;
 	tspi->clock_always_on = pdata->is_clkon_always;
 	tspi->rx_trig_words = pdata->rx_trig_words;
+	tspi->clk_pin = NULL;
+#if 0
 	tspi->clk_pin = (char *)pdata->clk_pin;
 	if (tspi->clk_pin) {
 		tspi->clk_pin_state_enabled = true;
@@ -1781,7 +1783,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "Pin group name for clock line is not defined.\n");
 		goto exit_free_master;
 	}
-
+#endif
 	tspi->gpio_slave_ready = pdata->gpio_slave_ready;
 
 	tegra_clk_pin_control(false, tspi);

Hi @ShaneCCC.

Thank you for your help. Could you share more about the loopback test setup? Did you connect the output from SPI0 to SPI1? Also how did you run the test? Did you use the spidev_test? How did you invoke it?

-Chinmay

Hi notthetup
Yes, we are reworked for SPI1A to SPI2A loopback and run spidev tests.

commands to be run:

  1. to enable SPI2A pinmux
    cat /sys/bus/platform/devices/7000d600.spi/force_unpacked_mode

  2. spidev test:
    MISO
    ./spidev_test -zz -D/dev/spidev1.0 -n1 -s10000000 -g16 -p1 -H -t -d1000000 &
    ./spidev_test -zz -D/dev/spidev0.0 -n1 -s10000000 -g16 -p1 -H -r
    MOSI
    ./spidev_test -zz -D/dev/spidev1.0 -n1 -s10000000 -g16 -p1 -H -r -d1000000 &
    ./spidev_test -D/dev/spidev0.0 -n1 -s10000000 -g16 -p1 -H -t

Attached debug change that use to enable pinmux for SPI2A and run spidev tests.

diff --git a/arch/arm64/boot/dts/tegra210-ers-e2220-1170-a00-00-common.dts b/arch/arm64/boot/dts/tegra210-ers-e2220-1170-a00-00-common.dts
index 48e03b8..ea27954 100644
--- a/arch/arm64/boot/dts/tegra210-ers-e2220-1170-a00-00-common.dts
+++ b/arch/arm64/boot/dts/tegra210-ers-e2220-1170-a00-00-common.dts
@@ -244,6 +244,7 @@
 	spi@7000d400 {
 		status = "okay";
 		earSmart: earSmart-codec@0 {
+			status = "disabled";
 			compatible = "adnc,earSmart-codec";
 			reg = <0>;
 			spi-max-frequency = <6000000>;
@@ -631,6 +632,10 @@
 		};
 	};
 
+	spi@7000d600 {
+		status = "okay";
+	};
+
 	spi@7000da00 {
 		status = "okay";
 		spi-max-frequency = <25000000>;
diff --git a/arch/arm64/boot/dts/tegra210-platforms/tegra210-ers-pinmux-e2220-1170-a00.dtsi b/arch/arm64/boot/dts/tegra210-platforms/tegra210-ers-pinmux-e2220-1170-a00.dtsi
index 2ef66e7..a5f989d 100644
--- a/arch/arm64/boot/dts/tegra210-platforms/tegra210-ers-pinmux-e2220-1170-a00.dtsi
+++ b/arch/arm64/boot/dts/tegra210-platforms/tegra210-ers-pinmux-e2220-1170-a00.dtsi
@@ -699,6 +699,46 @@
 				nvidia,enable-input = <TEGRA_PIN_DISABLE>;
 			};
 
+			spi2_mosi_pb4 {
+				nvidia,pins = "spi2_mosi_pb4";
+				nvidia,function = "spi2";
+				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+				nvidia,tristate = <TEGRA_PIN_DISABLE>;
+				nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+			};
+
+			spi2_miso_pb5 {
+				nvidia,pins = "spi2_miso_pb5";
+				nvidia,function = "spi2";
+				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+				nvidia,tristate = <TEGRA_PIN_DISABLE>;
+				nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+			};
+
+			spi2_sck_pb6 {
+				nvidia,pins = "spi2_sck_pb6";
+				nvidia,function = "spi2";
+				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+				nvidia,tristate = <TEGRA_PIN_DISABLE>;
+				nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+			};
+
+			spi2_cs0_pb7 {
+				nvidia,pins = "spi2_cs0_pb7";
+				nvidia,function = "spi2";
+				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+				nvidia,tristate = <TEGRA_PIN_DISABLE>;
+				nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+			};
+
+			spi2_cs1_pdd0 {
+				nvidia,pins = "spi2_cs1_pdd0";
+				nvidia,function = "spi2";
+				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+				nvidia,tristate = <TEGRA_PIN_DISABLE>;
+				nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+			};
+
 			uart3_tx_pd1 {
 				nvidia,pins = "uart3_tx_pd1";
 				nvidia,function = "uartc";
@@ -870,14 +910,6 @@
 				nvidia,enable-input = <TEGRA_PIN_ENABLE>;
 			};
 
-			spi2_mosi_pb4 {
-				nvidia,pins = "spi2_mosi_pb4";
-				nvidia,function = "rsvd2";
-				nvidia,pull = <TEGRA_PIN_PULL_UP>;
-				nvidia,tristate = <TEGRA_PIN_DISABLE>;
-				nvidia,enable-input = <TEGRA_PIN_ENABLE>;
-			};
-
 			pe6 {
 				nvidia,pins = "pe6";
 				nvidia,function = "rsvd0";
@@ -1307,37 +1339,6 @@
 		};
 
 		pinmux_unused_lowpower: unused_lowpower {
-			spi2_miso_pb5 {
-				nvidia,pins = "spi2_miso_pb5";
-				nvidia,function = "rsvd2";
-				nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
-				nvidia,tristate = <TEGRA_PIN_ENABLE>;
-				nvidia,enable-input = <TEGRA_PIN_DISABLE>;
-			};
-
-			spi2_sck_pb6 {
-				nvidia,pins = "spi2_sck_pb6";
-				nvidia,function = "rsvd2";
-				nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
-				nvidia,tristate = <TEGRA_PIN_ENABLE>;
-				nvidia,enable-input = <TEGRA_PIN_DISABLE>;
-			};
-
-			spi2_cs0_pb7 {
-				nvidia,pins = "spi2_cs0_pb7";
-				nvidia,function = "rsvd2";
-				nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
-				nvidia,tristate = <TEGRA_PIN_ENABLE>;
-				nvidia,enable-input = <TEGRA_PIN_DISABLE>;
-			};
-
-			spi2_cs1_pdd0 {
-				nvidia,pins = "spi2_cs1_pdd0";
-				nvidia,function = "rsvd1";
-				nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
-				nvidia,tristate = <TEGRA_PIN_ENABLE>;
-				nvidia,enable-input = <TEGRA_PIN_DISABLE>;
-			};
 		};
 
 		drive_default: drive {
diff --git a/arch/arm64/boot/dts/tegra210-soc-base.dtsi b/arch/arm64/boot/dts/tegra210-soc-base.dtsi
index 7344057..a91f9b8 100644
--- a/arch/arm64/boot/dts/tegra210-soc-base.dtsi
+++ b/arch/arm64/boot/dts/tegra210-soc-base.dtsi
@@ -689,9 +689,38 @@
 		dmas = <&apbdma 15>, <&apbdma 15>;
 		dma-names = "rx", "tx";
 		nvidia,clk-parents = "pll_p", "clk_m";
-		status = "disabled";
+		status = "okay";
+		spi0_0 {
+			compatible = "spidev";
+			reg = <0x0>;
+			spi-max-frequency = <0x1312d00>;
+		};
+	};
+
+	spi1: spi@7000d600 {
+		status = "okay";
+		compatible = "nvidia,tegra124-spi-slave";
+		reg = <0x0 0x7000d600 0x0 0x200>;
+		interrupts = <0 82 0x04>;
+		nvidia,dma-request-selector = <&apbdma 16>;
+		iommus = <&smmu TEGRA_SWGROUP_PPCS>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		dmas = <&apbdma 16>, <&apbdma 16>;
+		dma-names = "rx", "tx";
+		nvidia,clk-parents = "pll_p", "clk_m";
+		nvidia,rx-trigger-words = <0>;
+		spi1_0 {
+			compatible = "spidev";
+			reg = <0x0>;
+			spi-max-frequency = <0x1312d00>;
+		};
 	};
 
+	/*	nvidia,clk-pin = "gpio_x5_aud_px5";
+		nvidia,gpio-slave-ready = <&gpio TEGRA_GPIO(K, 4) 0>; / *PK4* /
+		nvidia,gpio-slave-ready-active-high;*/
+/*
 	spi1: spi@7000d600 {
 		compatible = "nvidia,tegra210-spi";
 		reg = <0x0 0x7000d600 0x0 0x200>;
@@ -705,6 +734,7 @@
 		nvidia,clk-parents = "pll_p", "clk_m";
 		status = "disabled";
 	};
+*/
 
 	spi2: spi@7000d800 {
 		compatible = "nvidia,tegra210-spi";
diff --git a/arch/arm64/configs/tegra21_defconfig b/arch/arm64/configs/tegra21_defconfig
index 6b51b2d..48b1fe3 100644
--- a/arch/arm64/configs/tegra21_defconfig
+++ b/arch/arm64/configs/tegra21_defconfig
@@ -1,6 +1,7 @@
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
@@ -60,7 +61,6 @@ CONFIG_ARMV7_COMPAT=y
 CONFIG_ZSMALLOC=y
 CONFIG_SECCOMP=y
 CONFIG_COMPAT=y
-CONFIG_FHANDLE=y
 # CONFIG_HAS_WAKELOCK is not set
 # CONFIG_WAKELOCK is not set
 CONFIG_PM_RUNTIME=y
@@ -260,7 +260,6 @@ CONFIG_VETH=y
 CONFIG_TIGON3=y
 CONFIG_E1000E=y
 CONFIG_IGB=m
-CONFIG_IGB_HWMON=y
 CONFIG_R8169=y
 CONFIG_SMC91X=y
 CONFIG_SMSC911X=y
@@ -318,10 +317,11 @@ CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_MUX_PCA954x=y
-CONFIG_I2C_IOEXPANDER_PCA9570=y
 CONFIG_I2C_TEGRA=y
 CONFIG_SPI=y
 CONFIG_SPI_TEGRA114=y
+CONFIG_SPI_TEGRA114_SLAVE=y
+CONFIG_SPI_SPIDEV=y
 CONFIG_PINCTRL_MAX77620=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_PCA953X=y
@@ -371,23 +371,22 @@ CONFIG_VIDEO_AD5823=y
 CONFIG_VIDEO_DW9718=y
 CONFIG_VIDEO_DW9714=y
 CONFIG_VIDEO_MT9M114=y
-CONFIG_VIDEO_IMX185=y
+CONFIG_VIDEO_IMX219=y
 CONFIG_VIDEO_CAMERA=y
 # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-CONFIG_VIDEO_I2C_OV5693=y
 CONFIG_VIDEO_IMX214=y
-CONFIG_VIDEO_IMX219=y
-CONFIG_VIDEO_IMX274=y
-CONFIG_VIDEO_OV23850=y
 CONFIG_VIDEO_LC898212=y
+CONFIG_VIDEO_I2C_OV5693=y
+CONFIG_VIDEO_OV23850=y
+CONFIG_VIDEO_IMX274=y
+CONFIG_VIDEO_IMX185=y
+CONFIG_I2C_IOEXPANDER_PCA9570=y
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
 CONFIG_TEGRA_GRHOST=y
 CONFIG_TEGRA_GRHOST_VII2C=y
 CONFIG_TEGRA_DC=y
-CONFIG_TEGRA_DP=y
 CONFIG_TEGRA_DSI=y
-CONFIG_TEGRA_DP=y
 CONFIG_TEGRA_HDMI2_0=y
 # CONFIG_TEGRA_CAMERA is not set
 CONFIG_NVHOST_BONDOUT_CHECK=y
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index a5e37f6..61c801f 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -882,26 +882,26 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
 		if (i2c_dev->msg_buf_remaining)
 			tegra_i2c_empty_rx_fifo(i2c_dev);
 		else {
-			dev_err(i2c_dev->dev, "--- register dump for buffer remain == 0----\n");
-			dev_err(i2c_dev->dev, "I2C_CNFG - 0x%x\n",
+			dev_dbg(i2c_dev->dev, "--- register dump for buffer remain == 0----\n");
+			dev_dbg(i2c_dev->dev, "I2C_CNFG - 0x%x\n",
 					i2c_readl(i2c_dev, I2C_CNFG));
-			dev_err(i2c_dev->dev, "I2C_PACKET_TRANSFER_STATUS - 0x%x\n",
+			dev_dbg(i2c_dev->dev, "I2C_PACKET_TRANSFER_STATUS - 0x%x\n",
 					i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS));
-			dev_err(i2c_dev->dev, "I2C_FIFO_CONTROL - 0x%x\n",
+			dev_dbg(i2c_dev->dev, "I2C_FIFO_CONTROL - 0x%x\n",
 					i2c_readl(i2c_dev, I2C_FIFO_CONTROL));
-			dev_err(i2c_dev->dev, "I2C_FIFO_STATUS - 0x%x\n",
+			dev_dbg(i2c_dev->dev, "I2C_FIFO_STATUS - 0x%x\n",
 					i2c_readl(i2c_dev, I2C_FIFO_STATUS));
-			dev_err(i2c_dev->dev, "I2C_INT_MASK - 0x%x\n",
+			dev_dbg(i2c_dev->dev, "I2C_INT_MASK - 0x%x\n",
 					i2c_readl(i2c_dev, I2C_INT_MASK));
-			dev_err(i2c_dev->dev, "I2C_INT_STATUS - 0x%x\n",
+			dev_dbg(i2c_dev->dev, "I2C_INT_STATUS - 0x%x\n",
 					i2c_readl(i2c_dev, I2C_INT_STATUS));
-			dev_err(i2c_dev->dev, "msg_err - 0x%x, msg_read - 0x%x, msg_add - 0x%x\n",
+			dev_dbg(i2c_dev->dev, "msg_err - 0x%x, msg_read - 0x%x, msg_add - 0x%x\n",
 					i2c_dev->msg_err, i2c_dev->msg_read, i2c_dev->msg_add);
 			if (i2c_dev->msgs) {
 				struct i2c_msg *msgs = i2c_dev->msgs;
 				int i;
 				for (i = 0; i < i2c_dev->msgs_num; i++)
-					dev_err(i2c_dev->dev,
+					dev_dbg(i2c_dev->dev,
 							"msgs[%d] %c, addr=0x%04x, len=%d\n",
 							i, (msgs[i].flags & I2C_M_RD) ? 'R' : 'W',
 							msgs[i].addr, msgs[i].len);
@@ -1209,7 +1209,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
 	ret = wait_for_completion_timeout(&i2c_dev->msg_complete,
 					TEGRA_I2C_TIMEOUT);
-	if (ret == 0) {
+	if (0) {
 		dev_err(i2c_dev->dev, "--- register dump for debugging ----\n");
 		dev_err(i2c_dev->dev, "I2C_CNFG - 0x%x\n",
 			i2c_readl(i2c_dev, I2C_CNFG));
@@ -1247,7 +1247,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 		tegra_i2c_disable_packet_mode(i2c_dev);
 
 	if (ret == 0) {
-		dev_err(i2c_dev->dev,
+		dev_dbg(i2c_dev->dev,
 			"i2c transfer timed out, addr 0x%04x, data 0x%02x\n",
 			msg->addr, msg->buf[0]);
 
diff --git a/drivers/spi/spi-tegra124-slave.c b/drivers/spi/spi-tegra124-slave.c
index 8d749b2..cdb51fa 100644
--- a/drivers/spi/spi-tegra124-slave.c
+++ b/drivers/spi/spi-tegra124-slave.c
@@ -360,6 +360,18 @@ static int tegra_spi_validate_request(struct spi_device *spi,
 			struct tegra_spi_data *tspi, struct spi_transfer *t);
 static int tegra_clk_pin_control(bool enable, struct tegra_spi_data *tspi);
 
+#include "../../../arch/arm/mach-tegra/iomap.h"
+void __iomem *pinbase = IO_ADDRESS(0x70000000);
+
+void spi2_pinmux(void)
+{
+	writel(0x00000040, pinbase + 0x3064);
+	writel(0x00000040, pinbase + 0x3068);
+	writel(0x00000040, pinbase + 0x306c);
+	writel(0x00000040, pinbase + 0x3070);
+	writel(0x00000040, pinbase + 0x3074);
+}
+
 #ifdef TEGRA_SPI_SLAVE_DEBUG
 static ssize_t force_unpacked_mode_set(struct device *dev,
 				  struct device_attribute *attr,
@@ -383,6 +395,7 @@ static ssize_t force_unpacked_mode_show(struct device *dev,
 {
 	struct tegra_spi_data *tspi;
 	struct spi_master *master = dev_get_drvdata(dev);
+	spi2_pinmux();
 	if (master) {
 		tspi = spi_master_get_devdata(master);
 		return sprintf(buf, "%d", tspi->force_unpacked_mode);
@@ -1759,6 +1772,8 @@ static int tegra_spi_probe(struct platform_device *pdev)
 	tspi->dma_req_sel = pdata->dma_req_sel;
 	tspi->clock_always_on = pdata->is_clkon_always;
 	tspi->rx_trig_words = pdata->rx_trig_words;
+	tspi->clk_pin = NULL;
+#if 0
 	tspi->clk_pin = (char *)pdata->clk_pin;
 	if (tspi->clk_pin) {
 		tspi->clk_pin_state_enabled = true;
@@ -1781,7 +1796,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "Pin group name for clock line is not defined.\n");
 		goto exit_free_master;
 	}
-
+#endif
 	tspi->gpio_slave_ready = pdata->gpio_slave_ready;
 
 	tegra_clk_pin_control(false, tspi);

Hi, ShaneCCC,

I have some questions.

I firstly created spidev0.0 for SPI master by following the contents of the website, http://elinux.org/Jetson/TX1_SPI.
In this case, for the loopback test, I installed a short wire between pins 19 & 21 and succeeded it.

Now I am trying to enable SPI-slave mode.
I referred to your post(#8 above) and modified device tree and spi-tegra124-slave.c.
spidev and spidev-slave modules are successfully loaded and two devices nodes (spidev0.0 and spidev1.0) are created.

To my understanding, spidev1.0 should be used to receive data from a SPI master device.
Am I right?
If yes, which pins should be used for connecting Jetson TX1 to SPI master devices?
Are they 19 (MOSI), 21(MISO), 23(CLK), and 24(CS)?

And, where can I find any example code for SPI-slave mode (e.g., a program that receives data from a SPI master device)?

Thank you in advance.
Cheers,
HyunYong.

My #8 comment is set SPI1.0 as slave mode and wired jump to SPI0.0 for verify.
The pin 19 (MOSI), 21(MISO), 23(CLK), and 24(CS) is the SPI0.0(spi@7000d400) and spi1.0(spi@7000d600) is on the camera expansion board show as below.
You can select one of them for your case. And program the select one to slave mode.

Hi, ShaneCCC

Thank you for your kind help.

To verify a functionality of SPI-slave mode Jetson TX1 (using /dev/spidev0.0), I got one SPI-master device.
I connected the SPI-master device to Jetson TX1 as you said.

Now, I am trying to read messages from the SPI-master device (that transfers a message every 1 second).
For this, I’ve tried to use ‘spidev_test.c’ code (which is found in sources/kernel/Documentation/spi).
But, I could not make it.

Could you provide a sample code for this case or guide me to relevant information ?

Thank you in advance.

Cheers,
HyunYong.

Hi Enoch
Did you probe the SPI bus to check any data from master?

Hi all,

I made some progress and want to share that.

  1. Environment

Jetson TX1 (SPI-slave) <–(using 19,21,23,24 gpio pins for spidev0.0)–> a SPI-master device (sends a message every 1 second)

  1. .dts file

Basically I followed the guideline in #8 above.
I just used SPI0.0(spi@7000d400) as the SPI-slave device. I mean I created spidev0.0 only.

Regarding the compilation of SPI-slave kernel module and the device tree, http://elinux.org/Jetson/TX1_SPI should be helpful.

  1. Code modification

In addition to the modification mentioned in #5 and #8 (for spi-tegra124-slave.c) above, I made the following change.

in spi-tegra124-slave.c file

if (!tspi->variable_length_transfer &&
tspi->words_to_transfer !=
tspi->curr_xfer->len/tspi->bytes_per_word) {
dump_regs(err_ratelimited, tspi, “transferred[%d] != requested[%d]”, tspi->words_to_transfer, tspi->curr_xfer->len/tspi->bytes_per_w ord);

  •             tspi->words_to_transfer = tspi->curr_xfer->len/tspi->bytes_per_word;
    
  •             tspi->tx_status = SPI_TX_FIFO_UNF;
    
  •            tspi->rx_status = SPI_RX_FIFO_OVF;
    
  •             //tspi->tx_status = SPI_TX_FIFO_UNF;
    
  •            //tspi->rx_status = SPI_RX_FIFO_OVF;
       }
    
  1. Test

For the test, I used spidev_test.c (which is found in sources/kernel/Documentation/spi).
I manusally set the speed of spidev0.0 to that of SPI master device.
I used “-d (delay)” option. (i.e., ]$ sudo ./spidev_test -d 100)
In addition, I set the size of transmission buffer of spi_ioc_transfer structure to 0.
struct spi_ioc_transfer tr = {
.tx_buf = 0,

With above setting, in my case, spidev_test program reads the data from the mSPI-master device successfully.

Cheers,
HyunYong.

Awesome, great to heard it. Thanks for your update.

Hi all,

I have some questions.

I created spidev0.0 for SPI master as #11 say,and I installed a short wire between pins 19&21 and succeeded it.

I did the same things in TK1(created spidev0.0 and the lookback test is worked.)

Now I am trying use TX1 as a slave and TK1 as a master.

I’ve done kernel configuration about SPI slave mode in TX1 as #15 say,and modified .dts file and copy to /boot and edited extlinux.conf file,after reboot I type "lsmod"and “ls /dev” in terminal I could see spidev and spi-tegra124-slave module and spidev0.0 file.

What should I do to make these two devices communicating with each other by SPI?

Sorry guys, I need to ask a stupid question…

After making the modifications to the spi-tegra124-slave.c as suggested eariler… I can compile the source file, make an object file, but what do I do after that? I keep getting the “Pin group name for clock line is not defined” even though I removed it from the source file. I believe the newly compiled spi-tegra124-slave.c is NOT where it should be on bootup.

Can someone just break it down in simple terms how I can put the new spi-tegra124-slave.o into bootup?

Thanks.

David.

Hi David,

The spi-tegra124-slave.c is a part of the Linux kernel drivers and needs to be compiled as a kernel module (.ko) file. You can then load it manually using insmod.

Thanks ‘nottheup’, so I can just use the SpiDev kernel module to use the spi-tegra124-slave kernel module.