From patchwork Sat Jun 14 14:35:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896302 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CACD81FC8; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911830; cv=none; b=JzhayILQwIMAYqB/tTXntoUO8rJJVMYIFhu6KcnJJVvN5+bXNGWjfDhMORhYN9uk0CLPSrZ5Y6J3EFXWU6kQauBAheyBs8+JLYI6rpbAJ7OjxAPkj1nu1r++WZFQ1fAiWqniBvwPU6j1IokBnHaDy2zM9BXulkVWWy6jAQ5yPug= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911830; c=relaxed/simple; bh=qXfPxK8iv4HT71BwVc8bhCncHX7rV2HtucsltCoXbLw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bxEuUdlIDY3LXLMuedZ0D9Ox/oSqq7zyTfjYW55/8kHSF0o1FZfCJn0EiWi9MOlO8DInsFsRrPb2hkz9QLOE+elVaHWMdYtoLhUnm1E8pSp+vav0MEQrFIsk8XNC6JTC3RPbdQhNlotjyV5wrE2tTQgXwQgPCjo+OOQ1RtEFVQI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=scTZlIPj; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="scTZlIPj" Received: by smtp.kernel.org (Postfix) with ESMTPS id 52DD2C4CEEE; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911830; bh=qXfPxK8iv4HT71BwVc8bhCncHX7rV2HtucsltCoXbLw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=scTZlIPjIL6mjGzkwJTLIK/ALWMjRU+4mMH5dITludibpwHJyHnjA31bZSwSnpni/ dwZwjsaPKyivW+7O+gsTSr+CVWibLps27Y7PuvXNbh7FFJS5vE99s6tD0dojo92/1G a6F7R+Cck1MejzI1IY1EPKpEfhbeRvLT5m1oaOh2INOthcKiqMwl4U58jC/+T0GVDR v8yjUCzsT4L3sqmt5BPr2sh6bQhG7MEeTuRo7KgbKKbVSakejDmaShsPItrPxNEZ0h ymRTx8BpD4+hASf1Eynojhua1CPFGRi/cfIPDeZ1Pd/1avHiylxKz8XMEy1Lqqtl1B qwqjzY5hiQSpA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 42820C71150; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:35:52 +0100 Subject: [PATCH v5 01/20] dt-bindings: mfd: adp5585: ease on the required properties Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-1-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=1054; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=HMDwWGXqEZmH5tU21NJ2ISWhkpP+9+F+CVII73zXj8U=; b=37JW1MYQFq6kxw5XjaQswGtoV+USbqu2VBX8fgxpE7QNTkw9SCU9gwqgmHIVymorPyHOGBPJM 0ms+K3XHtsEAjodEA2zmBHl4NutMOKn9KKm+eYqZKezH7pNAdGg+cHl X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá It is not mandatory to use all the capabilities of the device. One can very well only use it as a gpio controller without the PWM support. This will be even more evident when support for the matrix keymap is added. Hence drop the requirements for PWM and GPIO. Acked-by: Rob Herring (Arm) Reviewed-by: Laurent Pinchart Signed-off-by: Nuno Sá --- Documentation/devicetree/bindings/mfd/adi,adp5585.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml b/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml index ee2272f754a339569c793102928ddd13249f8fee..e30e22f964f78519b2ec207e9415e4897db5c702 100644 --- a/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml +++ b/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml @@ -52,9 +52,6 @@ patternProperties: required: - compatible - reg - - gpio-controller - - "#gpio-cells" - - "#pwm-cells" allOf: - if: From patchwork Sat Jun 14 14:35:53 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896301 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CADC62DECB0; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911830; cv=none; b=SMSp2m73eGoXIhg4IuCskvic/ppLTd7J8fv3cAEwMqoPg8rNN2g4T4k5Wh4CxKLnbp8oztNr49QvFFxd1+p5c+NG0QhTrpHvDk+IaStbUkgLiBlmqnlHO6gMEfZ/AloK1wwV6T96nG8GWlYZuu0Lgc5cnxsZz9A38Z2Owh7lBHc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911830; c=relaxed/simple; bh=/w8MsGHq9ZZ76nNqYzSb+A1zmWAxOxL03WPwNi1zBss=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=b5Rp77/OGtisCvk+OFN5EUwyE5MDBIOLkYbcYfgUwh9W8XdGwTwenU3I9FNwAcKi48BGahKOJfWGKnkDpsgQugMex+g5oIGb9BHPyuSj0ZyWUDBoKRRTpeCibqi+jRmLG/LZCH6f+VsQrlb6HsWnP4FRlG9iY17m7d4oa6HrZ0o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=apZ1d3CB; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="apZ1d3CB" Received: by smtp.kernel.org (Postfix) with ESMTPS id 60795C4CEF0; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911830; bh=/w8MsGHq9ZZ76nNqYzSb+A1zmWAxOxL03WPwNi1zBss=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=apZ1d3CBoJffVSPLAImowqp4dHFzVRvWlrLiBPA/0XXZAjzgGNEHl1p2edi5YRt9b DUGdHu02Wg/fxTKUjjxq0mFx9RmfFvA6F01VQol0vKtLNFKSNDt9xdWgkCFStLMshj hdUkTr8y71erUc1OqAETXxnVLh0PNEhcp398ZIUy+++DFfTilSueRnoGhaOQRo3zpF oQC/rlQ5QSpzToP04COivDG7TeK45UhUqzpmOVIKhOhabD1unrXtryuUoqmQfVG1Sb em2s+zXlG3AOJud5vselBLbubMBxvn16xMVqH/8gBq8lU6+lBNk/d/mIW9NIn42LtJ u3vrfebSPR7hg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50D71C71135; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:35:53 +0100 Subject: [PATCH v5 02/20] mfd: adp5585: only add devices given in FW Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-2-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=2284; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=vmniaSLpbgWkvwxYbHERkkcnOZlR873SC8mAfAx5A0s=; b=LxaH66/QxjUlRnWX+/Xgfj3sJUTmP7VP/JbSclQw4zgE3KsUBl8eMhgsnQ4WIflI1WK0NDymG hM4zHomuPyNA+QlB64ves30J2QiGWFiE1ebukVzdHglWlQSDsP2TUlr X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá Not all devices (features) of the adp5585 device are mandatory to be used in all platforms. Hence, check what's given in FW and dynamically create the mfd_cell array to be given to devm_mfd_add_devices(). Signed-off-by: Nuno Sá --- drivers/mfd/adp5585.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c index 160e0b38106a6d78f7d4b7c866cb603d96ea673e..53a46734f2d022ec54b3efc2ebbf389357f8d85a 100644 --- a/drivers/mfd/adp5585.c +++ b/drivers/mfd/adp5585.c @@ -17,7 +17,13 @@ #include #include -static const struct mfd_cell adp5585_devs[] = { +enum { + ADP5585_DEV_GPIO, + ADP5585_DEV_PWM, + ADP5585_DEV_MAX +}; + +static const struct mfd_cell adp5585_devs[ADP5585_DEV_MAX] = { { .name = "adp5585-gpio", }, { .name = "adp5585-pwm", }, }; @@ -110,6 +116,27 @@ static const struct regmap_config adp5585_regmap_configs[] = { }, }; +static int adp5585_add_devices(struct device *dev) +{ + int ret; + + if (device_property_present(dev, "#pwm-cells")) { + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, + &adp5585_devs[ADP5585_DEV_PWM], 1, NULL, 0, NULL); + if (ret) + return dev_err_probe(dev, ret, "Failed to add PWM device\n"); + } + + if (device_property_present(dev, "#gpio-cells")) { + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, + &adp5585_devs[ADP5585_DEV_GPIO], 1, NULL, 0, NULL); + if (ret) + return dev_err_probe(dev, ret, "Failed to add GPIO device\n"); + } + + return 0; +} + static int adp5585_i2c_probe(struct i2c_client *i2c) { const struct regmap_config *regmap_config; @@ -138,14 +165,7 @@ static int adp5585_i2c_probe(struct i2c_client *i2c) return dev_err_probe(&i2c->dev, -ENODEV, "Invalid device ID 0x%02x\n", id); - ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, - adp5585_devs, ARRAY_SIZE(adp5585_devs), - NULL, 0, NULL); - if (ret) - return dev_err_probe(&i2c->dev, ret, - "Failed to add child devices\n"); - - return 0; + return adp5585_add_devices(&i2c->dev); } static int adp5585_suspend(struct device *dev) From patchwork Sat Jun 14 14:35:56 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896300 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0D9D32E173E; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; cv=none; b=OdWS+qLdDINAdmIYYCRfyNsDFDCTFFOBtA5/+2UonECl5rnAycmVGXA7yys3qEtczUFzVKbpbBK2f3TGTQfedcbtJmUSZeZ+iE8ciLXk+u2pTOv+S2onOFFIB6HaGG2iLb0VTF+XuUylBV7xbJJ7/Zk8F7dr+tkSWJr45Psj2+w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; c=relaxed/simple; bh=OJ6TowkARp/Doi6+qnVBRc8J1B7tkneZYbYsIN03Ohw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kHBAkJEhx4TnWOIF4BJRxdpUjwKrPmcW7tdKZwk+XaEdXnHNaIy/hqpQVIjLEnjJteT4a9zNow8IzE4GnuExTXpszH4dX02QO3GpoQtz3yEwtZRQ1Z/mFef0lEeEWmPQ9d3sFu9nq4JqxEji3JXqIDKi/JvJ8Mu5WTO9NIEnT2c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OOIS0Q4C; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OOIS0Q4C" Received: by smtp.kernel.org (Postfix) with ESMTPS id 85F57C4AF10; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911830; bh=OJ6TowkARp/Doi6+qnVBRc8J1B7tkneZYbYsIN03Ohw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=OOIS0Q4CWX1RTXYRhOA8FpS3z2RMuE87Yyk9ViOUen6I6q6NJNA9AtMCIe/nNSOPu aDJHNFPqRrpMRK/OepMEbHln1ZpOT48VHQmZ+pbUQvke+2Tsy8fiufQGEKIyYPLqJQ SXUGaIoLfGjHNEUZHznB+oZLgBMeZNoJA48cqZty91TcDYUc++fFYA668MOD0J+iDM 4H1X1G9Im2M+YeCJH8vrbxUnXovfVpSbmdvH3indMAIB3sZ5GOQEX21mVtdqqs9ARg JvSQgy6uw4pDDRw8G+P61Al8j4Yr0ViOm6I48rVIO08aOXXvDHCngKPWtc328diBhJ OhtdMqoP+jXTQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7A2C9C71159; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:35:56 +0100 Subject: [PATCH v5 05/20] dt-bindings: mfd: adp5585: document adp5589 I/O expander Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-5-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=3683; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=beLTP9GDditX9ha6QitAuUXi6px8/CxhIbNd+KVg+k4=; b=yBAsWNaPzXJZWIGr7c/x8rqLZ5i/sL6MJE7GMWMMjU4Pr3tiJDcTHisY0jC6eRmnyFigpx6Ay W8WSaBLrDckAlIoNZjLk7L+x7lGb2eG9cN4t5StZFD9OK+V/mp/K/SD X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá The ADP5589 is a 19 I/O port expander with built-in keypad matrix decoder, programmable logic, reset generator, and PWM generator. We can't really have adp5589 devices fallback to adp5585 (which have less pins) because there are some significant differences in the register map. Reviewed-by: Rob Herring (Arm) Reviewed-by: Laurent Pinchart Signed-off-by: Nuno Sá --- .../devicetree/bindings/mfd/adi,adp5585.yaml | 47 +++++++++++++++++----- .../devicetree/bindings/trivial-devices.yaml | 2 - 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml b/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml index e30e22f964f78519b2ec207e9415e4897db5c702..9471af28419d820424745315ffb2129f7dd37581 100644 --- a/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml +++ b/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml @@ -15,14 +15,21 @@ description: properties: compatible: - items: - - enum: - - adi,adp5585-00 # Default - - adi,adp5585-01 # 11 GPIOs - - adi,adp5585-02 # No pull-up resistors by default on special pins - - adi,adp5585-03 # Alternate I2C address - - adi,adp5585-04 # Pull-down resistors on all pins by default - - const: adi,adp5585 + oneOf: + - items: + - enum: + - adi,adp5585-00 # Default + - adi,adp5585-01 # 11 GPIOs + - adi,adp5585-02 # No pull-up resistors by default on special pins + - adi,adp5585-03 # Alternate I2C address + - adi,adp5585-04 # Pull-down resistors on all pins by default + - const: adi,adp5585 + - items: + - enum: + - adi,adp5589-00 # Default + - adi,adp5589-01 # R4 defaulted to RESET1 output + - adi,adp5589-02 # Pull-down resistors by default on special pins + - const: adi,adp5589 reg: maxItems: 1 @@ -62,7 +69,17 @@ allOf: then: properties: gpio-reserved-ranges: false - else: + + - if: + properties: + compatible: + contains: + enum: + - adi,adp5585-00 + - adi,adp5585-02 + - adi,adp5585-03 + - adi,adp5585-04 + then: properties: gpio-reserved-ranges: maxItems: 1 @@ -71,6 +88,18 @@ allOf: - const: 5 - const: 1 + - if: + properties: + compatible: + contains: + enum: + - adi,adp5589-00 + - adi,adp5589-01 + - adi,adp5589-02 + then: + properties: + gpio-reserved-ranges: false + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 8da408107e55483affedb7e697eb79e8c8902ed9..208fe4242672d9da66799c2742a9381938737232 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -39,8 +39,6 @@ properties: - ad,adm9240 # AD5110 - Nonvolatile Digital Potentiometer - adi,ad5110 - # Analog Devices ADP5589 Keypad Decoder and I/O Expansion - - adi,adp5589 # Analog Devices LT7182S Dual Channel 6A, 20V PolyPhase Step-Down Silent Switcher - adi,lt7182s # AMS iAQ-Core VOC Sensor From patchwork Sat Jun 14 14:35:57 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896294 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8F0CE2E6D12; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; cv=none; b=kWsxryS8jMlZz0q/hCdHE9tE3k6PJhJj7cA7hcAow2mGbVIDy1xY5z87tRxXEeVIH8FAnhmrCYO/wyb0Ka8qzwV338eLNguAc/ZFI2CTORZ9Zh24g1TkRQ4TbfYtI1xjgw8+2MVI4HIhYcbsxkrHYjE76F0BlcB3bYpwXLVMOl4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; c=relaxed/simple; bh=cQZ7k71aUPmDY9FsdbbHgCTTiVJfFn9UvIU02hSTNAA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ko6C7NM2DojPLe4mFSkRBvfNYB4QDC92AGZ188mHOO+iq2NWQ0rBAvtwkmsBY7VOwy0shwg6jIeqnA44wV0B0+9F+m1/HdKfnBI9lpntRNA49zRgVUaqJqEudi4kKm6AVM/viAzjSlGxsnCmAqn4hrLq2CRliFaCzqs1hSYcJMs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bcIMWwMk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bcIMWwMk" Received: by smtp.kernel.org (Postfix) with ESMTPS id 95C41C4CEFC; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911830; bh=cQZ7k71aUPmDY9FsdbbHgCTTiVJfFn9UvIU02hSTNAA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=bcIMWwMkeqFyR0jT/3QkH4lVtWnqGHekeLYZvpG4kCzn2LlArRstXckOdkv5g0pjr Rc7Jb3pM9lQInXMKyW/MLVXA7c3QA9sseYfwBOkQ/t2I5e6/qrteEAediZbNf7vv/J PrkwBwkAORQW/h/pDU9Go+KRJZ2B1BNeVoBCxN/8aQM3MhLHSIMpR9qI1MgN54om+a gOda45FIXV9a/AKnHvndbXOqhl3NPbprTdHswLeypp/lHtL1Dv69jHsBbBLz9B6X4U 5Rfo4QoRTN1wLGhv/AyJ7ZGvGpr86u5eR1QbRZcoRCu1NBNnSMmym7GH/uAfydc/Mk k4k/6Kq/dzDdQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 880D3C71155; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:35:57 +0100 Subject: [PATCH v5 06/20] mfd: adp5585: refactor how regmap defaults are handled Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-6-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=5868; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=gxnnVDkz/yZuJfqUtXTtbS+LQlmNApR5Mbl7FSkcAHw=; b=dX7hEO7bWJ1N3Qq9v+a0F3TfGAN7S/gKV1rBt/kmA96kMOsvpEU45A2LMNYGQw3zsBE5U9hgx JL0MqiWuyWJAILSHgSxOuNE7CoHiQJyTOpR8x1Xz3vaqqR5n4VSbQ3D X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá The only thing changing between variants is the regmap default registers. Hence, instead of having a regmap configuration for every variant (duplicating lots of fields), add a chip info type of structure with a regmap ID to identify which defaults to use and populate regmap_config at runtime given a template plus the id. Also note that between variants, the defaults can be the same which means the chip info structure can be used in more than one compatible. This will also make it simpler adding new chips with more variants. Also note that the chip info structures are deliberately not const as they will also contain lots of members that are the same between the different devices variants and so we will fill those at runtime. Signed-off-by: Nuno Sá --- drivers/mfd/adp5585.c | 81 +++++++++++++++++++++++---------------------- include/linux/mfd/adp5585.h | 11 ++++++ 2 files changed, 53 insertions(+), 39 deletions(-) diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c index c764f481875831ff55bccb8cdc59421719afbedd..ec88adbace92791f10953fc2bbb463fc59557bd6 100644 --- a/drivers/mfd/adp5585.c +++ b/drivers/mfd/adp5585.c @@ -81,42 +81,37 @@ static const u8 adp5585_regmap_defaults_04[ADP5585_MAX_REG + 1] = { /* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, }; -enum adp5585_regmap_type { - ADP5585_REGMAP_00, - ADP5585_REGMAP_02, - ADP5585_REGMAP_04, +/* -1 since the enum starts at 1 for error checking in i2c_get_match_data() */ +static const u8 *adp5585_regmap_defaults[ADP5585_MAX] = { + [ADP5585_00] = adp5585_regmap_defaults_00, + [ADP5585_01] = adp5585_regmap_defaults_00, + [ADP5585_02] = adp5585_regmap_defaults_02, + [ADP5585_03] = adp5585_regmap_defaults_00, + [ADP5585_04] = adp5585_regmap_defaults_04, }; -static const struct regmap_config adp5585_regmap_configs[] = { - [ADP5585_REGMAP_00] = { - .reg_bits = 8, - .val_bits = 8, - .max_register = ADP5585_MAX_REG, - .volatile_table = &adp5585_volatile_regs, - .cache_type = REGCACHE_MAPLE, - .reg_defaults_raw = adp5585_regmap_defaults_00, - .num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_00), - }, - [ADP5585_REGMAP_02] = { - .reg_bits = 8, - .val_bits = 8, - .max_register = ADP5585_MAX_REG, - .volatile_table = &adp5585_volatile_regs, - .cache_type = REGCACHE_MAPLE, - .reg_defaults_raw = adp5585_regmap_defaults_02, - .num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_02), - }, - [ADP5585_REGMAP_04] = { - .reg_bits = 8, - .val_bits = 8, - .max_register = ADP5585_MAX_REG, - .volatile_table = &adp5585_volatile_regs, - .cache_type = REGCACHE_MAPLE, - .reg_defaults_raw = adp5585_regmap_defaults_04, - .num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_04), - }, +static const struct regmap_config adp5585_regmap_config_template = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ADP5585_MAX_REG, + .volatile_table = &adp5585_volatile_regs, + .cache_type = REGCACHE_MAPLE, + .num_reg_defaults_raw = ADP5585_MAX_REG + 1, }; +static struct regmap_config *adp5585_fill_regmap_config(const struct adp5585_dev *adp5585) +{ + struct regmap_config *regmap_config; + + regmap_config = devm_kmemdup(adp5585->dev, &adp5585_regmap_config_template, + sizeof(struct regmap_config), GFP_KERNEL); + if (!regmap_config) + return ERR_PTR(-ENOMEM); + + regmap_config->reg_defaults_raw = adp5585_regmap_defaults[adp5585->variant]; + return regmap_config; +} + static int adp5585_add_devices(struct device *dev) { int ret; @@ -147,7 +142,7 @@ static void adp5585_osc_disable(void *data) static int adp5585_i2c_probe(struct i2c_client *i2c) { - const struct regmap_config *regmap_config; + struct regmap_config *regmap_config; struct adp5585_dev *adp5585; unsigned int id; int ret; @@ -157,8 +152,16 @@ static int adp5585_i2c_probe(struct i2c_client *i2c) return -ENOMEM; i2c_set_clientdata(i2c, adp5585); + adp5585->dev = &i2c->dev; + + adp5585->variant = (enum adp5585_variant)(uintptr_t)i2c_get_match_data(i2c); + if (!adp5585->variant) + return -ENODEV; + + regmap_config = adp5585_fill_regmap_config(adp5585); + if (IS_ERR(regmap_config)) + return PTR_ERR(regmap_config); - regmap_config = i2c_get_match_data(i2c); adp5585->regmap = devm_regmap_init_i2c(i2c, regmap_config); if (IS_ERR(adp5585->regmap)) return dev_err_probe(&i2c->dev, PTR_ERR(adp5585->regmap), @@ -212,19 +215,19 @@ static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume); static const struct of_device_id adp5585_of_match[] = { { .compatible = "adi,adp5585-00", - .data = &adp5585_regmap_configs[ADP5585_REGMAP_00], + .data = (void *)ADP5585_00, }, { .compatible = "adi,adp5585-01", - .data = &adp5585_regmap_configs[ADP5585_REGMAP_00], + .data = (void *)ADP5585_01, }, { .compatible = "adi,adp5585-02", - .data = &adp5585_regmap_configs[ADP5585_REGMAP_02], + .data = (void *)ADP5585_02, }, { .compatible = "adi,adp5585-03", - .data = &adp5585_regmap_configs[ADP5585_REGMAP_00], + .data = (void *)ADP5585_03, }, { .compatible = "adi,adp5585-04", - .data = &adp5585_regmap_configs[ADP5585_REGMAP_04], + .data = (void *)ADP5585_04, }, { /* sentinel */ } }; diff --git a/include/linux/mfd/adp5585.h b/include/linux/mfd/adp5585.h index 016033cd68e46757aca86d21dd37025fd354b801..c56af8d8d76c4ebc0ede1ee4769ca059de29f53c 100644 --- a/include/linux/mfd/adp5585.h +++ b/include/linux/mfd/adp5585.h @@ -119,8 +119,19 @@ struct regmap; +enum adp5585_variant { + ADP5585_00 = 1, + ADP5585_01, + ADP5585_02, + ADP5585_03, + ADP5585_04, + ADP5585_MAX +}; + struct adp5585_dev { + struct device *dev; struct regmap *regmap; + enum adp5585_variant variant; }; #endif From patchwork Sat Jun 14 14:35:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896299 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 230922E2EF1; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; cv=none; b=AlpwZLWYLe+CI+0rgV/6fXpb9M8VX7eFfoNkOe0mao482NljfzsErzXyAhY5HHyM/GmhkcD5aFuiuIsN89yQsWX0hziB0PUA9X8Ok4FokcION9MzU/9UZK/Eh2WmljZK2wpOlHnwkBnEJiP30Nr6vNClMdXOSjf27cIHo3Rjaew= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; c=relaxed/simple; bh=TM/YleoWNqfiUAnTsGayFy7VS9UJCRMbArUvgJMX7Lc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Xc+JDbHjhy0xw7YgsyAKqV6wq5NjckwAm1l4Dwqhf2s8rPbIi7nhgdELuJ00yQdXAH4kKPIANxBfxJi3G9VEmYD759e9gEhFCTt1wipbnuR/3qWR/6eyJLva3+APnhwe2QPrqr2nU/vAQvXQfmEA2O/B3Mw7iL/QqY370Qb55Wc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WXqU8tix; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WXqU8tix" Received: by smtp.kernel.org (Postfix) with ESMTPS id B0225C116C6; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911830; bh=TM/YleoWNqfiUAnTsGayFy7VS9UJCRMbArUvgJMX7Lc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=WXqU8tix/bkBPsyh+vRK6vsgUyAMP5zSyuE97Isf9XlVHlFWw8ku2rSoxV4xQjnYa oLkszP3rrhKV+2NwRFGidACAnDZzoNpPw6B+jsRPKAnDEE1e1zPWKuABtNQrdys8SY cZGIPHnsCwm4s9AKnEtzhQcATziBu81Qn0GzdXHZsfvOt3IGPeOFfis3QrviJanHQa xdOLIyMRXSGN11iwz9p2a/g8va1c1RhSgb4CrdPeMoatUSplzRbbTdr+IUeZOpow1b 6pCj99bhXYe7u/BLIZa4QPI/A1hLn+9XlCley7xu0Dq6SeyXWj/hoNP8lhhjBWilcB S5CmlvD7mHjCg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A5CA6C71157; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:35:59 +0100 Subject: [PATCH v5 08/20] mfd: adp5585: add a per chip reg struture Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-8-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=2954; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=aHv0sgc3kzGQQnUWiT+5dfj17j4+zvtulsaM8Z2ayI8=; b=pRmVlYIIRpMJvA5ajZyimDu20N0Ra9c7tG7rwvdGSv9PfttzjDZVhWGtI/NNwGELXeAzK3B5B EwItGQMaSdtCbdJ8fs3VJ77rjHat8HeQ2HC5ZN8PjgkUNRDaA1kD/zL X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá There are some differences in the register map between the devices. Hence, add a register structure per device. This will be needed in following patches. On top of that adp5585_fill_regmap_config() is renamed and reworked so that the current struct adp5585_info act as template (they indeed contain all the different data between variants) which can then be complemented depending on the device (as identified by the id register). This is done like this since a lot of the data is pretty much the same between variants of the same device. Reviewed-by: Lee Jones Signed-off-by: Nuno Sá --- drivers/mfd/adp5585.c | 10 ++++++++++ include/linux/mfd/adp5585.h | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c index 54506e5b07dc505f51d3f21cc30adc55c191fc39..95f1f7b553e651a3b24dee2e1c68a3bbaa38cced 100644 --- a/drivers/mfd/adp5585.c +++ b/drivers/mfd/adp5585.c @@ -164,6 +164,14 @@ static const struct regmap_config adp5589_regmap_config_template = { .num_reg_defaults_raw = ADP5589_MAX_REG + 1, }; +static const struct adp5585_regs adp5585_regs = { + .ext_cfg = ADP5585_PIN_CONFIG_C, +}; + +static const struct adp5585_regs adp5589_regs = { + .ext_cfg = ADP5589_PIN_CONFIG_D, +}; + static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp5585) { struct regmap_config *regmap_config; @@ -175,6 +183,7 @@ static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp case ADP5585_03: case ADP5585_04: adp5585->id = ADP5585_MAN_ID_VALUE; + adp5585->regs = &adp5585_regs; regmap_config = devm_kmemdup(adp5585->dev, &adp5585_regmap_config_template, sizeof(struct regmap_config), GFP_KERNEL); break; @@ -182,6 +191,7 @@ static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp case ADP5589_01: case ADP5589_02: adp5585->id = ADP5589_MAN_ID_VALUE; + adp5585->regs = &adp5589_regs; regmap_config = devm_kmemdup(adp5585->dev, &adp5589_regmap_config_template, sizeof(struct regmap_config), GFP_KERNEL); break; diff --git a/include/linux/mfd/adp5585.h b/include/linux/mfd/adp5585.h index 70e58122a36a7321dc95d095b806f06fa57c97c9..6ecb90a6276c0f8f2c983c62c7268505d74b6583 100644 --- a/include/linux/mfd/adp5585.h +++ b/include/linux/mfd/adp5585.h @@ -120,6 +120,7 @@ /* ADP5589 */ #define ADP5589_MAN_ID_VALUE 0x10 #define ADP5589_GPI_STATUS_C 0x18 +#define ADP5589_PIN_CONFIG_D 0x4C #define ADP5589_INT_EN 0x4e #define ADP5589_MAX_REG ADP5589_INT_EN @@ -137,9 +138,14 @@ enum adp5585_variant { ADP5585_MAX }; +struct adp5585_regs { + unsigned int ext_cfg; +}; + struct adp5585_dev { struct device *dev; struct regmap *regmap; + const struct adp5585_regs *regs; enum adp5585_variant variant; unsigned int id; }; From patchwork Sat Jun 14 14:36:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896298 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4DEA92E338B; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; cv=none; b=ubVLNriaIYreKyPf0S+aAWoz6Tl3cOSN4czxpeKm16zjwsV9YftTnNcscvitvJ8DvdC9FJm3HsfsnS/ScUTB4vo3KEB6eFE+Ea9S+AfhuusQkJTWph1mgXbfRQFFeI8JBNkyXTV7k9pbmSSvB+no5JpZUf6t3L1S0+QC5/r+hjw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; c=relaxed/simple; bh=3SKh4WCBO9Cm8sUqhTNQIzrVOL1w3mjkX4cYQrc7F1Q=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ezfXZchns26JiTRMhSXNYrRsT73322lrAU2n0IBRSQ8WlF/AFvtqhy4tDzX60WZhliE7nGrXJHChJt500hrMMr1+gOztFYnAkJCmjj+99jxjCZET1Ood9U3HEuE3QwnK1+AvCklhvx+JnTvI1Eqp/QalR7dztHbAehJcl+L/mTM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=k72T+8Cc; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="k72T+8Cc" Received: by smtp.kernel.org (Postfix) with ESMTPS id ED95EC4CEFF; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911831; bh=3SKh4WCBO9Cm8sUqhTNQIzrVOL1w3mjkX4cYQrc7F1Q=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=k72T+8CcxO7tA8NanPUQKRRX6ZXtW+hFRQznkGME/sg7vL6oym63nybpqrl9EhMgy fFptx1s4TGKUJWJLqKX3ZcNrU/HFgRXq9QKRp7ht0VeIUAuDYTC4tCGVi7ZHmOho3D vBMoUUItVdrtCOclRTHw2Ou1TcawMooZJdlElmkAeNO2PYsnvNirubuyoVRhlGQQsZ rMM1j30+SfbWNQJdxsBpICuJQJ3EZvufOVbTjICvDhIjjulYEvoMLvu77Ps2jRbmL3 QY8vNXePxcg86aLlj5J3Y3/FJbRv5Dn28PpXvwsSUeUdC9FpSDZdXkG/kXO29RpinG wUpkOUOf1rm3A== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id E22D9C71157; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:36:03 +0100 Subject: [PATCH v5 12/20] mfd: adp5585: add support for event handling Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-12-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=9516; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=Ubaf+8avI8bmJ2w5OcK5hPy5jp9aqqXZDWWT7WEQZAo=; b=AdFibkIYKL+ovnOMvaWWnvpIk0eAqNkdn7LxWcAo2esSwv3SeJAshC+A3pXEx2Yv6sMm4GzE/ T9R0PrCPNF0Arx1FXayrC1XM0uv1lATnajfCH4DjHZDAzKmEMaGAKeu X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá These devices are capable of generate FIFO based events based on KEY or GPI presses. Add support for handling these events. This is in preparation of adding full support for keymap and gpis based events. Reviewed-by: Lee Jones Signed-off-by: Nuno Sá --- drivers/mfd/adp5585.c | 176 ++++++++++++++++++++++++++++++++++++++++++-- include/linux/mfd/adp5585.h | 18 +++++ 2 files changed, 186 insertions(+), 8 deletions(-) diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c index 95f1f7b553e651a3b24dee2e1c68a3bbaa38cced..b70b0b86de7129fad0d38a3e2fdf96d2db1c8d0e 100644 --- a/drivers/mfd/adp5585.c +++ b/drivers/mfd/adp5585.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -166,10 +167,16 @@ static const struct regmap_config adp5589_regmap_config_template = { static const struct adp5585_regs adp5585_regs = { .ext_cfg = ADP5585_PIN_CONFIG_C, + .int_en = ADP5585_INT_EN, + .gen_cfg = ADP5585_GENERAL_CFG, + .poll_ptime_cfg = ADP5585_POLL_PTIME_CFG, }; static const struct adp5585_regs adp5589_regs = { .ext_cfg = ADP5589_PIN_CONFIG_D, + .int_en = ADP5589_INT_EN, + .gen_cfg = ADP5589_GENERAL_CFG, + .poll_ptime_cfg = ADP5589_POLL_PTIME_CFG, }; static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp5585) @@ -242,6 +249,146 @@ static void adp5585_osc_disable(void *data) regmap_write(adp5585->regmap, ADP5585_GENERAL_CFG, 0); } +static void adp5585_report_events(struct adp5585_dev *adp5585, int ev_cnt) +{ + unsigned int i; + + for (i = 0; i < ev_cnt; i++) { + unsigned long key_val, key_press; + unsigned int key; + int ret; + + ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, &key); + if (ret) + return; + + key_val = FIELD_GET(ADP5585_KEY_EVENT_MASK, key); + key_press = FIELD_GET(ADP5585_KEV_EV_PRESS_MASK, key); + + blocking_notifier_call_chain(&adp5585->event_notifier, key_val, (void *)key_press); + } +} + +static irqreturn_t adp5585_irq(int irq, void *data) +{ + struct adp5585_dev *adp5585 = data; + unsigned int status, ev_cnt; + int ret; + + ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &status); + if (ret) + return IRQ_HANDLED; + + if (status & ADP5585_OVRFLOW_INT) + dev_err_ratelimited(adp5585->dev, "Event overflow error\n"); + + if (!(status & ADP5585_EVENT_INT)) + goto out_irq; + + ret = regmap_read(adp5585->regmap, ADP5585_STATUS, &ev_cnt); + if (ret) + goto out_irq; + + ev_cnt = FIELD_GET(ADP5585_EC_MASK, ev_cnt); + if (!ev_cnt) + goto out_irq; + + adp5585_report_events(adp5585, ev_cnt); +out_irq: + regmap_write(adp5585->regmap, ADP5585_INT_STATUS, status); + return IRQ_HANDLED; +} + +static int adp5585_setup(struct adp5585_dev *adp5585) +{ + const struct adp5585_regs *regs = adp5585->regs; + unsigned int reg_val, i; + int ret; + + /* Clear any possible event by reading all the FIFO entries */ + for (i = 0; i < ADP5585_EV_MAX; i++) { + ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, ®_val); + if (ret) + return ret; + } + + ret = regmap_write(adp5585->regmap, regs->poll_ptime_cfg, adp5585->ev_poll_time); + if (ret) + return ret; + + /* + * Enable the internal oscillator, as it's shared between multiple + * functions. + */ + ret = regmap_write(adp5585->regmap, regs->gen_cfg, + ADP5585_OSC_FREQ_500KHZ | ADP5585_INT_CFG | ADP5585_OSC_EN); + if (ret) + return ret; + + return devm_add_action_or_reset(adp5585->dev, adp5585_osc_disable, adp5585); +} + +static int adp5585_parse_fw(struct adp5585_dev *adp5585) +{ + unsigned int prop_val; + int ret; + + ret = device_property_read_u32(adp5585->dev, "poll-interval", &prop_val); + if (!ret) { + adp5585->ev_poll_time = prop_val / 10 - 1; + /* + * ev_poll_time is the raw value to be written on the register and 0 to 3 are the + * valid values. + */ + if (adp5585->ev_poll_time > 3) + return dev_err_probe(adp5585->dev, -EINVAL, + "Invalid value(%u) for poll-interval\n", prop_val); + } + + return 0; +} + +static void adp5585_irq_disable(void *data) +{ + struct adp5585_dev *adp5585 = data; + + regmap_write(adp5585->regmap, adp5585->regs->int_en, 0); +} + +static int adp5585_irq_enable(struct i2c_client *i2c, + struct adp5585_dev *adp5585) +{ + const struct adp5585_regs *regs = adp5585->regs; + unsigned int stat; + int ret; + + if (i2c->irq <= 0) + return 0; + + ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, adp5585_irq, + IRQF_ONESHOT, i2c->name, adp5585); + if (ret) + return ret; + + /* + * Clear any possible outstanding interrupt before enabling them. We do that by reading + * the status register and writing back the same value. + */ + ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &stat); + if (ret) + return ret; + + ret = regmap_write(adp5585->regmap, ADP5585_INT_STATUS, stat); + if (ret) + return ret; + + ret = regmap_write(adp5585->regmap, regs->int_en, ADP5585_OVRFLOW_IEN | ADP5585_EVENT_IEN); + if (ret) + return ret; + + return devm_add_action_or_reset(&i2c->dev, adp5585_irq_disable, adp5585); +} + static int adp5585_i2c_probe(struct i2c_client *i2c) { struct regmap_config *regmap_config; @@ -255,6 +402,8 @@ static int adp5585_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, adp5585); adp5585->dev = &i2c->dev; + adp5585->irq = i2c->irq; + BLOCKING_INIT_NOTIFIER_HEAD(&adp5585->event_notifier); adp5585->variant = (enum adp5585_variant)(uintptr_t)i2c_get_match_data(i2c); if (!adp5585->variant) @@ -279,25 +428,28 @@ static int adp5585_i2c_probe(struct i2c_client *i2c) return dev_err_probe(&i2c->dev, -ENODEV, "Invalid device ID 0x%02x\n", id); - /* - * Enable the internal oscillator, as it's shared between multiple - * functions. - */ - ret = regmap_set_bits(adp5585->regmap, ADP5585_GENERAL_CFG, ADP5585_OSC_EN); + ret = adp5585_parse_fw(adp5585); if (ret) return ret; - ret = devm_add_action_or_reset(&i2c->dev, adp5585_osc_disable, adp5585); + ret = adp5585_setup(adp5585); if (ret) return ret; - return adp5585_add_devices(adp5585); + ret = adp5585_add_devices(adp5585); + if (ret) + return ret; + + return adp5585_irq_enable(i2c, adp5585); } static int adp5585_suspend(struct device *dev) { struct adp5585_dev *adp5585 = dev_get_drvdata(dev); + if (adp5585->irq) + disable_irq(adp5585->irq); + regcache_cache_only(adp5585->regmap, true); return 0; @@ -306,11 +458,19 @@ static int adp5585_suspend(struct device *dev) static int adp5585_resume(struct device *dev) { struct adp5585_dev *adp5585 = dev_get_drvdata(dev); + int ret; regcache_cache_only(adp5585->regmap, false); regcache_mark_dirty(adp5585->regmap); - return regcache_sync(adp5585->regmap); + ret = regcache_sync(adp5585->regmap); + if (ret) + return ret; + + if (adp5585->irq) + enable_irq(adp5585->irq); + + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume); diff --git a/include/linux/mfd/adp5585.h b/include/linux/mfd/adp5585.h index 77f7c74f084dde01e11816fb7ed099721b6ed78d..43a33a3d3f5a1b4fe3a9c46335d29dee6e9d60f5 100644 --- a/include/linux/mfd/adp5585.h +++ b/include/linux/mfd/adp5585.h @@ -10,13 +10,20 @@ #define __MFD_ADP5585_H_ #include +#include #define ADP5585_ID 0x00 #define ADP5585_MAN_ID_VALUE 0x20 #define ADP5585_MAN_ID_MASK GENMASK(7, 4) +#define ADP5585_REV_ID_MASK GENMASK(3, 0) #define ADP5585_INT_STATUS 0x01 +#define ADP5585_OVRFLOW_INT BIT(2) +#define ADP5585_EVENT_INT BIT(0) #define ADP5585_STATUS 0x02 +#define ADP5585_EC_MASK GENMASK(4, 0) #define ADP5585_FIFO_1 0x03 +#define ADP5585_KEV_EV_PRESS_MASK BIT(7) +#define ADP5585_KEY_EVENT_MASK GENMASK(6, 0) #define ADP5585_FIFO_2 0x04 #define ADP5585_FIFO_3 0x05 #define ADP5585_FIFO_4 0x06 @@ -32,6 +39,7 @@ #define ADP5585_FIFO_14 0x10 #define ADP5585_FIFO_15 0x11 #define ADP5585_FIFO_16 0x12 +#define ADP5585_EV_MAX (ADP5585_FIFO_16 - ADP5585_FIFO_1 + 1) #define ADP5585_GPI_INT_STAT_A 0x13 #define ADP5585_GPI_INT_STAT_B 0x14 #define ADP5585_GPI_STATUS_A 0x15 @@ -104,6 +112,8 @@ #define ADP5585_INT_CFG BIT(1) #define ADP5585_RST_CFG BIT(0) #define ADP5585_INT_EN 0x3c +#define ADP5585_OVRFLOW_IEN BIT(2) +#define ADP5585_EVENT_IEN BIT(0) #define ADP5585_MAX_REG ADP5585_INT_EN @@ -121,7 +131,9 @@ #define ADP5589_PWM_OFFT_LOW 0x3e #define ADP5589_PWM_ONT_LOW 0x40 #define ADP5589_PWM_CFG 0x42 +#define ADP5589_POLL_PTIME_CFG 0x48 #define ADP5589_PIN_CONFIG_D 0x4C +#define ADP5589_GENERAL_CFG 0x4d #define ADP5589_INT_EN 0x4e #define ADP5589_MAX_REG ADP5589_INT_EN @@ -142,15 +154,21 @@ enum adp5585_variant { }; struct adp5585_regs { + unsigned int gen_cfg; unsigned int ext_cfg; + unsigned int int_en; + unsigned int poll_ptime_cfg; }; struct adp5585_dev { struct device *dev; struct regmap *regmap; const struct adp5585_regs *regs; + struct blocking_notifier_head event_notifier; enum adp5585_variant variant; unsigned int id; + int irq; + unsigned int ev_poll_time; }; #endif From patchwork Sat Jun 14 14:36:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896297 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54CA92E339B; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; cv=none; b=IzpbfP5yCHIymP/BvWwfYf4hO8ikBZXjsn/UA65fk5Jq0/qyjmGX6sXhck61B0DIW0DFSd+9O7eM/Rz3g1Dy3BPJRI7mAT2a98FwXTwJucGcEH+/lMtuSEIKTAV5lrQwj3Fytbz9JLJbkRPj2yyI0nEe3VdzcqDSuxn5cH59xIE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; c=relaxed/simple; bh=HjR7/A4umUR2JstMAv+QZ9jqSoHwy9RvO68ibPU/2XI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mau7WhHTycSIpCdO+2zmLs+Q/xNOFXa/ENsvYTehw/Esn4/eQiAqXyHk96UqyuFQWMcl81s+e1u2rsSNjujFl5H/pso//vy1fsw2CCHSzBJP3uwL3NVUTNnQuuw5pCzBjVMaQiXRvR419sPYKWAqmUVgd5H6kbJ6b31lXVLoKwE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=g+vd4bvN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="g+vd4bvN" Received: by smtp.kernel.org (Postfix) with ESMTPS id 077B6C4AF54; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911831; bh=HjR7/A4umUR2JstMAv+QZ9jqSoHwy9RvO68ibPU/2XI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=g+vd4bvNbres7DuVIelWyegQYoPSSHtMPT2MmKT195GndIuwWb9WU99NgXN4c3HKa TpLEfuWO86OkBDh/0SNVVHLy8nqqNI8EbqI7qzYp/s02hC6OcSkblviM4/pMnvrQpi D9H/S0M1bTgjYdjq8H6v2y/cRcaUPvorSg3chGRDtB1roa54hedN3zp9Ot+MrzIHiL DfdYiIBRdI/2Ftge++W4eOb148NNlhNR8r2YQ5LQc2EMwF8yvpxXi98MISn7oQ6XYV 8p5C8C0kTnl2HJ9oR/++k+bNonDvNr2pkWK6X7oNjY3u2X8m6VXPaDpKj+ayBlif4p TgaKafwrr08gA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id F0B3BC71153; Sat, 14 Jun 2025 14:37:10 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:36:04 +0100 Subject: [PATCH v5 13/20] mfd: adp5585: support reset and unlock events Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-13-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=14261; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=7sG5KRYWUQHFQTanRwpbSjYD1k9huJJ8Le8352zZpmw=; b=WgOUg4hUa+IuBJkub+Mev9Utyz/LU9YAeEhDOROTIGAw4NPV/JVrLqzbHTMuPf7frF5+ekW8P Tt/EsKd6QGtA+mhLOYrYZzv/emy3qLRffNCpYq6xzI8cDrXqstXAxoZ X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá The ADP558x family of devices can be programmed to respond to some especial events, In case of the unlock events, one can lock the keypad and use KEYS or GPIs events to unlock it. For the reset events, one can again use a combinations of GPIs/KEYs in order to generate an event that will trigger the device to generate an output reset pulse. Signed-off-by: Nuno Sá --- drivers/mfd/adp5585.c | 274 +++++++++++++++++++++++++++++++++++++++++++- include/linux/mfd/adp5585.h | 40 +++++++ 2 files changed, 312 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c index b70b0b86de7129fad0d38a3e2fdf96d2db1c8d0e..08ed35fbf7d39e16295d610cd995551b8e503132 100644 --- a/drivers/mfd/adp5585.c +++ b/drivers/mfd/adp5585.c @@ -170,6 +170,9 @@ static const struct adp5585_regs adp5585_regs = { .int_en = ADP5585_INT_EN, .gen_cfg = ADP5585_GENERAL_CFG, .poll_ptime_cfg = ADP5585_POLL_PTIME_CFG, + .reset_cfg = ADP5585_RESET_CFG, + .reset1_event_a = ADP5585_RESET1_EVENT_A, + .reset2_event_a = ADP5585_RESET2_EVENT_A, }; static const struct adp5585_regs adp5589_regs = { @@ -177,8 +180,54 @@ static const struct adp5585_regs adp5589_regs = { .int_en = ADP5589_INT_EN, .gen_cfg = ADP5589_GENERAL_CFG, .poll_ptime_cfg = ADP5589_POLL_PTIME_CFG, + .reset_cfg = ADP5589_RESET_CFG, + .reset1_event_a = ADP5589_RESET1_EVENT_A, + .reset2_event_a = ADP5589_RESET2_EVENT_A, }; +static int adp5585_validate_event(const struct adp5585_dev *adp5585, unsigned int ev) +{ + if (adp5585->has_pin6) { + if (ev >= ADP5585_ROW5_KEY_EVENT_START && ev <= ADP5585_ROW5_KEY_EVENT_END) + return 0; + if (ev >= ADP5585_GPI_EVENT_START && ev <= ADP5585_GPI_EVENT_END) + return 0; + + return dev_err_probe(adp5585->dev, -EINVAL, + "Invalid unlock/reset event(%u) for this device\n", ev); + } + + if (ev >= ADP5585_KEY_EVENT_START && ev <= ADP5585_KEY_EVENT_END) + return 0; + if (ev >= ADP5585_GPI_EVENT_START && ev <= ADP5585_GPI_EVENT_END) { + /* + * Some variants of the adp5585 do not have the Row 5 + * (meaning pin 6 or GPIO 6) available. Instead that pin serves + * as a reset pin. So, we need to make sure no event is + * configured for it. + */ + if (ev == (ADP5585_GPI_EVENT_START + 5)) + return dev_err_probe(adp5585->dev, -EINVAL, + "Invalid unlock/reset event(%u). R5 not available\n", + ev); + return 0; + } + + return dev_err_probe(adp5585->dev, -EINVAL, + "Invalid unlock/reset event(%u) for this device\n", ev); +} + +static int adp5589_validate_event(const struct adp5585_dev *adp5585, unsigned int ev) +{ + if (ev >= ADP5589_KEY_EVENT_START && ev <= ADP5589_KEY_EVENT_END) + return 0; + if (ev >= ADP5589_GPI_EVENT_START && ev <= ADP5589_GPI_EVENT_END) + return 0; + + return dev_err_probe(adp5585->dev, -EINVAL, + "Invalid unlock/reset event(%u) for this device\n", ev); +} + static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp5585) { struct regmap_config *regmap_config; @@ -191,6 +240,8 @@ static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp case ADP5585_04: adp5585->id = ADP5585_MAN_ID_VALUE; adp5585->regs = &adp5585_regs; + if (adp5585->variant == ADP5585_01) + adp5585->has_pin6 = true; regmap_config = devm_kmemdup(adp5585->dev, &adp5585_regmap_config_template, sizeof(struct regmap_config), GFP_KERNEL); break; @@ -199,6 +250,8 @@ static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp case ADP5589_02: adp5585->id = ADP5589_MAN_ID_VALUE; adp5585->regs = &adp5589_regs; + adp5585->has_unlock = true; + adp5585->has_pin6 = true; regmap_config = devm_kmemdup(adp5585->dev, &adp5589_regmap_config_template, sizeof(struct regmap_config), GFP_KERNEL); break; @@ -214,6 +267,167 @@ static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp return regmap_config; } +static int adp5585_parse_ev_array(const struct adp5585_dev *adp5585, const char *prop, u32 *events, + u32 *n_events, u32 max_evs, bool reset_ev) +{ + struct device *dev = adp5585->dev; + unsigned int ev; + int ret; + + /* + * The device has the capability of handling special events through GPIs or a Keypad: + * unlock events: Unlock the keymap until one of the configured events is detected. + * reset events: Generate a reset pulse when one of the configured events is detected. + */ + ret = device_property_count_u32(dev, prop); + if (ret < 0) + return 0; + + *n_events = ret; + + if (!adp5585->has_unlock && !reset_ev) + return dev_err_probe(dev, -EOPNOTSUPP, "Unlock keys not supported\n"); + + if (*n_events > max_evs) + return dev_err_probe(dev, -EINVAL, + "Invalid number of keys(%u > %u) for %s\n", + *n_events, max_evs, prop); + + ret = device_property_read_u32_array(dev, prop, events, *n_events); + if (ret) + return ret; + + for (ev = 0; ev < *n_events; ev++) { + if (!reset_ev && events[ev] == ADP5589_UNLOCK_WILDCARD) + continue; + + if (adp5585->id == ADP5585_MAN_ID_VALUE) + ret = adp5585_validate_event(adp5585, events[ev]); + else + ret = adp5589_validate_event(adp5585, events[ev]); + if (ret) + return ret; + } + + return 0; +} + +static int adp5585_unlock_ev_parse(struct adp5585_dev *adp5585) +{ + struct device *dev = adp5585->dev; + int ret; + + ret = adp5585_parse_ev_array(adp5585, "adi,unlock-events", adp5585->unlock_keys, + &adp5585->nkeys_unlock, ARRAY_SIZE(adp5585->unlock_keys), + false); + if (ret) + return ret; + if (!adp5585->nkeys_unlock) + return 0; + + ret = device_property_read_u32(dev, "adi,unlock-trigger-sec", &adp5585->unlock_time); + if (!ret) { + if (adp5585->unlock_time > ADP5585_MAX_UNLOCK_TIME_SEC) + return dev_err_probe(dev, -EINVAL, + "Invalid unlock time(%u > %d)\n", + adp5585->unlock_time, + ADP5585_MAX_UNLOCK_TIME_SEC); + } + + return 0; +} + +static int adp5585_reset_ev_parse(struct adp5585_dev *adp5585) +{ + struct device *dev = adp5585->dev; + u32 prop_val; + int ret; + + ret = adp5585_parse_ev_array(adp5585, "adi,reset1-events", adp5585->reset1_keys, + &adp5585->nkeys_reset1, + ARRAY_SIZE(adp5585->reset1_keys), true); + if (ret) + return ret; + + ret = adp5585_parse_ev_array(adp5585, "adi,reset2-events", + adp5585->reset2_keys, + &adp5585->nkeys_reset2, + ARRAY_SIZE(adp5585->reset2_keys), true); + if (ret) + return ret; + + if (!adp5585->nkeys_reset1 && !adp5585->nkeys_reset2) + return 0; + + if (adp5585->nkeys_reset1 && device_property_read_bool(dev, "adi,reset1-active-high")) + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET1_POL, 1); + + if (adp5585->nkeys_reset2 && device_property_read_bool(dev, "adi,reset2-active-high")) + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET2_POL, 1); + + if (device_property_read_bool(dev, "adi,rst-passthrough-enable")) + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RST_PASSTHRU_EN, 1); + + ret = device_property_read_u32(dev, "adi,reset-trigger-ms", &prop_val); + if (!ret) { + switch (prop_val) { + case 0: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 0); + break; + case 1000: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 1); + break; + case 1500: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 2); + break; + case 2000: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 3); + break; + case 2500: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 4); + break; + case 3000: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 5); + break; + case 3500: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 6); + break; + case 4000: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 7); + break; + default: + return dev_err_probe(dev, -EINVAL, + "Invalid value(%u) for adi,reset-trigger-ms\n", + prop_val); + } + } + + ret = device_property_read_u32(dev, "adi,reset-pulse-width-us", &prop_val); + if (!ret) { + switch (prop_val) { + case 500: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 0); + break; + case 1000: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 1); + break; + case 2000: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 2); + break; + case 10000: + adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 3); + break; + default: + return dev_err_probe(dev, -EINVAL, + "Invalid value(%u) for adi,reset-pulse-width-us\n", + prop_val); + } + return ret; + } + + return 0; +} + static int adp5585_add_devices(const struct adp5585_dev *adp5585) { struct device *dev = adp5585->dev; @@ -302,9 +516,61 @@ static irqreturn_t adp5585_irq(int irq, void *data) static int adp5585_setup(struct adp5585_dev *adp5585) { const struct adp5585_regs *regs = adp5585->regs; - unsigned int reg_val, i; + unsigned int reg_val = 0, i; int ret; + /* Configure the device with reset and unlock events */ + for (i = 0; i < adp5585->nkeys_unlock; i++) { + ret = regmap_write(adp5585->regmap, ADP5589_UNLOCK1 + i, + adp5585->unlock_keys[i] | ADP5589_UNLOCK_EV_PRESS); + if (ret) + return ret; + } + + if (adp5585->nkeys_unlock) { + ret = regmap_update_bits(adp5585->regmap, ADP5589_UNLOCK_TIMERS, + ADP5589_UNLOCK_TIMER, adp5585->unlock_time); + if (ret) + return ret; + + ret = regmap_set_bits(adp5585->regmap, ADP5589_LOCK_CFG, ADP5589_LOCK_EN); + if (ret) + return ret; + } + + for (i = 0; i < adp5585->nkeys_reset1; i++) { + ret = regmap_write(adp5585->regmap, regs->reset1_event_a + i, + adp5585->reset1_keys[i] | ADP5585_RESET_EV_PRESS); + if (ret) + return ret; + } + + for (i = 0; i < adp5585->nkeys_reset2; i++) { + ret = regmap_write(adp5585->regmap, regs->reset2_event_a + i, + adp5585->reset2_keys[i] | ADP5585_RESET_EV_PRESS); + if (ret) + return ret; + } + + if (adp5585->nkeys_reset1 || adp5585->nkeys_reset2) { + ret = regmap_write(adp5585->regmap, regs->reset_cfg, adp5585->reset_cfg); + if (ret) + return ret; + + /* If there's a reset1 event, then R4 is used as an output for the reset signal */ + if (adp5585->nkeys_reset1) + reg_val = ADP5585_R4_EXTEND_CFG_RESET1; + /* If there's a reset2 event, then C4 is used as an output for the reset signal */ + if (adp5585->nkeys_reset2) + reg_val |= ADP5585_C4_EXTEND_CFG_RESET2; + + ret = regmap_update_bits(adp5585->regmap, regs->ext_cfg, + ADP5585_C4_EXTEND_CFG_MASK | ADP5585_R4_EXTEND_CFG_MASK, + reg_val); + if (ret) + return ret; + } + /* Clear any possible event by reading all the FIFO entries */ for (i = 0; i < ADP5585_EV_MAX; i++) { ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, ®_val); @@ -345,7 +611,11 @@ static int adp5585_parse_fw(struct adp5585_dev *adp5585) "Invalid value(%u) for poll-interval\n", prop_val); } - return 0; + ret = adp5585_unlock_ev_parse(adp5585); + if (ret) + return ret; + + return adp5585_reset_ev_parse(adp5585); } static void adp5585_irq_disable(void *data) diff --git a/include/linux/mfd/adp5585.h b/include/linux/mfd/adp5585.h index 43a33a3d3f5a1b4fe3a9c46335d29dee6e9d60f5..db483ef9693a41d29a36910952e7a0bc54f86631 100644 --- a/include/linux/mfd/adp5585.h +++ b/include/linux/mfd/adp5585.h @@ -68,6 +68,7 @@ #define ADP5585_GPIO_DIRECTION_A 0x27 #define ADP5585_GPIO_DIRECTION_B 0x28 #define ADP5585_RESET1_EVENT_A 0x29 +#define ADP5585_RESET_EV_PRESS BIT(7) #define ADP5585_RESET1_EVENT_B 0x2a #define ADP5585_RESET1_EVENT_C 0x2b #define ADP5585_RESET2_EVENT_A 0x2c @@ -118,6 +119,13 @@ #define ADP5585_MAX_REG ADP5585_INT_EN #define ADP5585_PIN_MAX 11 +#define ADP5585_MAX_UNLOCK_TIME_SEC 7 +#define ADP5585_KEY_EVENT_START 1 +#define ADP5585_KEY_EVENT_END 25 +#define ADP5585_GPI_EVENT_START 37 +#define ADP5585_GPI_EVENT_END 47 +#define ADP5585_ROW5_KEY_EVENT_START 1 +#define ADP5585_ROW5_KEY_EVENT_END 30 /* ADP5589 */ #define ADP5589_MAN_ID_VALUE 0x10 @@ -128,6 +136,20 @@ #define ADP5589_GPO_DATA_OUT_A 0x2a #define ADP5589_GPO_OUT_MODE_A 0x2d #define ADP5589_GPIO_DIRECTION_A 0x30 +#define ADP5589_UNLOCK1 0x33 +#define ADP5589_UNLOCK_EV_PRESS BIT(7) +#define ADP5589_UNLOCK_TIMERS 0x36 +#define ADP5589_UNLOCK_TIMER GENMASK(2, 0) +#define ADP5589_LOCK_CFG 0x37 +#define ADP5589_LOCK_EN BIT(0) +#define ADP5589_RESET1_EVENT_A 0x38 +#define ADP5589_RESET2_EVENT_A 0x3B +#define ADP5589_RESET_CFG 0x3D +#define ADP5585_RESET2_POL BIT(7) +#define ADP5585_RESET1_POL BIT(6) +#define ADP5585_RST_PASSTHRU_EN BIT(5) +#define ADP5585_RESET_TRIG_TIME GENMASK(4, 2) +#define ADP5585_PULSE_WIDTH GENMASK(1, 0) #define ADP5589_PWM_OFFT_LOW 0x3e #define ADP5589_PWM_ONT_LOW 0x40 #define ADP5589_PWM_CFG 0x42 @@ -138,6 +160,11 @@ #define ADP5589_MAX_REG ADP5589_INT_EN #define ADP5589_PIN_MAX 19 +#define ADP5589_KEY_EVENT_START 1 +#define ADP5589_KEY_EVENT_END 88 +#define ADP5589_GPI_EVENT_START 97 +#define ADP5589_GPI_EVENT_END 115 +#define ADP5589_UNLOCK_WILDCARD 127 struct regmap; @@ -158,6 +185,9 @@ struct adp5585_regs { unsigned int ext_cfg; unsigned int int_en; unsigned int poll_ptime_cfg; + unsigned int reset_cfg; + unsigned int reset1_event_a; + unsigned int reset2_event_a; }; struct adp5585_dev { @@ -167,8 +197,18 @@ struct adp5585_dev { struct blocking_notifier_head event_notifier; enum adp5585_variant variant; unsigned int id; + bool has_unlock; + bool has_pin6; int irq; unsigned int ev_poll_time; + unsigned int unlock_time; + unsigned int unlock_keys[2]; + unsigned int nkeys_unlock; + unsigned int reset1_keys[3]; + unsigned int nkeys_reset1; + unsigned int reset2_keys[2]; + unsigned int nkeys_reset2; + u8 reset_cfg; }; #endif From patchwork Sat Jun 14 14:36:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896296 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B7BE2E62D7; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; cv=none; b=WIjGzmK0YfJZdaSECTT+b7CpQoLOAwDnEtKn74boobveR6tbTavHbpDek+NLgAtSluOQLqYkShwbasH0ariYYJdGJdm0Nczz1a2ITMpvONbC/tmxa2oBvRVO+0MkVf1jcNowjtVNnXgrhnQ1yDcStv0ZZDLajSSRxG2aaaZkpzU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; c=relaxed/simple; bh=/OU5QQy2ON17yJmBZuWfO54vm1YJzjp+Y/+4Mj5OYwI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Q5ZP901OjQmbcRq2J7dcSb0aK+ra2zw5s03LJKDzk2DtDm/DTJF6Ad7nQLj1E42DF0bzp0gNCsy7Eh5bE5ECnxrhNF96WRVlbcECuYOmPnsjvI/RYx9D7KgwN/cifDMMQKaNVra/AxnBAcFXx9tXjIS41a1WDf24AIw00TTU2cY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=h/BeNbRF; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="h/BeNbRF" Received: by smtp.kernel.org (Postfix) with ESMTPS id 3B478C4AF1A; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911831; bh=/OU5QQy2ON17yJmBZuWfO54vm1YJzjp+Y/+4Mj5OYwI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=h/BeNbRF3ycvJ9sWBfvd4gHHErVz77okm+aW/zIg9Cphk4sKcTvn6H1sOxtHTVqZQ 59R6XyyB0QYKV9wsd8HYshDsUxNVEGMbsvTz/SXiYxKPPQib8skjc36s5vwq2QDhA6 xHl7rm/issM7IgKM55Z1ViwUtgUaJ4RmTZK5S2DgGRKlamt/1OMthN7GKIivj21yUc 4GjvC7/bqA/tX381iaOOqRbFWoBab9xKNLW+uwQLr2ps6qmsAcu7HwNQYfDbpaaXDv lTb9n2m80PZWYgIzR/IeBMKE35fZug+cXD6fHxchUpiIK3XxSV84hjTVUyulW+Ls4p NC/dbf6P+xubw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2FE2EC71135; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:36:06 +0100 Subject: [PATCH v5 15/20] gpio: adp5585: support gpi events Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-15-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying , Bartosz Golaszewski X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=11547; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=fNhkKwm26/y30Dub2uRd6iuHYZoMLItERd7DBAdK8ZE=; b=Nlj8HdmCZJCt9cj4kSymNE0OQxv1f79p5P+0elPnxnn+TvAJq9sTWV2zwpOi75O5Hnf5/dVWb AkxF/pFQGTlDKI92236eoTuoYg+n7XGx/DMH8e4Q2svISIvOnNJcPVL X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá Add support for adding GPIs to the event FIFO. This is done by adding irq_chip support. Like this, one can use the input gpio_keys driver as a "frontend" device and input handler. As part of this change, we now implement .request() and .free() as we can't blindly consume all available pins as GPIOs (example: some pins can be used for forming a keymap matrix). Also note that the number of pins can now be obtained from the parent, top level device. Hence the 'max_gpio' variable can be removed. Reviewed-by: Linus Walleij Acked-by: Bartosz Golaszewski Signed-off-by: Nuno Sá --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-adp5585.c | 221 +++++++++++++++++++++++++++++++++++++++++++- include/linux/mfd/adp5585.h | 2 + 3 files changed, 220 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9ae806f45e19c1494d156b7f04b1882be68d3e3f..0b85d07ccb0b8a41f33fd3d930eb74f70787355d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1259,6 +1259,7 @@ config GPIO_ADP5520 config GPIO_ADP5585 tristate "GPIO Support for ADP5585" depends on MFD_ADP5585 + select GPIOLIB_IRQCHIP help This option enables support for the GPIO function found in the Analog Devices ADP5585. diff --git a/drivers/gpio/gpio-adp5585.c b/drivers/gpio/gpio-adp5585.c index cdf107742579cb44d73cc030646358ba5a23fd97..b2c8836c5f8477ebeea516b4eedc7d3d2aad59dd 100644 --- a/drivers/gpio/gpio-adp5585.c +++ b/drivers/gpio/gpio-adp5585.c @@ -7,10 +7,15 @@ * Copyright 2025 Analog Devices, Inc. */ +#include +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -36,20 +41,29 @@ struct adp5585_gpio_chip { int (*bank)(unsigned int off); int (*bit)(unsigned int off); - unsigned int max_gpio; unsigned int debounce_dis_a; unsigned int rpull_cfg_a; unsigned int gpo_data_a; unsigned int gpo_out_a; unsigned int gpio_dir_a; unsigned int gpi_stat_a; + unsigned int gpi_int_lvl_a; + unsigned int gpi_ev_a; + unsigned int gpi_ev_min; + unsigned int gpi_ev_max; bool has_bias_hole; }; struct adp5585_gpio_dev { struct gpio_chip gpio_chip; + struct notifier_block nb; const struct adp5585_gpio_chip *info; struct regmap *regmap; + unsigned long irq_mask; + unsigned long irq_en; + unsigned long irq_active_high; + /* used for irqchip bus locking */ + struct mutex bus_lock; }; static int adp5585_gpio_bank(unsigned int off) @@ -224,12 +238,175 @@ static int adp5585_gpio_set_config(struct gpio_chip *chip, unsigned int off, }; } +static int adp5585_gpio_request(struct gpio_chip *chip, unsigned int off) +{ + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); + const struct adp5585_gpio_chip *info = adp5585_gpio->info; + struct device *dev = chip->parent; + struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent); + const struct adp5585_regs *regs = adp5585->regs; + int ret; + + ret = test_and_set_bit(off, adp5585->pin_usage); + if (ret) + return -EBUSY; + + /* make sure it's configured for GPIO */ + return regmap_clear_bits(adp5585_gpio->regmap, + regs->pin_cfg_a + info->bank(off), + info->bit(off)); +} + +static void adp5585_gpio_free(struct gpio_chip *chip, unsigned int off) +{ + struct device *dev = chip->parent; + struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent); + + clear_bit(off, adp5585->pin_usage); +} + +static int adp5585_gpio_key_event(struct notifier_block *nb, unsigned long key, + void *data) +{ + struct adp5585_gpio_dev *adp5585_gpio = container_of(nb, struct adp5585_gpio_dev, nb); + struct device *dev = adp5585_gpio->gpio_chip.parent; + unsigned long key_press = (unsigned long)data; + unsigned int irq, irq_type; + struct irq_data *irqd; + bool active_high; + unsigned int off; + + /* make sure the event is for me */ + if (key < adp5585_gpio->info->gpi_ev_min || key > adp5585_gpio->info->gpi_ev_max) + return NOTIFY_DONE; + + off = key - adp5585_gpio->info->gpi_ev_min; + active_high = test_bit(off, &adp5585_gpio->irq_active_high); + + irq = irq_find_mapping(adp5585_gpio->gpio_chip.irq.domain, off); + if (!irq) + return NOTIFY_BAD; + + irqd = irq_get_irq_data(irq); + if (!irqd) { + dev_err(dev, "Could not get irq(%u) data\n", irq); + return NOTIFY_BAD; + } + + dev_dbg_ratelimited(dev, "gpio-keys event(%u) press=%lu, a_high=%u\n", + off, key_press, active_high); + + if (!active_high) + key_press = !key_press; + + irq_type = irqd_get_trigger_type(irqd); + + if ((irq_type & IRQ_TYPE_EDGE_RISING && key_press) || + (irq_type & IRQ_TYPE_EDGE_FALLING && !key_press)) + handle_nested_irq(irq); + + return NOTIFY_STOP; +} + +static void adp5585_irq_bus_lock(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(gc); + + mutex_lock(&adp5585_gpio->bus_lock); +} + +static void adp5585_irq_bus_sync_unlock(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); + const struct adp5585_gpio_chip *info = adp5585_gpio->info; + irq_hw_number_t hwirq = irqd_to_hwirq(d); + bool active_high = test_bit(hwirq, &adp5585_gpio->irq_active_high); + bool enabled = test_bit(hwirq, &adp5585_gpio->irq_en); + bool masked = test_bit(hwirq, &adp5585_gpio->irq_mask); + unsigned int bank = adp5585_gpio->info->bank(hwirq); + unsigned int bit = adp5585_gpio->info->bit(hwirq); + + if (masked && !enabled) + goto out_unlock; + if (!masked && enabled) + goto out_unlock; + + regmap_update_bits(adp5585_gpio->regmap, info->gpi_int_lvl_a + bank, bit, + active_high ? bit : 0); + regmap_update_bits(adp5585_gpio->regmap, info->gpi_ev_a + bank, bit, + masked ? 0 : bit); + assign_bit(hwirq, &adp5585_gpio->irq_en, !masked); + +out_unlock: + mutex_unlock(&adp5585_gpio->bus_lock); +} + +static void adp5585_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + __set_bit(hwirq, &adp5585_gpio->irq_mask); + gpiochip_disable_irq(gc, hwirq); +} + +static void adp5585_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + gpiochip_enable_irq(gc, hwirq); + __clear_bit(hwirq, &adp5585_gpio->irq_mask); +} + +static int adp5585_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + if (!(type & IRQ_TYPE_EDGE_BOTH)) + return -EINVAL; + + assign_bit(hwirq, &adp5585_gpio->irq_active_high, + type == IRQ_TYPE_EDGE_RISING); + + irq_set_handler_locked(d, handle_edge_irq); + return 0; +} + +static const struct irq_chip adp5585_irq_chip = { + .name = "adp5585", + .irq_mask = adp5585_irq_mask, + .irq_unmask = adp5585_irq_unmask, + .irq_bus_lock = adp5585_irq_bus_lock, + .irq_bus_sync_unlock = adp5585_irq_bus_sync_unlock, + .irq_set_type = adp5585_irq_set_type, + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static void adp5585_gpio_unreg_notifier(void *data) +{ + struct adp5585_gpio_dev *adp5585_gpio = data; + struct device *dev = adp5585_gpio->gpio_chip.parent; + struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent); + + blocking_notifier_chain_unregister(&adp5585->event_notifier, + &adp5585_gpio->nb); +} + static int adp5585_gpio_probe(struct platform_device *pdev) { struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent); const struct platform_device_id *id = platform_get_device_id(pdev); struct adp5585_gpio_dev *adp5585_gpio; struct device *dev = &pdev->dev; + struct gpio_irq_chip *girq; struct gpio_chip *gc; int ret; @@ -253,13 +430,43 @@ static int adp5585_gpio_probe(struct platform_device *pdev) gc->get = adp5585_gpio_get_value; gc->set_rv = adp5585_gpio_set_value; gc->set_config = adp5585_gpio_set_config; + gc->request = adp5585_gpio_request; + gc->free = adp5585_gpio_free; gc->can_sleep = true; gc->base = -1; - gc->ngpio = adp5585_gpio->info->max_gpio; + gc->ngpio = adp5585->n_pins; gc->label = pdev->name; gc->owner = THIS_MODULE; + if (device_property_present(dev->parent, "interrupt-controller")) { + if (!adp5585->irq) + return dev_err_probe(dev, -EINVAL, + "Unable to serve as interrupt controller without IRQ\n"); + + girq = &adp5585_gpio->gpio_chip.irq; + gpio_irq_chip_set_chip(girq, &adp5585_irq_chip); + girq->handler = handle_bad_irq; + girq->threaded = true; + + adp5585_gpio->nb.notifier_call = adp5585_gpio_key_event; + ret = blocking_notifier_chain_register(&adp5585->event_notifier, + &adp5585_gpio->nb); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, adp5585_gpio_unreg_notifier, + adp5585_gpio); + if (ret) + return ret; + } + + /* everything masked by default */ + adp5585_gpio->irq_mask = ~0UL; + + ret = devm_mutex_init(dev, &adp5585_gpio->bus_lock); + if (ret) + return ret; ret = devm_gpiochip_add_data(dev, &adp5585_gpio->gpio_chip, adp5585_gpio); if (ret) @@ -277,8 +484,11 @@ static const struct adp5585_gpio_chip adp5585_gpio_chip_info = { .gpo_out_a = ADP5585_GPO_OUT_MODE_A, .gpio_dir_a = ADP5585_GPIO_DIRECTION_A, .gpi_stat_a = ADP5585_GPI_STATUS_A, - .max_gpio = ADP5585_PIN_MAX, .has_bias_hole = true, + .gpi_ev_min = ADP5585_GPI_EVENT_START, + .gpi_ev_max = ADP5585_GPI_EVENT_END, + .gpi_int_lvl_a = ADP5585_GPI_INT_LEVEL_A, + .gpi_ev_a = ADP5585_GPI_EVENT_EN_A, }; static const struct adp5585_gpio_chip adp5589_gpio_chip_info = { @@ -290,7 +500,10 @@ static const struct adp5585_gpio_chip adp5589_gpio_chip_info = { .gpo_out_a = ADP5589_GPO_OUT_MODE_A, .gpio_dir_a = ADP5589_GPIO_DIRECTION_A, .gpi_stat_a = ADP5589_GPI_STATUS_A, - .max_gpio = ADP5589_PIN_MAX, + .gpi_ev_min = ADP5589_GPI_EVENT_START, + .gpi_ev_max = ADP5589_GPI_EVENT_END, + .gpi_int_lvl_a = ADP5589_GPI_INT_LEVEL_A, + .gpi_ev_a = ADP5589_GPI_EVENT_EN_A, }; static const struct platform_device_id adp5585_gpio_id_table[] = { diff --git a/include/linux/mfd/adp5585.h b/include/linux/mfd/adp5585.h index 41c5d2e1cc7ca40aa5192296ecc5ff8d737cb3e6..5237da6b4a9f2f3424e5f0c4814c5d08aebf080e 100644 --- a/include/linux/mfd/adp5585.h +++ b/include/linux/mfd/adp5585.h @@ -136,6 +136,8 @@ #define ADP5589_GPI_STATUS_A 0x16 #define ADP5589_GPI_STATUS_C 0x18 #define ADP5589_RPULL_CONFIG_A 0x19 +#define ADP5589_GPI_INT_LEVEL_A 0x1e +#define ADP5589_GPI_EVENT_EN_A 0x21 #define ADP5589_DEBOUNCE_DIS_A 0x27 #define ADP5589_GPO_DATA_OUT_A 0x2a #define ADP5589_GPO_OUT_MODE_A 0x2d From patchwork Sat Jun 14 14:36:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896295 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8847D2E6D0B; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; cv=none; b=YJqQge1kee+rFHVxya5W/Kk8339zr08hmzKKvgAYnbS427gi4KgnLB9725zL6E+Lmk8EanVU+ag1MtrxJa4d2r/MlnJXXONrQT5djI88E9QwQ5pNnGVv18H3xTGOF5NHO6JlSGR02pA1z6ZZmMClb8hPJKasJj/h2xCChrD6EEs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; c=relaxed/simple; bh=TLJxXnheWAv7O8Aitb9EAGsgascV3faUnHqbHaTQOJI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kuoe1OcWCtXWe3vTHpxAv4ZSR+TNdA5zLekVmX2X++AWY9ytwOEZxMKEzQWeApeXCWuiehV3hhwVA7GhpbBqJIxNsEe3oemxfVOQpArM09q8c8CqRI3cAr92iacSQPDKoxMdyDRtSJOy8H741PWlQPKd+dnVd7P2Bki4w0P8yeY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Rihg7RIB; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Rihg7RIB" Received: by smtp.kernel.org (Postfix) with ESMTPS id 48C7EC19422; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911831; bh=TLJxXnheWAv7O8Aitb9EAGsgascV3faUnHqbHaTQOJI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Rihg7RIBbHrZ/9kbiQZGGsPkgllQrG0t0XIrDliGnBcxzMqBxXpxGO80l3j78QFWt OKQf7qTJgh8Zqd3sr2G/kZAqXr2AwusY5IUIz12AKjTAhMhTC1RqlZXGfy0ISvbWfp jazH8S1oYD/GyUntO5EUrBHuCOU6UiPMUJnfsoBrXKiV6pXd8fe4NDyQLNsbZpO44C cgWWAFFdL3LHT3uzYxEf615QnX3Moc69FlQrABS9t3b8Ybz+qKHGv5azprcuj8QBBb xFuEFrcf8jC5TuwcDWYmndOjLfIaIgHUoBkrXzKRp2IENeVlk2tW4Te4eM4OKBCe41 8aAdfMnE3v5LA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3E616C71157; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:36:07 +0100 Subject: [PATCH v5 16/20] Input: adp5585: Add Analog Devices ADP5585/89 support Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-16-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=13652; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=jw1rj4wawUso/tVNl2xVy54WXAnff9qZbjQ5HvfBn8c=; b=bmrd9jV0cbXNUQ5SdvI9df6nFlSeNgUXx78s3QpWaBGjp6fFKu3ppZLcKhr/tScKB+8RQGf7U dDO7BSaz5b4AsT4jlQTvaBrSdYjl+7lkJnlqpVFR6EDaP/3aXTICWFJ X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá The ADP5585 is a 10/11 input/output port expander with a built in keypad matrix decoder, programmable logic, reset generator, and PWM generator. This driver supports the keyboard function using the platform device registered by the core MFD driver. The ADP5589 has 19 pins and also features an unlock function. Signed-off-by: Nuno Sá --- MAINTAINERS | 1 + drivers/input/keyboard/Kconfig | 11 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/adp5585-keys.c | 371 ++++++++++++++++++++++++++++++++++ 4 files changed, 384 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0737dcb2e41119426f1d8fbaec829cc90ed0bf64..18838ba19e5edbbe352a470c4e177c6d24136d83 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -550,6 +550,7 @@ L: linux-pwm@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/*/adi,adp5585*.yaml F: drivers/gpio/gpio-adp5585.c +F: drivers/input/keyboard/adp5585-keys.c F: drivers/mfd/adp5585.c F: drivers/pwm/pwm-adp5585.c F: include/linux/mfd/adp5585.h diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 721ab69e84ac6586f4f19102890a15ca3fcf1910..322da0957067db77c7f66ab26a181d39c2c1d513 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -37,6 +37,17 @@ config KEYBOARD_ADP5520 To compile this driver as a module, choose M here: the module will be called adp5520-keys. +config KEYBOARD_ADP5585 + tristate "ADP5585 and similar I2C QWERTY Keypad and IO Expanders" + depends on MFD_ADP5585 + select INPUT_MATRIXKMAP + help + This option enables support for the KEYMAP function found in the Analog + Devices ADP5585 and similar devices. + + To compile this driver as a module, choose M here: the + module will be called adp5585-keys. + config KEYBOARD_ADP5588 tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander" depends on I2C diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 1e0721c3070968a6339a42f65a95af48364f6897..f00ec003a59aa28577ae164c0539cc5aff9579fc 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_KEYBOARD_ADC) += adc-keys.o obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o +obj-$(CONFIG_KEYBOARD_ADP5585) += adp5585-keys.o obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o diff --git a/drivers/input/keyboard/adp5585-keys.c b/drivers/input/keyboard/adp5585-keys.c new file mode 100644 index 0000000000000000000000000000000000000000..4208229e13561db1919e2f671064171ab851e9c0 --- /dev/null +++ b/drivers/input/keyboard/adp5585-keys.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices ADP5585 Keys driver + * + * Copyright (C) 2025 Analog Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* As needed for the matrix parsing code */ +#define ADP5589_MAX_KEYMAPSIZE 123 + +struct adp5585_kpad_chip { + u8 key_ev_min; + u8 key_ev_max; + u8 max_rows; + u8 max_cols; +}; + +struct adp5585_kpad { + const struct adp5585_kpad_chip *info; + struct notifier_block nb; + struct input_dev *input; + unsigned short keycode[ADP5589_MAX_KEYMAPSIZE]; + struct device *dev; + unsigned long keypad; + int row_shift; +}; + +static int adp5585_keys_validate_events(const struct adp5585_kpad *kpad, + const u32 *events, u32 n_events) +{ + unsigned int ev; + u32 row, col; + + for (ev = 0; ev < n_events; ev++) { + if (events[ev] < kpad->info->key_ev_min || + events[ev] > kpad->info->key_ev_max) + continue; + + /* + * if the event is to be generated by the keymap, we need to make + * sure that the pins are part of it! + */ + row = (events[ev] - 1) / kpad->info->max_cols; + col = (events[ev] - 1) % kpad->info->max_cols; + + if (test_bit(row, &kpad->keypad) && + test_bit(col + kpad->info->max_rows, &kpad->keypad)) + continue; + + return dev_err_probe(kpad->dev, -EINVAL, + "Invalid unlock/reset event(%u) not used in the keypad\n", + events[ev]); + } + + return 0; +} + +static int adp5585_keys_check_special_events(const struct adp5585_dev *adp5585, + const struct adp5585_kpad *kpad) +{ + int error; + + error = adp5585_keys_validate_events(kpad, adp5585->unlock_keys, + adp5585->nkeys_unlock); + if (error) + return error; + + error = adp5585_keys_validate_events(kpad, adp5585->reset1_keys, + adp5585->nkeys_reset1); + if (error) + return error; + + return adp5585_keys_validate_events(kpad, adp5585->reset2_keys, + adp5585->nkeys_reset2); +} + +static void adp5585_keys_pins_free(void *data) +{ + struct adp5585_kpad *kpad = data; + struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent); + unsigned int pin; + + for_each_set_bit(pin, &kpad->keypad, adp5585->n_pins) + clear_bit(pin, adp5585->pin_usage); +} + +static int adp5585_keys_parse_fw(const struct adp5585_dev *adp5585, + struct adp5585_kpad *kpad) +{ + struct device *dev = kpad->dev; + u32 cols = 0, rows = 0, pin; + int error, n_pins; + + /* + * We do not check for errors (or no value) since the input device is + * only added if this property is present in the first place. + */ + n_pins = device_property_count_u32(dev, "adi,keypad-pins"); + if (n_pins > adp5585->n_pins) + return dev_err_probe(dev, -EINVAL, + "Too many keypad pins (%d) defined (max=%d)\n", + n_pins, adp5585->n_pins); + + unsigned int *keypad_pins __free(kfree) = kcalloc(n_pins, sizeof(*keypad_pins), + GFP_KERNEL); + if (!keypad_pins) + return -ENOMEM; + + error = device_property_read_u32_array(dev, "adi,keypad-pins", + keypad_pins, n_pins); + if (error) + return error; + + /* + * We can add the action here since it makes the code easier and nothing + * "bad" will happen out of it. Worst case, it will be a no-op and no + * bit will set. + */ + error = devm_add_action_or_reset(dev, adp5585_keys_pins_free, kpad); + if (error) + return error; + + for (pin = 0; pin < n_pins; pin++) { + if (keypad_pins[pin] >= adp5585->n_pins) + return dev_err_probe(dev, -EINVAL, + "Invalid keypad pin(%u) defined\n", + keypad_pins[pin]); + + if (test_and_set_bit(keypad_pins[pin], adp5585->pin_usage)) + return dev_err_probe(dev, -EBUSY, + "Keypad pin(%u) already used\n", + keypad_pins[pin]); + + __set_bit(keypad_pins[pin], &kpad->keypad); + } + + /* + * Note that given that we get a mask (and the HW allows it), we + * can have holes in our keypad (eg: row0, row1 and row7 enabled). + * However, for the matrix parsing functions we need to pass the + * number of rows/cols as the maximum row/col used plus 1. This + * pretty much means we will also have holes in our SW keypad. + */ + + rows = find_last_bit(&kpad->keypad, kpad->info->max_rows) + 1; + if (rows == kpad->info->max_rows + 1) + return dev_err_probe(dev, -EINVAL, + "Now rows defined in the keypad!\n"); + + cols = find_last_bit(&kpad->keypad, kpad->info->max_cols + kpad->info->max_rows); + if (cols < kpad->info->max_rows) + return dev_err_probe(dev, -EINVAL, + "No columns defined in the keypad!\n"); + + cols = cols + 1 - kpad->info->max_rows; + + error = matrix_keypad_build_keymap(NULL, NULL, rows, cols, + kpad->keycode, kpad->input); + if (error) + return error; + + kpad->row_shift = get_count_order(cols); + + if (device_property_read_bool(kpad->dev, "autorepeat")) + __set_bit(EV_REP, kpad->input->evbit); + + error = adp5585_keys_check_special_events(adp5585, kpad); + if (error) + return error; + + return 0; +} + +static int adp5585_keys_setup(const struct adp5585_dev *adp5585, + struct adp5585_kpad *kpad) +{ + unsigned long keys_bits, start = 0, nbits = kpad->info->max_rows; + const struct adp5585_regs *regs = adp5585->regs; + unsigned int i = 0, max_cols = kpad->info->max_cols; + int error; + + /* + * Take care as the below assumes max_rows is always less or equal than + * 8 which is true for the supported devices. If we happen to add + * another device we need to make sure this still holds true. Although + * adding a new device is very unlikely. + */ + do { + keys_bits = bitmap_read(&kpad->keypad, start, nbits); + if (keys_bits) { + error = regmap_write(adp5585->regmap, regs->pin_cfg_a + i, + keys_bits); + if (error) + return error; + } + + start += nbits; + if (max_cols > 8) { + nbits = 8; + max_cols -= nbits; + } else { + nbits = max_cols; + } + + i++; + } while (start < kpad->info->max_rows + kpad->info->max_cols); + + return 0; +} + +static int adp5585_keys_ev_handle(struct notifier_block *nb, unsigned long key, + void *data) +{ + struct adp5585_kpad *kpad = container_of(nb, struct adp5585_kpad, nb); + unsigned long key_press = (unsigned long)data; + unsigned int row, col, code; + + /* make sure the event is for us */ + if (key < kpad->info->key_ev_min || key > kpad->info->key_ev_max) + return NOTIFY_DONE; + + /* + * Unlikely but lets be on the safe side! We do not return any error + * because the event was indeed for us but with some weird value. So, + * we still want the caller know that the right handler was called. + */ + if (!key) + return NOTIFY_BAD; + + row = (key - 1) / (kpad->info->max_cols); + col = (key - 1) % (kpad->info->max_cols); + code = MATRIX_SCAN_CODE(row, col, kpad->row_shift); + + dev_dbg_ratelimited(kpad->dev, "report key(%lu) r(%d) c(%d) code(%d)\n", + key, row, col, kpad->keycode[code]); + + input_report_key(kpad->input, kpad->keycode[code], key_press); + input_sync(kpad->input); + + return NOTIFY_STOP; +} + +static void adp5585_keys_unreg_notifier(void *data) +{ + struct adp5585_kpad *kpad = data; + struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent); + + blocking_notifier_chain_unregister(&adp5585->event_notifier, + &kpad->nb); +} + +static int adp5585_keys_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct adp5585_kpad *kpad; + unsigned int revid; + const char *phys; + int error; + + kpad = devm_kzalloc(dev, sizeof(*kpad), GFP_KERNEL); + if (!kpad) + return -ENOMEM; + + if (!adp5585->irq) + return dev_err_probe(dev, -EINVAL, + "IRQ is mandatory for the keypad\n"); + + kpad->dev = dev; + + kpad->input = devm_input_allocate_device(dev); + if (!kpad->input) + return -ENOMEM; + + kpad->info = (const struct adp5585_kpad_chip *)id->driver_data; + if (!kpad->info) + return -ENODEV; + + error = regmap_read(adp5585->regmap, ADP5585_ID, &revid); + if (error) + return dev_err_probe(dev, error, "Failed to read device ID\n"); + + phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input0", pdev->name); + if (!phys) + return -ENOMEM; + + kpad->input->name = pdev->name; + kpad->input->phys = phys; + + kpad->input->id.bustype = BUS_I2C; + kpad->input->id.vendor = 0x0001; + kpad->input->id.product = 0x0001; + kpad->input->id.version = revid & ADP5585_REV_ID_MASK; + + device_set_of_node_from_dev(dev, dev->parent); + + error = adp5585_keys_parse_fw(adp5585, kpad); + if (error) + return error; + + error = adp5585_keys_setup(adp5585, kpad); + if (error) + return error; + + kpad->nb.notifier_call = adp5585_keys_ev_handle; + error = blocking_notifier_chain_register(&adp5585->event_notifier, + &kpad->nb); + if (error) + return error; + + error = devm_add_action_or_reset(dev, adp5585_keys_unreg_notifier, kpad); + if (error) + return error; + + error = input_register_device(kpad->input); + if (error) + return dev_err_probe(dev, error, + "Failed to register input device\n"); + + return 0; +} + +static const struct adp5585_kpad_chip adp5585_kpad_chip_info = { + .max_rows = 6, + .max_cols = 5, + .key_ev_min = ADP5585_ROW5_KEY_EVENT_START, + .key_ev_max = ADP5585_ROW5_KEY_EVENT_END, +}; + +static const struct adp5585_kpad_chip adp5589_kpad_chip_info = { + .max_rows = 8, + .max_cols = 11, + .key_ev_min = ADP5589_KEY_EVENT_START, + .key_ev_max = ADP5589_KEY_EVENT_END, +}; + +static const struct platform_device_id adp5585_keys_id_table[] = { + { "adp5585-keys", (kernel_ulong_t)&adp5585_kpad_chip_info }, + { "adp5589-keys", (kernel_ulong_t)&adp5589_kpad_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(platform, adp5585_keys_id_table); + +static struct platform_driver adp5585_keys_driver = { + .driver = { + .name = "adp5585-keys", + }, + .probe = adp5585_keys_probe, + .id_table = adp5585_keys_id_table, +}; +module_platform_driver(adp5585_keys_driver); + +MODULE_AUTHOR("Nuno Sá "); +MODULE_DESCRIPTION("ADP5585 Keys Driver"); +MODULE_LICENSE("GPL"); From patchwork Sat Jun 14 14:36:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896293 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ABE462E6D3B; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; cv=none; b=kt6BZ/XssPslqOfg/n22883/Wj5iYxgWJBprt+ZLpkIPNHb9kgHxSQe8f/7pgGol/lxWsj6df4exGQlzajf56LIf+n3EtmLiHkRogesltGh70CcsxFbep7bkG6oz6zfYdrjUpMbyDgibaF6kxaVbwBMwehdUGOf1H9ZfhkbNy/E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; c=relaxed/simple; bh=mLiaGU+SIn/Mgx1V/hSp9Hj1WK2nwp0MgZOKdibIj6Q=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZLo7PjmtuABlEdGy9mmVjECBq3l76L/RIbwN7JBEvyz5P51gJhIXbsnFQv8pk2iJS6O9TLOyt/x7qT9gYy4PoKLLN3+tvbiCGoV6ExIHhKgc3Mm1mjHRy4ROgGY0oswfqBwhthcUtFVXaaizo8a1w7IVKVjaALKiJESE+vNkKeg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dcqmBbhr; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dcqmBbhr" Received: by smtp.kernel.org (Postfix) with ESMTPS id 654B6C4AF15; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911831; bh=mLiaGU+SIn/Mgx1V/hSp9Hj1WK2nwp0MgZOKdibIj6Q=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=dcqmBbhrHzXfydh6G/jKrZbk6UCn/Toy6IW3+yzm19BWlyKI890tAN3o1mO76ic4t 1jl1fdrVcamY2oP5U0xtHhEmmMzWzisaV6bg1owzjIgcfi4IGRNQyXO3kQt5V91c1x o2Fch39oxGcngOGrfpJcmQ/hAdUDeDGkSKTmoeALFfD8unt7BAGWbCy3Sjeumbvc5y AufXaw1tK4JAKSKMdi8UmpN4BziTsVhxYLVmYcqSqLkY4NWTMTKIFcZbSAc2CEfXbu qD1r2KhiCrI5DH3hw/m5kPJ1S8yGzxPuXbyijzR/uCfwTeA3xPevEMjxELQlJAkBiH duZ680h31HOag== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5A57BC71155; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:36:09 +0100 Subject: [PATCH v5 18/20] mfd: adp5585: support getting vdd regulator Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-18-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=1292; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=YHxZoknRry0Hvk65sFGbz6N2xfvPc6b8ZJ/D4iQv1WE=; b=0hM2FsIW6Az+gChfSNnyXhFkFS73Ok6JojvajuTuwM37Q8I9Hj+36R8H3GefYF4TgUIp6Yjxf jx8qmSVylyKBtXZApkm/XEbl+j+QdqzudGDMj1ruFXNMtGYRAxnBZgZ X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá Make sure we get and enable the VDD supply (if available). Reviewed-by: Lee Jones Signed-off-by: Nuno Sá --- drivers/mfd/adp5585.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c index 3a53bc895e60e6a10f797aebcc29b722906ff087..e4a725b9e1475be03cd26898faa7a7bb8de4319b 100644 --- a/drivers/mfd/adp5585.c +++ b/drivers/mfd/adp5585.c @@ -17,6 +17,7 @@ #include #include #include +#include #include enum { @@ -710,6 +711,10 @@ static int adp5585_i2c_probe(struct i2c_client *i2c) if (IS_ERR(regmap_config)) return PTR_ERR(regmap_config); + ret = devm_regulator_get_enable(&i2c->dev, "vdd"); + if (ret) + return ret; + adp5585->regmap = devm_regmap_init_i2c(i2c, regmap_config); if (IS_ERR(adp5585->regmap)) return dev_err_probe(&i2c->dev, PTR_ERR(adp5585->regmap), @@ -726,6 +731,7 @@ static int adp5585_i2c_probe(struct i2c_client *i2c) "Invalid device ID 0x%02x\n", id); adp5585->pin_usage = devm_bitmap_zalloc(&i2c->dev, adp5585->n_pins, GFP_KERNEL); + if (!adp5585->pin_usage) return -ENOMEM; From patchwork Sat Jun 14 14:36:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= X-Patchwork-Id: 896292 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF15B2E763E; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; cv=none; b=EHoS0SUsaC5DTD9MuV5nBGfquY3zmqVyfUT3eDu3X2PRFalpjtnP4Y8+zatNL8w9HF+iwJOXl5SigOuM6zGB/z4F9MojgS1UXt4iNWtLo/MiUPH1+xWMAKzgO9PYLGBluvR7mM14nSzKXdn4Yo7Pl+/JwxXG9m1gZeZRni6EPJQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749911831; c=relaxed/simple; bh=gqzuVzoAcoLMlqnde1DPNYsbEP4wBW42R1IzeJJN0Ss=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eUkY7wzvq5ZHXBMHBOXwWE36aREpG0UNF/+r/E8ogtr4z/m2d5o92Wnry4aFCePxt1TaLx0mvCeo4tiG5XnFza67m0aU5OtsQ8pbJrzq7y5vDbcB2Gb3YHP+3PTFN9WR+ycGZxF8gzMtu6G3AqH5UQJqpDcTiGluc4w7QR0PIrA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZPzjjRdQ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZPzjjRdQ" Received: by smtp.kernel.org (Postfix) with ESMTPS id 8414AC4CEEB; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749911831; bh=gqzuVzoAcoLMlqnde1DPNYsbEP4wBW42R1IzeJJN0Ss=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ZPzjjRdQMJk/evsxSz5FKviRMXwLcb/OR9UVYnm4RTHvELi5oyE1vhRwpmHSO8URq N2hPEXIqelD2a5VrQ5F9/wuAu3Lj1SMQ1J/KIY2y2y0rotS8hoq8ONvRMq4ag8g881 2ykULMCVW62aF6UjFkQWFxwt18pYcPutKiPBEUmL91vh1aCFT+FOYuDqqtW2uahlBK ndGUJqcT5qIHwb2gFPD+syVujX/NKfi4s8TIiz3YWOqcFuLE4Y/JaSyTcwZyOThccr LpVKfJrg5ycyJnnX4U+pGEltIZqz9hemQsgrU58ToIfktYcB4Bk6EVQU8nv2VeK+SW /1oVvUh+0D6uw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 77E57C7115A; Sat, 14 Jun 2025 14:37:11 +0000 (UTC) From: =?utf-8?q?Nuno_S=C3=A1_via_B4_Relay?= Date: Sat, 14 Jun 2025 15:36:11 +0100 Subject: [PATCH v5 20/20] mfd: adp5585: add support for a reset pin Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250614-dev-adp5589-fw-v5-20-7e9d84906268@analog.com> References: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> In-Reply-To: <20250614-dev-adp5589-fw-v5-0-7e9d84906268@analog.com> To: linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Linus Walleij , Bartosz Golaszewski , Dmitry Torokhov , Laurent Pinchart , Liu Ying X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1749911835; l=1501; i=nuno.sa@analog.com; s=20231116; h=from:subject:message-id; bh=crfo1L2pahKRVWGjCu62YKRA70uwp/eYBp6lSfb2ZXg=; b=YpVCDSwn/NhAMpqywvkSiSAH3Gcf+rqYezhvawl2t3ErttcxBcJsCKdbA/Bw2oK56cZtRih8X JksiYk6XFiiCqjDkSQJHPU6ei2S3jBfpZ86fkQmEBRti8ur6Kjoxy4y X-Developer-Key: i=nuno.sa@analog.com; a=ed25519; pk=3NQwYA013OUYZsmDFBf8rmyyr5iQlxV/9H4/Df83o1E= X-Endpoint-Received: by B4 Relay for nuno.sa@analog.com/20231116 with auth_id=100 X-Original-From: =?utf-8?q?Nuno_S=C3=A1?= Reply-To: nuno.sa@analog.com From: Nuno Sá Make sure to perform an Hardware reset during probe if the pin is given in FW. Signed-off-by: Nuno Sá --- drivers/mfd/adp5585.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c index e4a725b9e1475be03cd26898faa7a7bb8de4319b..f6dcdb632667120f4c6ce54812dc18083ca5d15f 100644 --- a/drivers/mfd/adp5585.c +++ b/drivers/mfd/adp5585.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -691,6 +692,7 @@ static int adp5585_i2c_probe(struct i2c_client *i2c) { struct regmap_config *regmap_config; struct adp5585_dev *adp5585; + struct gpio_desc *gpio; unsigned int id; int ret; @@ -715,6 +717,20 @@ static int adp5585_i2c_probe(struct i2c_client *i2c) if (ret) return ret; + gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + /* + * Note the timings are not documented anywhere in the datasheet. They are just + * reasonable values that work. + */ + if (gpio) { + fsleep(30); + gpiod_set_value_cansleep(gpio, 0); + fsleep(60); + } + adp5585->regmap = devm_regmap_init_i2c(i2c, regmap_config); if (IS_ERR(adp5585->regmap)) return dev_err_probe(&i2c->dev, PTR_ERR(adp5585->regmap),