From patchwork Sun Sep 28 12:43:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 4991721 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 95858BEEA6 for ; Sun, 28 Sep 2014 12:44:27 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A555220251 for ; Sun, 28 Sep 2014 12:44:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B4D4320219 for ; Sun, 28 Sep 2014 12:44:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753956AbaI1MoZ (ORCPT ); Sun, 28 Sep 2014 08:44:25 -0400 Received: from mx1.redhat.com ([209.132.183.28]:27270 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753934AbaI1MoY (ORCPT ); Sun, 28 Sep 2014 08:44:24 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s8SChp7s008055 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Sun, 28 Sep 2014 08:43:51 -0400 Received: from shalem.localdomain.com (vpn1-4-237.ams2.redhat.com [10.36.4.237]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s8SChdan014107; Sun, 28 Sep 2014 08:43:48 -0400 From: Hans de Goede To: Jean-Christophe Plagniol-Villard , Tomi Valkeinen , Grant Likely , Rob Herring Cc: Luc Verhaegen , Maxime Ripard , Mike Turquette , linux-fbdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, devicetree , linux-sunxi@googlegroups.com, Hans de Goede Subject: [PATCH 4/4] simplefb: add clock handling code Date: Sun, 28 Sep 2014 14:43:38 +0200 Message-Id: <1411908218-20947-4-git-send-email-hdegoede@redhat.com> In-Reply-To: <1411908218-20947-1-git-send-email-hdegoede@redhat.com> References: <1411908218-20947-1-git-send-email-hdegoede@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 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.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable 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 From: Luc Verhaegen This claims and enables clocks listed in the simple framebuffer dt node. This is needed so that the display engine, in case the required clocks are known by the kernel code and are described in the dt, will remain properly enabled. Signed-off-by: Luc Verhaegen [hdegoede@redhat.com: drop dev_err on kzalloc failure] Signed-off-by: Hans de Goede --- drivers/video/fbdev/simplefb.c | 100 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index b7d5c08..f329cc1 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -26,6 +26,7 @@ #include #include #include +#include static struct fb_fix_screeninfo simplefb_fix = { .id = "simple", @@ -165,8 +166,98 @@ static int simplefb_parse_pd(struct platform_device *pdev, return 0; } +/* + * Clock handling code. + * + * Here we handle the clocks property of our "simple-framebuffer" dt node. + * This is necessary so that we can make sure that any clocks needed by + * the display engine that the bootloader set up for us (and for which it + * provided a simplefb dt node), stay up, for the life of the simplefb + * driver. + * + * When the driver unloads, we cleanly disable, and then release the clocks. + */ +struct simplefb_clock { + struct list_head list; + struct clk *clock; +}; + +/* + * We only complain about errors here, no action is taken as the most likely + * error can only happen due to a mismatch between the bootloader which set + * up simplefb, and the clock definitions in the device tree. Chances are + * that there are no adverse effects, and if there are, a clean teardown of + * the fb probe will not help us much either. So just complain and carry on, + * and hope that the user actually gets a working fb at the end of things. + */ +static void +simplefb_clocks_init(struct platform_device *pdev, struct list_head *list) +{ + struct device_node *np = pdev->dev.of_node; + int clock_count, i; + + INIT_LIST_HEAD(list); + + if (dev_get_platdata(&pdev->dev) || !np) + return; + + clock_count = of_clk_get_parent_count(np); + for (i = 0; i < clock_count; i++) { + struct simplefb_clock *entry; + struct clk *clock = of_clk_get(np, i); + int ret; + + if (IS_ERR(clock)) { + dev_err(&pdev->dev, "%s: clock %d not found: %ld\n", + __func__, i, PTR_ERR(clock)); + continue; + } + + ret = clk_prepare_enable(clock); + if (ret) { + dev_err(&pdev->dev, + "%s: failed to enable clock %d: %d\n", + __func__, i, ret); + clk_put(clock); + continue; + } + + entry = kzalloc(sizeof(struct simplefb_clock), GFP_KERNEL); + if (!entry) { + clk_disable_unprepare(clock); + clk_put(clock); + continue; + } + + entry->clock = clock; + /* + * add to the front of the list, so we disable clocks in the + * correct order. + */ + list_add(&entry->list, list); + } +} + +static void +simplefb_clocks_destroy(struct list_head *list) +{ + struct list_head *pos, *n; + + list_for_each_safe(pos, n, list) { + struct simplefb_clock *entry = + container_of(pos, struct simplefb_clock, list); + + list_del(&entry->list); + + clk_disable_unprepare(entry->clock); + clk_put(entry->clock); + kfree(entry); + } +} + struct simplefb_par { u32 palette[PSEUDO_PALETTE_SIZE]; + struct list_head clock_list[1]; }; static int simplefb_probe(struct platform_device *pdev) @@ -236,6 +327,8 @@ static int simplefb_probe(struct platform_device *pdev) } info->pseudo_palette = par->palette; + simplefb_clocks_init(pdev, par->clock_list); + dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n", info->fix.smem_start, info->fix.smem_len, info->screen_base); @@ -247,14 +340,15 @@ static int simplefb_probe(struct platform_device *pdev) ret = register_framebuffer(info); if (ret < 0) { dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); - goto error_unmap; + goto error_clocks; } dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node); return 0; - error_unmap: + error_clocks: + simplefb_clocks_destroy(par->clock_list); iounmap(info->screen_base); error_fb_release: @@ -266,8 +360,10 @@ static int simplefb_probe(struct platform_device *pdev) static int simplefb_remove(struct platform_device *pdev) { struct fb_info *info = platform_get_drvdata(pdev); + struct simplefb_par *par = info->par; unregister_framebuffer(info); + simplefb_clocks_destroy(par->clock_list); framebuffer_release(info); return 0;