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

Commit d0a0c28c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus/i2c-2636' of git://git.fluff.org/bjdooks/linux

* 'for-linus/i2c-2636' of git://git.fluff.org/bjdooks/linux:
  i2c/nuc900: add i2c driver support for nuc900
  i2c: Enable NXP LPC support in Kconfig
  i2c-pxa: fix compiler warning, due to missing const
  i2c: davinci: bus recovery procedure to clear the bus
  i2c: davinci: Add cpufreq support
  i2c: davinci: Add suspend/resume support
  i2c: davinci: Add helper functions for power management
  i2c: davinci: misc. cleanups: remove MOD_REG_BIT and IO_ADDRESS usage
  i2c: davinci: Fix smbus Oops with AIC33 usage
parents ce00f7fe f6e1901c
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
#ifndef __ASM_ARCH_NUC900_I2C_H
#define __ASM_ARCH_NUC900_I2C_H

struct nuc900_platform_i2c {
	int		bus_num;
	unsigned long   bus_freq;
};

#endif /* __ASM_ARCH_NUC900_I2C_H */
+9 −2
Original line number Original line Diff line number Diff line
@@ -448,6 +448,13 @@ config I2C_NOMADIK
	  If you say yes to this option, support will be included for the
	  If you say yes to this option, support will be included for the
	  I2C interface from ST-Ericsson's Nomadik and Ux500 architectures.
	  I2C interface from ST-Ericsson's Nomadik and Ux500 architectures.


config I2C_NUC900
	tristate "NUC900 I2C Driver"
	depends on ARCH_W90X900
	help
	  Say Y here to include support for I2C controller in the
	  Winbond/Nuvoton NUC900 based System-on-Chip devices.

config I2C_OCORES
config I2C_OCORES
	tristate "OpenCores I2C Controller"
	tristate "OpenCores I2C Controller"
	depends on EXPERIMENTAL
	depends on EXPERIMENTAL
@@ -496,8 +503,8 @@ config I2C_PMCMSP
	  will be called i2c-pmcmsp.
	  will be called i2c-pmcmsp.


config I2C_PNX
config I2C_PNX
	tristate "I2C bus support for Philips PNX targets"
	tristate "I2C bus support for Philips PNX and NXP LPC targets"
	depends on ARCH_PNX4008
	depends on ARCH_PNX4008 || ARCH_LPC32XX
	help
	help
	  This driver supports the Philips IP3204 I2C IP block master and/or
	  This driver supports the Philips IP3204 I2C IP block master and/or
	  slave controller
	  slave controller
+1 −0
Original line number Original line Diff line number Diff line
@@ -43,6 +43,7 @@ obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
obj-$(CONFIG_I2C_NOMADIK)	+= i2c-nomadik.o
obj-$(CONFIG_I2C_NOMADIK)	+= i2c-nomadik.o
obj-$(CONFIG_I2C_NUC900)	+= i2c-nuc900.o
obj-$(CONFIG_I2C_OCORES)	+= i2c-ocores.o
obj-$(CONFIG_I2C_OCORES)	+= i2c-ocores.o
obj-$(CONFIG_I2C_OMAP)		+= i2c-omap.o
obj-$(CONFIG_I2C_OMAP)		+= i2c-omap.o
obj-$(CONFIG_I2C_PASEMI)	+= i2c-pasemi.o
obj-$(CONFIG_I2C_PASEMI)	+= i2c-pasemi.o
+251 −63
Original line number Original line Diff line number Diff line
@@ -36,14 +36,16 @@
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
#include <linux/gpio.h>


#include <mach/hardware.h>
#include <mach/hardware.h>

#include <mach/i2c.h>
#include <mach/i2c.h>


/* ----- global defines ----------------------------------------------- */
/* ----- global defines ----------------------------------------------- */


#define DAVINCI_I2C_TIMEOUT	(1*HZ)
#define DAVINCI_I2C_TIMEOUT	(1*HZ)
#define DAVINCI_I2C_MAX_TRIES	2
#define I2C_DAVINCI_INTR_ALL    (DAVINCI_I2C_IMR_AAS | \
#define I2C_DAVINCI_INTR_ALL    (DAVINCI_I2C_IMR_AAS | \
				 DAVINCI_I2C_IMR_SCD | \
				 DAVINCI_I2C_IMR_SCD | \
				 DAVINCI_I2C_IMR_ARDY | \
				 DAVINCI_I2C_IMR_ARDY | \
@@ -72,37 +74,29 @@
#define DAVINCI_I2C_IVR_NACK	0x02
#define DAVINCI_I2C_IVR_NACK	0x02
#define DAVINCI_I2C_IVR_AL	0x01
#define DAVINCI_I2C_IVR_AL	0x01


#define DAVINCI_I2C_STR_BB	(1 << 12)
#define DAVINCI_I2C_STR_BB	BIT(12)
#define DAVINCI_I2C_STR_RSFULL	(1 << 11)
#define DAVINCI_I2C_STR_RSFULL	BIT(11)
#define DAVINCI_I2C_STR_SCD	(1 << 5)
#define DAVINCI_I2C_STR_SCD	BIT(5)
#define DAVINCI_I2C_STR_ARDY	(1 << 2)
#define DAVINCI_I2C_STR_ARDY	BIT(2)
#define DAVINCI_I2C_STR_NACK	(1 << 1)
#define DAVINCI_I2C_STR_NACK	BIT(1)
#define DAVINCI_I2C_STR_AL	(1 << 0)
#define DAVINCI_I2C_STR_AL	BIT(0)


#define DAVINCI_I2C_MDR_NACK	(1 << 15)
#define DAVINCI_I2C_MDR_NACK	BIT(15)
#define DAVINCI_I2C_MDR_STT	(1 << 13)
#define DAVINCI_I2C_MDR_STT	BIT(13)
#define DAVINCI_I2C_MDR_STP	(1 << 11)
#define DAVINCI_I2C_MDR_STP	BIT(11)
#define DAVINCI_I2C_MDR_MST	(1 << 10)
#define DAVINCI_I2C_MDR_MST	BIT(10)
#define DAVINCI_I2C_MDR_TRX	(1 << 9)
#define DAVINCI_I2C_MDR_TRX	BIT(9)
#define DAVINCI_I2C_MDR_XA	(1 << 8)
#define DAVINCI_I2C_MDR_XA	BIT(8)
#define DAVINCI_I2C_MDR_RM	(1 << 7)
#define DAVINCI_I2C_MDR_RM	BIT(7)
#define DAVINCI_I2C_MDR_IRS	(1 << 5)
#define DAVINCI_I2C_MDR_IRS	BIT(5)


#define DAVINCI_I2C_IMR_AAS	(1 << 6)
#define DAVINCI_I2C_IMR_AAS	BIT(6)
#define DAVINCI_I2C_IMR_SCD	(1 << 5)
#define DAVINCI_I2C_IMR_SCD	BIT(5)
#define DAVINCI_I2C_IMR_XRDY	(1 << 4)
#define DAVINCI_I2C_IMR_XRDY	BIT(4)
#define DAVINCI_I2C_IMR_RRDY	(1 << 3)
#define DAVINCI_I2C_IMR_RRDY	BIT(3)
#define DAVINCI_I2C_IMR_ARDY	(1 << 2)
#define DAVINCI_I2C_IMR_ARDY	BIT(2)
#define DAVINCI_I2C_IMR_NACK	(1 << 1)
#define DAVINCI_I2C_IMR_NACK	BIT(1)
#define DAVINCI_I2C_IMR_AL	(1 << 0)
#define DAVINCI_I2C_IMR_AL	BIT(0)

#define MOD_REG_BIT(val, mask, set) do { \
	if (set) { \
		val |= mask; \
	} else { \
		val &= ~mask; \
	} \
} while (0)


struct davinci_i2c_dev {
struct davinci_i2c_dev {
	struct device           *dev;
	struct device           *dev;
@@ -113,8 +107,13 @@ struct davinci_i2c_dev {
	u8			*buf;
	u8			*buf;
	size_t			buf_len;
	size_t			buf_len;
	int			irq;
	int			irq;
	int			stop;
	u8			terminate;
	u8			terminate;
	struct i2c_adapter	adapter;
	struct i2c_adapter	adapter;
#ifdef CONFIG_CPU_FREQ
	struct completion	xfr_complete;
	struct notifier_block	freq_transition;
#endif
};
};


/* default platform data to use if not supplied in the platform_device */
/* default platform data to use if not supplied in the platform_device */
@@ -134,12 +133,59 @@ static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
	return __raw_readw(i2c_dev->base + reg);
	return __raw_readw(i2c_dev->base + reg);
}
}


/*
/* Generate a pulse on the i2c clock pin. */
 * This functions configures I2C and brings I2C out of reset.
static void generic_i2c_clock_pulse(unsigned int scl_pin)
 * This function is called during I2C init function. This function
{
 * also gets called if I2C encounters any errors.
	u16 i;

	if (scl_pin) {
		/* Send high and low on the SCL line */
		for (i = 0; i < 9; i++) {
			gpio_set_value(scl_pin, 0);
			udelay(20);
			gpio_set_value(scl_pin, 1);
			udelay(20);
		}
	}
}

/* This routine does i2c bus recovery as specified in the
 * i2c protocol Rev. 03 section 3.16 titled "Bus clear"
 */
 */
static int i2c_davinci_init(struct davinci_i2c_dev *dev)
static void i2c_recover_bus(struct davinci_i2c_dev *dev)
{
	u32 flag = 0;
	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;

	dev_err(dev->dev, "initiating i2c bus recovery\n");
	/* Send NACK to the slave */
	flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
	flag |=  DAVINCI_I2C_MDR_NACK;
	/* write the data into mode register */
	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
	if (pdata)
		generic_i2c_clock_pulse(pdata->scl_pin);
	/* Send STOP */
	flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
	flag |= DAVINCI_I2C_MDR_STP;
	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
}

static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
								int val)
{
	u16 w;

	w = davinci_i2c_read_reg(i2c_dev, DAVINCI_I2C_MDR_REG);
	if (!val)	/* put I2C into reset */
		w &= ~DAVINCI_I2C_MDR_IRS;
	else		/* take I2C out of reset */
		w |= DAVINCI_I2C_MDR_IRS;

	davinci_i2c_write_reg(i2c_dev, DAVINCI_I2C_MDR_REG, w);
}

static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
{
{
	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
	u16 psc;
	u16 psc;
@@ -148,15 +194,6 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
	u32 clkh;
	u32 clkh;
	u32 clkl;
	u32 clkl;
	u32 input_clock = clk_get_rate(dev->clk);
	u32 input_clock = clk_get_rate(dev->clk);
	u16 w;

	if (!pdata)
		pdata = &davinci_i2c_platform_data_default;

	/* put I2C into reset */
	w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
	MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 0);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);


	/* NOTE: I2C Clock divider programming info
	/* NOTE: I2C Clock divider programming info
	 * As per I2C specs the following formulas provide prescaler
	 * As per I2C specs the following formulas provide prescaler
@@ -188,12 +225,32 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);


	dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
}

/*
 * This function configures I2C and brings I2C out of reset.
 * This function is called during I2C init function. This function
 * also gets called if I2C encounters any errors.
 */
static int i2c_davinci_init(struct davinci_i2c_dev *dev)
{
	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;

	if (!pdata)
		pdata = &davinci_i2c_platform_data_default;

	/* put I2C into reset */
	davinci_i2c_reset_ctrl(dev, 0);

	/* compute clock dividers */
	i2c_davinci_calc_clk_dividers(dev);

	/* Respond at reserved "SMBus Host" slave address" (and zero);
	/* Respond at reserved "SMBus Host" slave address" (and zero);
	 * we seem to have no option to not respond...
	 * we seem to have no option to not respond...
	 */
	 */
	davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08);


	dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
	dev_dbg(dev->dev, "PSC  = %d\n",
	dev_dbg(dev->dev, "PSC  = %d\n",
		davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
		davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
	dev_dbg(dev->dev, "CLKL = %d\n",
	dev_dbg(dev->dev, "CLKL = %d\n",
@@ -204,9 +261,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
		pdata->bus_freq, pdata->bus_delay);
		pdata->bus_freq, pdata->bus_delay);


	/* Take the I2C module out of reset: */
	/* Take the I2C module out of reset: */
	w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
	davinci_i2c_reset_ctrl(dev, 1);
	MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 1);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);


	/* Enable interrupts */
	/* Enable interrupts */
	davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL);
@@ -221,14 +276,22 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
					 char allow_sleep)
					 char allow_sleep)
{
{
	unsigned long timeout;
	unsigned long timeout;
	static u16 to_cnt;


	timeout = jiffies + dev->adapter.timeout;
	timeout = jiffies + dev->adapter.timeout;
	while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
	while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
	       & DAVINCI_I2C_STR_BB) {
	       & DAVINCI_I2C_STR_BB) {
		if (to_cnt <= DAVINCI_I2C_MAX_TRIES) {
			if (time_after(jiffies, timeout)) {
			if (time_after(jiffies, timeout)) {
				dev_warn(dev->dev,
				dev_warn(dev->dev,
				"timeout waiting for bus ready\n");
				"timeout waiting for bus ready\n");
				to_cnt++;
				return -ETIMEDOUT;
				return -ETIMEDOUT;
			} else {
				to_cnt = 0;
				i2c_recover_bus(dev);
				i2c_davinci_init(dev);
			}
		}
		}
		if (allow_sleep)
		if (allow_sleep)
			schedule_timeout(1);
			schedule_timeout(1);
@@ -250,9 +313,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
	u16 w;
	u16 w;
	int r;
	int r;


	if (msg->len == 0)
		return -EINVAL;

	if (!pdata)
	if (!pdata)
		pdata = &davinci_i2c_platform_data_default;
		pdata = &davinci_i2c_platform_data_default;
	/* Introduce a delay, required for some boards (e.g Davinci EVM) */
	/* Introduce a delay, required for some boards (e.g Davinci EVM) */
@@ -264,6 +324,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)


	dev->buf = msg->buf;
	dev->buf = msg->buf;
	dev->buf_len = msg->len;
	dev->buf_len = msg->len;
	dev->stop = stop;


	davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);


@@ -281,23 +342,40 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
		flag |= DAVINCI_I2C_MDR_TRX;
		flag |= DAVINCI_I2C_MDR_TRX;
	if (stop)
	if (stop)
		flag |= DAVINCI_I2C_MDR_STP;
		flag |= DAVINCI_I2C_MDR_STP;
	if (msg->len == 0) {
		flag |= DAVINCI_I2C_MDR_RM;
		flag &= ~DAVINCI_I2C_MDR_STP;
	}


	/* Enable receive or transmit interrupts */
	/* Enable receive or transmit interrupts */
	w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
	w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
	if (msg->flags & I2C_M_RD)
	if (msg->flags & I2C_M_RD)
		MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 1);
		w |= DAVINCI_I2C_IMR_RRDY;
	else
	else
		MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1);
		w |= DAVINCI_I2C_IMR_XRDY;
	davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);


	dev->terminate = 0;
	dev->terminate = 0;

	/* write the data into mode register */
	/* write the data into mode register */
	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);


	/*
	 * First byte should be set here, not after interrupt,
	 * because transmit-data-ready interrupt can come before
	 * NACK-interrupt during sending of previous message and
	 * ICDXR may have wrong data
	 */
	if ((!(msg->flags & I2C_M_RD)) && dev->buf_len) {
		davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, *dev->buf++);
		dev->buf_len--;
	}

	r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
	r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
						      dev->adapter.timeout);
						      dev->adapter.timeout);
	if (r == 0) {
	if (r == 0) {
		dev_err(dev->dev, "controller timed out\n");
		dev_err(dev->dev, "controller timed out\n");
		i2c_recover_bus(dev);
		i2c_davinci_init(dev);
		i2c_davinci_init(dev);
		dev->buf_len = 0;
		dev->buf_len = 0;
		return -ETIMEDOUT;
		return -ETIMEDOUT;
@@ -334,7 +412,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
			return msg->len;
			return msg->len;
		if (stop) {
		if (stop) {
			w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
			w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
			MOD_REG_BIT(w, DAVINCI_I2C_MDR_STP, 1);
			w |= DAVINCI_I2C_MDR_STP;
			davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
			davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
		}
		}
		return -EREMOTEIO;
		return -EREMOTEIO;
@@ -367,12 +445,17 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
		if (ret < 0)
		if (ret < 0)
			return ret;
			return ret;
	}
	}

#ifdef CONFIG_CPU_FREQ
	complete(&dev->xfr_complete);
#endif

	return num;
	return num;
}
}


static u32 i2c_davinci_func(struct i2c_adapter *adap)
static u32 i2c_davinci_func(struct i2c_adapter *adap)
{
{
	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
}


static void terminate_read(struct davinci_i2c_dev *dev)
static void terminate_read(struct davinci_i2c_dev *dev)
@@ -431,6 +514,14 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
		case DAVINCI_I2C_IVR_ARDY:
		case DAVINCI_I2C_IVR_ARDY:
			davinci_i2c_write_reg(dev,
			davinci_i2c_write_reg(dev,
				DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_ARDY);
				DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_ARDY);
			if (((dev->buf_len == 0) && (dev->stop != 0)) ||
			    (dev->cmd_err & DAVINCI_I2C_STR_NACK)) {
				w = davinci_i2c_read_reg(dev,
							 DAVINCI_I2C_MDR_REG);
				w |= DAVINCI_I2C_MDR_STP;
				davinci_i2c_write_reg(dev,
						      DAVINCI_I2C_MDR_REG, w);
			}
			complete(&dev->cmd_complete);
			complete(&dev->cmd_complete);
			break;
			break;


@@ -462,7 +553,7 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)


				w = davinci_i2c_read_reg(dev,
				w = davinci_i2c_read_reg(dev,
							 DAVINCI_I2C_IMR_REG);
							 DAVINCI_I2C_IMR_REG);
				MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 0);
				w &= ~DAVINCI_I2C_IMR_XRDY;
				davinci_i2c_write_reg(dev,
				davinci_i2c_write_reg(dev,
						      DAVINCI_I2C_IMR_REG,
						      DAVINCI_I2C_IMR_REG,
						      w);
						      w);
@@ -491,6 +582,48 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
	return count ? IRQ_HANDLED : IRQ_NONE;
	return count ? IRQ_HANDLED : IRQ_NONE;
}
}


#ifdef CONFIG_CPU_FREQ
static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,
				     unsigned long val, void *data)
{
	struct davinci_i2c_dev *dev;

	dev = container_of(nb, struct davinci_i2c_dev, freq_transition);
	if (val == CPUFREQ_PRECHANGE) {
		wait_for_completion(&dev->xfr_complete);
		davinci_i2c_reset_ctrl(dev, 0);
	} else if (val == CPUFREQ_POSTCHANGE) {
		i2c_davinci_calc_clk_dividers(dev);
		davinci_i2c_reset_ctrl(dev, 1);
	}

	return 0;
}

static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev)
{
	dev->freq_transition.notifier_call = i2c_davinci_cpufreq_transition;

	return cpufreq_register_notifier(&dev->freq_transition,
					 CPUFREQ_TRANSITION_NOTIFIER);
}

static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev)
{
	cpufreq_unregister_notifier(&dev->freq_transition,
				    CPUFREQ_TRANSITION_NOTIFIER);
}
#else
static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev)
{
	return 0;
}

static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev)
{
}
#endif

static struct i2c_algorithm i2c_davinci_algo = {
static struct i2c_algorithm i2c_davinci_algo = {
	.master_xfer	= i2c_davinci_xfer,
	.master_xfer	= i2c_davinci_xfer,
	.functionality	= i2c_davinci_func,
	.functionality	= i2c_davinci_func,
@@ -530,6 +663,9 @@ static int davinci_i2c_probe(struct platform_device *pdev)
	}
	}


	init_completion(&dev->cmd_complete);
	init_completion(&dev->cmd_complete);
#ifdef CONFIG_CPU_FREQ
	init_completion(&dev->xfr_complete);
#endif
	dev->dev = get_device(&pdev->dev);
	dev->dev = get_device(&pdev->dev);
	dev->irq = irq->start;
	dev->irq = irq->start;
	platform_set_drvdata(pdev, dev);
	platform_set_drvdata(pdev, dev);
@@ -541,7 +677,12 @@ static int davinci_i2c_probe(struct platform_device *pdev)
	}
	}
	clk_enable(dev->clk);
	clk_enable(dev->clk);


	dev->base = (void __iomem *)IO_ADDRESS(mem->start);
	dev->base = ioremap(mem->start, resource_size(mem));
	if (!dev->base) {
		r = -EBUSY;
		goto err_mem_ioremap;
	}

	i2c_davinci_init(dev);
	i2c_davinci_init(dev);


	r = request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev);
	r = request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev);
@@ -550,6 +691,12 @@ static int davinci_i2c_probe(struct platform_device *pdev)
		goto err_unuse_clocks;
		goto err_unuse_clocks;
	}
	}


	r = i2c_davinci_cpufreq_register(dev);
	if (r) {
		dev_err(&pdev->dev, "failed to register cpufreq\n");
		goto err_free_irq;
	}

	adap = &dev->adapter;
	adap = &dev->adapter;
	i2c_set_adapdata(adap, dev);
	i2c_set_adapdata(adap, dev);
	adap->owner = THIS_MODULE;
	adap->owner = THIS_MODULE;
@@ -571,6 +718,8 @@ static int davinci_i2c_probe(struct platform_device *pdev)
err_free_irq:
err_free_irq:
	free_irq(dev->irq, dev);
	free_irq(dev->irq, dev);
err_unuse_clocks:
err_unuse_clocks:
	iounmap(dev->base);
err_mem_ioremap:
	clk_disable(dev->clk);
	clk_disable(dev->clk);
	clk_put(dev->clk);
	clk_put(dev->clk);
	dev->clk = NULL;
	dev->clk = NULL;
@@ -589,6 +738,8 @@ static int davinci_i2c_remove(struct platform_device *pdev)
	struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
	struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
	struct resource *mem;
	struct resource *mem;


	i2c_davinci_cpufreq_deregister(dev);

	platform_set_drvdata(pdev, NULL);
	platform_set_drvdata(pdev, NULL);
	i2c_del_adapter(&dev->adapter);
	i2c_del_adapter(&dev->adapter);
	put_device(&pdev->dev);
	put_device(&pdev->dev);
@@ -599,6 +750,7 @@ static int davinci_i2c_remove(struct platform_device *pdev)


	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
	free_irq(IRQ_I2C, dev);
	free_irq(IRQ_I2C, dev);
	iounmap(dev->base);
	kfree(dev);
	kfree(dev);


	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -606,6 +758,41 @@ static int davinci_i2c_remove(struct platform_device *pdev)
	return 0;
	return 0;
}
}


#ifdef CONFIG_PM
static int davinci_i2c_suspend(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);

	/* put I2C into reset */
	davinci_i2c_reset_ctrl(i2c_dev, 0);
	clk_disable(i2c_dev->clk);

	return 0;
}

static int davinci_i2c_resume(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);

	clk_enable(i2c_dev->clk);
	/* take I2C out of reset */
	davinci_i2c_reset_ctrl(i2c_dev, 1);

	return 0;
}

static const struct dev_pm_ops davinci_i2c_pm = {
	.suspend        = davinci_i2c_suspend,
	.resume         = davinci_i2c_resume,
};

#define davinci_i2c_pm_ops (&davinci_i2c_pm)
#else
#define davinci_i2c_pm_ops NULL
#endif

/* work with hotplug and coldplug */
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_davinci");
MODULE_ALIAS("platform:i2c_davinci");


@@ -615,6 +802,7 @@ static struct platform_driver davinci_i2c_driver = {
	.driver		= {
	.driver		= {
		.name	= "i2c_davinci",
		.name	= "i2c_davinci",
		.owner	= THIS_MODULE,
		.owner	= THIS_MODULE,
		.pm	= davinci_i2c_pm_ops,
	},
	},
};
};


+709 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading