From patchwork Mon Jan 29 11:52:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 767504 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 alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (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 71B03C48286 for ; Mon, 29 Jan 2024 11:54:06 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id D304E846; Mon, 29 Jan 2024 12:53:54 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz D304E846 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1706529244; bh=S2rlUFR7COiCXocSNwYdxys7hBLM3PNkPdINVgzUk+A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=tXoJ2OYNYQUSWM9E6+qAzJJ3fDMJa4R77d2MZYBOFZoQ6RZJTPUW4+3YBElJxZpPK xbi20tr0h+7zZISFB5kujdmAFKueoB9h0X/KsHxXZTOPy/n8h+n8Hrv1+LTAIVZIiM rjWJPU9wgfraSOfS4FXweqLZFH6/wow3zpX5WbNk= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 8FDA0F8060D; Mon, 29 Jan 2024 12:52:55 +0100 (CET) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id EB119F80617; Mon, 29 Jan 2024 12:52:54 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 37343F805DA; Mon, 29 Jan 2024 12:52:47 +0100 (CET) Received: from mail-lj1-x230.google.com (mail-lj1-x230.google.com [IPv6:2a00:1450:4864:20::230]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 94A5EF800FB for ; Mon, 29 Jan 2024 12:52:28 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 94A5EF800FB Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key, unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=RiwAz0ih Received: by mail-lj1-x230.google.com with SMTP id 38308e7fff4ca-2cf5917f049so14781611fa.2 for ; Mon, 29 Jan 2024 03:52:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1706529147; x=1707133947; darn=alsa-project.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=xRfi7bENx/I9rSbdoOaYxClTFMvpbeifXHCV8MulR38=; b=RiwAz0ihpVlYzNknw4iDaVJ2L/tsHA9Z1IEtNdlG89vj/P0Srh/XRMmX0MQw9mXG+q OvHH4q5iEsLZ9zPKaXLcYdUJpa/sNHeIY82hQZSFd7idVJySRpJjA0HKaSysohP0ohNr +Jic7PhXjEVzBj7O4w7O66qEIhN99P86piWRfLKgFs6yc2/mYWwfxrs9EdQhuyAWNfmQ qF9altw1DfKHrek2p/EcQirQpK/uNetzA3uj0mFCtvW3IlvlWBw/0TYQrVuTZZrT+BEt 6u1QnywYeBWtvCZz8409QOBbk/X22+6U9xmnjHKsOlYNTIZ2AQ8NuepD46EIyveNIPz6 hmrQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706529147; x=1707133947; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=xRfi7bENx/I9rSbdoOaYxClTFMvpbeifXHCV8MulR38=; b=sbVBWFhZPmjZbSonKr2e82fgc0grsxjmwhTozxhfx8hZMP49woslTOl04DMl5XBayM dAwBTGqnEi/TW+sH4Nf63PWpzf/vI5ma8mnra8wGySbccs1UKzdiCbCb6JJr8OZ6k6QQ wEo6DeaNRGxIm0n+bTSQ5SY03zIAYX0JobLbaZon5PlF5YcHYAYH08fCXC9mBB8crO0k WekTMKrLhIYsZgu0qi1aC9pwGOTKbIR4MbDMtaEWrRJ/L/ekgkg0F0FSh4P83arRtgoz p/50mAM/LqmjMB+iXFvSXmyIkGtJntkvzjZgfAAJHMBHlhmm9mGSXuy0JCkEm5okjDYC 4HlQ== X-Gm-Message-State: AOJu0YyiqqksTvuKT+aL8vUjkSamohL75gdWiRdYVeXOqi943GccldxF gPf57GickDp0sixbmqbZcnngvemfmq0sF3s54g1URmWi4AirSbcRBzwHMnpI7hM= X-Google-Smtp-Source: AGHT+IFTEM1THZirVtQxIZP9MNaZbkSv6DdZKpitrgxDoUeFmnTOnnYNuKze7r5nrTa1FW6MWC6RQw== X-Received: by 2002:a2e:be11:0:b0:2d0:4c41:695 with SMTP id z17-20020a2ebe11000000b002d04c410695mr1588148ljq.37.1706529147037; Mon, 29 Jan 2024 03:52:27 -0800 (PST) Received: from krzk-bin.. ([178.197.222.62]) by smtp.gmail.com with ESMTPSA id ec19-20020a0564020d5300b0055f29ececeasm19907edb.57.2024.01.29.03.52.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 03:52:26 -0800 (PST) From: Krzysztof Kozlowski To: Srinivas Kandagatla , Banajit Goswami , Bjorn Andersson , Konrad Dybcio , Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , "Rafael J. Wysocki" , Viresh Kumar , Frank Rowand , Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-arm-msm@vger.kernel.org, linux-sound@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org Cc: Krzysztof Kozlowski , Bartosz Golaszewski , Chris Packham , Sean Anderson , Bartosz Golaszewski Subject: [PATCH v6 3/6] reset: gpio: Add GPIO-based reset controller Date: Mon, 29 Jan 2024 12:52:13 +0100 Message-Id: <20240129115216.96479-4-krzysztof.kozlowski@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240129115216.96479-1-krzysztof.kozlowski@linaro.org> References: <20240129115216.96479-1-krzysztof.kozlowski@linaro.org> MIME-Version: 1.0 Message-ID-Hash: 27WKGZN5X7Y75IEL2Y3XXCAFMP7RR3FK X-Message-ID-Hash: 27WKGZN5X7Y75IEL2Y3XXCAFMP7RR3FK X-MailFrom: krzysztof.kozlowski@linaro.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.9 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add a simple driver to control GPIO-based resets using the reset controller API for the cases when the GPIOs are shared and reset should be coordinated. The driver is expected to be used by reset core framework for ad-hoc reset controllers. Cc: Bartosz Golaszewski Cc: Chris Packham Cc: Sean Anderson Reviewed-by: Bartosz Golaszewski Reviewed-by: Philipp Zabel Signed-off-by: Krzysztof Kozlowski --- MAINTAINERS | 5 ++ drivers/reset/Kconfig | 9 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-gpio.c | 119 +++++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 drivers/reset/reset-gpio.c diff --git a/MAINTAINERS b/MAINTAINERS index ddc5e1049921..91d45c6bade7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8905,6 +8905,11 @@ F: Documentation/i2c/muxes/i2c-mux-gpio.rst F: drivers/i2c/muxes/i2c-mux-gpio.c F: include/linux/platform_data/i2c-mux-gpio.h +GENERIC GPIO RESET DRIVER +M: Krzysztof Kozlowski +S: Maintained +F: drivers/reset/reset-gpio.c + GENERIC HDLC (WAN) DRIVERS M: Krzysztof Halasa S: Maintained diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index ccd59ddd7610..bb1b5a326eb7 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -66,6 +66,15 @@ config RESET_BRCMSTB_RESCAL This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on BCM7216. +config RESET_GPIO + tristate "GPIO reset controller" + help + This enables a generic reset controller for resets attached via + GPIOs. Typically for OF platforms this driver expects "reset-gpios" + property. + + If compiled as module, it will be called reset-gpio. + config RESET_HSDK bool "Synopsys HSDK Reset Driver" depends on HAS_IOMEM diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 8270da8a4baa..fd8b49fa46fc 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o +obj-$(CONFIG_RESET_GPIO) += reset-gpio.o obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o diff --git a/drivers/reset/reset-gpio.c b/drivers/reset/reset-gpio.c new file mode 100644 index 000000000000..2290b25b6703 --- /dev/null +++ b/drivers/reset/reset-gpio.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include + +struct reset_gpio_priv { + struct reset_controller_dev rc; + struct gpio_desc *reset; +}; + +static inline struct reset_gpio_priv +*rc_to_reset_gpio(struct reset_controller_dev *rc) +{ + return container_of(rc, struct reset_gpio_priv, rc); +} + +static int reset_gpio_assert(struct reset_controller_dev *rc, unsigned long id) +{ + struct reset_gpio_priv *priv = rc_to_reset_gpio(rc); + + gpiod_set_value_cansleep(priv->reset, 1); + + return 0; +} + +static int reset_gpio_deassert(struct reset_controller_dev *rc, + unsigned long id) +{ + struct reset_gpio_priv *priv = rc_to_reset_gpio(rc); + + gpiod_set_value_cansleep(priv->reset, 0); + + return 0; +} + +static int reset_gpio_status(struct reset_controller_dev *rc, unsigned long id) +{ + struct reset_gpio_priv *priv = rc_to_reset_gpio(rc); + + return gpiod_get_value_cansleep(priv->reset); +} + +static const struct reset_control_ops reset_gpio_ops = { + .assert = reset_gpio_assert, + .deassert = reset_gpio_deassert, + .status = reset_gpio_status, +}; + +static int reset_gpio_of_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + return reset_spec->args[0]; +} + +static void reset_gpio_of_node_put(void *data) +{ + of_node_put(data); +} + +static int reset_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct of_phandle_args *platdata = dev_get_platdata(dev); + struct reset_gpio_priv *priv; + int ret; + + if (!platdata) + return -EINVAL; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, &priv->rc); + + priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(priv->reset)) + return dev_err_probe(dev, PTR_ERR(priv->reset), + "Could not get reset gpios\n"); + + priv->rc.ops = &reset_gpio_ops; + priv->rc.owner = THIS_MODULE; + priv->rc.dev = dev; + priv->rc.of_args = platdata; + ret = devm_add_action_or_reset(dev, reset_gpio_of_node_put, + priv->rc.of_node); + if (ret) + return ret; + + /* Cells to match GPIO specifier, but it's not really used */ + priv->rc.of_reset_n_cells = 2; + priv->rc.of_xlate = reset_gpio_of_xlate; + priv->rc.nr_resets = 1; + + return devm_reset_controller_register(dev, &priv->rc); +} + +static const struct platform_device_id reset_gpio_ids[] = { + { .name = "reset-gpio", }, + {} +}; +MODULE_DEVICE_TABLE(platform, reset_gpio_ids); + +static struct platform_driver reset_gpio_driver = { + .probe = reset_gpio_probe, + .id_table = reset_gpio_ids, + .driver = { + .name = "reset-gpio", + }, +}; +module_platform_driver(reset_gpio_driver); + +MODULE_AUTHOR("Krzysztof Kozlowski "); +MODULE_DESCRIPTION("Generic GPIO reset driver"); +MODULE_LICENSE("GPL"); From patchwork Mon Jan 29 11:52:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 767503 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 alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (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 31480C47DA9 for ; Mon, 29 Jan 2024 11:54:39 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 98957827; Mon, 29 Jan 2024 12:54:27 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 98957827 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1706529277; bh=RDKdQXX40OiNl7/3DjOh16dFowMeZxhASXBGszdgn6Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=btQg3jRHrprBQlpU6P5OPt/pIqun/ZY5uCcMLbT5qQBfKypIf5FdhYSQIEe/bUVp+ SFOw/+/Zsxfoo3LtX4dYLzJdyptyolpDtHw+P/TdAZ0JcAmclAaIun/fS0fBLwzDED 8iThmKADLfmklcPtMxLjhpnu6R2pDft3BUyGuJYM= Received: by alsa1.perex.cz (Postfix, from userid 50401) id B5FF2F8065D; Mon, 29 Jan 2024 12:53:02 +0100 (CET) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 2273BF8067C; Mon, 29 Jan 2024 12:53:02 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id D9E5CF805F1; Mon, 29 Jan 2024 12:52:50 +0100 (CET) Received: from mail-lj1-x22a.google.com (mail-lj1-x22a.google.com [IPv6:2a00:1450:4864:20::22a]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id AF767F80310 for ; Mon, 29 Jan 2024 12:52:30 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz AF767F80310 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key, unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=du0Wt+ZF Received: by mail-lj1-x22a.google.com with SMTP id 38308e7fff4ca-2cf3ed3b917so27960741fa.1 for ; Mon, 29 Jan 2024 03:52:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1706529149; x=1707133949; darn=alsa-project.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=1TBfXvR6pIfyFCcQcCo2FCNn/31lFzDY7nyc0/6S74g=; b=du0Wt+ZFLR5YEgjRTZE5C6D21wFSL8y9V6+ua1ERbY0Za1PrbpDVUzBWLhes/oXqHU LQ9L/1ISewJrMh2BSy6Jt3aJkD4zaZRAgEDMsmEu092/CcHVxphlQBSBwhI8878dleWF HFa2Mz5yKQo5v4iiFK/5hVjhhWjalF174HmHJE3+n9CQkIbB5TfF+7FGk8bloN7W47my osA7Dqw55Y0sCvO57mxycEPsC01JD0fXmeR6TU0966wP0VlsjPFCUdDSkyUIkluUeCJW AEDPrEXF5r3EygzCuQHB1m4uSgVoNkkLAYDNLgzRGUtgvKc5v/XuQjh2UHV6DVbwGq0l Laiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706529149; x=1707133949; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=1TBfXvR6pIfyFCcQcCo2FCNn/31lFzDY7nyc0/6S74g=; b=ptDkYrQbJoBEJmdZu+ntBLd5UrjmFxFnWuPAxwcNe4mlPsVRwu4qjLkSYdlQN8hARq 9CvOxNci9TwgTeK6WZyYUSnAX8pmRLXMPPTyaqYpS+ct69O7v3KomGZDmf3UpObepr8m qgz4/G1h6Ja5TQU0sU5dD9nHiQW8O7CSnPh9qZLQLry0+upfXGXq+PX+hE2uGnNPj/qR OewC2oo/Musi2HYoVdvSnFd5N/5HbH28CZogY4GO9R8DclTh2I8+DfC9OOR9/8vNoP9p dWnLnoVDtJ6J9XGc2GerNKPJYMOJxAx74zf7MncMK2ZFBKU5U4MZkIyJiIl0y6XYgO9L eDwg== X-Gm-Message-State: AOJu0YzyDmJ4Jzu9M3Dl553r3s0jvK0NPi2HyvkdFk2Q+hyYqz5G/TWL guiyGKdIuwrHKuJsWZuPs9JhZU3ZmQvfd65+bgpgGMW0wfDo92HVxo8+m2RNP9w= X-Google-Smtp-Source: AGHT+IEOGZ6MfF3HmlXB4x4R5GOlcW0mTpY+bx5fMK/MIU4Sr7wowYDUrzOBo9Az3e9nhPMxZs/twQ== X-Received: by 2002:a2e:a796:0:b0:2cd:ef2c:b43e with SMTP id c22-20020a2ea796000000b002cdef2cb43emr4500136ljf.2.1706529149616; Mon, 29 Jan 2024 03:52:29 -0800 (PST) Received: from krzk-bin.. ([178.197.222.62]) by smtp.gmail.com with ESMTPSA id ec19-20020a0564020d5300b0055f29ececeasm19907edb.57.2024.01.29.03.52.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 03:52:29 -0800 (PST) From: Krzysztof Kozlowski To: Srinivas Kandagatla , Banajit Goswami , Bjorn Andersson , Konrad Dybcio , Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , "Rafael J. Wysocki" , Viresh Kumar , Frank Rowand , Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-arm-msm@vger.kernel.org, linux-sound@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org Cc: Krzysztof Kozlowski , Bartosz Golaszewski , Chris Packham , Sean Anderson Subject: [PATCH v6 4/6] reset: Instantiate reset GPIO controller for shared reset-gpios Date: Mon, 29 Jan 2024 12:52:14 +0100 Message-Id: <20240129115216.96479-5-krzysztof.kozlowski@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240129115216.96479-1-krzysztof.kozlowski@linaro.org> References: <20240129115216.96479-1-krzysztof.kozlowski@linaro.org> MIME-Version: 1.0 Message-ID-Hash: O3WR6XNW2DR5NQPHLOZXEQRMBGNQ6P6V X-Message-ID-Hash: O3WR6XNW2DR5NQPHLOZXEQRMBGNQ6P6V X-MailFrom: krzysztof.kozlowski@linaro.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.9 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Devices sharing a reset GPIO could use the reset framework for coordinated handling of that shared GPIO line. We have several cases of such needs, at least for Devicetree-based platforms. If Devicetree-based device requests a reset line, while "resets" Devicetree property is missing but there is a "reset-gpios" one, instantiate a new "reset-gpio" platform device which will handle such reset line. This allows seamless handling of such shared reset-gpios without need of changing Devicetree binding [1]. To avoid creating multiple "reset-gpio" platform devices, store the Devicetree "reset-gpios" GPIO specifiers used for new devices on a linked list. Later such Devicetree GPIO specifier (phandle to GPIO controller, GPIO number and GPIO flags) is used to check if reset controller for given GPIO was already registered. If two devices have conflicting "reset-gpios" property, e.g. with different ACTIVE_xxx flags, this would allow to spawn two separate "reset-gpio" devices, where the second would fail probing on busy GPIO request. Link: https://lore.kernel.org/all/YXi5CUCEi7YmNxXM@robh.at.kernel.org/ [1] Cc: Bartosz Golaszewski Cc: Chris Packham Cc: Sean Anderson Reviewed-by: Philipp Zabel Signed-off-by: Krzysztof Kozlowski Acked-by: Bartosz Golaszewski --- Depends on: 1. Previous OF change. 2. !GPIOLIB stub: https://lore.kernel.org/all/20240125081601.118051-3-krzysztof.kozlowski@linaro.org/ --- drivers/reset/core.c | 224 +++++++++++++++++++++++++++++-- include/linux/reset-controller.h | 4 + 2 files changed, 215 insertions(+), 13 deletions(-) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 4d5a78d3c085..dba74e857be6 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -5,14 +5,19 @@ * Copyright 2013 Philipp Zabel, Pengutronix */ #include +#include #include #include #include #include #include +#include +#include +#include #include #include #include +#include #include #include #include @@ -23,6 +28,11 @@ static LIST_HEAD(reset_controller_list); static DEFINE_MUTEX(reset_lookup_mutex); static LIST_HEAD(reset_lookup_list); +/* Protects reset_gpio_lookup_list */ +static DEFINE_MUTEX(reset_gpio_lookup_mutex); +static LIST_HEAD(reset_gpio_lookup_list); +static DEFINE_IDA(reset_gpio_ida); + /** * struct reset_control - a reset control * @rcdev: a pointer to the reset controller device @@ -63,6 +73,16 @@ struct reset_control_array { struct reset_control *rstc[] __counted_by(num_rstcs); }; +/** + * struct reset_gpio_lookup - lookup key for ad-hoc created reset-gpio devices + * @of_args: phandle to the reset controller with all the args like GPIO number + * @list: list entry for the reset_gpio_lookup_list + */ +struct reset_gpio_lookup { + struct of_phandle_args of_args; + struct list_head list; +}; + static const char *rcdev_name(struct reset_controller_dev *rcdev) { if (rcdev->dev) @@ -71,6 +91,9 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev) if (rcdev->of_node) return rcdev->of_node->full_name; + if (rcdev->of_args) + return rcdev->of_args->np->full_name; + return NULL; } @@ -99,6 +122,9 @@ static int of_reset_simple_xlate(struct reset_controller_dev *rcdev, */ int reset_controller_register(struct reset_controller_dev *rcdev) { + if (rcdev->of_node && rcdev->of_args) + return -EINVAL; + if (!rcdev->of_xlate) { rcdev->of_reset_n_cells = 1; rcdev->of_xlate = of_reset_simple_xlate; @@ -813,12 +839,171 @@ static void __reset_control_put_internal(struct reset_control *rstc) kref_put(&rstc->refcnt, __reset_control_release); } +static int __reset_add_reset_gpio_lookup(int id, struct device_node *np, + unsigned int gpio, + unsigned int of_flags) +{ + const struct fwnode_handle *fwnode = of_fwnode_handle(np); + unsigned int lookup_flags; + const char *label_tmp; + + /* + * Later we map GPIO flags between OF and Linux, however not all + * constants from include/dt-bindings/gpio/gpio.h and + * include/linux/gpio/machine.h match each other. + */ + if (of_flags > GPIO_ACTIVE_LOW) { + pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n", + of_flags, gpio); + return -EINVAL; + } + + struct gpio_device *gdev __free(gpio_device_put) = gpio_device_find_by_fwnode(fwnode); + if (!gdev) + return -EPROBE_DEFER; + + label_tmp = gpio_device_get_label(gdev); + if (!label_tmp) + return -EINVAL; + + char *label __free(kfree) = kstrdup(label_tmp, GFP_KERNEL); + if (!label) + return -ENOMEM; + + /* Size: one lookup entry plus sentinel */ + struct gpiod_lookup_table *lookup __free(kfree) = kzalloc(struct_size(lookup, table, 2), + GFP_KERNEL); + if (!lookup) + return -ENOMEM; + + lookup->dev_id = kasprintf(GFP_KERNEL, "reset-gpio.%d", id); + if (!lookup->dev_id) + return -ENOMEM; + + lookup_flags = GPIO_PERSISTENT; + lookup_flags |= of_flags & GPIO_ACTIVE_LOW; + lookup->table[0] = GPIO_LOOKUP(no_free_ptr(label), gpio, "reset", + lookup_flags); + + /* Not freed on success, because it is persisent subsystem data. */ + gpiod_add_lookup_table(no_free_ptr(lookup)); + + return 0; +} + +/* + * @args: phandle to the GPIO provider with all the args like GPIO number + */ +static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) +{ + struct reset_gpio_lookup *rgpio_dev; + struct platform_device *pdev; + int id, ret; + + /* + * Currently only #gpio-cells=2 is supported with the meaning of: + * args[0]: GPIO number + * args[1]: GPIO flags + * TODO: Handle other cases. + */ + if (args->args_count != 2) + return -ENOENT; + + /* + * Registering reset-gpio device might cause immediate + * bind, resulting in its probe() registering new reset controller thus + * taking reset_list_mutex lock via reset_controller_register(). + */ + lockdep_assert_not_held(&reset_list_mutex); + + mutex_lock(&reset_gpio_lookup_mutex); + + list_for_each_entry(rgpio_dev, &reset_gpio_lookup_list, list) { + if (args->np == rgpio_dev->of_args.np) { + if (of_phandle_args_equal(args, &rgpio_dev->of_args)) + goto out; /* Already on the list, done */ + } + } + + id = ida_alloc(&reset_gpio_ida, GFP_KERNEL); + if (id < 0) { + ret = id; + goto err_unlock; + } + + /* Not freed on success, because it is persisent subsystem data. */ + rgpio_dev = kzalloc(sizeof(*rgpio_dev), GFP_KERNEL); + if (!rgpio_dev) { + ret = -ENOMEM; + goto err_ida_free; + } + + ret = __reset_add_reset_gpio_lookup(id, args->np, args->args[0], + args->args[1]); + if (ret < 0) + goto err_kfree; + + rgpio_dev->of_args = *args; + /* + * We keep the device_node reference, but of_args.np is put at the end + * of __of_reset_control_get(), so get it one more time. + * Hold reference as long as rgpio_dev memory is valid. + */ + of_node_get(rgpio_dev->of_args.np); + pdev = platform_device_register_data(NULL, "reset-gpio", id, + &rgpio_dev->of_args, + sizeof(rgpio_dev->of_args)); + ret = PTR_ERR_OR_ZERO(pdev); + if (ret) + goto err_put; + + list_add(&rgpio_dev->list, &reset_gpio_lookup_list); + +out: + mutex_unlock(&reset_gpio_lookup_mutex); + + return 0; + +err_put: + of_node_put(rgpio_dev->of_args.np); +err_kfree: + kfree(rgpio_dev); +err_ida_free: + ida_free(&reset_gpio_ida, id); +err_unlock: + mutex_unlock(&reset_gpio_lookup_mutex); + + return ret; +} + +static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_args *args, + bool gpio_fallback) +{ + struct reset_controller_dev *rcdev; + + lockdep_assert_held(&reset_list_mutex); + + list_for_each_entry(rcdev, &reset_controller_list, list) { + if (gpio_fallback) { + if (rcdev->of_args && of_phandle_args_equal(args, + rcdev->of_args)) + return rcdev; + } else { + if (args->np == rcdev->of_node) + return rcdev; + } + } + + return NULL; +} + struct reset_control * __of_reset_control_get(struct device_node *node, const char *id, int index, bool shared, bool optional, bool acquired) { + bool gpio_fallback = false; struct reset_control *rstc; - struct reset_controller_dev *r, *rcdev; + struct reset_controller_dev *rcdev; struct of_phandle_args args; int rstc_id; int ret; @@ -839,39 +1024,52 @@ __of_reset_control_get(struct device_node *node, const char *id, int index, index, &args); if (ret == -EINVAL) return ERR_PTR(ret); - if (ret) - return optional ? NULL : ERR_PTR(ret); + if (ret) { + if (!IS_ENABLED(CONFIG_RESET_GPIO)) + return optional ? NULL : ERR_PTR(ret); - mutex_lock(&reset_list_mutex); - rcdev = NULL; - list_for_each_entry(r, &reset_controller_list, list) { - if (args.np == r->of_node) { - rcdev = r; - break; + /* + * There can be only one reset-gpio for regular devices, so + * don't bother with the "reset-gpios" phandle index. + */ + ret = of_parse_phandle_with_args(node, "reset-gpios", "#gpio-cells", + 0, &args); + if (ret) + return optional ? NULL : ERR_PTR(ret); + + gpio_fallback = true; + + ret = __reset_add_reset_gpio_device(&args); + if (ret) { + rstc = ERR_PTR(ret); + goto out_put; } } + mutex_lock(&reset_list_mutex); + rcdev = __reset_find_rcdev(&args, gpio_fallback); if (!rcdev) { rstc = ERR_PTR(-EPROBE_DEFER); - goto out; + goto out_unlock; } if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) { rstc = ERR_PTR(-EINVAL); - goto out; + goto out_unlock; } rstc_id = rcdev->of_xlate(rcdev, &args); if (rstc_id < 0) { rstc = ERR_PTR(rstc_id); - goto out; + goto out_unlock; } /* reset_list_mutex also protects the rcdev's reset_control list */ rstc = __reset_control_get_internal(rcdev, rstc_id, shared, acquired); -out: +out_unlock: mutex_unlock(&reset_list_mutex); +out_put: of_node_put(args.np); return rstc; diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h index 0fa4f60e1186..357df16ede32 100644 --- a/include/linux/reset-controller.h +++ b/include/linux/reset-controller.h @@ -60,6 +60,9 @@ struct reset_control_lookup { * @reset_control_head: head of internal list of requested reset controls * @dev: corresponding driver model device struct * @of_node: corresponding device tree node as phandle target + * @of_args: for reset-gpios controllers: corresponding phandle args with + * of_node and GPIO number complementing of_node; either this or + * of_node should be present * @of_reset_n_cells: number of cells in reset line specifiers * @of_xlate: translation function to translate from specifier as found in the * device tree to id as given to the reset control ops, defaults @@ -73,6 +76,7 @@ struct reset_controller_dev { struct list_head reset_control_head; struct device *dev; struct device_node *of_node; + const struct of_phandle_args *of_args; int of_reset_n_cells; int (*of_xlate)(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec);