1 /****************************************************************************
3 * Copyright (c) 2006 Dave Hylands <dhylands@gmail.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
14 ****************************************************************************/
19 * @brief This file contains the implementation for performing I2C operations
22 ****************************************************************************/
24 // ---- Include Files -------------------------------------------------------
37 // ---- Public Variables ----------------------------------------------------
39 // ---- Private Constants and Types -----------------------------------------
41 // ---- Private Variables ---------------------------------------------------
43 static I2C_Addr_t gI2cAddr
;
46 // ---- Private Function Prototypes -----------------------------------------
48 // ---- Functions -----------------------------------------------------------
50 //***************************************************************************
53 * Sets the I2C address that we'll be communicating with, as well as whether
54 * the device uses smbus PEC (CRC).
57 void I2cSetSlaveAddress( int i2cDev
, I2C_Addr_t i2cAddr
, int useCrc
)
62 LogDebug( "----- I2cSetSlaveAddress i2cAddr:0x%02x useCrc:%d -----\n",
65 // Indicate which slave we wish to speak to
67 if ( ioctl( i2cDev
, I2C_SLAVE
, gI2cAddr
) < 0 )
69 LogError( "I2cSetSlaveAddress: Error trying to set slave address to 0x%02x (%d %s)\n",
70 gI2cAddr
, errno
, strerror( errno
));
73 // We do the CRC calculation ourself, so we don't need to tell the driver
74 // that we're using it.
77 // Indicate that we use PEC (aka CRCs)
79 if ( ioctl( i2cDev
, I2C_PEC
, 1 ) < 0 )
81 LogError( "I2cSetSlaveAddress: Error trying to set PEC mode\n" );
85 } // I2cSetSlaveAddress
87 //***************************************************************************
89 * Transfer data to/from an i2c device.
91 * This function implements the equivalent of the smbus functions using
94 * The PXA driver doesn't support the smbus transfers.
96 * This function can perform the following SMBUS transactions:
98 * Write Byte: wrLen == 1, rdLen == 0
99 * Read Byte: wrLen == 0, rdLen == 1
100 * Write Word: wrLen == 2, rdLen == 0
101 * Read Word: wrLen == 0, rdLen == 2
102 * Process Call: wrLen == 2, rdLen == 2
103 * Write Block: wrLen == 0x80 + numBytes, rdLen == 0
104 * Read Block: wrLen == 0, rdLen == 0x80 + numBytes
105 * Process Block: wrLen == 0x80 + numBytes, rdLen == 0x80 + numBytes
110 int i2cDev
, ///< Handle to i2c-dev file
111 uint8_t cmd
, ///< Command to send
112 const void *wrData
, ///< Data to write
113 uint8_t wrLen
, ///< Number of bytes to write (or in 0x80 for a block write)
114 void *rdData
, ///< Place to store data read
115 uint8_t rdLen
, ///< Number of bytes to read (or in 0x80 for a block read)
116 uint8_t *bytesReadp
///< Place to store number of bytes read
119 struct i2c_rdwr_ioctl_data rdwr
;
120 struct i2c_msg msg
[ 2 ];
121 uint8_t wrBuf
[ I2C_MAX_DATA_LEN
+ 3 ]; // +1 for cmd, +1 for len, +1 for CRC
122 uint8_t rdBuf
[ I2C_MAX_DATA_LEN
+ 2 ]; // +1 for len, +1 for CRC
124 uint8_t wrBlock
= (( wrLen
& 0x80 ) != 0 );
125 uint8_t rdBlock
= (( rdLen
& 0x80 ) != 0 );
128 LogDebug( "----- I2cTransfer: cmd:0x%02x wrLen:0x%02x rdLen:0x%02x wrBlock:%d rdBlock:%d -----\n",
129 cmd
, wrLen
, rdLen
, wrBlock
, rdBlock
);
130 if ( wrData
!= NULL
)
132 LogDebug( "----- wrData:0x%08x *wrData:0x%02x -----\n", wrData
, *(const uint8_t *)wrData
);
138 if ( bytesReadp
!= NULL
)
143 if ( wrLen
> I2C_MAX_DATA_LEN
)
145 LogError( "I2cTransfer: wrLen too big: %d, max is %d\n",
146 wrLen
, I2C_MAX_DATA_LEN
);
151 if ( rdLen
> I2C_MAX_DATA_LEN
)
153 LogError( "I2cTransfer: rdLen too big: %d, max is %d\n",
154 rdLen
, I2C_MAX_DATA_LEN
);
159 // Whether we're doing a read or a write, we always send
162 msg
[ 0 ].addr
= gI2cAddr
;
164 msg
[ 0 ].len
= wrLen
+ 1 + wrBlock
; // +1 for cmd
165 msg
[ 0 ].buf
= (char *)&wrBuf
[ 0 ];
169 crc
= Crc8( 0, gI2cAddr
<< 1 );
170 crc
= Crc8( crc
, cmd
);
177 // We have some data to send down to the device
182 memcpy( &wrBuf
[ 2 ], wrData
, wrLen
);
183 wrLen
++; // Add in cmd to the length
187 memcpy( &wrBuf
[ 1 ], wrData
, wrLen
);
191 crc
= Crc8Block( crc
, &wrBuf
[ 1 ], wrLen
);
195 // This is a write-only, so we need to send the CRC
197 wrBuf
[ wrLen
+ 1 ] = crc
;
205 Log( "msg[ 0 ].addr = 0x%02x\n", msg
[ 0 ].addr
);
206 Log( "msg[ 0 ].flags = 0x%04x\n", msg
[ 0 ].flags
);
207 Log( "msg[ 0 ].len = %d\n", msg
[ 0 ].len
);
208 DumpMem( "I2cTransfer W", 0, &wrBuf
[ 0 ], msg
[ 0 ].len
);
216 // We're expecting some data to come back
218 msg
[ 1 ].addr
= gI2cAddr
;
219 msg
[ 1 ].flags
= I2C_M_RD
;
220 msg
[ 1 ].len
= rdLen
+ rdBlock
+ gUseCrc
;
221 msg
[ 1 ].buf
= (char *)&rdBuf
[ 0 ];
227 crc
= Crc8( crc
, ( gI2cAddr
<< 1 ) | 1 );
232 Log( "msg[ 1 ].addr = 0x%02x\n", msg
[ 1 ].addr
);
233 Log( "msg[ 1 ].flags = 0x%04x\n", msg
[ 1 ].flags
);
234 Log( "msg[ 1 ].len = %d\n", msg
[ 1 ].len
);
238 if ( ioctl( i2cDev
, I2C_RDWR
, &rdwr
) < 0 )
240 LogError( "I2cTransfer: ioctl failed: %s (%d)\n", strerror( errno
), errno
);
248 if ( rdBuf
[ 0 ] > rdLen
)
250 LogError( "I2cTransfer: length is too big: %d max: %d\n", rdBuf
[ 0 ], rdLen
);
262 crc
= Crc8Block( crc
, &rdBuf
[ 0 ], rdLen
+ rdBlock
);
264 if ( crc
!= rdBuf
[ rdLen
+ rdBlock
] )
266 LogError( "I2cTransfer: CRC failed: Rcvd: 0x%02x, expecting: 0x%02x\n",
267 rdBuf
[ rdLen
+ rdBlock
], crc
);
274 DumpMem( "I2cTransfer R", 0, &rdBuf
[ 0 ], msg
[ 1 ].len
);
276 memcpy( rdData
, &rdBuf
[ rdBlock
], rdLen
);
278 if ( bytesReadp
!= NULL
)
287 //***************************************************************************
289 * Uses the SMBUS Process-Block protocol to read data from a device.
294 int i2cDev
, ///< Handle to i2c-dev file
295 uint8_t cmd
, ///< Command to send
296 const void *wrData
, ///< Data to write
297 uint8_t wrLen
, ///< Number of bytes to write
298 void *rdData
, ///< Place to store data read
299 uint8_t rdLen
, ///< Number of bytes to read
300 uint8_t *bytesReadp
///< Place to store number of bytes read
303 LogDebug( "----- I2cProcessBlock cmd: 0x%02x wrLen:0x%02x rdLen:0x%02x -----\n", cmd
, wrLen
, rdLen
);
305 return I2cTransfer( i2cDev
, cmd
, wrData
, 0x80 | wrLen
, rdData
, 0x80 | rdLen
, bytesReadp
);
309 //***************************************************************************
311 * Uses the SMBUS Read-Block protocol to read data from a device.
316 int i2cDev
, ///< Handle to i2c-dev file
317 uint8_t cmd
, ///< Command to send
318 void *rdData
, ///< Place to store data read
319 uint8_t rdLen
, ///< Number of bytes to read
320 uint8_t *bytesReadp
///< Place to store number of bytes read
323 LogDebug( "----- I2cReadBlock cmd: 0x%02x rdLen:0x%02x -----\n", cmd
, rdLen
);
325 return I2cTransfer( i2cDev
, cmd
, NULL
, 0, rdData
, 0x80 | rdLen
, bytesReadp
);
329 //***************************************************************************
331 * Uses the SMBUS Read-Byte protocol to read a byte.
336 int i2cDev
, ///< Handle to i2c-dev file
337 uint8_t cmd
, ///< Command to send
338 uint8_t *rdByte
///< Place to store byte read
341 LogDebug( "----- I2cReadByte cmd: 0x%02x -----\n", cmd
);
343 return I2cTransfer( i2cDev
, cmd
, NULL
, 0, rdByte
, 1, NULL
);
347 //***************************************************************************
349 * Reads an array of bytes usinng i2c (not compatible with SMBUS)
354 int i2cDev
, ///< Handle to i2c-dev file
355 uint8_t cmd
, ///< Command to send
356 void *rdByte
, ///< Place to store bytes read
357 uint8_t rdLen
///< Number of bytes to read
360 LogDebug( "----- I2cReadBytes cmd: 0x%02x rdLen: 0x%02x -----\n", cmd
, rdLen
);
362 return I2cTransfer( i2cDev
, cmd
, NULL
, 0, rdByte
, rdLen
, NULL
);
366 //***************************************************************************
368 * Uses the SMBUS Write-Block protocol to write data from a device.
373 int i2cDev
, ///< Handle to i2c-dev file
374 uint8_t cmd
, ///< Command to send
375 const void *wrData
, ///< Data to write
376 uint8_t wrLen
///< Number of bytes to write
379 LogDebug( "----- I2cWriteBlock cmd: 0x%02x wrLen:0x%02x -----\n", cmd
, wrLen
);
381 return I2cTransfer( i2cDev
, cmd
, wrData
, 0x80 | wrLen
, NULL
, 0, NULL
);
385 //***************************************************************************
387 * Uses the SMBUS Write-Byte protocol to write a byte.
392 int i2cDev
, ///< Handle to i2c-dev file
393 uint8_t cmd
, ///< Command to send
394 uint8_t wrByte
///< Byte to write
397 LogDebug( "----- I2cWriteByte cmd: 0x%02x wrByte:0x%02x -----\n", cmd
, wrByte
);
398 LogDebug( "----- &wrByte = 0x%08x wrByte = 0x%02x -----\n", &wrByte
, *&wrByte
);
400 return I2cTransfer( i2cDev
, cmd
, &wrByte
, 1, NULL
, 0, NULL
);
404 //***************************************************************************
406 * Writes an array of bytes using i2c (not compatible with SMBUS)
411 int i2cDev
, ///< Handle to i2c-dev file
412 uint8_t cmd
, ///< Command to send
413 const void *wrByte
, ///< Bytes to write
414 uint8_t wrLen
///< Number of bytes to write
417 LogDebug( "----- I2cWriteBytes cmd: 0x%02x wrLen: 0x%02x -----\n", cmd
, wrLen
);
419 return I2cTransfer( i2cDev
, cmd
, wrByte
, wrLen
, NULL
, 0, NULL
);
423 //***************************************************************************
425 * Uses the SMBUS Receive-Byte protocol to read a byte.
430 int i2cDev
, ///< Handle to i2c-dev file
431 uint8_t *rdByte
///< Place to store byte read
434 return I2cReceiveBytes( i2cDev
, rdByte
, 1 );
438 //***************************************************************************
440 * Uses the SMBUS Receive-Byte protocol to read multiple (or one or zero) bytes.
445 int i2cDev
, ///< Handle to i2c-dev file
446 uint8_t *rdData
, ///< Place to store data read
447 uint8_t rdLen
///< Number of bytes to read
450 struct i2c_rdwr_ioctl_data rdwr
;
453 LogDebug( "----- I2cReceiveBytes -----\n" );
456 msg
.flags
= I2C_M_RD
;
458 msg
.buf
= (char *)rdData
;
463 if ( ioctl( i2cDev
, I2C_RDWR
, &rdwr
) < 0 )
465 LogError( "I2cReceiveBytes: ioctl failed: %s (%d)\n", strerror( errno
), errno
);
473 //***************************************************************************
475 * Uses the SMBUS Send-Byte protocol to write a byte.
480 int i2cDev
, ///< Handle to i2c-dev file
481 uint8_t wrByte
///< Byte to write
484 return I2cSendBytes( i2cDev
, &wrByte
, 1 );
488 //***************************************************************************
490 * Uses the SMBUS Send-Byte protocol to write multiple (or zero or one) bytes.
495 int i2cDev
, ///< Handle to i2c-dev file
496 uint8_t *wrData
, ///< Pointer to data to write
497 uint8_t wrLen
///< NUmber of bytes to write
500 struct i2c_rdwr_ioctl_data rdwr
;
503 LogDebug( "----- I2cSendBytes wrLen = 0x%02x -----\n", wrLen
);
508 msg
.buf
= (char *)wrData
;
513 if ( ioctl( i2cDev
, I2C_RDWR
, &rdwr
) < 0 )
515 LogError( "I2cSendBytes: ioctl failed: %s (%d)\n", strerror( errno
), errno
);