From patchwork Fri Jan 18 04:58:22 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Prisk X-Patchwork-Id: 1999111 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id 105B53FED4 for ; Fri, 18 Jan 2013 05:00:30 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Tw41p-0007AN-9x; Fri, 18 Jan 2013 04:58:09 +0000 Received: from server.prisktech.co.nz ([115.188.14.127]) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Tw41m-00079Y-7M for linux-arm-kernel@lists.infradead.org; Fri, 18 Jan 2013 04:58:07 +0000 Received: from localhost.localdomain (unknown [192.168.0.102]) by server.prisktech.co.nz (Postfix) with ESMTP id 91392FC08FA; Fri, 18 Jan 2013 17:58:04 +1300 (NZDT) From: Tony Prisk To: Grant Likely , Linus Walleij Subject: [PATCH v3] gpio: vt8500: memory cleanup missing Date: Fri, 18 Jan 2013 17:58:22 +1300 Message-Id: <1358485102-6585-1-git-send-email-linux@prisktech.co.nz> X-Mailer: git-send-email 1.7.9.5 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130117_235806_779552_948FB021 X-CRM114-Status: GOOD ( 20.95 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: vt8500-wm8505-linux-kernel@googlegroups.com, Tony Prisk , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This driver is missing a .remove callback, and the fail path on probe is incomplete. If an error occurs in vt8500_add_chips, gpio_base is not unmapped. The driver is also ignoring the return value from this function so if a chip fails to register it completes as successful. Replaced pr_err with dev_err in vt8500_add_chips since the device is available. There is also no .remove callback defined so the function is added. Signed-off-by: Tony Prisk --- v2: Remove global vtchip and store pointer in platform_data - As pointed out by Russell King. v3: Following problems pointed out by Grant Likely: Removed unnecessary whitespace change. Removed test against pdev->dev.of_node (np). Replaced code with a devm_request_and_ioremap so np is now unneccessary. This also removes the need for cleanup in the fail path. Move struct vt8500_gpio_chip within vt8500_data and store the iobase and num_banks in vt8500_data. drivers/gpio/gpio-vt8500.c | 61 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c index b53320a..5c8cd7c 100644 --- a/drivers/gpio/gpio-vt8500.c +++ b/drivers/gpio/gpio-vt8500.c @@ -127,6 +127,12 @@ struct vt8500_gpio_chip { void __iomem *base; }; +struct vt8500_data { + struct vt8500_gpio_chip *chip; + void __iomem *iobase; + int num_banks; +}; + #define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip) @@ -224,19 +230,32 @@ static int vt8500_of_xlate(struct gpio_chip *gc, static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base, const struct vt8500_gpio_data *data) { + struct vt8500_data *priv; struct vt8500_gpio_chip *vtchip; struct gpio_chip *chip; int i; int pin_cnt = 0; - vtchip = devm_kzalloc(&pdev->dev, + priv = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_data), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + priv->chip = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_gpio_chip) * data->num_banks, GFP_KERNEL); - if (!vtchip) { - pr_err("%s: failed to allocate chip memory\n", __func__); + if (!priv->chip) { + dev_err(&pdev->dev, "failed to allocate chip memory\n"); return -ENOMEM; } + priv->iobase = base; + priv->num_banks = data->num_banks; + platform_set_drvdata(pdev, priv); + + vtchip = priv->chip; + for (i = 0; i < data->num_banks; i++) { vtchip[i].base = base; vtchip[i].regs = &data->banks[i]; @@ -273,36 +292,54 @@ static struct of_device_id vt8500_gpio_dt_ids[] = { static int vt8500_gpio_probe(struct platform_device *pdev) { + int ret; void __iomem *gpio_base; - struct device_node *np; + struct resource *res; const struct of_device_id *of_id = of_match_device(vt8500_gpio_dt_ids, &pdev->dev); if (!of_id) { - dev_err(&pdev->dev, "Failed to find gpio controller\n"); + dev_err(&pdev->dev, "No matching driver data\n"); return -ENODEV; } - np = pdev->dev.of_node; - if (!np) { - dev_err(&pdev->dev, "Missing GPIO description in devicetree\n"); - return -EFAULT; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Unable to get IO resource\n"); + return -ENODEV; } - gpio_base = of_iomap(np, 0); + gpio_base = devm_request_and_ioremap(&pdev->dev, res); if (!gpio_base) { dev_err(&pdev->dev, "Unable to map GPIO registers\n"); - of_node_put(np); return -ENOMEM; } - vt8500_add_chips(pdev, gpio_base, of_id->data); + ret = vt8500_add_chips(pdev, gpio_base, of_id->data); + + return ret; +} + +static int vt8500_gpio_remove(struct platform_device *pdev) +{ + int i; + int ret; + struct vt8500_data *priv = platform_get_drvdata(pdev); + struct vt8500_gpio_chip *vtchip = priv->chip; + + for (i = 0; i < priv->num_banks; i++) { + ret = gpiochip_remove(&vtchip[i].chip); + if (ret) + dev_warn(&pdev->dev, "gpiochip_remove returned %d\n", + ret); + } return 0; } static struct platform_driver vt8500_gpio_driver = { .probe = vt8500_gpio_probe, + .remove = vt8500_gpio_remove, .driver = { .name = "vt8500-gpio", .owner = THIS_MODULE,