Skip to contentSkip to conversation

2.5.31 i2c updates

PATCH In review Albert Cranford 1 participant 1 message Aug 12, 2002 I2C

lore
Share & tools
lore
#0 lore raw

PATCH 2/4 2.5.31 i2c updates

Hello Linus,
Please apply the following four tested patches that update 2.5.31 with these I2C changes:
o Support for SMBus 2.0 PEC Packet Error Checking
o New adapter-i2c-frodo for SA 1110 board
o New adapter-i2c-rpx for embeded MPC8XX
o Replace depreciated cli()&sti() with spin_{un}lock_irq()
o Updated documentation
Thanks,
Albert

drivers/i2c/i2c-core.c 2002-07-07 21:37:15.000000000 -0400 renamed from drivers/i2c/i2c-core.c.orig 2002-07-05 19:42:07.000000000 -0400 +196 -18
@@ -18,9 +18,10 @@
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <[email protected]>.
-   All SMBus-related things are written by Frodo Looijaard <[email protected]> */
+   All SMBus-related things are written by Frodo Looijaard <[email protected]>
+   SMBus 2.0 support by Mark Studebaker <[email protected]>                */
 
-/* $Id: i2c-core.c,v 1.73 2002/03/03 17:37:44 mds Exp $ */
+/* $Id: i2c-core.c,v 1.83 2002/07/08 01:37:15 mds Exp $ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -71,7 +72,7 @@
 static int driver_count;
 
 /**** debug level */
-static int i2c_debug=1;
+static int i2c_debug=1;
 
 /* ---------------------------------------------------
  * /proc entry declarations
@@ -371,7 +372,7 @@
                                struct i2c_client *client = adap->clients[j];
                                if (client != NULL && 
                                    client->driver == driver) {
-                                       DEB2(printk("i2c-core.o: "
+                                       DEB2(printk(KERN_DEBUG "i2c-core.o: "
                                                    "detaching client %s:\n",
                                                    client->name));
                                        if ((res = driver->
@@ -1002,6 +1001,123 @@
 
 /* The SMBus parts */
 
+#define POLY    (0x1070U << 3) 
+static u8
+crc8(u16 data)
+{
+       int i;
+  
+       for(i = 0; i < 8; i++) {
+               if (data & 0x8000) 
+                       data = data ^ POLY;
+               data = data << 1;
+       }
+       return (u8)(data >> 8);
+}
+
+/* CRC over count bytes in the first array plus the bytes in the rest
+   array if it is non-null. rest[0] is the (length of rest) - 1
+   and is included. */
+u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest)
+{
+       int i;
+
+       for(i = 0; i < count; i++)
+               crc = crc8((crc ^ first[i]) << 8);
+       if(rest != NULL)
+               for(i = 0; i <= rest[0]; i++)
+                       crc = crc8((crc ^ rest[i]) << 8);
+       return crc;
+}
+
+u8 i2c_smbus_pec(int count, u8 *first, u8 *rest)
+{
+       return i2c_smbus_partial_pec(0, count, first, rest);
+}
+
+/* Returns new "size" (transaction type)
+   Note that we convert byte to byte_data and byte_data to word_data
+   rather than invent new xxx_PEC transactions. */
+int i2c_smbus_add_pec(u16 addr, u8 command, int size,
+                      union i2c_smbus_data *data)
+{
+       u8 buf[3];
+
+       buf[0] = addr << 1;
+       buf[1] = command;
+       switch(size) {
+               case I2C_SMBUS_BYTE:
+                       data->byte = i2c_smbus_pec(2, buf, NULL);
+                       size = I2C_SMBUS_BYTE_DATA;
+                       break;
+               case I2C_SMBUS_BYTE_DATA:
+                       buf[2] = data->byte;
+                       data->word = buf[2] ||
+                                   (i2c_smbus_pec(3, buf, NULL) << 8);
+                       size = I2C_SMBUS_WORD_DATA;
+                       break;
+               case I2C_SMBUS_WORD_DATA:
+                       /* unsupported */
+                       break;
+               case I2C_SMBUS_BLOCK_DATA:
+                       data->block[data->block[0] + 1] =
+                                    i2c_smbus_pec(2, buf, data->block);
+                       size = I2C_SMBUS_BLOCK_DATA_PEC;
+                       break;
+       }
+       return size;    
+}
+
+int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial,
+                        union i2c_smbus_data *data)
+{
+       u8 buf[3], rpec, cpec;
+
+       buf[1] = command;
+       switch(size) {
+               case I2C_SMBUS_BYTE_DATA:
+                       buf[0] = (addr << 1) | 1;
+                       cpec = i2c_smbus_pec(2, buf, NULL);
+                       rpec = data->byte;
+                       break;
+               case I2C_SMBUS_WORD_DATA:
+                       buf[0] = (addr << 1) | 1;
+                       buf[2] = data->word & 0xff;
+                       cpec = i2c_smbus_pec(3, buf, NULL);
+                       rpec = data->word >> 8;
+                       break;
+               case I2C_SMBUS_WORD_DATA_PEC:
+                       /* unsupported */
+                       cpec = rpec = 0;
+                       break;
+               case I2C_SMBUS_PROC_CALL_PEC:
+                       /* unsupported */
+                       cpec = rpec = 0;
+                       break;
+               case I2C_SMBUS_BLOCK_DATA_PEC:
+                       buf[0] = (addr << 1);
+                       buf[2] = (addr << 1) | 1;
+                       cpec = i2c_smbus_pec(3, buf, data->block);
+                       rpec = data->block[data->block[0] + 1];
+                       break;
+               case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+                       buf[0] = (addr << 1) | 1;
+                       rpec = i2c_smbus_partial_pec(partial, 1,
+                                                    buf, data->block);
+                       cpec = data->block[data->block[0] + 1];
+                       break;
+               default:
+                       cpec = rpec = 0;
+                       break;
+       }
+       if(rpec != cpec) {
+               DEB(printk(KERN_DEBUG "i2c-core.o: Bad PEC 0x%02x vs. 0x%02x\n",
+                          rpec, cpec));
+               return -1;
+       }
+       return 0;       
+}
+
 extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value)
 {
        return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
@@ -1020,8 +1136,9 @@
 
 extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value)
 {
+       union i2c_smbus_data data;      /* only for PEC */
        return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                             I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
+                             I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data);
 }
 
 extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command)
@@ -1099,8 +1216,8 @@
 {
        union i2c_smbus_data data;
        int i;
-       if (length > 32)
-               length = 32;
+       if (length > I2C_SMBUS_BLOCK_MAX)
+               length = I2C_SMBUS_BLOCK_MAX;
        for (i = 1; i <= length; i++)
                data.block[i] = values[i-1];
        data.block[0] = length;
@@ -1110,6 +1227,26 @@
 }
 
 /* Returns the number of read bytes */
+extern s32 i2c_smbus_block_process_call(struct i2c_client * client,
+                                        u8 command, u8 length, u8 *values)
+{
+       union i2c_smbus_data data;
+       int i;
+       if (length > I2C_SMBUS_BLOCK_MAX - 1)
+               return -1;
+       data.block[0] = length;
+       for (i = 1; i <= length; i++)
+               data.block[i] = values[i-1];
+       if(i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+                         I2C_SMBUS_WRITE, command,
+                         I2C_SMBUS_BLOCK_PROC_CALL, &data))
+               return -1;
+       for (i = 1; i <= data.block[0]; i++)
+               values[i-1] = data.block[i];
+       return data.block[0];
+}
+
+/* Returns the number of read bytes */
 extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
                                          u8 command, u8 *values)
 {
@@ -1131,8 +1268,8 @@
 {
        union i2c_smbus_data data;
        int i;
-       if (length > 32)
-               length = 32;
+       if (length > I2C_SMBUS_I2C_BLOCK_MAX)
+               length = I2C_SMBUS_I2C_BLOCK_MAX;
        for (i = 1; i <= length; i++)
                data.block[i] = values[i-1];
        data.block[0] = length;
@@ -1194,34 +1331,43 @@
                break;
        case I2C_SMBUS_PROC_CALL:
                num = 2; /* Special case */
+               read_write = I2C_SMBUS_READ;
                msg[0].len = 3;
                msg[1].len = 2;
                msgbuf0[1] = data->word & 0xff;
                msgbuf0[2] = (data->word >> 8) & 0xff;
                break;
        case I2C_SMBUS_BLOCK_DATA:
+       case I2C_SMBUS_BLOCK_DATA_PEC:
                if (read_write == I2C_SMBUS_READ) {
-                       printk(KERN_ERR "i2c-core.o: Block read not supported under "
-                              "I2C emulation!\n");
-               return -1;
+                       printk(KERN_ERR "i2c-core.o: Block read not supported "
+                              "under I2C emulation!\n");
+                       return -1;
                } else {
                        msg[0].len = data->block[0] + 2;
-                       if (msg[0].len > 34) {
+                       if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
                                printk(KERN_ERR "i2c-core.o: smbus_access called with "
                                       "invalid block write size (%d)\n",
                                       data->block[0]);
                                return -1;
                        }
+                       if(size == I2C_SMBUS_BLOCK_DATA_PEC)
+                               (msg[0].len)++;
                        for (i = 1; i <= msg[0].len; i++)
                                msgbuf0[i] = data->block[i-1];
                }
                break;
+       case I2C_SMBUS_BLOCK_PROC_CALL:
+       case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+               printk(KERN_ERR "i2c-core.o: Block process call not supported "
+                      "under I2C emulation!\n");
+               return -1;
        case I2C_SMBUS_I2C_BLOCK_DATA:
                if (read_write == I2C_SMBUS_READ) {
-                       msg[1].len = 32;
+                       msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX;
                } else {
                        msg[0].len = data->block[0] + 2;
-                       if (msg[0].len > 34) {
+                       if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 2) {
                                printk("i2c-core.o: i2c_smbus_xfer_emulated called with "
                                       "invalid block write size (%d)\n",
                                       data->block[0]);
@@ -1254,8 +1400,8 @@
                                break;
                        case I2C_SMBUS_I2C_BLOCK_DATA:
                                /* fixed at 32 for now */
-                               data->block[0] = 32;
-                               for (i = 0; i < 32; i++)
+                               data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX;
+                               for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++)
                                        data->block[i+1] = msgbuf1[i];
                                break;
                }
@@ -1268,7 +1414,29 @@
                    union i2c_smbus_data * data)
 {
        s32 res;
-       flags = flags & I2C_M_TEN;
+       int swpec = 0;
+       u8 partial = 0;
+
+       flags &= I2C_M_TEN | I2C_CLIENT_PEC;
+       if((flags & I2C_CLIENT_PEC) &&
+          !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) {
+               swpec = 1;
+               if(read_write == I2C_SMBUS_READ &&
+                  size == I2C_SMBUS_BLOCK_DATA)
+                       size = I2C_SMBUS_BLOCK_DATA_PEC;
+               else if(size == I2C_SMBUS_PROC_CALL)
+                       size = I2C_SMBUS_PROC_CALL_PEC;
+               else if(size == I2C_SMBUS_BLOCK_PROC_CALL) {
+                       i2c_smbus_add_pec(addr, command,
+                                         I2C_SMBUS_BLOCK_DATA, data);
+                       partial = data->block[data->block[0] + 1];
+                       size = I2C_SMBUS_BLOCK_PROC_CALL_PEC;
+               } else if(read_write == I2C_SMBUS_WRITE &&
+                         size != I2C_SMBUS_QUICK &&
+                         size != I2C_SMBUS_I2C_BLOCK_DATA)
+                       size = i2c_smbus_add_pec(addr, command, size, data);
+       }
+
        if (adapter->algo->smbus_xfer) {
                I2C_LOCK(adapter);
                res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
@@ -1277,6 +1445,14 @@
        } else
                res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
                                              command,size,data);
+
+       if(res >= 0 && swpec &&
+          size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA &&
+          (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC ||
+           size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {
+               if(i2c_smbus_check_pec(addr, command, size, partial, data))
+                       return -1;
+       }
        return res;
 }
 
drivers/i2c/i2c-dev.c 2002-07-05 22:07:39.000000000 -0400 renamed from drivers/i2c/i2c-dev.c.orig 2002-07-05 19:42:33.000000000 -0400 +14 -3
@@ -28,7 +28,7 @@
 /* The devfs code is contributed by Philipp Matthias Hahn 
    <[email protected]> */
 
-/* $Id: i2c-dev.c,v 1.44 2001/11/19 18:45:02 mds Exp $ */
+/* $Id: i2c-dev.c,v 1.46 2002/07/06 02:07:39 mds Exp $ */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -236,6 +236,12 @@
                else
                        client->flags &= ~I2C_M_TEN;
                return 0;
+       case I2C_PEC:
+               if (arg)
+                       client->flags |= I2C_CLIENT_PEC;
+               else
+                       client->flags &= ~I2C_CLIENT_PEC;
+               return 0;
        case I2C_FUNCS:
                funcs = i2c_get_functionality(client->adapter);
                return (copy_to_user((unsigned long *)arg,&funcs,
@@ -312,7 +318,8 @@
                    (data_arg.size != I2C_SMBUS_WORD_DATA) &&
                    (data_arg.size != I2C_SMBUS_PROC_CALL) &&
                    (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
-                   (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA)) {
+                   (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
+                   (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
 #ifdef DEBUG
                        printk(KERN_DEBUG "i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
                               data_arg.size);
@@ -355,10 +362,11 @@
                else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 
                         (data_arg.size == I2C_SMBUS_PROC_CALL))
                        datasize = sizeof(data_arg.data->word);
-               else /* size == I2C_SMBUS_BLOCK_DATA */
+               else /* size == smbus block, i2c block, or block proc. call */
                        datasize = sizeof(data_arg.data->block);
 
                if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
+                   (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 
                    (data_arg.read_write == I2C_SMBUS_WRITE)) {
                        if (copy_from_user(&temp, data_arg.data, datasize))
                                return -EFAULT;
@@ -367,6 +375,7 @@
                      data_arg.read_write,
                      data_arg.command,data_arg.size,&temp);
                if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
+                             (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 
                              (data_arg.read_write == I2C_SMBUS_READ))) {
                        if (copy_to_user(data_arg.data, &temp, datasize))
                                return -EFAULT;
@@ -535,6 +544,8 @@
        return 0;
 }
 
+EXPORT_NO_SYMBOLS;
+
 #ifdef MODULE
 
 MODULE_AUTHOR("Frodo Looijaard <[email protected]> and Simon G. Vogl <[email protected]>");
include/linux/i2c-dev.h 2002-07-07 11:42:47.000000000 -0400 renamed from include/linux/i2c-dev.h.orig 2002-07-05 19:42:19.000000000 -0400 +23 -2
@@ -19,7 +19,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/* $Id: i2c-dev.h,v 1.10 2001/11/19 19:01:46 mds Exp $ */
+/* $Id: i2c-dev.h,v 1.11 2002/07/07 15:42:47 mds Exp $ */
 
 #ifndef I2C_DEV_H
 #define I2C_DEV_H
@@ -144,7 +144,7 @@
        else {
                for (i = 1; i <= data.block[0]; i++)
                        values[i-1] = data.block[i];
-                       return data.block[0];
+               return data.block[0];
        }
 }
 
@@ -192,6 +192,27 @@
                                I2C_SMBUS_I2C_BLOCK_DATA, &data);
 }
 
+/* Returns the number of read bytes */
+static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,
+                                                 __u8 length, __u8 *values)
+{
+       union i2c_smbus_data data;
+       int i;
+       if (length > 32)
+               length = 32;
+       for (i = 1; i <= length; i++)
+               data.block[i] = values[i-1];
+       data.block[0] = length;
+       if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+                            I2C_SMBUS_BLOCK_PROC_CALL,&data))
+               return -1;
+       else {
+               for (i = 1; i <= data.block[0]; i++)
+                       values[i-1] = data.block[i];
+               return data.block[0];
+       }
+}
+
 #endif /* ndef __KERNEL__ */
 
 #endif
include/linux/i2c-id.h 2002-07-10 09:28:44.000000000 -0400 renamed from include/linux/i2c-id.h.orig 2002-07-05 19:42:03.000000000 -0400 +19 -3
@@ -20,7 +20,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
 /* ------------------------------------------------------------------------- */
 
-/* $Id: i2c-id.h,v 1.41 2002/03/11 07:18:55 simon Exp $ */
+/* $Id: i2c-id.h,v 1.52 2002/07/10 13:28:44 abz Exp $ */
 
 #ifndef I2C_ID_H
 #define I2C_ID_H
@@ -90,8 +90,12 @@
 #define I2C_DRIVERID_DRP3510   43     /* ADR decoder (Astra Radio)     */
 #define I2C_DRIVERID_SP5055    44     /* Satellite tuner               */
 #define I2C_DRIVERID_STV0030   45     /* Multipurpose switch           */
-#define I2C_DRIVERID_SAA7108    46     /* video decoder, image scaler   */
-
+#define I2C_DRIVERID_SAA7108   46     /* video decoder, image scaler   */
+#define I2C_DRIVERID_DS1307    47     /* DS1307 real time clock        */
+#define I2C_DRIVERID_ADV717x   48     /* ADV 7175/7176 video encoder   */
+#define I2C_DRIVERID_ZR36067   49     /* Zoran 36067 video encoder     */
+#define I2C_DRIVERID_ZR36120   50     /* Zoran 36120 video encoder     */
+#define I2C_DRIVERID_24LC32A   51              /* Microchip 24LC32A 32k EEPROM */
 
 
 
@@ -102,6 +106,8 @@
 
 #define I2C_DRIVERID_I2CDEV    900
 #define I2C_DRIVERID_I2CPROC   901
+#define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
+#define I2C_DRIVERID_ALERT      903    /* SMBus Alert Responder Client  */
 
 /* IDs --   Use DRIVERIDs 1000-1999 for sensors. 
    These were originally in sensors.h in the lm_sensors package */
@@ -134,6 +140,9 @@
 #define I2C_DRIVERID_FSCPOS 1028
 #define I2C_DRIVERID_FSCSCY 1029
 #define I2C_DRIVERID_PCF8591 1030
+#define I2C_DRIVERID_SMSC47M1 1031
+#define I2C_DRIVERID_VT1211 1032
+#define I2C_DRIVERID_LM92 1033
 
 /*
  * ---- Adapter types ----------------------------------------------------
@@ -155,6 +164,7 @@
 #define I2C_ALGO_EC     0x100000        /* ACPI embedded controller     */
 
 #define I2C_ALGO_MPC8XX 0x110000       /* MPC8xx PowerPC I2C algorithm */
+#define I2C_ALGO_OCP    0x120000       /* IBM or otherwise On-chip I2C algorithm */
 
 #define I2C_ALGO_EXP   0x800000        /* experimental                 */
 
@@ -182,9 +192,11 @@
 #define I2C_HW_B_I810  0x0a    /* Intel I810                           */
 #define I2C_HW_B_VOO   0x0b    /* 3dfx Voodoo 3 / Banshee              */
 #define I2C_HW_B_PPORT  0x0c   /* Primitive parallel port adapter      */
+#define I2C_HW_B_SAVG  0x0d    /* Savage 4                             */
 #define I2C_HW_B_RIVA  0x10    /* Riva based graphics cards            */
 #define I2C_HW_B_IOC   0x11    /* IOC bit-wiggling                     */
 #define I2C_HW_B_TSUNA  0x12   /* DEC Tsunami chipset                  */
+#define I2C_HW_B_FRODO  0x13    /* 2d3D, Inc. SA-1110 Development Board */
 
 /* --- PCF 8584 based algorithms                                       */
 #define I2C_HW_P_LP    0x00    /* Parallel port interface              */
@@ -200,6 +212,10 @@
 /* --- ITE based algorithms                                            */
 #define I2C_HW_I_IIC   0x00    /* controller on the ITE */
 
+/* --- PowerPC on-chip adapters                                                */
+#define I2C_HW_OCP 0x00        /* IBM on-chip I2C adapter      */
+
+
 /* --- SMBus only adapters                                             */
 #define I2C_HW_SMBUS_PIIX4     0x00
 #define I2C_HW_SMBUS_ALI15X3   0x01
drivers/i2c/i2c-proc.c 2002-04-22 19:21:49.000000000 -0400 renamed from drivers/i2c/i2c-proc.c.orig 2002-07-05 19:42:28.000000000 -0400 +47 -1

72 lines not on this page · raw message

include/linux/i2c.h 2002-07-19 16:53:45.000000000 -0400 renamed from include/linux/i2c.h.orig 2002-07-05 19:42:14.000000000 -0400 +39 -7

106 lines not on this page · raw message

Signature · 2 lines
Albert Cranford Deerfield Beach FL USA
[email protected]