From patchwork Mon Mar 18 21:31:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Figa X-Patchwork-Id: 2296511 Return-Path: X-Original-To: patchwork-linux-samsung-soc@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 79A22E00E6 for ; Mon, 18 Mar 2013 21:40:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933716Ab3CRVkJ (ORCPT ); Mon, 18 Mar 2013 17:40:09 -0400 Received: from mail-ea0-f175.google.com ([209.85.215.175]:48813 "EHLO mail-ea0-f175.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933108Ab3CRVkH (ORCPT ); Mon, 18 Mar 2013 17:40:07 -0400 Received: by mail-ea0-f175.google.com with SMTP id o10so2712777eaj.34 for ; Mon, 18 Mar 2013 14:40:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=pHMu7J96Qfxju9GtNxWiBelHBhz1U1hnCGsm0t6S7BA=; b=dUnp+fdRUbVidPaBkhAkzdHv9pK8euXYt7pD4C2HWhO189KxeCNsJ7t6dvaVRLjL18 Dszzl2bjnMJKBtVDIrw2la8x/6qCQjQjPYMXf946WN2FjvKJpLbMUZWy+GYlacbdpGUz BHHOxejstjxiYeH9WEC0io7Q1n4n+kjwHyV4VQBPGZDhazecwIvd76g0RRxzeSqYgclJ I1pMYjrPV7Ss91LIpsjmqYDy8iCCKJLsuExD5L1NAT/4yoEttMTuuZUFyjb1vBlqSjrU VwO13ji4SuOZiOYvzyf9NNejqy7Ndw34TCCqGszIAyX8OPh0haYXED98KeaELQSkCTc7 2evw== X-Received: by 10.14.220.135 with SMTP id o7mr53588532eep.3.1363642329473; Mon, 18 Mar 2013 14:32:09 -0700 (PDT) Received: from flatron.tomeq (87-207-52-162.dynamic.chello.pl. [87.207.52.162]) by mx.google.com with ESMTPS id f47sm29540034eep.13.2013.03.18.14.32.07 (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 18 Mar 2013 14:32:08 -0700 (PDT) From: Tomasz Figa To: linux-arm-kernel@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org, kgene.kim@samsung.com, thomas.abraham@linaro.org, linus.walleij@linaro.org, Tomasz Figa Subject: [PATCH 1/6] pinctrl: samsung: Protect bank registers with a spinlock Date: Mon, 18 Mar 2013 22:31:50 +0100 Message-Id: <1363642315-10331-2-git-send-email-tomasz.figa@gmail.com> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1363642315-10331-1-git-send-email-tomasz.figa@gmail.com> References: <1363642315-10331-1-git-send-email-tomasz.figa@gmail.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org Certain pin control registers can be accessed from different contexts, i.e. pinctrl, gpio and irq functions. This makes the locking provided by pin control core insufficient. This patch adds necessary locking using a per bank spinlock as it was done in the old Samsung GPIO driver. Signed-off-by: Tomasz Figa --- drivers/pinctrl/pinctrl-exynos.c | 11 +++++++++++ drivers/pinctrl/pinctrl-samsung.c | 24 ++++++++++++++++++++++++ drivers/pinctrl/pinctrl-samsung.h | 2 ++ 3 files changed, 37 insertions(+) diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 538b9dd..cf7700e 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,7 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) unsigned int shift = EXYNOS_EINT_CON_LEN * pin; unsigned int con, trig_type; unsigned long reg_con = ctrl->geint_con + bank->eint_offset; + unsigned long flags; unsigned int mask; switch (type) { @@ -118,11 +120,15 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) shift = pin * bank->func_width; mask = (1 << bank->func_width) - 1; + spin_lock_irqsave(&bank->slock, flags); + con = readl(d->virt_base + reg_con); con &= ~(mask << shift); con |= EXYNOS_EINT_FUNC << shift; writel(con, d->virt_base + reg_con); + spin_unlock_irqrestore(&bank->slock, flags); + return 0; } @@ -258,6 +264,7 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset; unsigned long shift = EXYNOS_EINT_CON_LEN * pin; unsigned long con, trig_type; + unsigned long flags; unsigned int mask; switch (type) { @@ -295,11 +302,15 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) shift = pin * bank->func_width; mask = (1 << bank->func_width) - 1; + spin_lock_irqsave(&bank->slock, flags); + con = readl(d->virt_base + reg_con); con &= ~(mask << shift); con |= EXYNOS_EINT_FUNC << shift; writel(con, d->virt_base + reg_con); + spin_unlock_irqrestore(&bank->slock, flags); + return 0; } diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 3475b92..b1d4ac8 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "core.h" #include "pinctrl-samsung.h" @@ -289,6 +290,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, struct samsung_pin_bank *bank; void __iomem *reg; u32 mask, shift, data, pin_offset, cnt; + unsigned long flags; drvdata = pinctrl_dev_get_drvdata(pctldev); pins = drvdata->pin_groups[group].pins; @@ -303,11 +305,15 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, mask = (1 << bank->func_width) - 1; shift = pin_offset * bank->func_width; + spin_lock_irqsave(&bank->slock, flags); + data = readl(reg); data &= ~(mask << shift); if (enable) data |= drvdata->pin_groups[group].func << shift; writel(data, reg); + + spin_unlock_irqrestore(&bank->slock, flags); } } @@ -338,6 +344,7 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, struct samsung_pinctrl_drv_data *drvdata; void __iomem *reg; u32 data, pin_offset, mask, shift; + unsigned long flags; bank = gc_to_pin_bank(range->gc); drvdata = pinctrl_dev_get_drvdata(pctldev); @@ -348,11 +355,16 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, mask = (1 << bank->func_width) - 1; shift = pin_offset * bank->func_width; + spin_lock_irqsave(&bank->slock, flags); + data = readl(reg); data &= ~(mask << shift); if (!input) data |= FUNC_OUTPUT << shift; writel(data, reg); + + spin_unlock_irqrestore(&bank->slock, flags); + return 0; } @@ -376,6 +388,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); u32 data, width, pin_offset, mask, shift; u32 cfg_value, cfg_reg; + unsigned long flags; drvdata = pinctrl_dev_get_drvdata(pctldev); pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, @@ -406,6 +419,8 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, if (!width) return -EINVAL; + spin_lock_irqsave(&bank->slock, flags); + mask = (1 << width) - 1; shift = pin_offset * width; data = readl(reg_base + cfg_reg); @@ -420,6 +435,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, data &= mask; *config = PINCFG_PACK(cfg_type, data); } + + spin_unlock_irqrestore(&bank->slock, flags); + return 0; } @@ -479,16 +497,21 @@ static const struct pinconf_ops samsung_pinconf_ops = { static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { struct samsung_pin_bank *bank = gc_to_pin_bank(gc); + unsigned long flags; void __iomem *reg; u32 data; reg = bank->drvdata->virt_base + bank->pctl_offset; + spin_lock_irqsave(&bank->slock, flags); + data = readl(reg + DAT_REG); data &= ~(1 << offset); if (value) data |= 1 << offset; writel(data, reg + DAT_REG); + + spin_unlock_irqrestore(&bank->slock, flags); } /* gpiolib gpio_get callback function */ @@ -859,6 +882,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( bank = ctrl->pin_banks; for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + spin_lock_init(&bank->slock); bank->drvdata = d; bank->pin_base = ctrl->nr_pins; ctrl->nr_pins += bank->nr_pins; diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index e2d4e67..b9dbe79 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -119,6 +119,7 @@ struct samsung_pinctrl_drv_data; * @irq_domain: IRQ domain of the bank. * @gpio_chip: GPIO chip of the bank. * @grange: linux gpio pin range supported by this bank. + * @slock: spinlock protecting bank registers */ struct samsung_pin_bank { u32 pctl_offset; @@ -137,6 +138,7 @@ struct samsung_pin_bank { struct irq_domain *irq_domain; struct gpio_chip gpio_chip; struct pinctrl_gpio_range grange; + spinlock_t slock; }; /**