Add I2C
Our file of interest will be qemu/hw/arm/vexpress.c. Open it. First step will be to define I2C controller in this big enum at the beginning of file. Let's add VE_I2C as last item. Next step will be to define memory region for this controller, let's say 0x50000000 (and hope that it won't overlap with others). Put it into motherboard_legacy_map and motherboard_aseries_map.[VE_I2C] = 0x50000000legacy_map is used in a9_daughterboard, which we're using in our simulation, adding this to the other one will just simplify things. Now, initialization. To complete this we need to modify vexpress_common_init function to proper add I2C bus to our board. We need to create new versatile_i2c device. Put following line of code:
dev = sysbus_create_simple("versatile_i2c", map[VE_I2C], NULL);somewhere near other calls to this function, for example after creating pl111 device. We're done with bus.
Add sensor
Next step is to attach temperature sensor to I2C bus. This is as simple as adding i2c bus itself. Define I2CBus *i2c variable and put following line to obtain pointer to bus object:i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");Now we are able to attach our sensor to this bus by calling
i2c_create_slave(i2c, "tmp105", 0x68);Where 0x68 is our I2C device address. To make this compile properly we need to include hw/i2c/i2c.h. Type make and make install. You're now done with this part.
Kernel support
In order to support tmp105 device we need a driver in kernel. Driver responsible for this sensor is LM75 driver: linux-stable/drivers/hwmon/lm75.c. Quick look at linux-stable/drivers/hwmon/Makefile reveals that we need to set CONFIG_SENSORS_LM75 in kernel configuration. Go to buildroot and type make linux-menuconfig, find proper entry (for example type "/" to open search box and type LM75, press "1" as it will be the first search result, press two times space to mark this entry as "*" - we don't need module). Now we can rebuild kernel by make linux-rebuild.Device tree
This is first time when we use device tree. Device tree is form of describing hardware on the board. I won't go much into details, you can read something about it at http://www.devicetree.org/Device_Tree_Usage. First we need to edit linux-stable/arch/arm/boot/dts/vexpress-v2p-ca9.dts. Add following entry:i2c: i2c@50000000 {Now run make menuconfig in buildroot directory. Go to Kernel, check Build a Device Tree Blob and put "vexpress-v2p-ca9" into Device Tree Source file names. Save and exit. Run make linux-rebuild. Now you should have vexpress-v2p-ca9.dtb file created in your output/images directory of buildroot.
#address-cells = <1>;
#size-cells = <0>;
compatible = "arm,versatile-i2c";
reg = <0x50000000 0x1000>;
tmp105@68 {
compatible = "ti,tmp105";
reg = <0x68>;
};
};
Running
Now we should be able to run our custom qemu with our custom kernel and custom device tree file. Something like this would be sufficient (just remember to pass correct paths):~/opt/bin/qemu-system-arm -M vexpress-a9 -kernel images/zImage -drive file=./images/rootfs.ext2,if=sd -append "console=ttyAMA0,115200 root=/dev/mmcblk0" -serial stdio -dtb images/vexpress-v2p-ca9.dtbLogin as root and check out following directories:
- /sys/devices/50000000.i2c/
- /sys/devices/50000000.i2c/i2c-0/0-0068/
cat /sys/devices/50000000.i2c/i2c-0/0-0068/hwmon/hwmon0/temp1_inputAnd check device type by
cat /sys/devices/50000000.i2c/i2c-0/0-0068/hwmon/hwmon0/nameThat's enough hacking for today ;).
Homework: Figure out how this driver and device is working. You can pass new value for temperature via "-device tmp105,temperature=11" qemu command line. This will call tmp105_set_temperature from hw/misc/tmp105.c. Have fun!