From nobody Sun Feb 8 18:08:51 2026 Received: from mail-ed1-f41.google.com (mail-ed1-f41.google.com [209.85.208.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 81BDB294A1A for ; Tue, 29 Apr 2025 08:22:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914931; cv=none; b=ZMmskOyl9XBY6WdTwSVoRi+g3Gp7c0QqDEBV6nSvPnto8zAa+qTl2IS3LReq7ObrvgP7TSpxkNv76C39dgr0hJSKj9O13WoQ5Sw8iAwJnSG2DLv6VP5HOgoTSQcWoz4iHT5LhEVDS6msv43qakiW5nvVY7kCBXpY50lM8GlyuxA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914931; c=relaxed/simple; bh=4SBDb8RMix1AfTeAapS22vbsprNHW5kDlKivkfzgJb4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ToScEEU2uifqu6ku8qlceGoY5cEyoxulDFe6TRv17OcbOxq2zDvzRZnJcDOQfmZfr+q7l2qMJT6J1C1hap2tgYQ6p1TlFB4xOfD4ae6jTwr26V4NnKBrVkwWAFHEOVIPC1LTTS9b5Q2XQROTB/7K4xsL09FqJSAe09WuAfgnQWU= 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=V213g7fd; arc=none smtp.client-ip=209.85.208.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="V213g7fd" Received: by mail-ed1-f41.google.com with SMTP id 4fb4d7f45d1cf-5f6c3f7b0b0so10716931a12.0 for ; Tue, 29 Apr 2025 01:22:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1745914928; x=1746519728; 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=V213g7fdjlzD8p0pydscPcSBtYQ2ey2pm02mGAtkuCKZXE+ufB8hHmidHEagPvSaqB FrJLdOpLwBOQ6dXgdxqqXYwE0/OnHZji3bdHZMPLlMyKPpYimz9V1poORaD40BEqrJe3 zmJY+cAIbo2sfibyutyrhgttEVVkonQwPhnO66DqCkJcZpvPUA89Apy7h3lpygYGCzG9 VkEBKxVgtcz2Ezw3fXK7gcEVo7UDZ4YTVhuIiU3JYb1E0AJyb2jhty9Y3jt/rEWhTQvU cEK5thfDTyEhid5YZlAO+w5j+PKktAiecXDVoli65xBQv7YonqrHPEmZgTFn5Wqd1iK3 5eUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745914928; x=1746519728; 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=nd1L9wsRg8UdzWQKNGebRd8JSlz3xn6H9lUCYJD+8VJiEivr8xGNlQp2eQ2Rwn800P y8ZlZBfJmkYUFSssecrWY4jw0UvFqWDtlBps4aXERs+ubGmy1qfeuI2Jfosxenmmx23Q z3iPh1oxbCZZBkZSXOusUvdLZ2+ELDy6hcf/5r1sTALuwVzZNpkVvTYdvJjg3rRbNxZ0 FRZ5TbLEGyOqhPgBzXhyPjnEz1BYqfmWakaaWAIeiWl2IiweVBckbf6OYELD77fWIoKK Ht9ShrFbfRgPYTW9IKxhNgowtDE6Jey1sfL0W91V4fHj5XMDHEGVjvmRxkZO4TSQks+v 5EDQ== X-Forwarded-Encrypted: i=1; AJvYcCWUav9UfTH1P4dMaGbNYtldd7J0cFngKHQHD3C3wKzGZqRi0YpaBuZxgqqsI13OCm6Q4cWaCoZGNnYNbcQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yw2r5pCHcQlEL1fDT+T5hezch1k8KEamP7nxePAqagIwAahEcHF fBa9BWMcnUnGoR9VNq86b6qnXslIcI9BY/GbFKVhv4O++DU8DxTrYOEcyo9kZDk= X-Gm-Gg: ASbGnctw7XmEScELwIk68x6EJwDFBLllRhY481prUYB5g4ga+mRguQEHd6RMmshCejH 9vOyKTCnNUfXmohaZavXckplslNFys2NtdlXzFUl/3tEmJUEVFpL4QkPyEjCAIMKNVslLXezjO2 YKl2/yzPqQrG0ynKLbhJIxiVQZQMDHlP6D35kZQLymj6NE/F8aLnmt7N+GFlbaWWw7gYSIYCcss u5x0gLuYJk5eEhwjjAknoYRrgxss5ACgtb9Sdvqq+XYrN8sevtbaEm+vG8WwjwXlDPiQmb55EYt VFbmtZeRVuZ7amtPwePXS5kcOPn7YfXiE0mWsfD7r5Ns0GUECWMRAa5CO/sSrzwu7OhvCHadXGg oSmCrKJ88OhtWp5rFHIpV4R8E X-Google-Smtp-Source: AGHT+IFKdKniSEsGUnq1iYx8etj6NA6NxBliPsow0jh+bOsIlETHYTkVhBYFIQ8GlA5A8lzlAc2nDA== X-Received: by 2002:a17:907:7b9a:b0:aca:c924:c14 with SMTP id a640c23a62f3a-acec69721e7mr248138766b.17.1745914927654; Tue, 29 Apr 2025 01:22:07 -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-ace6e41bbf4sm737905466b.36.2025.04.29.01.22.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Apr 2025 01:22:07 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Tue, 29 Apr 2025 09:21:37 +0100 Subject: [PATCH v8 1/6] dt-bindings: gpio: add max77759 binding Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250429-max77759-mfd-v8-1-72d72dc79a1f@linaro.org> References: <20250429-max77759-mfd-v8-0-72d72dc79a1f@linaro.org> In-Reply-To: <20250429-max77759-mfd-v8-0-72d72dc79a1f@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?Andr=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=C3=A9 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.yam= l b/Documentation/devicetree/bindings/gpio/maxim,max77759-gpio.yaml new file mode 100644 index 0000000000000000000000000000000000000000..55734190d5ebdbc351e1f91675d= ddd8a9db80cd7 --- /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=C3=A9 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..0c7bf694468e9798946baecdfd0= 3d6eacdba2ce3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14663,6 +14663,12 @@ F: Documentation/devicetree/bindings/mfd/maxim,max= 77714.yaml F: drivers/mfd/max77714.c F: include/linux/mfd/max77714.h =20 +MAXIM MAX77759 PMIC MFD DRIVER +M: Andr=C3=A9 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 --=20 2.49.0.901.g37484f566f-goog From nobody Sun Feb 8 18:08:51 2026 Received: from mail-ej1-f44.google.com (mail-ej1-f44.google.com [209.85.218.44]) (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 141BA293B58 for ; Tue, 29 Apr 2025 08:22:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914933; cv=none; b=U4K3azMH7fBCJNDQSqfNgrsm8JjCGH+MR8HIj52DH8mZGh/wcDDAad2p7kHBVCFhig6kqhJtUBeO9pNiGdfe9YQKjZN5dnUA58QFokAzk5Zu8BgdkHyRCzbo9Lt/sdTOfMrM6Pwvo1vD7rXpB2ZzI4SjGzB9KgbrOfMS3JDThZI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914933; c=relaxed/simple; bh=Cc1Ucs7d+DoVlcf66E1KPy7NQ5fP8mutIpm2TD0VDuE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MbvgkEMw7h9CWR7xFRJk9KNqCXKzTHJtS39MoSiirNo67LePIROrxnWHMatkjku3HESqyUi38kRi+/MMVsn93FbuQWxFvxhE/9sr045H2+70HAtXJ9y/i1CHL4Sy9g6FtV5lIF/+DKlWiMYg/V7jQ5CGODmy8HE3e7WD97IayN4= 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=JIx/2dq0; arc=none smtp.client-ip=209.85.218.44 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="JIx/2dq0" Received: by mail-ej1-f44.google.com with SMTP id a640c23a62f3a-ac2dfdf3c38so983518066b.3 for ; Tue, 29 Apr 2025 01:22:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1745914928; x=1746519728; 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=Rgc6ivQ4v0OBxVxiMV//REmkxOVzSIsF9RwMWgdL0S4=; b=JIx/2dq0IdP5lsWIrTOPOeR6rm7/Ty0PDCRQFTGX5B+VLkE2tL7NxkZqVceAoqOeNb mVD3rpFNJ6vrN1bXWUjkrbklE8VG8Ln6Kh5sh7Qt/Aj2SIfW/dI01tp9c/K4CfrTojtK Zfj/SQ820rMqH2oHDyia9AyjQy9PTH3yhVUkUaFBUjETIPku/bTrUT/zp0CJOl7PYAi1 kGrPUWO5WpfGeskOfcmfd/cZWKL2Wa1e19CNBqGFjMDPEUpKD1sOiZNyqigG9cfN8SOB V6pxHsDYgZCtHXs2xg9dJ0+OoeOeXDu/esQGmZiOihr4G2wPV03hZctH/+29F2WwLBWr lxqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745914928; x=1746519728; 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=Rgc6ivQ4v0OBxVxiMV//REmkxOVzSIsF9RwMWgdL0S4=; b=BgsovfjOgGi4+AyzBjiMI0B1/x7fuNi7Yn9her7fTRfzuv9thhWtxtMGRxmLrFMI3A rn8mhpCrJSmm2UoGpr4F0JAGm3qa6RApCkp59nP7v0RjrbcAoOCDQ+Y81+FnwkR0dQRV hviQM+s/gqT2DOOlmmwfFpScPsHHdkqgBJA0fVmF/EpDAyoq8D+4u0syy4XXvTGhneXW zvR/QMFce69U4X57X+S59TgAniveespwi4iIzxdm4FSmKN9LtEAb655n2zf5T83kMn/w OKHldxpN/MkrujzyMZBdduAKBiI6SWy/NE9+/9TgtcNscwLWe+OcZOMxvUSNWzSgbduc aUIg== X-Forwarded-Encrypted: i=1; AJvYcCUJNe7JtneKQBh/pd0XgdZhdGgHuOausYfbRsHqb0RoizKliotD0GfGrqazOXi40SOqTn4Mtr9QtpoYSjA=@vger.kernel.org X-Gm-Message-State: AOJu0YwFSGojqqcnaLweLpGszV/03iL6iWnnYjaZvED3ZZlq3OnOdyUE M7S3CRTJdbawuqMs3Cv9qkyfMRvHdUJi7RbmaPK9MQvFiQpP040DVtzLrOLzQEU= X-Gm-Gg: ASbGncv4b0KBqQU3zsJPaXytxnHmpOvA1gjtcK8Oz90ZqBRhBo2UEIh6yCLXtmlVeA0 UuQTi+qEWG/B1Tc3cP7Lf7oO5mEfcgZH40f0iEKJf5xeyqIdy1hlmEjtCVQA1appyCSEmghx8sZ zmQe4rG/0l6gqaxB+e3jRQPe5FLfg2ifnGtJhnKivubse8HCzVUZwosDlo6rM1DuwS+RYzshRWU lk6ifOYQuZ8ycQvzgc4aF6rwOxt4nFlrG30TMCo2z5TVRTHT53gTQGtnKlIzyqryYJUM5ITUIhB hoUhzmBi/EYXbXMAV7kIaToYJn+3Dn8kPz8qbANySPbNu540xD8PK5oZJEebZvaYXkm9LjrF/kw cpXi0a7ucijbmWOCcAAHTwVwE X-Google-Smtp-Source: AGHT+IFe3Pnn1X/IyxiNpZeYuCh2G0CyBjUHp/1BGmD7TkeokHlJhATW4MV7s/37c0u7zNh9awdx1w== X-Received: by 2002:a17:907:7e84:b0:aca:d83b:611b with SMTP id a640c23a62f3a-ace84aad97bmr1190165266b.43.1745914928158; Tue, 29 Apr 2025 01:22:08 -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-ace6e41bbf4sm737905466b.36.2025.04.29.01.22.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Apr 2025 01:22:07 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Tue, 29 Apr 2025 09:21:38 +0100 Subject: [PATCH v8 2/6] dt-bindings: nvmem: add max77759 binding Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250429-max77759-mfd-v8-2-72d72dc79a1f@linaro.org> References: <20250429-max77759-mfd-v8-0-72d72dc79a1f@linaro.org> In-Reply-To: <20250429-max77759-mfd-v8-0-72d72dc79a1f@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?Andr=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 its storage module (NVMEM). Reviewed-by: Rob Herring (Arm) Signed-off-by: Andr=C3=A9 Draszik --- v2: * drop example as the MFD binding has a complete one (Rob) Note: MAINTAINERS doesn't need updating, the binding update for the first leaf device (gpio) adds a wildcard matching all max77759 bindings --- .../bindings/nvmem/maxim,max77759-nvmem.yaml | 32 ++++++++++++++++++= ++++ 1 file changed, 32 insertions(+) diff --git a/Documentation/devicetree/bindings/nvmem/maxim,max77759-nvmem.y= aml b/Documentation/devicetree/bindings/nvmem/maxim,max77759-nvmem.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1e3bd4433007341a11040f513bf= 444866b9e38a8 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/maxim,max77759-nvmem.yaml @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/maxim,max77759-nvmem.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX77759 Non Volatile Memory + +maintainers: + - Andr=C3=A9 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, Non Volatile Memory + (NVMEM) with 30 bytes of storage which can be used by software to store + information or communicate with a boot loader. + +properties: + compatible: + const: maxim,max77759-nvmem + + wp-gpios: false + +required: + - compatible + +allOf: + - $ref: nvmem.yaml# + +unevaluatedProperties: false --=20 2.49.0.901.g37484f566f-goog From nobody Sun Feb 8 18:08:51 2026 Received: from mail-ed1-f43.google.com (mail-ed1-f43.google.com [209.85.208.43]) (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 AE56829B23E for ; Tue, 29 Apr 2025 08:22:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914934; cv=none; b=l4PG43IWxRzoaJ9RtRls2+8a1mUlOW/IDsq/pc8rxWl6o5DRxBWM8r0r9mCTEEB+tnGCs6LRcm/q2bxKqumm296W+qZmnwSEUm0Qt94T1AJMMnAEFYpT/T9EHrcMUtTRNptQ22DYNRPb3rXUt5CIgG+3INTiLY5jCRNKKbu45vg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914934; c=relaxed/simple; bh=bFksOeknh8d+JfpwdhA3LClj8Y8cCin0vyzLAmX/vl4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YtXEvzDptXULbKmn5n1y1vTkSATCupfOOFenwhE+6oteJ+HfVy7p23NiJMXiO+Gf5lZ62LE9PG/8OlbOgRI95Ymgc81XI6iIHmrIP4XA21uspnIExORDTgpSqr/bv6OO4RRoCzdKEV3+5F12uE0r8rWzx0BMsKCRv37nAxYfQ5k= 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=bd/1cZk0; arc=none smtp.client-ip=209.85.208.43 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="bd/1cZk0" Received: by mail-ed1-f43.google.com with SMTP id 4fb4d7f45d1cf-5e6c18e2c7dso11019092a12.3 for ; Tue, 29 Apr 2025 01:22:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1745914929; x=1746519729; 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=bd/1cZk0rWDbHxQ3J04toubS5K18q6pCmY+V22R06qt0mORt1LVXtuh8L/MUzJU8DZ Oj0AS2oNl3+O2cFdJDYo8FPXdVC2idJb+Z3UzbyHoi3NTBTdlU8NgZdpULc5vM4xcPjZ b/OUdUEjHfQH0OPfRQnQn7+W9fwwD5kbHuV1WB5+867mYp34oQTsIRAVDSVYCErJqSvc 8uO2D7+wa1o3kjFJo//YdwFru+RyYUC7ZCyeEPzLZtm8BWDwMk5cbtQHUl2x30beRwFg 9cINqr27apkfAMIG+gA+mzbruGQ0IheHCapeifIVPSM45naZU2O9F5otH040IooI7WXT QOrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745914929; x=1746519729; 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=kMSGmmgvRQU37YoYkIPY59OQU38rDDvFJWs4ESj8mfXItJRP7S6w9UART0FH0V9+Ld 6V7M9shfies50Z2Qdi9ZScY9tS3fE8iG8BSw4WW+loH4K19GJVUcMup4nt0jTmdauGx3 glSo4KQUg53obm79fqDCC++1eb8ECp6ZxN0D1ypEilemxnfwZDh/L/UB5VWxE9XQVLXv H0yAEhTCznMBcvxrT8ItEnq+AIdyy2AL6SrGh3p3d1HXUqdBgsg+Azon3n70+ZP0Mljx 69H1QnW/F+2eBtChKfaohtfLAa/KQzW1hu506boYBjoPVuCHpNMgVzWO6xR7WbdmdO+O 7pzw== X-Forwarded-Encrypted: i=1; AJvYcCUc0svRbjE+OkkjodXoGP9n/HzPxc05RMS8opwcDxj3TKqRdt1Jby50o32/KO+FT+Z4TtAClcPCp0aYyYU=@vger.kernel.org X-Gm-Message-State: AOJu0Yyud0RPOm8hvmQlPy7wqkK+5QKh+JWrx53wOj0k5OssFPCmHp0O etphoIfcTf+DnJ8r+lwG5LmDNH+2yEGj6Y7g/V+OAxZmSbH9yqIqYpcu8BIeQ9A= X-Gm-Gg: ASbGnctoifVmuuL10VxdCC2xaRh8exBN1e8p4Ysz5vkv4r/ifyj8r9Qvjc9hi9p2Y/I H25SIC/T0dQ4Sn41lKDmbsyJMjnKfQ/J0IORFEk//+ulrKqRmEyeiDdizq2ikYXZMsjjQk+J8Qg t5gcG2437gX/GgQBfWMnEsigDhR38jM0EVxd0sJKZJAlveghWWl4ce5CJQ6IpMe2YIEVl51eZST 3mx4TCyDa0d87ktMlMqGVtm13bl1iNxLRRBXnZDUFNCEXYIRQteIDpnVyzC6tLmvzsOqWY6KXbt OZzwZNREMhvMrukgB24bpL849qDptiW3gs28qj8dy7KNic9Ciok6gBwGd7noW1Ybl9xtFkDywJg skROumd5SWg6Cgo905X0tsEdwExmYEzsI9QA= X-Google-Smtp-Source: AGHT+IHzcQQ+9hyFiMjckDJ0NsHxoITKhor7RUapPEL2dlwcirTYuq+HRPXA4/n2SoNbKNkmp3RVPg== X-Received: by 2002:a17:907:72d0:b0:acb:b08c:76ae with SMTP id a640c23a62f3a-acec84d2cb7mr160276166b.16.1745914928732; Tue, 29 Apr 2025 01:22:08 -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-ace6e41bbf4sm737905466b.36.2025.04.29.01.22.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Apr 2025 01:22:08 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Tue, 29 Apr 2025 09:21:39 +0100 Subject: [PATCH v8 3/6] dt-bindings: mfd: add max77759 binding Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250429-max77759-mfd-v8-3-72d72dc79a1f@linaro.org> References: <20250429-max77759-mfd-v8-0-72d72dc79a1f@linaro.org> In-Reply-To: <20250429-max77759-mfd-v8-0-72d72dc79a1f@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?Andr=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=C3=A9 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/Do= cumentation/devicetree/bindings/mfd/maxim,max77759.yaml new file mode 100644 index 0000000000000000000000000000000000000000..525de9ab3c2b7b431e484973306= 40857540625b1 --- /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=C3=A9 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 =3D <1>; + #size-cells =3D <0>; + + pmic@66 { + compatible =3D "maxim,max77759"; + reg =3D <0x66>; + interrupts-extended =3D <&gpa8 3 IRQ_TYPE_LEVEL_LOW>; + + interrupt-controller; + #interrupt-cells =3D <2>; + + gpio { + compatible =3D "maxim,max77759-gpio"; + + gpio-controller; + #gpio-cells =3D <2>; + + interrupt-controller; + #interrupt-cells =3D <2>; + }; + + nvmem-0 { + compatible =3D "maxim,max77759-nvmem"; + + nvmem-layout { + compatible =3D "fixed-layout"; + #address-cells =3D <1>; + #size-cells =3D <1>; + + reboot-mode@0 { + reg =3D <0x0 0x4>; + }; + + boot-reason@4 { + reg =3D <0x4 0x4>; + }; + + shutdown-user-flag@8 { + reg =3D <0x8 0x1>; + }; + + rsoc@10 { + reg =3D <0xa 0x2>; + }; + }; + }; + }; + }; --=20 2.49.0.901.g37484f566f-goog From nobody Sun Feb 8 18:08:51 2026 Received: from mail-ed1-f53.google.com (mail-ed1-f53.google.com [209.85.208.53]) (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 A94AA29B234 for ; Tue, 29 Apr 2025 08:22:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914936; cv=none; b=kowB/kxnQnXk/lmCfQbjQSg5sxsnXWdNdr8nlz3/zAyiG5Xnz917TVCQI1YJIE4RT70ntfe8fchqDu0jgtpAfXOWNKiinZZuC1VbxJgMC0GoKyS++jU4zuzODJGgZcSTneswqmFW/c8ecCSuj9U3B/rEnR4g4nB0KKHRyXZbRTk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914936; c=relaxed/simple; bh=ETC0/fQ2J0eodVufxbigax62gsNYjoMjRIRivyab6iI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QwhBZFMwl58154TVEXVcaFK6ArONlWPeSZ1uz5mmh24rki04KDMjYzZ9IBcEJLnQFQLGFEelNLJrGLhotcrfNsozAxzvOMyDrtestXTi8F97oWMvvwaVWLujK0hky6pC5tpYyEvR7ju5jl4SXp3D7rinM6vLCF0RmkoB2397gDM= 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=tgc4a3GG; arc=none smtp.client-ip=209.85.208.53 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="tgc4a3GG" Received: by mail-ed1-f53.google.com with SMTP id 4fb4d7f45d1cf-5e8be1bdb7bso9084026a12.0 for ; Tue, 29 Apr 2025 01:22:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1745914929; x=1746519729; 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=RNMGX8xTAJV03xiy4EuyoYxFrFzL7vnGQ/tRNVy0Y60=; b=tgc4a3GG7A0JwSBKqIXkz2elVCmtBNCQ0Nh8MYlD/OEPXb7IMy+IW9FYiCVYBAAcqf qI84QP+eywBDLWDWjgjuSp5oBQvyV9Xa1ysTdpI559mC25oZQlgO0/pXwrkJ3EHoY145 4hLBbTZrFj0HbmtBZoZqgEmSFPsYEKF5Fwa+1HFkcvBe4m68lUqxsf0Hht5PTGhCayO5 n194Ram1hNz64FQTk4Wvp1HzYf7EprDDyg2b7tebpnL94idRZziXiRTEYRhkmMSqP0B+ 5kIBrYIP/BZvmZXOisNl5Rd42lB+WWg1ZBzZIvFqDXxO5xSk3frSyIjuYe91MM7wwlWC spqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745914929; x=1746519729; 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=RNMGX8xTAJV03xiy4EuyoYxFrFzL7vnGQ/tRNVy0Y60=; b=Icnv+oWz1JFIVViZlkRXYo41p/6cTfVH1EcAc+ZPEkuQXK1foD/d5uZsAvwHVe4rUg B6fZl7XZ39hClTnQhddJu70Zcx2on8C1jclsxX7hxF/ussvR960uBqsGgbkbyoWfm3vI dLJZvAqTTZ5E4pmrxIAF9WAvzjAX6938kPZcc/zJyFTte6XLRtHZohDxtEo5PF7g4rwR Qq3Xa1+Fvemje5Iu5w6lvF8YxC8sQpyG30bcFUkMfqUos0j60YcBLW2VexacJ3cXJRVt o87K5o9isI+KYpny24ZN8Rq/YPgoFb5MDiXdOIM/AkjA0FkQUU6q4Q4qC8ZXTfw+Y6Rf +ahg== X-Forwarded-Encrypted: i=1; AJvYcCVctAwkwMXIp8RX2i92XidxwEhJCMMBxQmJTrhAc8kt15i4M6QmzmuC5WqZH5NndtzBV/7p5YJrJ/NcgpY=@vger.kernel.org X-Gm-Message-State: AOJu0YxfKIhkXGFvvmWMzTpwvLqxb5uB+tg6XyQfTcUcIDkSXpbs0jpk TZH+SoPe6ArIqV+eP4smolGyTVqP/17X+30acf6hdP30VjzRerX9ZRQLS0epYEBmf60/gHb/DVv 0Rt8= X-Gm-Gg: ASbGncstQOJRWm21JrroUh5N/XBkq//I8bAHEsz/ICDSn5ILftA1PxuKiVDKRcH4ML/ G1kdcxmEhFqPsNt4f1XEs/6cX1ZzxVioT30YSebRbLoTDX9/jK/v3ajrGzfxG79RRg0FLv66BFf +E89wvHaCjX6sSmAPz4k6W1qgTH7qLry27KyN2kXth8R7psKQMSvBudLEXYulob32j1E+XLFOFB +43Y1AfpI/5qZFBW6XnjksrxTfMQUqTefdyJEFZTcMBnxFKMNKxmczJQVgX6Wasp8LNg2RTCWMk 8oR6f+wXhdueacOqPLmDRiT1UHKISluunR4v6K3+6dUGkuvW0YZQpxK3qKTPSpWv3EnwaxAvbWF MeB/0VPQOLQZlBtwMsU+LTfDh X-Google-Smtp-Source: AGHT+IEyqU1NEv5YMW/GnjYUFt3eUUK8DkYeidbALuLM90vIgayc+LM0mOct1rsNQ8LaH1P1T577pg== X-Received: by 2002:a17:907:3f9e:b0:aca:cc55:fd35 with SMTP id a640c23a62f3a-acec87b7a04mr173239666b.56.1745914929350; Tue, 29 Apr 2025 01:22:09 -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-ace6e41bbf4sm737905466b.36.2025.04.29.01.22.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Apr 2025 01:22:08 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Tue, 29 Apr 2025 09:21:40 +0100 Subject: [PATCH v8 4/6] mfd: max77759: add Maxim MAX77759 core mfd driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250429-max77759-mfd-v8-4-72d72dc79a1f@linaro.org> References: <20250429-max77759-mfd-v8-0-72d72dc79a1f@linaro.org> In-Reply-To: <20250429-max77759-mfd-v8-0-72d72dc79a1f@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?Andr=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. Fuel Gauge and TCPC have separate and independent I2C addresses, register maps, and interrupt lines and are therefore excluded from the MFD core device driver here. The GPIO and NVMEM interfaces are accessed via specific commands to the built-in microprocessor. This driver implements an API that client drivers can use for accessing those. Signed-off-by: Andr=C3=A9 Draszik --- v6: really use postinc v5: * update all (I hope) of Lee's comments: * file header C comment (not C++) * drop references to 'MFD' * extra indent register bit definitions * make 'struct max77759' public * drop comments that were used for visual separation only * drop MAX77759_*_REG_LAST_REGISTER defines * add comments to regmap ranges * use longer lines * sort local variable in reverse christmas tree order * update comments in max77759_maxq_command() * drop BUILD_BUG_ON() * use dev_err() in max77759_maxq_command() * reflow max77759_create_i2c_subdev() slightly and update error messages * drop useless comment in max77759_add_chained_maxq() * reflow max77759_probe() * consistent upper-/lower-case in messages v4: * add missing build_bug.h include * update an irq chip comment * fix a whitespace in register definitions v2: * add kernel doc for max77759_maxq_command() and related structs * fix an msec / usec typo * add missing error handling of devm_mutex_init() (Christophe) * align sentinel in max77759_of_id[] with max77759_i2c_id[] (Christophe) * some tidy-ups in max77759_maxq_command() (Christophe) max77759 Lee's updates --- MAINTAINERS | 2 + drivers/mfd/Kconfig | 20 ++ drivers/mfd/Makefile | 1 + drivers/mfd/max77759.c | 690 +++++++++++++++++++++++++++++++++++++++= ++++ include/linux/mfd/max77759.h | 165 +++++++++++ 5 files changed, 878 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0c7bf694468e9798946baecdfd03d6eacdba2ce3..1259d09e700a21215e8ae2facef= 858df5304346e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14668,6 +14668,8 @@ M: Andr=C3=A9 Draszik L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/*/maxim,max77759*.yaml +F: drivers/mfd/max77759.c +F: include/linux/mfd/max77759.h =20 MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER M: Javier Martinez Canillas diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 22b93631003943c393d9fe704748bc23f1905397..96992af22565205716d72db0494= c7bf2567b045e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -943,6 +943,26 @@ config MFD_MAX77714 drivers must be enabled in order to use each functionality of the device. =20 +config MFD_MAX77759 + tristate "Maxim Integrated MAX77759 PMIC" + depends on I2C + depends on OF + select IRQ_DOMAIN + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + help + Say yes here to add support for Maxim Integrated MAX77759. + This is a companion Power Management IC for USB Type-C applications + with Battery Charger, Fuel Gauge, temperature sensors, USB Type-C + Port Controller (TCPC), NVMEM, and additional GPIO interfaces. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. + + To compile this driver as a module, choose M here: the module will be + called max77759. + config MFD_MAX77843 bool "Maxim Semiconductor MAX77843 PMIC Support" depends on I2C=3Dy diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 948cbdf42a18b22a826f0b17fb8d5796a7ec8ba6..5e5cc279af6036a6b3ea1f1f0fe= eddf45b85f15c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -169,6 +169,7 @@ obj-$(CONFIG_MFD_MAX77686) +=3D max77686.o obj-$(CONFIG_MFD_MAX77693) +=3D max77693.o obj-$(CONFIG_MFD_MAX77705) +=3D max77705.o obj-$(CONFIG_MFD_MAX77714) +=3D max77714.o +obj-$(CONFIG_MFD_MAX77759) +=3D max77759.o obj-$(CONFIG_MFD_MAX77843) +=3D max77843.o obj-$(CONFIG_MFD_MAX8907) +=3D max8907.o max8925-objs :=3D max8925-core.o max8925-i2c.o diff --git a/drivers/mfd/max77759.c b/drivers/mfd/max77759.c new file mode 100644 index 0000000000000000000000000000000000000000..15723ac3ef49771eafd5c2e9984= abc550eec7aa1 --- /dev/null +++ b/drivers/mfd/max77759.c @@ -0,0 +1,690 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2020 Google Inc + * Copyright 2025 Linaro Ltd. + * + * Core driver for Maxim MAX77759 companion PMIC for USB Type-C + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Chip ID as per MAX77759_PMIC_REG_PMIC_ID */ +enum { + MAX77759_CHIP_ID =3D 59, +}; + +enum max77759_i2c_subdev_id { + /* + * These are arbitrary and simply used to match struct + * max77759_i2c_subdev entries to the regmap pointers in struct + * max77759 during probe(). + */ + MAX77759_I2C_SUBDEV_ID_MAXQ, + MAX77759_I2C_SUBDEV_ID_CHARGER, +}; + +struct max77759_i2c_subdev { + enum max77759_i2c_subdev_id id; + const struct regmap_config *cfg; + u16 i2c_address; +}; + +static const struct regmap_range max77759_top_registers[] =3D { + regmap_reg_range(0x00, 0x02), /* PMIC_ID / PMIC_REVISION / OTP_REVISION */ + regmap_reg_range(0x22, 0x24), /* INTSRC / INTSRCMASK / TOPSYS_INT */ + regmap_reg_range(0x26, 0x26), /* TOPSYS_INT_MASK */ + regmap_reg_range(0x40, 0x40), /* I2C_CNFG */ + regmap_reg_range(0x50, 0x51), /* SWRESET / CONTROL_FG */ +}; + +static const struct regmap_range max77759_top_ro_registers[] =3D { + regmap_reg_range(0x00, 0x02), + regmap_reg_range(0x22, 0x22), +}; + +static const struct regmap_range max77759_top_volatile_registers[] =3D { + regmap_reg_range(0x22, 0x22), + regmap_reg_range(0x24, 0x24), +}; + +static const struct regmap_access_table max77759_top_wr_table =3D { + .yes_ranges =3D max77759_top_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_top_registers), + .no_ranges =3D max77759_top_ro_registers, + .n_no_ranges =3D ARRAY_SIZE(max77759_top_ro_registers), +}; + +static const struct regmap_access_table max77759_top_rd_table =3D { + .yes_ranges =3D max77759_top_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_top_registers), +}; + +static const struct regmap_access_table max77759_top_volatile_table =3D { + .yes_ranges =3D max77759_top_volatile_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_top_volatile_registers), +}; + +static const struct regmap_config max77759_regmap_config_top =3D { + .name =3D "top", + .reg_bits =3D 8, + .val_bits =3D 8, + .max_register =3D MAX77759_PMIC_REG_CONTROL_FG, + .wr_table =3D &max77759_top_wr_table, + .rd_table =3D &max77759_top_rd_table, + .volatile_table =3D &max77759_top_volatile_table, + .num_reg_defaults_raw =3D MAX77759_PMIC_REG_CONTROL_FG + 1, + .cache_type =3D REGCACHE_FLAT, +}; + +static const struct regmap_range max77759_maxq_registers[] =3D { + regmap_reg_range(0x60, 0x73), /* Device ID, Rev, INTx, STATUSx, MASKx */ + regmap_reg_range(0x81, 0xa1), /* AP_DATAOUTx */ + regmap_reg_range(0xb1, 0xd1), /* AP_DATAINx */ + regmap_reg_range(0xe0, 0xe0), /* UIC_SWRST */ +}; + +static const struct regmap_range max77759_maxq_ro_registers[] =3D { + regmap_reg_range(0x60, 0x63), /* Device ID, Rev */ + regmap_reg_range(0x68, 0x6f), /* STATUSx */ + regmap_reg_range(0xb1, 0xd1), +}; + +static const struct regmap_range max77759_maxq_volatile_registers[] =3D { + regmap_reg_range(0x64, 0x6f), /* INTx, STATUSx */ + regmap_reg_range(0xb1, 0xd1), + regmap_reg_range(0xe0, 0xe0), +}; + +static const struct regmap_access_table max77759_maxq_wr_table =3D { + .yes_ranges =3D max77759_maxq_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_maxq_registers), + .no_ranges =3D max77759_maxq_ro_registers, + .n_no_ranges =3D ARRAY_SIZE(max77759_maxq_ro_registers), +}; + +static const struct regmap_access_table max77759_maxq_rd_table =3D { + .yes_ranges =3D max77759_maxq_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_maxq_registers), +}; + +static const struct regmap_access_table max77759_maxq_volatile_table =3D { + .yes_ranges =3D max77759_maxq_volatile_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_maxq_volatile_registers), +}; + +static const struct regmap_config max77759_regmap_config_maxq =3D { + .name =3D "maxq", + .reg_bits =3D 8, + .val_bits =3D 8, + .max_register =3D MAX77759_MAXQ_REG_UIC_SWRST, + .wr_table =3D &max77759_maxq_wr_table, + .rd_table =3D &max77759_maxq_rd_table, + .volatile_table =3D &max77759_maxq_volatile_table, + .num_reg_defaults_raw =3D MAX77759_MAXQ_REG_UIC_SWRST + 1, + .cache_type =3D REGCACHE_FLAT, +}; + +static const struct regmap_range max77759_charger_registers[] =3D { + regmap_reg_range(0xb0, 0xcc), +}; + +static const struct regmap_range max77759_charger_ro_registers[] =3D { + regmap_reg_range(0xb4, 0xb8), /* INT_OK, DETAILS_0x */ +}; + +static const struct regmap_range max77759_charger_volatile_registers[] =3D= { + regmap_reg_range(0xb0, 0xb1), /* INTx */ + regmap_reg_range(0xb4, 0xb8), +}; + +static const struct regmap_access_table max77759_charger_wr_table =3D { + .yes_ranges =3D max77759_charger_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_charger_registers), + .no_ranges =3D max77759_charger_ro_registers, + .n_no_ranges =3D ARRAY_SIZE(max77759_charger_ro_registers), +}; + +static const struct regmap_access_table max77759_charger_rd_table =3D { + .yes_ranges =3D max77759_charger_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_charger_registers), +}; + +static const struct regmap_access_table max77759_charger_volatile_table = =3D { + .yes_ranges =3D max77759_charger_volatile_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_charger_volatile_registers), +}; + +static const struct regmap_config max77759_regmap_config_charger =3D { + .name =3D "charger", + .reg_bits =3D 8, + .val_bits =3D 8, + .max_register =3D MAX77759_CHGR_REG_CHG_CNFG_19, + .wr_table =3D &max77759_charger_wr_table, + .rd_table =3D &max77759_charger_rd_table, + .volatile_table =3D &max77759_charger_volatile_table, + .num_reg_defaults_raw =3D MAX77759_CHGR_REG_CHG_CNFG_19 + 1, + .cache_type =3D REGCACHE_FLAT, +}; + +/* + * Interrupts - with the following interrupt hierarchy: + * pmic IRQs (INTSRC) + * - MAXQ_INT: MaxQ IRQs + * - UIC_INT1 + * - APCmdResI + * - SysMsgI + * - GPIOxI + * - TOPSYS_INT: topsys + * - TOPSYS_INT + * - TSHDN_INT + * - SYSOVLO_INT + * - SYSUVLO_INT + * - FSHIP_NOT_RD + * - CHGR_INT: charger + * - CHG_INT + * - CHG_INT2 + */ +enum { + MAX77759_INT_MAXQ, + MAX77759_INT_TOPSYS, + MAX77759_INT_CHGR, +}; + +enum { + MAX77759_TOPSYS_INT_TSHDN, + MAX77759_TOPSYS_INT_SYSOVLO, + MAX77759_TOPSYS_INT_SYSUVLO, + MAX77759_TOPSYS_INT_FSHIP_NOT_RD, +}; + +enum { + MAX77759_MAXQ_INT_APCMDRESI, + MAX77759_MAXQ_INT_SYSMSGI, + MAX77759_MAXQ_INT_GPIO, + MAX77759_MAXQ_INT_UIC1, + MAX77759_MAXQ_INT_UIC2, + MAX77759_MAXQ_INT_UIC3, + MAX77759_MAXQ_INT_UIC4, +}; + +enum { + MAX77759_CHARGER_INT_1, + MAX77759_CHARGER_INT_2, +}; + +static const struct regmap_irq max77759_pmic_irqs[] =3D { + REGMAP_IRQ_REG(MAX77759_INT_MAXQ, 0, MAX77759_PMIC_REG_INTSRC_MAXQ), + REGMAP_IRQ_REG(MAX77759_INT_TOPSYS, 0, MAX77759_PMIC_REG_INTSRC_TOPSYS), + REGMAP_IRQ_REG(MAX77759_INT_CHGR, 0, MAX77759_PMIC_REG_INTSRC_CHGR), +}; + +static const struct regmap_irq max77759_maxq_irqs[] =3D { + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_APCMDRESI, 0, MAX77759_MAXQ_REG_UIC_INT1= _APCMDRESI), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_SYSMSGI, 0, MAX77759_MAXQ_REG_UIC_INT1_S= YSMSGI), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_GPIO, 0, GENMASK(1, 0)), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_UIC1, 0, GENMASK(5, 2)), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_UIC2, 1, GENMASK(7, 0)), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_UIC3, 2, GENMASK(7, 0)), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_UIC4, 3, GENMASK(7, 0)), +}; + +static const struct regmap_irq max77759_topsys_irqs[] =3D { + REGMAP_IRQ_REG(MAX77759_TOPSYS_INT_TSHDN, 0, MAX77759_PMIC_REG_TOPSYS_INT= _TSHDN), + REGMAP_IRQ_REG(MAX77759_TOPSYS_INT_SYSOVLO, 0, MAX77759_PMIC_REG_TOPSYS_I= NT_SYSOVLO), + REGMAP_IRQ_REG(MAX77759_TOPSYS_INT_SYSUVLO, 0, MAX77759_PMIC_REG_TOPSYS_I= NT_SYSUVLO), + REGMAP_IRQ_REG(MAX77759_TOPSYS_INT_FSHIP_NOT_RD, 0, MAX77759_PMIC_REG_TOP= SYS_INT_FSHIP), +}; + +static const struct regmap_irq max77759_chgr_irqs[] =3D { + REGMAP_IRQ_REG(MAX77759_CHARGER_INT_1, 0, GENMASK(7, 0)), + REGMAP_IRQ_REG(MAX77759_CHARGER_INT_2, 1, GENMASK(7, 0)), +}; + +static const struct regmap_irq_chip max77759_pmic_irq_chip =3D { + .name =3D "max77759-pmic", + /* INTSRC is read-only and doesn't require clearing */ + .status_base =3D MAX77759_PMIC_REG_INTSRC, + .mask_base =3D MAX77759_PMIC_REG_INTSRCMASK, + .num_regs =3D 1, + .irqs =3D max77759_pmic_irqs, + .num_irqs =3D ARRAY_SIZE(max77759_pmic_irqs), +}; + +/* + * We can let regmap-irq auto-ack the topsys interrupt bits as required, b= ut + * for all others the individual drivers need to know which interrupt bit + * exactly is set inside their interrupt handlers, and therefore we can no= t set + * .ack_base for those. + */ +static const struct regmap_irq_chip max77759_maxq_irq_chip =3D { + .name =3D "max77759-maxq", + .domain_suffix =3D "MAXQ", + .status_base =3D MAX77759_MAXQ_REG_UIC_INT1, + .mask_base =3D MAX77759_MAXQ_REG_UIC_INT1_M, + .num_regs =3D 4, + .irqs =3D max77759_maxq_irqs, + .num_irqs =3D ARRAY_SIZE(max77759_maxq_irqs), +}; + +static const struct regmap_irq_chip max77759_topsys_irq_chip =3D { + .name =3D "max77759-topsys", + .domain_suffix =3D "TOPSYS", + .status_base =3D MAX77759_PMIC_REG_TOPSYS_INT, + .mask_base =3D MAX77759_PMIC_REG_TOPSYS_INT_MASK, + .ack_base =3D MAX77759_PMIC_REG_TOPSYS_INT, + .num_regs =3D 1, + .irqs =3D max77759_topsys_irqs, + .num_irqs =3D ARRAY_SIZE(max77759_topsys_irqs), +}; + +static const struct regmap_irq_chip max77759_chrg_irq_chip =3D { + .name =3D "max77759-chgr", + .domain_suffix =3D "CHGR", + .status_base =3D MAX77759_CHGR_REG_CHG_INT, + .mask_base =3D MAX77759_CHGR_REG_CHG_INT_MASK, + .num_regs =3D 2, + .irqs =3D max77759_chgr_irqs, + .num_irqs =3D ARRAY_SIZE(max77759_chgr_irqs), +}; + +static const struct max77759_i2c_subdev max77759_i2c_subdevs[] =3D { + { + .id =3D MAX77759_I2C_SUBDEV_ID_MAXQ, + .cfg =3D &max77759_regmap_config_maxq, + /* I2C address is same as for sub-block 'top' */ + }, + { + .id =3D MAX77759_I2C_SUBDEV_ID_CHARGER, + .cfg =3D &max77759_regmap_config_charger, + .i2c_address =3D 0x69, + }, +}; + +static const struct resource max77759_gpio_resources[] =3D { + DEFINE_RES_IRQ_NAMED(MAX77759_MAXQ_INT_GPIO, "GPI"), +}; + +static const struct resource max77759_charger_resources[] =3D { + DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_1, "INT1"), + DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_2, "INT2"), +}; + +static const struct mfd_cell max77759_cells[] =3D { + MFD_CELL_OF("max77759-nvmem", NULL, NULL, 0, 0, + "maxim,max77759-nvmem"), +}; + +static const struct mfd_cell max77759_maxq_cells[] =3D { + MFD_CELL_OF("max77759-gpio", max77759_gpio_resources, NULL, 0, 0, + "maxim,max77759-gpio"), +}; + +static const struct mfd_cell max77759_charger_cells[] =3D { + MFD_CELL_RES("max77759-charger", max77759_charger_resources), +}; + +int max77759_maxq_command(struct max77759 *max77759, + const struct max77759_maxq_command *cmd, + struct max77759_maxq_response *rsp) +{ + DEFINE_FLEX(struct max77759_maxq_response, _rsp, rsp, length, 1); + struct device *dev =3D regmap_get_device(max77759->regmap_maxq); + static const unsigned int timeout_ms =3D 200; + int ret; + + if (cmd->length > MAX77759_MAXQ_OPCODE_MAXLENGTH) + return -EINVAL; + + /* + * As a convenience for API users when issuing simple commands, rsp is + * allowed to be NULL. In that case we need a temporary here to write + * the response to, as we need to verify that the command was indeed + * completed correctly. + */ + if (!rsp) + rsp =3D _rsp; + + if (!rsp->length || rsp->length > MAX77759_MAXQ_OPCODE_MAXLENGTH) + return -EINVAL; + + guard(mutex)(&max77759->maxq_lock); + + reinit_completion(&max77759->cmd_done); + + /* + * MaxQ latches the message when the DATAOUT32 register is written. If + * cmd->length is shorter we still need to write 0 to it. + */ + ret =3D regmap_bulk_write(max77759->regmap_maxq, + MAX77759_MAXQ_REG_AP_DATAOUT0, cmd->cmd, + cmd->length); + if (!ret && cmd->length < MAX77759_MAXQ_OPCODE_MAXLENGTH) + ret =3D regmap_write(max77759->regmap_maxq, + MAX77759_MAXQ_REG_AP_DATAOUT32, 0); + if (ret) { + dev_err(dev, "writing command failed: %d\n", ret); + return ret; + } + + /* wait for response from MaxQ */ + if (!wait_for_completion_timeout(&max77759->cmd_done, + msecs_to_jiffies(timeout_ms))) { + dev_err(dev, "timed out waiting for response\n"); + return -ETIMEDOUT; + } + + ret =3D regmap_bulk_read(max77759->regmap_maxq, + MAX77759_MAXQ_REG_AP_DATAIN0, + rsp->rsp, rsp->length); + if (ret) { + dev_err(dev, "reading response failed: %d\n", ret); + return ret; + } + + /* + * As per the protocol, the first byte of the reply will match the + * request. + */ + if (cmd->cmd[0] !=3D rsp->rsp[0]) { + dev_err(dev, "unexpected opcode response for %#.2x: %*ph\n", + cmd->cmd[0], (int)rsp->length, rsp->rsp); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL_GPL(max77759_maxq_command); + +static irqreturn_t apcmdres_irq_handler(int irq, void *irq_data) +{ + struct max77759 *max77759 =3D irq_data; + + regmap_write(max77759->regmap_maxq, MAX77759_MAXQ_REG_UIC_INT1, + MAX77759_MAXQ_REG_UIC_INT1_APCMDRESI); + + complete(&max77759->cmd_done); + + return IRQ_HANDLED; +} + +static int max77759_create_i2c_subdev(struct i2c_client *client, + struct max77759 *max77759, + const struct max77759_i2c_subdev *sd) +{ + struct i2c_client *sub; + struct regmap *regmap; + int ret; + + /* + * If 'sd' has an I2C address, 'sub' will be assigned a new 'dummy' + * device, otherwise use it as-is. + */ + sub =3D client; + if (sd->i2c_address) { + sub =3D devm_i2c_new_dummy_device(&client->dev, + client->adapter, + sd->i2c_address); + + if (IS_ERR(sub)) + return dev_err_probe(&client->dev, PTR_ERR(sub), + "failed to claim I2C device %s\n", + sd->cfg->name); + } + + regmap =3D devm_regmap_init_i2c(sub, sd->cfg); + if (IS_ERR(regmap)) + return dev_err_probe(&sub->dev, PTR_ERR(regmap), + "regmap init for '%s' failed\n", + sd->cfg->name); + + ret =3D regmap_attach_dev(&client->dev, regmap, sd->cfg); + if (ret) + return dev_err_probe(&client->dev, ret, + "regmap attach of '%s' failed\n", + sd->cfg->name); + + if (sd->id =3D=3D MAX77759_I2C_SUBDEV_ID_MAXQ) + max77759->regmap_maxq =3D regmap; + else if (sd->id =3D=3D MAX77759_I2C_SUBDEV_ID_CHARGER) + max77759->regmap_charger =3D regmap; + + return 0; +} + +static int max77759_add_chained_irq_chip(struct device *dev, + struct regmap *regmap, + int pirq, + struct regmap_irq_chip_data *parent, + const struct regmap_irq_chip *chip, + struct regmap_irq_chip_data **data) +{ + int irq, ret; + + irq =3D regmap_irq_get_virq(parent, pirq); + if (irq < 0) + return dev_err_probe(dev, irq, + "failed to get parent vIRQ(%d) for chip %s\n", + pirq, chip->name); + + ret =3D devm_regmap_add_irq_chip(dev, regmap, irq, + IRQF_ONESHOT | IRQF_SHARED, 0, chip, + data); + if (ret) + return dev_err_probe(dev, ret, "failed to add %s IRQ chip\n", + chip->name); + + return 0; +} + +static int max77759_add_chained_maxq(struct i2c_client *client, + struct max77759 *max77759, + struct regmap_irq_chip_data *parent) +{ + struct regmap_irq_chip_data *irq_chip_data; + int apcmdres_irq; + int ret; + + ret =3D max77759_add_chained_irq_chip(&client->dev, + max77759->regmap_maxq, + MAX77759_INT_MAXQ, + parent, + &max77759_maxq_irq_chip, + &irq_chip_data); + if (ret) + return ret; + + init_completion(&max77759->cmd_done); + apcmdres_irq =3D regmap_irq_get_virq(irq_chip_data, + MAX77759_MAXQ_INT_APCMDRESI); + + ret =3D devm_request_threaded_irq(&client->dev, apcmdres_irq, + NULL, apcmdres_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + dev_name(&client->dev), max77759); + if (ret) + return dev_err_probe(&client->dev, ret, + "MAX77759_MAXQ_INT_APCMDRESI failed\n"); + + ret =3D devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, + max77759_maxq_cells, + ARRAY_SIZE(max77759_maxq_cells), + NULL, 0, + regmap_irq_get_domain(irq_chip_data)); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to add child devices (MaxQ)\n"); + + return 0; +} + +static int max77759_add_chained_topsys(struct i2c_client *client, + struct max77759 *max77759, + struct regmap_irq_chip_data *parent) +{ + struct regmap_irq_chip_data *irq_chip_data; + int ret; + + ret =3D max77759_add_chained_irq_chip(&client->dev, + max77759->regmap_top, + MAX77759_INT_TOPSYS, + parent, + &max77759_topsys_irq_chip, + &irq_chip_data); + if (ret) + return ret; + + return 0; +} + +static int max77759_add_chained_charger(struct i2c_client *client, + struct max77759 *max77759, + struct regmap_irq_chip_data *parent) +{ + struct regmap_irq_chip_data *irq_chip_data; + int ret; + + ret =3D max77759_add_chained_irq_chip(&client->dev, + max77759->regmap_charger, + MAX77759_INT_CHGR, + parent, + &max77759_chrg_irq_chip, + &irq_chip_data); + if (ret) + return ret; + + ret =3D devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, + max77759_charger_cells, + ARRAY_SIZE(max77759_charger_cells), + NULL, 0, + regmap_irq_get_domain(irq_chip_data)); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to add child devices (charger)\n"); + + return 0; +} + +static int max77759_probe(struct i2c_client *client) +{ + struct regmap_irq_chip_data *irq_chip_data_pmic; + struct irq_data *irq_data; + struct max77759 *max77759; + unsigned long irq_flags; + unsigned int pmic_id; + int ret; + + max77759 =3D devm_kzalloc(&client->dev, sizeof(*max77759), GFP_KERNEL); + if (!max77759) + return -ENOMEM; + + i2c_set_clientdata(client, max77759); + + max77759->regmap_top =3D devm_regmap_init_i2c(client, + &max77759_regmap_config_top); + if (IS_ERR(max77759->regmap_top)) + return dev_err_probe(&client->dev, PTR_ERR(max77759->regmap_top), + "regmap init for '%s' failed\n", + max77759_regmap_config_top.name); + + ret =3D regmap_read(max77759->regmap_top, + MAX77759_PMIC_REG_PMIC_ID, &pmic_id); + if (ret) + return dev_err_probe(&client->dev, ret, + "unable to read device ID\n"); + + if (pmic_id !=3D MAX77759_CHIP_ID) + return dev_err_probe(&client->dev, -ENODEV, + "unsupported device ID %#.2x (%d)\n", + pmic_id, pmic_id); + + ret =3D devm_mutex_init(&client->dev, &max77759->maxq_lock); + if (ret) + return ret; + + for (int i =3D 0; i < ARRAY_SIZE(max77759_i2c_subdevs); i++) { + ret =3D max77759_create_i2c_subdev(client, max77759, + &max77759_i2c_subdevs[i]); + if (ret) + return ret; + } + + irq_data =3D irq_get_irq_data(client->irq); + if (!irq_data) + return dev_err_probe(&client->dev, -EINVAL, + "invalid IRQ: %d\n", client->irq); + + irq_flags =3D IRQF_ONESHOT | IRQF_SHARED; + irq_flags |=3D irqd_get_trigger_type(irq_data); + + ret =3D devm_regmap_add_irq_chip(&client->dev, max77759->regmap_top, + client->irq, irq_flags, 0, + &max77759_pmic_irq_chip, + &irq_chip_data_pmic); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to add IRQ chip '%s'\n", + max77759_pmic_irq_chip.name); + + ret =3D max77759_add_chained_maxq(client, max77759, irq_chip_data_pmic); + if (ret) + return ret; + + ret =3D max77759_add_chained_topsys(client, max77759, irq_chip_data_pmic); + if (ret) + return ret; + + ret =3D max77759_add_chained_charger(client, max77759, irq_chip_data_pmic= ); + if (ret) + return ret; + + return devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, + max77759_cells, ARRAY_SIZE(max77759_cells), + NULL, 0, + regmap_irq_get_domain(irq_chip_data_pmic)); +} + +static const struct i2c_device_id max77759_i2c_id[] =3D { + { "max77759" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max77759_i2c_id); + +static const struct of_device_id max77759_of_id[] =3D { + { .compatible =3D "maxim,max77759", }, + { } +}; +MODULE_DEVICE_TABLE(of, max77759_of_id); + +static struct i2c_driver max77759_i2c_driver =3D { + .driver =3D { + .name =3D "max77759", + .of_match_table =3D max77759_of_id, + }, + .probe =3D max77759_probe, + .id_table =3D max77759_i2c_id, +}; +module_i2c_driver(max77759_i2c_driver); + +MODULE_AUTHOR("Andr=C3=A9 Draszik "); +MODULE_DESCRIPTION("Maxim MAX77759 core driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/max77759.h b/include/linux/mfd/max77759.h new file mode 100644 index 0000000000000000000000000000000000000000..c6face34e38555cbc09db413192= 5b6ed781af511 --- /dev/null +++ b/include/linux/mfd/max77759.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2020 Google Inc. + * Copyright 2025 Linaro Ltd. + * + * Maxim MAX77759 core driver + */ + +#ifndef __LINUX_MFD_MAX77759_H +#define __LINUX_MFD_MAX77759_H + +#include +#include +#include + +#define MAX77759_PMIC_REG_PMIC_ID 0x00 +#define MAX77759_PMIC_REG_PMIC_REVISION 0x01 +#define MAX77759_PMIC_REG_OTP_REVISION 0x02 +#define MAX77759_PMIC_REG_INTSRC 0x22 +#define MAX77759_PMIC_REG_INTSRCMASK 0x23 +#define MAX77759_PMIC_REG_INTSRC_MAXQ BIT(3) +#define MAX77759_PMIC_REG_INTSRC_TOPSYS BIT(1) +#define MAX77759_PMIC_REG_INTSRC_CHGR BIT(0) +#define MAX77759_PMIC_REG_TOPSYS_INT 0x24 +#define MAX77759_PMIC_REG_TOPSYS_INT_MASK 0x26 +#define MAX77759_PMIC_REG_TOPSYS_INT_TSHDN BIT(6) +#define MAX77759_PMIC_REG_TOPSYS_INT_SYSOVLO BIT(5) +#define MAX77759_PMIC_REG_TOPSYS_INT_SYSUVLO BIT(4) +#define MAX77759_PMIC_REG_TOPSYS_INT_FSHIP BIT(0) +#define MAX77759_PMIC_REG_I2C_CNFG 0x40 +#define MAX77759_PMIC_REG_SWRESET 0x50 +#define MAX77759_PMIC_REG_CONTROL_FG 0x51 + +#define MAX77759_MAXQ_REG_UIC_INT1 0x64 +#define MAX77759_MAXQ_REG_UIC_INT1_APCMDRESI BIT(7) +#define MAX77759_MAXQ_REG_UIC_INT1_SYSMSGI BIT(6) +#define MAX77759_MAXQ_REG_UIC_INT1_GPIO6I BIT(1) +#define MAX77759_MAXQ_REG_UIC_INT1_GPIO5I BIT(0) +#define MAX77759_MAXQ_REG_UIC_INT1_GPIOxI(offs, en) (((en) & 1) << (off= s)) +#define MAX77759_MAXQ_REG_UIC_INT1_GPIOxI_MASK(offs) \ + MAX77759_MAXQ_REG_UIC_INT1_GPIOxI(offs, ~0) +#define MAX77759_MAXQ_REG_UIC_INT2 0x65 +#define MAX77759_MAXQ_REG_UIC_INT3 0x66 +#define MAX77759_MAXQ_REG_UIC_INT4 0x67 +#define MAX77759_MAXQ_REG_UIC_UIC_STATUS1 0x68 +#define MAX77759_MAXQ_REG_UIC_UIC_STATUS2 0x69 +#define MAX77759_MAXQ_REG_UIC_UIC_STATUS3 0x6a +#define MAX77759_MAXQ_REG_UIC_UIC_STATUS4 0x6b +#define MAX77759_MAXQ_REG_UIC_UIC_STATUS5 0x6c +#define MAX77759_MAXQ_REG_UIC_UIC_STATUS6 0x6d +#define MAX77759_MAXQ_REG_UIC_UIC_STATUS7 0x6f +#define MAX77759_MAXQ_REG_UIC_UIC_STATUS8 0x6f +#define MAX77759_MAXQ_REG_UIC_INT1_M 0x70 +#define MAX77759_MAXQ_REG_UIC_INT2_M 0x71 +#define MAX77759_MAXQ_REG_UIC_INT3_M 0x72 +#define MAX77759_MAXQ_REG_UIC_INT4_M 0x73 +#define MAX77759_MAXQ_REG_AP_DATAOUT0 0x81 +#define MAX77759_MAXQ_REG_AP_DATAOUT32 0xa1 +#define MAX77759_MAXQ_REG_AP_DATAIN0 0xb1 +#define MAX77759_MAXQ_REG_UIC_SWRST 0xe0 + +#define MAX77759_CHGR_REG_CHG_INT 0xb0 +#define MAX77759_CHGR_REG_CHG_INT2 0xb1 +#define MAX77759_CHGR_REG_CHG_INT_MASK 0xb2 +#define MAX77759_CHGR_REG_CHG_INT2_MASK 0xb3 +#define MAX77759_CHGR_REG_CHG_INT_OK 0xb4 +#define MAX77759_CHGR_REG_CHG_DETAILS_00 0xb5 +#define MAX77759_CHGR_REG_CHG_DETAILS_01 0xb6 +#define MAX77759_CHGR_REG_CHG_DETAILS_02 0xb7 +#define MAX77759_CHGR_REG_CHG_DETAILS_03 0xb8 +#define MAX77759_CHGR_REG_CHG_CNFG_00 0xb9 +#define MAX77759_CHGR_REG_CHG_CNFG_01 0xba +#define MAX77759_CHGR_REG_CHG_CNFG_02 0xbb +#define MAX77759_CHGR_REG_CHG_CNFG_03 0xbc +#define MAX77759_CHGR_REG_CHG_CNFG_04 0xbd +#define MAX77759_CHGR_REG_CHG_CNFG_05 0xbe +#define MAX77759_CHGR_REG_CHG_CNFG_06 0xbf +#define MAX77759_CHGR_REG_CHG_CNFG_07 0xc0 +#define MAX77759_CHGR_REG_CHG_CNFG_08 0xc1 +#define MAX77759_CHGR_REG_CHG_CNFG_09 0xc2 +#define MAX77759_CHGR_REG_CHG_CNFG_10 0xc3 +#define MAX77759_CHGR_REG_CHG_CNFG_11 0xc4 +#define MAX77759_CHGR_REG_CHG_CNFG_12 0xc5 +#define MAX77759_CHGR_REG_CHG_CNFG_13 0xc6 +#define MAX77759_CHGR_REG_CHG_CNFG_14 0xc7 +#define MAX77759_CHGR_REG_CHG_CNFG_15 0xc8 +#define MAX77759_CHGR_REG_CHG_CNFG_16 0xc9 +#define MAX77759_CHGR_REG_CHG_CNFG_17 0xca +#define MAX77759_CHGR_REG_CHG_CNFG_18 0xcb +#define MAX77759_CHGR_REG_CHG_CNFG_19 0xcc + +/* MaxQ opcodes for max77759_maxq_command() */ +#define MAX77759_MAXQ_OPCODE_MAXLENGTH (MAX77759_MAXQ_REG_AP_DATAOUT32 - \ + MAX77759_MAXQ_REG_AP_DATAOUT0 + \ + 1) + +#define MAX77759_MAXQ_OPCODE_GPIO_TRIGGER_READ 0x21 +#define MAX77759_MAXQ_OPCODE_GPIO_TRIGGER_WRITE 0x22 +#define MAX77759_MAXQ_OPCODE_GPIO_CONTROL_READ 0x23 +#define MAX77759_MAXQ_OPCODE_GPIO_CONTROL_WRITE 0x24 +#define MAX77759_MAXQ_OPCODE_USER_SPACE_READ 0x81 +#define MAX77759_MAXQ_OPCODE_USER_SPACE_WRITE 0x82 + +/** + * struct max77759 - core max77759 internal data structure + * + * @regmap_top: Regmap for accessing TOP registers + * @maxq_lock: Lock for serializing access to MaxQ + * @regmap_maxq: Regmap for accessing MaxQ registers + * @cmd_done: Used to signal completion of a MaxQ command + * @regmap_charger: Regmap for accessing charger registers + * + * The MAX77759 comprises several sub-blocks, namely TOP, MaxQ, Charger, + * Fuel Gauge, and TCPCI. + */ +struct max77759 { + struct regmap *regmap_top; + + /* This protects MaxQ commands - only one can be active */ + struct mutex maxq_lock; + struct regmap *regmap_maxq; + struct completion cmd_done; + + struct regmap *regmap_charger; +}; + +/** + * struct max77759_maxq_command - structure containing the MaxQ command to + * send + * + * @length: The number of bytes to send. + * @cmd: The data to send. + */ +struct max77759_maxq_command { + u8 length; + u8 cmd[] __counted_by(length); +}; + +/** + * struct max77759_maxq_response - structure containing the MaxQ response + * + * @length: The number of bytes to receive. + * @rsp: The data received. Must have at least @length bytes space. + */ +struct max77759_maxq_response { + u8 length; + u8 rsp[] __counted_by(length); +}; + +/** + * max77759_maxq_command() - issue a MaxQ command and wait for the response + * and associated data + * + * @max77759: The core max77759 device handle. + * @cmd: The command to be sent. + * @rsp: Any response data associated with the command will be copied here; + * can be %NULL if the command has no response (other than ACK). + * + * Return: 0 on success, a negative error number otherwise. + */ +int max77759_maxq_command(struct max77759 *max77759, + const struct max77759_maxq_command *cmd, + struct max77759_maxq_response *rsp); + +#endif /* __LINUX_MFD_MAX77759_H */ --=20 2.49.0.901.g37484f566f-goog From nobody Sun Feb 8 18:08:51 2026 Received: from mail-ej1-f42.google.com (mail-ej1-f42.google.com [209.85.218.42]) (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 A204229B21D for ; Tue, 29 Apr 2025 08:22:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914935; cv=none; b=kQU8HgXpzKm92DwVQvuS58l3if4OI0m3fe3RkwsIHNMkitwKtkWI84uWI5RH6TUoXeusNOTXpjixnuo/x5XGqu8SE8aKhcR/0/gMiVSSARxciVbGY+67rZx9IYmhiL6cf94TIJu6RXfLZFy27k0gyEwFp0uzQ/b1vqr5qrOiYYA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914935; c=relaxed/simple; bh=fzKstZUVeQBSYl0cS0pI2cvSc+v8nYyTBa1Wr1QDJPU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Uzo7uXQqC2JQvgp6V5/I8ogN4pBup31vT27KdscNA1ZANS5T0sdTDKMsXrrZEUpDRrD3XyP61PWhZvDAjVvkMxOrK2G7H0BmE46encboRXkWwim1SSXgo8YYEsqb6IpQkC83n21B9A4fuJUyK6RsrYGNfjgt7msSJtbi/csVuLI= 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=yN+9lhIx; arc=none smtp.client-ip=209.85.218.42 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="yN+9lhIx" Received: by mail-ej1-f42.google.com with SMTP id a640c23a62f3a-ace333d5f7bso927508166b.3 for ; Tue, 29 Apr 2025 01:22:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1745914930; x=1746519730; 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=mygQ5tEgtTV0ftu+MUNaQUht9cpvP+4gLNPLiSnhTGk=; b=yN+9lhIxmLUNQQ6VTb7P2pYYJVQoRum3/Vzpndv5HyyiyW4o4vDjAgilaAe3J1i34B HylJHJ8HldSrZ9iTjxJVjyI4opF+eqmuQ9G66V7WvfjFojflMtBwkCCCe9KIDuvVFhaj AwxmZMJaU/2R5Za6M9efcd5PFcYh8f8TVLLp7eXPR97Z+1BFSuqUXdBcmrJMWeLoOhSi kVahVP7iYP7edpJTi41JFS5q+4aqUH4AC0+LX7+vOohx/dES7APMIpvFxTTghCOaULiq P03kn4ZeeT+z0s9RpeDVlhwfOzIhmpSw5Q9M8Oz7GSbrfDI2lTR7OxLQjoznfrXceGEQ fS3Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745914930; x=1746519730; 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=mygQ5tEgtTV0ftu+MUNaQUht9cpvP+4gLNPLiSnhTGk=; b=k0ypKRfetMnJ8OBfs83bT+V8oK2CrDDB00xSDZrqj560FulltAnz20hZdGWq9Mrktq B4+XVsvk/CZB1dcUjCQ9rhsk/kbcMEiDJdYq/Beuqy1TOYnwpgeVgKtyszRQg5ZwbvFE KwmyMSM2GvSU64K3OaPrGjwaORVZp2rAWJUhlHfLKK4dwzd7+cMesvLyGVZx/YT/Zmin 3SjgThraNQiPg86HPZF/6aqIH/5tTItgaPsKjyaAs41COdN2ksXqN0rESrS9hPWzMRvj NoeDIETeyczybx6bKPfO3RMH28SXAHCnG+rZyksbIRBvRLEQFw0vpj81t9j1RmEpiBzY u4ww== X-Forwarded-Encrypted: i=1; AJvYcCUGxLxTkx0t69jMmBQZhsXvVJvYCWAOVFgsFh5K2fPOIpcb8a+E/Oo4JPKjh6024JKVUVad1VmL75M7HhM=@vger.kernel.org X-Gm-Message-State: AOJu0Yzu/Di+bsXD0G5bZ0IM+B/W+o/LKk0bOuX6710TRSZFcKmMztdG h+MBV34dKtt/5re4pvXdRvWYcDLRakZEQPRCJZ43WwfN8RPhrs8AqmcuQkSLqqE= X-Gm-Gg: ASbGnctBoZOICzDmI49Vkq3hCIH6EISEHLHXRpKSg4jvJH3ViSx4eIfuPU4DdRIEqFB g+sDtO3Ot2tDx41/x6ISUCvQGEqAUHXx3rlAzqXHIp7kqgXF4q3JTV4PxFj7j+TeKOayEfEBaJm 8wZYhfvBiXCoiQrKgSZsQumRJNedmvYcVzv34gDrqnbES62JwYWrclXN1cJucJ02y5D+dhLBrto O0xfa6z67Jj3x00znZ0vGG4yz1fxqOWHliCE2QW/J6aYbg9ouF4Mj2Kd9+W5RB2oEw/zpFPw4C8 Tnx1GPa94cvKcsXKR5HSMLZKukAzwkF2Jm4PTsJ/qyeuDCSEBjJWdWdo9xfvvJXfeCQ+jj9kOgp pWk8S9V2XLdzj4GSzpiYqbe1O X-Google-Smtp-Source: AGHT+IGJBIyjyssjwSYc5tWtf3900ENeYx9rADm33OqV4nrIeVXZ4KdXhVTJ7NWmlVnzTjqPm/LxNw== X-Received: by 2002:a17:907:2d90:b0:ac3:5c8e:d3f5 with SMTP id a640c23a62f3a-ace8493ae33mr1140096066b.27.1745914929932; Tue, 29 Apr 2025 01:22:09 -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-ace6e41bbf4sm737905466b.36.2025.04.29.01.22.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Apr 2025 01:22:09 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Tue, 29 Apr 2025 09:21:41 +0100 Subject: [PATCH v8 5/6] gpio: max77759: add Maxim MAX77759 gpio driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250429-max77759-mfd-v8-5-72d72dc79a1f@linaro.org> References: <20250429-max77759-mfd-v8-0-72d72dc79a1f@linaro.org> In-Reply-To: <20250429-max77759-mfd-v8-0-72d72dc79a1f@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?Andr=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 driver supports the GPIO functions using the platform device registered by the core MFD driver. Signed-off-by: Andr=C3=A9 Draszik Acked-by: Bartosz Golaszewski Reviewed-by: Linus Walleij --- 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..0db5e1fe64930e85265913e6a7d= d2669c645cf42 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14668,6 +14668,7 @@ M: Andr=C3=A9 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 =20 diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9ae806f45e19c1494d156b7f04b1882be68d3e3f..bbc71cdde9ed66b2fe69dcbc750= 8d51690d2cfa4 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. =20 +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..1abae4477ed76b88aff08e83f6d= 41e58d0b71ff5 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_GPIO_MAX730X) +=3D gpio-max730x.o obj-$(CONFIG_GPIO_MAX732X) +=3D gpio-max732x.o obj-$(CONFIG_GPIO_MAX77620) +=3D gpio-max77620.o obj-$(CONFIG_GPIO_MAX77650) +=3D gpio-max77650.o +obj-$(CONFIG_GPIO_MAX77759) +=3D gpio-max77759.o obj-$(CONFIG_GPIO_MB86S7X) +=3D gpio-mb86s7x.o obj-$(CONFIG_GPIO_MC33880) +=3D gpio-mc33880.o obj-$(CONFIG_GPIO_MENZ127) +=3D gpio-menz127.o diff --git a/drivers/gpio/gpio-max77759.c b/drivers/gpio/gpio-max77759.c new file mode 100644 index 0000000000000000000000000000000000000000..7fe8e6f697d044ebf9c620f41e5= 9f150a6ae086a --- /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[] =3D { "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 =3D 0, + MAX77759_GPIO_TRIGGER_FALLING =3D 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 =3D 0, + MAX77759_GPIO_DIR_OUT =3D 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] =3D MAX77759_MAXQ_OPCODE_GPIO_TRIGGER_READ; + + ret =3D 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] =3D MAX77759_MAXQ_OPCODE_GPIO_TRIGGER_WRITE; + cmd->cmd[1] =3D 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] =3D MAX77759_MAXQ_OPCODE_GPIO_CONTROL_READ; + + ret =3D 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] =3D MAX77759_MAXQ_OPCODE_GPIO_CONTROL_WRITE; + cmd->cmd[1] =3D 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 =3D !!(ctrl & MAX77759_GPIOx_DIR_MASK(offset)); + return ((dir =3D=3D 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 =3D gpiochip_get_data(gc); + int ctrl; + + ctrl =3D 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 =3D gpiochip_get_data(gc); + int ctrl, new_ctrl; + + guard(mutex)(&chip->maxq_lock); + + ctrl =3D max77759_gpio_maxq_gpio_control_read(chip); + if (ctrl < 0) + return ctrl; + + new_ctrl =3D ctrl & ~MAX77759_GPIOx_DIR_MASK(offset); + new_ctrl |=3D MAX77759_GPIOx_DIR(offset, dir); + + if (dir =3D=3D MAX77759_GPIO_DIR_OUT) { + new_ctrl &=3D ~MAX77759_GPIOx_OUTVAL_MASK(offset); + new_ctrl |=3D MAX77759_GPIOx_OUTVAL(offset, value); + } + + if (new_ctrl =3D=3D 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 offs= et) +{ + struct max77759_gpio_chip *chip =3D gpiochip_get_data(gc); + int ctrl, mask; + + ctrl =3D 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 =3D ((max77759_gpio_direction_from_control(ctrl, offset) + =3D=3D 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 =3D gpiochip_get_data(gc); + int ctrl, new_ctrl; + + guard(mutex)(&chip->maxq_lock); + + ctrl =3D max77759_gpio_maxq_gpio_control_read(chip); + if (ctrl < 0) + return ctrl; + + new_ctrl =3D ctrl & ~MAX77759_GPIOx_OUTVAL_MASK(offset); + new_ctrl |=3D MAX77759_GPIOx_OUTVAL(offset, value); + + if (new_ctrl =3D=3D 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 =3D irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip =3D gpiochip_get_data(gc); + irq_hw_number_t hwirq =3D irqd_to_hwirq(d); + + chip->irq_mask &=3D ~MAX77759_MAXQ_REG_UIC_INT1_GPIOxI_MASK(hwirq); + chip->irq_mask |=3D MAX77759_MAXQ_REG_UIC_INT1_GPIOxI(hwirq, 1); + chip->irq_mask_changed |=3D 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 =3D irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip =3D gpiochip_get_data(gc); + irq_hw_number_t hwirq =3D irqd_to_hwirq(d); + + gpiochip_enable_irq(gc, hwirq); + + chip->irq_mask &=3D ~MAX77759_MAXQ_REG_UIC_INT1_GPIOxI_MASK(hwirq); + chip->irq_mask |=3D MAX77759_MAXQ_REG_UIC_INT1_GPIOxI(hwirq, 0); + chip->irq_mask_changed |=3D MAX77759_MAXQ_REG_UIC_INT1_GPIOxI(hwirq, 1); +} + +static int max77759_gpio_set_irq_type(struct irq_data *d, unsigned int typ= e) +{ + struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip =3D gpiochip_get_data(gc); + irq_hw_number_t hwirq =3D irqd_to_hwirq(d); + + chip->irq_trig &=3D ~MAX77759_GPIOx_TRIGGER_MASK(hwirq); + switch (type) { + case IRQ_TYPE_EDGE_RISING: + chip->irq_trig |=3D MAX77759_GPIOx_TRIGGER(hwirq, + MAX77759_GPIO_TRIGGER_RISING); + break; + + case IRQ_TYPE_EDGE_FALLING: + chip->irq_trig |=3D MAX77759_GPIOx_TRIGGER(hwirq, + MAX77759_GPIO_TRIGGER_FALLING); + break; + + default: + return -EINVAL; + } + + chip->irq_trig_changed |=3D MAX77759_GPIOx_TRIGGER(hwirq, 1); + + return 0; +} + +static void max77759_gpio_bus_lock(struct irq_data *d) +{ + struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip =3D 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 =3D max77759_gpio_maxq_gpio_control_read(chip); + trigger =3D 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 =3D trigger & ~chip->irq_trig_changed; + new_trigger |=3D (chip->irq_trig & chip->irq_trig_changed); + + /* change GPIO direction if required */ + new_ctrl =3D ctrl; + irq_trig_changed =3D chip->irq_trig_changed; + for_each_set_bit(offset, &irq_trig_changed, MAX77759_N_GPIOS) { + new_ctrl &=3D ~MAX77759_GPIOx_DIR_MASK(offset); + new_ctrl |=3D MAX77759_GPIOx_DIR(offset, MAX77759_GPIO_DIR_IN); + } + + if (new_trigger !=3D trigger) { + ret =3D 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 !=3D ctrl) { + ret =3D 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 =3D 0; + + return 0; +} + +static void max77759_gpio_bus_sync_unlock(struct irq_data *d) +{ + struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); + struct max77759_gpio_chip *chip =3D gpiochip_get_data(gc); + int ret; + + scoped_guard(mutex, &chip->maxq_lock) { + ret =3D max77759_gpio_bus_sync_unlock_helper(gc, chip); + if (ret) + goto out_unlock; + } + + ret =3D 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 =3D 0; + +out_unlock: + mutex_unlock(&chip->irq_lock); +} + +static void max77759_gpio_irq_print_chip(struct irq_data *d, struct seq_fi= le *p) +{ + struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); + + seq_puts(p, dev_name(gc->parent)); +} + +static const struct irq_chip max77759_gpio_irq_chip =3D { + .irq_mask =3D max77759_gpio_irq_mask, + .irq_unmask =3D max77759_gpio_irq_unmask, + .irq_set_type =3D max77759_gpio_set_irq_type, + .irq_bus_lock =3D max77759_gpio_bus_lock, + .irq_bus_sync_unlock =3D max77759_gpio_bus_sync_unlock, + .irq_print_chip =3D max77759_gpio_irq_print_chip, + .flags =3D IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static irqreturn_t max77759_gpio_irqhandler(int irq, void *data) +{ + struct max77759_gpio_chip *chip =3D data; + struct gpio_chip *gc =3D &chip->gc; + bool handled =3D false; + + /* iterate until no interrupt is pending */ + while (true) { + unsigned int uic_int1; + int ret; + unsigned long pending; + int offset; + + ret =3D 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 =3D uic_int1; + pending &=3D (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 =3D 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 =3D devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->map =3D dev_get_regmap(pdev->dev.parent, "maxq"); + if (!chip->map) + return dev_err_probe(&pdev->dev, -ENODEV, "Missing regmap\n"); + + irq =3D platform_get_irq_byname(pdev, "GPI"); + if (irq < 0) + return dev_err_probe(&pdev->dev, irq, "Failed to get IRQ\n"); + + chip->max77759 =3D dev_get_drvdata(pdev->dev.parent); + ret =3D devm_mutex_init(&pdev->dev, &chip->maxq_lock); + if (ret) + return ret; + ret =3D devm_mutex_init(&pdev->dev, &chip->irq_lock); + if (ret) + return ret; + + chip->gc.base =3D -1; + chip->gc.label =3D dev_name(&pdev->dev); + chip->gc.parent =3D &pdev->dev; + chip->gc.can_sleep =3D true; + + chip->gc.names =3D max77759_gpio_line_names; + chip->gc.ngpio =3D MAX77759_N_GPIOS; + chip->gc.get_direction =3D max77759_gpio_get_direction; + chip->gc.direction_input =3D max77759_gpio_direction_input; + chip->gc.direction_output =3D max77759_gpio_direction_output; + chip->gc.get =3D max77759_gpio_get_value; + chip->gc.set_rv =3D max77759_gpio_set_value; + + girq =3D &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 =3D NULL; + girq->num_parents =3D 0; + girq->parents =3D NULL; + girq->default_type =3D IRQ_TYPE_NONE; + girq->handler =3D handle_simple_irq; + girq->threaded =3D true; + + ret =3D 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 =3D IRQF_ONESHOT | IRQF_SHARED; + irqd =3D irq_get_irq_data(irq); + if (irqd) + irq_flags |=3D irqd_get_trigger_type(irqd); + + ret =3D 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[] =3D { + { .compatible =3D "maxim,max77759-gpio", }, + { } +}; +MODULE_DEVICE_TABLE(of, max77759_gpio_of_id); + +static const struct platform_device_id max77759_gpio_platform_id[] =3D { + { "max77759-gpio", }, + { } +}; +MODULE_DEVICE_TABLE(platform, max77759_gpio_platform_id); + +static struct platform_driver max77759_gpio_driver =3D { + .driver =3D { + .name =3D "max77759-gpio", + .probe_type =3D PROBE_PREFER_ASYNCHRONOUS, + .of_match_table =3D max77759_gpio_of_id, + }, + .probe =3D max77759_gpio_probe, + .id_table =3D max77759_gpio_platform_id, +}; + +module_platform_driver(max77759_gpio_driver); + +MODULE_AUTHOR("Andr=C3=A9 Draszik "); +MODULE_DESCRIPTION("GPIO driver for Maxim MAX77759"); +MODULE_LICENSE("GPL"); --=20 2.49.0.901.g37484f566f-goog From nobody Sun Feb 8 18:08:51 2026 Received: from mail-ej1-f50.google.com (mail-ej1-f50.google.com [209.85.218.50]) (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 7F5082949F4 for ; Tue, 29 Apr 2025 08:22:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914936; cv=none; b=VQrCKE6tBXqym1sifYkfMe1CcP58UUZh2W1N3+1e0Dnd7lctX/1seLtzAjF+V/iy8UU440A8TDpN7KDjmHt2817pLcWxsZsNM0Fr6WMD+Gc7LHXkVnodoC3fbLe8XOG4NTww7jfMajSZSV4XwOg/rxWey3GjSf39JzQnbCReSfU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745914936; c=relaxed/simple; bh=qXh1LhaYLkXSWWH/b3QjTmcFi9Y6Mcen5lXF4ti3jus=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Ol02RjQ0XfqGZCChQJPr19DLtztGwdxDECv78XeNZHHB4f7PxvXQQPs3hg910EwyCtmUDb1TiDmkZBdcrUFsjP7GUAaDeTYjV+JKFUiFjCV8zpvEvBRm4h9aoPq0Cxdms8/PNgI8qEWS9zLTk9ignLg9aqQv/2MbcbYtmZn++Ws= 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=KHOvBL1t; arc=none smtp.client-ip=209.85.218.50 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="KHOvBL1t" Received: by mail-ej1-f50.google.com with SMTP id a640c23a62f3a-ac2bdea5a38so824942666b.0 for ; Tue, 29 Apr 2025 01:22:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1745914930; x=1746519730; 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=f56V+PMS/zh+2CuvUyMs7Dtx3aNokKMlJLq1w/Edaiw=; b=KHOvBL1tLAGU+ewZwQH2P2ES4uSJEmmcXGVnodhcit+aJaW2V7TLqe0W37CASytjE8 7cFOpimni5CTQseJ7mQmyDvkkrVk6QPMByP/T6W/A/gHG2K9+C8psEDdOdUoOuZCRtiX 45EJr5NEGJAlMszM+E1r5tjg2WKq6p+ukojIAtclg8LZCMtnK/e1k20WfmTlyXkaSpT8 OemeIgQmCWSRXNMtCiM2TJPThqGGOTuMjd++vwLYY/gE4mGgnUJ29q8aro2P7L2767A9 K4moAClZwECLuohGbi6qdyjsumqYO8i5rXwr/SWrjTEWn5aIEWlesSDDjU6C6BDbRY+2 FW5Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745914930; x=1746519730; 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=f56V+PMS/zh+2CuvUyMs7Dtx3aNokKMlJLq1w/Edaiw=; b=WdCU92GAlGD3/cSobnIkrZ2vztOfxFsXnaxx6pRARHwCDape72ZEta3TOPEapQoeCR UE/9xd5P1kJasRlTvibxl/dKYpfWTiiHL3FNTbSjncfjFi3wYxftQN+HffyqayFO/hs0 BimUGmRV4PYos4WK/HKEGKgKCOgcs3DW7SNNd4joxODuNUvc+h3C3AV7BYQ0Bsp3SRNr 0MOFRkl55Hr12PuXyo39D4oxWJxuM/ngxNavqdcDVV/+dyZjhQnlzDV4K5yf8dcGUe0L XBkwOPQsppKd0L7g8FOb/urTCE/yqq8Sds4gW3h5sab8udPISUIT3OP+3wQVJLOC+C/S Cm+Q== X-Forwarded-Encrypted: i=1; AJvYcCVUowtfrONJbvHO5rPx87psVPfZY3O16dxuh3e2EOf8n/ockf9O8dtSsoMiI+6Zu7d+0xpmAKupIyocirU=@vger.kernel.org X-Gm-Message-State: AOJu0YzA5jG5LqkYdS/Rv1DwGU2z9TwAP8/055I0uHzGGtFTaid1ucTD Q+u8VElLHxzGbNGWvLl5D2vaSIqis7HYQ0i+4GOk4L3ztvMXmqliQGbM/bYOcWw= X-Gm-Gg: ASbGncun6u2bEfX7yQ8ptz3gg9ZgcST1OgRbnwGJgIIt2YvC39TBWSnb6IHB3FBkNh/ rO/1s4hBDe20t+tLTMPHG8x7Ao69wVAK2wtadD6BcfxOTwX89OoNbAvrkDPx9EfVINgSKWg1KfK X7AUK6GZMpDT+0FlJ8Dg0Y/QjUm8KHzHws0rtXwPTjByFE0teBczejnCkXGwpXcRka689G8b7Hp cSkU6+yOgC1mvyDeGOzUhQ4D7CDiPLmerv9PVUzAd2M8rITwv+2nYc4mF4QJnl6n/5m+RI2bS4r a239/yBhJHsvSpCtpIFTZkUH2dDOFexsqN6fDGG1UeiFnFajESqRTABmsiLVA/8MmOHl3rq96gR XK6DK1pbPLeUrPCCF2aIRqhbT X-Google-Smtp-Source: AGHT+IGj8hisvwsc6IDrQZfOJ2kFI+cl+XZ/yhKxkqTWsDCHln82PCyF+lR+RtDEIFXKTgUNw9lP8g== X-Received: by 2002:a17:907:8688:b0:ace:6a18:595c with SMTP id a640c23a62f3a-acec4b7e233mr195098766b.16.1745914930482; Tue, 29 Apr 2025 01:22:10 -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-ace6e41bbf4sm737905466b.36.2025.04.29.01.22.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Apr 2025 01:22:10 -0700 (PDT) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Tue, 29 Apr 2025 09:21:42 +0100 Subject: [PATCH v8 6/6] nvmem: max77759: add Maxim MAX77759 NVMEM driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250429-max77759-mfd-v8-6-72d72dc79a1f@linaro.org> References: <20250429-max77759-mfd-v8-0-72d72dc79a1f@linaro.org> In-Reply-To: <20250429-max77759-mfd-v8-0-72d72dc79a1f@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?Andr=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 driver exposes the non volatile memory using the platform device registered by the core MFD driver. Signed-off-by: Andr=C3=A9 Draszik --- v8: * replace MODULE_ALIAS() with .id_table (Krzysztof) * drop previous tags v5: * follow API updates of max77759 core driver v2: * align sentinel in max77759_nvmem_of_id[] with other max77759 drivers (Christophe) --- MAINTAINERS | 1 + drivers/nvmem/Kconfig | 12 +++ drivers/nvmem/Makefile | 2 + drivers/nvmem/max77759-nvmem.c | 162 +++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 177 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0db5e1fe64930e85265913e6a7dd2669c645cf42..b821502afc48f95d48fb8c6ac69= 41d1dd8e63582 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14670,6 +14670,7 @@ S: Maintained F: Documentation/devicetree/bindings/*/maxim,max77759*.yaml F: drivers/gpio/gpio-max77759.c F: drivers/mfd/max77759.c +F: drivers/nvmem/max77759-nvmem.c F: include/linux/mfd/max77759.h =20 MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 8671b7c974b933e147154bb40b5d41b5730518d2..3de07ef524906ad24a89e58abdf= e93529a83c80f 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -154,6 +154,18 @@ config NVMEM_LPC18XX_OTP To compile this driver as a module, choose M here: the module will be called nvmem_lpc18xx_otp. =20 +config NVMEM_MAX77759 + tristate "Maxim Integrated MAX77759 NVMEM Support" + depends on MFD_MAX77759 + default MFD_MAX77759 + help + Say Y here to include support for the user-accessible storage found + in Maxim Integrated MAX77759 PMICs. This IC provides space for 30 + bytes of storage. + + This driver can also be built as a module. If so, the module + will be called nvmem-max77759. + config NVMEM_MESON_EFUSE tristate "Amlogic Meson GX eFuse Support" depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 5b77bbb6488bf89bfb305750a1cbf4a6731a0a58..a9d03cfbbd27e68d40f8c330e72= e20378b12a481 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -34,6 +34,8 @@ obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) +=3D nvmem_lpc18xx_eep= rom.o nvmem_lpc18xx_eeprom-y :=3D lpc18xx_eeprom.o obj-$(CONFIG_NVMEM_LPC18XX_OTP) +=3D nvmem_lpc18xx_otp.o nvmem_lpc18xx_otp-y :=3D lpc18xx_otp.o +obj-$(CONFIG_NVMEM_MAX77759) +=3D nvmem-max77759.o +nvmem-max77759-y :=3D max77759-nvmem.o obj-$(CONFIG_NVMEM_MESON_EFUSE) +=3D nvmem_meson_efuse.o nvmem_meson_efuse-y :=3D meson-efuse.o obj-$(CONFIG_NVMEM_MESON_MX_EFUSE) +=3D nvmem_meson_mx_efuse.o diff --git a/drivers/nvmem/max77759-nvmem.c b/drivers/nvmem/max77759-nvmem.c new file mode 100644 index 0000000000000000000000000000000000000000..df7d1998fa2f116450d2fd50eba= 70d9b61a24574 --- /dev/null +++ b/drivers/nvmem/max77759-nvmem.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright 2020 Google Inc +// Copyright 2025 Linaro Ltd. +// +// NVMEM driver for Maxim MAX77759 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX77759_NVMEM_OPCODE_HEADER_LEN 3 +/* + * NVMEM commands have a three byte header (which becomes part of the comm= and), + * so we need to subtract that. + */ +#define MAX77759_NVMEM_SIZE (MAX77759_MAXQ_OPCODE_MAXLENGTH \ + - MAX77759_NVMEM_OPCODE_HEADER_LEN) + +struct max77759_nvmem { + struct device *dev; + struct max77759 *max77759; +}; + +static bool max77759_nvmem_is_valid(unsigned int offset, size_t bytes) +{ + return (offset + bytes - 1 <=3D MAX77759_NVMEM_SIZE); +} + +static int max77759_nvmem_reg_read(void *priv, unsigned int offset, + void *val, size_t bytes) +{ + struct max77759_nvmem *nvmem =3D priv; + DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length, + MAX77759_NVMEM_OPCODE_HEADER_LEN); + DEFINE_FLEX(struct max77759_maxq_response, rsp, rsp, length, + MAX77759_MAXQ_OPCODE_MAXLENGTH); + int ret; + + if (!max77759_nvmem_is_valid(offset, bytes)) { + dev_err(nvmem->dev, "outside NVMEM area: %u / %zu\n", + offset, bytes); + return -EINVAL; + } + + cmd->cmd[0] =3D MAX77759_MAXQ_OPCODE_USER_SPACE_READ; + cmd->cmd[1] =3D offset; + cmd->cmd[2] =3D bytes; + rsp->length =3D bytes + MAX77759_NVMEM_OPCODE_HEADER_LEN; + + ret =3D max77759_maxq_command(nvmem->max77759, cmd, rsp); + if (ret < 0) + return ret; + + if (memcmp(cmd->cmd, rsp->rsp, MAX77759_NVMEM_OPCODE_HEADER_LEN)) { + dev_warn(nvmem->dev, "protocol error (read)\n"); + return -EIO; + } + + memcpy(val, &rsp->rsp[MAX77759_NVMEM_OPCODE_HEADER_LEN], bytes); + + return 0; +} + +static int max77759_nvmem_reg_write(void *priv, unsigned int offset, + void *val, size_t bytes) +{ + struct max77759_nvmem *nvmem =3D priv; + DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length, + MAX77759_MAXQ_OPCODE_MAXLENGTH); + DEFINE_FLEX(struct max77759_maxq_response, rsp, rsp, length, + MAX77759_MAXQ_OPCODE_MAXLENGTH); + int ret; + + if (!max77759_nvmem_is_valid(offset, bytes)) { + dev_err(nvmem->dev, "outside NVMEM area: %u / %zu\n", + offset, bytes); + return -EINVAL; + } + + cmd->cmd[0] =3D MAX77759_MAXQ_OPCODE_USER_SPACE_WRITE; + cmd->cmd[1] =3D offset; + cmd->cmd[2] =3D bytes; + memcpy(&cmd->cmd[MAX77759_NVMEM_OPCODE_HEADER_LEN], val, bytes); + cmd->length =3D bytes + MAX77759_NVMEM_OPCODE_HEADER_LEN; + rsp->length =3D cmd->length; + + ret =3D max77759_maxq_command(nvmem->max77759, cmd, rsp); + if (ret < 0) + return ret; + + if (memcmp(cmd->cmd, rsp->rsp, cmd->length)) { + dev_warn(nvmem->dev, "protocol error (write)\n"); + return -EIO; + } + + return 0; +} + +static int max77759_nvmem_probe(struct platform_device *pdev) +{ + struct nvmem_config config =3D { + .dev =3D &pdev->dev, + .name =3D dev_name(&pdev->dev), + .id =3D NVMEM_DEVID_NONE, + .type =3D NVMEM_TYPE_EEPROM, + .ignore_wp =3D true, + .size =3D MAX77759_NVMEM_SIZE, + .word_size =3D sizeof(u8), + .stride =3D sizeof(u8), + .reg_read =3D max77759_nvmem_reg_read, + .reg_write =3D max77759_nvmem_reg_write, + }; + struct max77759_nvmem *nvmem; + + nvmem =3D devm_kzalloc(&pdev->dev, sizeof(*nvmem), GFP_KERNEL); + if (!nvmem) + return -ENOMEM; + + nvmem->dev =3D &pdev->dev; + nvmem->max77759 =3D dev_get_drvdata(pdev->dev.parent); + + config.priv =3D nvmem; + + return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config)); +} + +static const struct of_device_id max77759_nvmem_of_id[] =3D { + { .compatible =3D "maxim,max77759-nvmem", }, + { } +}; +MODULE_DEVICE_TABLE(of, max77759_nvmem_of_id); + +static const struct platform_device_id max77759_nvmem_platform_id[] =3D { + { "max77759-nvmem", }, + { } +}; +MODULE_DEVICE_TABLE(platform, max77759_nvmem_platform_id); + +static struct platform_driver max77759_nvmem_driver =3D { + .driver =3D { + .name =3D "max77759-nvmem", + .probe_type =3D PROBE_PREFER_ASYNCHRONOUS, + .of_match_table =3D max77759_nvmem_of_id, + }, + .probe =3D max77759_nvmem_probe, + .id_table =3D max77759_nvmem_platform_id, +}; + +module_platform_driver(max77759_nvmem_driver); + +MODULE_AUTHOR("Andr=C3=A9 Draszik "); +MODULE_DESCRIPTION("NVMEM driver for Maxim MAX77759"); +MODULE_LICENSE("GPL"); --=20 2.49.0.901.g37484f566f-goog