Developing a Linux driver for a chip with I2C registers
In the past I have always hauled around a simple i2c Linux app I wrote so I could read and write I2C registers when I tried to make sense of some confusing datasheet. This was in the dark ages before there was a standard I2C sub-system in Linux.
Recently while working on a touch screen driver for the TI TPS65070 chip (the combo analog chip for the way cool OMAP-L138 SoC), I came across i2c-tools from the folks over at lm-sensors. After a quick port to the SDK framework, I ran the i2cdetect tool and got the output:
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- 08 -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 20: -- 21 -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- UU -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
UU means a chip was detects and since the datasheet said my chip had address 0×48, I was seeing a response I expected.
Next, I read the TPS65070 datasheet to see how to configure the chip to post an interrupt when the screen was touched. I needed to set a couple of I2C registers and for this simple test, I poll once a second.
# step 1 - enable the ADC, select TSC input to ADC i2cset -y 1 0x48 0x07 0x8F # step 2 - set tsc mode to detect touch i2cset -y 1 0x48 0x08 0x05 # step 3 - poll tsc interrupt (bit 3) until it is set while sleep 1 ; do i2cget -y 1 0x48 0x02 ; done
Example output:
0x00 0x00 0x08 0x00 0x00
As soon as I read the I2C interrupt register, the interrupt is cleared.
There is a series of steps request to read the X and Y locations, so I wrote a simple shell script
tsc_read () { # first parameter is ASCII charcter between 0 .. 7 tsc_mode=$1 #enable the ADC and set it to use all TSC functions i2cset -y -f 1 0x48 0x07 0x9E # set the tsc mode i2cset -y -f 1 0x48 0x08 0x0$tsc_mode # start the conversion on ADC input TSC i2cset -y -f 1 0x48 0x07 0xDE # verify we are done (shell script should be slow enough) # check that bit 5 is set i2cget -y -f 1 0x48 0x07 # read the A/D converted value i2cget -y -f 1 0x48 0x0A i2cget -y -f 1 0x48 0x09 }
And now to read the X and Y locations is easy
# step 4 - read X position tsc_read 0 # step 5 -read Y position tsc_read 1
Example output:
# tsc_read 0 0xaf 0x01 0xf6 # tsc_read 1 0xaf 0x01 0x83
meaning on a 10 bit A/D scale 0×000 … 0×3FF (x,y) = (0×1F6, 0×183)
Overall, I found the i2c-tools very helpful in validating I understand how to interact with the chip registers properly.