Accessing I2C Devices in Linux Print


The Linux kernel provides a device driver for the I2C controller of the LPC4357, enabled in the kernel with the CONFIG_I2C_LPC2K build-time option. To enable the driver in the kernel configuration, run make kmenuconfig in your project directory, go to Device Drivers and enable I2C support. Then go to I2C bus support for NXP LPC2K and LPC178x targets:

Another kernel configuration option that you will require is CONFIG_I2C_CHARDEV. This option enables the kernel API that allows accessing I2C devices from user-space application code. To enable CONFIG_I2C_CHARDEV, proceed to Device Drivers, then go to I2C support and in there enable I2C device interface:

Having enabled CONFIG_I2C_LPC2K, go to System Type ->LPC18xx I/O interfaces and enable the specific I2C interfaces you require in your application:

Do not enable any I2C interfaces except for those that you plan to use in your application. For one thing, unless an I2C interface is actually required, you want to keep it in reset in order to save some power. Another consideration is that I2C signals may conflict with other I/O interfaces on the LPC4357 pins. More on that right below.

Allocation of the LPC4357 pins to specific I/O interfaces is defined in linux/arch/arm/mach-18xx/iomux.c. When you have enabled I2C interfaces that you require in your application, make sure that there is appropriate code in iomux.c that routes the I2C signals to those LPC4357 pins that you have allocated for I2C in your application. For example, for I2C0 there is the following code defined in iomux.c:

#if defined(CONFIG_LPC18XX_I2C0)
writel(LPC18XX_SFSI2C0_CONFIG, LPC18XX_SFSI2C0);
#endif

There must be a device node in the target root file system for each I2C interface you enable to allow accessing it using standard Linux interfaces. Add the following lines into your <project>.initramfs file to create device nodes for all 3 I2C interfaces:

nod /dev/i2c-0 0666 0 0 c 89 0
nod /dev/i2c-1 0666 0 0 c 89 1
nod /dev/i2c-2 0666 0 0 c 89 2

The Emcraft uClinux distribution includes the Linux tools that can be used to access I2C devices from user space. Add the following lines to your <project>.initramfs file in order to add these tools to the target file system:

file /usr/sbin/i2cdetect ${INSTALL_ROOT}/A2F/root/usr/sbin/i2cdetect 755 0 0
file /usr/sbin/i2cdump ${INSTALL_ROOT}/A2F/root/usr/sbin/i2cdump 755 0 0
file /usr/sbin/i2cget ${INSTALL_ROOT}/A2F/root/usr/sbin/i2cget 755 0 0
file /usr/sbin/i2cset ${INSTALL_ROOT}/A2F/root/usr/sbin/i2cset 755 0 0

Having updated your project configuration as described above, build the bootable Linux image (<project>.uImage) by running make in the project directory.

When you load the uImage to the target, the kernel will register a platform device for the I2C0 controller. You should see the following line in the kernel boot messages on the target:

...
I2C: i2c-0: LPC2K I2C adapter
...

Run the Linux I2C tools to examine I2C devices on your target. For instance, the following command scans the I2C0 interface and reports any devices it detects on the bus:

~ # i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- 1a -- -- 1d -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: 50 51 52 53 54 55 56 57 -- -- -- -- -- -- -- --
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Refer to documentation available from the Internet for detailed manuals on the Linux I2C tools, for instance:
http://www.lm-sensors.org/wiki/i2cToolsDocumentation

In all likelihood, you will want to develop your own application code to access specific I2C devices on your embedded device. Search the Internet for CONFIG_I2C_CHARDEV to get pointers to many materials describing how to do that. For instance, the following article provides a demo user-space application that shows how to access an I2C sensor from C code:
http://andicelabs.com/2013/06/linux-using-i2c-from-user-land/