Commit 9870acd3 authored by Sowjanya Komatineni's avatar Sowjanya Komatineni Committed by Linus Walleij

pinctrl: tegra: Add suspend and resume support

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.
Acked-by: default avatarThierry Reding <treding@nvidia.com>
Reviewed-by: default avatarDmitry Osipenko <digetx@gmail.com>
Signed-off-by: default avatarSowjanya Komatineni <skomatineni@nvidia.com>
Link: https://lore.kernel.org/r/1564607463-28802-2-git-send-email-skomatineni@nvidia.comSigned-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 3d6ade0a
...@@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx) ...@@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
} }
} }
static size_t tegra_pinctrl_get_bank_size(struct device *dev,
unsigned int bank_id)
{
struct platform_device *pdev = to_platform_device(dev);
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id);
return resource_size(res) / 4;
}
static int tegra_pinctrl_suspend(struct device *dev)
{
struct tegra_pmx *pmx = dev_get_drvdata(dev);
u32 *backup_regs = pmx->backup_regs;
u32 *regs;
size_t bank_size;
unsigned int i, k;
for (i = 0; i < pmx->nbanks; i++) {
bank_size = tegra_pinctrl_get_bank_size(dev, i);
regs = pmx->regs[i];
for (k = 0; k < bank_size; k++)
*backup_regs++ = readl_relaxed(regs++);
}
return pinctrl_force_sleep(pmx->pctl);
}
static int tegra_pinctrl_resume(struct device *dev)
{
struct tegra_pmx *pmx = dev_get_drvdata(dev);
u32 *backup_regs = pmx->backup_regs;
u32 *regs;
size_t bank_size;
unsigned int i, k;
for (i = 0; i < pmx->nbanks; i++) {
bank_size = tegra_pinctrl_get_bank_size(dev, i);
regs = pmx->regs[i];
for (k = 0; k < bank_size; k++)
writel_relaxed(*backup_regs++, regs++);
}
return 0;
}
const struct dev_pm_ops tegra_pinctrl_pm = {
.suspend = &tegra_pinctrl_suspend,
.resume = &tegra_pinctrl_resume
};
static bool gpio_node_has_range(const char *compatible) static bool gpio_node_has_range(const char *compatible)
{ {
struct device_node *np; struct device_node *np;
...@@ -655,6 +707,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev, ...@@ -655,6 +707,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
int i; int i;
const char **group_pins; const char **group_pins;
int fn, gn, gfn; int fn, gn, gfn;
unsigned long backup_regs_size = 0;
pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
if (!pmx) if (!pmx)
...@@ -707,6 +760,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev, ...@@ -707,6 +760,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
res = platform_get_resource(pdev, IORESOURCE_MEM, i); res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res) if (!res)
break; break;
backup_regs_size += resource_size(res);
} }
pmx->nbanks = i; pmx->nbanks = i;
...@@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev, ...@@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
if (!pmx->regs) if (!pmx->regs)
return -ENOMEM; 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++) { for (i = 0; i < pmx->nbanks; i++) {
res = platform_get_resource(pdev, IORESOURCE_MEM, i); res = platform_get_resource(pdev, IORESOURCE_MEM, i);
pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res); pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
......
...@@ -17,6 +17,7 @@ struct tegra_pmx { ...@@ -17,6 +17,7 @@ struct tegra_pmx {
int nbanks; int nbanks;
void __iomem **regs; void __iomem **regs;
u32 *backup_regs;
}; };
enum tegra_pinconf_param { enum tegra_pinconf_param {
...@@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data { ...@@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data {
bool drvtype_in_mux; bool drvtype_in_mux;
}; };
extern const struct dev_pm_ops tegra_pinctrl_pm;
int tegra_pinctrl_probe(struct platform_device *pdev, int tegra_pinctrl_probe(struct platform_device *pdev,
const struct tegra_pinctrl_soc_data *soc_data); const struct tegra_pinctrl_soc_data *soc_data);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment