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 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 = { \
	/*				\
	 * slave data setup time, which is	\
@@ -219,19 +219,21 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \
	.rft		= _rft,		\
	/* std. mode operation */	\
	.clk_freq	= clk,		\
	/* Slave response timeout(ms) */\
	.timeout	= t_out,	\
	.sm		= _sm,		\
}

/*
 * The board uses 4 i2c controllers, initialize all of
 * 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
 */
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)
{
+5 −3
Original line number Diff line number Diff line
@@ -11,8 +11,8 @@
enum i2c_freq_mode {
	I2C_FREQ_MODE_STANDARD,		/* up to 100 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_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
 * @tft:	Tx FIFO Threshold in bytes
 * @rft:	Rx FIFO Threshold in bytes
 * @timeout	Slave response timeout(ms)
 * @sm:		speed mode
 */
struct nmk_i2c_controller {
@@ -31,6 +32,7 @@ struct nmk_i2c_controller {
	unsigned short	slsu;
	unsigned char	tft;
	unsigned char	rft;
	int timeout;
	enum i2c_freq_mode	sm;
};

+7 −3
Original line number Diff line number Diff line
@@ -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"

+2 −0
Original line number Diff line number Diff line
@@ -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,}
};

+184 −92
Original line number Diff line number Diff line
@@ -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,15 +515,60 @@ 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;
	}

	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
 * @i2c_adap: Adapter pointer to the controller
@@ -559,15 +621,23 @@ 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;

	status = init_hw(dev);
	if (status)
		return status;
	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)
		goto out;

	/* Attempt three times to send the message queue */
	for (j = 0; j < 3; j++) {
		/* setup the i2c controller */
		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)) {
				dev_err(&dev->pdev->dev, "10 bit addressing"
						"not supported\n");
			return -EINVAL;

				status = -EINVAL;
				goto out;
			}
			dev->cli.slave_adr	= msgs[i].addr;
			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->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 = 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),
Loading