|
@@ -36,14 +36,16 @@
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/slab.h>
|
|
|
+#include <linux/cpufreq.h>
|
|
|
+#include <linux/gpio.h>
|
|
|
|
|
|
#include <mach/hardware.h>
|
|
|
-
|
|
|
#include <mach/i2c.h>
|
|
|
|
|
|
/* ----- global defines ----------------------------------------------- */
|
|
|
|
|
|
#define DAVINCI_I2C_TIMEOUT (1*HZ)
|
|
|
+#define DAVINCI_I2C_MAX_TRIES 2
|
|
|
#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_AAS | \
|
|
|
DAVINCI_I2C_IMR_SCD | \
|
|
|
DAVINCI_I2C_IMR_ARDY | \
|
|
@@ -72,37 +74,29 @@
|
|
|
#define DAVINCI_I2C_IVR_NACK 0x02
|
|
|
#define DAVINCI_I2C_IVR_AL 0x01
|
|
|
|
|
|
-#define DAVINCI_I2C_STR_BB (1 << 12)
|
|
|
-#define DAVINCI_I2C_STR_RSFULL (1 << 11)
|
|
|
-#define DAVINCI_I2C_STR_SCD (1 << 5)
|
|
|
-#define DAVINCI_I2C_STR_ARDY (1 << 2)
|
|
|
-#define DAVINCI_I2C_STR_NACK (1 << 1)
|
|
|
-#define DAVINCI_I2C_STR_AL (1 << 0)
|
|
|
-
|
|
|
-#define DAVINCI_I2C_MDR_NACK (1 << 15)
|
|
|
-#define DAVINCI_I2C_MDR_STT (1 << 13)
|
|
|
-#define DAVINCI_I2C_MDR_STP (1 << 11)
|
|
|
-#define DAVINCI_I2C_MDR_MST (1 << 10)
|
|
|
-#define DAVINCI_I2C_MDR_TRX (1 << 9)
|
|
|
-#define DAVINCI_I2C_MDR_XA (1 << 8)
|
|
|
-#define DAVINCI_I2C_MDR_RM (1 << 7)
|
|
|
-#define DAVINCI_I2C_MDR_IRS (1 << 5)
|
|
|
-
|
|
|
-#define DAVINCI_I2C_IMR_AAS (1 << 6)
|
|
|
-#define DAVINCI_I2C_IMR_SCD (1 << 5)
|
|
|
-#define DAVINCI_I2C_IMR_XRDY (1 << 4)
|
|
|
-#define DAVINCI_I2C_IMR_RRDY (1 << 3)
|
|
|
-#define DAVINCI_I2C_IMR_ARDY (1 << 2)
|
|
|
-#define DAVINCI_I2C_IMR_NACK (1 << 1)
|
|
|
-#define DAVINCI_I2C_IMR_AL (1 << 0)
|
|
|
-
|
|
|
-#define MOD_REG_BIT(val, mask, set) do { \
|
|
|
- if (set) { \
|
|
|
- val |= mask; \
|
|
|
- } else { \
|
|
|
- val &= ~mask; \
|
|
|
- } \
|
|
|
-} while (0)
|
|
|
+#define DAVINCI_I2C_STR_BB BIT(12)
|
|
|
+#define DAVINCI_I2C_STR_RSFULL BIT(11)
|
|
|
+#define DAVINCI_I2C_STR_SCD BIT(5)
|
|
|
+#define DAVINCI_I2C_STR_ARDY BIT(2)
|
|
|
+#define DAVINCI_I2C_STR_NACK BIT(1)
|
|
|
+#define DAVINCI_I2C_STR_AL BIT(0)
|
|
|
+
|
|
|
+#define DAVINCI_I2C_MDR_NACK BIT(15)
|
|
|
+#define DAVINCI_I2C_MDR_STT BIT(13)
|
|
|
+#define DAVINCI_I2C_MDR_STP BIT(11)
|
|
|
+#define DAVINCI_I2C_MDR_MST BIT(10)
|
|
|
+#define DAVINCI_I2C_MDR_TRX BIT(9)
|
|
|
+#define DAVINCI_I2C_MDR_XA BIT(8)
|
|
|
+#define DAVINCI_I2C_MDR_RM BIT(7)
|
|
|
+#define DAVINCI_I2C_MDR_IRS BIT(5)
|
|
|
+
|
|
|
+#define DAVINCI_I2C_IMR_AAS BIT(6)
|
|
|
+#define DAVINCI_I2C_IMR_SCD BIT(5)
|
|
|
+#define DAVINCI_I2C_IMR_XRDY BIT(4)
|
|
|
+#define DAVINCI_I2C_IMR_RRDY BIT(3)
|
|
|
+#define DAVINCI_I2C_IMR_ARDY BIT(2)
|
|
|
+#define DAVINCI_I2C_IMR_NACK BIT(1)
|
|
|
+#define DAVINCI_I2C_IMR_AL BIT(0)
|
|
|
|
|
|
struct davinci_i2c_dev {
|
|
|
struct device *dev;
|
|
@@ -113,8 +107,13 @@ struct davinci_i2c_dev {
|
|
|
u8 *buf;
|
|
|
size_t buf_len;
|
|
|
int irq;
|
|
|
+ int stop;
|
|
|
u8 terminate;
|
|
|
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 */
|
|
@@ -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);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * This functions 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.
|
|
|
+/* Generate a pulse on the i2c clock pin. */
|
|
|
+static void generic_i2c_clock_pulse(unsigned int scl_pin)
|
|
|
+{
|
|
|
+ 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;
|
|
|
u16 psc;
|
|
@@ -148,15 +194,6 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
|
|
|
u32 clkh;
|
|
|
u32 clkl;
|
|
|
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
|
|
|
* 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_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);
|
|
|
* we seem to have no option to not respond...
|
|
|
*/
|
|
|
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",
|
|
|
davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
|
|
|
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);
|
|
|
|
|
|
/* Take the I2C module out of reset: */
|
|
|
- w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
|
|
|
- MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 1);
|
|
|
- davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
|
|
|
+ davinci_i2c_reset_ctrl(dev, 1);
|
|
|
|
|
|
/* Enable interrupts */
|
|
|
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)
|
|
|
{
|
|
|
unsigned long timeout;
|
|
|
+ static u16 to_cnt;
|
|
|
|
|
|
timeout = jiffies + dev->adapter.timeout;
|
|
|
while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
|
|
|
& DAVINCI_I2C_STR_BB) {
|
|
|
- if (time_after(jiffies, timeout)) {
|
|
|
- dev_warn(dev->dev,
|
|
|
- "timeout waiting for bus ready\n");
|
|
|
- return -ETIMEDOUT;
|
|
|
+ if (to_cnt <= DAVINCI_I2C_MAX_TRIES) {
|
|
|
+ if (time_after(jiffies, timeout)) {
|
|
|
+ dev_warn(dev->dev,
|
|
|
+ "timeout waiting for bus ready\n");
|
|
|
+ to_cnt++;
|
|
|
+ return -ETIMEDOUT;
|
|
|
+ } else {
|
|
|
+ to_cnt = 0;
|
|
|
+ i2c_recover_bus(dev);
|
|
|
+ i2c_davinci_init(dev);
|
|
|
+ }
|
|
|
}
|
|
|
if (allow_sleep)
|
|
|
schedule_timeout(1);
|
|
@@ -250,9 +313,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
|
|
|
u16 w;
|
|
|
int r;
|
|
|
|
|
|
- if (msg->len == 0)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
if (!pdata)
|
|
|
pdata = &davinci_i2c_platform_data_default;
|
|
|
/* 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_len = msg->len;
|
|
|
+ dev->stop = stop;
|
|
|
|
|
|
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;
|
|
|
if (stop)
|
|
|
flag |= DAVINCI_I2C_MDR_STP;
|
|
|
+ if (msg->len == 0) {
|
|
|
+ flag |= DAVINCI_I2C_MDR_RM;
|
|
|
+ flag &= ~DAVINCI_I2C_MDR_STP;
|
|
|
+ }
|
|
|
|
|
|
/* Enable receive or transmit interrupts */
|
|
|
w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
|
|
|
if (msg->flags & I2C_M_RD)
|
|
|
- MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 1);
|
|
|
+ w |= DAVINCI_I2C_IMR_RRDY;
|
|
|
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);
|
|
|
|
|
|
dev->terminate = 0;
|
|
|
+
|
|
|
/* write the data into mode register */
|
|
|
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,
|
|
|
dev->adapter.timeout);
|
|
|
if (r == 0) {
|
|
|
dev_err(dev->dev, "controller timed out\n");
|
|
|
+ i2c_recover_bus(dev);
|
|
|
i2c_davinci_init(dev);
|
|
|
dev->buf_len = 0;
|
|
|
return -ETIMEDOUT;
|
|
@@ -334,7 +412,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
|
|
|
return msg->len;
|
|
|
if (stop) {
|
|
|
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);
|
|
|
}
|
|
|
return -EREMOTEIO;
|
|
@@ -367,12 +445,17 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
+#ifdef CONFIG_CPU_FREQ
|
|
|
+ complete(&dev->xfr_complete);
|
|
|
+#endif
|
|
|
+
|
|
|
return num;
|
|
|
}
|
|
|
|
|
|
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)
|
|
@@ -431,6 +514,14 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
|
|
|
case DAVINCI_I2C_IVR_ARDY:
|
|
|
davinci_i2c_write_reg(dev,
|
|
|
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);
|
|
|
break;
|
|
|
|
|
@@ -462,7 +553,7 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
|
|
|
|
|
|
w = davinci_i2c_read_reg(dev,
|
|
|
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_IMR_REG,
|
|
|
w);
|
|
@@ -491,6 +582,48 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
|
|
|
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 = {
|
|
|
.master_xfer = i2c_davinci_xfer,
|
|
|
.functionality = i2c_davinci_func,
|
|
@@ -530,6 +663,9 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
|
|
}
|
|
|
|
|
|
init_completion(&dev->cmd_complete);
|
|
|
+#ifdef CONFIG_CPU_FREQ
|
|
|
+ init_completion(&dev->xfr_complete);
|
|
|
+#endif
|
|
|
dev->dev = get_device(&pdev->dev);
|
|
|
dev->irq = irq->start;
|
|
|
platform_set_drvdata(pdev, dev);
|
|
@@ -541,7 +677,12 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
|
|
}
|
|
|
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);
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
+ r = i2c_davinci_cpufreq_register(dev);
|
|
|
+ if (r) {
|
|
|
+ dev_err(&pdev->dev, "failed to register cpufreq\n");
|
|
|
+ goto err_free_irq;
|
|
|
+ }
|
|
|
+
|
|
|
adap = &dev->adapter;
|
|
|
i2c_set_adapdata(adap, dev);
|
|
|
adap->owner = THIS_MODULE;
|
|
@@ -571,6 +718,8 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
|
|
err_free_irq:
|
|
|
free_irq(dev->irq, dev);
|
|
|
err_unuse_clocks:
|
|
|
+ iounmap(dev->base);
|
|
|
+err_mem_ioremap:
|
|
|
clk_disable(dev->clk);
|
|
|
clk_put(dev->clk);
|
|
|
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 resource *mem;
|
|
|
|
|
|
+ i2c_davinci_cpufreq_deregister(dev);
|
|
|
+
|
|
|
platform_set_drvdata(pdev, NULL);
|
|
|
i2c_del_adapter(&dev->adapter);
|
|
|
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);
|
|
|
free_irq(IRQ_I2C, dev);
|
|
|
+ iounmap(dev->base);
|
|
|
kfree(dev);
|
|
|
|
|
|
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
@@ -606,6 +758,41 @@ static int davinci_i2c_remove(struct platform_device *pdev)
|
|
|
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 */
|
|
|
MODULE_ALIAS("platform:i2c_davinci");
|
|
|
|
|
@@ -615,6 +802,7 @@ static struct platform_driver davinci_i2c_driver = {
|
|
|
.driver = {
|
|
|
.name = "i2c_davinci",
|
|
|
.owner = THIS_MODULE,
|
|
|
+ .pm = davinci_i2c_pm_ops,
|
|
|
},
|
|
|
};
|
|
|
|