mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 09:12:07 +00:00
Merge branch 'i2c/i2c-host' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git
This commit is contained in:
commit
2f19d7a812
@ -621,8 +621,8 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
|
||||
unsigned int i2c_clk_rate)
|
||||
static int i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
|
||||
unsigned int i2c_clk_rate)
|
||||
{
|
||||
struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
|
||||
unsigned int div;
|
||||
@ -637,7 +637,11 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
|
||||
|
||||
/* Divider value calculation */
|
||||
if (i2c_imx->cur_clk == i2c_clk_rate)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/* Keep the denominator of the following program always NOT equal to 0. */
|
||||
if (!(i2c_clk_rate / 2))
|
||||
return -EINVAL;
|
||||
|
||||
i2c_imx->cur_clk = i2c_clk_rate;
|
||||
|
||||
@ -668,6 +672,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
|
||||
dev_dbg(&i2c_imx->adapter.dev, "IFDR[IC]=0x%x, REAL DIV=%d\n",
|
||||
i2c_clk_div[i].val, i2c_clk_div[i].div);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_imx_clk_notifier_call(struct notifier_block *nb,
|
||||
@ -677,11 +683,12 @@ static int i2c_imx_clk_notifier_call(struct notifier_block *nb,
|
||||
struct imx_i2c_struct *i2c_imx = container_of(nb,
|
||||
struct imx_i2c_struct,
|
||||
clk_change_nb);
|
||||
int ret = 0;
|
||||
|
||||
if (action & POST_RATE_CHANGE)
|
||||
i2c_imx_set_clk(i2c_imx, ndata->new_rate);
|
||||
ret = i2c_imx_set_clk(i2c_imx, ndata->new_rate);
|
||||
|
||||
return NOTIFY_OK;
|
||||
return notifier_from_errno(ret);
|
||||
}
|
||||
|
||||
static int i2c_imx_start(struct imx_i2c_struct *i2c_imx, bool atomic)
|
||||
@ -1760,7 +1767,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
||||
goto rpm_disable;
|
||||
|
||||
/* Request IRQ */
|
||||
ret = request_irq(irq, i2c_imx_isr, IRQF_SHARED, pdev->name, i2c_imx);
|
||||
ret = request_irq(irq, i2c_imx_isr, IRQF_SHARED | IRQF_NO_SUSPEND,
|
||||
pdev->name, i2c_imx);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
|
||||
goto rpm_disable;
|
||||
@ -1780,7 +1788,11 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
||||
i2c_imx->bitrate = pdata->bitrate;
|
||||
i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call;
|
||||
clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
|
||||
i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
|
||||
ret = i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "can't get I2C clock\n");
|
||||
goto clk_notifier_unregister;
|
||||
}
|
||||
|
||||
i2c_imx_reset_regs(i2c_imx);
|
||||
|
||||
@ -1874,7 +1886,43 @@ static int i2c_imx_runtime_resume(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2c_imx_suspend(struct device *dev)
|
||||
{
|
||||
/*
|
||||
* Some I2C devices may need the I2C controller to remain active
|
||||
* during resume_noirq() or suspend_noirq(). If the controller is
|
||||
* autosuspended, there is no way to wake it up once runtime PM is
|
||||
* disabled (in suspend_late()).
|
||||
*
|
||||
* During system resume, the I2C controller will be available only
|
||||
* after runtime PM is re-enabled (in resume_early()). However, this
|
||||
* may be too late for some devices.
|
||||
*
|
||||
* Wake up the controller in the suspend() callback while runtime PM
|
||||
* is still enabled. The I2C controller will remain available until
|
||||
* the suspend_noirq() callback (pm_runtime_force_suspend()) is
|
||||
* called. During resume, the I2C controller can be restored by the
|
||||
* resume_noirq() callback (pm_runtime_force_resume()).
|
||||
*
|
||||
* Finally, the resume() callback re-enables autosuspend, ensuring
|
||||
* the I2C controller remains available until the system enters
|
||||
* suspend_noirq() and from resume_noirq().
|
||||
*/
|
||||
return pm_runtime_resume_and_get(dev);
|
||||
}
|
||||
|
||||
static int i2c_imx_resume(struct device *dev)
|
||||
{
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops i2c_imx_pm_ops = {
|
||||
NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
|
||||
RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
|
@ -464,12 +464,8 @@ static void ki2c_unregister_devices(struct ki2c *ki2c)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ki2c->client_size; i++) {
|
||||
struct i2c_client *client = ki2c->client[i];
|
||||
|
||||
if (client)
|
||||
i2c_unregister_device(client);
|
||||
}
|
||||
for (i = 0; i < ki2c->client_size; i++)
|
||||
i2c_unregister_device(ki2c->client[i]);
|
||||
}
|
||||
|
||||
static int ki2c_register_devices(struct ki2c *ki2c)
|
||||
|
Loading…
Reference in New Issue
Block a user