About

Controlling the SPI bus from userspace allows you to communicate with SPI devices without messing with kernel drivers, which can be painful and make you reboot often.

Setup

See the tutorial for building the image, but before launching "make" apply this patch:

diff --git a/target/linux/ramips/files/arch/mips/ralink/rt305x/mach-carambola.c b/target/linux/ramips/files/arch/mips/ralink/rt305x/mach-carambola.c
index baa23c1..66d1930 100644
--- a/target/linux/ramips/files/arch/mips/ralink/rt305x/mach-carambola.c
+++ b/target/linux/ramips/files/arch/mips/ralink/rt305x/mach-carambola.c
@@ -21,9 +21,12 @@
 #include <asm/sizes.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
+#include <linux/spi/spi.h>
 
 #include "devices.h"
 
+#define CONFIG_MTD_PARTITIONS 1
+
 #ifdef CONFIG_MTD_PARTITIONS
 
 #define CARAMBOLA_UBOOT_SIZE   0x030000 /*  192KB */
@@ -62,12 +65,12 @@ static struct mtd_partition carambola_partitions[] = {
 };
 #endif /* CONFIG_MTD_PARTITIONS */
 
-static struct physmap_flash_data carambola_flash_data = {
-#ifdef CONFIG_MTD_PARTITIONS
-       .nr_parts       = ARRAY_SIZE(carambola_partitions),
-       .parts          = carambola_partitions,
-#endif
-};
+// static struct physmap_flash_data carambola_flash_data = {
+// #ifdef CONFIG_MTD_PARTITIONS
+//     .nr_parts       = ARRAY_SIZE(carambola_partitions),
+//     .parts          = carambola_partitions,
+// #endif
+// };
 
 
 static int __init carambola_register_gpiodev(void)
@@ -99,6 +102,16 @@ static struct platform_device carambola_i2c_gpio = {
        },
 };
 
+struct spi_board_info carambola_spi_dev_info[] __initdata = {
+    {
+        .modalias   = "spidev",
+        .max_speed_hz   = 10000000,
+        .bus_num    = 0,
+        .chip_select    = 0,
+        .mode = SPI_MODE_0,
+    },
+};
+
 static struct platform_device *carambola_devices[] __initdata = {
         &carambola_i2c_gpio
 };
@@ -106,10 +119,16 @@ static struct platform_device *carambola_devices[] __initdata = {
 static void __init carambola_init(void)
 {
        rt305x_gpio_init((RT305X_GPIO_MODE_GPIO << RT305X_GPIO_MODE_UART0_SHIFT) |
-                        RT305X_GPIO_MODE_I2C);
+                        RT305X_GPIO_MODE_I2C | RT305X_GPIO_MODE_SPI);
        carambola_register_gpiodev();
+    rt305x_register_spi(carambola_spi_dev_info, 
+                           ARRAY_SIZE(carambola_spi_dev_info));
        platform_add_devices(carambola_devices, ARRAY_SIZE(carambola_devices));
-       rt305x_register_flash(0, &carambola_flash_data);
+    #ifdef CONFIG_MTD_PARTITIONS
+    rt305x_flash0_data.nr_parts = ARRAY_SIZE(carambola_partitions);
+    rt305x_flash0_data.parts = carambola_partitions;
+    #endif
+       rt305x_register_flash(0);
 
        rt305x_esw_data.vlan_config = RT305X_ESW_VLAN_CONFIG_LLLLW;
        rt305x_register_ethernet();

After compiling the image, you should find the file /dev/spidev0.0

Enabling the SPI bus controller

To "connect" the bus to the actual pins (instead of using them as GPIOs) use the 'io' tool to clear the bit 1 of the memory address 0x10000060

io 0x10000060 0x1d

Coding