Unverified Commit a1539b2e authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'tegra-for-5.17-drivers' of...

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: default avatarArnd Bergmann <arnd@arndb.de>
parents 4f34ebad e0abae19
Loading
Loading
Loading
Loading
+44 −6
Original line number Diff line number Diff line
@@ -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);
+65 −16
Original line number Diff line number Diff line
@@ -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		= {
+50 −8
Original line number Diff line number Diff line
@@ -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,
+64 −18
Original line number Diff line number Diff line
@@ -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;
	}

static int tegra_pwm_resume(struct device *dev)
	return 0;
}

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 = {
+25 −0
Original line number Diff line number Diff line
@@ -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;
Loading