Commit e7db443b authored by Kevin Hilman's avatar Kevin Hilman

Merge branch 'davinci-i2c' into davinci-reset

parents 042f6a50 96642b3d
...@@ -36,14 +36,16 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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 (time_after(jiffies, timeout)) { if (to_cnt <= DAVINCI_I2C_MAX_TRIES) {
dev_warn(dev->dev, if (time_after(jiffies, timeout)) {
"timeout waiting for bus ready\n"); dev_warn(dev->dev,
return -ETIMEDOUT; "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) 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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 = { ...@@ -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,
}, },
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment