aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Blake <ed.blake@sondrel.com>2017-10-28 07:44:34 -0400
committerWolfram Sang <wsa@the-dreams.de>2017-10-28 08:03:45 -0400
commit93222bd9b966105f43418fd336654ad10045783a (patch)
tree600a399d2268f6bca3baefa0ad157645b6f73577
parent750bd8b990856ec89a3af5836c7915ea6e2dd712 (diff)
i2c: img-scb: Add runtime PM
The i2c-img-scb driver already dynamically enables / disables clocks to save power, but doesn't use the runtime PM framework. Convert the driver to use runtime PM, so that dynamic clock management will be disabled when runtime PM is disabled, and so that autosuspend can be used to avoid unnecessarily disabling and re-enabling clocks repeatedly during a sequence of transactions. Signed-off-by: Ed Blake <ed.blake@sondrel.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r--drivers/i2c/busses/i2c-img-scb.c97
1 files changed, 78 insertions, 19 deletions
diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
index 823b0b33b2cb..f038858b6c54 100644
--- a/drivers/i2c/busses/i2c-img-scb.c
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -82,6 +82,7 @@
82#include <linux/module.h> 82#include <linux/module.h>
83#include <linux/of_platform.h> 83#include <linux/of_platform.h>
84#include <linux/platform_device.h> 84#include <linux/platform_device.h>
85#include <linux/pm_runtime.h>
85#include <linux/slab.h> 86#include <linux/slab.h>
86#include <linux/timer.h> 87#include <linux/timer.h>
87 88
@@ -280,6 +281,8 @@
280#define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err))) 281#define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err)))
281#define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M) 282#define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M)
282 283
284#define IMG_I2C_PM_TIMEOUT 1000 /* ms */
285
283enum img_i2c_mode { 286enum img_i2c_mode {
284 MODE_INACTIVE, 287 MODE_INACTIVE,
285 MODE_RAW, 288 MODE_RAW,
@@ -408,6 +411,9 @@ struct img_i2c {
408 unsigned int raw_timeout; 411 unsigned int raw_timeout;
409}; 412};
410 413
414static int img_i2c_runtime_suspend(struct device *dev);
415static int img_i2c_runtime_resume(struct device *dev);
416
411static void img_i2c_writel(struct img_i2c *i2c, u32 offset, u32 value) 417static void img_i2c_writel(struct img_i2c *i2c, u32 offset, u32 value)
412{ 418{
413 writel(value, i2c->base + offset); 419 writel(value, i2c->base + offset);
@@ -1054,8 +1060,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
1054 atomic = true; 1060 atomic = true;
1055 } 1061 }
1056 1062
1057 ret = clk_prepare_enable(i2c->scb_clk); 1063 ret = pm_runtime_get_sync(adap->dev.parent);
1058 if (ret) 1064 if (ret < 0)
1059 return ret; 1065 return ret;
1060 1066
1061 for (i = 0; i < num; i++) { 1067 for (i = 0; i < num; i++) {
@@ -1131,7 +1137,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
1131 break; 1137 break;
1132 } 1138 }
1133 1139
1134 clk_disable_unprepare(i2c->scb_clk); 1140 pm_runtime_mark_last_busy(adap->dev.parent);
1141 pm_runtime_put_autosuspend(adap->dev.parent);
1135 1142
1136 return i2c->msg_status ? i2c->msg_status : num; 1143 return i2c->msg_status ? i2c->msg_status : num;
1137} 1144}
@@ -1149,12 +1156,13 @@ static const struct i2c_algorithm img_i2c_algo = {
1149static int img_i2c_init(struct img_i2c *i2c) 1156static int img_i2c_init(struct img_i2c *i2c)
1150{ 1157{
1151 unsigned int clk_khz, bitrate_khz, clk_period, tckh, tckl, tsdh; 1158 unsigned int clk_khz, bitrate_khz, clk_period, tckh, tckl, tsdh;
1152 unsigned int i, ret, data, prescale, inc, int_bitrate, filt; 1159 unsigned int i, data, prescale, inc, int_bitrate, filt;
1153 struct img_i2c_timings timing; 1160 struct img_i2c_timings timing;
1154 u32 rev; 1161 u32 rev;
1162 int ret;
1155 1163
1156 ret = clk_prepare_enable(i2c->scb_clk); 1164 ret = pm_runtime_get_sync(i2c->adap.dev.parent);
1157 if (ret) 1165 if (ret < 0)
1158 return ret; 1166 return ret;
1159 1167
1160 rev = img_i2c_readl(i2c, SCB_CORE_REV_REG); 1168 rev = img_i2c_readl(i2c, SCB_CORE_REV_REG);
@@ -1163,7 +1171,8 @@ static int img_i2c_init(struct img_i2c *i2c)
1163 "Unknown hardware revision (%d.%d.%d.%d)\n", 1171 "Unknown hardware revision (%d.%d.%d.%d)\n",
1164 (rev >> 24) & 0xff, (rev >> 16) & 0xff, 1172 (rev >> 24) & 0xff, (rev >> 16) & 0xff,
1165 (rev >> 8) & 0xff, rev & 0xff); 1173 (rev >> 8) & 0xff, rev & 0xff);
1166 clk_disable_unprepare(i2c->scb_clk); 1174 pm_runtime_mark_last_busy(i2c->adap.dev.parent);
1175 pm_runtime_put_autosuspend(i2c->adap.dev.parent);
1167 return -EINVAL; 1176 return -EINVAL;
1168 } 1177 }
1169 1178
@@ -1314,7 +1323,8 @@ static int img_i2c_init(struct img_i2c *i2c)
1314 /* Perform a synchronous sequence to reset the bus */ 1323 /* Perform a synchronous sequence to reset the bus */
1315 ret = img_i2c_reset_bus(i2c); 1324 ret = img_i2c_reset_bus(i2c);
1316 1325
1317 clk_disable_unprepare(i2c->scb_clk); 1326 pm_runtime_mark_last_busy(i2c->adap.dev.parent);
1327 pm_runtime_put_autosuspend(i2c->adap.dev.parent);
1318 1328
1319 return ret; 1329 return ret;
1320} 1330}
@@ -1383,22 +1393,30 @@ static int img_i2c_probe(struct platform_device *pdev)
1383 1393
1384 platform_set_drvdata(pdev, i2c); 1394 platform_set_drvdata(pdev, i2c);
1385 1395
1386 ret = clk_prepare_enable(i2c->sys_clk); 1396 pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_I2C_PM_TIMEOUT);
1387 if (ret) 1397 pm_runtime_use_autosuspend(&pdev->dev);
1388 return ret; 1398 pm_runtime_enable(&pdev->dev);
1399 if (!pm_runtime_enabled(&pdev->dev)) {
1400 ret = img_i2c_runtime_resume(&pdev->dev);
1401 if (ret)
1402 return ret;
1403 }
1389 1404
1390 ret = img_i2c_init(i2c); 1405 ret = img_i2c_init(i2c);
1391 if (ret) 1406 if (ret)
1392 goto disable_clk; 1407 goto rpm_disable;
1393 1408
1394 ret = i2c_add_numbered_adapter(&i2c->adap); 1409 ret = i2c_add_numbered_adapter(&i2c->adap);
1395 if (ret < 0) 1410 if (ret < 0)
1396 goto disable_clk; 1411 goto rpm_disable;
1397 1412
1398 return 0; 1413 return 0;
1399 1414
1400disable_clk: 1415rpm_disable:
1401 clk_disable_unprepare(i2c->sys_clk); 1416 if (!pm_runtime_enabled(&pdev->dev))
1417 img_i2c_runtime_suspend(&pdev->dev);
1418 pm_runtime_disable(&pdev->dev);
1419 pm_runtime_dont_use_autosuspend(&pdev->dev);
1402 return ret; 1420 return ret;
1403} 1421}
1404 1422
@@ -1407,19 +1425,55 @@ static int img_i2c_remove(struct platform_device *dev)
1407 struct img_i2c *i2c = platform_get_drvdata(dev); 1425 struct img_i2c *i2c = platform_get_drvdata(dev);
1408 1426
1409 i2c_del_adapter(&i2c->adap); 1427 i2c_del_adapter(&i2c->adap);
1428 pm_runtime_disable(&dev->dev);
1429 if (!pm_runtime_status_suspended(&dev->dev))
1430 img_i2c_runtime_suspend(&dev->dev);
1431
1432 return 0;
1433}
1434
1435static int img_i2c_runtime_suspend(struct device *dev)
1436{
1437 struct img_i2c *i2c = dev_get_drvdata(dev);
1438
1439 clk_disable_unprepare(i2c->scb_clk);
1410 clk_disable_unprepare(i2c->sys_clk); 1440 clk_disable_unprepare(i2c->sys_clk);
1411 1441
1412 return 0; 1442 return 0;
1413} 1443}
1414 1444
1445static int img_i2c_runtime_resume(struct device *dev)
1446{
1447 struct img_i2c *i2c = dev_get_drvdata(dev);
1448 int ret;
1449
1450 ret = clk_prepare_enable(i2c->sys_clk);
1451 if (ret) {
1452 dev_err(dev, "Unable to enable sys clock\n");
1453 return ret;
1454 }
1455
1456 ret = clk_prepare_enable(i2c->scb_clk);
1457 if (ret) {
1458 dev_err(dev, "Unable to enable scb clock\n");
1459 clk_disable_unprepare(i2c->sys_clk);
1460 return ret;
1461 }
1462
1463 return 0;
1464}
1465
1415#ifdef CONFIG_PM_SLEEP 1466#ifdef CONFIG_PM_SLEEP
1416static int img_i2c_suspend(struct device *dev) 1467static int img_i2c_suspend(struct device *dev)
1417{ 1468{
1418 struct img_i2c *i2c = dev_get_drvdata(dev); 1469 struct img_i2c *i2c = dev_get_drvdata(dev);
1470 int ret;
1419 1471
1420 img_i2c_switch_mode(i2c, MODE_SUSPEND); 1472 ret = pm_runtime_force_suspend(dev);
1473 if (ret)
1474 return ret;
1421 1475
1422 clk_disable_unprepare(i2c->sys_clk); 1476 img_i2c_switch_mode(i2c, MODE_SUSPEND);
1423 1477
1424 return 0; 1478 return 0;
1425} 1479}
@@ -1429,7 +1483,7 @@ static int img_i2c_resume(struct device *dev)
1429 struct img_i2c *i2c = dev_get_drvdata(dev); 1483 struct img_i2c *i2c = dev_get_drvdata(dev);
1430 int ret; 1484 int ret;
1431 1485
1432 ret = clk_prepare_enable(i2c->sys_clk); 1486 ret = pm_runtime_force_resume(dev);
1433 if (ret) 1487 if (ret)
1434 return ret; 1488 return ret;
1435 1489
@@ -1439,7 +1493,12 @@ static int img_i2c_resume(struct device *dev)
1439} 1493}
1440#endif /* CONFIG_PM_SLEEP */ 1494#endif /* CONFIG_PM_SLEEP */
1441 1495
1442static SIMPLE_DEV_PM_OPS(img_i2c_pm, img_i2c_suspend, img_i2c_resume); 1496static const struct dev_pm_ops img_i2c_pm = {
1497 SET_RUNTIME_PM_OPS(img_i2c_runtime_suspend,
1498 img_i2c_runtime_resume,
1499 NULL)
1500 SET_SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume)
1501};
1443 1502
1444static const struct of_device_id img_scb_i2c_match[] = { 1503static const struct of_device_id img_scb_i2c_match[] = {
1445 { .compatible = "img,scb-i2c" }, 1504 { .compatible = "img,scb-i2c" },