diff mbox series

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

Message ID 1561345379-2429-3-git-send-email-skomatineni@nvidia.com
State New
Headers show
Series SC7 entry and exit support for Tegra210 | expand

Commit Message

Sowjanya Komatineni June 24, 2019, 3:02 a.m. UTC
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@nvidia.com>
---
 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(+)

Comments

Dmitry Osipenko June 24, 2019, 9:46 a.m. UTC | #1
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@nvidia.com>
> ---
>  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.

> +{
> +	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?
Sowjanya Komatineni June 24, 2019, 5:34 p.m. UTC | #2
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@nvidia.com>
>> ---
>>   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
Thierry Reding June 26, 2019, 10:08 a.m. UTC | #3
On Sun, Jun 23, 2019 at 08:02:43PM -0700, Sowjanya Komatineni wrote:
> 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@nvidia.com>
> ---
>  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(+)

With Dmitry's comments addressed, this is:

Acked-by: Thierry Reding <treding@nvidia.com>
diff mbox series

Patch

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)
+{
+	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
+};
+
 static const struct of_device_id tegra210_pinctrl_of_match[] = {
 	{ .compatible = "nvidia,tegra210-pinmux", },
 	{ },
@@ -1571,6 +1576,7 @@  static struct platform_driver tegra210_pinctrl_driver = {
 	.driver = {
 		.name = "tegra210-pinctrl",
 		.of_match_table = tegra210_pinctrl_of_match,
+		.pm = &tegra_pinctrl_pm,
 	},
 	.probe = tegra210_pinctrl_probe,
 };