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

mmc: sdhci-of-dwcmshc: Add runtime PM operations

This commit implements the runtime PM operations to disable eMMC card clock
when idle.

Reviewed-by: David Thompson <davthompson@nvidia.com>
Signed-off-by: Liming Sun <limings@nvidia.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/20230822195929.168552-2-limings@nvidia.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Liming Sun and committed by
Ulf Hansson
48fe8fad a11937b3

+62 -2
+62 -2
drivers/mmc/host/sdhci-of-dwcmshc.c
··· 15 15 #include <linux/module.h> 16 16 #include <linux/of.h> 17 17 #include <linux/platform_device.h> 18 + #include <linux/pm_runtime.h> 18 19 #include <linux/reset.h> 19 20 #include <linux/sizes.h> 20 21 ··· 549 548 550 549 host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; 551 550 551 + pm_runtime_get_noresume(dev); 552 + pm_runtime_set_active(dev); 553 + pm_runtime_enable(dev); 554 + 552 555 err = sdhci_setup_host(host); 553 556 if (err) 554 - goto err_clk; 557 + goto err_rpm; 555 558 556 559 if (rk_priv) 557 560 dwcmshc_rk35xx_postinit(host, priv); ··· 564 559 if (err) 565 560 goto err_setup_host; 566 561 562 + pm_runtime_put(dev); 563 + 567 564 return 0; 568 565 569 566 err_setup_host: 570 567 sdhci_cleanup_host(host); 568 + err_rpm: 569 + pm_runtime_disable(dev); 570 + pm_runtime_put_noidle(dev); 571 571 err_clk: 572 572 clk_disable_unprepare(pltfm_host->clk); 573 573 clk_disable_unprepare(priv->bus_clk); ··· 609 599 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); 610 600 struct rk35xx_priv *rk_priv = priv->priv; 611 601 int ret; 602 + 603 + pm_runtime_resume(dev); 612 604 613 605 ret = sdhci_suspend_host(host); 614 606 if (ret) ··· 671 659 } 672 660 #endif 673 661 674 - static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume); 662 + #ifdef CONFIG_PM 663 + 664 + static void dwcmshc_enable_card_clk(struct sdhci_host *host) 665 + { 666 + u16 ctrl; 667 + 668 + ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 669 + if ((ctrl & SDHCI_CLOCK_INT_EN) && !(ctrl & SDHCI_CLOCK_CARD_EN)) { 670 + ctrl |= SDHCI_CLOCK_CARD_EN; 671 + sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL); 672 + } 673 + } 674 + 675 + static void dwcmshc_disable_card_clk(struct sdhci_host *host) 676 + { 677 + u16 ctrl; 678 + 679 + ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 680 + if (ctrl & SDHCI_CLOCK_CARD_EN) { 681 + ctrl &= ~SDHCI_CLOCK_CARD_EN; 682 + sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL); 683 + } 684 + } 685 + 686 + static int dwcmshc_runtime_suspend(struct device *dev) 687 + { 688 + struct sdhci_host *host = dev_get_drvdata(dev); 689 + 690 + dwcmshc_disable_card_clk(host); 691 + 692 + return 0; 693 + } 694 + 695 + static int dwcmshc_runtime_resume(struct device *dev) 696 + { 697 + struct sdhci_host *host = dev_get_drvdata(dev); 698 + 699 + dwcmshc_enable_card_clk(host); 700 + 701 + return 0; 702 + } 703 + 704 + #endif 705 + 706 + static const struct dev_pm_ops dwcmshc_pmops = { 707 + SET_SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend, dwcmshc_resume) 708 + SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend, 709 + dwcmshc_runtime_resume, NULL) 710 + }; 675 711 676 712 static struct platform_driver sdhci_dwcmshc_driver = { 677 713 .driver = {