From patchwork Wed Apr 30 09:03:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andr=C3=A9_Draszik?= X-Patchwork-Id: 886197 Received: from mail-ej1-f45.google.com (mail-ej1-f45.google.com [209.85.218.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A515621B19F for ; Wed, 30 Apr 2025 09:03:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746003797; cv=none; b=LLRXjxEUxMNalDvHTi26FF14Cqruyxwm3zhtT/NwN9IuYkf7FKSIxr9kp6BOw96+HD6q+qq1AErg2YJFlYgGcFNKMR76PAqG1jtRLJ2jqd9D8lLjULSMO9mEMc7102UoIrllsjtlMxVtb3wrtxtA4LBFp6lCsAWCbfI5l3jwZxw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746003797; c=relaxed/simple; bh=4SBDb8RMix1AfTeAapS22vbsprNHW5kDlKivkfzgJb4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LR3jle9mTixzfUyNi2crIC4ssxoxUnAXo/gaFjcqqe7J7IKMkf5nbk3utRwtTNWx+nkNXysWBGZP+zrB/6fpu4XMI5cxyEuZh0FTOTYVpKIMEBulZQIC7i7qJuT+V/7o/i+HQ8NU9Xgjjon4FXi00EVkt0puSuH9fGS9yObwz1M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=SCR2iUJo; arc=none smtp.client-ip=209.85.218.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="SCR2iUJo" Received: by mail-ej1-f45.google.com with SMTP id a640c23a62f3a-ac2bb7ca40bso1176348866b.3 for ; Wed, 30 Apr 2025 02:03:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1746003793; x=1746608593; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=UsPhnEzsIjMyr2jWNVlW883QIlYElONTjUn31M/bDFU=; b=SCR2iUJouxyuhKI6WT29nyLHmzdiyJvYz0wS2PbWU3IhUKJXILJm7DFm1JvPbEPUbN +YZhPJgw/cKXms9tA/5A4Vce8D6AtQVLpZMpt+a5eMmj9T9JMQ900kqNN21C9PUSKgl6 XweOc73qhilqfh11BHe2WICOT29sjPVcSvaC95w2Eeq2nRice1RA6s9pv5s5NBoJ80qP 9iSoDsiDiJVFm9VYClO/oAgAhoBdSEQpMjfw11/7bVs5tOWx//l0cEWN2783ffpGZKor MRKEO7XQBs6GzKwjO6oVzv+MBmS+l75eFnG0BIUFKUP7/QA8JET+RL1PmvGVQc/ebUTy ilJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746003793; x=1746608593; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UsPhnEzsIjMyr2jWNVlW883QIlYElONTjUn31M/bDFU=; b=ehRgNGIsdRQM2cnXRzBKUvT6poJSkEnduzvBqQ1v2sSEisE9JRicQ895dxAX7bfag9 tRNwSM0vzoBBVUang/jNiYxfbOuonTkUr4ABoUMMRvSCHvKoGS/8VUfTKEDjEJCZCXFN tBcU3oL9tAaJdYOMNSqe3FZ+k/eGYAyjjy7PQu4ip1vixatefi4hQux9eFuRSsvbZFL2 q/iAvvSGMZ1KGJ14w9Yyr287eSIlxh0AowI1T095fhhGA8D78vGhOlYDHYw14uoISSgk 2FeaN0vXkfMONs95xCroCj19cZZKPZXjOORP68STRPFmymptG4SXNmYJt/3FPQv+1jfK VfCg== X-Forwarded-Encrypted: i=1; AJvYcCVWTOSr/iJMrfvc5gTpGCs00ZPcMVt7Kj3EuM+lo4JylWPS31tO9wdHL8WTDYLkKnEkZ3Cqh+SA7Yp/@vger.kernel.org X-Gm-Message-State: AOJu0YyHcrE1YwvHkrU+3BdiDFmralgLRYBBWPxofIn1hI9wq6H+3bwr 4I4jmozIy5RVfbe6uEFytXa566gI0jVYYaqddohClfTM78+AGePI+pruM6ss08Y= X-Gm-Gg: ASbGnct3iGZyHjqSqD5JWZZptUrPTsJh8KtKjNVs0Dr/ZUup3qwudE53EX4uXy2wogX AB4wrw5IqfqyTi9/t/9FzmsbOjpqdxjofPCkJc6H5PELQpq7R7mEqvSDLDJ1PShCU659kfQiN9m scHKI2xOVuqvvJ+y6XyQoM7r/nJivzuwc37LQA0GLbAEvakUuNsAFtXQUv9C1BMUwWnlwXzJ27i ttHTz8RnZCqIKHncndPXo8zjnyO4k/NcTihLBU3GQLGgoMlGjjiGgN8ZuBLKF1RMRH/Athqns7x oQWQa52qW3akkCiFX1j4fee57RoyA9ITOvMN5yy/oAdgxwISajHKzFixrkqZopchzsZL5P1bSvC ogPUbKO4TsowI4OwuRXvmz4dM X-Google-Smtp-Source: AGHT+IHVsZ8xYEbEizsgZIRrUswi5I9gaZlF8LH7SsKiLHMHKzkdmybyODeG5bKN3kGAyjZ7wypovA== X-Received: by 2002:a17:907:970d:b0:acb:66ea:5786 with SMTP id a640c23a62f3a-acedc6342a5mr263771366b.31.1746003792448; Wed, 30 Apr 2025 02:03:12 -0700 (PDT) Received: from puffmais.c.googlers.com (8.239.204.35.bc.googleusercontent.com. [35.204.239.8]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ace6e41bbb6sm889676766b.28.2025.04.30.02.03.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Apr 2025 02:03:12 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Wed, 30 Apr 2025 10:03:08 +0100 Subject: [PATCH v9 1/6] dt-bindings: gpio: add max77759 binding Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250430-max77759-mfd-v9-1-639763e23598@linaro.org> References: <20250430-max77759-mfd-v9-0-639763e23598@linaro.org> In-Reply-To: <20250430-max77759-mfd-v9-0-639763e23598@linaro.org> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , Srinivas Kandagatla , Kees Cook , "Gustavo A. R. Silva" Cc: Peter Griffin , Tudor Ambarus , Will McVicker , kernel-team@android.com, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-gpio@vger.kernel.org, linux-hardening@vger.kernel.org, =?utf-8?q?And?= =?utf-8?q?r=C3=A9_Draszik?= , Bartosz Golaszewski X-Mailer: b4 0.14.2 The Maxim MAX77759 is a companion PMIC for USB Type-C applications and includes Battery Charger, Fuel Gauge, temperature sensors, USB Type-C Port Controller (TCPC), NVMEM, and a GPIO expander. This describes its GPIO module. Reviewed-by: Rob Herring (Arm) Acked-by: Bartosz Golaszewski Signed-off-by: André Draszik --- v2: * drop 'interrupts' property and sort properties alphabetically --- .../bindings/gpio/maxim,max77759-gpio.yaml | 44 ++++++++++++++++++++++ MAINTAINERS | 6 +++ 2 files changed, 50 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/maxim,max77759-gpio.yaml b/Documentation/devicetree/bindings/gpio/maxim,max77759-gpio.yaml new file mode 100644 index 0000000000000000000000000000000000000000..55734190d5ebdbc351e1f91675dddd8a9db80cd7 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/maxim,max77759-gpio.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/maxim,max77759-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX77759 GPIO + +maintainers: + - André Draszik + +description: | + This module is part of the MAX77759 PMIC. For additional information, see + Documentation/devicetree/bindings/mfd/maxim,max77759.yaml. + + The MAX77759 is a PMIC integrating, amongst others, a GPIO controller + including interrupt support for 2 GPIO lines. + +properties: + compatible: + const: maxim,max77759-gpio + + "#gpio-cells": + const: 2 + + gpio-controller: true + + gpio-line-names: + minItems: 1 + maxItems: 2 + + "#interrupt-cells": + const: 2 + + interrupt-controller: true + +required: + - compatible + - "#gpio-cells" + - gpio-controller + - "#interrupt-cells" + - interrupt-controller + +additionalProperties: false diff --git a/MAINTAINERS b/MAINTAINERS index 906881b6c5cb6ff743e13b251873b89138c69a1c..0c7bf694468e9798946baecdfd03d6eacdba2ce3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14663,6 +14663,12 @@ F: Documentation/devicetree/bindings/mfd/maxim,max77714.yaml F: drivers/mfd/max77714.c F: include/linux/mfd/max77714.h +MAXIM MAX77759 PMIC MFD DRIVER +M: André Draszik +L: linux-kernel@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/*/maxim,max77759*.yaml + MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER M: Javier Martinez Canillas L: linux-kernel@vger.kernel.org From patchwork Wed Apr 30 09:03:10 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andr=C3=A9_Draszik?= X-Patchwork-Id: 886196 Received: from mail-ej1-f41.google.com (mail-ej1-f41.google.com [209.85.218.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C3CA21B9F2 for ; Wed, 30 Apr 2025 09:03:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746003798; cv=none; b=tf12Y6J6vcbt2fo5/zUlcH2Lm3vFrON5ErU5YFsFcVrMnj4d7U+p8cWWNJQ/l31eKONtw9dtKcVix5NaTyFDKKyL7R5Ih/JS/23q0vnD7cIXl2tn+HPUb7RjCp8GLLm6qtdGWZr9VZMng2KPLi1d7SA4RTALm14mg173zs90T34= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746003798; c=relaxed/simple; bh=bFksOeknh8d+JfpwdhA3LClj8Y8cCin0vyzLAmX/vl4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BFbvjn/oTuofUFOqOQq9X9SGgXbOUoNZ5iNkrf23cFunVL5hsR0xYkTOiNpeTALmhB4LTFaUJxLQH5N5OpsFUcyG2ZhSjaS3t5ETKMqYpNw95Zph3Mw5D+n09yQFJPfpgCgNKvjOiqKogOPYYTm1r2AOo2+jKlyxamyOa8O0ysU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=SpnR9hNl; arc=none smtp.client-ip=209.85.218.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="SpnR9hNl" Received: by mail-ej1-f41.google.com with SMTP id a640c23a62f3a-ac2aeada833so148133466b.0 for ; Wed, 30 Apr 2025 02:03:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1746003794; x=1746608594; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=kyiytjDRdFd6s+6c7xd37xzCdnxjjI1OzqbZfUcJ7Kk=; b=SpnR9hNl9mWf+MlzGEOO3WnMpHiOBSGnU437elz744n2CDKB5ZyIS62qos4elyYpZO m2aQxpVcXAxbhg0eUcNDuYhjJ0yPxl5Km1SA47YQ6EG3fURKHyWChpBw+jpSTzstIsE1 KhL4KRQdgnc5bkNkubk3ixyYV/NVJcXwKG1dwNbvlu85t+ZXqsSSyzCe4XL73ccrA54l aOwRG8ByaUMAFGl3eVSKFgkLsWLBBeTaboTQcSM4seJiPhrjNnSv5ldBEx5+jaEc8a5B vVFkDvyHRUw5WXoL4blNNoZroeU3ZBVc8osHJs8gbIToUFuJoWwVM3FUZPqwXPI1Il/x WfVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746003794; x=1746608594; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=kyiytjDRdFd6s+6c7xd37xzCdnxjjI1OzqbZfUcJ7Kk=; b=ApO7v4NCtyU6js6qcdyu2naXkWuLd9DhAYEifqn7I+f3p5VHtuNgrYdUv7dTweapKl FbWH/eVGrKPCab9Xt/CcD1o/UpBof9jYCMPWPlDyCzn6YyportB1eJiT+uN3g3C+3Ptt SFrTKPQwALbkTpG3ZNoTv0bwT3wkQaOGtU8sOKlcPxh2xVpT+x94LrDbDUApAnkI36JM bFf1Av0QV2mxREt1uPWjQg8Y7MYlHN9YgnpAQ5XEv9dZwIRfoNWE3gvrmDfdq5mTLwOj CgrW9cjrUgNg+Gbtra9I5Tb5d6BBs9h3kVtIrX02e0Yx8X8wFA7blKHJGnxvw6/wkfHe /HTg== X-Forwarded-Encrypted: i=1; AJvYcCURwczjU0bie7TrkXOYym/Z9GJ4Zd5uDv9uLZp3fpwBv72Hxl0jUlq3uoFYUxPvbJsjAjie6PAIhJSk@vger.kernel.org X-Gm-Message-State: AOJu0YzPIVKOrwfMzkSE0NxmvIzptnEhOWJoHiMPXcY2W+Am4DFTOMha Ci40McdO4s1qs22TZ516T71CQHv/rSWXhUcJQNFnv9EY5iY1Dn9eTgB5PJFmURQ= X-Gm-Gg: ASbGncsLu0scJDnRxyPgN0prfKdGUjs/ac55B5dcWQjz1U9gl3xr5cQIbbjRSfXhSGa Qj3ZD2/a67h/IxAvaena3QMOAf1tfhtspVJpI4Lkuz8Uz/FQyrpkAfBszGn4xNyPdd3NDK9QOpz xH0dlj1IVibQeb5CUM96bHeFa0ZDlBlL6lJto+6ePAuOAEvw7Hi4+KWE2CgGX6uhz5d7wHvmkTB um4YlSOHQbeVR3KB8K8qh9NYMXHRtK+HYw8Ejs59VdxSU/K3OiJzWNcYybOS5hNw5dQRefmBnHS VCjPk0a4rFzpjG4UZwHSI194EtxP8aiOLZre8/oaV/rVzTT+m+2c2tQ9nPVde3VQduLO/tnXfi9 l3XJajOakTHWkjwETphl6wwaA X-Google-Smtp-Source: AGHT+IGcixekqMbiCwTt0euFgr8qyktPoka758m284mP8XwKbyfXBT71rs+QPFdZrVWILYzT2lipaw== X-Received: by 2002:a17:907:72ca:b0:acb:37ae:619c with SMTP id a640c23a62f3a-acedf6be04dmr180503466b.15.1746003793663; Wed, 30 Apr 2025 02:03:13 -0700 (PDT) Received: from puffmais.c.googlers.com (8.239.204.35.bc.googleusercontent.com. [35.204.239.8]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ace6e41bbb6sm889676766b.28.2025.04.30.02.03.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Apr 2025 02:03:13 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Wed, 30 Apr 2025 10:03:10 +0100 Subject: [PATCH v9 3/6] dt-bindings: mfd: add max77759 binding Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250430-max77759-mfd-v9-3-639763e23598@linaro.org> References: <20250430-max77759-mfd-v9-0-639763e23598@linaro.org> In-Reply-To: <20250430-max77759-mfd-v9-0-639763e23598@linaro.org> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , Srinivas Kandagatla , Kees Cook , "Gustavo A. R. Silva" Cc: Peter Griffin , Tudor Ambarus , Will McVicker , kernel-team@android.com, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-gpio@vger.kernel.org, linux-hardening@vger.kernel.org, =?utf-8?q?And?= =?utf-8?q?r=C3=A9_Draszik?= X-Mailer: b4 0.14.2 The Maxim MAX77759 is a companion PMIC for USB Type-C applications and includes Battery Charger, Fuel Gauge, temperature sensors, USB Type-C Port Controller (TCPC), NVMEM, and a GPIO expander. This describes the top-level device. Reviewed-by: Rob Herring (Arm) Signed-off-by: André Draszik --- v3: * drop gpio-controller and gpio-cells, GPIO is provided by the child (Rob) v2: * rename expected nvmem subdev nodename to 'nvmem-0' I'd have preferred just 'nvmem', but that matches nvmem-consumer.yaml and fails validation. Note: MAINTAINERS doesn't need updating, the binding update for the first leaf device (gpio) adds a wildcard matching all max77759 bindings --- .../devicetree/bindings/mfd/maxim,max77759.yaml | 99 ++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml new file mode 100644 index 0000000000000000000000000000000000000000..525de9ab3c2b7b431e48497330640857540625b1 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/maxim,max77759.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX77759 PMIC for USB Type-C applications + +maintainers: + - André Draszik + +description: | + This is a part of device tree bindings for the MAX77759 companion Power + Management IC for USB Type-C applications. + + The MAX77759 includes Battery Charger, Fuel Gauge, temperature sensors, USB + Type-C Port Controller (TCPC), NVMEM, and a GPIO expander. + +properties: + compatible: + const: maxim,max77759 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + reg: + maxItems: 1 + + gpio: + $ref: /schemas/gpio/maxim,max77759-gpio.yaml + + nvmem-0: + $ref: /schemas/nvmem/maxim,max77759-nvmem.yaml + +required: + - compatible + - interrupts + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@66 { + compatible = "maxim,max77759"; + reg = <0x66>; + interrupts-extended = <&gpa8 3 IRQ_TYPE_LEVEL_LOW>; + + interrupt-controller; + #interrupt-cells = <2>; + + gpio { + compatible = "maxim,max77759-gpio"; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + nvmem-0 { + compatible = "maxim,max77759-nvmem"; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + reboot-mode@0 { + reg = <0x0 0x4>; + }; + + boot-reason@4 { + reg = <0x4 0x4>; + }; + + shutdown-user-flag@8 { + reg = <0x8 0x1>; + }; + + rsoc@10 { + reg = <0xa 0x2>; + }; + }; + }; + }; + }; From patchwork Wed Apr 30 09:03:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andr=C3=A9_Draszik?= X-Patchwork-Id: 886195 Received: from mail-ej1-f54.google.com (mail-ej1-f54.google.com [209.85.218.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 427B621CC4F for ; Wed, 30 Apr 2025 09:03:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746003801; cv=none; b=kdZUGtCie46hIeuwuf+3/HGhrwW0ZcQDSpzvEWSI+TOQ45G31m4rQ24uE+M8BMjUzivVbxhIOdJ0OC94SZ937fLogvJ/k+9GdPFiWJk70jT0Kd2dDqXgRMsE+VfiXuSC1/YRT3/0QHltobf0qZollL9gYC0i9MRcxWB/xp/4kYU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746003801; c=relaxed/simple; bh=XqoIewFhHfNmVYOpePvM3e9Sq5HQyuI/EA+aQi/NHYc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KyJY3oJofFy5SvoEHXeENmURNfA91z5idoHse7galClSAbihIBIZtdc9azTvnjg2MKo0WauhXeWkFJeM1qQe8GUd+f+tEUOak9coeRmoM8Zvmd4M+PkrSDoaK1Mnz/Ok9ilv1Yc0yyiy8uSfCwXIwGsoG1qEl0pMR2HgFpiC/DA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=ysRjeioy; arc=none smtp.client-ip=209.85.218.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="ysRjeioy" Received: by mail-ej1-f54.google.com with SMTP id a640c23a62f3a-ac2af2f15d1so878791566b.1 for ; Wed, 30 Apr 2025 02:03:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1746003795; x=1746608595; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=51WfKLwzr7VTpMyREiuoFgn/xarlpLYCgMiyf4+NwUo=; b=ysRjeioypI0pg500Fe16vbUoa78LiB8Hy058FZsJHc8Q+uMSzSDLY1pKlSv24FigoO sqUsqqOp9FhPkN72h6ppw1AFxD9QjzT1h+kZTHUjqEYJcJAZBKFniCpi7sCBUWQ5517C 8tat7akAmgqvKmxzi69jGIafyhdDDSYzgYyMPzS0ZludCrUKQJ1vHAc96rSimFrT6iq1 NGkRrT7fh4/sxW4IUY0utPTBoa9wTUfPCemSn8R5W2ZAalSnWWM/Ojl6AJ3WwUHRCYVn Y5rbTbWsQc2gRmDZ+IikkXKdVP5M85UpFZaFM7mveKboDEkLRxTVBCy5bsKOLOHdUuA0 yFgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746003795; x=1746608595; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=51WfKLwzr7VTpMyREiuoFgn/xarlpLYCgMiyf4+NwUo=; b=BZQB6KB1v++z7xVrhltfJaCt1SLAUJPWC4R+tdzkrDMABs4MNxhEY8IUPOXkJ14Ci6 ne1ZKtuexC4G8HCQdFlUSKu+x57IsgKDgt+2NEJJK0RdRu6eb9zDROviOoeOc7tRcpQg sCc5IMdvFu9wr83ZWBsk3m7chm/af2fvsXP6vtRM8MtynYpriB6n7vdam7XYwbAJ7nvu qhAKbiH93UD32kNSTEcoWAfNvyWk/Onszhdf0pCpG7I6AUI8oRcmTlovK+PkAJPnzYqV j1tVQeqyq6wJVUFXyJTdHWNY6SDYJ1FhjAlcnO3f7bUULfJaD2fb0uBcnM/jT9YIDjlf Eaog== X-Forwarded-Encrypted: i=1; AJvYcCXFmwuVrLEcSuGJu8uZUEXi/xKtmelG400WoH8787sCpCNcBo9rYqf3NLxUcNbJxwCmpg0sILvvwJhy@vger.kernel.org X-Gm-Message-State: AOJu0YzQy2YWN8onBibx+atGJfOBQMczJCItGv3BCVbt4WM1TZLMimmY 2hTNVDNcaWCqdyq8GvF/UCniPFeQbhFn/6NznzUEWiHdUy6JzD8T9UYXvwYe0c0= X-Gm-Gg: ASbGnctF43+niUVarw3mczeEpWSRNF11hVvgs9ZIsLA9Ih7IZXxQ/bMzdVOSF6O5DtF oZ9qn8+tSUbpwv7MdCH9Dv6MC5k5JYx4RXfhGbPcBzu4IGAisEsfvBnS49LLW3oH+r1zntAqw7Q /JpPKl5W3nZxHmydPzVGThP/TDLT2GcgGzL4oFgNi+fNJ4VXTefKtyolWzz13YTucZp5SR7bGf4 psQ+rD3r56Xuo8pIFDaO8pX7JilT648WSRaH0Bakh1GjNrFcx38MdZXC49JLXWy1p9CaogyeaW1 06aqosfpTk7dnka8N+St888eIWn9taAulrBRNHXizPFXuh8+6MTTDIEcaDLxnWtCjmrJf8x//su rS2w+PHMuk0n2bGMTEVj6DsxB X-Google-Smtp-Source: AGHT+IEzi5VezjW91w/fsxeBdw9eUtZwPcwXU11ZQMX0lMnSeiOSz5XWRXwqOY+cBo44nlRQ+nNexA== X-Received: by 2002:a17:907:3f98:b0:ac7:3323:cfd8 with SMTP id a640c23a62f3a-acedc5cf5ffmr258471566b.16.1746003794947; Wed, 30 Apr 2025 02:03:14 -0700 (PDT) Received: from puffmais.c.googlers.com (8.239.204.35.bc.googleusercontent.com. [35.204.239.8]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ace6e41bbb6sm889676766b.28.2025.04.30.02.03.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Apr 2025 02:03:14 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Wed, 30 Apr 2025 10:03:12 +0100 Subject: [PATCH v9 5/6] gpio: max77759: add Maxim MAX77759 gpio driver Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250430-max77759-mfd-v9-5-639763e23598@linaro.org> References: <20250430-max77759-mfd-v9-0-639763e23598@linaro.org> In-Reply-To: <20250430-max77759-mfd-v9-0-639763e23598@linaro.org> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , Srinivas Kandagatla , Kees Cook , "Gustavo A. R. Silva" Cc: Peter Griffin , Tudor Ambarus , Will McVicker , kernel-team@android.com, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-gpio@vger.kernel.org, linux-hardening@vger.kernel.org, =?utf-8?q?And?= =?utf-8?q?r=C3=A9_Draszik?= , Bartosz Golaszewski X-Mailer: b4 0.14.2 The Maxim MAX77759 is a companion PMIC for USB Type-C applications and includes Battery Charger, Fuel Gauge, temperature sensors, USB Type-C Port Controller (TCPC), NVMEM, and a GPIO expander. This driver supports the GPIO functions using the platform device registered by the core MFD driver. Acked-by: Bartosz Golaszewski Signed-off-by: André Draszik --- v8: * switch to gpio_chip::set_rv() (Bartosz) * replace MODULE_ALIAS() with .id_table (Krzysztof) * drop previous tags v5: * follow API updates of max77759 core driver v3: * drop duplicate init of 'handled' variable in irq handler * use boolean with IRQ_RETVAL() (Linus) * drop 'virq' variable inside irq handler to avoid confusion (Linus) * drop assignment of struct gpio_chip::owner (Linus) v2: * fix max77759_gpio_direction_from_control() * add missing error handling of devm_mutex_init() (Christophe) * align sentinel in max77759_gpio_of_id[] with other max77759 drivers (Christophe) --- MAINTAINERS | 1 + drivers/gpio/Kconfig | 13 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-max77759.c | 530 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 545 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1259d09e700a21215e8ae2facef858df5304346e..0db5e1fe64930e85265913e6a7dd2669c645cf42 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14668,6 +14668,7 @@ M: André Draszik L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/*/maxim,max77759*.yaml +F: drivers/gpio/gpio-max77759.c F: drivers/mfd/max77759.c F: include/linux/mfd/max77759.h diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9ae806f45e19c1494d156b7f04b1882be68d3e3f..bbc71cdde9ed66b2fe69dcbc7508d51690d2cfa4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1483,6 +1483,19 @@ config GPIO_MAX77650 GPIO driver for MAX77650/77651 PMIC from Maxim Semiconductor. These chips have a single pin that can be configured as GPIO. +config GPIO_MAX77759 + tristate "Maxim Integrated MAX77759 GPIO support" + depends on MFD_MAX77759 + default MFD_MAX77759 + select GPIOLIB_IRQCHIP + help + GPIO driver for MAX77759 PMIC from Maxim Integrated. + There are two GPIOs available on these chips in total, both of + which can also generate interrupts. + + This driver can also be built as a module. If so, the module will be + called gpio-max77759. + config GPIO_PALMAS bool "TI PALMAS series PMICs GPIO" depends on MFD_PALMAS diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9aabbb9cb4c61ea57833adf2edb265c204b42cdf..1abae4477ed76b88aff08e83f6d41e58d0b71ff5 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o +obj-$(CONFIG_GPIO_MAX77759) += gpio-max77759.o obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o diff --git a/drivers/gpio/gpio-max77759.c b/drivers/gpio/gpio-max77759.c new file mode 100644 index 0000000000000000000000000000000000000000..7fe8e6f697d044ebf9c620f41e59f150a6ae086a --- /dev/null +++ b/drivers/gpio/gpio-max77759.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright 2020 Google Inc +// Copyright 2025 Linaro Ltd. +// +// GPIO driver for Maxim MAX77759 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX77759_N_GPIOS ARRAY_SIZE(max77759_gpio_line_names) +static const char * const max77759_gpio_line_names[] = { "GPIO5", "GPIO6" }; + +struct max77759_gpio_chip { + struct regmap *map; + struct max77759 *max77759; + struct gpio_chip gc; + struct mutex maxq_lock; /* protect MaxQ r/m/w operations */ + + struct mutex irq_lock; /* protect irq bus */ + int irq_mask; + int irq_mask_changed; + int irq_trig; + int irq_trig_changed; +}; + +#define MAX77759_GPIOx_TRIGGER(offs, val) (((val) & 1) << (offs)) +#define MAX77759_GPIOx_TRIGGER_MASK(offs) MAX77759_GPIOx_TRIGGER(offs, ~0) +enum max77759_trigger_gpio_type { + MAX77759_GPIO_TRIGGER_RISING = 0, + MAX77759_GPIO_TRIGGER_FALLING = 1 +}; + +#define MAX77759_GPIOx_DIR(offs, dir) (((dir) & 1) << (2 + (3 * (offs)))) +#define MAX77759_GPIOx_DIR_MASK(offs) MAX77759_GPIOx_DIR(offs, ~0) +enum max77759_control_gpio_dir { + MAX77759_GPIO_DIR_IN = 0, + MAX77759_GPIO_DIR_OUT = 1 +}; + +#define MAX77759_GPIOx_OUTVAL(offs, val) (((val) & 1) << (3 + (3 * (offs)))) +#define MAX77759_GPIOx_OUTVAL_MASK(offs) MAX77759_GPIOx_OUTVAL(offs, ~0) + +#define MAX77759_GPIOx_INVAL_MASK(offs) (BIT(4) << (3 * (offs))) + +static int max77759_gpio_maxq_gpio_trigger_read(struct max77759_gpio_chip *chip) +{ + DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length, 1); + DEFINE_FLEX(struct max77759_maxq_response, rsp, rsp, length, 2); + int ret; + + cmd->cmd[0] = MAX77759_MAXQ_OPCODE_GPIO_TRIGGER_READ; + + ret = max77759_maxq_command(chip->max77759, cmd, rsp); + if (ret < 0) + return ret; + + return rsp->rsp[1]; +} + +static int max77759_gpio_maxq_gpio_trigger_write(struct max77759_gpio_chip *chip, + u8 trigger) +{ + DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length, 2); + + cmd->cmd[0] = MAX77759_MAXQ_OPCODE_GPIO_TRIGGER_WRITE; + cmd->cmd[1] = trigger; + + return max77759_maxq_command(chip->max77759, cmd, NULL); +} + +static int max77759_gpio_maxq_gpio_control_read(struct max77759_gpio_chip *chip) +{ + DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length, 1); + DEFINE_FLEX(struct max77759_maxq_response, rsp, rsp, length, 2); + int ret; + + cmd->cmd[0] = MAX77759_MAXQ_OPCODE_GPIO_CONTROL_READ; + + ret = max77759_maxq_command(chip->max77759, cmd, rsp); + if (ret < 0) + return ret; + + return rsp->rsp[1]; +} + +static int max77759_gpio_maxq_gpio_control_write(struct max77759_gpio_chip *chip, + u8 ctrl) +{ + DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length, 2); + + cmd->cmd[0] = MAX77759_MAXQ_OPCODE_GPIO_CONTROL_WRITE; + cmd->cmd[1] = ctrl; + + return max77759_maxq_command(chip->max77759, cmd, NULL); +} + +static int +max77759_gpio_direction_from_control(int ctrl, unsigned int offset) +{ + enum max77759_control_gpio_dir dir; + + dir = !!(ctrl & MAX77759_GPIOx_DIR_MASK(offset)); + return ((dir == MAX77759_GPIO_DIR_OUT) + ? GPIO_LINE_DIRECTION_OUT + : GPIO_LINE_DIRECTION_IN); +} + +static int max77759_gpio_get_direction(struct gpio_chip *gc, + unsigned int offset) +{ + struct max77759_gpio_chip *chip = gpiochip_get_data(gc); + int ctrl; + + ctrl = max77759_gpio_maxq_gpio_control_read(chip); + if (ctrl < 0) + return ctrl; + + return max77759_gpio_direction_from_control(ctrl, offset); +} + +static int max77759_gpio_direction_helper(struct gpio_chip *gc, + unsigned int offset, + enum max77759_control_gpio_dir dir, + int value) +{ + struct max77759_gpio_chip *chip = gpiochip_get_data(gc); + int ctrl, new_ctrl; + + guard(mutex)(&chip->maxq_lock); + + ctrl = max77759_gpio_maxq_gpio_control_read(chip); + if (ctrl < 0) + return ctrl; + + new_ctrl = ctrl & ~MAX77759_GPIOx_DIR_MASK(offset); + new_ctrl |= MAX77759_GPIOx_DIR(offset, dir); + + if (dir == MAX77759_GPIO_DIR_OUT) { + new_ctrl &= ~MAX77759_GPIOx_OUTVAL_MASK(offset); + new_ctrl |= MAX77759_GPIOx_OUTVAL(offset, value); + } + + if (new_ctrl == ctrl) + return 0; + + return max77759_gpio_maxq_gpio_control_write(chip, new_ctrl); +} + +static int max77759_gpio_direction_input(struct gpio_chip *gc, + unsigned int offset) +{ + return max77759_gpio_direction_helper(gc, offset, + MAX77759_GPIO_DIR_IN, -1); +} + +static int max77759_gpio_direction_output(struct gpio_chip *gc, + unsigned int offset, int value) +{ + return max77759_gpio_direction_helper(gc, offset, + MAX77759_GPIO_DIR_OUT, value); +} + +static int max77759_gpio_get_value(struct gpio_chip *gc, unsigned int offset) +{ + struct max77759_gpio_chip *chip = gpiochip_get_data(gc); + int ctrl, mask; + + ctrl = max77759_gpio_maxq_gpio_control_read(chip); + if (ctrl < 0) + return ctrl; + + /* + * The input status bit doesn't reflect the pin state when the GPIO is + * configured as an output. Check the direction, and inspect the input + * or output bit accordingly. + */ + mask = ((max77759_gpio_direction_from_control(ctrl, offset) + == GPIO_LINE_DIRECTION_IN) + ? MAX77759_GPIOx_INVAL_MASK(offset) + : MAX77759_GPIOx_OUTVAL_MASK(offset)); + + return !!(ctrl & mask); +} + +static int max77759_gpio_set_value(struct gpio_chip *gc, + unsigned int offset, int value) +{ + struct max77759_gpio_chip *chip = gpiochip_get_data(gc); + int ctrl, new_ctrl; + + guard(mutex)(&chip->maxq_lock); + + ctrl = max77759_gpio_maxq_gpio_control_read(chip); + if (ctrl < 0) + return ctrl; + + new_ctrl = ctrl & ~MAX77759_GPIOx_OUTVAL_MASK(offset); + new_ctrl |= MAX77759_GPIOx_OUTVAL(offset, value); + + if (new_ctrl == ctrl) + return 0; + + return max77759_gpio_maxq_gpio_control_write(chip, new_ctrl); +} + +static void max77759_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + chip->irq_mask &= ~MAX77759_MAXQ_REG_UIC_INT1_GPIOxI_MASK(hwirq); + chip->irq_mask |= MAX77759_MAXQ_REG_UIC_INT1_GPIOxI(hwirq, 1); + chip->irq_mask_changed |= MAX77759_MAXQ_REG_UIC_INT1_GPIOxI(hwirq, 1); + + gpiochip_disable_irq(gc, hwirq); +} + +static void max77759_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + gpiochip_enable_irq(gc, hwirq); + + chip->irq_mask &= ~MAX77759_MAXQ_REG_UIC_INT1_GPIOxI_MASK(hwirq); + chip->irq_mask |= MAX77759_MAXQ_REG_UIC_INT1_GPIOxI(hwirq, 0); + chip->irq_mask_changed |= MAX77759_MAXQ_REG_UIC_INT1_GPIOxI(hwirq, 1); +} + +static int max77759_gpio_set_irq_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + chip->irq_trig &= ~MAX77759_GPIOx_TRIGGER_MASK(hwirq); + switch (type) { + case IRQ_TYPE_EDGE_RISING: + chip->irq_trig |= MAX77759_GPIOx_TRIGGER(hwirq, + MAX77759_GPIO_TRIGGER_RISING); + break; + + case IRQ_TYPE_EDGE_FALLING: + chip->irq_trig |= MAX77759_GPIOx_TRIGGER(hwirq, + MAX77759_GPIO_TRIGGER_FALLING); + break; + + default: + return -EINVAL; + } + + chip->irq_trig_changed |= MAX77759_GPIOx_TRIGGER(hwirq, 1); + + return 0; +} + +static void max77759_gpio_bus_lock(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip = gpiochip_get_data(gc); + + mutex_lock(&chip->irq_lock); +} + +static int max77759_gpio_bus_sync_unlock_helper(struct gpio_chip *gc, + struct max77759_gpio_chip *chip) + __must_hold(&chip->maxq_lock) +{ + int ctrl, trigger, new_trigger, new_ctrl; + unsigned long irq_trig_changed; + int offset; + int ret; + + lockdep_assert_held(&chip->maxq_lock); + + ctrl = max77759_gpio_maxq_gpio_control_read(chip); + trigger = max77759_gpio_maxq_gpio_trigger_read(chip); + if (ctrl < 0 || trigger < 0) { + dev_err(gc->parent, "failed to read current state: %d / %d\n", + ctrl, trigger); + return (ctrl < 0) ? ctrl : trigger; + } + + new_trigger = trigger & ~chip->irq_trig_changed; + new_trigger |= (chip->irq_trig & chip->irq_trig_changed); + + /* change GPIO direction if required */ + new_ctrl = ctrl; + irq_trig_changed = chip->irq_trig_changed; + for_each_set_bit(offset, &irq_trig_changed, MAX77759_N_GPIOS) { + new_ctrl &= ~MAX77759_GPIOx_DIR_MASK(offset); + new_ctrl |= MAX77759_GPIOx_DIR(offset, MAX77759_GPIO_DIR_IN); + } + + if (new_trigger != trigger) { + ret = max77759_gpio_maxq_gpio_trigger_write(chip, new_trigger); + if (ret) { + dev_err(gc->parent, + "failed to write new trigger: %d\n", ret); + return ret; + } + } + + if (new_ctrl != ctrl) { + ret = max77759_gpio_maxq_gpio_control_write(chip, new_ctrl); + if (ret) { + dev_err(gc->parent, + "failed to write new control: %d\n", ret); + return ret; + } + } + + chip->irq_trig_changed = 0; + + return 0; +} + +static void max77759_gpio_bus_sync_unlock(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip = gpiochip_get_data(gc); + int ret; + + scoped_guard(mutex, &chip->maxq_lock) { + ret = max77759_gpio_bus_sync_unlock_helper(gc, chip); + if (ret) + goto out_unlock; + } + + ret = regmap_update_bits(chip->map, + MAX77759_MAXQ_REG_UIC_INT1_M, + chip->irq_mask_changed, chip->irq_mask); + if (ret) { + dev_err(gc->parent, + "failed to update UIC_INT1 irq mask: %d\n", ret); + goto out_unlock; + } + + chip->irq_mask_changed = 0; + +out_unlock: + mutex_unlock(&chip->irq_lock); +} + +static void max77759_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + seq_puts(p, dev_name(gc->parent)); +} + +static const struct irq_chip max77759_gpio_irq_chip = { + .irq_mask = max77759_gpio_irq_mask, + .irq_unmask = max77759_gpio_irq_unmask, + .irq_set_type = max77759_gpio_set_irq_type, + .irq_bus_lock = max77759_gpio_bus_lock, + .irq_bus_sync_unlock = max77759_gpio_bus_sync_unlock, + .irq_print_chip = max77759_gpio_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static irqreturn_t max77759_gpio_irqhandler(int irq, void *data) +{ + struct max77759_gpio_chip *chip = data; + struct gpio_chip *gc = &chip->gc; + bool handled = false; + + /* iterate until no interrupt is pending */ + while (true) { + unsigned int uic_int1; + int ret; + unsigned long pending; + int offset; + + ret = regmap_read(chip->map, MAX77759_MAXQ_REG_UIC_INT1, + &uic_int1); + if (ret < 0) { + dev_err_ratelimited(gc->parent, + "failed to read IRQ status: %d\n", + ret); + /* + * If !handled, we have looped not even once, which + * means we should return IRQ_NONE in that case (and + * of course IRQ_HANDLED otherwise). + */ + return IRQ_RETVAL(handled); + } + + pending = uic_int1; + pending &= (MAX77759_MAXQ_REG_UIC_INT1_GPIO6I + | MAX77759_MAXQ_REG_UIC_INT1_GPIO5I); + if (!pending) + break; + + for_each_set_bit(offset, &pending, MAX77759_N_GPIOS) { + /* + * ACK interrupt by writing 1 to bit 'offset', all + * others need to be written as 0. This needs to be + * done unconditionally hence regmap_set_bits() is + * inappropriate here. + */ + regmap_write(chip->map, MAX77759_MAXQ_REG_UIC_INT1, + BIT(offset)); + + handle_nested_irq(irq_find_mapping(gc->irq.domain, + offset)); + + handled = true; + } + } + + return IRQ_RETVAL(handled); +} + +static int max77759_gpio_probe(struct platform_device *pdev) +{ + struct max77759_gpio_chip *chip; + int irq; + struct gpio_irq_chip *girq; + int ret; + unsigned long irq_flags; + struct irq_data *irqd; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->map = dev_get_regmap(pdev->dev.parent, "maxq"); + if (!chip->map) + return dev_err_probe(&pdev->dev, -ENODEV, "Missing regmap\n"); + + irq = platform_get_irq_byname(pdev, "GPI"); + if (irq < 0) + return dev_err_probe(&pdev->dev, irq, "Failed to get IRQ\n"); + + chip->max77759 = dev_get_drvdata(pdev->dev.parent); + ret = devm_mutex_init(&pdev->dev, &chip->maxq_lock); + if (ret) + return ret; + ret = devm_mutex_init(&pdev->dev, &chip->irq_lock); + if (ret) + return ret; + + chip->gc.base = -1; + chip->gc.label = dev_name(&pdev->dev); + chip->gc.parent = &pdev->dev; + chip->gc.can_sleep = true; + + chip->gc.names = max77759_gpio_line_names; + chip->gc.ngpio = MAX77759_N_GPIOS; + chip->gc.get_direction = max77759_gpio_get_direction; + chip->gc.direction_input = max77759_gpio_direction_input; + chip->gc.direction_output = max77759_gpio_direction_output; + chip->gc.get = max77759_gpio_get_value; + chip->gc.set_rv = max77759_gpio_set_value; + + girq = &chip->gc.irq; + gpio_irq_chip_set_chip(girq, &max77759_gpio_irq_chip); + /* This will let us handle the parent IRQ in the driver */ + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + girq->threaded = true; + + ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to add GPIO chip\n"); + + irq_flags = IRQF_ONESHOT | IRQF_SHARED; + irqd = irq_get_irq_data(irq); + if (irqd) + irq_flags |= irqd_get_trigger_type(irqd); + + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + max77759_gpio_irqhandler, irq_flags, + dev_name(&pdev->dev), chip); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to request IRQ\n"); + + return ret; +} + +static const struct of_device_id max77759_gpio_of_id[] = { + { .compatible = "maxim,max77759-gpio", }, + { } +}; +MODULE_DEVICE_TABLE(of, max77759_gpio_of_id); + +static const struct platform_device_id max77759_gpio_platform_id[] = { + { "max77759-gpio", }, + { } +}; +MODULE_DEVICE_TABLE(platform, max77759_gpio_platform_id); + +static struct platform_driver max77759_gpio_driver = { + .driver = { + .name = "max77759-gpio", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = max77759_gpio_of_id, + }, + .probe = max77759_gpio_probe, + .id_table = max77759_gpio_platform_id, +}; + +module_platform_driver(max77759_gpio_driver); + +MODULE_AUTHOR("André Draszik "); +MODULE_DESCRIPTION("GPIO driver for Maxim MAX77759"); +MODULE_LICENSE("GPL");