From patchwork Tue Sep 23 12:21:58 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Geert Uytterhoeven X-Patchwork-Id: 4956231 Return-Path: X-Original-To: patchwork-linux-fbdev@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id A3860BEEA5 for ; Tue, 23 Sep 2014 12:22:14 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D6D9B2018E for ; Tue, 23 Sep 2014 12:22:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 43F462011B for ; Tue, 23 Sep 2014 12:22:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753739AbaIWMWG (ORCPT ); Tue, 23 Sep 2014 08:22:06 -0400 Received: from baptiste.telenet-ops.be ([195.130.132.51]:52025 "EHLO baptiste.telenet-ops.be" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753245AbaIWMWF (ORCPT ); Tue, 23 Sep 2014 08:22:05 -0400 Received: from ayla.of.borg ([84.193.84.167]) by baptiste.telenet-ops.be with bizsmtp id ucN21o00r3cczKo01cN2uY; Tue, 23 Sep 2014 14:22:03 +0200 Received: from ramsan.of.borg ([192.168.97.29] helo=ramsan) by ayla.of.borg with esmtp (Exim 4.76) (envelope-from ) id 1XWP6Y-0007R1-Dq; Tue, 23 Sep 2014 14:22:02 +0200 Received: from geert by ramsan with local (Exim 4.82) (envelope-from ) id 1XWP6Y-0000mM-J2; Tue, 23 Sep 2014 14:22:02 +0200 From: Geert Uytterhoeven To: Jean-Christophe Plagniol-Villard , Tomi Valkeinen , "Rafael J. Wysocki" Cc: Ulf Hansson , Guennadi Liakhovetski , linux-fbdev@vger.kernel.org, linux-pm@vger.kernel.org, linux-sh@vger.kernel.org, Geert Uytterhoeven Subject: [PATCH/RFC] fbdev: sh_mobile_hdmi: Re-init regs before irq re-enable on resume Date: Tue, 23 Sep 2014 14:21:58 +0200 Message-Id: <1411474918-2955-1-git-send-email-geert+renesas@glider.be> X-Mailer: git-send-email 1.9.1 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org X-Spam-Status: No, score=-7.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- Is there a specific reason why the .suspend_noirq() and .resume_noirq() callbacks are not called when using genpd, unlike .suspend(), .suspend_late(), .resume_early(), and .resume()? --- drivers/video/fbdev/sh_mobile_hdmi.c | 44 ++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/sh_mobile_hdmi.c b/drivers/video/fbdev/sh_mobile_hdmi.c index 9a33ee0413fb584d..7c72a3f02056445d 100644 --- a/drivers/video/fbdev/sh_mobile_hdmi.c +++ b/drivers/video/fbdev/sh_mobile_hdmi.c @@ -281,6 +281,7 @@ struct sh_hdmi { u8 edid_block_addr; u8 edid_segment_nr; u8 edid_blocks; + int irq; struct clk *hdmi_clk; struct device *dev; struct delayed_work edid_work; @@ -1299,6 +1300,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) hdmi->dev = &pdev->dev; hdmi->entity.owner = THIS_MODULE; hdmi->entity.ops = &sh_hdmi_ops; + hdmi->irq = irq; hdmi->hdmi_clk = clk_get(&pdev->dev, "ick"); if (IS_ERR(hdmi->hdmi_clk)) { @@ -1415,12 +1417,11 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) { struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev)); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - int irq = platform_get_irq(pdev, 0); snd_soc_unregister_codec(&pdev->dev); /* No new work will be scheduled, wait for running ISR */ - free_irq(irq, hdmi); + free_irq(hdmi->irq, hdmi); /* Wait for already scheduled work */ cancel_delayed_work_sync(&hdmi->edid_work); pm_runtime_put(&pdev->dev); @@ -1435,10 +1436,49 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) return 0; } +static int sh_hdmi_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev)); + + disable_irq(hdmi->irq); + /* Wait for already scheduled work */ + cancel_delayed_work_sync(&hdmi->edid_work); + return 0; +} + +static int sh_hdmi_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_mobile_hdmi_info *pdata = dev_get_platdata(dev); + struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev)); + + /* Re-init interrupt polarity */ + if (pdata->flags & HDMI_OUTPUT_PUSH_PULL) + hdmi_bit_set(hdmi, 0x02, 0x02, HDMI_SYSTEM_CTRL); + + if (pdata->flags & HDMI_OUTPUT_POLARITY_HI) + hdmi_bit_set(hdmi, 0x01, 0x01, HDMI_SYSTEM_CTRL); + + /* Re-init htop1 */ + if (hdmi->htop1) + sh_hdmi_htop1_init(hdmi); + + /* Now it's safe to enable interrupts again */ + enable_irq(hdmi->irq); + return 0; +} + +static const struct dev_pm_ops sh_hdmi_pm_ops = { + .suspend = sh_hdmi_suspend, + .resume = sh_hdmi_resume, +}; + static struct platform_driver sh_hdmi_driver = { .remove = __exit_p(sh_hdmi_remove), .driver = { .name = "sh-mobile-hdmi", + .pm = &sh_hdmi_pm_ops, }, };