summary refs log tree commit diff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-24 16:39:23 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-24 16:39:23 -0700
commit4a7df24ddc7097cd789a7527187826552ea0765e (patch)
tree2e70557e1d8e6d971ee6094de823900df1f8288e /drivers/i2c
parent37d8cb5478651b27779b9a80d024c614c452eae3 (diff)
parent5bdfdfeed5eed599a3ddc455f7c254a209ceae8d (diff)
downloadlinux-4a7df24ddc7097cd789a7527187826552ea0765e.tar.gz
Merge branch 'for-linus/2640/i2c' of git://git.fluff.org/bjdooks/linux
* 'for-linus/2640/i2c' of git://git.fluff.org/bjdooks/linux: (21 commits)
  mach-ux500: set proper I2C platform data from MOP500s
  i2c-nomadik: break out single messsage transmission
  i2c-nomadik: reset the hw after status check
  i2c-nomadik: remove the unnecessary delay
  i2c-nomadik: change the TX and RX threshold
  i2c-nomadik: add code to retry on timeout failure
  i2c-nomadik: use pm_runtime API
  i2c-nomadik: print abort cause only on abort tag
  i2c-nomadik: correct adapter timeout initialization
  i2c-nomadik: remove the redundant error message
  i2c-nomadik: corrrect returned error numbers
  i2c-nomadik: fix speed enumerator
  i2c-nomadik: make i2c timeout specific per i2c bus
  i2c-nomadik: add regulator support
  i2c: i2c-sh_mobile bus speed platform data V2
  i2c: i2c-sh_mobile clock string removal
  i2c-eg20t: Support new device ML7223 IOH
  i2c: tegra: Add de-bounce cycles.
  i2c: tegra: fix repeated start handling
  i2c: tegra: recover from spurious interrupt storm
  ...
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig10
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c2
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c276
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c19
-rw-r--r--drivers/i2c/busses/i2c-tegra.c39
5 files changed, 240 insertions, 106 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 428d098c35ef..646068e5100b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -673,15 +673,19 @@ config I2C_XILINX
 	  will be called xilinx_i2c.
 
 config I2C_EG20T
-	tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH"
+	tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)"
 	depends on PCI
 	help
 	  This driver is for PCH(Platform controller Hub) I2C of EG20T which
 	  is an IOH(Input/Output Hub) for x86 embedded processor.
 	  This driver can access PCH I2C bus device.
 
-	  This driver also supports the ML7213, a companion chip for the
-	  Atom E6xx series and compatible with the Intel EG20T PCH.
+	  This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+	  Output Hub), ML7213 and ML7223.
+	  ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
+	  for MP(Media Phone) use.
+	  ML7213/ML7223 is companion chip for Intel Atom E6xx series.
+	  ML7213/ML7223 is completely compatible for Intel EG20T PCH.
 
 comment "External I2C/SMBus adapter drivers"
 
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index 878a12026af2..8abfa4a03ce1 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -182,10 +182,12 @@ static DEFINE_MUTEX(pch_mutex);
 /* Definition for ML7213 by OKI SEMICONDUCTOR */
 #define PCI_VENDOR_ID_ROHM		0x10DB
 #define PCI_DEVICE_ID_ML7213_I2C	0x802D
+#define PCI_DEVICE_ID_ML7223_I2C	0x8010
 
 static struct pci_device_id __devinitdata pch_pcidev_id[] = {
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
 	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
+	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
 	{0,}
 };
 
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index e10e5cf3751a..0c731ca69f15 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -15,13 +15,14 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/i2c.h>
 
@@ -103,9 +104,6 @@
 /* maximum threshold value */
 #define MAX_I2C_FIFO_THRESHOLD	15
 
-/* per-transfer delay, required for the hardware to stabilize */
-#define I2C_DELAY		150
-
 enum i2c_status {
 	I2C_NOP,
 	I2C_ON_GOING,
@@ -120,9 +118,6 @@ enum i2c_operation {
 	I2C_READ = 0x01
 };
 
-/* controller response timeout in ms */
-#define I2C_TIMEOUT_MS	2000
-
 /**
  * struct i2c_nmk_client - client specific data
  * @slave_adr: 7-bit slave address
@@ -151,6 +146,7 @@ struct i2c_nmk_client {
  * @stop: stop condition
  * @xfer_complete: acknowledge completion for a I2C message
  * @result: controller propogated result
+ * @busy: Busy doing transfer
  */
 struct nmk_i2c_dev {
 	struct platform_device		*pdev;
@@ -163,6 +159,8 @@ struct nmk_i2c_dev {
 	int 				stop;
 	struct completion		xfer_complete;
 	int 				result;
+	struct regulator		*regulator;
+	bool				busy;
 };
 
 /* controller's abort causes */
@@ -209,7 +207,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
 	writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
 
 	for (i = 0; i < LOOP_ATTEMPTS; i++) {
-		timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT_MS);
+		timeout = jiffies + dev->adap.timeout;
 
 		while (!time_after(jiffies, timeout)) {
 			if ((readl(dev->virtbase + I2C_CR) &
@@ -253,11 +251,9 @@ static int init_hw(struct nmk_i2c_dev *dev)
 {
 	int stat;
 
-	clk_enable(dev->clk);
-
 	stat = flush_i2c_fifo(dev);
 	if (stat)
-		return stat;
+		goto exit;
 
 	/* disable the controller */
 	i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
@@ -268,10 +264,8 @@ static int init_hw(struct nmk_i2c_dev *dev)
 
 	dev->cli.operation = I2C_NO_OPERATION;
 
-	clk_disable(dev->clk);
-
-	udelay(I2C_DELAY);
-	return 0;
+exit:
+	return stat;
 }
 
 /* enable peripheral, master mode operation */
@@ -424,7 +418,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
 			dev->virtbase + I2C_IMSCR);
 
 	timeout = wait_for_completion_interruptible_timeout(
-		&dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+		&dev->xfer_complete, dev->adap.timeout);
 
 	if (timeout < 0) {
 		dev_err(&dev->pdev->dev,
@@ -434,14 +428,32 @@ static int read_i2c(struct nmk_i2c_dev *dev)
 	}
 
 	if (timeout == 0) {
-		/* controller has timedout, re-init the h/w */
-		dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
-		(void) init_hw(dev);
+		/* Controller timed out */
+		dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
+				dev->cli.slave_adr);
 		status = -ETIMEDOUT;
 	}
 	return status;
 }
 
+static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
+{
+	int count;
+
+	for (count = (no_bytes - 2);
+			(count > 0) &&
+			(dev->cli.count != 0);
+			count--) {
+		/* write to the Tx FIFO */
+		writeb(*dev->cli.buffer,
+			dev->virtbase + I2C_TFR);
+		dev->cli.buffer++;
+		dev->cli.count--;
+		dev->cli.xfer_bytes++;
+	}
+
+}
+
 /**
  * write_i2c() - Write data to I2C client.
  * @dev: private data of I2C Driver
@@ -469,8 +481,13 @@ static int write_i2c(struct nmk_i2c_dev *dev)
 	init_completion(&dev->xfer_complete);
 
 	/* enable interrupts by settings the masks */
-	irq_mask = (I2C_IT_TXFNE | I2C_IT_TXFOVR |
-			I2C_IT_MAL | I2C_IT_BERR);
+	irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
+
+	/* Fill the TX FIFO with transmit data */
+	fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD);
+
+	if (dev->cli.count != 0)
+		irq_mask |= I2C_IT_TXFNE;
 
 	/*
 	 * check if we want to transfer a single or multiple bytes, if so
@@ -488,7 +505,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
 			dev->virtbase + I2C_IMSCR);
 
 	timeout = wait_for_completion_interruptible_timeout(
-		&dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+		&dev->xfer_complete, dev->adap.timeout);
 
 	if (timeout < 0) {
 		dev_err(&dev->pdev->dev,
@@ -498,9 +515,9 @@ static int write_i2c(struct nmk_i2c_dev *dev)
 	}
 
 	if (timeout == 0) {
-		/* controller has timedout, re-init the h/w */
-		dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
-		(void) init_hw(dev);
+		/* Controller timed out */
+		dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
+				dev->cli.slave_adr);
 		status = -ETIMEDOUT;
 	}
 
@@ -508,6 +525,51 @@ static int write_i2c(struct nmk_i2c_dev *dev)
 }
 
 /**
+ * nmk_i2c_xfer_one() - transmit a single I2C message
+ * @dev: device with a message encoded into it
+ * @flags: message flags
+ */
+static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
+{
+	int status;
+
+	if (flags & I2C_M_RD) {
+		/* read operation */
+		dev->cli.operation = I2C_READ;
+		status = read_i2c(dev);
+	} else {
+		/* write operation */
+		dev->cli.operation = I2C_WRITE;
+		status = write_i2c(dev);
+	}
+
+	if (status || (dev->result)) {
+		u32 i2c_sr;
+		u32 cause;
+
+		i2c_sr = readl(dev->virtbase + I2C_SR);
+		/*
+		 * Check if the controller I2C operation status
+		 * is set to ABORT(11b).
+		 */
+		if (((i2c_sr >> 2) & 0x3) == 0x3) {
+			/* get the abort cause */
+			cause =	(i2c_sr >> 4) & 0x7;
+			dev_err(&dev->pdev->dev, "%s\n", cause
+				>= ARRAY_SIZE(abort_causes) ?
+				"unknown reason" :
+				abort_causes[cause]);
+		}
+
+		(void) init_hw(dev);
+
+		status = status ? status : dev->result;
+	}
+
+	return status;
+}
+
+/**
  * nmk_i2c_xfer() - I2C transfer function used by kernel framework
  * @i2c_adap: Adapter pointer to the controller
  * @msgs: Pointer to data to be written.
@@ -559,53 +621,55 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 {
 	int status;
 	int i;
-	u32 cause;
 	struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+	int j;
+
+	dev->busy = true;
+
+	if (dev->regulator)
+		regulator_enable(dev->regulator);
+	pm_runtime_get_sync(&dev->pdev->dev);
+
+	clk_enable(dev->clk);
 
 	status = init_hw(dev);
 	if (status)
-		return status;
+		goto out;
 
-	clk_enable(dev->clk);
+	/* Attempt three times to send the message queue */
+	for (j = 0; j < 3; j++) {
+		/* setup the i2c controller */
+		setup_i2c_controller(dev);
 
-	/* setup the i2c controller */
-	setup_i2c_controller(dev);
+		for (i = 0; i < num_msgs; i++) {
+			if (unlikely(msgs[i].flags & I2C_M_TEN)) {
+				dev_err(&dev->pdev->dev, "10 bit addressing"
+						"not supported\n");
 
-	for (i = 0; i < num_msgs; i++) {
-		if (unlikely(msgs[i].flags & I2C_M_TEN)) {
-			dev_err(&dev->pdev->dev, "10 bit addressing"
-					"not supported\n");
-			return -EINVAL;
-		}
-		dev->cli.slave_adr	= msgs[i].addr;
-		dev->cli.buffer		= msgs[i].buf;
-		dev->cli.count		= msgs[i].len;
-		dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
-		dev->result = 0;
-
-		if (msgs[i].flags & I2C_M_RD) {
-			/* it is a read operation */
-			dev->cli.operation = I2C_READ;
-			status = read_i2c(dev);
-		} else {
-			/* write operation */
-			dev->cli.operation = I2C_WRITE;
-			status = write_i2c(dev);
-		}
-		if (status || (dev->result)) {
-			/* get the abort cause */
-			cause =	(readl(dev->virtbase + I2C_SR) >> 4) & 0x7;
-			dev_err(&dev->pdev->dev, "error during I2C"
-					"message xfer: %d\n", cause);
-			dev_err(&dev->pdev->dev, "%s\n",
-				cause >= ARRAY_SIZE(abort_causes)
-				? "unknown reason" : abort_causes[cause]);
-			clk_disable(dev->clk);
-			return status;
+				status = -EINVAL;
+				goto out;
+			}
+			dev->cli.slave_adr	= msgs[i].addr;
+			dev->cli.buffer		= msgs[i].buf;
+			dev->cli.count		= msgs[i].len;
+			dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
+			dev->result = 0;
+
+			status = nmk_i2c_xfer_one(dev, msgs[i].flags);
+			if (status != 0)
+				break;
 		}
-		udelay(I2C_DELAY);
+		if (status == 0)
+			break;
 	}
+
+out:
 	clk_disable(dev->clk);
+	pm_runtime_put_sync(&dev->pdev->dev);
+	if (dev->regulator)
+		regulator_disable(dev->regulator);
+
+	dev->busy = false;
 
 	/* return the no. messages processed */
 	if (status)
@@ -666,17 +730,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 			 */
 			disable_interrupts(dev, I2C_IT_TXFNE);
 		} else {
-			for (count = (MAX_I2C_FIFO_THRESHOLD - tft - 2);
-					(count > 0) &&
-					(dev->cli.count != 0);
-					count--) {
-				/* write to the Tx FIFO */
-				writeb(*dev->cli.buffer,
-					dev->virtbase + I2C_TFR);
-				dev->cli.buffer++;
-				dev->cli.count--;
-				dev->cli.xfer_bytes++;
-			}
+			fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
 			/*
 			 * if done, close the transfer by disabling the
 			 * corresponding TXFNE interrupt
@@ -729,16 +783,11 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 			}
 		}
 
-		i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTD);
-		i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS);
-
-		disable_interrupts(dev,
-				(I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF
-					| I2C_IT_TXFOVR | I2C_IT_RXFNF
-					| I2C_IT_RXFF | I2C_IT_RXFE));
+		disable_all_interrupts(dev);
+		clear_all_interrupts(dev);
 
 		if (dev->cli.count) {
-			dev->result = -1;
+			dev->result = -EIO;
 			dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
 					"xfered\n", dev->cli.count);
 			(void) init_hw(dev);
@@ -749,7 +798,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 
 	/* Master Arbitration lost interrupt */
 	case I2C_IT_MAL:
-		dev->result = -1;
+		dev->result = -EIO;
 		(void) init_hw(dev);
 
 		i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
@@ -763,7 +812,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 	 * during the transaction.
 	 */
 	case I2C_IT_BERR:
-		dev->result = -1;
+		dev->result = -EIO;
 		/* get the status */
 		if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
 			(void) init_hw(dev);
@@ -779,7 +828,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 	 * the Tx FIFO is full.
 	 */
 	case I2C_IT_TXFOVR:
-		dev->result = -1;
+		dev->result = -EIO;
 		(void) init_hw(dev);
 
 		dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
@@ -805,6 +854,38 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
+
+#ifdef CONFIG_PM
+static int nmk_i2c_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev);
+
+	if (nmk_i2c->busy)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int nmk_i2c_resume(struct device *dev)
+{
+	return 0;
+}
+#else
+#define nmk_i2c_suspend	NULL
+#define nmk_i2c_resume	NULL
+#endif
+
+/*
+ * We use noirq so that we suspend late and resume before the wakeup interrupt
+ * to ensure that we do the !pm_runtime_suspended() check in resume before
+ * there has been a regular pm runtime resume (via pm_runtime_get_sync()).
+ */
+static const struct dev_pm_ops nmk_i2c_pm = {
+	.suspend_noirq	= nmk_i2c_suspend,
+	.resume_noirq	= nmk_i2c_resume,
+};
+
 static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -830,7 +911,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 		ret = -ENOMEM;
 		goto err_no_mem;
 	}
-
+	dev->busy = false;
 	dev->pdev = pdev;
 	platform_set_drvdata(pdev, dev);
 
@@ -860,6 +941,15 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 		goto err_irq;
 	}
 
+	dev->regulator = regulator_get(&pdev->dev, "v-i2c");
+	if (IS_ERR(dev->regulator)) {
+		dev_warn(&pdev->dev, "could not get i2c regulator\n");
+		dev->regulator = NULL;
+	}
+
+	pm_suspend_ignore_children(&pdev->dev, true);
+	pm_runtime_enable(&pdev->dev);
+
 	dev->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(dev->clk)) {
 		dev_err(&pdev->dev, "could not get i2c clock\n");
@@ -872,6 +962,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 	adap->owner	= THIS_MODULE;
 	adap->class	= I2C_CLASS_HWMON | I2C_CLASS_SPD;
 	adap->algo	= &nmk_i2c_algo;
+	adap->timeout	= pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
+		msecs_to_jiffies(20000);
 	snprintf(adap->name, sizeof(adap->name),
 		 "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
 
@@ -887,12 +979,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
 	i2c_set_adapdata(adap, dev);
 
-	ret = init_hw(dev);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "error in initializing i2c hardware\n");
-		goto err_init_hw;
-	}
-
 	dev_info(&pdev->dev, "initialize %s on virtual "
 		"base %p\n", adap->name, dev->virtbase);
 
@@ -904,10 +990,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
 	return 0;
 
- err_init_hw:
  err_add_adap:
 	clk_put(dev->clk);
  err_no_clk:
+	if (dev->regulator)
+		regulator_put(dev->regulator);
+	pm_runtime_disable(&pdev->dev);
 	free_irq(dev->irq, dev);
  err_irq:
 	iounmap(dev->virtbase);
@@ -938,6 +1026,9 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
 	if (res)
 		release_mem_region(res->start, resource_size(res));
 	clk_put(dev->clk);
+	if (dev->regulator)
+		regulator_put(dev->regulator);
+	pm_runtime_disable(&pdev->dev);
 	platform_set_drvdata(pdev, NULL);
 	kfree(dev);
 
@@ -948,6 +1039,7 @@ static struct platform_driver nmk_i2c_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = DRIVER_NAME,
+		.pm = &nmk_i2c_pm,
 	},
 	.probe = nmk_i2c_probe,
 	.remove = __devexit_p(nmk_i2c_remove),
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 81ccd7875627..f633a53b6dbe 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -32,6 +32,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/i2c/i2c-sh_mobile.h>
 
 /* Transmit operation:                                                      */
 /*                                                                          */
@@ -117,7 +118,7 @@ struct sh_mobile_i2c_data {
 	struct device *dev;
 	void __iomem *reg;
 	struct i2c_adapter adap;
-
+	unsigned long bus_speed;
 	struct clk *clk;
 	u_int8_t icic;
 	u_int8_t iccl;
@@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd)
 	 * We also round off the result.
 	 */
 	num = i2c_clk * 5;
-	denom = NORMAL_SPEED * 9;
+	denom = pd->bus_speed * 9;
 	tmp = num * 10 / denom;
 	if (tmp % 10 >= 5)
 		pd->iccl = (u_int8_t)((num/denom) + 1);
@@ -574,10 +575,10 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
 
 static int sh_mobile_i2c_probe(struct platform_device *dev)
 {
+	struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data;
 	struct sh_mobile_i2c_data *pd;
 	struct i2c_adapter *adap;
 	struct resource *res;
-	char clk_name[8];
 	int size;
 	int ret;
 
@@ -587,10 +588,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
 		return -ENOMEM;
 	}
 
-	snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id);
-	pd->clk = clk_get(&dev->dev, clk_name);
+	pd->clk = clk_get(&dev->dev, NULL);
 	if (IS_ERR(pd->clk)) {
-		dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name);
+		dev_err(&dev->dev, "cannot get clock\n");
 		ret = PTR_ERR(pd->clk);
 		goto err;
 	}
@@ -620,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
 		goto err_irq;
 	}
 
+	/* Use platformd data bus speed or NORMAL_SPEED */
+	pd->bus_speed = NORMAL_SPEED;
+	if (pdata && pdata->bus_speed)
+		pd->bus_speed = pdata->bus_speed;
+
 	/* The IIC blocks on SH-Mobile ARM processors
 	 * come with two new bits in ICIC.
 	 */
@@ -660,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
 		goto err_all;
 	}
 
+	dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n",
+		 adap->nr, pd->bus_speed);
 	return 0;
 
  err_all:
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index b4ab39b741eb..4d9319665e32 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -35,8 +35,10 @@
 #define BYTES_PER_FIFO_WORD 4
 
 #define I2C_CNFG				0x000
+#define I2C_CNFG_DEBOUNCE_CNT_SHIFT		12
 #define I2C_CNFG_PACKET_MODE_EN			(1<<10)
 #define I2C_CNFG_NEW_MASTER_FSM			(1<<11)
+#define I2C_STATUS				0x01C
 #define I2C_SL_CNFG				0x020
 #define I2C_SL_CNFG_NEWSL			(1<<2)
 #define I2C_SL_ADDR1				0x02c
@@ -77,6 +79,7 @@
 #define I2C_ERR_NONE				0x00
 #define I2C_ERR_NO_ACK				0x01
 #define I2C_ERR_ARBITRATION_LOST		0x02
+#define I2C_ERR_UNKNOWN_INTERRUPT		0x04
 
 #define PACKET_HEADER0_HEADER_SIZE_SHIFT	28
 #define PACKET_HEADER0_PACKET_ID_SHIFT		16
@@ -121,6 +124,7 @@ struct tegra_i2c_dev {
 	void __iomem *base;
 	int cont_id;
 	int irq;
+	bool irq_disabled;
 	int is_dvc;
 	struct completion msg_complete;
 	int msg_err;
@@ -325,11 +329,17 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 	if (i2c_dev->is_dvc)
 		tegra_dvc_init(i2c_dev);
 
-	val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN;
+	val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
+		(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
 	i2c_writel(i2c_dev, val, I2C_CNFG);
 	i2c_writel(i2c_dev, 0, I2C_INT_MASK);
 	clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8);
 
+	if (!i2c_dev->is_dvc) {
+		u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
+		i2c_writel(i2c_dev, sl_cfg | I2C_SL_CNFG_NEWSL, I2C_SL_CNFG);
+	}
+
 	val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
 		0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
 	i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
@@ -338,6 +348,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 		err = -ETIMEDOUT;
 
 	clk_disable(i2c_dev->clk);
+
+	if (i2c_dev->irq_disabled) {
+		i2c_dev->irq_disabled = 0;
+		enable_irq(i2c_dev->irq);
+	}
+
 	return err;
 }
 
@@ -350,8 +366,19 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
 	status = i2c_readl(i2c_dev, I2C_INT_STATUS);
 
 	if (status == 0) {
-		dev_warn(i2c_dev->dev, "interrupt with no status\n");
-		return IRQ_NONE;
+		dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
+			 i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
+			 i2c_readl(i2c_dev, I2C_STATUS),
+			 i2c_readl(i2c_dev, I2C_CNFG));
+		i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
+
+		if (!i2c_dev->irq_disabled) {
+			disable_irq_nosync(i2c_dev->irq);
+			i2c_dev->irq_disabled = 1;
+		}
+
+		complete(&i2c_dev->msg_complete);
+		goto err;
 	}
 
 	if (unlikely(status & status_err)) {
@@ -391,6 +418,8 @@ err:
 		I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
 		I2C_INT_RX_FIFO_DATA_REQ);
 	i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+	if (i2c_dev->is_dvc)
+		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
 	return IRQ_HANDLED;
 }
 
@@ -424,12 +453,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
 	packet_header = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
 	packet_header |= I2C_HEADER_IE_ENABLE;
+	if (!stop)
+		packet_header |= I2C_HEADER_REPEAT_START;
 	if (msg->flags & I2C_M_TEN)
 		packet_header |= I2C_HEADER_10BIT_ADDR;
 	if (msg->flags & I2C_M_IGNORE_NAK)
 		packet_header |= I2C_HEADER_CONT_ON_NAK;
-	if (msg->flags & I2C_M_NOSTART)
-		packet_header |= I2C_HEADER_REPEAT_START;
 	if (msg->flags & I2C_M_RD)
 		packet_header |= I2C_HEADER_READ;
 	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);