Skip to content

Commit 13d6eb2

Browse files
fugangduanWolfram Sang
authored and
Wolfram Sang
committed
i2c: imx-lpi2c: add runtime pm support
Add runtime pm support to dynamically manage the clock to avoid enable/disable clock in frequently that can improve the i2c bus transfer performance. And use pm_runtime_force_suspend/resume() instead of lpi2c_imx_suspend/resume(). Signed-off-by: Fugang Duan <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent fe34fbf commit 13d6eb2

File tree

1 file changed

+51
-17
lines changed

1 file changed

+51
-17
lines changed

drivers/i2c/busses/i2c-imx-lpi2c.c

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/of_device.h>
3131
#include <linux/pinctrl/consumer.h>
3232
#include <linux/platform_device.h>
33+
#include <linux/pm_runtime.h>
3334
#include <linux/sched.h>
3435
#include <linux/slab.h>
3536

@@ -90,6 +91,8 @@
9091
#define FAST_PLUS_MAX_BITRATE 3400000
9192
#define HIGHSPEED_MAX_BITRATE 5000000
9293

94+
#define I2C_PM_TIMEOUT 10 /* ms */
95+
9396
enum lpi2c_imx_mode {
9497
STANDARD, /* 100+Kbps */
9598
FAST, /* 400+Kbps */
@@ -274,8 +277,8 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
274277
unsigned int temp;
275278
int ret;
276279

277-
ret = clk_enable(lpi2c_imx->clk);
278-
if (ret)
280+
ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent);
281+
if (ret < 0)
279282
return ret;
280283

281284
temp = MCR_RST;
@@ -284,16 +287,17 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
284287

285288
ret = lpi2c_imx_config(lpi2c_imx);
286289
if (ret)
287-
goto clk_disable;
290+
goto rpm_put;
288291

289292
temp = readl(lpi2c_imx->base + LPI2C_MCR);
290293
temp |= MCR_MEN;
291294
writel(temp, lpi2c_imx->base + LPI2C_MCR);
292295

293296
return 0;
294297

295-
clk_disable:
296-
clk_disable(lpi2c_imx->clk);
298+
rpm_put:
299+
pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
300+
pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
297301

298302
return ret;
299303
}
@@ -306,7 +310,8 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
306310
temp &= ~MCR_MEN;
307311
writel(temp, lpi2c_imx->base + LPI2C_MCR);
308312

309-
clk_disable(lpi2c_imx->clk);
313+
pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
314+
pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
310315

311316
return 0;
312317
}
@@ -606,22 +611,31 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
606611
return ret;
607612
}
608613

614+
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
615+
pm_runtime_use_autosuspend(&pdev->dev);
616+
pm_runtime_get_noresume(&pdev->dev);
617+
pm_runtime_set_active(&pdev->dev);
618+
pm_runtime_enable(&pdev->dev);
619+
609620
temp = readl(lpi2c_imx->base + LPI2C_PARAM);
610621
lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
611622
lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
612623

613-
clk_disable(lpi2c_imx->clk);
614-
615624
ret = i2c_add_adapter(&lpi2c_imx->adapter);
616625
if (ret)
617-
goto clk_unprepare;
626+
goto rpm_disable;
627+
628+
pm_runtime_mark_last_busy(&pdev->dev);
629+
pm_runtime_put_autosuspend(&pdev->dev);
618630

619631
dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
620632

621633
return 0;
622634

623-
clk_unprepare:
624-
clk_unprepare(lpi2c_imx->clk);
635+
rpm_disable:
636+
pm_runtime_put(&pdev->dev);
637+
pm_runtime_disable(&pdev->dev);
638+
pm_runtime_dont_use_autosuspend(&pdev->dev);
625639

626640
return ret;
627641
}
@@ -632,36 +646,56 @@ static int lpi2c_imx_remove(struct platform_device *pdev)
632646

633647
i2c_del_adapter(&lpi2c_imx->adapter);
634648

635-
clk_unprepare(lpi2c_imx->clk);
649+
pm_runtime_disable(&pdev->dev);
650+
pm_runtime_dont_use_autosuspend(&pdev->dev);
636651

637652
return 0;
638653
}
639654

640655
#ifdef CONFIG_PM_SLEEP
641-
static int lpi2c_imx_suspend(struct device *dev)
656+
static int lpi2c_runtime_suspend(struct device *dev)
642657
{
658+
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
659+
660+
clk_disable_unprepare(lpi2c_imx->clk);
643661
pinctrl_pm_select_sleep_state(dev);
644662

645663
return 0;
646664
}
647665

648-
static int lpi2c_imx_resume(struct device *dev)
666+
static int lpi2c_runtime_resume(struct device *dev)
649667
{
668+
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
669+
int ret;
670+
650671
pinctrl_pm_select_default_state(dev);
672+
ret = clk_prepare_enable(lpi2c_imx->clk);
673+
if (ret) {
674+
dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
675+
return ret;
676+
}
651677

652678
return 0;
653679
}
654-
#endif
655680

656-
static SIMPLE_DEV_PM_OPS(imx_lpi2c_pm, lpi2c_imx_suspend, lpi2c_imx_resume);
681+
static const struct dev_pm_ops lpi2c_pm_ops = {
682+
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
683+
pm_runtime_force_resume)
684+
SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend,
685+
lpi2c_runtime_resume, NULL)
686+
};
687+
#define IMX_LPI2C_PM (&lpi2c_pm_ops)
688+
#else
689+
#define IMX_LPI2C_PM NULL
690+
#endif
657691

658692
static struct platform_driver lpi2c_imx_driver = {
659693
.probe = lpi2c_imx_probe,
660694
.remove = lpi2c_imx_remove,
661695
.driver = {
662696
.name = DRIVER_NAME,
663697
.of_match_table = lpi2c_imx_of_match,
664-
.pm = &imx_lpi2c_pm,
698+
.pm = IMX_LPI2C_PM,
665699
},
666700
};
667701

0 commit comments

Comments
 (0)