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:1196
and 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 (CONFIG_I2C_DESIGNWARE_CORE=m
and
CONFIG_I2C_DESIGNWARE_PCI=m
).
After recompiling the kernel, the LKMs can be inserted using
modprobe
or 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.