Skip to content

Commit 90ad2cb

Browse files
lynxeye-devWolfram Sang
authored andcommitted
i2c: imx: use clk notifier for rate changes
Instead of repeatedly calling clk_get_rate for each transfer, register a clock notifier to update the cached divider value each time the clock rate actually changes. Signed-off-by: Lucas Stach <[email protected]> Reviewed-by: Philipp Zabel <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 398432e commit 90ad2cb

1 file changed

Lines changed: 25 additions & 7 deletions

File tree

drivers/i2c/busses/i2c-imx.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ struct imx_i2c_dma {
194194
struct imx_i2c_struct {
195195
struct i2c_adapter adapter;
196196
struct clk *clk;
197+
struct notifier_block clk_change_nb;
197198
void __iomem *base;
198199
wait_queue_head_t queue;
199200
unsigned long i2csr;
@@ -467,15 +468,14 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
467468
return 0;
468469
}
469470

470-
static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx)
471+
static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
472+
unsigned int i2c_clk_rate)
471473
{
472474
struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
473-
unsigned int i2c_clk_rate;
474475
unsigned int div;
475476
int i;
476477

477478
/* Divider value calculation */
478-
i2c_clk_rate = clk_get_rate(i2c_imx->clk);
479479
if (i2c_imx->cur_clk == i2c_clk_rate)
480480
return;
481481

@@ -510,15 +510,27 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx)
510510
#endif
511511
}
512512

513+
static int i2c_imx_clk_notifier_call(struct notifier_block *nb,
514+
unsigned long action, void *data)
515+
{
516+
struct clk_notifier_data *ndata = data;
517+
struct imx_i2c_struct *i2c_imx = container_of(&ndata->clk,
518+
struct imx_i2c_struct,
519+
clk);
520+
521+
if (action & POST_RATE_CHANGE)
522+
i2c_imx_set_clk(i2c_imx, ndata->new_rate);
523+
524+
return NOTIFY_OK;
525+
}
526+
513527
static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
514528
{
515529
unsigned int temp = 0;
516530
int result;
517531

518532
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
519533

520-
i2c_imx_set_clk(i2c_imx);
521-
522534
imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
523535
/* Enable I2C controller */
524536
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
@@ -1131,6 +1143,9 @@ static int i2c_imx_probe(struct platform_device *pdev)
11311143
"clock-frequency", &i2c_imx->bitrate);
11321144
if (ret < 0 && pdata && pdata->bitrate)
11331145
i2c_imx->bitrate = pdata->bitrate;
1146+
i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call;
1147+
clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
1148+
i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
11341149

11351150
/* Set up chip registers to defaults */
11361151
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
@@ -1141,12 +1156,12 @@ static int i2c_imx_probe(struct platform_device *pdev)
11411156
ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
11421157
/* Give it another chance if pinctrl used is not ready yet */
11431158
if (ret == -EPROBE_DEFER)
1144-
goto rpm_disable;
1159+
goto clk_notifier_unregister;
11451160

11461161
/* Add I2C adapter */
11471162
ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
11481163
if (ret < 0)
1149-
goto rpm_disable;
1164+
goto clk_notifier_unregister;
11501165

11511166
pm_runtime_mark_last_busy(&pdev->dev);
11521167
pm_runtime_put_autosuspend(&pdev->dev);
@@ -1162,6 +1177,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
11621177

11631178
return 0; /* Return OK */
11641179

1180+
clk_notifier_unregister:
1181+
clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
11651182
rpm_disable:
11661183
pm_runtime_put_noidle(&pdev->dev);
11671184
pm_runtime_disable(&pdev->dev);
@@ -1195,6 +1212,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
11951212
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
11961213
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
11971214

1215+
clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
11981216
clk_disable_unprepare(i2c_imx->clk);
11991217

12001218
pm_runtime_put_noidle(&pdev->dev);

0 commit comments

Comments
 (0)