VoCore2 SPI: full duplex

mt7628a has a wafer/silicon bug on SPI, we can not use its SPI in full duplex mode, but we can use bitbang for that mode. For some device do not support half-duplex, maybe this is the only way.

To enable bitbang on VoCore2, we need to modify Linux kernel code, VOCORE2.DTS and kernel setting.

Setup Kernel Setting

  1. call “make kernel_menuconfig”
  2. In menu, select “Device Drivers” => “SPI Support” => <*>   GPIO-based bitbanging SPI Master

VOCORE2.dts

This file is in target/linux/ramips/dts, example of the DTS. We need to set the driver to “spi-gpio” and pinctrl set the pins to GPIO mode.

/dts-v1/;

#include "VOCORE2.dtsi"

#include <dt-bindings/gpio/gpio.h>

/ {
	compatible = "vocore,vocore2", "mediatek,mt7628an-soc";
	model = "VoCore2";

	gpio-leds {
		compatible = "gpio-leds";

		status {
			label = "vocore2:fuchsia:status";
			gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
		};
	};

	spi1: spi-gpio {
		status = "okay";

		compatible = "spi-gpio";

		gpio-sck = <&gpio0 7 1>;
        	gpio-miso = <&gpio0 9 1>;
        	gpio-mosi = <&gpio0 8 1>;

        	cs-gpios = <&gpio0 10 1>, <&gpio0 6 1>;
        	num-chipselects = <2>;
	};
};

&pinctrl {
        state_default: pinctrl0 {
                spi {
                        ralink,group = "spi";
                        ralink,function = "gpio";
                };
                spi_cs1 {
                        ralink,group = "spi cs1";
                        ralink,function = "gpio";
                };
        };
};

&i2c {
	status = "okay";
};

&spi1 {
	m25p80@0 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "jedec,spi-nor";
		reg = <0>;
		spi-max-frequency = <10000000>;
		m25p,chunked-io = <32>;

		partition@0 {
			label = "u-boot";
			reg = <0x0 0x30000>;
			read-only;
		};

		partition@30000 {
			label = "u-boot-env";
			reg = <0x30000 0x10000>;
			read-only;
		};

		factory: partition@40000 {
			label = "factory";
			reg = <0x40000 0x10000>;
			read-only;
		};

		partition@50000 {
			label = "firmware";
			reg = <0x50000 0xfb0000>;
		};
	};

	spidev@1 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "rohm,dh2228fv";
		reg = <1>;
		spi-max-frequency = <10000000>;
	};
};

Patch Linux spi-gpio.c

This is because CS1 pins has a default pull low resistor. If we do not patch it, CS1 will be low at startup, conflict with the flash driver who use CS0. So we must at startup setup CS1 pin to output and value to high.

                if (!SPI_N_CHIPSEL)
                        spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT;
                else
                        for (i = 0; i < SPI_N_CHIPSEL; i++) {
                                status = of_get_named_gpio(np, "cs-gpios", i);
                                if (status < 0) {
                                        dev_err(&pdev->dev,
                                                "invalid cs-gpios property\n");
                                        goto gpio_free;
                                }
                                spi_gpio->cs_gpios[i] = status;

+                               gpio_request(status, dev_name(&pdev->dev));
+                               gpio_direction_output(status, 1);
+                               gpio_free(status);
                        }
        }
#endif

        spi_gpio->bitbang.master = master;
        spi_gpio->bitbang.chipselect = spi_gpio_chipselect;

That is all 🙂 Now the firmware is able to support SPI device in full duplex mode.