chiark / gitweb /
Gah. another small fix to the I2C code.
[wiringPi.git] / wiringPi / wiringPiI2C.c
index 93fe1d3c4ad672fe1a2cf34b2f1a103e416f233d..c787bcea27d2f24f848c4e841aa3eae22f79e074 100644 (file)
  ***********************************************************************
  */
 
+/*
+ * 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 ;
 }
 
 
@@ -52,12 +135,22 @@ int wiringPiI2CRead (int fd)
 
 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 ;
 }
 
 
@@ -69,7 +162,7 @@ int wiringPiI2CReadReg16 (int fd, int reg)
 
 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) ;
 }
 
 
@@ -79,14 +172,41 @@ int wiringPiI2CWrite (int fd, int data)
  *********************************************************************************
  */
 
-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 ;
 }
 
 
@@ -96,27 +216,17 @@ int wiringPiI2CWriteReg16 (int fd, int reg, int data)
  *********************************************************************************
  */
 
-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) ;
 }