diff options
-rw-r--r-- | drivers/i2c/busses/i2c-imx.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 999557729ad2..c9632b2f0eaa 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c | |||
@@ -194,6 +194,7 @@ struct imx_i2c_dma { | |||
194 | struct imx_i2c_struct { | 194 | struct imx_i2c_struct { |
195 | struct i2c_adapter adapter; | 195 | struct i2c_adapter adapter; |
196 | struct clk *clk; | 196 | struct clk *clk; |
197 | struct notifier_block clk_change_nb; | ||
197 | void __iomem *base; | 198 | void __iomem *base; |
198 | wait_queue_head_t queue; | 199 | wait_queue_head_t queue; |
199 | unsigned long i2csr; | 200 | unsigned long i2csr; |
@@ -467,15 +468,14 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx) | |||
467 | return 0; | 468 | return 0; |
468 | } | 469 | } |
469 | 470 | ||
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) | ||
471 | { | 473 | { |
472 | struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; | 474 | struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; |
473 | unsigned int i2c_clk_rate; | ||
474 | unsigned int div; | 475 | unsigned int div; |
475 | int i; | 476 | int i; |
476 | 477 | ||
477 | /* Divider value calculation */ | 478 | /* Divider value calculation */ |
478 | i2c_clk_rate = clk_get_rate(i2c_imx->clk); | ||
479 | if (i2c_imx->cur_clk == i2c_clk_rate) | 479 | if (i2c_imx->cur_clk == i2c_clk_rate) |
480 | return; | 480 | return; |
481 | 481 | ||
@@ -510,6 +510,20 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) | |||
510 | #endif | 510 | #endif |
511 | } | 511 | } |
512 | 512 | ||
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 | |||
513 | static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) | 527 | static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) |
514 | { | 528 | { |
515 | unsigned int temp = 0; | 529 | unsigned int temp = 0; |
@@ -517,8 +531,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) | |||
517 | 531 | ||
518 | dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); | 532 | dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); |
519 | 533 | ||
520 | i2c_imx_set_clk(i2c_imx); | ||
521 | |||
522 | imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); | 534 | imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); |
523 | /* Enable I2C controller */ | 535 | /* Enable I2C controller */ |
524 | imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); | 536 | 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) | |||
1131 | "clock-frequency", &i2c_imx->bitrate); | 1143 | "clock-frequency", &i2c_imx->bitrate); |
1132 | if (ret < 0 && pdata && pdata->bitrate) | 1144 | if (ret < 0 && pdata && pdata->bitrate) |
1133 | i2c_imx->bitrate = pdata->bitrate; | 1145 | 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)); | ||
1134 | 1149 | ||
1135 | /* Set up chip registers to defaults */ | 1150 | /* Set up chip registers to defaults */ |
1136 | imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, | 1151 | 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) | |||
1141 | ret = i2c_imx_init_recovery_info(i2c_imx, pdev); | 1156 | ret = i2c_imx_init_recovery_info(i2c_imx, pdev); |
1142 | /* Give it another chance if pinctrl used is not ready yet */ | 1157 | /* Give it another chance if pinctrl used is not ready yet */ |
1143 | if (ret == -EPROBE_DEFER) | 1158 | if (ret == -EPROBE_DEFER) |
1144 | goto rpm_disable; | 1159 | goto clk_notifier_unregister; |
1145 | 1160 | ||
1146 | /* Add I2C adapter */ | 1161 | /* Add I2C adapter */ |
1147 | ret = i2c_add_numbered_adapter(&i2c_imx->adapter); | 1162 | ret = i2c_add_numbered_adapter(&i2c_imx->adapter); |
1148 | if (ret < 0) | 1163 | if (ret < 0) |
1149 | goto rpm_disable; | 1164 | goto clk_notifier_unregister; |
1150 | 1165 | ||
1151 | pm_runtime_mark_last_busy(&pdev->dev); | 1166 | pm_runtime_mark_last_busy(&pdev->dev); |
1152 | pm_runtime_put_autosuspend(&pdev->dev); | 1167 | pm_runtime_put_autosuspend(&pdev->dev); |
@@ -1162,6 +1177,8 @@ static int i2c_imx_probe(struct platform_device *pdev) | |||
1162 | 1177 | ||
1163 | return 0; /* Return OK */ | 1178 | return 0; /* Return OK */ |
1164 | 1179 | ||
1180 | clk_notifier_unregister: | ||
1181 | clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); | ||
1165 | rpm_disable: | 1182 | rpm_disable: |
1166 | pm_runtime_put_noidle(&pdev->dev); | 1183 | pm_runtime_put_noidle(&pdev->dev); |
1167 | pm_runtime_disable(&pdev->dev); | 1184 | pm_runtime_disable(&pdev->dev); |
@@ -1195,6 +1212,7 @@ static int i2c_imx_remove(struct platform_device *pdev) | |||
1195 | imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR); | 1212 | imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR); |
1196 | imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR); | 1213 | imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR); |
1197 | 1214 | ||
1215 | clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); | ||
1198 | clk_disable_unprepare(i2c_imx->clk); | 1216 | clk_disable_unprepare(i2c_imx->clk); |
1199 | 1217 | ||
1200 | pm_runtime_put_noidle(&pdev->dev); | 1218 | pm_runtime_put_noidle(&pdev->dev); |