From nobody Sun Feb 8 14:34:40 2026 Received: from mail-pf1-f175.google.com (mail-pf1-f175.google.com [209.85.210.175]) (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 555332E8E07 for ; Wed, 29 Oct 2025 02:33:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761705202; cv=none; b=XY2aaks7CvuK56Ly8PWfJ/jLujseY8jdEbNAkrCefbdqw7HZ4mgSvNB0L1cBdUITfy9FCWphLiSCH0/2cwBu+ETxRH2WKYa7TPHQInVW8wenMHw7CfIYa68ElzdbA9V0zl5yrb4bVf5HyyAQVSUQ1sYK8Cdzg2KudjjtZka8REY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761705202; c=relaxed/simple; bh=RG3VjxSuk1dPK3rWGefJjSSYxJn6F7W3FX+uCWi/X38=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=RSm8OhKEAWOvME+WL3A5vWuKUZ+f7rYkVR/BVvDCp00QRMKvDP5YyfWkjeCuZpNkcy2fBEWgzOCVW4AkLhK4pEhKdKjxvVBZZRTlX2sLixAgVlXuSVW5lrFjdfjiAS+g4Pwt47zNc/6qrIgw8PucWk6OQ6IOKHSrXcRKXM8EXV8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=kaFTV6Wq; arc=none smtp.client-ip=209.85.210.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kaFTV6Wq" Received: by mail-pf1-f175.google.com with SMTP id d2e1a72fcca58-78118e163e5so441771b3a.0 for ; Tue, 28 Oct 2025 19:33:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1761705200; x=1762310000; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9d/kXcE3zchMHrpNlcXGlLJoWMLUpaE86fchVvnzwz0=; b=kaFTV6Wq01dkYhr0PveqNQDRDfkFOtiMQKuv7fDTsaURBzr+tqwblsaVitkGpKTQy+ RVuwua5//V/ynws7C+jMalqOymtor0tP/tIBDdCgNp51ZUhhpaOun1HDgItMjnoyFHFT Nd0c7/4biLEXj/621eyW4CTbgk/h2U1dvuiLdUMewAOxAMqmuvxxuXO6D7z3w5RffFCF NTOZTyC/aRxEGO8P+QqZPA13wcrR6gPKa/SW5aMgbFydJ+j7Eps3EDYXtFRV2zJ9+RyQ 0DZSkmAmIicPALlvbqbJSsJXUAR/3N7J9hPqVUbuvlDhdXTY2siTkO0nw2ZI0GPJU5H0 KHBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761705200; x=1762310000; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9d/kXcE3zchMHrpNlcXGlLJoWMLUpaE86fchVvnzwz0=; b=EAi+K9TXdjod8H+cyH3eE1UmF+5DhXAi96FVjD4VYU6fO4wpemE39As/24T6uBG14m x63mAiaQ5hoxREISu/jBsTTAu57+0l/pp8R+5jEiAChcA/rqggGr6jcXoTaLC2s1gLPS M8acYbVWWNgfaK14hNRPp+7goPSyTCvDJ96TfS/tw/cTvUOWZf0GfBb218ZFQj99KDvr fUEZaUlBPDInF/u9lwcY5zncqnYhn5KovM+qy/Xbb2xitXVBK4rph0x0qIJ9Oj5aNy0D N8s2JXariMdoF5kwM8W8/ischtvw4e8jjbMdD5JIAgQqRgCu1wBd+V0DZJzoJ+VwKnlk yRMQ== X-Forwarded-Encrypted: i=1; AJvYcCWdyJMX1CQWD4try5B4+0RU+CcOgNUrKjZrymbDc1es5AW2x5wVPfp+L/BbWWyKn/B1ucuXnpLarymbtAM=@vger.kernel.org X-Gm-Message-State: AOJu0Yx5JpKRKwLUpM56bbUQ6qnFk2wL/wtzKavnR0OGOPtJmnriRseR luzhZll1t9Whlwi2BXj9F+lD/h3m9q/TFgg/097F+bp3vgUzAtqsuOrS X-Gm-Gg: ASbGncvNdcAPrWP6JVmCHt7fkN/YNEpXwVKFpXg/jirkw/M3H01O8ymnqB7pEHqXUTt 7WXvTN1WmdQWIFmDa7VOGAZxE2wx8EZml/9dB/ffSWaa8cGdCtdUqZ4SyDy1XA56PEXmjfv1uFA kxMk9jwVKIzBYxMNepzHmr83VYzfUbpYIflgd1TOR2zQqRzAhpBzvgy9WuXwEUOYOKTQISm7wIY odzQ2NGJ+FMy/Zz4Jwd1KpEDrM+/RRDdbt59rlh2LEgxcfJk123R4frrCHuhiW27ijUyr09oNUI yvPmje2U6+nkZ+GA+WU3ZgRypIHLlHNraKMtkhQGQn9QraelknuIoGRd2BXDDQ89X8LE4iDIFsD KmuL//kD7XnZRTMnEnGeFbT4440vA09E/lQom4p3pTMOt82VPbKEXl666qBJLF4ImeOunPrRn+J wIPdkxIkibuGLXoMb0/CUPLCklZ+uS3A== X-Google-Smtp-Source: AGHT+IGWfPejzIWvEWLTpc+YxVSh6qwG2ZKdFfLW6QYjD6u0iPEqoRuk88tPfjcThSD7tSNu7dCc8Q== X-Received: by 2002:a17:90b:2ecf:b0:33d:ad58:cb6a with SMTP id 98e67ed59e1d1-340286bc823mr3849615a91.8.1761705199443; Tue, 28 Oct 2025 19:33:19 -0700 (PDT) Received: from HYB-iPCgmhaB8Cy.ad.analog.com ([59.9.235.253]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-b7127bf47a1sm11826966a12.10.2025.10.28.19.33.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Oct 2025 19:33:17 -0700 (PDT) From: Joan-Na-adi X-Google-Original-From: Joan-Na-adi To: Liam Girdwood Cc: Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Joan Na Subject: [PATCH v5 1/2] regulator: dt-bindings: Add MAX77675 regulator binding Date: Wed, 29 Oct 2025 11:32:52 +0900 Message-Id: <20251029023253.150257-2-joan.na@analog.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251029023253.150257-1-joan.na@analog.com> References: <20251029023253.150257-1-joan.na@analog.com> 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 From: Joan Na Add device tree binding YAML schema for the Maxim MAX77675 PMIC regulator. This defines the node properties and supported regulator names for use in device tree sources. Signed-off-by: Joan Na --- .../bindings/regulator/maxim,max77675.yaml | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/maxim,max77= 675.yaml diff --git a/Documentation/devicetree/bindings/regulator/maxim,max77675.yam= l b/Documentation/devicetree/bindings/regulator/maxim,max77675.yaml new file mode 100644 index 000000000000..5d4a643ea5b1 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/maxim,max77675.yaml @@ -0,0 +1,186 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/maxim,max77675.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX77675 PMIC Regulator + +maintainers: + - Joan Na + +description: + The MAX77675 is a Power Management IC providing four switching buck + regulators (SBB0=E2=80=93SBB3) accessible via I2C. It supports configura= tion + of output voltages and enable controls for each regulator. + +allOf: + - $ref: /schemas/input/input.yaml + +properties: + compatible: + const: maxim,max77675 + + reg: + maxItems: 1 + + reset-time-sec: + description: Manual reset time in seconds + enum: [4, 8, 12, 16] + default: 4 + + maxim,en-mode: + description: | + Enable mode configuration. + The debounce time set by 'maxim,debounce-time-us' applies to + both push-button and slide-switch modes. + "push-button" - A long press triggers power-on or power-down + "slide-switch" - Low level powers on, high level powers down + "logic" - Low level powers on, high level powers down (no deb= ounce time) + $ref: /schemas/types.yaml#/definitions/string + enum: [push-button, slide-switch, logic] + default: slide-switch + + maxim,voltage-change-latency-us: + description: + Specifies the delay (in microseconds) between an output voltage chan= ge request + and the start of the SBB voltage ramp. + enum: [10, 100] + default: 100 + + maxim,drv-sbb-strength: + description: | + SIMO Buck-Boost Drive Strength Trim. + Controls the drive strength of the SIMO regulator's power MOSFETs. + This setting affects the switching speed, which impacts power effici= ency and EMI. + "max" =E2=80=93 Maximum drive strength (~0.6 ns transition time) + "high" =E2=80=93 High drive strength (~1.2 ns transition time) + "low" =E2=80=93 Low drive strength (~1.8 ns transition time) + "min" =E2=80=93 Minimum drive strength (~8 ns transition time) + $ref: /schemas/types.yaml#/definitions/string + enum: [max, high, low, min] + default: max + + maxim,dvs-slew-rate-mv-per-us: + description: + Dynamic rising slew rate for output voltage transitions, in mV/=CE= =BCs. + This setting is only used when 'maxim,fixed-slew-rate' is not presen= t. + enum: [5, 10] + default: 5 + + maxim,debounce-time-us: + description: Debounce time for the enable pin, in microseconds + enum: [100, 30000] + default: 100 + + maxim,en-pullup-disable: + type: boolean + description: Disable internal pull-up for EN pin + default: false + + maxim,bias-low-power-request: + type: boolean + description: Request low-power bias mode + default: false + + maxim,simo-int-ldo-always-on: + type: boolean + description: Set internal LDO to always supply 1.8V + default: false + + regulators: + type: object + description: Regulator child nodes + patternProperties: + "^sbb[0-3]$": + type: object + $ref: regulator.yaml# + properties: + maxim,fps-slot: + description: | + FPS (Flexible Power Sequencer) slot selection. + The Flexible Power Sequencer allows resources to power up un= der + hardware or software control. Additionally, each resource can + power up independently or among a group of other regulators = with + adjustable power-up and power-down slots. + "slot0" - Assign to FPS Slot 0 + "slot1" - Assign to FPS Slot 1 + "slot2" - Assign to FPS Slot 2 + "slot3" - Assign to FPS Slot 3 + "default" - Use the default FPS slot value stored in OTP and= read from the register + $ref: /schemas/types.yaml#/definitions/string + enum: [slot0, slot1, slot2, slot3, default] + default: default + + maxim,fixed-slew-rate: + type: boolean + description: + When this property is present, the device uses a constant 2 = mV/=CE=BCs + slew rate and ignores any dynamic slew rate configuration. + When absent, the device uses the dynamic slew rate specified + by 'maxim,dvs-slew-rate-mv-per-us' + default: true + + unevaluatedProperties: false + +required: + - compatible + - reg + - regulators + +additionalProperties: false + +examples: + - | + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + max77675: pmic@44 { + compatible =3D "maxim,max77675"; + reg =3D <0x44>; + + reset-time-sec =3D <4>; + + maxim,en-mode =3D "slide-switch"; + maxim,voltage-change-latency-us =3D <100>; + maxim,drv-sbb-strength =3D "max"; + maxim,dvs-slew-rate-mv-per-us =3D <5>; + maxim,debounce-time-us =3D <100>; + + regulators { + sbb0: sbb0 { + regulator-name =3D "sbb0"; + regulator-min-microvolt =3D <500000>; + regulator-max-microvolt =3D <5500000>; + maxim,fps-slot =3D "default"; + maxim,fixed-slew-rate; + }; + + sbb1: sbb1 { + regulator-name =3D "sbb1"; + regulator-min-microvolt =3D <500000>; + regulator-max-microvolt =3D <5500000>; + maxim,fps-slot =3D "default"; + maxim,fixed-slew-rate; + }; + + sbb2: sbb2 { + regulator-name =3D "sbb2"; + regulator-min-microvolt =3D <500000>; + regulator-max-microvolt =3D <5500000>; + maxim,fps-slot =3D "default"; + maxim,fixed-slew-rate; + }; + + sbb3: sbb3 { + regulator-name =3D "sbb3"; + regulator-min-microvolt =3D <500000>; + regulator-max-microvolt =3D <5500000>; + maxim,fps-slot =3D "default"; + maxim,fixed-slew-rate; + }; + }; + }; + }; + -- 2.34.1 From nobody Sun Feb 8 14:34:40 2026 Received: from mail-pg1-f177.google.com (mail-pg1-f177.google.com [209.85.215.177]) (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 EBEC42EBB8D for ; Wed, 29 Oct 2025 02:33:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761705208; cv=none; b=OTSD6jiWoy2lSkrrrWhPVKHeYBYAyRpQzsOXY5a0bm/TUesuwWfDat4P1vZN+3/zSszRxUNR+TATPQU4D+lBnqCzba2Igy9qG+X+9er4g0yiYl6SHmGSWAkm92CUVteQXv702sAEIWPyrgYVs8AdrWkQNJr3pUoZrIKWBHYtjPM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761705208; c=relaxed/simple; bh=Oow8Ag7vguZNXxe8lqwfjZzi97Ch2SfWu3SsjvifdmA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=VbTs2xaBMaCnaf3SOPTtS/fxqyq0b8AjZQhRvYzfvKCeZ1ntD0FL7zvE/z+K/A2TQgZ8QGrLaplCZo9gRSakwFG0UGb+Zx6nyZW1OENJ/Jm4bWwEEWkZ4UpypKXSqA9jF8GmMNOM5sa22fJMfi5dchygUsqOSqKqCukSYxLVlWw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=c36vcHJ4; arc=none smtp.client-ip=209.85.215.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="c36vcHJ4" Received: by mail-pg1-f177.google.com with SMTP id 41be03b00d2f7-b5a631b9c82so4087663a12.1 for ; Tue, 28 Oct 2025 19:33:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1761705205; x=1762310005; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=gCKCXr08PD4cDopp/Mxm2Ji9B2eL21Zy/xW+Qa1BAeA=; b=c36vcHJ4m+FmX737Tc0/FtMWsYYoBXUCF2da05UhShRdkyPMbSapmLeC7FF4W+4d/i VaVeCpSzCZRg9YmM8UJ1bJotEbXxAxmU7wrPa0K9bHMaMKNNZFeN9aIqkyP58iUQvLGK Pzm0sWPMOLhXurFH0fNw3T8JimQStipisr6Lgc5/o8Oopp51lzaHgW1ZVTcLdsq0FiNH bigTGKkrElzCcPg4D0VpG3EnGaiZtXS5CtInqqq3FiSAN7jhNiX8/fzGgPilAT0aBMUl /1Lr8XaXPXjw+h/NVqs/I1P9YU0w76IM1wfMzLQccV4/KE4cDcOYPYV3fvUMOkz51T89 6BoQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761705205; x=1762310005; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=gCKCXr08PD4cDopp/Mxm2Ji9B2eL21Zy/xW+Qa1BAeA=; b=snLZ7AICPo+sVc8ahkPZxDzg9iW7W8MbnP3HTJqDz7iRqP+mxMOsZKEfp5HYAUz/MV FzIWErWif/PwmDQv3xJSgNIy2WemV6kp7edd6jhuvBV/JDSjp9NN+GJgYgd7RF9oaODL LOG6JrY2cjD5qc830+03iNcvDnilmUZ5Q4BvHHfka7qqk7uehFRp+sFhfuMLqJECCUFy HYNKmfGdeBBkBQCx6IssSxinNFqajIPvtz7+oekRekzeMOq3gcZiQr8wA5cOE+t6KJe+ oCmrn3kOcw65UBQw7rHqnzq9FXYnqtAJ+dieqGd0Jq189FEpT72kQtSM55mlQ5hnfXM7 CkuQ== X-Forwarded-Encrypted: i=1; AJvYcCVVwDK+YvmvwNxuFa1m+XWPLMcyLKlSW6hlUzND5eB48mmSUILhUUYmO+s50LAPjsWMT2cukCnQaZGnMhI=@vger.kernel.org X-Gm-Message-State: AOJu0YwsAlYSQXrT337TPq5XU348p0mL5IDm8p7nTKDxmrZ/vGEcIRF6 likG6wgqOX1beXJhTSoa0w6diITmCB6/jeUtPBI7L9hgdwWnHy4kKDzn X-Gm-Gg: ASbGncvRTn2JlPXASmdnSd6/DL3Fad17AJx+0iZ+kD4uMkBLwQ47i0jrZdZloHaTGmM 2n0jhUlCnIPacgXQ7559qpdb2pZDjRiSV3zuMmlNupluNtmMAOfqLAoEvjhRXccNkFlYE9YEQFG emot+gkey1mT4b0Fqevsmqc2qTB7GYHcXWK4hVtZ/GbXalH/2vn88WqsCWNd76Vl9MziPjzWYA0 dKXQLzUmv1YhuGOsA2QFQTtPNYr6wwuAyF//i000bA/7LjLOhjtNVeQF7ln635uusjSrRyF7isB sWGggecNaauAjb+2sjR/0PAv44IRCX4b0Vub324dEhLVo0LisTmLsjbkhu9Pq9SqZkZypA6KRQ4 Axp+aJgyeUQlESGdfV5qiMf7/g9ZnAk9lX/QPTJJ0Evhz77IPBJbeNuu35y7ljPb2WTqPHNCNLm tWQZY476gVOuf3j+jd/nAdMmGjU9Cs/g== X-Google-Smtp-Source: AGHT+IGXlW567gCNF0gwuqpbZixblKrwSQBahIqSQ1SHM2XS5dKZj8Gs7mVB7pSzN88xFdtv6atuVA== X-Received: by 2002:a17:903:230b:b0:235:e8da:8d1 with SMTP id d9443c01a7336-294dedfc92bmr12144555ad.8.1761705205015; Tue, 28 Oct 2025 19:33:25 -0700 (PDT) Received: from HYB-iPCgmhaB8Cy.ad.analog.com ([59.9.235.253]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-b7127bf47a1sm11826966a12.10.2025.10.28.19.33.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Oct 2025 19:33:24 -0700 (PDT) From: Joan-Na-adi X-Google-Original-From: Joan-Na-adi To: Liam Girdwood Cc: Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Joan Na Subject: [PATCH v5 2/2] regulator: max77675: Add MAX77675 regulator driver Date: Wed, 29 Oct 2025 11:32:53 +0900 Message-Id: <20251029023253.150257-3-joan.na@analog.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251029023253.150257-1-joan.na@analog.com> References: <20251029023253.150257-1-joan.na@analog.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Joan Na Add support for the Maxim Integrated MAX77675 PMIC regulator. The MAX77675 is a compact, highly efficient SIMO (Single Inductor Multiple = Output) power management IC that provides four programmable buck-boost switching re= gulators with only one inductor. It supports up to 700mA total output current and op= erates from a single-cell Li-ion battery. An integrated power-up sequencer and I2C interface allow flexible startup configuration and runtime control. Signed-off-by: Joan Na --- drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/max77675-regulator.c | 861 +++++++++++++++++++++++++ drivers/regulator/max77675-regulator.h | 260 ++++++++ 4 files changed, 1131 insertions(+) create mode 100644 drivers/regulator/max77675-regulator.c create mode 100644 drivers/regulator/max77675-regulator.h diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index d84f3d054c59..93131446e402 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -649,6 +649,15 @@ config REGULATOR_MAX77650 Semiconductor. This device has a SIMO with three independent power rails and an LDO. +config REGULATOR_MAX77675 + tristate "Maxim MAX77675 regulator driver" + depends on I2C + select REGMAP_I2C + help + This driver controls the Maxim MAX77675 power regulator via I2C. + It supports four programmable buck-boost outputs. + Say Y here to enable the regulator driver + config REGULATOR_MAX77857 tristate "ADI MAX77857/MAX77831 regulator support" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b3101376029d..cdd99669cd24 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MAX77503) +=3D max77503-regulator.o obj-$(CONFIG_REGULATOR_MAX77541) +=3D max77541-regulator.o obj-$(CONFIG_REGULATOR_MAX77620) +=3D max77620-regulator.o obj-$(CONFIG_REGULATOR_MAX77650) +=3D max77650-regulator.o +obj-$(CONFIG_REGULATOR_MAX77675) +=3D max77675-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) +=3D max8649.o obj-$(CONFIG_REGULATOR_MAX8660) +=3D max8660.o obj-$(CONFIG_REGULATOR_MAX8893) +=3D max8893.o diff --git a/drivers/regulator/max77675-regulator.c b/drivers/regulator/max= 77675-regulator.c new file mode 100644 index 000000000000..c1281f07fe43 --- /dev/null +++ b/drivers/regulator/max77675-regulator.c @@ -0,0 +1,861 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2025 Analog Devices, Inc. + * ADI regulator driver for MAX77675. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "max77675-regulator.h" + +struct max77675_regulator_pdata { + u8 fps_slot; + bool fixed_slew_rate; +}; + +struct max77675_config { + u8 en_mode; + u8 voltage_change_latency; + u8 drv_sbb_strength; + u8 dvs_slew_rate; + u8 debounce_time; + u8 manual_reset_time; + bool en_pullup_disable; + bool bias_low_power_request; + bool simo_int_ldo_always_on; +}; + +struct max77675_regulator { + struct device *dev; + struct regmap *regmap; + struct max77675_config config; + struct max77675_regulator_pdata pdata[MAX77675_ID_NUM_MAX]; +}; + +/** + * Set latency mode. + * + * @param maxreg Pointer to max77675 device structure. + * @param enable true to enable latency mode, false to disable. + */ +static int max77675_set_latency_mode(struct max77675_regulator *maxreg, bo= ol enable) +{ + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_B, + MAX77675_LAT_MODE_BIT, + FIELD_PREP(MAX77675_LAT_MODE_BIT, enable)); +} + +/** + * Set DVS slew rate mode. + * + * @param maxreg Pointer to max77675 device structure. + * @param enable true to use DVS-controlled slew rate, false for fixed 2mV= /us. + */ +static int max77675_set_dvs_slew_rate(struct max77675_regulator *maxreg, b= ool enable) +{ + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_B, + MAX77675_DVS_SLEW_BIT, + FIELD_PREP(MAX77675_DVS_SLEW_BIT, enable)); +} + +/** + * Set drive strength. + * + * @param maxreg Pointer to max77675 device structure. + * @param strength 2-bit drive strength value (0-3). + * + * @return 0 on success, negative error code on failure. + */ +static int max77675_set_drv_sbb_strength(struct max77675_regulator *maxreg= , u8 strength) +{ + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_A, + MAX77675_DRV_SBB_MASK, + FIELD_PREP(MAX77675_DRV_SBB_MASK, strength)); +} + +/** + * Set manual reset time (MRT) for EN pin. + * + * @param maxreg Pointer to max77675 device structure. + * @param mrt 2-bit value (0x0: 4s, 0x1: 8s, 0x2: 12s, 0x3: 16s) + */ +static int max77675_set_manual_reset_time(struct max77675_regulator *maxre= g, u8 mrt) +{ + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_MRT_MASK, + FIELD_PREP(MAX77675_MRT_MASK, mrt)); +} + +/** + * Enable or disable internal pull-up resistor on EN pin. + * + * @param maxreg Pointer to max77675 device structure. + * @param disable true to disable pull-up, false to enable + */ +static int max77675_set_en_pullup_disable(struct max77675_regulator *maxre= g, bool disable) +{ + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_PU_DIS_BIT, + FIELD_PREP(MAX77675_PU_DIS_BIT, disable)); +} + +/** + * Request main bias to enter low-power mode. + * + * @param maxreg Pointer to max77675 device structure. + * @param enable true to request low-power mode, false for normal + */ +static int max77675_set_bias_low_power_request(struct max77675_regulator *= maxreg, bool enable) +{ + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_BIAS_LPM_BIT, + FIELD_PREP(MAX77675_BIAS_LPM_BIT, enable)); +} + +/** + * Force SIMO internal LDO to always supply 1.8V. + * + * @param maxreg Pointer to max77675 device structure. + * @param enable true to always supply 1.8V, false for normal operation + */ +static int max77675_set_simo_int_ldo_always_on(struct max77675_regulator *= maxreg, bool enable) +{ + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_SIMO_CH_DIS_BIT, + FIELD_PREP(MAX77675_SIMO_CH_DIS_BIT, enable)); +} + +/** + * Set EN pin mode. + * + * @param maxreg Pointer to max77675 device structure. + * @param mode 2-bit value: 0x0 (push-button), 0x1 (slide-switch), 0x2 (lo= gic) + */ +static int max77675_set_en_mode(struct max77675_regulator *maxreg, u8 mode) +{ + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_EN_MODE_MASK, + FIELD_PREP(MAX77675_EN_MODE_MASK, mode)); +} + +/** + * Set debounce time for EN pin. + * + * @param maxreg Pointer to max77675 device structure. + * @param debounce_30ms true for 30ms, false for 100us + */ +static int max77675_set_debounce_time(struct max77675_regulator *maxreg, b= ool debounce_30ms) +{ + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_DBEN_EN_BIT, + FIELD_PREP(MAX77675_DBEN_EN_BIT, debounce_30ms)); +} + +static int max77675_regulator_get_fps_src(struct max77675_regulator *maxre= g, int id) +{ + unsigned int reg_addr; + unsigned int val; + int ret; + + switch (id) { + case MAX77675_ID_SBB0: + reg_addr =3D MAX77675_REG_CNFG_SBB0_B; + break; + case MAX77675_ID_SBB1: + reg_addr =3D MAX77675_REG_CNFG_SBB1_B; + break; + case MAX77675_ID_SBB2: + reg_addr =3D MAX77675_REG_CNFG_SBB2_B; + break; + case MAX77675_ID_SBB3: + reg_addr =3D MAX77675_REG_CNFG_SBB3_B; + break; + default: + dev_err(maxreg->dev, "Invalid regulator id: %d\n", id); + return -EINVAL; + } + + ret =3D regmap_read(maxreg->regmap, reg_addr, &val); + if (ret < 0) { + dev_err(maxreg->dev, "Failed to read FPS source (reg 0x%02x): %d\n", + reg_addr, ret); + return ret; + } + + return val & MAX77675_EN_SBB_MASK; +} + +static int max77675_regulator_set_fps_src(struct max77675_regulator *maxre= g, int id, u8 fps_src) +{ + unsigned int reg_addr; + int ret; + + switch (id) { + case MAX77675_ID_SBB0: + reg_addr =3D MAX77675_REG_CNFG_SBB0_B; + break; + case MAX77675_ID_SBB1: + reg_addr =3D MAX77675_REG_CNFG_SBB1_B; + break; + case MAX77675_ID_SBB2: + reg_addr =3D MAX77675_REG_CNFG_SBB2_B; + break; + case MAX77675_ID_SBB3: + reg_addr =3D MAX77675_REG_CNFG_SBB3_B; + break; + default: + dev_err(maxreg->dev, "Invalid regulator id: %d\n", id); + return -EINVAL; + } + + ret =3D regmap_update_bits(maxreg->regmap, reg_addr, + MAX77675_EN_SBB_MASK, fps_src); + if (ret < 0) { + dev_err(maxreg->dev, "Failed to set FPS source (reg 0x%02x): %d\n", + reg_addr, ret); + return ret; + } + + return 0; +} + +/** + * max77675_set_sbb_slew_rate_fixed - Set the slew rate for a specific SBB= regulator channel + * + * @maxreg: Pointer to the max77675 regulator structure + * @id: Regulator channel ID (ID_SBB0 ~ ID_SBB3) + * @fixed: Slew rate value (true =3D 2mV/us, false =3D use DVS_SLEW) + * + * This function configures the slew rate control source for the specified= SBB channel by + * updating the corresponding bits in the CNFG_SBB_TOP_B register. + * + * Return: 0 on success, negative error code on failure (e.g., invalid cha= nnel ID). + */ +static int max77675_set_sbb_slew_rate_fixed(struct max77675_regulator *max= reg, int id, bool fixed) +{ + u8 mask, value; + u8 slew_src_ctrl_bit =3D fixed ? 0 : 1; + + switch (id) { + case MAX77675_ID_SBB0: + mask =3D MAX77675_SR_SBB0_BIT; + value =3D FIELD_PREP(MAX77675_SR_SBB0_BIT, slew_src_ctrl_bit); + break; + + case MAX77675_ID_SBB1: + mask =3D MAX77675_SR_SBB1_BIT; + value =3D FIELD_PREP(MAX77675_SR_SBB1_BIT, slew_src_ctrl_bit); + break; + + case MAX77675_ID_SBB2: + mask =3D MAX77675_SR_SBB2_BIT; + value =3D FIELD_PREP(MAX77675_SR_SBB2_BIT, slew_src_ctrl_bit); + break; + + case MAX77675_ID_SBB3: + mask =3D MAX77675_SR_SBB3_BIT; + value =3D FIELD_PREP(MAX77675_SR_SBB3_BIT, slew_src_ctrl_bit); + break; + + default: + return -EINVAL; + } + + return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_B, ma= sk, value); +} + +static int max77675_init_regulator(struct max77675_regulator *maxreg, int = id) +{ + struct max77675_regulator_pdata *rpdata =3D &maxreg->pdata[id]; + int ret; + + if (rpdata->fps_slot =3D=3D MAX77675_FPS_DEF) { + ret =3D max77675_regulator_get_fps_src(maxreg, id); + if (ret < 0) { + dev_err(maxreg->dev, "Failed to read FPS source for ID %d\n", id); + return ret; + } + rpdata->fps_slot =3D ret; + } else { + ret =3D max77675_regulator_set_fps_src(maxreg, id, rpdata->fps_slot); + if (ret) + dev_warn(maxreg->dev, "Failed to set FPS source for ID %d\n", id); + } + + ret =3D max77675_set_sbb_slew_rate_fixed(maxreg, id, rpdata->fixed_slew_r= ate); + if (ret) + dev_warn(maxreg->dev, "Failed to set slew rate for ID %d\n", id); + + return 0; +} + +static int max77675_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct max77675_regulator *maxreg =3D config->driver_data; + struct max77675_regulator_pdata *rpdata =3D &maxreg->pdata[desc->id]; + u32 pval; + int ret; + + /* Parse FPS slot from DT */ + ret =3D of_property_read_u32(np, "maxim,fps-slot", &pval); + rpdata->fps_slot =3D (!ret) ? (u8)pval : MAX77675_FPS_DEF; + + /* Parse slew rate control source */ + rpdata->fixed_slew_rate =3D of_property_read_bool(np, "maxim,fixed-slew-r= ate"); + + /* Apply parsed configuration */ + return max77675_init_regulator(maxreg, desc->id); +} + +static int max77675_get_error_flags(struct regulator_dev *rdev, unsigned i= nt *flags) +{ + struct max77675_regulator *maxreg =3D rdev_get_drvdata(rdev); + unsigned int int_flags; + int id =3D rdev_get_id(rdev); + int ret; + + ret =3D regmap_read(maxreg->regmap, MAX77675_REG_INT_GLBL, &int_flags); + if (ret) { + dev_err(maxreg->dev, "Failed to read INT_GLBL: %d\n", ret); + return ret; + } + + *flags =3D 0; + + switch (id) { + case MAX77675_ID_SBB0: + if (int_flags & MAX77675_INT_SBB0_F_BIT) + *flags |=3D REGULATOR_ERROR_FAIL; + break; + case MAX77675_ID_SBB1: + if (int_flags & MAX77675_INT_SBB1_F_BIT) + *flags |=3D REGULATOR_ERROR_FAIL; + break; + case MAX77675_ID_SBB2: + if (int_flags & MAX77675_INT_SBB2_F_BIT) + *flags |=3D REGULATOR_ERROR_FAIL; + break; + case MAX77675_ID_SBB3: + if (int_flags & MAX77675_INT_SBB3_F_BIT) + *flags |=3D REGULATOR_ERROR_FAIL; + break; + default: + dev_warn(maxreg->dev, "Unsupported regulator ID: %d\n", id); + break; + } + + if (int_flags & MAX77675_INT_TJAL2_R_BIT) { + /* TJAL2 interrupt: Over-temperature condition (above 120 degree) */ + *flags |=3D REGULATOR_ERROR_OVER_TEMP; + } + + return 0; +} + +static const struct regulator_ops max77675_regulator_ops =3D { + .list_voltage =3D regulator_list_voltage_linear, + .enable =3D regulator_enable_regmap, + .disable =3D regulator_disable_regmap, + .is_enabled =3D regulator_is_enabled_regmap, + .map_voltage =3D regulator_map_voltage_linear, + .set_voltage_sel =3D regulator_set_voltage_sel_regmap, + .get_voltage_sel =3D regulator_get_voltage_sel_regmap, + .set_active_discharge =3D regulator_set_active_discharge_regmap, + .get_error_flags =3D max77675_get_error_flags, +}; + +static struct regulator_desc max77675_regulators[MAX77675_ID_NUM_MAX] =3D { + { + .name =3D "sbb0", + .of_match =3D of_match_ptr("sbb0"), + .regulators_node =3D of_match_ptr("regulators"), + .of_parse_cb =3D max77675_of_parse_cb, + .id =3D MAX77675_ID_SBB0, + .ops =3D &max77675_regulator_ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, + .n_voltages =3D MAX77675_NUM_LEVELS_25MV, + .min_uV =3D MAX77675_MIN_UV, + .uV_step =3D MAX77675_STEP_25MV, + .vsel_reg =3D MAX77675_REG_CNFG_SBB0_A, + .vsel_mask =3D MAX77675_TV_SBB0_MASK, + .enable_reg =3D MAX77675_REG_CNFG_SBB0_B, + .enable_mask =3D MAX77675_EN_SBB0_MASK, + .enable_val =3D MAX77675_ENABLE_ON, + .disable_val =3D MAX77675_ENABLE_OFF, + .active_discharge_off =3D MAX77675_REGULATOR_AD_OFF, + .active_discharge_on =3D MAX77675_REGULATOR_AD_ON, + .active_discharge_mask =3D MAX77675_ADE_SBB0_BIT, + .active_discharge_reg =3D MAX77675_REG_CNFG_SBB0_B, + }, + { + .name =3D "sbb1", + .of_match =3D of_match_ptr("sbb1"), + .regulators_node =3D of_match_ptr("regulators"), + .of_parse_cb =3D max77675_of_parse_cb, + .id =3D MAX77675_ID_SBB1, + .ops =3D &max77675_regulator_ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, + .n_voltages =3D MAX77675_NUM_LEVELS_25MV, + .min_uV =3D MAX77675_MIN_UV, + .uV_step =3D MAX77675_STEP_25MV, + .vsel_reg =3D MAX77675_REG_CNFG_SBB1_A, + .vsel_mask =3D MAX77675_TV_SBB1_MASK, + .enable_reg =3D MAX77675_REG_CNFG_SBB1_B, + .enable_mask =3D MAX77675_EN_SBB1_MASK, + .enable_val =3D MAX77675_ENABLE_ON, + .disable_val =3D MAX77675_ENABLE_OFF, + .active_discharge_off =3D MAX77675_REGULATOR_AD_OFF, + .active_discharge_on =3D MAX77675_REGULATOR_AD_ON, + .active_discharge_mask =3D MAX77675_ADE_SBB1_BIT, + .active_discharge_reg =3D MAX77675_REG_CNFG_SBB1_B, + }, + { + .name =3D "sbb2", + .of_match =3D of_match_ptr("sbb2"), + .regulators_node =3D of_match_ptr("regulators"), + .of_parse_cb =3D max77675_of_parse_cb, + .id =3D MAX77675_ID_SBB2, + .ops =3D &max77675_regulator_ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, + .n_voltages =3D MAX77675_NUM_LEVELS_25MV, + .min_uV =3D MAX77675_MIN_UV, + .uV_step =3D MAX77675_STEP_25MV, + .vsel_reg =3D MAX77675_REG_CNFG_SBB2_A, + .vsel_mask =3D MAX77675_TV_SBB2_MASK, + .enable_reg =3D MAX77675_REG_CNFG_SBB2_B, + .enable_mask =3D MAX77675_EN_SBB2_MASK, + .enable_val =3D MAX77675_ENABLE_ON, + .disable_val =3D MAX77675_ENABLE_OFF, + .active_discharge_off =3D MAX77675_REGULATOR_AD_OFF, + .active_discharge_on =3D MAX77675_REGULATOR_AD_ON, + .active_discharge_mask =3D MAX77675_ADE_SBB2_BIT, + .active_discharge_reg =3D MAX77675_REG_CNFG_SBB2_B, + }, + { + .name =3D "sbb3", + .of_match =3D of_match_ptr("sbb3"), + .regulators_node =3D of_match_ptr("regulators"), + .of_parse_cb =3D max77675_of_parse_cb, + .id =3D MAX77675_ID_SBB3, + .ops =3D &max77675_regulator_ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, + .n_voltages =3D MAX77675_NUM_LEVELS_25MV, + .min_uV =3D MAX77675_MIN_UV, + .uV_step =3D MAX77675_STEP_25MV, + .vsel_reg =3D MAX77675_REG_CNFG_SBB3_A, + .vsel_mask =3D MAX77675_TV_SBB3_MASK, + .enable_reg =3D MAX77675_REG_CNFG_SBB3_B, + .enable_mask =3D MAX77675_EN_SBB3_MASK, + .enable_val =3D MAX77675_ENABLE_ON, + .disable_val =3D MAX77675_ENABLE_OFF, + .active_discharge_off =3D MAX77675_REGULATOR_AD_OFF, + .active_discharge_on =3D MAX77675_REGULATOR_AD_ON, + .active_discharge_mask =3D MAX77675_ADE_SBB3_BIT, + .active_discharge_reg =3D MAX77675_REG_CNFG_SBB3_B, + }, +}; + +static bool max77675_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX77675_REG_CNFG_GLBL_B: + /* This register can be updated by an internal state machine */ + case MAX77675_REG_INT_GLBL: + case MAX77675_REG_STAT_GLBL: + case MAX77675_REG_ERCF_GLBL: + return true; + default: + return false; + } +} + +static const struct regmap_config max77675_regmap_config =3D { + .reg_bits =3D 8, + .val_bits =3D 8, + .max_register =3D MAX77675_MAX_REGISTER, + .cache_type =3D REGCACHE_MAPLE, + .volatile_reg =3D max77675_volatile_reg, +}; + +static int max77675_apply_config(struct max77675_regulator *maxreg) +{ + const struct max77675_config *config =3D &maxreg->config; + int ret; + + ret =3D max77675_set_en_mode(maxreg, config->en_mode); + if (ret) { + dev_err(maxreg->dev, "Failed to set EN mode: %d\n", ret); + return ret; + } + + ret =3D max77675_set_latency_mode(maxreg, config->voltage_change_latency); + if (ret) { + dev_err(maxreg->dev, "Failed to set latency mode: %d\n", ret); + return ret; + } + + ret =3D max77675_set_drv_sbb_strength(maxreg, config->drv_sbb_strength); + if (ret) { + dev_err(maxreg->dev, "Failed to set drive strength: %d\n", ret); + return ret; + } + + ret =3D max77675_set_dvs_slew_rate(maxreg, config->dvs_slew_rate); + if (ret) { + dev_err(maxreg->dev, "Failed to set DVS slew rate: %d\n", ret); + return ret; + } + + ret =3D max77675_set_debounce_time(maxreg, config->debounce_time); + if (ret) { + dev_err(maxreg->dev, "Failed to set EN debounce time: %d\n", ret); + return ret; + } + + ret =3D max77675_set_manual_reset_time(maxreg, config->manual_reset_time); + if (ret) { + dev_err(maxreg->dev, "Failed to set manual reset time: %d\n", ret); + return ret; + } + + ret =3D max77675_set_en_pullup_disable(maxreg, config->en_pullup_disable); + if (ret) { + dev_err(maxreg->dev, "Failed to set EN pull-up disable: %d\n", ret); + return ret; + } + + ret =3D max77675_set_bias_low_power_request(maxreg, config->bias_low_powe= r_request); + if (ret) { + dev_err(maxreg->dev, "Failed to set bias low-power request: %d\n", ret); + return ret; + } + + ret =3D max77675_set_simo_int_ldo_always_on(maxreg, config->simo_int_ldo_= always_on); + if (ret) { + dev_err(maxreg->dev, "Failed to set SIMO internal LDO always-on: %d\n", = ret); + return ret; + } + + return 0; +} + +static u8 max77675_parse_voltage_change_latency(struct device_node *np) +{ + u32 val; + + if (!of_property_read_u32(np, "maxim,voltage-change-latency-us", &val)) { + switch (val) { + case 10: + return MAX77675_LOW_LATENCY_MODE; + case 100: + return MAX77675_HIGH_LATENCY_MODE; + default: + break; + } + } + + /* default: high latency */ + return MAX77675_HIGH_LATENCY_MODE; +} + +static u8 max77675_parse_en_mode(struct device_node *np) +{ + const char *str; + + if (!of_property_read_string(np, "maxim,en-mode", &str)) { + if (!strcasecmp(str, "push-button")) + return MAX77675_EN_PUSH_BUTTON; + else if (!strcasecmp(str, "slide-switch")) + return MAX77675_EN_SLIDE_SWITCH; + else if (!strcasecmp(str, "logic")) + return MAX77675_EN_LOGIC; + } + + /* default : slide-switch */ + return MAX77675_EN_SLIDE_SWITCH; +} + +static u8 max77675_parse_manual_reset_time(struct device_node *np) +{ + u32 val; + + if (!of_property_read_u32(np, "reset-time-sec", &val)) { + switch (val) { + case 4: + return MAX77675_MRT_4S; + case 8: + return MAX77675_MRT_8S; + case 12: + return MAX77675_MRT_12S; + case 16: + return MAX77675_MRT_16S; + default: + break; + } + } + + /* default : 4 seconds */ + return MAX77675_MRT_4S; +} + +static u8 max77675_parse_dvs_slew_rate(struct device_node *np) +{ + u32 val; + + if (!of_property_read_u32(np, "maxim,dvs-slew-rate-mv-per-us", &val)) { + switch (val) { + case 5: + return MAX77675_DVS_SLEW_5MV_PER_US; + case 10: + return MAX77675_DVS_SLEW_10MV_PER_US; + default: + break; + } + } + + /* default: 5 mV/us */ + return MAX77675_DVS_SLEW_5MV_PER_US; +} + +static u8 max77675_parse_drv_sbb_strength(struct device_node *np) +{ + const char *str; + + if (!of_property_read_string(np, "maxim,drv-sbb-strength", &str)) { + if (!strcasecmp(str, "max")) + return MAX77675_DRV_SBB_STRENGTH_MAX; + else if (!strcasecmp(str, "high")) + return MAX77675_DRV_SBB_STRENGTH_HIGH; + else if (!strcasecmp(str, "low")) + return MAX77675_DRV_SBB_STRENGTH_LOW; + else if (!strcasecmp(str, "min")) + return MAX77675_DRV_SBB_STRENGTH_MIN; + } + + /* default : maximum */ + return MAX77675_DRV_SBB_STRENGTH_MAX; +} + +static u8 max77675_parse_debounce_time_us(struct device_node *np) +{ + u32 val; + + if (!of_property_read_u32(np, "maxim,debounce-time-us", &val)) { + switch (val) { + case 100: + return MAX77675_DBEN_100US; + case 30000: + return MAX77675_DBEN_30000US; + default: + break; + } + } + + /* default: 100 us */ + return MAX77675_DBEN_100US; +} + +static int max77675_parse_config(struct max77675_regulator *maxreg) +{ + struct device_node *np =3D maxreg->dev->of_node; + struct max77675_config *config =3D &maxreg->config; + int ret; + + /* EN pin mode: push-button, slide-switch, or logic */ + config->en_mode =3D max77675_parse_en_mode(np); + + /* latency mode */ + config->voltage_change_latency =3D max77675_parse_voltage_change_latency(= np); + + /* drive strength */ + config->drv_sbb_strength =3D max77675_parse_drv_sbb_strength(np); + + /* drv slew rate */ + config->dvs_slew_rate =3D max77675_parse_dvs_slew_rate(np); + + /* Debounce time for EN pin */ + config->debounce_time =3D max77675_parse_debounce_time_us(np); + + /* Manual reset time for EN pin */ + config->manual_reset_time =3D max77675_parse_manual_reset_time(np); + + /* Disable internal pull-up resistor on EN pin */ + config->en_pullup_disable =3D of_property_read_bool(np, "maxim,en-pullup-= disable"); + + /* Request low-power mode for main bias */ + config->bias_low_power_request =3D of_property_read_bool(np, "maxim,bias-= low-power-request"); + + /* Force internal LDO to always supply 1.8V */ + config->simo_int_ldo_always_on =3D of_property_read_bool(np, "maxim,simo-= int-ldo-always-on"); + + ret =3D max77675_apply_config(maxreg); + + return ret; +} + +static int max77675_init_event(struct max77675_regulator *maxreg) +{ + unsigned int ercflag, int_glbl; + int ret; + + ret =3D regmap_read(maxreg->regmap, MAX77675_REG_ERCF_GLBL, &ercflag); + if (ret) { + dev_err(maxreg->dev, "Failed to read CID register: %d\n", ret); + return ret; + } + + ret =3D regmap_read(maxreg->regmap, MAX77675_REG_INT_GLBL, &int_glbl); + if (ret) { + dev_err(maxreg->dev, "Failed to read INT_GLBL register: %d\n", ret); + return ret; + } + + if (ercflag & MAX77675_SFT_CRST_F_BIT) + dev_info(maxreg->dev, "Software Cold Reset Flag is set\n"); + + if (ercflag & MAX77675_SFT_OFF_F_BIT) + dev_info(maxreg->dev, "Software Off Flag is set\n"); + + if (ercflag & MAX77675_MRST_BIT) + dev_info(maxreg->dev, "Manual Reset Timer Flag is set\n"); + + if (ercflag & MAX77675_UVLO_BIT) + dev_info(maxreg->dev, "Undervoltage Lockout Flag is set\n"); + + if (ercflag & MAX77675_OVLO_BIT) + dev_info(maxreg->dev, "Overvoltage Lockout Flag is set\n"); + + if (ercflag & MAX77675_TOVLD_BIT) + dev_info(maxreg->dev, "Thermal Overload Flag is set\n"); + + if (int_glbl & MAX77675_INT_SBB3_F_BIT) + dev_info(maxreg->dev, "SBB3 Channel Fault Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_SBB2_F_BIT) + dev_info(maxreg->dev, "SBB2 Channel Fault Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_SBB1_F_BIT) + dev_info(maxreg->dev, "SBB1 Channel Fault Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_SBB0_F_BIT) + dev_info(maxreg->dev, "SBB0 Channel Fault Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_TJAL2_R_BIT) + dev_info(maxreg->dev, "Thermal Alarm 2 Rising Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_TJAL1_R_BIT) + dev_info(maxreg->dev, "Thermal Alarm 1 Rising Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_EN_R_BIT) + dev_info(maxreg->dev, "nEN Rising Edge Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_EN_F_BIT) + dev_info(maxreg->dev, "nEN Falling Edge Interrupt occurred\n"); + + return 0; +} + +static int max77675_regulator_probe(struct i2c_client *client) +{ + struct max77675_regulator *maxreg; + struct regulator_config config =3D {}; + struct device_node *regulators_np; + int i, ret; + + maxreg =3D devm_kzalloc(&client->dev, sizeof(*maxreg), GFP_KERNEL); + if (!maxreg) + return -ENOMEM; + + maxreg->dev =3D &client->dev; + + maxreg->regmap =3D devm_regmap_init_i2c(client, &max77675_regmap_config); + if (IS_ERR(maxreg->regmap)) + return dev_err_probe(maxreg->dev, + PTR_ERR(maxreg->regmap), + "Failed to init regmap\n"); + + ret =3D max77675_init_event(maxreg); + if (ret) + return dev_err_probe(maxreg->dev, ret, "Failed to init event\n"); + + ret =3D max77675_parse_config(maxreg); + if (ret) + return dev_err_probe(maxreg->dev, ret, "Failed to apply config\n"); + + config.dev =3D &client->dev; + config.regmap =3D maxreg->regmap; + config.driver_data =3D maxreg; + + regulators_np =3D of_get_child_by_name(client->dev.of_node, "regulators"); + if (!regulators_np) { + dev_err(maxreg->dev, "No 'regulators' subnode found in DT\n"); + return -EINVAL; + } + + for (i =3D 0; i < MAX77675_ID_NUM_MAX; i++) { + const struct regulator_desc *desc =3D &max77675_regulators[i]; + struct regulator_dev *rdev; + + config.of_node =3D of_get_child_by_name(regulators_np, desc->name); + if (!config.of_node) { + dev_warn(maxreg->dev, "No DT node for regulator %s\n", desc->name); + continue; + } + + rdev =3D devm_regulator_register(&client->dev, desc, &config); + of_node_put(config.of_node); + if (IS_ERR(rdev)) { + of_node_put(regulators_np); + return dev_err_probe(maxreg->dev, PTR_ERR(rdev), + "Failed to register regulator %d (%s): %d\n", + i, desc->name, ret); + } + } + + of_node_put(regulators_np); + i2c_set_clientdata(client, maxreg); + + return 0; +} + +static const struct i2c_device_id max77675_i2c_id[] =3D { + { "max77675", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max77675_i2c_id); + +static const struct of_device_id __maybe_unused max77675_of_match[] =3D { + { .compatible =3D "maxim,max77675", }, + { } +}; +MODULE_DEVICE_TABLE(of, max77675_of_match); + +static struct i2c_driver max77675_regulator_driver =3D { + .driver =3D { + .name =3D "max77675", + .of_match_table =3D of_match_ptr(max77675_of_match), + }, + .probe =3D max77675_regulator_probe, + .id_table =3D max77675_i2c_id, +}; + +module_i2c_driver(max77675_regulator_driver); + +MODULE_DESCRIPTION("MAX77675 Regulator Driver"); +MODULE_AUTHOR("Joan Na "); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max77675-regulator.h b/drivers/regulator/max= 77675-regulator.h new file mode 100644 index 000000000000..0aaa30a630ca --- /dev/null +++ b/drivers/regulator/max77675-regulator.h @@ -0,0 +1,260 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * MAX77675 Register Definitions + * Reference: MAX77675 Datasheet + */ + +#ifndef __MAX77675_REG_H__ +#define __MAX77675_REG_H__ + +#include + +/* Register Addresses */ +#define MAX77675_REG_CNFG_GLBL_A 0x00 +#define MAX77675_REG_CNFG_GLBL_B 0x01 +#define MAX77675_REG_INT_GLBL 0x02 +#define MAX77675_REG_INTM_GLBL 0x03 +#define MAX77675_REG_STAT_GLBL 0x04 +#define MAX77675_REG_ERCF_GLBL 0x05 +#define MAX77675_REG_CID 0x06 +#define MAX77675_REG_CNFG_SBB_TOP_A 0x07 +#define MAX77675_REG_CNFG_SBB0_A 0x08 +#define MAX77675_REG_CNFG_SBB0_B 0x09 +#define MAX77675_REG_CNFG_SBB1_A 0x0A +#define MAX77675_REG_CNFG_SBB1_B 0x0B +#define MAX77675_REG_CNFG_SBB2_A 0x0C +#define MAX77675_REG_CNFG_SBB2_B 0x0D +#define MAX77675_REG_CNFG_SBB3_A 0x0E +#define MAX77675_REG_CNFG_SBB3_B 0x0F +#define MAX77675_REG_CNFG_SBB_TOP_B 0x10 + +/* CNFG_GLBL_A (0x00) bit masks and shifts */ +#define MAX77675_MRT_MASK GENMASK(7, 6) /* Manual Reset Time = (bits 7:6) */ +#define MAX77675_MRT_SHIFT 6 +#define MAX77675_PU_DIS_BIT BIT(5) /* Pullup Disable (bi= t 5) */ +#define MAX77675_PU_DIS_SHIFT 5 +#define MAX77675_BIAS_LPM_BIT BIT(4) /* Bias Low Power Mod= e (bit 4) */ +#define MAX77675_BIAS_LPM_SHIFT 4 +#define MAX77675_SIMO_CH_DIS_BIT BIT(3) /* SIMO Internal Chan= nel Disable (bit 3) */ +#define MAX77675_SIMO_CH_DIS_SHIFT 3 +#define MAX77675_EN_MODE_MASK GENMASK(2, 1) /* nEN Mode (bits 2:1= ) */ +#define MAX77675_EN_MODE_SHIFT 1 +#define MAX77675_DBEN_EN_BIT BIT(0) /* Debounce Enable (b= it 0) */ +#define MAX77675_DBEN_EN_SHIFT 0 + +/* CNFG_GLBL_B (0x01) */ +#define MAX77675_SFT_CTRL_MASK GENMASK(2, 0) /* Soft Start Control= */ +#define MAX77675_SFT_CTRL_SHIFT 0 + +/* INT_GLBL (0x02) bit bits and shifts */ +#define MAX77675_INT_SBB3_F_BIT BIT(7) +#define MAX77675_INT_SBB3_F_SHIFT 7 +#define MAX77675_INT_SBB2_F_BIT BIT(6) +#define MAX77675_INT_SBB2_F_SHIFT 6 +#define MAX77675_INT_SBB1_F_BIT BIT(5) +#define MAX77675_INT_SBB1_F_SHIFT 5 +#define MAX77675_INT_SBB0_F_BIT BIT(4) +#define MAX77675_INT_SBB0_F_SHIFT 4 +#define MAX77675_INT_TJAL2_R_BIT BIT(3) +#define MAX77675_INT_TJAL2_R_SHIFT 3 +#define MAX77675_INT_TJAL1_R_BIT BIT(2) +#define MAX77675_INT_TJAL1_R_SHIFT 2 +#define MAX77675_INT_EN_R_BIT BIT(1) +#define MAX77675_INT_EN_R_SHIFT 1 +#define MAX77675_INT_EN_F_BIT BIT(0) +#define MAX77675_INT_EN_F_SHIFT 0 + +/* INTM_GLBL (0x03) bits and shifts */ +#define MAX77675_INTM_SBB3_F_BIT BIT(7) +#define MAX77675_INTM_SBB3_F_SHIFT 7 +#define MAX77675_INTM_SBB2_F_BIT BIT(6) +#define MAX77675_INTM_SBB2_F_SHIFT 6 +#define MAX77675_INTM_SBB1_F_BIT BIT(5) +#define MAX77675_INTM_SBB1_F_SHIFT 5 +#define MAX77675_INTM_SBB0_F_BIT BIT(4) +#define MAX77675_INTM_SBB0_F_SHIFT 4 +#define MAX77675_INTM_TJAL2_R_BIT BIT(3) +#define MAX77675_INTM_TJAL2_R_SHIFT 3 +#define MAX77675_INTM_TJAL1_R_BIT BIT(2) +#define MAX77675_INTM_TJAL1_R_SHIFT 2 +#define MAX77675_INTM_EN_R_BIT BIT(1) +#define MAX77675_INTM_EN_R_SHIFT 1 +#define MAX77675_INTM_EN_F_BIT BIT(0) +#define MAX77675_INTM_EN_F_SHIFT 0 + +/* STAT_GLBL (0x04) bits and shifts */ +#define MAX77675_STAT_SBB3_S_BIT BIT(7) +#define MAX77675_STAT_SBB3_S_SHIFT 7 +#define MAX77675_STAT_SBB2_S_BIT BIT(6) +#define MAX77675_STAT_SBB2_S_SHIFT 6 +#define MAX77675_STAT_SBB1_S_BIT BIT(5) +#define MAX77675_STAT_SBB1_S_SHIFT 5 +#define MAX77675_STAT_SBB0_S_BIT BIT(4) +#define MAX77675_STAT_SBB0_S_SHIFT 4 +#define MAX77675_STAT_TJAL2_S_BIT BIT(2) +#define MAX77675_STAT_TJAL2_S_SHIFT 2 +#define MAX77675_STAT_TJAL1_S_BIT BIT(1) +#define MAX77675_STAT_TJAL1_S_SHIFT 1 +#define MAX77675_STAT_STAT_EN_BIT BIT(0) +#define MAX77675_STAT_STAT_EN_SHIFT 0 + +#define MAX77675_STAT_STAT_EN_BIT BIT(0) +#define MAX77675_STAT_STAT_EN_SHIFT 0 + +/* ERCFLAG (0x05) bits and shifts */ +#define MAX77675_SFT_CRST_F_BIT BIT(5) /* Software Cold Reset Flag */ +#define MAX77675_SFT_CRST_F_SHIFT 5 +#define MAX77675_SFT_OFF_F_BIT BIT(4) /* Software Off Flag */ +#define MAX77675_SFT_OFF_F_SHIFT 4 +#define MAX77675_MRST_BIT BIT(3) /* Manual Reset Timer Flag */ +#define MAX77675_MRST_SHIFT 3 +#define MAX77675_UVLO_BIT BIT(2) /* Undervoltage Lockout Flag */ +#define MAX77675_UVLO_SHIFT 2 +#define MAX77675_OVLO_BIT BIT(1) /* Overvoltage Lockout Flag */ +#define MAX77675_OVLO_SHIFT 1 +#define MAX77675_TOVLD_BIT BIT(0) /* Thermal Overload Flag */ +#define MAX77675_TOVLD_SHIFT 0 + +/* CID (0x06) bits and shifts */ +#define MAX77675_CID_MASK GENMASK(4, 0) /* Chip Identification = Code mask */ +#define MAX77675_CID_SHIFT 0 /* Starts at bit 0 */ + +/* CNFG_SBB_TOP_A (0x07) bits and shifts */ +#define MAX77675_STEP_SZ_SBB3_BIT BIT(5) +#define MAX77675_STEP_SZ_SBB3_SHIFT 5 +#define MAX77675_STEP_SZ_SBB2_BIT BIT(4) +#define MAX77675_STEP_SZ_SBB2_SHIFT 4 +#define MAX77675_STEP_SZ_SBB1_BIT BIT(3) +#define MAX77675_STEP_SZ_SBB1_SHIFT 3 +#define MAX77675_STEP_SZ_SBB0_BIT BIT(2) +#define MAX77675_STEP_SZ_SBB0_SHIFT 2 +#define MAX77675_DRV_SBB_MASK GENMASK(1, 0) +#define MAX77675_DRV_SBB_SHIFT 0 + +/* CNFG_SBB0_A (0x08) bits and shifts */ +#define MAX77675_TV_SBB0_MASK GENMASK(7, 0) +#define MAX77675_TV_SBB0_SHIFT 0 + +/* CNFG_SBB0_B (0x09) bits and shifts */ +#define MAX77675_ADE_SBB0_BIT BIT(3) +#define MAX77675_ADE_SBB0_SHIFT 3 +#define MAX77675_EN_SBB0_MASK GENMASK(2, 0) +#define MAX77675_EN_SBB0_SHIFT 0 + +/* CNFG_SBB1_A (0x0A) bits and shifts */ +#define MAX77675_TV_SBB1_MASK GENMASK(7, 0) +#define MAX77675_TV_SBB1_SHIFT 0 + +/* CNFG_SBB1_B (0x0B) bits and shifts */ +#define MAX77675_ADE_SBB1_BIT BIT(3) +#define MAX77675_ADE_SBB1_SHIFT 3 +#define MAX77675_EN_SBB1_MASK GENMASK(2, 0) +#define MAX77675_EN_SBB1_SHIFT 0 + +/* CNFG_SBB2_A (0x0C) bits and shifts */ +#define MAX77675_TV_SBB2_MASK GENMASK(7, 0) +#define MAX77675_TV_SBB2_SHIFT 0 + +/* CNFG_SBB2_B (0x0D) bits and shifts */ +#define MAX77675_ADE_SBB2_BIT BIT(3) +#define MAX77675_ADE_SBB2_SHIFT 3 +#define MAX77675_EN_SBB2_MASK GENMASK(2, 0) +#define MAX77675_EN_SBB2_SHIFT 0 + +/* CNFG_SBB3_A (0x0E) bits and shifts */ +#define MAX77675_TV_SBB3_MASK GENMASK(7, 0) +#define MAX77675_TV_SBB3_SHIFT 0 + +/* CNFG_SBB3_B (0x0F) bits and shifts */ +#define MAX77675_ADE_SBB3_BIT BIT(3) +#define MAX77675_ADE_SBB3_SHIFT 3 +#define MAX77675_EN_SBB3_MASK GENMASK(2, 0) +#define MAX77675_EN_SBB3_SHIFT 0 + +#define MAX77675_EN_SBB_MASK GENMASK(2, 0) + +/* CNFG_SBB_TOP_B (0x10) bits and shifts */ +#define MAX77675_DVS_SLEW_BIT BIT(5) +#define MAX77675_DVS_SLEW_SHIFT 5 +#define MAX77675_LAT_MODE_BIT BIT(4) +#define MAX77675_LAT_MODE_SHIFT 4 +#define MAX77675_SR_SBB3_BIT BIT(3) +#define MAX77675_SR_SBB3_SHIFT 3 +#define MAX77675_SR_SBB2_BIT BIT(2) +#define MAX77675_SR_SBB2_SHIFT 2 +#define MAX77675_SR_SBB1_BIT BIT(1) +#define MAX77675_SR_SBB1_SHIFT 1 +#define MAX77675_SR_SBB0_BIT BIT(0) +#define MAX77675_SR_SBB0_SHIFT 0 + +#define MAX77675_MAX_REGISTER 0x10 + +/* Common minimum voltage (in microvolts) */ +#define MAX77675_MIN_UV 500000 // 500 mV + +/* Voltage step configuration for 25mV mode */ +#define MAX77675_STEP_25MV 25000 // Step size: 25 mV +#define MAX77675_MAX_UV_25MV 5500000 // Max voltage: 5.5 V +#define MAX77675_NUM_LEVELS_25MV 201 // levels =3D (5500mV - 500= mV) / 25mV + 1 + +/* Voltage step configuration for 12.5mV mode */ +#define MAX77675_STEP_12_5MV 12500 // Step size: 12.5 mV +#define MAX77675_MAX_UV_12_5MV 3687500 // Max voltage: 3.6875 V +#define MAX77675_NUM_LEVELS_12_5MV 255 // levels =3D (3687.5mV - 5= 00mV) / 12.5mV + 1 + +#define MAX77675_ENABLE_OFF 0x04 +#define MAX77675_ENABLE_ON 0x06 + +#define MAX77675_REGULATOR_AD_OFF 0x00 +#define MAX77675_REGULATOR_AD_ON BIT(3) + +/* FPS source */ +#define MAX77675_FPS_SLOT_0 0x0 +#define MAX77675_FPS_SLOT_1 0x1 +#define MAX77675_FPS_SLOT_2 0x2 +#define MAX77675_FPS_SLOT_3 0x3 +#define MAX77675_FPS_DEF 0x4 + +/* nEN Manual Reset Time Configuration (MRT) */ +#define MAX77675_MRT_4S 0x0 +#define MAX77675_MRT_8S 0x1 +#define MAX77675_MRT_12S 0x2 +#define MAX77675_MRT_16S 0x3 + +/* nEN Mode Configuration */ +#define MAX77675_EN_PUSH_BUTTON 0x0 +#define MAX77675_EN_SLIDE_SWITCH 0x1 +#define MAX77675_EN_LOGIC 0x2 + +/* Debounce Timer Enable (DBEN_nEN) */ +#define MAX77675_DBEN_100US 0x0 +#define MAX77675_DBEN_30000US 0x1 + +/* Rising slew rate control for SBB0 when ramping up */ +#define MAX77675_SR_2MV_PER_US 0x0 // 2 mV/us +#define MAX77675_SR_USE_DVS 0x1 // Use DVS slew rate setting (maxim= ,dvs-slew-rate) + +/* Dynamic Voltage Scaling (DVS) Slew Rate */ +#define MAX77675_DVS_SLEW_5MV_PER_US 0x0 // 5 mV/us +#define MAX77675_DVS_SLEW_10MV_PER_US 0x1 // 10 mV/us + +/* Latency Mode */ +#define MAX77675_HIGH_LATENCY_MODE 0x0 // High latency, low quiescent c= urrent (~100us) +#define MAX77675_LOW_LATENCY_MODE 0x1 // Low latency, high quiescent c= urrent (~10us) + +/* SIMO Buck-Boost Drive Strength (All Channels) */ +#define MAX77675_DRV_SBB_STRENGTH_MAX 0x0 // Maximum drive strength (~0.= 6 ns transition time) +#define MAX77675_DRV_SBB_STRENGTH_HIGH 0x1 // High drive strength (~1.2 n= s transition time) +#define MAX77675_DRV_SBB_STRENGTH_LOW 0x2 // Low drive strength (~1.8 ns= transition time) +#define MAX77675_DRV_SBB_STRENGTH_MIN 0x3 // Minimum drive strength (~8 = ns transition time) + +/* Regulator ID enumeration */ +enum max77675_regulator_id { + MAX77675_ID_SBB0 =3D 0, + MAX77675_ID_SBB1, + MAX77675_ID_SBB2, + MAX77675_ID_SBB3, + MAX77675_ID_NUM_MAX, +}; + +#endif /* __MAX77675_REG_H__ */ -- 2.34.1