diff mbox series

[V2] clk: vc5: Add suspend/resume support

Message ID 20181212014130.18634-1-marek.vasut+renesas@gmail.com (mailing list archive)
State Superseded
Delegated to: Geert Uytterhoeven
Headers show
Series [V2] clk: vc5: Add suspend/resume support | expand

Commit Message

Marek Vasut Dec. 12, 2018, 1:41 a.m. UTC
Add simple suspend/resume handlers to the driver to restore the chip
configuration after resume. It is possible that the chip was configured
with non-default values before suspend-resume cycle and that the chip
is powered down during this cycle, so the configuration could get lost.

Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Alexey Firago <alexey_firago@mentor.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: linux-renesas-soc@vger.kernel.org
---
V2: Replace ifdef with __maybe_unused
    Simplify return value handling in resume
---
 drivers/clk/clk-versaclock5.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

Comments

Laurent Pinchart Dec. 12, 2018, 8:43 a.m. UTC | #1
Hi Marex,

Thank you for the patch.

On Wednesday, 12 December 2018 03:41:30 EET Marek Vasut wrote:
> Add simple suspend/resume handlers to the driver to restore the chip
> configuration after resume. It is possible that the chip was configured
> with non-default values before suspend-resume cycle and that the chip
> is powered down during this cycle, so the configuration could get lost.
> 
> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
> Cc: Alexey Firago <alexey_firago@mentor.com>
> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Cc: linux-renesas-soc@vger.kernel.org
> ---
> V2: Replace ifdef with __maybe_unused
>     Simplify return value handling in resume
> ---
>  drivers/clk/clk-versaclock5.c | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c
> index decffb3826ec..b66586a3abb7 100644
> --- a/drivers/clk/clk-versaclock5.c
> +++ b/drivers/clk/clk-versaclock5.c
> @@ -906,6 +906,34 @@ static int vc5_remove(struct i2c_client *client)
>  	return 0;
>  }
> 
> +static int __maybe_unused vc5_suspend(struct device *dev)
> +{
> +	struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = regcache_sync(vc5->regmap);

Didn't you say the sync here was unneeded and would be dropped ?

> +	if (ret != 0) {
> +		dev_err(dev, "Failed to save register map: %d\n", ret);
> +		return ret;
> +	}
> +	regcache_cache_only(vc5->regmap, true);
> +	regcache_mark_dirty(vc5->regmap);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused vc5_resume(struct device *dev)
> +{
> +	struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
> +	int ret;
> +
> +	regcache_cache_only(vc5->regmap, false);
> +	ret = regcache_sync(vc5->regmap);
> +	if (ret)
> +		dev_err(dev, "Failed to restore register map: %d\n", ret);
> +	return ret;
> +}
> +
>  static const struct vc5_chip_info idt_5p49v5923_info = {
>  	.model = IDT_VC5_5P49V5923,
>  	.clk_fod_cnt = 2,
> @@ -961,9 +989,12 @@ static const struct of_device_id clk_vc5_of_match[] = {
> };
>  MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
> 
> +static SIMPLE_DEV_PM_OPS(vc5_pm_ops, vc5_suspend, vc5_resume);
> +
>  static struct i2c_driver vc5_driver = {
>  	.driver = {
>  		.name = "vc5",
> +		.pm	= &vc5_pm_ops,
>  		.of_match_table = clk_vc5_of_match,
>  	},
>  	.probe		= vc5_probe,
Marek Vasut Dec. 13, 2018, 2:09 a.m. UTC | #2
On 12/12/2018 09:43 AM, Laurent Pinchart wrote:
> Hi Marex,

Hi,

> Thank you for the patch.
> 
> On Wednesday, 12 December 2018 03:41:30 EET Marek Vasut wrote:
>> Add simple suspend/resume handlers to the driver to restore the chip
>> configuration after resume. It is possible that the chip was configured
>> with non-default values before suspend-resume cycle and that the chip
>> is powered down during this cycle, so the configuration could get lost.
>>
>> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
>> Cc: Alexey Firago <alexey_firago@mentor.com>
>> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> Cc: Michael Turquette <mturquette@baylibre.com>
>> Cc: Stephen Boyd <sboyd@codeaurora.org>
>> Cc: linux-renesas-soc@vger.kernel.org
>> ---
>> V2: Replace ifdef with __maybe_unused
>>     Simplify return value handling in resume
>> ---
>>  drivers/clk/clk-versaclock5.c | 31 +++++++++++++++++++++++++++++++
>>  1 file changed, 31 insertions(+)
>>
>> diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c
>> index decffb3826ec..b66586a3abb7 100644
>> --- a/drivers/clk/clk-versaclock5.c
>> +++ b/drivers/clk/clk-versaclock5.c
>> @@ -906,6 +906,34 @@ static int vc5_remove(struct i2c_client *client)
>>  	return 0;
>>  }
>>
>> +static int __maybe_unused vc5_suspend(struct device *dev)
>> +{
>> +	struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
>> +	int ret;
>> +
>> +	ret = regcache_sync(vc5->regmap);
> 
> Didn't you say the sync here was unneeded and would be dropped ?
> 
>> +	if (ret != 0) {
>> +		dev_err(dev, "Failed to save register map: %d\n", ret);
>> +		return ret;
>> +	}

If you have a setup with working DU and VGA on something close to next
(it's broken in next), can you try dropping this hunk (basically do
ret = 0;//regcache_sync(vc5->regmap); ) and see if the regcache stays
consistent ? It should. If so, I'll drop this in V3.

>> +	regcache_cache_only(vc5->regmap, true);
>> +	regcache_mark_dirty(vc5->regmap);
[...]
Laurent Pinchart Dec. 13, 2018, 4:52 a.m. UTC | #3
Hi Marek,

On Thursday, 13 December 2018 04:09:19 EET Marek Vasut wrote:
> On 12/12/2018 09:43 AM, Laurent Pinchart wrote:
> > On Wednesday, 12 December 2018 03:41:30 EET Marek Vasut wrote:
> >> Add simple suspend/resume handlers to the driver to restore the chip
> >> configuration after resume. It is possible that the chip was configured
> >> with non-default values before suspend-resume cycle and that the chip
> >> is powered down during this cycle, so the configuration could get lost.
> >> 
> >> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
> >> Cc: Alexey Firago <alexey_firago@mentor.com>
> >> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> Cc: Michael Turquette <mturquette@baylibre.com>
> >> Cc: Stephen Boyd <sboyd@codeaurora.org>
> >> Cc: linux-renesas-soc@vger.kernel.org
> >> ---
> >> V2: Replace ifdef with __maybe_unused
> >> 
> >>     Simplify return value handling in resume
> >> 
> >> ---
> >> 
> >>  drivers/clk/clk-versaclock5.c | 31 +++++++++++++++++++++++++++++++
> >>  1 file changed, 31 insertions(+)
> >> 
> >> diff --git a/drivers/clk/clk-versaclock5.c
> >> b/drivers/clk/clk-versaclock5.c
> >> index decffb3826ec..b66586a3abb7 100644
> >> --- a/drivers/clk/clk-versaclock5.c
> >> +++ b/drivers/clk/clk-versaclock5.c
> >> @@ -906,6 +906,34 @@ static int vc5_remove(struct i2c_client *client)
> >>  	return 0;
> >>  }
> >> 
> >> +static int __maybe_unused vc5_suspend(struct device *dev)
> >> +{
> >> +	struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
> >> +	int ret;
> >> +
> >> +	ret = regcache_sync(vc5->regmap);
> > 
> > Didn't you say the sync here was unneeded and would be dropped ?
> > 
> >> +	if (ret != 0) {
> >> +		dev_err(dev, "Failed to save register map: %d\n", ret);
> >> +		return ret;
> >> +	}
> 
> If you have a setup with working DU and VGA on something close to next
> (it's broken in next), can you try dropping this hunk (basically do
> ret = 0;//regcache_sync(vc5->regmap); ) and see if the regcache stays
> consistent ? It should. If so, I'll drop this in V3.
> 
> >> +	regcache_cache_only(vc5->regmap, true);
> >> +	regcache_mark_dirty(vc5->regmap);
> 
> [...]

Here's my test procedure:

- Boot the board
- Dump the VC5 state (into vc5-next+*-1-boot.log)
- Enable the VGA output with kmstest -c VGA-1
- Dump the VC5 state (into vc5-next+*-2-display-on.log)
- Suspend and resume
- Dump the VC5 state (into vc5-next+*-3-post-suspend.log)
- Stop kmstest
- Dump the VC5 state (into vc5-next+*-4-display-off.log)

To dump the VC5 state, I use

-----------------------------------------------------------------------------
#!/bin/sh

echo "-------- i2cdump --------"
i2cdump -f -y 4 0x6a

for f in /sys/kernel/debug/regmap/4-006a/* ; do
        echo "-------- $f --------"
        cat $f
done
-----------------------------------------------------------------------------

The base kernel version is v4.20-rc6 + the fixes branch from linux media. I've 
tested the following three configurations, in order:

next+0 - Base
next+1 - Base + this patch
next+2 - Base + this patch + removal of regcache_sync() from vc5_suspend()

With base, the VGA output would remain off after resume, and running kmstest 
again wouldn't help. With the other two configurations the problem is fixed 
and the VGA output is functional.

Furthermore, there are no differences in the VC5 dumps between next+1 and 
next+2, neither are there between the boot and display-on dumps between any of 
the three configurations.

I've attached the logs to this e-mail.
Marek Vasut Dec. 13, 2018, 4:17 p.m. UTC | #4
On 12/13/2018 05:52 AM, Laurent Pinchart wrote:
> Hi Marek,

Hi,

> On Thursday, 13 December 2018 04:09:19 EET Marek Vasut wrote:
>> On 12/12/2018 09:43 AM, Laurent Pinchart wrote:
>>> On Wednesday, 12 December 2018 03:41:30 EET Marek Vasut wrote:
>>>> Add simple suspend/resume handlers to the driver to restore the chip
>>>> configuration after resume. It is possible that the chip was configured
>>>> with non-default values before suspend-resume cycle and that the chip
>>>> is powered down during this cycle, so the configuration could get lost.
>>>>
>>>> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
>>>> Cc: Alexey Firago <alexey_firago@mentor.com>
>>>> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>>> Cc: Michael Turquette <mturquette@baylibre.com>
>>>> Cc: Stephen Boyd <sboyd@codeaurora.org>
>>>> Cc: linux-renesas-soc@vger.kernel.org
>>>> ---
>>>> V2: Replace ifdef with __maybe_unused
>>>>
>>>>     Simplify return value handling in resume
>>>>
>>>> ---
>>>>
>>>>  drivers/clk/clk-versaclock5.c | 31 +++++++++++++++++++++++++++++++
>>>>  1 file changed, 31 insertions(+)
>>>>
>>>> diff --git a/drivers/clk/clk-versaclock5.c
>>>> b/drivers/clk/clk-versaclock5.c
>>>> index decffb3826ec..b66586a3abb7 100644
>>>> --- a/drivers/clk/clk-versaclock5.c
>>>> +++ b/drivers/clk/clk-versaclock5.c
>>>> @@ -906,6 +906,34 @@ static int vc5_remove(struct i2c_client *client)
>>>>  	return 0;
>>>>  }
>>>>
>>>> +static int __maybe_unused vc5_suspend(struct device *dev)
>>>> +{
>>>> +	struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
>>>> +	int ret;
>>>> +
>>>> +	ret = regcache_sync(vc5->regmap);
>>>
>>> Didn't you say the sync here was unneeded and would be dropped ?
>>>
>>>> +	if (ret != 0) {
>>>> +		dev_err(dev, "Failed to save register map: %d\n", ret);
>>>> +		return ret;
>>>> +	}
>>
>> If you have a setup with working DU and VGA on something close to next
>> (it's broken in next), can you try dropping this hunk (basically do
>> ret = 0;//regcache_sync(vc5->regmap); ) and see if the regcache stays
>> consistent ? It should. If so, I'll drop this in V3.
>>
>>>> +	regcache_cache_only(vc5->regmap, true);
>>>> +	regcache_mark_dirty(vc5->regmap);
>>
>> [...]
> 
> Here's my test procedure:
> 
> - Boot the board
> - Dump the VC5 state (into vc5-next+*-1-boot.log)
> - Enable the VGA output with kmstest -c VGA-1

I didn't know this was needed, all right.

> - Dump the VC5 state (into vc5-next+*-2-display-on.log)
> - Suspend and resume
> - Dump the VC5 state (into vc5-next+*-3-post-suspend.log)
> - Stop kmstest
> - Dump the VC5 state (into vc5-next+*-4-display-off.log)
> 
> To dump the VC5 state, I use
> 
> -----------------------------------------------------------------------------
> #!/bin/sh
> 
> echo "-------- i2cdump --------"
> i2cdump -f -y 4 0x6a
> 
> for f in /sys/kernel/debug/regmap/4-006a/* ; do
>         echo "-------- $f --------"
>         cat $f
> done
> -----------------------------------------------------------------------------
> 
> The base kernel version is v4.20-rc6 + the fixes branch from linux media. I've 
> tested the following three configurations, in order:
> 
> next+0 - Base
> next+1 - Base + this patch
> next+2 - Base + this patch + removal of regcache_sync() from vc5_suspend()
> 
> With base, the VGA output would remain off after resume, and running kmstest 
> again wouldn't help. With the other two configurations the problem is fixed 
> and the VGA output is functional.
> 
> Furthermore, there are no differences in the VC5 dumps between next+1 and 
> next+2, neither are there between the boot and display-on dumps between any of 
> the three configurations.
> 
> I've attached the logs to this e-mail.

Thanks for the test, I sent out a V3 without the regcache_sync() .
diff mbox series

Patch

diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c
index decffb3826ec..b66586a3abb7 100644
--- a/drivers/clk/clk-versaclock5.c
+++ b/drivers/clk/clk-versaclock5.c
@@ -906,6 +906,34 @@  static int vc5_remove(struct i2c_client *client)
 	return 0;
 }
 
+static int __maybe_unused vc5_suspend(struct device *dev)
+{
+	struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regcache_sync(vc5->regmap);
+	if (ret != 0) {
+		dev_err(dev, "Failed to save register map: %d\n", ret);
+		return ret;
+	}
+	regcache_cache_only(vc5->regmap, true);
+	regcache_mark_dirty(vc5->regmap);
+
+	return 0;
+}
+
+static int __maybe_unused vc5_resume(struct device *dev)
+{
+	struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
+	int ret;
+
+	regcache_cache_only(vc5->regmap, false);
+	ret = regcache_sync(vc5->regmap);
+	if (ret)
+		dev_err(dev, "Failed to restore register map: %d\n", ret);
+	return ret;
+}
+
 static const struct vc5_chip_info idt_5p49v5923_info = {
 	.model = IDT_VC5_5P49V5923,
 	.clk_fod_cnt = 2,
@@ -961,9 +989,12 @@  static const struct of_device_id clk_vc5_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
 
+static SIMPLE_DEV_PM_OPS(vc5_pm_ops, vc5_suspend, vc5_resume);
+
 static struct i2c_driver vc5_driver = {
 	.driver = {
 		.name = "vc5",
+		.pm	= &vc5_pm_ops,
 		.of_match_table = clk_vc5_of_match,
 	},
 	.probe		= vc5_probe,