Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a7df24d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
  ...
parents 37d8cb54 5bdfdfee
Loading
Loading
Loading
Loading
+8 −6
Original line number Original line Diff line number Diff line
@@ -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(0, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(2,	0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
U8500_I2C_CONTROLLER(2,	0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(3,	0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
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
Original line number Original line Diff line number Diff line
@@ -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,6 +24,7 @@ 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 {
@@ -31,6 +32,7 @@ struct nmk_i2c_controller {
	unsigned short	slsu;
	unsigned short	slsu;
	unsigned char	tft;
	unsigned char	tft;
	unsigned char	rft;
	unsigned char	rft;
	int timeout;
	enum i2c_freq_mode	sm;
	enum i2c_freq_mode	sm;
};
};


+7 −3
Original line number Original line Diff line number Diff line
@@ -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
	  This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
	  Atom E6xx series and compatible with the Intel EG20T PCH.
	  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
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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);
exit:

	return stat;
	udelay(I2C_DELAY);
	return 0;
}
}


/* 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 */
		/* Controller timed out */
		dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
		dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
		(void) init_hw(dev);
				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 |
	irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
			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 */
		/* Controller timed out */
		dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
		dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
		(void) init_hw(dev);
				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,15 +621,23 @@ 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;


	status = init_hw(dev);
	dev->busy = true;
	if (status)

		return status;
	if (dev->regulator)
		regulator_enable(dev->regulator);
	pm_runtime_get_sync(&dev->pdev->dev);


	clk_enable(dev->clk);
	clk_enable(dev->clk);


	status = init_hw(dev);
	if (status)
		goto out;

	/* Attempt three times to send the message queue */
	for (j = 0; j < 3; j++) {
		/* setup the i2c controller */
		/* setup the i2c controller */
		setup_i2c_controller(dev);
		setup_i2c_controller(dev);


@@ -575,7 +645,9 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
			if (unlikely(msgs[i].flags & I2C_M_TEN)) {
			if (unlikely(msgs[i].flags & I2C_M_TEN)) {
				dev_err(&dev->pdev->dev, "10 bit addressing"
				dev_err(&dev->pdev->dev, "10 bit addressing"
						"not supported\n");
						"not supported\n");
			return -EINVAL;

				status = -EINVAL;
				goto out;
			}
			}
			dev->cli.slave_adr	= msgs[i].addr;
			dev->cli.slave_adr	= msgs[i].addr;
			dev->cli.buffer		= msgs[i].buf;
			dev->cli.buffer		= msgs[i].buf;
@@ -583,29 +655,21 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
			dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
			dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
			dev->result = 0;
			dev->result = 0;


		if (msgs[i].flags & I2C_M_RD) {
			status = nmk_i2c_xfer_one(dev, msgs[i].flags);
			/* it is a read operation */
			if (status != 0)
			dev->cli.operation = I2C_READ;
				break;
			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;
		}
		}
		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);
			fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
					(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++;
			}
			/*
			/*
			 * 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);
		disable_all_interrupts(dev);
		i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS);
		clear_all_interrupts(dev);

		disable_interrupts(dev,
				(I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF
					| I2C_IT_TXFOVR | I2C_IT_RXFNF
					| I2C_IT_RXFF | I2C_IT_RXFE));


		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),
Loading