Re: [PATCH V4 02/18] pinctrl: tegra: add suspend and resume support

From: Sowjanya Komatineni
Date: Mon Jun 24 2019 - 13:34:18 EST



On 6/24/19 2:46 AM, Dmitry Osipenko wrote:
24.06.2019 6:02, Sowjanya Komatineni ÐÐÑÐÑ:
This patch adds support for Tegra pinctrl driver suspend and resume.

During suspend, context of all pinctrl registers are stored and
on resume they are all restored to have all the pinmux and pad
configuration for normal operation.

Signed-off-by: Sowjanya Komatineni <skomatineni@xxxxxxxxxx>
---
drivers/pinctrl/tegra/pinctrl-tegra.c | 47 ++++++++++++++++++++++++++++++++
drivers/pinctrl/tegra/pinctrl-tegra.h | 4 +++
drivers/pinctrl/tegra/pinctrl-tegra210.c | 6 ++++
3 files changed, 57 insertions(+)

diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index b03c465917b8..c0ba6fa63ad1 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -631,6 +631,38 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
}
}
+int __maybe_unused tegra_pinctrl_suspend(struct device *dev)
The "maybe_unused" attribute isn't needed for global functions because
compiler always assumes that such functions are used somewhere outside.
Will fix this in V5
+{
+ struct tegra_pmx *pmx = dev_get_drvdata(dev);
+ u32 *backup_regs = pmx->backup_regs;
+ u32 *regs;
+ unsigned int i, j;
+
+ for (i = 0; i < pmx->nbanks; i++) {
+ regs = pmx->regs[i];
+ for (j = 0; j < pmx->reg_bank_size[i] / 4; j++)
+ *backup_regs++ = readl(regs++);
+ }
+
+ return pinctrl_force_sleep(pmx->pctl);
+}
+
+int __maybe_unused tegra_pinctrl_resume(struct device *dev)
+{
+ struct tegra_pmx *pmx = dev_get_drvdata(dev);
+ u32 *backup_regs = pmx->backup_regs;
+ u32 *regs;
+ unsigned int i, j;
+
+ for (i = 0; i < pmx->nbanks; i++) {
+ regs = pmx->regs[i];
+ for (j = 0; j < pmx->reg_bank_size[i] / 4; j++)
+ writel(*backup_regs++, regs++);
+ }
+
+ return 0;
+}
+
static bool gpio_node_has_range(const char *compatible)
{
struct device_node *np;
@@ -655,6 +687,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
int i;
const char **group_pins;
int fn, gn, gfn;
+ unsigned long backup_regs_size = 0;
pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
if (!pmx)
@@ -707,6 +740,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res)
break;
+ backup_regs_size += resource_size(res);
}
pmx->nbanks = i;
@@ -715,11 +749,24 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
if (!pmx->regs)
return -ENOMEM;
+ pmx->reg_bank_size = devm_kcalloc(&pdev->dev, pmx->nbanks,
+ sizeof(*pmx->reg_bank_size),
+ GFP_KERNEL);
+ if (!pmx->reg_bank_size)
+ return -ENOMEM;
+
+ pmx->backup_regs = devm_kzalloc(&pdev->dev, backup_regs_size,
+ GFP_KERNEL);
+ if (!pmx->backup_regs)
+ return -ENOMEM;
+
for (i = 0; i < pmx->nbanks; i++) {
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pmx->regs[i]))
return PTR_ERR(pmx->regs[i]);
+
+ pmx->reg_bank_size[i] = resource_size(res);
}
pmx->pctl = devm_pinctrl_register(&pdev->dev, &tegra_pinctrl_desc, pmx);
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
index 32642af3f871..65fcbf8c7579 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.h
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
@@ -17,6 +17,8 @@ struct tegra_pmx {
int nbanks;
void __iomem **regs;
+ size_t *reg_bank_size;
+ u32 *backup_regs;
};
enum tegra_pinconf_param {
@@ -195,4 +197,6 @@ struct tegra_pinctrl_soc_data {
int tegra_pinctrl_probe(struct platform_device *pdev,
const struct tegra_pinctrl_soc_data *soc_data);
+int __maybe_unused tegra_pinctrl_suspend(struct device *dev);
+int __maybe_unused tegra_pinctrl_resume(struct device *dev);
#endif
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
index 617ad963f5ad..4616bbc2efba 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra210.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
@@ -1562,6 +1562,11 @@ static int tegra210_pinctrl_probe(struct platform_device *pdev)
return tegra_pinctrl_probe(pdev, &tegra210_pinctrl);
}
+static const struct dev_pm_ops tegra_pinctrl_pm = {
+ .suspend = &tegra_pinctrl_suspend,
+ .resume = &tegra_pinctrl_resume
+};
What about to move tegra_pinctrl_pm out into pinctrl-tegra.c to make it
common for all of the drivers?
OK, Will do that in V5