Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[pandora-kernel.git] / drivers / i2c / busses / i2c-mv64xxx.c
index 251154a..9e8118d 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Driver for the i2c controller on the Marvell line of host bridges for MIPS
- * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0).
+ * Driver for the i2c controller on the Marvell line of host bridges
+ * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, and Orion SoC family).
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
  *
@@ -14,7 +14,7 @@
 #include <linux/spinlock.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
-#include <linux/mv643xx.h>
+#include <linux/mv643xx_i2c.h>
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
@@ -86,6 +86,7 @@ struct mv64xxx_i2c_data {
        u32                     cntl_bits;
        void __iomem            *reg_base;
        u32                     reg_base_p;
+       u32                     reg_size;
        u32                     addr1;
        u32                     addr2;
        u32                     bytes_left;
@@ -107,6 +108,21 @@ struct mv64xxx_i2c_data {
  *
  *****************************************************************************
  */
+
+/* Reset hardware and initialize FSM */
+static void
+mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
+{
+       writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
+       writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
+               drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
+       writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
+       writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
+       writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
+               drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+       drv_data->state = MV64XXX_I2C_STATE_IDLE;
+}
+
 static void
 mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
 {
@@ -203,7 +219,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
                         drv_data->state, status, drv_data->msg->addr,
                         drv_data->msg->flags);
                drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
-               drv_data->state = MV64XXX_I2C_STATE_IDLE;
+               mv64xxx_i2c_hw_init(drv_data);
                drv_data->rc = -EIO;
        }
 }
@@ -367,6 +383,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
                                "mv64xxx: I2C bus locked, block: %d, "
                                "time_left: %d\n", drv_data->block,
                                (int)time_left);
+                       mv64xxx_i2c_hw_init(drv_data);
                }
        } else
                spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -443,34 +460,24 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
  *
  *****************************************************************************
  */
-static void __devinit
-mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
-{
-       writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
-       writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
-               drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
-       writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
-       writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
-       writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
-               drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
-       drv_data->state = MV64XXX_I2C_STATE_IDLE;
-}
-
 static int __devinit
 mv64xxx_i2c_map_regs(struct platform_device *pd,
        struct mv64xxx_i2c_data *drv_data)
 {
-       struct resource *r;
+       int size;
+       struct resource *r = platform_get_resource(pd, IORESOURCE_MEM, 0);
+
+       if (!r)
+               return -ENODEV;
 
-       if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) &&
-               request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE,
-                       drv_data->adapter.name)) {
+       size = r->end - r->start + 1;
 
-               drv_data->reg_base = ioremap(r->start,
-                       MV64XXX_I2C_REG_BLOCK_SIZE);
-               drv_data->reg_base_p = r->start;
-       } else
-               return -ENOMEM;
+       if (!request_mem_region(r->start, size, drv_data->adapter.name))
+               return -EBUSY;
+
+       drv_data->reg_base = ioremap(r->start, size);
+       drv_data->reg_base_p = r->start;
+       drv_data->reg_size = size;
 
        return 0;
 }
@@ -480,8 +487,7 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
 {
        if (drv_data->reg_base) {
                iounmap(drv_data->reg_base);
-               release_mem_region(drv_data->reg_base_p,
-                       MV64XXX_I2C_REG_BLOCK_SIZE);
+               release_mem_region(drv_data->reg_base_p, drv_data->reg_size);
        }
 
        drv_data->reg_base = NULL;
@@ -524,9 +530,8 @@ mv64xxx_i2c_probe(struct platform_device *pd)
        drv_data->adapter.id = I2C_HW_MV64XXX;
        drv_data->adapter.algo = &mv64xxx_i2c_algo;
        drv_data->adapter.owner = THIS_MODULE;
-       drv_data->adapter.class = I2C_CLASS_HWMON;
+       drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        drv_data->adapter.timeout = pdata->timeout;
-       drv_data->adapter.retries = pdata->retries;
        drv_data->adapter.nr = pd->id;
        platform_set_drvdata(pd, drv_data);
        i2c_set_adapdata(&drv_data->adapter, drv_data);