***********************************************************************
*/
+/*
+ * Notes:
+ * The Linux I2C code is actually the same (almost) as the SMBus code.
+ * SMBus is System Management Bus - and in essentially I2C with some
+ * additional functionality added, and stricter controls on the electrical
+ * specifications, etc. however I2C does work well with it and the
+ * protocols work over both.
+ *
+ * I'm directly including the SMBus functions here as some Linux distros
+ * lack the correct header files, and also some header files are GPLv2
+ * rather than the LGPL that wiringPi is released under - presumably because
+ * originally no-one expected I2C/SMBus to be used outside the kernel -
+ * however enter the Raspberry Pi with people now taking directly to I2C
+ * devices without going via the kernel...
+ *
+ * This may ultimately reduce the flexibility of this code, but it won't be
+ * hard to maintain it and keep it current, should things change.
+ *
+ * Information here gained from: kernel/Documentation/i2c/dev-interface
+ * as well as other online resources.
+ *********************************************************************************
+ */
+
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
-#include <linux/i2c-dev.h>
#include "wiringPi.h"
#include "wiringPiI2C.h"
+// I2C definitions
+
+#define I2C_SLAVE 0x0703
+#define I2C_SMBUS 0x0720 /* SMBus-level access */
+
+#define I2C_SMBUS_READ 1
+#define I2C_SMBUS_WRITE 0
+
+// SMBus transaction types
+
+#define I2C_SMBUS_QUICK 0
+#define I2C_SMBUS_BYTE 1
+#define I2C_SMBUS_BYTE_DATA 2
+#define I2C_SMBUS_WORD_DATA 3
+#define I2C_SMBUS_PROC_CALL 4
+#define I2C_SMBUS_BLOCK_DATA 5
+#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
+#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
+#define I2C_SMBUS_I2C_BLOCK_DATA 8
+
+// SMBus messages
+
+#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
+#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */
+
+// Structures used in the ioctl() calls
+
+union i2c_smbus_data
+{
+ uint8_t byte ;
+ uint16_t word ;
+ uint8_t block [I2C_SMBUS_BLOCK_MAX + 2] ; // block [0] is used for length + one more for PEC
+} ;
+
+struct i2c_smbus_ioctl_data
+{
+ char read_write ;
+ uint8_t command ;
+ int size ;
+ union i2c_smbus_data *data ;
+} ;
+
+static inline int i2c_smbus_access (int fd, char rw, uint8_t command, int size, union i2c_smbus_data *data)
+{
+ struct i2c_smbus_ioctl_data args ;
+
+ args.read_write = rw ;
+ args.command = command ;
+ args.size = size ;
+ args.data = data ;
+ return ioctl (fd, I2C_SMBUS, &args) ;
+}
+
/*
* wiringPiI2CRead:
int wiringPiI2CRead (int fd)
{
- return i2c_smbus_read_byte (fd) ;
+ union i2c_smbus_data data ;
+
+ if (i2c_smbus_access (fd, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data))
+ return -1 ;
+ else
+ return data.byte & 0xFF ;
}
int wiringPiI2CReadReg8 (int fd, int reg)
{
- return i2c_smbus_read_byte_data (fd, reg) ;
+ union i2c_smbus_data data;
+
+ if (i2c_smbus_access (fd, I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data))
+ return -1 ;
+ else
+ return data.byte & 0xFF ;
}
int wiringPiI2CReadReg16 (int fd, int reg)
{
- return i2c_smbus_read_word_data (fd, reg) ;
+ union i2c_smbus_data data;
+
+ if (i2c_smbus_access (fd, I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, &data))
+ return -1 ;
+ else
+ return data.word & 0xFFFF ;
}
int wiringPiI2CWrite (int fd, int data)
{
- return i2c_smbus_write_byte (fd, data) ;
+ return i2c_smbus_access (fd, I2C_SMBUS_WRITE, data, I2C_SMBUS_BYTE, NULL) ;
}
*********************************************************************************
*/
-int wiringPiI2CWriteReg8 (int fd, int reg, int data)
+int wiringPiI2CWriteReg8 (int fd, int reg, int value)
{
- return i2c_smbus_write_byte_data (fd, reg, data) ;
+ union i2c_smbus_data data ;
+
+ data.byte = value ;
+ return i2c_smbus_access (fd, I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &data) ;
}
-int wiringPiI2CWriteReg16 (int fd, int reg, int data)
+int wiringPiI2CWriteReg16 (int fd, int reg, int value)
{
- return i2c_smbus_write_word_data (fd, reg, data) ;
+ union i2c_smbus_data data ;
+
+ data.word = value ;
+ return i2c_smbus_access (fd, I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, &data) ;
+}
+
+
+/*
+ * wiringPiI2CSetupInterface:
+ * Undocumented access to set the interface explicitly - might be used
+ * for the Pi's 2nd I2C interface...
+ *********************************************************************************
+ */
+
+int wiringPiI2CSetupInterface (const char *device, int devId)
+{
+ int fd ;
+
+ if ((fd = open (device, O_RDWR)) < 0)
+ return wiringPiFailure (WPI_ALMOST, "Unable to open I2C device: %s\n", strerror (errno)) ;
+
+ if (ioctl (fd, I2C_SLAVE, devId) < 0)
+ return wiringPiFailure (WPI_ALMOST, "Unable to select I2C device: %s\n", strerror (errno)) ;
+
+ return fd ;
}
*********************************************************************************
*/
-int wiringPiI2CSetup (int devId)
+int wiringPiI2CSetup (const int devId)
{
- int rev, fd ;
- char *device ;
+ int rev ;
+ const char *device ;
- if ((rev = piBoardRev ()) < 0)
- {
- fprintf (stderr, "wiringPiI2CSetup: Unable to determine Pi board revision\n") ;
- exit (1) ;
- }
+ rev = piBoardRev () ;
if (rev == 1)
device = "/dev/i2c-0" ;
else
device = "/dev/i2c-1" ;
- if ((fd = open (device, O_RDWR)) < 0)
- return -1 ;
-
- if (ioctl (fd, I2C_SLAVE, devId) < 0)
- return -1 ;
-
- return fd ;
+ return wiringPiI2CSetupInterface (device, devId) ;
}