Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux...
[sfrench/cifs-2.6.git] / drivers / i2c / busses / i2c-powermac.c
index 3c9d71f60187ac6f979027238e31d4230cd5a764..1c440a70ec6139c8c6bfe5b1fd9195608dd9de71 100644 (file)
@@ -49,48 +49,38 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter*     adap,
        int                     rc = 0;
        int                     read = (read_write == I2C_SMBUS_READ);
        int                     addrdir = (addr << 1) | read;
+       int                     mode, subsize, len;
+       u32                     subaddr;
+       u8                      *buf;
        u8                      local[2];
 
-       rc = pmac_i2c_open(bus, 0);
-       if (rc)
-               return rc;
+       if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {
+               mode = pmac_i2c_mode_std;
+               subsize = 0;
+               subaddr = 0;
+       } else {
+               mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;
+               subsize = 1;
+               subaddr = command;
+       }
 
        switch (size) {
         case I2C_SMBUS_QUICK:
-               rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0);
+               buf = NULL;
+               len = 0;
                break;
         case I2C_SMBUS_BYTE:
-               rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1);
-               break;
         case I2C_SMBUS_BYTE_DATA:
-               rc = pmac_i2c_setmode(bus, read ?
-                                     pmac_i2c_mode_combined :
-                                     pmac_i2c_mode_stdsub);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1);
+               buf = &data->byte;
+               len = 1;
                break;
         case I2C_SMBUS_WORD_DATA:
-               rc = pmac_i2c_setmode(bus, read ?
-                                     pmac_i2c_mode_combined :
-                                     pmac_i2c_mode_stdsub);
-               if (rc)
-                       goto bail;
                if (!read) {
                        local[0] = data->word & 0xff;
                        local[1] = (data->word >> 8) & 0xff;
                }
-               rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2);
-               if (rc == 0 && read) {
-                       data->word = ((u16)local[1]) << 8;
-                       data->word |= local[0];
-               }
+               buf = local;
+               len = 2;
                break;
 
        /* Note that these are broken vs. the expected smbus API where
@@ -105,28 +95,44 @@ static s32 i2c_powermac_smbus_xfer(        struct i2c_adapter*     adap,
         * a repeat start/addr phase (but not stop in between)
         */
         case I2C_SMBUS_BLOCK_DATA:
-               rc = pmac_i2c_setmode(bus, read ?
-                                     pmac_i2c_mode_combined :
-                                     pmac_i2c_mode_stdsub);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block,
-                                  data->block[0] + 1);
-
+               buf = data->block;
+               len = data->block[0] + 1;
                break;
        case I2C_SMBUS_I2C_BLOCK_DATA:
-               rc = pmac_i2c_setmode(bus, read ?
-                                     pmac_i2c_mode_combined :
-                                     pmac_i2c_mode_stdsub);
-               if (rc)
-                       goto bail;
-               rc = pmac_i2c_xfer(bus, addrdir, 1, command,
-                                  &data->block[1], data->block[0]);
+               buf = &data->block[1];
+               len = data->block[0];
                break;
 
         default:
-               rc = -EINVAL;
+               return -EINVAL;
+       }
+
+       rc = pmac_i2c_open(bus, 0);
+       if (rc) {
+               dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+               return rc;
+       }
+
+       rc = pmac_i2c_setmode(bus, mode);
+       if (rc) {
+               dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+                       mode, rc);
+               goto bail;
        }
+
+       rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
+       if (rc) {
+               dev_err(&adap->dev,
+                       "I2C transfer at 0x%02x failed, size %d, err %d\n",
+                       addrdir >> 1, size, rc);
+               goto bail;
+       }
+
+       if (size == I2C_SMBUS_WORD_DATA && read) {
+               data->word = ((u16)local[1]) << 8;
+               data->word |= local[0];
+       }
+
  bail:
        pmac_i2c_close(bus);
        return rc;
@@ -146,20 +152,33 @@ static int i2c_powermac_master_xfer(      struct i2c_adapter *adap,
        int                     read;
        int                     addrdir;
 
+       if (num != 1) {
+               dev_err(&adap->dev,
+                       "Multi-message I2C transactions not supported\n");
+               return -EOPNOTSUPP;
+       }
+
        if (msgs->flags & I2C_M_TEN)
                return -EINVAL;
        read = (msgs->flags & I2C_M_RD) != 0;
        addrdir = (msgs->addr << 1) | read;
-       if (msgs->flags & I2C_M_REV_DIR_ADDR)
-               addrdir ^= 1;
 
        rc = pmac_i2c_open(bus, 0);
-       if (rc)
+       if (rc) {
+               dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
                return rc;
+       }
        rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
-       if (rc)
+       if (rc) {
+               dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+                       pmac_i2c_mode_std, rc);
                goto bail;
+       }
        rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+       if (rc < 0)
+               dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+                       addrdir & 1 ? "read from" : "write to", addrdir >> 1,
+                       rc);
  bail:
        pmac_i2c_close(bus);
        return rc < 0 ? rc : 1;
@@ -183,19 +202,16 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
 static int __devexit i2c_powermac_remove(struct platform_device *dev)
 {
        struct i2c_adapter      *adapter = platform_get_drvdata(dev);
-       struct pmac_i2c_bus     *bus = i2c_get_adapdata(adapter);
        int                     rc;
 
        rc = i2c_del_adapter(adapter);
-       pmac_i2c_detach_adapter(bus, adapter);
-       i2c_set_adapdata(adapter, NULL);
        /* We aren't that prepared to deal with this... */
        if (rc)
                printk(KERN_WARNING
                       "i2c-powermac.c: Failed to remove bus %s !\n",
                       adapter->name);
        platform_set_drvdata(dev, NULL);
-       kfree(adapter);
+       memset(adapter, 0, sizeof(*adapter));
 
        return 0;
 }
@@ -206,12 +222,12 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
        struct pmac_i2c_bus *bus = dev->dev.platform_data;
        struct device_node *parent = NULL;
        struct i2c_adapter *adapter;
-       char name[32];
        const char *basename;
        int rc;
 
        if (bus == NULL)
                return -EINVAL;
+       adapter = pmac_i2c_get_adapter(bus);
 
        /* Ok, now we need to make up a name for the interface that will
         * match what we used to do in the past, that is basically the
@@ -237,29 +253,22 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
        default:
                return -EINVAL;
        }
-       snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus));
+       snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
+                pmac_i2c_get_channel(bus));
        of_node_put(parent);
 
-       adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
-       if (adapter == NULL) {
-               printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
-               return -ENOMEM;
-       }
        platform_set_drvdata(dev, adapter);
-       strcpy(adapter->name, name);
        adapter->algo = &i2c_powermac_algorithm;
        i2c_set_adapdata(adapter, bus);
        adapter->dev.parent = &dev->dev;
-       pmac_i2c_attach_adapter(bus, adapter);
        rc = i2c_add_adapter(adapter);
        if (rc) {
                printk(KERN_ERR "i2c-powermac: Adapter %s registration "
-                      "failed\n", name);
-               i2c_set_adapdata(adapter, NULL);
-               pmac_i2c_detach_adapter(bus, adapter);
+                      "failed\n", adapter->name);
+               memset(adapter, 0, sizeof(*adapter));
        }
 
-       printk(KERN_INFO "PowerMac i2c bus %s registered\n", name);
+       printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
 
        if (!strncmp(basename, "uni-n", 5)) {
                struct device_node *np;