drivers: Changes for v5.17-rc1

This is an assortment of driver patches that rely on some of the changes
 in the for-5.17/soc branch. These have all been acked by the respective
 maintainers and go through the Tegra tree to more easily handle the
 build dependency.
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCAAxFiEEiOrDCAFJzPfAjcif3SOs138+s6EFAmG8sMMTHHRyZWRpbmdA
 bnZpZGlhLmNvbQAKCRDdI6zXfz6zoZo+EACQhJAgO3Qo/Xaxcyh5qRBAgYKCwGSR
 eJcuaEcinYFomXUfRb57SycZDVNTFRXnbr/2SbvNlOLVrf7gRVkan/2rdCHlc27n
 BNDjiCx4c0oD1crnhJriM57ILUYqRNB0YWjnfsv3oOl+ZNkzNdIHmM8hxwEY6+5U
 Mc2Qj7WADZe0I+dFahyvDyfgBiPuPmamK1tWeJoeXOWNhgY51NFIgvGvp6IPCJFN
 NVWkhm+YB93e5t5KZMNEETqNx63Ep0k31tP6LPkqKDoScpFkSZLTq5Icx92Kr6Vk
 e+nSJn8sdsoym2VOHl33Cx7WXIHu+crmM7y/I+BNvgafigOd6LhzA2EnzMDyPHCo
 8ngd2x7vvy/CPaI45yczvPyyyptZGYPO2G9PmpFsT8ydPbMOzx0igQ3mtF8cZaeN
 izkcSvxRczCjN9rVhybghxktAmQihlGJLYB67sDoplLlc5QAJjH8kKSQcaLDmyAu
 /xgxwssSjWRtVacT7Ro5h8BYD6pmnlH9XmHCYprUQRdd446MWSl56bdw4iZXkpCM
 UdLnsgjHHNN41d8cKSU97KLxG2ynnPRF2mqxRDEXa8OWQfK/6H6spCkLqPgo572T
 N+AezZ2hqljuO0AGeixx+bExQLbqKt8becQP6CqynT9xZVkk+b2iYCTGKA04gb1l
 tpxRe5X1Sracow==
 =YfSG
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmHAbq4ACgkQmmx57+YA
 GNncmhAAgYwqoRCobfEDxMm+4zjFoimuZWynahKG0c/t7GcFfBQVIh4uLmTLd0bm
 8sjGW7R9BcNRtbI5ZX2buN5LpZ5qDk/HAoNA+QhgWwHuLS4/FHx2bOnYOfvCWKdK
 elXfI8SaZ3l5DClasvt865niELpj95PHEN2Yr3CqOircgGApazN/GkrefNj3v+YL
 UqhDNW2XhUKjdKddBXH9n8SftHHdc9CP61c8zNUql7CikpzPAfh/ZjBuxqwF5NtZ
 C7XaH9uRVr6v/rWl7T5+YSSgXkZFBH/D6NWFg+VVVkZwoZJDHuPY0yv3JwBDxzQL
 F7WNWxT7fZrXBjFxVvQGLvP5kab4RV4nZAwkwalOZQ7EmtqpKmtwurOh/X8qGbmk
 IpqeprisWVeUuRQxS3vARMRr9Xvf4yRQ+Z0AIW0u/eadVrpboXvHKQZpxfviA8v2
 tITsOHVB8/3hFt7t6FGMdaQhnp8Nsk9WNUv8zDwpa5cNoItZST9t0sXh+XnBKJ7N
 5WH83w64N/fBuFs1/c4A3MUP+GX7V7p3IoJIQZYFLRokXz3meuw9fGjQJZWAb+Mv
 OiWjQS1rUAJl81hU1KWXDelHJ1vg8DMZu1MrLmw4PzgtFq8yy8HICxLuwZdcvDhR
 0A8/ue+5r++XtYAfj+euhrUvNVKYXa5M9Th7LtSeATjX5r0D4UU=
 =lWBt
 -----END PGP SIGNATURE-----

Merge tag 'tegra-for-5.17-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into arm/drivers

drivers: Changes for v5.17-rc1

This is an assortment of driver patches that rely on some of the changes
in the for-5.17/soc branch. These have all been acked by the respective
maintainers and go through the Tegra tree to more easily handle the
build dependency.

* tag 'tegra-for-5.17-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  media: staging: tegra-vde: Support generic power domain
  spi: tegra20-slink: Add OPP support
  mtd: rawnand: tegra: Add runtime PM and OPP support
  mmc: sdhci-tegra: Add runtime PM and OPP support
  pwm: tegra: Add runtime PM and OPP support
  bus: tegra-gmi: Add runtime PM and OPP support
  usb: chipidea: tegra: Add runtime PM and OPP support
  soc/tegra: Add devm_tegra_core_dev_init_opp_table_common()
  soc/tegra: Enable runtime PM during OPP state-syncing

Link: https://lore.kernel.org/r/20211217162253.1801077-2-thierry.reding@gmail.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2021-12-20 12:53:18 +01:00
commit a1539b2e26
9 changed files with 369 additions and 67 deletions

View File

@ -13,8 +13,11 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <soc/tegra/common.h>
#define TEGRA_GMI_CONFIG 0x00
#define TEGRA_GMI_CONFIG_GO BIT(31)
#define TEGRA_GMI_BUS_WIDTH_32BIT BIT(30)
@ -54,9 +57,10 @@ static int tegra_gmi_enable(struct tegra_gmi *gmi)
{
int err;
err = clk_prepare_enable(gmi->clk);
if (err < 0) {
dev_err(gmi->dev, "failed to enable clock: %d\n", err);
pm_runtime_enable(gmi->dev);
err = pm_runtime_resume_and_get(gmi->dev);
if (err) {
pm_runtime_disable(gmi->dev);
return err;
}
@ -83,7 +87,9 @@ static void tegra_gmi_disable(struct tegra_gmi *gmi)
writel(config, gmi->base + TEGRA_GMI_CONFIG);
reset_control_assert(gmi->rst);
clk_disable_unprepare(gmi->clk);
pm_runtime_put_sync_suspend(gmi->dev);
pm_runtime_force_suspend(gmi->dev);
}
static int tegra_gmi_parse_dt(struct tegra_gmi *gmi)
@ -213,6 +219,7 @@ static int tegra_gmi_probe(struct platform_device *pdev)
if (!gmi)
return -ENOMEM;
platform_set_drvdata(pdev, gmi);
gmi->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -232,6 +239,10 @@ static int tegra_gmi_probe(struct platform_device *pdev)
return PTR_ERR(gmi->rst);
}
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (err)
return err;
err = tegra_gmi_parse_dt(gmi);
if (err)
return err;
@ -247,8 +258,6 @@ static int tegra_gmi_probe(struct platform_device *pdev)
return err;
}
platform_set_drvdata(pdev, gmi);
return 0;
}
@ -262,6 +271,34 @@ static int tegra_gmi_remove(struct platform_device *pdev)
return 0;
}
static int __maybe_unused tegra_gmi_runtime_resume(struct device *dev)
{
struct tegra_gmi *gmi = dev_get_drvdata(dev);
int err;
err = clk_prepare_enable(gmi->clk);
if (err < 0) {
dev_err(gmi->dev, "failed to enable clock: %d\n", err);
return err;
}
return 0;
}
static int __maybe_unused tegra_gmi_runtime_suspend(struct device *dev)
{
struct tegra_gmi *gmi = dev_get_drvdata(dev);
clk_disable_unprepare(gmi->clk);
return 0;
}
static const struct dev_pm_ops tegra_gmi_pm = {
SET_RUNTIME_PM_OPS(tegra_gmi_runtime_suspend, tegra_gmi_runtime_resume,
NULL)
};
static const struct of_device_id tegra_gmi_id_table[] = {
{ .compatible = "nvidia,tegra20-gmi", },
{ .compatible = "nvidia,tegra30-gmi", },
@ -275,6 +312,7 @@ static struct platform_driver tegra_gmi_driver = {
.driver = {
.name = "tegra-gmi",
.of_match_table = tegra_gmi_id_table,
.pm = &tegra_gmi_pm,
},
};
module_platform_driver(tegra_gmi_driver);

View File

@ -15,6 +15,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/mmc/card.h>
@ -24,6 +26,8 @@
#include <linux/gpio/consumer.h>
#include <linux/ktime.h>
#include <soc/tegra/common.h>
#include "sdhci-pltfm.h"
#include "cqhci.h"
@ -760,7 +764,9 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
struct device *dev = mmc_dev(host->mmc);
unsigned long host_clk;
int err;
if (!clock)
return sdhci_set_clock(host, clock);
@ -778,7 +784,12 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
* from clk_get_rate() is used.
*/
host_clk = tegra_host->ddr_signaling ? clock * 2 : clock;
clk_set_rate(pltfm_host->clk, host_clk);
err = dev_pm_opp_set_rate(dev, host_clk);
if (err)
dev_err(dev, "failed to set clk rate to %luHz: %d\n",
host_clk, err);
tegra_host->curr_clk_rate = host_clk;
if (tegra_host->ddr_signaling)
host->max_clk = host_clk;
@ -1705,7 +1716,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
"failed to get clock\n");
goto err_clk_get;
}
clk_prepare_enable(clk);
pltfm_host->clk = clk;
tegra_host->rst = devm_reset_control_get_exclusive(&pdev->dev,
@ -1716,15 +1726,24 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
goto err_rst_get;
}
rc = reset_control_assert(tegra_host->rst);
rc = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (rc)
goto err_rst_get;
pm_runtime_enable(&pdev->dev);
rc = pm_runtime_resume_and_get(&pdev->dev);
if (rc)
goto err_pm_get;
rc = reset_control_assert(tegra_host->rst);
if (rc)
goto err_rst_assert;
usleep_range(2000, 4000);
rc = reset_control_deassert(tegra_host->rst);
if (rc)
goto err_rst_get;
goto err_rst_assert;
usleep_range(2000, 4000);
@ -1736,8 +1755,11 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
err_add_host:
reset_control_assert(tegra_host->rst);
err_rst_assert:
pm_runtime_put_sync_suspend(&pdev->dev);
err_pm_get:
pm_runtime_disable(&pdev->dev);
err_rst_get:
clk_disable_unprepare(pltfm_host->clk);
err_clk_get:
clk_disable_unprepare(tegra_host->tmclk);
err_power_req:
@ -1756,19 +1778,38 @@ static int sdhci_tegra_remove(struct platform_device *pdev)
reset_control_assert(tegra_host->rst);
usleep_range(2000, 4000);
clk_disable_unprepare(pltfm_host->clk);
clk_disable_unprepare(tegra_host->tmclk);
pm_runtime_put_sync_suspend(&pdev->dev);
pm_runtime_force_suspend(&pdev->dev);
clk_disable_unprepare(tegra_host->tmclk);
sdhci_pltfm_free(pdev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int __maybe_unused sdhci_tegra_suspend(struct device *dev)
static int __maybe_unused sdhci_tegra_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
clk_disable_unprepare(pltfm_host->clk);
return 0;
}
static int __maybe_unused sdhci_tegra_runtime_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
return clk_prepare_enable(pltfm_host->clk);
}
#ifdef CONFIG_PM_SLEEP
static int sdhci_tegra_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
int ret;
if (host->mmc->caps2 & MMC_CAP2_CQE) {
@ -1783,17 +1824,22 @@ static int __maybe_unused sdhci_tegra_suspend(struct device *dev)
return ret;
}
clk_disable_unprepare(pltfm_host->clk);
ret = pm_runtime_force_suspend(dev);
if (ret) {
sdhci_resume_host(host);
cqhci_resume(host->mmc);
return ret;
}
return 0;
}
static int __maybe_unused sdhci_tegra_resume(struct device *dev)
static int sdhci_tegra_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int ret;
ret = clk_prepare_enable(pltfm_host->clk);
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
@ -1812,13 +1858,16 @@ static int __maybe_unused sdhci_tegra_resume(struct device *dev)
suspend_host:
sdhci_suspend_host(host);
disable_clk:
clk_disable_unprepare(pltfm_host->clk);
pm_runtime_force_suspend(dev);
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(sdhci_tegra_dev_pm_ops, sdhci_tegra_suspend,
sdhci_tegra_resume);
static const struct dev_pm_ops sdhci_tegra_dev_pm_ops = {
SET_RUNTIME_PM_OPS(sdhci_tegra_runtime_suspend, sdhci_tegra_runtime_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(sdhci_tegra_suspend, sdhci_tegra_resume)
};
static struct platform_driver sdhci_tegra_driver = {
.driver = {

View File

@ -17,8 +17,11 @@
#include <linux/mtd/rawnand.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <soc/tegra/common.h>
#define COMMAND 0x00
#define COMMAND_GO BIT(31)
#define COMMAND_CLE BIT(30)
@ -1151,6 +1154,7 @@ static int tegra_nand_probe(struct platform_device *pdev)
return -ENOMEM;
ctrl->dev = &pdev->dev;
platform_set_drvdata(pdev, ctrl);
nand_controller_init(&ctrl->controller);
ctrl->controller.ops = &tegra_nand_controller_ops;
@ -1166,14 +1170,23 @@ static int tegra_nand_probe(struct platform_device *pdev)
if (IS_ERR(ctrl->clk))
return PTR_ERR(ctrl->clk);
err = clk_prepare_enable(ctrl->clk);
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (err)
return err;
/*
* This driver doesn't support active power management yet,
* so we will simply keep device resumed.
*/
pm_runtime_enable(&pdev->dev);
err = pm_runtime_resume_and_get(&pdev->dev);
if (err)
return err;
err = reset_control_reset(rst);
if (err) {
dev_err(ctrl->dev, "Failed to reset HW: %d\n", err);
goto err_disable_clk;
goto err_put_pm;
}
writel_relaxed(HWSTATUS_CMD_DEFAULT, ctrl->regs + HWSTATUS_CMD);
@ -1188,21 +1201,20 @@ static int tegra_nand_probe(struct platform_device *pdev)
dev_name(&pdev->dev), ctrl);
if (err) {
dev_err(ctrl->dev, "Failed to get IRQ: %d\n", err);
goto err_disable_clk;
goto err_put_pm;
}
writel_relaxed(DMA_MST_CTRL_IS_DONE, ctrl->regs + DMA_MST_CTRL);
err = tegra_nand_chips_init(ctrl->dev, ctrl);
if (err)
goto err_disable_clk;
platform_set_drvdata(pdev, ctrl);
goto err_put_pm;
return 0;
err_disable_clk:
clk_disable_unprepare(ctrl->clk);
err_put_pm:
pm_runtime_put_sync_suspend(ctrl->dev);
pm_runtime_force_suspend(ctrl->dev);
return err;
}
@ -1219,11 +1231,40 @@ static int tegra_nand_remove(struct platform_device *pdev)
nand_cleanup(chip);
pm_runtime_put_sync_suspend(ctrl->dev);
pm_runtime_force_suspend(ctrl->dev);
return 0;
}
static int __maybe_unused tegra_nand_runtime_resume(struct device *dev)
{
struct tegra_nand_controller *ctrl = dev_get_drvdata(dev);
int err;
err = clk_prepare_enable(ctrl->clk);
if (err) {
dev_err(dev, "Failed to enable clock: %d\n", err);
return err;
}
return 0;
}
static int __maybe_unused tegra_nand_runtime_suspend(struct device *dev)
{
struct tegra_nand_controller *ctrl = dev_get_drvdata(dev);
clk_disable_unprepare(ctrl->clk);
return 0;
}
static const struct dev_pm_ops tegra_nand_pm = {
SET_RUNTIME_PM_OPS(tegra_nand_runtime_suspend, tegra_nand_runtime_resume,
NULL)
};
static const struct of_device_id tegra_nand_of_match[] = {
{ .compatible = "nvidia,tegra20-nand" },
{ /* sentinel */ }
@ -1234,6 +1275,7 @@ static struct platform_driver tegra_nand_driver = {
.driver = {
.name = "tegra-nand",
.of_match_table = tegra_nand_of_match,
.pm = &tegra_nand_pm,
},
.probe = tegra_nand_probe,
.remove = tegra_nand_remove,

View File

@ -42,12 +42,16 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pm_opp.h>
#include <linux/pwm.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/reset.h>
#include <soc/tegra/common.h>
#define PWM_ENABLE (1 << 31)
#define PWM_DUTY_WIDTH 8
#define PWM_DUTY_SHIFT 16
@ -145,7 +149,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
required_clk_rate =
(NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH;
err = clk_set_rate(pc->clk, required_clk_rate);
err = dev_pm_opp_set_rate(pc->dev, required_clk_rate);
if (err < 0)
return -EINVAL;
@ -181,8 +185,8 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* before writing the register. Otherwise, keep it enabled.
*/
if (!pwm_is_enabled(pwm)) {
err = clk_prepare_enable(pc->clk);
if (err < 0)
err = pm_runtime_resume_and_get(pc->dev);
if (err)
return err;
} else
val |= PWM_ENABLE;
@ -193,7 +197,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* If the PWM is not enabled, turn the clock off again to save power.
*/
if (!pwm_is_enabled(pwm))
clk_disable_unprepare(pc->clk);
pm_runtime_put(pc->dev);
return 0;
}
@ -204,8 +208,8 @@ static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
int rc = 0;
u32 val;
rc = clk_prepare_enable(pc->clk);
if (rc < 0)
rc = pm_runtime_resume_and_get(pc->dev);
if (rc)
return rc;
val = pwm_readl(pc, pwm->hwpwm);
@ -224,7 +228,7 @@ static void tegra_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
val &= ~PWM_ENABLE;
pwm_writel(pc, pwm->hwpwm, val);
clk_disable_unprepare(pc->clk);
pm_runtime_put_sync(pc->dev);
}
static const struct pwm_ops tegra_pwm_ops = {
@ -256,11 +260,20 @@ static int tegra_pwm_probe(struct platform_device *pdev)
if (IS_ERR(pwm->clk))
return PTR_ERR(pwm->clk);
ret = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (ret)
return ret;
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret)
return ret;
/* Set maximum frequency of the IP */
ret = clk_set_rate(pwm->clk, pwm->soc->max_frequency);
ret = dev_pm_opp_set_rate(pwm->dev, pwm->soc->max_frequency);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to set max frequency: %d\n", ret);
return ret;
goto put_pm;
}
/*
@ -278,7 +291,7 @@ static int tegra_pwm_probe(struct platform_device *pdev)
if (IS_ERR(pwm->rst)) {
ret = PTR_ERR(pwm->rst);
dev_err(&pdev->dev, "Reset control is not found: %d\n", ret);
return ret;
goto put_pm;
}
reset_control_deassert(pwm->rst);
@ -291,10 +304,16 @@ static int tegra_pwm_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
reset_control_assert(pwm->rst);
return ret;
goto put_pm;
}
pm_runtime_put(&pdev->dev);
return 0;
put_pm:
pm_runtime_put_sync_suspend(&pdev->dev);
pm_runtime_force_suspend(&pdev->dev);
return ret;
}
static int tegra_pwm_remove(struct platform_device *pdev)
@ -305,20 +324,44 @@ static int tegra_pwm_remove(struct platform_device *pdev)
reset_control_assert(pc->rst);
pm_runtime_force_suspend(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int tegra_pwm_suspend(struct device *dev)
static int __maybe_unused tegra_pwm_runtime_suspend(struct device *dev)
{
return pinctrl_pm_select_sleep_state(dev);
struct tegra_pwm_chip *pc = dev_get_drvdata(dev);
int err;
clk_disable_unprepare(pc->clk);
err = pinctrl_pm_select_sleep_state(dev);
if (err) {
clk_prepare_enable(pc->clk);
return err;
}
return 0;
}
static int tegra_pwm_resume(struct device *dev)
static int __maybe_unused tegra_pwm_runtime_resume(struct device *dev)
{
return pinctrl_pm_select_default_state(dev);
struct tegra_pwm_chip *pc = dev_get_drvdata(dev);
int err;
err = pinctrl_pm_select_default_state(dev);
if (err)
return err;
err = clk_prepare_enable(pc->clk);
if (err) {
pinctrl_pm_select_sleep_state(dev);
return err;
}
return 0;
}
#endif
static const struct tegra_pwm_soc tegra20_pwm_soc = {
.num_channels = 4,
@ -344,7 +387,10 @@ static const struct of_device_id tegra_pwm_of_match[] = {
MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
static const struct dev_pm_ops tegra_pwm_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(tegra_pwm_suspend, tegra_pwm_resume)
SET_RUNTIME_PM_OPS(tegra_pwm_runtime_suspend, tegra_pwm_runtime_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static struct platform_driver tegra_pwm_driver = {

View File

@ -10,6 +10,7 @@
#include <linux/export.h>
#include <linux/of.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <soc/tegra/common.h>
#include <soc/tegra/fuse.h>
@ -43,6 +44,7 @@ static int tegra_core_dev_init_opp_state(struct device *dev)
{
unsigned long rate;
struct clk *clk;
bool rpm_enabled;
int err;
clk = devm_clk_get(dev, NULL);
@ -57,8 +59,31 @@ static int tegra_core_dev_init_opp_state(struct device *dev)
return -EINVAL;
}
/*
* Runtime PM of the device must be enabled in order to set up
* GENPD's performance properly because GENPD core checks whether
* device is suspended and this check doesn't work while RPM is
* disabled. This makes sure the OPP vote below gets cached in
* GENPD for the device. Instead, the vote is done the next time
* the device gets runtime resumed.
*/
rpm_enabled = pm_runtime_enabled(dev);
if (!rpm_enabled)
pm_runtime_enable(dev);
/* should never happen in practice */
if (!pm_runtime_enabled(dev)) {
dev_WARN(dev, "failed to enable runtime PM\n");
pm_runtime_disable(dev);
return -EINVAL;
}
/* first dummy rate-setting initializes voltage vote */
err = dev_pm_opp_set_rate(dev, rate);
if (!rpm_enabled)
pm_runtime_disable(dev);
if (err) {
dev_err(dev, "failed to initialize OPP clock: %d\n", err);
return err;

View File

@ -18,12 +18,15 @@
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
#include <soc/tegra/common.h>
#define SLINK_COMMAND 0x000
#define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0)
#define SLINK_WORD_SIZE(x) (((x) & 0x1f) << 5)
@ -680,7 +683,7 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi,
bits_per_word = t->bits_per_word;
speed = t->speed_hz;
if (speed != tspi->cur_speed) {
clk_set_rate(tspi->clk, speed * 4);
dev_pm_opp_set_rate(tspi->dev, speed * 4);
tspi->cur_speed = speed;
}
@ -1066,6 +1069,10 @@ static int tegra_slink_probe(struct platform_device *pdev)
goto exit_free_master;
}
ret = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (ret)
goto exit_free_master;
tspi->max_buf_size = SLINK_FIFO_DEPTH << 2;
tspi->dma_buf_size = DEFAULT_SPI_DMA_BUF_LEN;

View File

@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <soc/tegra/common.h>
#include <soc/tegra/pmc.h>
#include "uapi.h"
@ -920,13 +921,17 @@ static __maybe_unused int tegra_vde_runtime_suspend(struct device *dev)
struct tegra_vde *vde = dev_get_drvdata(dev);
int err;
err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC);
if (err) {
dev_err(dev, "Failed to power down HW: %d\n", err);
return err;
if (!dev->pm_domain) {
err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC);
if (err) {
dev_err(dev, "Failed to power down HW: %d\n", err);
return err;
}
}
clk_disable_unprepare(vde->clk);
reset_control_release(vde->rst);
reset_control_release(vde->rst_mc);
return 0;
}
@ -936,14 +941,45 @@ static __maybe_unused int tegra_vde_runtime_resume(struct device *dev)
struct tegra_vde *vde = dev_get_drvdata(dev);
int err;
err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC,
vde->clk, vde->rst);
err = reset_control_acquire(vde->rst_mc);
if (err) {
dev_err(dev, "Failed to power up HW : %d\n", err);
dev_err(dev, "Failed to acquire mc reset: %d\n", err);
return err;
}
err = reset_control_acquire(vde->rst);
if (err) {
dev_err(dev, "Failed to acquire reset: %d\n", err);
goto release_mc_reset;
}
if (!dev->pm_domain) {
err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC,
vde->clk, vde->rst);
if (err) {
dev_err(dev, "Failed to power up HW : %d\n", err);
goto release_reset;
}
} else {
/*
* tegra_powergate_sequence_power_up() leaves clocks enabled,
* while GENPD not.
*/
err = clk_prepare_enable(vde->clk);
if (err) {
dev_err(dev, "Failed to enable clock: %d\n", err);
goto release_reset;
}
}
return 0;
release_reset:
reset_control_release(vde->rst);
release_mc_reset:
reset_control_release(vde->rst_mc);
return err;
}
static int tegra_vde_probe(struct platform_device *pdev)
@ -1001,14 +1037,14 @@ static int tegra_vde_probe(struct platform_device *pdev)
return err;
}
vde->rst = devm_reset_control_get(dev, NULL);
vde->rst = devm_reset_control_get_exclusive_released(dev, NULL);
if (IS_ERR(vde->rst)) {
err = PTR_ERR(vde->rst);
dev_err(dev, "Could not get VDE reset %d\n", err);
return err;
}
vde->rst_mc = devm_reset_control_get_optional(dev, "mc");
vde->rst_mc = devm_reset_control_get_optional_exclusive_released(dev, "mc");
if (IS_ERR(vde->rst_mc)) {
err = PTR_ERR(vde->rst_mc);
dev_err(dev, "Could not get MC reset %d\n", err);
@ -1026,6 +1062,12 @@ static int tegra_vde_probe(struct platform_device *pdev)
return err;
}
err = devm_tegra_core_dev_init_opp_table_common(dev);
if (err) {
dev_err(dev, "Could initialize OPP table %d\n", err);
return err;
}
vde->iram_pool = of_gen_pool_get(dev->of_node, "iram", 0);
if (!vde->iram_pool) {
dev_err(dev, "Could not get IRAM pool\n");
@ -1133,8 +1175,7 @@ static void tegra_vde_shutdown(struct platform_device *pdev)
* On some devices bootloader isn't ready to a power-gated VDE on
* a warm-reboot, machine will hang in that case.
*/
if (pm_runtime_status_suspended(&pdev->dev))
tegra_vde_runtime_resume(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
}
static __maybe_unused int tegra_vde_pm_suspend(struct device *dev)

View File

@ -7,6 +7,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/usb.h>
@ -15,6 +16,8 @@
#include <linux/usb/of.h>
#include <linux/usb/phy.h>
#include <soc/tegra/common.h>
#include "../host/ehci.h"
#include "ci.h"
@ -278,6 +281,8 @@ static int tegra_usb_probe(struct platform_device *pdev)
if (!usb)
return -ENOMEM;
platform_set_drvdata(pdev, usb);
soc = of_device_get_match_data(&pdev->dev);
if (!soc) {
dev_err(&pdev->dev, "failed to match OF data\n");
@ -296,11 +301,14 @@ static int tegra_usb_probe(struct platform_device *pdev)
return err;
}
err = clk_prepare_enable(usb->clk);
if (err < 0) {
dev_err(&pdev->dev, "failed to enable clock: %d\n", err);
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (err)
return err;
pm_runtime_enable(&pdev->dev);
err = pm_runtime_resume_and_get(&pdev->dev);
if (err)
return err;
}
if (device_property_present(&pdev->dev, "nvidia,needs-double-reset"))
usb->needs_double_reset = true;
@ -320,8 +328,6 @@ static int tegra_usb_probe(struct platform_device *pdev)
if (err)
goto fail_power_off;
platform_set_drvdata(pdev, usb);
/* setup and register ChipIdea HDRC device */
usb->soc = soc;
usb->data.name = "tegra-usb";
@ -350,7 +356,9 @@ static int tegra_usb_probe(struct platform_device *pdev)
phy_shutdown:
usb_phy_shutdown(usb->phy);
fail_power_off:
clk_disable_unprepare(usb->clk);
pm_runtime_put_sync_suspend(&pdev->dev);
pm_runtime_force_suspend(&pdev->dev);
return err;
}
@ -360,15 +368,46 @@ static int tegra_usb_remove(struct platform_device *pdev)
ci_hdrc_remove_device(usb->dev);
usb_phy_shutdown(usb->phy);
pm_runtime_put_sync_suspend(&pdev->dev);
pm_runtime_force_suspend(&pdev->dev);
return 0;
}
static int __maybe_unused tegra_usb_runtime_resume(struct device *dev)
{
struct tegra_usb *usb = dev_get_drvdata(dev);
int err;
err = clk_prepare_enable(usb->clk);
if (err < 0) {
dev_err(dev, "failed to enable clock: %d\n", err);
return err;
}
return 0;
}
static int __maybe_unused tegra_usb_runtime_suspend(struct device *dev)
{
struct tegra_usb *usb = dev_get_drvdata(dev);
clk_disable_unprepare(usb->clk);
return 0;
}
static const struct dev_pm_ops tegra_usb_pm = {
SET_RUNTIME_PM_OPS(tegra_usb_runtime_suspend, tegra_usb_runtime_resume,
NULL)
};
static struct platform_driver tegra_usb_driver = {
.driver = {
.name = "tegra-usb",
.of_match_table = tegra_usb_of_match,
.pm = &tegra_usb_pm,
},
.probe = tegra_usb_probe,
.remove = tegra_usb_remove,

View File

@ -39,4 +39,19 @@ devm_tegra_core_dev_init_opp_table(struct device *dev,
}
#endif
static inline int
devm_tegra_core_dev_init_opp_table_common(struct device *dev)
{
struct tegra_core_opp_params opp_params = {};
int err;
opp_params.init_state = true;
err = devm_tegra_core_dev_init_opp_table(dev, &opp_params);
if (err != -ENODEV)
return err;
return 0;
}
#endif /* __SOC_TEGRA_COMMON_H__ */