瀏覽代碼

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
  ...
Linus Torvalds 14 年之前
父節點
當前提交
4a7df24ddc

+ 8 - 6
arch/arm/mach-ux500/board-mop500.c

@@ -204,7 +204,7 @@ static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
 	},
 	},
 };
 };
 
 
-#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
+#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, t_out, _sm)	\
 static struct nmk_i2c_controller u8500_i2c##id##_data = { \
 static struct nmk_i2c_controller u8500_i2c##id##_data = { \
 	/*				\
 	/*				\
 	 * slave data setup time, which is	\
 	 * slave data setup time, which is	\
@@ -219,19 +219,21 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \
 	.rft		= _rft,		\
 	.rft		= _rft,		\
 	/* std. mode operation */	\
 	/* std. mode operation */	\
 	.clk_freq	= clk,		\
 	.clk_freq	= clk,		\
+	/* Slave response timeout(ms) */\
+	.timeout	= t_out,	\
 	.sm		= _sm,		\
 	.sm		= _sm,		\
 }
 }
 
 
 /*
 /*
  * The board uses 4 i2c controllers, initialize all of
  * The board uses 4 i2c controllers, initialize all of
  * them with slave data setup time of 250 ns,
  * them with slave data setup time of 250 ns,
- * Tx & Rx FIFO threshold values as 1 and standard
+ * Tx & Rx FIFO threshold values as 8 and standard
  * mode of operation
  * mode of operation
  */
  */
-U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(2,	0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(3,	0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
+U8500_I2C_CONTROLLER(0, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(2,	0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(3,	0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 
 
 static void __init mop500_i2c_init(void)
 static void __init mop500_i2c_init(void)
 {
 {

+ 5 - 3
arch/arm/plat-nomadik/include/plat/i2c.h

@@ -11,8 +11,8 @@
 enum i2c_freq_mode {
 enum i2c_freq_mode {
 	I2C_FREQ_MODE_STANDARD,		/* up to 100 Kb/s */
 	I2C_FREQ_MODE_STANDARD,		/* up to 100 Kb/s */
 	I2C_FREQ_MODE_FAST,		/* up to 400 Kb/s */
 	I2C_FREQ_MODE_FAST,		/* up to 400 Kb/s */
+	I2C_FREQ_MODE_HIGH_SPEED,	/* up to 3.4 Mb/s */
 	I2C_FREQ_MODE_FAST_PLUS,	/* up to 1 Mb/s */
 	I2C_FREQ_MODE_FAST_PLUS,	/* up to 1 Mb/s */
-	I2C_FREQ_MODE_HIGH_SPEED	/* up to 3.4 Mb/s */
 };
 };
 
 
 /**
 /**
@@ -24,13 +24,15 @@ enum i2c_freq_mode {
  *		to the values of 14, 6, 2 for a 48 MHz i2c clk
  *		to the values of 14, 6, 2 for a 48 MHz i2c clk
  * @tft:	Tx FIFO Threshold in bytes
  * @tft:	Tx FIFO Threshold in bytes
  * @rft:	Rx FIFO Threshold in bytes
  * @rft:	Rx FIFO Threshold in bytes
+ * @timeout	Slave response timeout(ms)
  * @sm:		speed mode
  * @sm:		speed mode
  */
  */
 struct nmk_i2c_controller {
 struct nmk_i2c_controller {
 	unsigned long	clk_freq;
 	unsigned long	clk_freq;
 	unsigned short	slsu;
 	unsigned short	slsu;
-	unsigned char 	tft;
-	unsigned char 	rft;
+	unsigned char	tft;
+	unsigned char	rft;
+	int timeout;
 	enum i2c_freq_mode	sm;
 	enum i2c_freq_mode	sm;
 };
 };
 
 

+ 7 - 3
drivers/i2c/busses/Kconfig

@@ -673,15 +673,19 @@ config I2C_XILINX
 	  will be called xilinx_i2c.
 	  will be called xilinx_i2c.
 
 
 config I2C_EG20T
 config I2C_EG20T
-	tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH"
+	tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)"
 	depends on PCI
 	depends on PCI
 	help
 	help
 	  This driver is for PCH(Platform controller Hub) I2C of EG20T which
 	  This driver is for PCH(Platform controller Hub) I2C of EG20T which
 	  is an IOH(Input/Output Hub) for x86 embedded processor.
 	  is an IOH(Input/Output Hub) for x86 embedded processor.
 	  This driver can access PCH I2C bus device.
 	  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"
 comment "External I2C/SMBus adapter drivers"
 
 

+ 2 - 0
drivers/i2c/busses/i2c-eg20t.c

@@ -182,10 +182,12 @@ static DEFINE_MUTEX(pch_mutex);
 /* Definition for ML7213 by OKI SEMICONDUCTOR */
 /* Definition for ML7213 by OKI SEMICONDUCTOR */
 #define PCI_VENDOR_ID_ROHM		0x10DB
 #define PCI_VENDOR_ID_ROHM		0x10DB
 #define PCI_DEVICE_ID_ML7213_I2C	0x802D
 #define PCI_DEVICE_ID_ML7213_I2C	0x802D
+#define PCI_DEVICE_ID_ML7223_I2C	0x8010
 
 
 static struct pci_device_id __devinitdata pch_pcidev_id[] = {
 static struct pci_device_id __devinitdata pch_pcidev_id[] = {
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
 	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
 	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
+	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
 	{0,}
 	{0,}
 };
 };
 
 

+ 184 - 92
drivers/i2c/busses/i2c-nomadik.c

@@ -15,13 +15,14 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 
 #include <plat/i2c.h>
 #include <plat/i2c.h>
 
 
@@ -103,9 +104,6 @@
 /* maximum threshold value */
 /* maximum threshold value */
 #define MAX_I2C_FIFO_THRESHOLD	15
 #define MAX_I2C_FIFO_THRESHOLD	15
 
 
-/* per-transfer delay, required for the hardware to stabilize */
-#define I2C_DELAY		150
-
 enum i2c_status {
 enum i2c_status {
 	I2C_NOP,
 	I2C_NOP,
 	I2C_ON_GOING,
 	I2C_ON_GOING,
@@ -120,9 +118,6 @@ enum i2c_operation {
 	I2C_READ = 0x01
 	I2C_READ = 0x01
 };
 };
 
 
-/* controller response timeout in ms */
-#define I2C_TIMEOUT_MS	2000
-
 /**
 /**
  * struct i2c_nmk_client - client specific data
  * struct i2c_nmk_client - client specific data
  * @slave_adr: 7-bit slave address
  * @slave_adr: 7-bit slave address
@@ -151,6 +146,7 @@ struct i2c_nmk_client {
  * @stop: stop condition
  * @stop: stop condition
  * @xfer_complete: acknowledge completion for a I2C message
  * @xfer_complete: acknowledge completion for a I2C message
  * @result: controller propogated result
  * @result: controller propogated result
+ * @busy: Busy doing transfer
  */
  */
 struct nmk_i2c_dev {
 struct nmk_i2c_dev {
 	struct platform_device		*pdev;
 	struct platform_device		*pdev;
@@ -163,6 +159,8 @@ struct nmk_i2c_dev {
 	int 				stop;
 	int 				stop;
 	struct completion		xfer_complete;
 	struct completion		xfer_complete;
 	int 				result;
 	int 				result;
+	struct regulator		*regulator;
+	bool				busy;
 };
 };
 
 
 /* controller's abort causes */
 /* 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);
 	writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
 
 
 	for (i = 0; i < LOOP_ATTEMPTS; i++) {
 	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)) {
 		while (!time_after(jiffies, timeout)) {
 			if ((readl(dev->virtbase + I2C_CR) &
 			if ((readl(dev->virtbase + I2C_CR) &
@@ -253,11 +251,9 @@ static int init_hw(struct nmk_i2c_dev *dev)
 {
 {
 	int stat;
 	int stat;
 
 
-	clk_enable(dev->clk);
-
 	stat = flush_i2c_fifo(dev);
 	stat = flush_i2c_fifo(dev);
 	if (stat)
 	if (stat)
-		return stat;
+		goto exit;
 
 
 	/* disable the controller */
 	/* disable the controller */
 	i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
 	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;
 	dev->cli.operation = I2C_NO_OPERATION;
 
 
-	clk_disable(dev->clk);
-
-	udelay(I2C_DELAY);
-	return 0;
+exit:
+	return stat;
 }
 }
 
 
 /* enable peripheral, master mode operation */
 /* enable peripheral, master mode operation */
@@ -424,7 +418,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
 			dev->virtbase + I2C_IMSCR);
 			dev->virtbase + I2C_IMSCR);
 
 
 	timeout = wait_for_completion_interruptible_timeout(
 	timeout = wait_for_completion_interruptible_timeout(
-		&dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+		&dev->xfer_complete, dev->adap.timeout);
 
 
 	if (timeout < 0) {
 	if (timeout < 0) {
 		dev_err(&dev->pdev->dev,
 		dev_err(&dev->pdev->dev,
@@ -434,14 +428,32 @@ static int read_i2c(struct nmk_i2c_dev *dev)
 	}
 	}
 
 
 	if (timeout == 0) {
 	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;
 		status = -ETIMEDOUT;
 	}
 	}
 	return status;
 	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.
  * write_i2c() - Write data to I2C client.
  * @dev: private data of I2C Driver
  * @dev: private data of I2C Driver
@@ -469,8 +481,13 @@ static int write_i2c(struct nmk_i2c_dev *dev)
 	init_completion(&dev->xfer_complete);
 	init_completion(&dev->xfer_complete);
 
 
 	/* enable interrupts by settings the masks */
 	/* 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
 	 * 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);
 			dev->virtbase + I2C_IMSCR);
 
 
 	timeout = wait_for_completion_interruptible_timeout(
 	timeout = wait_for_completion_interruptible_timeout(
-		&dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+		&dev->xfer_complete, dev->adap.timeout);
 
 
 	if (timeout < 0) {
 	if (timeout < 0) {
 		dev_err(&dev->pdev->dev,
 		dev_err(&dev->pdev->dev,
@@ -498,15 +515,60 @@ static int write_i2c(struct nmk_i2c_dev *dev)
 	}
 	}
 
 
 	if (timeout == 0) {
 	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;
 		status = -ETIMEDOUT;
 	}
 	}
 
 
 	return status;
 	return status;
 }
 }
 
 
+/**
+ * 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
  * nmk_i2c_xfer() - I2C transfer function used by kernel framework
  * @i2c_adap: Adapter pointer to the controller
  * @i2c_adap: Adapter pointer to the controller
@@ -559,53 +621,55 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 {
 {
 	int status;
 	int status;
 	int i;
 	int i;
-	u32 cause;
 	struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
 	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);
 	status = init_hw(dev);
 	if (status)
 	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);
 	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 */
 	/* return the no. messages processed */
 	if (status)
 	if (status)
@@ -666,17 +730,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 			 */
 			 */
 			disable_interrupts(dev, I2C_IT_TXFNE);
 			disable_interrupts(dev, I2C_IT_TXFNE);
 		} else {
 		} 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
 			 * if done, close the transfer by disabling the
 			 * corresponding TXFNE interrupt
 			 * 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) {
 		if (dev->cli.count) {
-			dev->result = -1;
+			dev->result = -EIO;
 			dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
 			dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
 					"xfered\n", dev->cli.count);
 					"xfered\n", dev->cli.count);
 			(void) init_hw(dev);
 			(void) init_hw(dev);
@@ -749,7 +798,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 
 
 	/* Master Arbitration lost interrupt */
 	/* Master Arbitration lost interrupt */
 	case I2C_IT_MAL:
 	case I2C_IT_MAL:
-		dev->result = -1;
+		dev->result = -EIO;
 		(void) init_hw(dev);
 		(void) init_hw(dev);
 
 
 		i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
 		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.
 	 * during the transaction.
 	 */
 	 */
 	case I2C_IT_BERR:
 	case I2C_IT_BERR:
-		dev->result = -1;
+		dev->result = -EIO;
 		/* get the status */
 		/* get the status */
 		if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
 		if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
 			(void) init_hw(dev);
 			(void) init_hw(dev);
@@ -779,7 +828,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 	 * the Tx FIFO is full.
 	 * the Tx FIFO is full.
 	 */
 	 */
 	case I2C_IT_TXFOVR:
 	case I2C_IT_TXFOVR:
-		dev->result = -1;
+		dev->result = -EIO;
 		(void) init_hw(dev);
 		(void) init_hw(dev);
 
 
 		dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
 		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;
 	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)
 static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
 {
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -830,7 +911,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err_no_mem;
 		goto err_no_mem;
 	}
 	}
-
+	dev->busy = false;
 	dev->pdev = pdev;
 	dev->pdev = pdev;
 	platform_set_drvdata(pdev, dev);
 	platform_set_drvdata(pdev, dev);
 
 
@@ -860,6 +941,15 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 		goto err_irq;
 		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);
 	dev->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(dev->clk)) {
 	if (IS_ERR(dev->clk)) {
 		dev_err(&pdev->dev, "could not get i2c clock\n");
 		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->owner	= THIS_MODULE;
 	adap->class	= I2C_CLASS_HWMON | I2C_CLASS_SPD;
 	adap->class	= I2C_CLASS_HWMON | I2C_CLASS_SPD;
 	adap->algo	= &nmk_i2c_algo;
 	adap->algo	= &nmk_i2c_algo;
+	adap->timeout	= pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
+		msecs_to_jiffies(20000);
 	snprintf(adap->name, sizeof(adap->name),
 	snprintf(adap->name, sizeof(adap->name),
 		 "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
 		 "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);
 	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 "
 	dev_info(&pdev->dev, "initialize %s on virtual "
 		"base %p\n", adap->name, dev->virtbase);
 		"base %p\n", adap->name, dev->virtbase);
 
 
@@ -904,10 +990,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
 
 	return 0;
 	return 0;
 
 
- err_init_hw:
  err_add_adap:
  err_add_adap:
 	clk_put(dev->clk);
 	clk_put(dev->clk);
  err_no_clk:
  err_no_clk:
+	if (dev->regulator)
+		regulator_put(dev->regulator);
+	pm_runtime_disable(&pdev->dev);
 	free_irq(dev->irq, dev);
 	free_irq(dev->irq, dev);
  err_irq:
  err_irq:
 	iounmap(dev->virtbase);
 	iounmap(dev->virtbase);
@@ -938,6 +1026,9 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
 	if (res)
 	if (res)
 		release_mem_region(res->start, resource_size(res));
 		release_mem_region(res->start, resource_size(res));
 	clk_put(dev->clk);
 	clk_put(dev->clk);
+	if (dev->regulator)
+		regulator_put(dev->regulator);
+	pm_runtime_disable(&pdev->dev);
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);
 	kfree(dev);
 	kfree(dev);
 
 
@@ -948,6 +1039,7 @@ static struct platform_driver nmk_i2c_driver = {
 	.driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 		.name = DRIVER_NAME,
 		.name = DRIVER_NAME,
+		.pm = &nmk_i2c_pm,
 	},
 	},
 	.probe = nmk_i2c_probe,
 	.probe = nmk_i2c_probe,
 	.remove = __devexit_p(nmk_i2c_remove),
 	.remove = __devexit_p(nmk_i2c_remove),

+ 13 - 6
drivers/i2c/busses/i2c-sh_mobile.c

@@ -32,6 +32,7 @@
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/i2c/i2c-sh_mobile.h>
 
 
 /* Transmit operation:                                                      */
 /* Transmit operation:                                                      */
 /*                                                                          */
 /*                                                                          */
@@ -117,7 +118,7 @@ struct sh_mobile_i2c_data {
 	struct device *dev;
 	struct device *dev;
 	void __iomem *reg;
 	void __iomem *reg;
 	struct i2c_adapter adap;
 	struct i2c_adapter adap;
-
+	unsigned long bus_speed;
 	struct clk *clk;
 	struct clk *clk;
 	u_int8_t icic;
 	u_int8_t icic;
 	u_int8_t iccl;
 	u_int8_t iccl;
@@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd)
 	 * We also round off the result.
 	 * We also round off the result.
 	 */
 	 */
 	num = i2c_clk * 5;
 	num = i2c_clk * 5;
-	denom = NORMAL_SPEED * 9;
+	denom = pd->bus_speed * 9;
 	tmp = num * 10 / denom;
 	tmp = num * 10 / denom;
 	if (tmp % 10 >= 5)
 	if (tmp % 10 >= 5)
 		pd->iccl = (u_int8_t)((num/denom) + 1);
 		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)
 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 sh_mobile_i2c_data *pd;
 	struct i2c_adapter *adap;
 	struct i2c_adapter *adap;
 	struct resource *res;
 	struct resource *res;
-	char clk_name[8];
 	int size;
 	int size;
 	int ret;
 	int ret;
 
 
@@ -587,10 +588,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
 		return -ENOMEM;
 		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)) {
 	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);
 		ret = PTR_ERR(pd->clk);
 		goto err;
 		goto err;
 	}
 	}
@@ -620,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
 		goto err_irq;
 		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
 	/* The IIC blocks on SH-Mobile ARM processors
 	 * come with two new bits in ICIC.
 	 * come with two new bits in ICIC.
 	 */
 	 */
@@ -660,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
 		goto err_all;
 		goto err_all;
 	}
 	}
 
 
+	dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n",
+		 adap->nr, pd->bus_speed);
 	return 0;
 	return 0;
 
 
  err_all:
  err_all:

+ 34 - 5
drivers/i2c/busses/i2c-tegra.c

@@ -35,8 +35,10 @@
 #define BYTES_PER_FIFO_WORD 4
 #define BYTES_PER_FIFO_WORD 4
 
 
 #define I2C_CNFG				0x000
 #define I2C_CNFG				0x000
+#define I2C_CNFG_DEBOUNCE_CNT_SHIFT		12
 #define I2C_CNFG_PACKET_MODE_EN			(1<<10)
 #define I2C_CNFG_PACKET_MODE_EN			(1<<10)
 #define I2C_CNFG_NEW_MASTER_FSM			(1<<11)
 #define I2C_CNFG_NEW_MASTER_FSM			(1<<11)
+#define I2C_STATUS				0x01C
 #define I2C_SL_CNFG				0x020
 #define I2C_SL_CNFG				0x020
 #define I2C_SL_CNFG_NEWSL			(1<<2)
 #define I2C_SL_CNFG_NEWSL			(1<<2)
 #define I2C_SL_ADDR1				0x02c
 #define I2C_SL_ADDR1				0x02c
@@ -77,6 +79,7 @@
 #define I2C_ERR_NONE				0x00
 #define I2C_ERR_NONE				0x00
 #define I2C_ERR_NO_ACK				0x01
 #define I2C_ERR_NO_ACK				0x01
 #define I2C_ERR_ARBITRATION_LOST		0x02
 #define I2C_ERR_ARBITRATION_LOST		0x02
+#define I2C_ERR_UNKNOWN_INTERRUPT		0x04
 
 
 #define PACKET_HEADER0_HEADER_SIZE_SHIFT	28
 #define PACKET_HEADER0_HEADER_SIZE_SHIFT	28
 #define PACKET_HEADER0_PACKET_ID_SHIFT		16
 #define PACKET_HEADER0_PACKET_ID_SHIFT		16
@@ -121,6 +124,7 @@ struct tegra_i2c_dev {
 	void __iomem *base;
 	void __iomem *base;
 	int cont_id;
 	int cont_id;
 	int irq;
 	int irq;
+	bool irq_disabled;
 	int is_dvc;
 	int is_dvc;
 	struct completion msg_complete;
 	struct completion msg_complete;
 	int msg_err;
 	int msg_err;
@@ -325,11 +329,17 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 	if (i2c_dev->is_dvc)
 	if (i2c_dev->is_dvc)
 		tegra_dvc_init(i2c_dev);
 		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, val, I2C_CNFG);
 	i2c_writel(i2c_dev, 0, I2C_INT_MASK);
 	i2c_writel(i2c_dev, 0, I2C_INT_MASK);
 	clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8);
 	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 |
 	val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
 		0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
 		0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
 	i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
 	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;
 		err = -ETIMEDOUT;
 
 
 	clk_disable(i2c_dev->clk);
 	clk_disable(i2c_dev->clk);
+
+	if (i2c_dev->irq_disabled) {
+		i2c_dev->irq_disabled = 0;
+		enable_irq(i2c_dev->irq);
+	}
+
 	return err;
 	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);
 	status = i2c_readl(i2c_dev, I2C_INT_STATUS);
 
 
 	if (status == 0) {
 	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)) {
 	if (unlikely(status & status_err)) {
@@ -391,6 +418,8 @@ err:
 		I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
 		I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
 		I2C_INT_RX_FIFO_DATA_REQ);
 		I2C_INT_RX_FIFO_DATA_REQ);
 	i2c_writel(i2c_dev, status, I2C_INT_STATUS);
 	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;
 	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 = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
 	packet_header |= I2C_HEADER_IE_ENABLE;
 	packet_header |= I2C_HEADER_IE_ENABLE;
+	if (!stop)
+		packet_header |= I2C_HEADER_REPEAT_START;
 	if (msg->flags & I2C_M_TEN)
 	if (msg->flags & I2C_M_TEN)
 		packet_header |= I2C_HEADER_10BIT_ADDR;
 		packet_header |= I2C_HEADER_10BIT_ADDR;
 	if (msg->flags & I2C_M_IGNORE_NAK)
 	if (msg->flags & I2C_M_IGNORE_NAK)
 		packet_header |= I2C_HEADER_CONT_ON_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)
 	if (msg->flags & I2C_M_RD)
 		packet_header |= I2C_HEADER_READ;
 		packet_header |= I2C_HEADER_READ;
 	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
 	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);

+ 10 - 0
include/linux/i2c/i2c-sh_mobile.h

@@ -0,0 +1,10 @@
+#ifndef __I2C_SH_MOBILE_H__
+#define __I2C_SH_MOBILE_H__
+
+#include <linux/platform_device.h>
+
+struct i2c_sh_mobile_platform_data {
+	unsigned long bus_speed;
+};
+
+#endif /* __I2C_SH_MOBILE_H__ */