Intel Edison: i2c-6 with vanilla Linux
Thanks to the amazing work of Andy Shevchenko, it’s possible to run recent vanilla Linux kernels on Intel’s discontinued Edison module. There is a nice writeup about this available on the web. One of the drawbacks of this approach, however, is that one of the two user-accessible I2C bus controllers is not available: i2c-6. This is due to the fact, that initially it’s configured to be used by the SCU and there is no way to change this.
In order to use i2c-6, a pinctrl setting needs to be applied. This can be done using a pinctrl mapping in the board specific initialization code. That makes the pinctrl setting to be applied once the device in question (here i2c-6) is probed. When I did this, however, I could see that the pinmux was claimed by the i2c-6 device but the pins’ mode was still set to 2 which is wrong:
$ mount -t debugfs non /sys/kernel/debug/ $ cat /sys/kernel/debug/pinctrl/pinctrl-merrifield/pinmux-pins | grep I2C_6 pin 111 (GP27_I2C_6_SCL): 0000:00:09.1 (GPIO UNCLAIMED) function i2c6 group i2c6_grp pin 112 (GP28_I2C_6_SDA): 0000:00:09.1 (GPIO UNCLAIMED) function i2c6 group i2c6_grp $ cat /sys/kernel/debug/pinctrl/pinctrl-merrifield/pins | grep I2C_6 pin 111 (GP27_I2C_6_SCL) mode 2 0x00203512 pin 112 (GP28_I2C_6_SDA) mode 2 0x00203592
So I dug a little into the code and looked at the function
mrfld_pinmux_set_mux in particular. The pinctrl settings for the pins in question are write-protected, which means that changing them requires an SCU IPC call, see
mrfld_update_phys. That IPC call, however, returned
-ENODEV because the SCU device is not probed by the time i2c-6 is probed which in turn triggers setting the pinmux.
Both the I2C controller and the SCU are PCI devices with vendor/device ID equal to
8086:11a0, respectively. Typically, the PCI bus is enumerated in order, which means that the I2C bus devices will be probed before the SCU device since the device ID is smaller. To circumvent this, I configured the I2C bus driver to be built as lodable kernel modules (
After recompiling the kernel, the LKMs can be inserted using
insmod. Not only will this succeed now, but the pins’ mode will change as well:
$ cat /sys/kernel/debug/pinctrl/pinctrl-merrifield/pins | grep I2C_6 pin 111 (GP27_I2C_6_SCL) mode 1 0x00000511 pin 112 (GP28_I2C_6_SDA) mode 1 0x00000591
The changes that were required in the Linux kernel can be found in my GitHub repo.