aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert+renesas@glider.be>2014-09-23 08:21:58 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2014-09-30 06:42:13 -0400
commita00d91ea264f974b3d57babce143ba157921629a (patch)
tree6a379687526afecf02b932d0064896f34ca6e453 /drivers/video
parent5b789da8a7fc357661fc61faaf853e9161cc9700 (diff)
fbdev: sh_mobile_hdmi: Re-init regs before irq re-enable on resume
When the PM domain containing the HDMI hardware block is powered down, the HDMI register values (incl. interrupt polarity settings) are lost. During resume, after powering up the PM domain, interrupts are re-enabled, and an interrupt storm happens due to incorrect interrupt polarity settings: irq 163: nobody cared (try booting with the "irqpoll" option) ... Disabling IRQ #163 To fix this, re-initialize the interrupt polarity settings, and the htop1 register block (if present), during resume. As the .suspend_noirq() and .resume_noirq() callbacks are not called when using the generic PM domain, the normal .resume() callback is used, and the device interrupt needs to be disabled/enabled manually. This fixes resume from s2ram with power down of the A4MP PM domain on r8a7740/Armadillo. Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/sh_mobile_hdmi.c44
1 files changed, 42 insertions, 2 deletions
diff --git a/drivers/video/fbdev/sh_mobile_hdmi.c b/drivers/video/fbdev/sh_mobile_hdmi.c
index 9a33ee0413fb..7c72a3f02056 100644
--- a/drivers/video/fbdev/sh_mobile_hdmi.c
+++ b/drivers/video/fbdev/sh_mobile_hdmi.c
@@ -281,6 +281,7 @@ struct sh_hdmi {
281 u8 edid_block_addr; 281 u8 edid_block_addr;
282 u8 edid_segment_nr; 282 u8 edid_segment_nr;
283 u8 edid_blocks; 283 u8 edid_blocks;
284 int irq;
284 struct clk *hdmi_clk; 285 struct clk *hdmi_clk;
285 struct device *dev; 286 struct device *dev;
286 struct delayed_work edid_work; 287 struct delayed_work edid_work;
@@ -1299,6 +1300,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
1299 hdmi->dev = &pdev->dev; 1300 hdmi->dev = &pdev->dev;
1300 hdmi->entity.owner = THIS_MODULE; 1301 hdmi->entity.owner = THIS_MODULE;
1301 hdmi->entity.ops = &sh_hdmi_ops; 1302 hdmi->entity.ops = &sh_hdmi_ops;
1303 hdmi->irq = irq;
1302 1304
1303 hdmi->hdmi_clk = clk_get(&pdev->dev, "ick"); 1305 hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
1304 if (IS_ERR(hdmi->hdmi_clk)) { 1306 if (IS_ERR(hdmi->hdmi_clk)) {
@@ -1415,12 +1417,11 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
1415{ 1417{
1416 struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev)); 1418 struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev));
1417 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1419 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1418 int irq = platform_get_irq(pdev, 0);
1419 1420
1420 snd_soc_unregister_codec(&pdev->dev); 1421 snd_soc_unregister_codec(&pdev->dev);
1421 1422
1422 /* No new work will be scheduled, wait for running ISR */ 1423 /* No new work will be scheduled, wait for running ISR */
1423 free_irq(irq, hdmi); 1424 free_irq(hdmi->irq, hdmi);
1424 /* Wait for already scheduled work */ 1425 /* Wait for already scheduled work */
1425 cancel_delayed_work_sync(&hdmi->edid_work); 1426 cancel_delayed_work_sync(&hdmi->edid_work);
1426 pm_runtime_put(&pdev->dev); 1427 pm_runtime_put(&pdev->dev);
@@ -1435,10 +1436,49 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
1435 return 0; 1436 return 0;
1436} 1437}
1437 1438
1439static int sh_hdmi_suspend(struct device *dev)
1440{
1441 struct platform_device *pdev = to_platform_device(dev);
1442 struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev));
1443
1444 disable_irq(hdmi->irq);
1445 /* Wait for already scheduled work */
1446 cancel_delayed_work_sync(&hdmi->edid_work);
1447 return 0;
1448}
1449
1450static int sh_hdmi_resume(struct device *dev)
1451{
1452 struct platform_device *pdev = to_platform_device(dev);
1453 struct sh_mobile_hdmi_info *pdata = dev_get_platdata(dev);
1454 struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev));
1455
1456 /* Re-init interrupt polarity */
1457 if (pdata->flags & HDMI_OUTPUT_PUSH_PULL)
1458 hdmi_bit_set(hdmi, 0x02, 0x02, HDMI_SYSTEM_CTRL);
1459
1460 if (pdata->flags & HDMI_OUTPUT_POLARITY_HI)
1461 hdmi_bit_set(hdmi, 0x01, 0x01, HDMI_SYSTEM_CTRL);
1462
1463 /* Re-init htop1 */
1464 if (hdmi->htop1)
1465 sh_hdmi_htop1_init(hdmi);
1466
1467 /* Now it's safe to enable interrupts again */
1468 enable_irq(hdmi->irq);
1469 return 0;
1470}
1471
1472static const struct dev_pm_ops sh_hdmi_pm_ops = {
1473 .suspend = sh_hdmi_suspend,
1474 .resume = sh_hdmi_resume,
1475};
1476
1438static struct platform_driver sh_hdmi_driver = { 1477static struct platform_driver sh_hdmi_driver = {
1439 .remove = __exit_p(sh_hdmi_remove), 1478 .remove = __exit_p(sh_hdmi_remove),
1440 .driver = { 1479 .driver = {
1441 .name = "sh-mobile-hdmi", 1480 .name = "sh-mobile-hdmi",
1481 .pm = &sh_hdmi_pm_ops,
1442 }, 1482 },
1443}; 1483};
1444 1484