Developing a Linux driver for a chip with I2C registers

From RidgeRun Developer Wiki
Revision as of 09:49, 8 March 2014 by Spalli (talk | contribs)

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 0x0E

# 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.