From patchwork Fri Apr 26 13:10:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andr=C3=A9_Draszik?= X-Patchwork-Id: 13644789 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9F419C4345F for ; Fri, 26 Apr 2024 13:11:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References:Message-Id :MIME-Version:Subject:Date:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=J5OPy+DtSMP2nwcYtC+sXFlNUXxzQWbky7yjigc7W3E=; b=abEF249z/T5E5t t3Qvasr2dfbjYMWisFKTkRMCS6Z2RQ+vhf0cygpUmgTXxUFKnQ5AViQh5Uovh4YWM0m2Xb4h0bWBU qKnFovdzSgblYi69GcLNfDl2rQdcOFA4tBTTzllO0roKGdUUiRdLzoY4awUqRXFYYED53YJbiwLIi CYgvloF29zmhav7rWh3yX9JJ50PttoMjdvON7HPzZMVuKZIXW3eE+sQasxis5BWToeveaZ2MfavcT dvwjx63KakOMe7UDMnvQn9pKwuJNKAVbmsB56EopIrzEwQ4jKBD82xeA2ZA5eZkuJZehrgeddiFGu eq5Hq4gB36ipU2aJewpQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1s0LLw-0000000CabM-3DGG; Fri, 26 Apr 2024 13:11:00 +0000 Received: from mail-ed1-x531.google.com ([2a00:1450:4864:20::531]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1s0LLt-0000000CaZP-0eM4 for linux-arm-kernel@lists.infradead.org; Fri, 26 Apr 2024 13:10:58 +0000 Received: by mail-ed1-x531.google.com with SMTP id 4fb4d7f45d1cf-56e477db7fbso3219349a12.3 for ; Fri, 26 Apr 2024 06:10:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1714137050; x=1714741850; darn=lists.infradead.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=kyR9vWPsqsAUgpTsJMpV9yCJydAsWbKkcw3s9RwSvbs=; b=B5ZzXtpJwOVp40temdiAIog6svOROp7CsvJopYV+2+5FxsuEBe0uIyDHCU39WiNFnR BB904dyvvUk84VhTMy6IV8bWi2mlLyI8w6EzHeuGHqRJxXJLYQSqaQyBB1v6XN866U5N LYYJprqNir7iMu/+4Mlq4YHsP09k+YnOQxhgT2Q0Z8vx3Mv1qTZ+jgqiiGjC7Bo+PQI4 0rQJ78QSb4KtrRblZ4HUp00IR35C68btazkFCb+x1bt581sMnsfc+HmSKYJF88Tpk9ZJ C11cFz2fkLVbPREOQdowjqxfBYfP+wlPJzS8a6BWKmkFGFdMRtf897tuprPKcKY6Pq/o JCJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1714137050; x=1714741850; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=kyR9vWPsqsAUgpTsJMpV9yCJydAsWbKkcw3s9RwSvbs=; b=dAKMoprwuHy/mTQtOYvKKx6JDrHEURX7+yv7qWFlafNPgvPJR+ryfb/pk/Eyg5caZT goIoVlOs/wW4aor6vq2zH+a/wiQaB5WudZ8CnOOySoXRWboCYlVWKmYKofWsafFaRnmq J0bbC9n3cgz9z4HFExQpj6ijhd6oWe4r42r3ok2nCSfjzdDUI2gCdOyOv5vUcGpwSZUm aZ9w0AY09vmcpckusfP4OqfIomK/DpT74evXGbpxInvcMR0fqfkMaOD50ktbLf7QVTSF 6WymJ79n0NQyiJ8esspPGkKr64gArPAax3UOsrcaVBRnrsDoglrT/cZAUKAKmCQGUW/d vekA== X-Forwarded-Encrypted: i=1; AJvYcCUV62hT8rX7pXz2Ru8Kvc32fYJzC1SPgZaigQ8oaCFZ0fMWkZbhXuJpXtfa0/F4gPX+3fP65qxEpJojkSeUOgsC9F5j89OtrfUozpCD5AqjlDZ5W8w= X-Gm-Message-State: AOJu0YykoinJTEToroQsHr7JdaFUVlpcSKVEKJwkVprz72lkbWpoXETq dOzq4zw+fjBYPQFN9kH9vwqc0NZ8jjtoR+6BisT3iU71YQTrOglGaT1Q5goKLQ1PJgTVSZbM7yh OJZLLYg== X-Google-Smtp-Source: AGHT+IGSGholbRCB3xXRiKBdGHoIKLecb79/UgfewA7TWa6VNEesp01r2lLxHu5AHKlfCKAu7HlkxQ== X-Received: by 2002:a17:906:305b:b0:a58:a4bc:575d with SMTP id d27-20020a170906305b00b00a58a4bc575dmr1819263ejd.40.1714137049990; Fri, 26 Apr 2024 06:10:49 -0700 (PDT) Received: from puffmais.c.googlers.com (8.239.204.35.bc.googleusercontent.com. [35.204.239.8]) by smtp.gmail.com with ESMTPSA id u18-20020a170906c41200b00a58bec2ae2bsm1396948ejz.39.2024.04.26.06.10.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 26 Apr 2024 06:10:49 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Fri, 26 Apr 2024 14:10:46 +0100 Subject: [PATCH v2 1/2] dt-bindings: pinctrl: samsung: google,gs101-pinctrl needs a clock MIME-Version: 1.0 Message-Id: <20240426-samsung-pinctrl-busclock-v2-1-8dfecaabf020@linaro.org> References: <20240426-samsung-pinctrl-busclock-v2-0-8dfecaabf020@linaro.org> In-Reply-To: <20240426-samsung-pinctrl-busclock-v2-0-8dfecaabf020@linaro.org> To: Krzysztof Kozlowski , Sylwester Nawrocki , Alim Akhtar , Linus Walleij , Rob Herring , Conor Dooley , Tomasz Figa , Peter Griffin Cc: Tudor Ambarus , Will McVicker , Sam Protsenko , kernel-team@android.com, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, =?utf-8?q?Andr=C3=A9_Draszik?= X-Mailer: b4 0.12.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240426_061057_247821_733E1E11 X-CRM114-Status: GOOD ( 10.17 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The pin controller on Google Tensor gs101 requires a bus clock for register access to work. Add it. Signed-off-by: AndrĂ© Draszik --- As we only have the one clock here, please let me know if the clock-names should be removed. Having it does make /sys/kernel/debug/clk/clk_summary look nicer / more meaningful though :-) --- .../devicetree/bindings/pinctrl/samsung,pinctrl.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml index 118549c25976..49cc36b76fd0 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml @@ -73,6 +73,13 @@ properties: minItems: 1 maxItems: 2 + clocks: + maxItems: 1 + + clock-names: + items: + - const: pclk + wakeup-interrupt-controller: $ref: samsung,pinctrl-wakeup-interrupt.yaml @@ -120,6 +127,16 @@ required: allOf: - $ref: pinctrl.yaml# + - if: + properties: + compatible: + contains: + const: google,gs101-pinctrl + then: + required: + - clocks + - clock-names + - if: properties: compatible: From patchwork Fri Apr 26 13:10:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andr=C3=A9_Draszik?= X-Patchwork-Id: 13644790 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D9AA6C04FFE for ; Fri, 26 Apr 2024 13:11:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References:Message-Id :MIME-Version:Subject:Date:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=g77jSpkBtaeVxraPeEORslP1lZLPzU/IidrOLx9V7uM=; b=Tionx6V5e0NOmX fd8ui0I3A/23I7tMLUtWgau+boUbOzSBo6Mq5yytO9B4jNR/dtfoqg+mE0w3rZzYQA3miWwsF1lrq S17V3fo/zwfMo6lh6PlWc4MlanNBok6qvYO28Qd2rhtqlku4xMFPsFJAcX0cUdZ44qv1dUSLrVKJc wYIivszRXps2dCNYtiuC0K/mK30UuazSw/neEyo2bDb6IyfkryM3UNVlHM+9ycbTHzaSdJzQYxHLj EGzKliQNDqdCkby60GvQ2EE6aYSCc9zJ+fq78V5tQvmvnBRGj8qvofBYWHH0mOx28DkFLjssFGShZ EOvfiJztUYq0cP8o+IIQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1s0LME-0000000Caju-3CnD; Fri, 26 Apr 2024 13:11:18 +0000 Received: from mail-ej1-x62a.google.com ([2a00:1450:4864:20::62a]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1s0LLt-0000000CaZX-0eVe for linux-arm-kernel@lists.infradead.org; Fri, 26 Apr 2024 13:10:59 +0000 Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-a5883518135so248872766b.3 for ; Fri, 26 Apr 2024 06:10:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1714137051; x=1714741851; darn=lists.infradead.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=S9Qwvd6hs9zicHZIfahxQLk96QTDqsG31aYfRw5jOvY=; b=if0YaLLFKBjJ48JVEaAY9Jq0bfD/9xAnGVyAd+enMpqpInfxFzqG5id3gvPQK/aD2y ygvsGp5mV/j2ergnzAYsNTzJZLKZ3BK+KmRH712RWcWPgGp9CL80zJEEgcKW5mq2GRie q29q8T9zJFDh655yo7VfAVxg4nBLWheWELk4IKdzLUf9TlMIC3q2bQGUcW6sQxEi+gzM m2bkVXUdSxwhbS51wY2csqnhjwOqOn5fn5AGXGJ4B4jYqbprnyFWcVxzoYSTpshFi88o L5avIDIa38+V/Uo8/86XpCDrS6Gbdmz4d7LMDy51R4BpNZwuRqiRuue0B/hl7CKc7Wqd eGJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1714137051; x=1714741851; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=S9Qwvd6hs9zicHZIfahxQLk96QTDqsG31aYfRw5jOvY=; b=a1XKFOmFeBCeL4lptwBITdbj9Ql4IMTOFe06fBoIHrCo7RjBrPafmTlB8vzGy5ZnQR AT9pv15LElLOmDC9Y7eW+25r6oKT0jvdQeiWgbfLpywNjSeDEhVVKkTClOcsXU8AvqZR Ny47sruRFuqkon8626yYT1GnV+zPaMKbZbhEYoA/wNJvkU93NNL+ElmazOZv3HtWNUlK pCwDRdDmmetLJytafcd5NsEqsCJlentNbq03pGVdHUWQoOuQ2KpdosTggNlvN/xbn/RJ T+0/kPwlNjVGv2XncaRfL+C5MhQmGLkIgUBBc5m7LsBiblH8Gkz/z0Iuz+ZYzuql6f1g QoYw== X-Forwarded-Encrypted: i=1; AJvYcCWU+7ireopvZtIFXJayZdjaOh+rpp+ho7+3siXQZLaqoFNEdh6lc6PuoeiM95CQ4dEpYIn5nyIxLQ/7z94SHxhEWS0ZJdbnYokPbp4qoWruSJjsF+Y= X-Gm-Message-State: AOJu0YzqUEGwAWkmJlhllWOVZDh43SZGzopAjtKAcSaC0ScCZ+Y/PG6S JHYxZ+dJSqkuQFXW1dG/vw8SVmI17ENuelzMDDebPs0wGqnpBJYQ5G9qVXICif9i0OU+H621RMM boPhbFg== X-Google-Smtp-Source: AGHT+IFSOiz9rRsJTgrW9U2HDcEazy/PcTJg277ufvRSlfrOXfldfE2Gty+LDpIJur7Hq05qn7kHbQ== X-Received: by 2002:a17:906:b292:b0:a58:be00:7e7f with SMTP id q18-20020a170906b29200b00a58be007e7fmr2031703ejz.57.1714137051150; Fri, 26 Apr 2024 06:10:51 -0700 (PDT) Received: from puffmais.c.googlers.com (8.239.204.35.bc.googleusercontent.com. [35.204.239.8]) by smtp.gmail.com with ESMTPSA id u18-20020a170906c41200b00a58bec2ae2bsm1396948ejz.39.2024.04.26.06.10.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 26 Apr 2024 06:10:50 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Fri, 26 Apr 2024 14:10:47 +0100 Subject: [PATCH v2 2/2] pinctrl: samsung: support a bus clock MIME-Version: 1.0 Message-Id: <20240426-samsung-pinctrl-busclock-v2-2-8dfecaabf020@linaro.org> References: <20240426-samsung-pinctrl-busclock-v2-0-8dfecaabf020@linaro.org> In-Reply-To: <20240426-samsung-pinctrl-busclock-v2-0-8dfecaabf020@linaro.org> To: Krzysztof Kozlowski , Sylwester Nawrocki , Alim Akhtar , Linus Walleij , Rob Herring , Conor Dooley , Tomasz Figa , Peter Griffin Cc: Tudor Ambarus , Will McVicker , Sam Protsenko , kernel-team@android.com, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, =?utf-8?q?Andr=C3=A9_Draszik?= X-Mailer: b4 0.12.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240426_061057_340458_B6816FAE X-CRM114-Status: GOOD ( 22.48 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On some Samsung-based SoCs there are separate bus clocks / gates each for each pinctrl instance. To be able to access each pinctrl instance's registers, this bus clock needs to be running, otherwise register access will hang. Google Tensor gs101 is one example for such an implementation. Update the driver to handle this optional bus clock: * handle an optional bus clock from DT * prepare it during driver probe * enclose all relevant register accesses with a clock enable & disable Signed-off-by: AndrĂ© Draszik --- v2: - propagate clk_enable() errors in samsung_pinmux_setup(), i.e. struct pinmux_ops::set_mux() - move clk_enable()/disable() outside bank->slock lock, to avoid possible deadlocks due to locking inversion - fix some comments - use 'ret' instead of 'i' in samsung_pinctrl_resume() --- drivers/pinctrl/samsung/pinctrl-exynos.c | 112 ++++++++++++++++++++++++++++++ drivers/pinctrl/samsung/pinctrl-samsung.c | 95 ++++++++++++++++++++++++- drivers/pinctrl/samsung/pinctrl-samsung.h | 2 + 3 files changed, 206 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 871c1eb46ddf..ce5e6783b5b9 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -13,6 +13,7 @@ // the Samsung pinctrl/gpiolib driver. It also includes the implementation of // external gpio and wakeup interrupt support. +#include #include #include #include @@ -61,6 +62,12 @@ static void exynos_irq_mask(struct irq_data *irqd) else reg_mask = our_chip->eint_mask + bank->eint_offset; + if (clk_enable(bank->drvdata->pclk)) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for masking IRQ\n"); + return; + } + raw_spin_lock_irqsave(&bank->slock, flags); mask = readl(bank->eint_base + reg_mask); @@ -68,6 +75,8 @@ static void exynos_irq_mask(struct irq_data *irqd) writel(mask, bank->eint_base + reg_mask); raw_spin_unlock_irqrestore(&bank->slock, flags); + + clk_disable(bank->drvdata->pclk); } static void exynos_irq_ack(struct irq_data *irqd) @@ -82,7 +91,15 @@ static void exynos_irq_ack(struct irq_data *irqd) else reg_pend = our_chip->eint_pend + bank->eint_offset; + if (clk_enable(bank->drvdata->pclk)) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock to ack IRQ\n"); + return; + } + writel(1 << irqd->hwirq, bank->eint_base + reg_pend); + + clk_disable(bank->drvdata->pclk); } static void exynos_irq_unmask(struct irq_data *irqd) @@ -110,6 +127,12 @@ static void exynos_irq_unmask(struct irq_data *irqd) else reg_mask = our_chip->eint_mask + bank->eint_offset; + if (clk_enable(bank->drvdata->pclk)) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for unmasking IRQ\n"); + return; + } + raw_spin_lock_irqsave(&bank->slock, flags); mask = readl(bank->eint_base + reg_mask); @@ -117,6 +140,8 @@ static void exynos_irq_unmask(struct irq_data *irqd) writel(mask, bank->eint_base + reg_mask); raw_spin_unlock_irqrestore(&bank->slock, flags); + + clk_disable(bank->drvdata->pclk); } static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type) @@ -127,6 +152,7 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type) unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq; unsigned int con, trig_type; unsigned long reg_con; + int ret; switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -159,11 +185,20 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type) else reg_con = our_chip->eint_con + bank->eint_offset; + ret = clk_enable(bank->drvdata->pclk); + if (ret) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for configuring IRQ type\n"); + return ret; + } + con = readl(bank->eint_base + reg_con); con &= ~(EXYNOS_EINT_CON_MASK << shift); con |= trig_type << shift; writel(con, bank->eint_base + reg_con); + clk_disable(bank->drvdata->pclk); + return 0; } @@ -200,6 +235,14 @@ static int exynos_irq_request_resources(struct irq_data *irqd) shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC]; mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1; + ret = clk_enable(bank->drvdata->pclk); + if (ret) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for configuring pin %s-%lu\n", + bank->name, irqd->hwirq); + return ret; + } + raw_spin_lock_irqsave(&bank->slock, flags); con = readl(bank->pctl_base + reg_con); @@ -209,6 +252,8 @@ static int exynos_irq_request_resources(struct irq_data *irqd) raw_spin_unlock_irqrestore(&bank->slock, flags); + clk_disable(bank->drvdata->pclk); + return 0; } @@ -223,6 +268,13 @@ static void exynos_irq_release_resources(struct irq_data *irqd) shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC]; mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1; + if (clk_enable(bank->drvdata->pclk)) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for deconfiguring pin %s-%lu\n", + bank->name, irqd->hwirq); + return; + } + raw_spin_lock_irqsave(&bank->slock, flags); con = readl(bank->pctl_base + reg_con); @@ -232,6 +284,8 @@ static void exynos_irq_release_resources(struct irq_data *irqd) raw_spin_unlock_irqrestore(&bank->slock, flags); + clk_disable(bank->drvdata->pclk); + gpiochip_unlock_as_irq(&bank->gpio_chip, irqd->hwirq); } @@ -281,10 +335,19 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) unsigned int svc, group, pin; int ret; + if (clk_enable(bank->drvdata->pclk)) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for handling IRQ\n"); + return IRQ_NONE; + } + if (bank->eint_con_offset) svc = readl(bank->eint_base + EXYNOSAUTO_SVC_OFFSET); else svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET); + + clk_disable(bank->drvdata->pclk); + group = EXYNOS_SVC_GROUP(svc); pin = svc & EXYNOS_SVC_NUM_MASK; @@ -563,6 +626,20 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc) chained_irq_enter(chip, desc); + /* + * just enable the clock once here, to avoid an enable/disable dance for + * each bank. + */ + if (eintd->nr_banks) { + struct samsung_pin_bank *b = eintd->banks[0]; + + if (clk_enable(b->drvdata->pclk)) { + dev_err(b->gpio_chip.parent, + "unable to enable clock for pending IRQs\n"); + return; + } + } + for (i = 0; i < eintd->nr_banks; ++i) { struct samsung_pin_bank *b = eintd->banks[i]; pend = readl(b->eint_base + b->irq_chip->eint_pend @@ -572,6 +649,9 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc) exynos_irq_demux_eint(pend & ~mask, b->irq_domain); } + if (eintd->nr_banks) + clk_disable(eintd->banks[0]->drvdata->pclk); + chained_irq_exit(chip, desc); } @@ -695,6 +775,12 @@ static void exynos_pinctrl_suspend_bank( struct exynos_eint_gpio_save *save = bank->soc_priv; const void __iomem *regs = bank->eint_base; + if (clk_enable(bank->drvdata->pclk)) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for saving state\n"); + return; + } + save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET + bank->eint_offset); save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET @@ -704,6 +790,8 @@ static void exynos_pinctrl_suspend_bank( save->eint_mask = readl(regs + bank->irq_chip->eint_mask + bank->eint_offset); + clk_disable(bank->drvdata->pclk); + pr_debug("%s: save con %#010x\n", bank->name, save->eint_con); pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0); pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1); @@ -716,9 +804,17 @@ static void exynosauto_pinctrl_suspend_bank(struct samsung_pinctrl_drv_data *drv struct exynos_eint_gpio_save *save = bank->soc_priv; const void __iomem *regs = bank->eint_base; + if (clk_enable(bank->drvdata->pclk)) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for saving state\n"); + return; + } + save->eint_con = readl(regs + bank->pctl_offset + bank->eint_con_offset); save->eint_mask = readl(regs + bank->pctl_offset + bank->eint_mask_offset); + clk_disable(bank->drvdata->pclk); + pr_debug("%s: save con %#010x\n", bank->name, save->eint_con); pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask); } @@ -753,6 +849,12 @@ static void exynos_pinctrl_resume_bank( struct exynos_eint_gpio_save *save = bank->soc_priv; void __iomem *regs = bank->eint_base; + if (clk_enable(bank->drvdata->pclk)) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for restoring state\n"); + return; + } + pr_debug("%s: con %#010x => %#010x\n", bank->name, readl(regs + EXYNOS_GPIO_ECON_OFFSET + bank->eint_offset), save->eint_con); @@ -774,6 +876,8 @@ static void exynos_pinctrl_resume_bank( + 2 * bank->eint_offset + 4); writel(save->eint_mask, regs + bank->irq_chip->eint_mask + bank->eint_offset); + + clk_disable(bank->drvdata->pclk); } static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvdata, @@ -782,6 +886,12 @@ static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvd struct exynos_eint_gpio_save *save = bank->soc_priv; void __iomem *regs = bank->eint_base; + if (clk_enable(bank->drvdata->pclk)) { + dev_err(bank->gpio_chip.parent, + "unable to enable clock for restoring state\n"); + return; + } + pr_debug("%s: con %#010x => %#010x\n", bank->name, readl(regs + bank->pctl_offset + bank->eint_con_offset), save->eint_con); pr_debug("%s: mask %#010x => %#010x\n", bank->name, @@ -789,6 +899,8 @@ static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvd writel(save->eint_con, regs + bank->pctl_offset + bank->eint_con_offset); writel(save->eint_mask, regs + bank->pctl_offset + bank->eint_mask_offset); + + clk_disable(bank->drvdata->pclk); } void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata) diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index ed07e23e0912..acde42983934 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -15,6 +15,7 @@ // but provides extensions to which platform specific implementation of the gpio // and wakeup interrupts can be hooked to. +#include #include #include #include @@ -371,7 +372,7 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, } /* enable or disable a pinmux function */ -static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, +static int samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { struct samsung_pinctrl_drv_data *drvdata; @@ -382,6 +383,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, unsigned long flags; const struct samsung_pmx_func *func; const struct samsung_pin_group *grp; + int ret; drvdata = pinctrl_dev_get_drvdata(pctldev); func = &drvdata->pmx_functions[selector]; @@ -397,6 +399,12 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, reg += 4; } + ret = clk_enable(drvdata->pclk); + if (ret) { + dev_err(pctldev->dev, "failed to enable clock for setup\n"); + return ret; + } + raw_spin_lock_irqsave(&bank->slock, flags); data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]); @@ -405,6 +413,10 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]); raw_spin_unlock_irqrestore(&bank->slock, flags); + + clk_disable(drvdata->pclk); + + return 0; } /* enable a specified pinmux by writing to registers */ @@ -412,8 +424,7 @@ static int samsung_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { - samsung_pinmux_setup(pctldev, selector, group); - return 0; + return samsung_pinmux_setup(pctldev, selector, group); } /* list of pinmux callbacks for the pinmux vertical in pinctrl core */ @@ -436,6 +447,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, u32 data, width, pin_offset, mask, shift; u32 cfg_value, cfg_reg; unsigned long flags; + int ret; drvdata = pinctrl_dev_get_drvdata(pctldev); pin_to_reg_bank(drvdata, pin, ®_base, &pin_offset, &bank); @@ -447,6 +459,12 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, width = type->fld_width[cfg_type]; cfg_reg = type->reg_offset[cfg_type]; + ret = clk_enable(drvdata->pclk); + if (ret) { + dev_err(drvdata->dev, "failed to enable clock\n"); + return ret; + } + raw_spin_lock_irqsave(&bank->slock, flags); mask = (1 << width) - 1; @@ -466,6 +484,8 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, raw_spin_unlock_irqrestore(&bank->slock, flags); + clk_disable(drvdata->pclk); + return 0; } @@ -555,11 +575,19 @@ static void samsung_gpio_set_value(struct gpio_chip *gc, static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { struct samsung_pin_bank *bank = gpiochip_get_data(gc); + struct samsung_pinctrl_drv_data *drvdata = bank->drvdata; unsigned long flags; + if (clk_enable(drvdata->pclk)) { + dev_err(drvdata->dev, "failed to enable clock\n"); + return; + } + raw_spin_lock_irqsave(&bank->slock, flags); samsung_gpio_set_value(gc, offset, value); raw_spin_unlock_irqrestore(&bank->slock, flags); + + clk_disable(drvdata->pclk); } /* gpiolib gpio_get callback function */ @@ -569,12 +597,23 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) u32 data; struct samsung_pin_bank *bank = gpiochip_get_data(gc); const struct samsung_pin_bank_type *type = bank->type; + struct samsung_pinctrl_drv_data *drvdata = bank->drvdata; + int ret; reg = bank->pctl_base + bank->pctl_offset; + ret = clk_enable(drvdata->pclk); + if (ret) { + dev_err(drvdata->dev, "failed to enable clock\n"); + return ret; + } + data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]); data >>= offset; data &= 1; + + clk_disable(drvdata->pclk); + return data; } @@ -591,9 +630,11 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc, struct samsung_pin_bank *bank; void __iomem *reg; u32 data, mask, shift; + struct samsung_pinctrl_drv_data *drvdata; bank = gpiochip_get_data(gc); type = bank->type; + drvdata = bank->drvdata; reg = bank->pctl_base + bank->pctl_offset + type->reg_offset[PINCFG_TYPE_FUNC]; @@ -619,12 +660,22 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc, static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) { struct samsung_pin_bank *bank = gpiochip_get_data(gc); + struct samsung_pinctrl_drv_data *drvdata = bank->drvdata; unsigned long flags; int ret; + ret = clk_enable(drvdata->pclk); + if (ret) { + dev_err(drvdata->dev, "failed to enable clock\n"); + return ret; + } + raw_spin_lock_irqsave(&bank->slock, flags); ret = samsung_gpio_set_direction(gc, offset, true); raw_spin_unlock_irqrestore(&bank->slock, flags); + + clk_disable(drvdata->pclk); + return ret; } @@ -633,14 +684,23 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int value) { struct samsung_pin_bank *bank = gpiochip_get_data(gc); + struct samsung_pinctrl_drv_data *drvdata = bank->drvdata; unsigned long flags; int ret; + ret = clk_enable(drvdata->pclk); + if (ret) { + dev_err(drvdata->dev, "failed to enable clock\n"); + return ret; + } + raw_spin_lock_irqsave(&bank->slock, flags); samsung_gpio_set_value(gc, offset, value); ret = samsung_gpio_set_direction(gc, offset, false); raw_spin_unlock_irqrestore(&bank->slock, flags); + clk_disable(drvdata->pclk); + return ret; } @@ -1164,6 +1224,12 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) } } + drvdata->pclk = devm_clk_get_optional_prepared(dev, "pclk"); + if (IS_ERR(drvdata->pclk)) { + ret = PTR_ERR(drvdata->pclk); + goto err_put_banks; + } + ret = samsung_pinctrl_register(pdev, drvdata); if (ret) goto err_put_banks; @@ -1202,6 +1268,13 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev) struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev); int i; + i = clk_enable(drvdata->pclk); + if (i) { + dev_err(drvdata->dev, + "failed to enable clock for saving state\n"); + return i; + } + for (i = 0; i < drvdata->nr_banks; i++) { struct samsung_pin_bank *bank = &drvdata->pin_banks[i]; const void __iomem *reg = bank->pctl_base + bank->pctl_offset; @@ -1231,6 +1304,8 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev) } } + clk_disable(drvdata->pclk); + if (drvdata->suspend) drvdata->suspend(drvdata); if (drvdata->retention_ctrl && drvdata->retention_ctrl->enable) @@ -1250,8 +1325,20 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev) static int __maybe_unused samsung_pinctrl_resume(struct device *dev) { struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev); + int ret; int i; + /* + * enable clock before the callback, as we don't want to have to deal + * with callback cleanup on clock failures. + */ + ret = clk_enable(drvdata->pclk); + if (ret) { + dev_err(drvdata->dev, + "failed to enable clock for restoring state\n"); + return ret; + } + if (drvdata->resume) drvdata->resume(drvdata); @@ -1286,6 +1373,8 @@ static int __maybe_unused samsung_pinctrl_resume(struct device *dev) writel(bank->pm_save[type], reg + offs[type]); } + clk_disable(drvdata->pclk); + if (drvdata->retention_ctrl && drvdata->retention_ctrl->disable) drvdata->retention_ctrl->disable(drvdata); diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index ab791afaabf5..d50ba6f07d5d 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -274,6 +274,7 @@ struct samsung_pin_ctrl { * through samsung_pinctrl_drv_data, not samsung_pin_bank). * @dev: device instance representing the controller. * @irq: interrpt number used by the controller to notify gpio interrupts. + * @pclk: optional bus clock if required for accessing registers * @ctrl: pin controller instance managed by the driver. * @pctl: pin controller descriptor registered with the pinctrl subsystem. * @pctl_dev: cookie representing pinctrl device instance. @@ -293,6 +294,7 @@ struct samsung_pinctrl_drv_data { void __iomem *virt_base; struct device *dev; int irq; + struct clk *pclk; struct pinctrl_desc pctl; struct pinctrl_dev *pctl_dev;