mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
Merge branch 'davinci-i2c' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci into for-2636/i2c/davinci
This commit is contained in:
commit
e126613e67
1 changed files with 249 additions and 61 deletions
|
@ -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_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 (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_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 (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_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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue