Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i3c: dw: Add power management support

Add support for runtime and system power management.
Handle clocks, resets, pads as part of suspend and resume.
Restore controller registers that could be lost due to suspend.
Finally add get and put calls appropriately in functions which
access controller : bus_init, do_daa, send_ccc_cmd, priv_xfers,
i2c_xfers, ibi and hot-join.

Signed-off-by: Aniket <aniketmaurya@google.com>
Link: https://lore.kernel.org/r/20240708062103.3296587-4-aniketmaurya@google.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

authored by

Aniket and committed by
Alexandre Belloni
62fe9d06 effd2174

+209 -17
+208 -17
drivers/i3c/master/dw-i3c-master.c
··· 17 17 #include <linux/list.h> 18 18 #include <linux/module.h> 19 19 #include <linux/of.h> 20 + #include <linux/pinctrl/consumer.h> 20 21 #include <linux/platform_device.h> 22 + #include <linux/pm_runtime.h> 21 23 #include <linux/reset.h> 22 24 #include <linux/slab.h> 23 25 ··· 219 217 #define I3C_BUS_THIGH_MAX_NS 41 220 218 221 219 #define XFER_TIMEOUT (msecs_to_jiffies(1000)) 222 - 220 + #define RPM_AUTOSUSPEND_TIMEOUT 1000 /* ms */ 223 221 struct dw_i3c_cmd { 224 222 u32 cmd_lo; 225 223 u32 cmd_hi; ··· 652 650 struct i3c_device_info info = { }; 653 651 int ret; 654 652 653 + ret = pm_runtime_resume_and_get(master->dev); 654 + if (ret < 0) { 655 + dev_err(master->dev, 656 + "<%s> cannot resume i3c bus master, err: %d\n", 657 + __func__, ret); 658 + return ret; 659 + } 660 + 655 661 ret = master->platform_ops->init(master); 656 662 if (ret) 657 - return ret; 663 + goto rpm_out; 658 664 659 665 switch (bus->mode) { 660 666 case I3C_BUS_MODE_MIXED_FAST: 661 667 case I3C_BUS_MODE_MIXED_LIMITED: 662 668 ret = dw_i2c_clk_cfg(master); 663 669 if (ret) 664 - return ret; 670 + goto rpm_out; 665 671 fallthrough; 666 672 case I3C_BUS_MODE_PURE: 667 673 ret = dw_i3c_clk_cfg(master); 668 674 if (ret) 669 - return ret; 675 + goto rpm_out; 670 676 break; 671 677 default: 672 - return -EINVAL; 678 + ret = -EINVAL; 679 + goto rpm_out; 673 680 } 674 681 675 682 ret = i3c_master_get_free_addr(m, 0); 676 683 if (ret < 0) 677 - return ret; 684 + goto rpm_out; 678 685 679 686 writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret), 680 687 master->regs + DEVICE_ADDR); ··· 693 682 694 683 ret = i3c_master_set_info(&master->base, &info); 695 684 if (ret) 696 - return ret; 685 + goto rpm_out; 697 686 698 687 dw_i3c_master_set_intr_regs(master); 699 688 dw_i3c_master_enable(master); 700 689 701 - return 0; 690 + rpm_out: 691 + pm_runtime_mark_last_busy(master->dev); 692 + pm_runtime_put_autosuspend(master->dev); 693 + return ret; 702 694 } 703 695 704 696 static void dw_i3c_master_bus_cleanup(struct i3c_master_controller *m) ··· 803 789 if (ccc->id == I3C_CCC_ENTDAA) 804 790 return -EINVAL; 805 791 792 + ret = pm_runtime_resume_and_get(master->dev); 793 + if (ret < 0) { 794 + dev_err(master->dev, 795 + "<%s> cannot resume i3c bus master, err: %d\n", 796 + __func__, ret); 797 + return ret; 798 + } 799 + 806 800 if (ccc->rnw) 807 801 ret = dw_i3c_ccc_get(master, ccc); 808 802 else 809 803 ret = dw_i3c_ccc_set(master, ccc); 810 804 805 + pm_runtime_mark_last_busy(master->dev); 806 + pm_runtime_put_autosuspend(master->dev); 811 807 return ret; 812 808 } 813 809 ··· 830 806 u8 p, last_addr = 0; 831 807 int ret, pos; 832 808 809 + ret = pm_runtime_resume_and_get(master->dev); 810 + if (ret < 0) { 811 + dev_err(master->dev, 812 + "<%s> cannot resume i3c bus master, err: %d\n", 813 + __func__, ret); 814 + return ret; 815 + } 816 + 833 817 olddevs = ~(master->free_pos); 834 818 835 819 /* Prepare DAT before launching DAA. */ ··· 846 814 continue; 847 815 848 816 ret = i3c_master_get_free_addr(m, last_addr + 1); 849 - if (ret < 0) 850 - return -ENOSPC; 817 + if (ret < 0) { 818 + ret = -ENOSPC; 819 + goto rpm_out; 820 + } 851 821 852 822 master->devs[pos].addr = ret; 853 823 p = even_parity(ret); ··· 859 825 writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(ret), 860 826 master->regs + 861 827 DEV_ADDR_TABLE_LOC(master->datstartaddr, pos)); 828 + 829 + ret = 0; 862 830 } 863 831 864 832 xfer = dw_i3c_master_alloc_xfer(master, 1); 865 - if (!xfer) 866 - return -ENOMEM; 833 + if (!xfer) { 834 + ret = -ENOMEM; 835 + goto rpm_out; 836 + } 867 837 868 838 pos = dw_i3c_master_get_free_pos(master); 869 839 if (pos < 0) { 870 840 dw_i3c_master_free_xfer(xfer); 871 - return pos; 841 + ret = pos; 842 + goto rpm_out; 872 843 } 873 844 cmd = &xfer->cmds[0]; 874 845 cmd->cmd_hi = 0x1; ··· 898 859 899 860 dw_i3c_master_free_xfer(xfer); 900 861 901 - return 0; 862 + rpm_out: 863 + pm_runtime_mark_last_busy(master->dev); 864 + pm_runtime_put_autosuspend(master->dev); 865 + return ret; 902 866 } 903 867 904 868 static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, ··· 935 893 xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers); 936 894 if (!xfer) 937 895 return -ENOMEM; 896 + 897 + ret = pm_runtime_resume_and_get(master->dev); 898 + if (ret < 0) { 899 + dev_err(master->dev, 900 + "<%s> cannot resume i3c bus master, err: %d\n", 901 + __func__, ret); 902 + return ret; 903 + } 938 904 939 905 for (i = 0; i < i3c_nxfers; i++) { 940 906 struct dw_i3c_cmd *cmd = &xfer->cmds[i]; ··· 985 935 ret = xfer->ret; 986 936 dw_i3c_master_free_xfer(xfer); 987 937 938 + pm_runtime_mark_last_busy(master->dev); 939 + pm_runtime_put_autosuspend(master->dev); 988 940 return ret; 989 941 } 990 942 ··· 1097 1045 if (!xfer) 1098 1046 return -ENOMEM; 1099 1047 1048 + ret = pm_runtime_resume_and_get(master->dev); 1049 + if (ret < 0) { 1050 + dev_err(master->dev, 1051 + "<%s> cannot resume i3c bus master, err: %d\n", 1052 + __func__, ret); 1053 + return ret; 1054 + } 1055 + 1100 1056 for (i = 0; i < i2c_nxfers; i++) { 1101 1057 struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 1102 1058 ··· 1135 1075 ret = xfer->ret; 1136 1076 dw_i3c_master_free_xfer(xfer); 1137 1077 1078 + pm_runtime_mark_last_busy(master->dev); 1079 + pm_runtime_put_autosuspend(master->dev); 1138 1080 return ret; 1139 1081 } 1140 1082 ··· 1279 1217 static int dw_i3c_master_enable_hotjoin(struct i3c_master_controller *m) 1280 1218 { 1281 1219 struct dw_i3c_master *master = to_dw_i3c_master(m); 1220 + int ret; 1221 + 1222 + ret = pm_runtime_resume_and_get(master->dev); 1223 + if (ret < 0) { 1224 + dev_err(master->dev, 1225 + "<%s> cannot resume i3c bus master, err: %d\n", 1226 + __func__, ret); 1227 + return ret; 1228 + } 1282 1229 1283 1230 dw_i3c_master_enable_sir_signal(master, true); 1284 1231 writel(readl(master->regs + DEVICE_CTRL) & ~DEV_CTRL_HOT_JOIN_NACK, ··· 1303 1232 writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK, 1304 1233 master->regs + DEVICE_CTRL); 1305 1234 1235 + pm_runtime_mark_last_busy(master->dev); 1236 + pm_runtime_put_autosuspend(master->dev); 1306 1237 return 0; 1307 1238 } 1308 1239 ··· 1315 1242 struct dw_i3c_master *master = to_dw_i3c_master(m); 1316 1243 int rc; 1317 1244 1245 + rc = pm_runtime_resume_and_get(master->dev); 1246 + if (rc < 0) { 1247 + dev_err(master->dev, 1248 + "<%s> cannot resume i3c bus master, err: %d\n", 1249 + __func__, rc); 1250 + return rc; 1251 + } 1252 + 1318 1253 dw_i3c_master_set_sir_enabled(master, dev, data->index, true); 1319 1254 1320 1255 rc = i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); 1321 1256 1322 - if (rc) 1257 + if (rc) { 1323 1258 dw_i3c_master_set_sir_enabled(master, dev, data->index, false); 1259 + pm_runtime_mark_last_busy(master->dev); 1260 + pm_runtime_put_autosuspend(master->dev); 1261 + } 1324 1262 1325 1263 return rc; 1326 1264 } ··· 1349 1265 1350 1266 dw_i3c_master_set_sir_enabled(master, dev, data->index, false); 1351 1267 1268 + pm_runtime_mark_last_busy(master->dev); 1269 + pm_runtime_put_autosuspend(master->dev); 1352 1270 return 0; 1353 1271 } 1354 1272 ··· 1551 1465 if (!master->platform_ops) 1552 1466 master->platform_ops = &dw_i3c_platform_ops_default; 1553 1467 1468 + master->dev = &pdev->dev; 1469 + 1554 1470 master->regs = devm_platform_ioremap_resource(pdev, 0); 1555 1471 if (IS_ERR(master->regs)) 1556 1472 return PTR_ERR(master->regs); ··· 1585 1497 1586 1498 platform_set_drvdata(pdev, master); 1587 1499 1500 + pm_runtime_set_autosuspend_delay(&pdev->dev, RPM_AUTOSUSPEND_TIMEOUT); 1501 + pm_runtime_use_autosuspend(&pdev->dev); 1502 + pm_runtime_set_active(&pdev->dev); 1503 + pm_runtime_enable(&pdev->dev); 1504 + 1588 1505 /* Information regarding the FIFOs/QUEUEs depth */ 1589 1506 ret = readl(master->regs + QUEUE_STATUS_LEVEL); 1590 1507 master->caps.cmdfifodepth = QUEUE_STATUS_LEVEL_CMD(ret); ··· 1606 1513 ret = i3c_master_register(&master->base, &pdev->dev, 1607 1514 &dw_mipi_i3c_ops, false); 1608 1515 if (ret) 1609 - goto err_assert_rst; 1516 + goto err_disable_pm; 1610 1517 1611 1518 return 0; 1519 + 1520 + err_disable_pm: 1521 + pm_runtime_disable(&pdev->dev); 1522 + pm_runtime_set_suspended(&pdev->dev); 1523 + pm_runtime_dont_use_autosuspend(&pdev->dev); 1612 1524 1613 1525 err_assert_rst: 1614 1526 reset_control_assert(master->core_rst); ··· 1626 1528 { 1627 1529 i3c_master_unregister(&master->base); 1628 1530 1629 - reset_control_assert(master->core_rst); 1531 + pm_runtime_disable(master->dev); 1532 + pm_runtime_set_suspended(master->dev); 1533 + pm_runtime_dont_use_autosuspend(master->dev); 1630 1534 } 1631 1535 EXPORT_SYMBOL_GPL(dw_i3c_common_remove); 1632 1536 ··· 1652 1552 dw_i3c_common_remove(master); 1653 1553 } 1654 1554 1555 + static void dw_i3c_master_restore_addrs(struct dw_i3c_master *master) 1556 + { 1557 + u32 pos, reg_val; 1558 + 1559 + writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(master->dev_addr), 1560 + master->regs + DEVICE_ADDR); 1561 + 1562 + for (pos = 0; pos < master->maxdevs; pos++) { 1563 + if (master->free_pos & BIT(pos)) 1564 + continue; 1565 + 1566 + if (master->devs[pos].is_i2c_addr) 1567 + reg_val = DEV_ADDR_TABLE_LEGACY_I2C_DEV | 1568 + DEV_ADDR_TABLE_STATIC_ADDR(master->devs[pos].addr); 1569 + else 1570 + reg_val = DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr); 1571 + 1572 + writel(reg_val, master->regs + DEV_ADDR_TABLE_LOC(master->datstartaddr, pos)); 1573 + } 1574 + } 1575 + 1576 + static void dw_i3c_master_restore_timing_regs(struct dw_i3c_master *master) 1577 + { 1578 + writel(master->i3c_pp_timing, master->regs + SCL_I3C_PP_TIMING); 1579 + writel(master->bus_free_timing, master->regs + BUS_FREE_TIMING); 1580 + writel(master->i3c_od_timing, master->regs + SCL_I3C_OD_TIMING); 1581 + writel(master->ext_lcnt_timing, master->regs + SCL_EXT_LCNT_TIMING); 1582 + 1583 + if (master->i2c_slv_prsnt) { 1584 + writel(master->i2c_fmp_timing, master->regs + SCL_I2C_FMP_TIMING); 1585 + writel(master->i2c_fm_timing, master->regs + SCL_I2C_FM_TIMING); 1586 + } 1587 + } 1588 + 1589 + static int dw_i3c_master_enable_clks(struct dw_i3c_master *master) 1590 + { 1591 + int ret = 0; 1592 + 1593 + ret = clk_prepare_enable(master->core_clk); 1594 + if (ret) 1595 + return ret; 1596 + 1597 + ret = clk_prepare_enable(master->pclk); 1598 + if (ret) { 1599 + clk_disable_unprepare(master->core_clk); 1600 + return ret; 1601 + } 1602 + 1603 + return 0; 1604 + } 1605 + 1606 + static inline void dw_i3c_master_disable_clks(struct dw_i3c_master *master) 1607 + { 1608 + clk_disable_unprepare(master->pclk); 1609 + clk_disable_unprepare(master->core_clk); 1610 + } 1611 + 1612 + static int __maybe_unused dw_i3c_master_runtime_suspend(struct device *dev) 1613 + { 1614 + struct dw_i3c_master *master = dev_get_drvdata(dev); 1615 + 1616 + dw_i3c_master_disable(master); 1617 + 1618 + reset_control_assert(master->core_rst); 1619 + dw_i3c_master_disable_clks(master); 1620 + pinctrl_pm_select_sleep_state(dev); 1621 + return 0; 1622 + } 1623 + 1624 + static int __maybe_unused dw_i3c_master_runtime_resume(struct device *dev) 1625 + { 1626 + struct dw_i3c_master *master = dev_get_drvdata(dev); 1627 + 1628 + pinctrl_pm_select_default_state(dev); 1629 + dw_i3c_master_enable_clks(master); 1630 + reset_control_deassert(master->core_rst); 1631 + 1632 + dw_i3c_master_set_intr_regs(master); 1633 + dw_i3c_master_restore_timing_regs(master); 1634 + dw_i3c_master_restore_addrs(master); 1635 + 1636 + dw_i3c_master_enable(master); 1637 + return 0; 1638 + } 1639 + 1640 + static const struct dev_pm_ops dw_i3c_pm_ops = { 1641 + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) 1642 + SET_RUNTIME_PM_OPS(dw_i3c_master_runtime_suspend, dw_i3c_master_runtime_resume, NULL) 1643 + }; 1644 + 1655 1645 static const struct of_device_id dw_i3c_master_of_match[] = { 1656 1646 { .compatible = "snps,dw-i3c-master-1.00a", }, 1657 1647 {}, ··· 1754 1564 .driver = { 1755 1565 .name = "dw-i3c-master", 1756 1566 .of_match_table = dw_i3c_master_of_match, 1567 + .pm = &dw_i3c_pm_ops, 1757 1568 }, 1758 1569 }; 1759 1570 module_platform_driver(dw_i3c_driver);
+1
drivers/i3c/master/dw-i3c-master.h
··· 25 25 26 26 struct dw_i3c_master { 27 27 struct i3c_master_controller base; 28 + struct device *dev; 28 29 u16 maxdevs; 29 30 u16 datstartaddr; 30 31 u32 free_pos;