Merge branch 'i2c/i2c-host' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git

This commit is contained in:
Stephen Rothwell 2024-12-20 11:07:36 +11:00
commit 2f19d7a812
2 changed files with 57 additions and 13 deletions

View File

@ -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)
};

View File

@ -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)