From nobody Tue Dec 2 02:04:58 2025 Received: from mail-pg1-f175.google.com (mail-pg1-f175.google.com [209.85.215.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 CFE5E337BAC for ; Thu, 20 Nov 2025 12:55:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763643342; cv=none; b=vDvhFQIGCXIWA2uFyIrYchV7NBpu1R3YuAXMiqQt1khx9Z/36hmgZrwH48oZprfMtOmSY0Nh81c0dmyuiSApYw1wZH9p/3a2YdYWidlRJp3CfZVQ3elgTWpgcc52SzSDOuSjhZy8N101qN6kugrSd0vpcvByP8+CfluZUjhnoms= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763643342; c=relaxed/simple; bh=7Qop9pQOba4WavvdpVLkW1HzG/gkZvlgTI8mQYbwu8s=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=X4CKt4d0PkTNepgB3Wr1e0Wg1CBC4brnnbTQg1gyvncWziq0Nh5wf8FPPou1pd6DHYMXWUGzM+l470AD/JYm7KlwIPmqX7hR6s5+0L2QzIBTbOOMdqsPPswudJUWkq66isdEE1rim4ctDa+JjQCWsGElx8s17Y2nnlQ0p2wc/Ws= 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=Tr0PIsWT; arc=none smtp.client-ip=209.85.215.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="Tr0PIsWT" Received: by mail-pg1-f175.google.com with SMTP id 41be03b00d2f7-ba599137cf8so378024a12.0 for ; Thu, 20 Nov 2025 04:55:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1763643340; x=1764248140; 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=RT4QXy2Xbpg+0ghciHdo8WcFPq/mhKF8gSFMuIRCiIg=; b=Tr0PIsWTqYidsSwWk9AuKbtimWlzYoqS3TGZr2agdJznHMKVgq6jwKdY+AKjDJ/YKJ btU8ncG5jz8SvWt6omAnsiWaWnhYg0yGom9Q8ZuGQdcs6BFAZpXsRNj+N6VSgx1kF1Jn VHLOQtvLDoKqyPTjAR78M8LqBPfhVtF1ZqCLye5Xa+fIlWQjUyOYNy6YN0kzMtlHOVmk nqH6eHwBicYygGn9T0u7IHuHZWmhrfbotdLTIYt2aun2kTmwtZqtzwa+sL+lfHOEKzla 4uvYONCh2b5WUsTb998A1+OeMDSEefXySzcwsuAW29qOcm6LJlr1aQ7fXEe/+F7ZaDb+ M78A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763643340; x=1764248140; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=RT4QXy2Xbpg+0ghciHdo8WcFPq/mhKF8gSFMuIRCiIg=; b=miUePF2XqCfJRJYp2+UJwUa4aRpbXpJde5HDCVjaA2lQXdPGtEHdmw0FtDOxTeAMXq eP9bXQGi82DR6U6Og0ZH11k5qp4gxrT4XR66vicj+ibxN2CR7gVTUTAMdx9rCBSUhubR 5tW34dUnIAkfh9IFssHeH2n/ZX4Zw3p09orh3SHofWRY34lxR779UVOYACyxdTguXzQh aXJqtfPB7xFRf0/SN2VfeYjkklgFK/MUJKVBxfOBegAsyuXXJ/ZpcU1WM6DqB1gOFai6 MygYUYowYw4Kdgh4dEZMhWeu/zldZPU367jHdABYHDGeK/Odxf++Rum9uxePdi2NZCD9 4ShA== X-Forwarded-Encrypted: i=1; AJvYcCWAYgzKBNXBKHTxvCAtVwSnhFXrCwt0nC8T+LlXnmPyXra5Kp3tn/i8AMpEq66gMX3DXPoCgi9zHziR6iQ=@vger.kernel.org X-Gm-Message-State: AOJu0YxT4DE58fErB4uNrrKXDsC7gHNrKr4tZd530GvifazzGWjS/ajr kPo4g2nXEZtv0pPocjzr7jM5/Wib3YjH3ET/jTSv79oIaaPP5wpnMj8j X-Gm-Gg: ASbGncsjD9XLN4sMGw3ntrUG41g98lqhmX+ckqLu7HLKGg2ZbiWoTaaQE2xbgXFjA7q 6ytIejD8KYT5EoHj7FT2O3ZppNZH6KZ6risKvv9tdJPfzsg8MAFglQrUILsYVgSsE1S6rljDS0u PzxqwZFaTdEleNZwPMJE37XBJ0uaGuRp7aGEnt9lteJ0xbfWubgBkpR39fPAaLXaLo4RCYX+fH5 r9CsIyhK80kZ1oVM7Exw7ljawZ/APi9ScIt04c7pswtgnuiDTsj0zqxHz89Riv78SikYzpeiV3+ m62AhkAs7P+icF3tsexXd9qoxU3XkoRhtkrSId8GX45c4SzTgwJfeqIDyAnB94jxmaALnizQKjJ eYd+xjkzKyoMqlzD0bO4/geIueTet7M4ajmoPk0myqBkShOk970Rd61smUuC3cbPFzRyF0dEQC1 yuJcTjlMG75c3GjLMbT2hFTkKnwqBsuw== X-Google-Smtp-Source: AGHT+IEB2LOc/vPb8PA7yWNBC8M3aZXFReRgFhNjQzoIAbwNm9dOdzdw2FZf6jVb2r+s5SUHlS8PYg== X-Received: by 2002:a17:90b:5210:b0:343:6a63:85d5 with SMTP id 98e67ed59e1d1-3472988d12cmr2798067a91.16.1763643340150; Thu, 20 Nov 2025 04:55:40 -0800 (PST) Received: from HYB-iPCgmhaB8Cy.ad.analog.com ([59.9.235.253]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-34726696b52sm2586746a91.1.2025.11.20.04.55.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Nov 2025 04:55:39 -0800 (PST) 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 v6 1/2] regulator: dt-bindings: Add MAX77675 regulator Date: Thu, 20 Nov 2025 21:54:48 +0900 Message-Id: <20251120125449.26530-2-joan.na@analog.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251120125449.26530-1-joan.na@analog.com> References: <20251120125449.26530-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. Signed-off-by: Joan Na Reviewed-by: Rob Herring (Arm) --- .../bindings/regulator/adi,max77675.yaml | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/adi,max7767= 5.yaml diff --git a/Documentation/devicetree/bindings/regulator/adi,max77675.yaml = b/Documentation/devicetree/bindings/regulator/adi,max77675.yaml new file mode 100644 index 000000000000..54cbbd59ff5b --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/adi,max77675.yaml @@ -0,0 +1,188 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/adi,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 + - $ref: /schemas/pinctrl/pincfg-node.yaml + +properties: + compatible: + const: adi,max77675 + + reg: + maxItems: 1 + + reset-time-sec: + description: Manual reset time in seconds + enum: [4, 8, 12, 16] + default: 4 + + bias-disable: + type: boolean + description: Disable internal pull-up for EN pin + default: false + + input-debounce: + description: Debounce time for the enable pin, in microseconds + items: + - enum: [100, 30000] + default: 100 + + adi,en-mode: + description: | + Enable mode configuration. + The debounce time set by 'adi,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 : powers on, High : powers down + "logic" - Low : powers on, High : powers down (no debounce ti= me) + $ref: /schemas/types.yaml#/definitions/string + enum: [push-button, slide-switch, logic] + default: slide-switch + + adi,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 + + adi,drv-sbb-strength: + description: | + SIMO Buck-Boost Drive Strength Trim. + Controls the drive strength of the SIMO regulator's power MOSFETs. + This setting affects switching speed, impacting power efficiency 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 + + adi,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 'adi,fixed-slew-rate' is not present. + enum: [5, 10] + default: 5 + + adi,bias-low-power-request: + type: boolean + description: Request low-power bias mode + default: false + + adi,simo-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: + adi,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 register + $ref: /schemas/types.yaml#/definitions/string + enum: [slot0, slot1, slot2, slot3, default] + default: default + + adi,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 'adi,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 "adi,max77675"; + reg =3D <0x44>; + + reset-time-sec =3D <4>; + input-debounce =3D <100>; + + adi,en-mode =3D "slide-switch"; + adi,voltage-change-latency-us =3D <100>; + adi,drv-sbb-strength =3D "max"; + adi,dvs-slew-rate-mv-per-us =3D <5>; + + regulators { + sbb0: sbb0 { + regulator-name =3D "sbb0"; + regulator-min-microvolt =3D <500000>; + regulator-max-microvolt =3D <5500000>; + adi,fps-slot =3D "default"; + adi,fixed-slew-rate; + }; + + sbb1: sbb1 { + regulator-name =3D "sbb1"; + regulator-min-microvolt =3D <500000>; + regulator-max-microvolt =3D <5500000>; + adi,fps-slot =3D "default"; + adi,fixed-slew-rate; + }; + + sbb2: sbb2 { + regulator-name =3D "sbb2"; + regulator-min-microvolt =3D <500000>; + regulator-max-microvolt =3D <5500000>; + adi,fps-slot =3D "default"; + adi,fixed-slew-rate; + }; + + sbb3: sbb3 { + regulator-name =3D "sbb3"; + regulator-min-microvolt =3D <500000>; + regulator-max-microvolt =3D <5500000>; + adi,fps-slot =3D "default"; + adi,fixed-slew-rate; + }; + }; + }; + }; + -- 2.34.1 From nobody Tue Dec 2 02:04:58 2025 Received: from mail-pj1-f53.google.com (mail-pj1-f53.google.com [209.85.216.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 EC507338F39 for ; Thu, 20 Nov 2025 12:55:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763643349; cv=none; b=ulORs8Sdv5d7e8eL3nNqEJWJAwwLZzSKKF0Foch9FCN2U43QOHwf8f8bY020Dci+BZD1nzK0dEI6ZUK6lZpO3bX9FkIT0WiE+S1OS4FGk7aO4MJ6N+aXXDpuB+8Z2rGzTSK5iAU8cnT1RLo5iQ3499mAEAgUH3vFXZT4KXBIyQ0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763643349; c=relaxed/simple; bh=xxnFKI6FqfcNEXfx3SaQkSRvTNXezo+dyZmpL2eZJlU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=B3JMtmD/bg8OfsHvMZ/jG7PFHdk1Qkcp/dkmg0IaqMs5uo/slg8DHWPt3YuCWqbX71xcDZw/SPHiJTlXv5J8vQcy969hXN7uwW4SpbS9+SQLQr7Qf6LiCy2CUm//LBoDLyvUufMMq8jlLCnxsp0m3ATl58l6NJbahOL9IgXI1WY= 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=Jth3aWsZ; arc=none smtp.client-ip=209.85.216.53 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="Jth3aWsZ" Received: by mail-pj1-f53.google.com with SMTP id 98e67ed59e1d1-3436a97f092so948722a91.3 for ; Thu, 20 Nov 2025 04:55:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1763643345; x=1764248145; 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=J+g7ogf4+VYd/wsNiP9R1OvtWBotxUrYkCVKvQ4Lfn0=; b=Jth3aWsZtNqI7pfH99RB1ysWHENpqgePckjx6rXcQ9N07v/+9mQg/a+0OP2eNLyeVr +lkFGQmCFD0/+1wJyCWk7nz+FcqO4kWNrW18EHYUcfltp4OubEoIqgOLU4qo4O4J6M8a d0mGepvEL6gaMVbk5sv1YIAjSfpYYiZ30EELPvZKPWRrIJnz53ax/mr5qEe7mbKDTJhp sRpQKu9T0R3+Vqflo6l0Tuc1QKHQ4yzU14xk2pQN8WbirOKIjjVsLXZxP9A096B+saBb jaya5PvU1xuly7Gj/54qwPDaUIG1+VZnTGeOj4bDtKjYtZ7LrVXJd57m6Xjtwm/4j4jz P6vA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763643345; x=1764248145; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=J+g7ogf4+VYd/wsNiP9R1OvtWBotxUrYkCVKvQ4Lfn0=; b=uPGQXmNp21gbHapHX9OdGA6GOmRiSAUZM6xTz9G96d2KhSHLlrL44UkvoViri9sUFN K+OGc8HJnVHVTbnnhNl9NrCRrWrOzrg5Mahpwtg/ys8Rq9Sp/ZcRgqcqPUxfYQY3hpOW PuP/tEDKPWz92QX2M4ZnMaBLuNNlp/h1uY4I+SB9FKel/sR/lbRT0JIPDru1mBoKN5E5 GbXEKHITPcvLyGYwwcrH4vvgQnJ4a4SFH+uHCRvZjhB88LLSb9I5sg47QNFPZgEf7PNj djhrxnVI+UeCxzQg/3S4e6ckUP+tvlbewqUR/eGUNwxNOWAty/auYWjRL4rgZfliZeMW H70Q== X-Forwarded-Encrypted: i=1; AJvYcCWcgP8ye6wvTGYEE9jmx9ZZyFCjVKDIRZ8ponZoTAMqTChmoCHE9Ba1OD0A+uuQQnpXgptxadPGpP8WRBI=@vger.kernel.org X-Gm-Message-State: AOJu0YzlwTGtPMxY+TkK8Xt/ur5lDfWFDTD9IwYKVhcNDE4KraV6ckhO 2JJBfzxYz+37ZQMt/WZ0mcCfsqBs6HvZr4bC7RtxwFoQsbGYpYE46ZzM X-Gm-Gg: ASbGncsz6qvmdKa763aFner+Sby4vwFxfGLc0+Kd/yRMg51xxs6GnsMhRk1QlkQzhB1 fxhvZfw+lYxHLBJYsa4jLL+czhdJx5yK5N8rGfSrJB+SqffaCX+tYEkeuG205bgH11DBNFjfwsx LFDqWvXfiUc0PNsoFxGffyFZPcbaHgTM3199vB71FFhk5kbKBhf66osgfd0ocC7F2lwNBtMAf5+ 8YpHFwmj3U7C5BRWfYlDC/vranMGJlCe4xNWLvSqHcOjBQKtiby35XtbETpk+P8mZYuap1uGGtE XR9btLtEzWopcKsQGS/pIHdMImv42mc+VHmNvIkEiDvSzJ3TulaPVwoc2OIFUyfHdk5HOwAg7yl MyTrXlurkNxmx23vwXYUl44T8XWQiVOnQUUC1q6SITyADG5KU++xh5u0OGEnG2MrBi0K9UvEs8o WGbBOOIaUnqcW2mVE+hCr2PX2LXCmrqw== X-Google-Smtp-Source: AGHT+IG8y6r0bhZzSXFUynM1PkkosKNq37YwnbKzhTHb0uS8ASuc7kfMiWn5gJFvejmRcURvvQsmyw== X-Received: by 2002:a17:90b:4fc2:b0:341:133:e13d with SMTP id 98e67ed59e1d1-34727bdc0afmr3047555a91.5.1763643345078; Thu, 20 Nov 2025 04:55:45 -0800 (PST) Received: from HYB-iPCgmhaB8Cy.ad.analog.com ([59.9.235.253]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-34726696b52sm2586746a91.1.2025.11.20.04.55.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Nov 2025 04:55:44 -0800 (PST) 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 v6 2/2] regulator: max77675: Add MAX77675 regulator driver Date: Thu, 20 Nov 2025 21:54:49 +0900 Message-Id: <20251120125449.26530-3-joan.na@analog.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251120125449.26530-1-joan.na@analog.com> References: <20251120125449.26530-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 | 1056 ++++++++++++++++++++++++ 3 files changed, 1066 insertions(+) create mode 100644 drivers/regulator/max77675-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index d84f3d054c59..381edaa90098 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 && OF + 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..584554680f9d --- /dev/null +++ b/drivers/regulator/max77675-regulator.c @@ -0,0 +1,1056 @@ +// 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 +#include +#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 (adi= ,dvs-slew-rate) + +/* 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) + +/* 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 + +/* 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, +}; + +struct max77675_regulator_sbb_setting { + 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_ldo_always_on; +}; + +struct max77675_regulator { + struct device *dev; + struct regmap *regmap; + struct max77675_config config; + struct max77675_regulator_sbb_setting sbb_setting[MAX77675_ID_NUM_MAX]; +}; + +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 FIELD_GET(MAX77675_EN_SBB_MASK, val); +} + +static int max77675_regulator_set_fps_src(struct max77675_regulator *maxre= g, int id, u8 fps_src) +{ + unsigned int reg_addr; + + 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; + } + + return regmap_update_bits(maxreg->regmap, reg_addr, MAX77675_EN_SBB_MASK,= fps_src); +} + +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_sbb_setting *sbb_setting =3D &maxreg->sbb_setti= ng[id]; + int ret; + + if (sbb_setting->fps_slot =3D=3D MAX77675_FPS_DEF) { + ret =3D max77675_regulator_get_fps_src(maxreg, id); + if (ret < 0) + return ret; + + sbb_setting->fps_slot =3D ret; + } else { + ret =3D max77675_regulator_set_fps_src(maxreg, id, sbb_setting->fps_slot= ); + if (ret < 0) + return ret; + } + + ret =3D max77675_set_sbb_slew_rate_fixed(maxreg, id, sbb_setting->fixed_s= lew_rate); + if (ret < 0) + return ret; + + 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_sbb_setting *sbb_setting =3D &maxreg->sbb_setti= ng[desc->id]; + static const char * const fps_slots[] =3D { "slot0", "slot1", "slot2", "s= lot3", "default" }; + const char *fps_str; + int slot; + + /* Parse FPS slot from DT */ + if (of_property_read_string(np, "adi,fps-slot", &fps_str)) { + /* Property not set, use default */ + sbb_setting->fps_slot =3D MAX77675_FPS_DEF; + } else { + /* Match string to index */ + slot =3D match_string(fps_slots, ARRAY_SIZE(fps_slots), fps_str); + if (slot < 0) { + dev_dbg(maxreg->dev, "Invalid fps-slot '%s', using default\n", fps_str); + sbb_setting->fps_slot =3D MAX77675_FPS_DEF; + } else { + sbb_setting->fps_slot =3D slot; + } + } + + /* Parse slew rate control source */ + sbb_setting->fixed_slew_rate =3D of_property_read_bool(np, "adi,fixed-sle= w-rate"); + + /* 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 *cfg =3D &maxreg->config; + int ret; + + /* Set EN pin mode */ + ret =3D regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_EN_MODE_MASK, + FIELD_PREP(MAX77675_EN_MODE_MASK, cfg->en_mode)); + if (ret) { + dev_err(maxreg->dev, "Failed to set EN mode: %d\n", ret); + return ret; + } + + /* Set the latency between output voltage change and SBBx voltage ramp st= art */ + ret =3D regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_B, + MAX77675_LAT_MODE_BIT, + FIELD_PREP(MAX77675_LAT_MODE_BIT, cfg->voltage_change_latency)); + if (ret) { + dev_err(maxreg->dev, "Failed to set latency mode: %d\n", ret); + return ret; + } + + /* Set drive strength */ + ret =3D regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_A, + MAX77675_DRV_SBB_MASK, + FIELD_PREP(MAX77675_DRV_SBB_MASK, cfg->drv_sbb_strength)); + if (ret) { + dev_err(maxreg->dev, "Failed to set drive strength: %d\n", ret); + return ret; + } + + /* Set DVS slew rate */ + ret =3D regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_B, + MAX77675_DVS_SLEW_BIT, + FIELD_PREP(MAX77675_DVS_SLEW_BIT, cfg->dvs_slew_rate)); + if (ret) { + dev_err(maxreg->dev, "Failed to set DVS slew rate: %d\n", ret); + return ret; + } + + /* Set debounce time for EN pin */ + ret =3D regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_DBEN_EN_BIT, + FIELD_PREP(MAX77675_DBEN_EN_BIT, cfg->debounce_time)); + if (ret) { + dev_err(maxreg->dev, "Failed to set EN debounce time: %d\n", ret); + return ret; + } + + /* Set manual reset time (MRT) for EN pin */ + ret =3D regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_MRT_MASK, + FIELD_PREP(MAX77675_MRT_MASK, cfg->manual_reset_time)); + if (ret) { + dev_err(maxreg->dev, "Failed to set manual reset time: %d\n", ret); + return ret; + } + + /* Enable or disable internal pull-up resistor on EN pin */ + ret =3D regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_PU_DIS_BIT, + FIELD_PREP(MAX77675_PU_DIS_BIT, cfg->en_pullup_disable)); + if (ret) { + dev_err(maxreg->dev, "Failed to set EN pull-up disable: %d\n", ret); + return ret; + } + + /* Request main bias to enter low-power mode */ + ret =3D regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_BIAS_LPM_BIT, + FIELD_PREP(MAX77675_BIAS_LPM_BIT, cfg->bias_low_power_request)); + if (ret) { + dev_err(maxreg->dev, "Failed to set bias low-power request: %d\n", ret); + return ret; + } + + /* Force SIMO internal LDO to always supply 1.8V */ + ret =3D regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A, + MAX77675_SIMO_CH_DIS_BIT, + FIELD_PREP(MAX77675_SIMO_CH_DIS_BIT, cfg->simo_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 int max77675_parse_en_mode(struct device *dev, + struct device_node *np, + u8 *en_mode) +{ + static const char * const en_modes[] =3D {"push-button", "slide-switch", = "logic"}; + const char *str; + int index; + + *en_mode =3D MAX77675_EN_SLIDE_SWITCH; + + if (of_property_read_string(np, "adi,en-mode", &str)) + return 0; + + index =3D match_string(en_modes, ARRAY_SIZE(en_modes), str); + if (index < 0) { + dev_err(dev, "Invalid 'adi,en-mode' value '%s'\n", str); + return -EINVAL; + } + + *en_mode =3D index; + + return 0; +} + +static int max77675_parse_voltage_change_latency(struct device *dev, + struct device_node *np, + u8 *latency_mode) +{ + u32 val; + + *latency_mode =3D MAX77675_HIGH_LATENCY_MODE; + + if (!of_property_read_u32(np, "adi,voltage-change-latency-us", &val)) { + switch (val) { + case 10: + *latency_mode =3D MAX77675_LOW_LATENCY_MODE; + break; + case 100: + *latency_mode =3D MAX77675_HIGH_LATENCY_MODE; + break; + default: + dev_err(dev, "Invalid voltage-change-latency-us value: %u\n", val); + return -EINVAL; + } + } + + return 0; +} + +static int max77675_parse_manual_reset_time(struct device *dev, + struct device_node *np, + u8 *reset_time) +{ + u32 val; + + *reset_time =3D MAX77675_MRT_4S; + + if (!of_property_read_u32(np, "reset-time-sec", &val)) { + switch (val) { + case 4: + *reset_time =3D MAX77675_MRT_4S; + break; + case 8: + *reset_time =3D MAX77675_MRT_8S; + break; + case 12: + *reset_time =3D MAX77675_MRT_12S; + break; + case 16: + *reset_time =3D MAX77675_MRT_16S; + break; + default: + dev_err(dev, "Invalid reset-time-sec value: %u\n", val); + return -EINVAL; + } + } + + return 0; +} + +static int max77675_parse_dvs_slew_rate(struct device *dev, struct device_= node *np, u8 *slew_rate) +{ + u32 val; + + /* Set default: 5 mV/us */ + *slew_rate =3D MAX77675_DVS_SLEW_5MV_PER_US; + + if (!of_property_read_u32(np, "adi,dvs-slew-rate-mv-per-us", &val)) { + switch (val) { + case 5: + *slew_rate =3D MAX77675_DVS_SLEW_5MV_PER_US; + break; + case 10: + *slew_rate =3D MAX77675_DVS_SLEW_10MV_PER_US; + break; + default: + dev_err(dev, "Invalid dvs-slew-rate-mv-per-us value: %u\n", val); + return -EINVAL; + } + } + + return 0; +} + +static int max77675_parse_drv_sbb_strength(struct device *dev, struct devi= ce_node *np, u8 *strength) +{ + static const char * const strength_names[] =3D {"max", "high", "low", "mi= n"}; + const char *str; + int index; + + /* Set default: maximum drive strength */ + *strength =3D MAX77675_DRV_SBB_STRENGTH_MAX; + + if (of_property_read_string(np, "adi,drv-sbb-strength", &str)) + return 0; + + index =3D match_string(strength_names, ARRAY_SIZE(strength_names), str); + if (index < 0) { + dev_err(dev, "Invalid 'adi,drv-sbb-strength' value: '%s'\n", str); + return -EINVAL; + } + + *strength =3D index; + + return 0; +} + +static int max77675_parse_debounce_time_us(struct device *dev, + struct device_node *np, + u8 *debounce_time) +{ + u32 val; + + *debounce_time =3D MAX77675_DBEN_100US; + + if (!of_property_read_u32(np, "input-debounce", &val)) { + switch (val) { + case 100: + *debounce_time =3D MAX77675_DBEN_100US; + break; + case 30000: + *debounce_time =3D MAX77675_DBEN_30000US; + break; + default: + dev_err(dev, "Invalid input-debounce value: %u\n", val); + return -EINVAL; + } + } + + return 0; +} + +static int max77675_parse_config(struct max77675_regulator *maxreg) +{ + struct device_node *np =3D maxreg->dev->of_node; + struct max77675_config *cfg =3D &maxreg->config; + int ret; + + /* EN pin mode */ + ret =3D max77675_parse_en_mode(maxreg->dev, np, &cfg->en_mode); + if (ret < 0) + return ret; + + /* voltage change latency */ + ret =3D max77675_parse_voltage_change_latency(maxreg->dev, np, &cfg->volt= age_change_latency); + if (ret < 0) + return ret; + + /* drive strength */ + ret =3D max77675_parse_drv_sbb_strength(maxreg->dev, np, &cfg->drv_sbb_st= rength); + if (ret < 0) + return ret; + + /* dvs slew rate */ + ret =3D max77675_parse_dvs_slew_rate(maxreg->dev, np, &cfg->dvs_slew_rate= ); + if (ret < 0) + return ret; + + /* Debounce time for EN pin */ + ret =3D max77675_parse_debounce_time_us(maxreg->dev, np, &cfg->debounce_t= ime); + if (ret < 0) + return ret; + + /* Manual reset time for EN pin */ + ret =3D max77675_parse_manual_reset_time(maxreg->dev, np, &cfg->manual_re= set_time); + if (ret < 0) + return ret; + + /* Disable internal pull-up resistor on EN pin */ + cfg->en_pullup_disable =3D of_property_read_bool(np, "bias-disable"); + + /* Request low-power mode for main bias */ + cfg->bias_low_power_request =3D of_property_read_bool(np, "adi,bias-low-p= ower-request"); + + /* Force internal LDO to always supply 1.8V */ + cfg->simo_ldo_always_on =3D of_property_read_bool(np, "adi,simo-ldo-alway= s-on"); + + 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_dbg(maxreg->dev, "Software Cold Reset Flag is set\n"); + + if (ercflag & MAX77675_SFT_OFF_F_BIT) + dev_dbg(maxreg->dev, "Software Off Flag is set\n"); + + if (ercflag & MAX77675_MRST_BIT) + dev_dbg(maxreg->dev, "Manual Reset Timer Flag is set\n"); + + if (ercflag & MAX77675_UVLO_BIT) + dev_dbg(maxreg->dev, "Undervoltage Lockout Flag is set\n"); + + if (ercflag & MAX77675_OVLO_BIT) + dev_dbg(maxreg->dev, "Overvoltage Lockout Flag is set\n"); + + if (ercflag & MAX77675_TOVLD_BIT) + dev_dbg(maxreg->dev, "Thermal Overload Flag is set\n"); + + if (int_glbl & MAX77675_INT_SBB3_F_BIT) + dev_dbg(maxreg->dev, "SBB3 Channel Fault Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_SBB2_F_BIT) + dev_dbg(maxreg->dev, "SBB2 Channel Fault Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_SBB1_F_BIT) + dev_dbg(maxreg->dev, "SBB1 Channel Fault Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_SBB0_F_BIT) + dev_dbg(maxreg->dev, "SBB0 Channel Fault Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_TJAL2_R_BIT) + dev_dbg(maxreg->dev, "Thermal Alarm 2 Rising Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_TJAL1_R_BIT) + dev_dbg(maxreg->dev, "Thermal Alarm 1 Rising Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_EN_R_BIT) + dev_dbg(maxreg->dev, "nEN Rising Edge Interrupt occurred\n"); + + if (int_glbl & MAX77675_INT_EN_F_BIT) + dev_dbg(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 __free(device_node) =3D NULL; + 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 < 0) + return dev_err_probe(maxreg->dev, ret, "Failed to init event\n"); + + ret =3D max77675_parse_config(maxreg); + if (ret < 0) + return dev_err_probe(maxreg->dev, ret, "Failed to parse config\n"); + + ret =3D max77675_apply_config(maxreg); + if (ret < 0) + 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; + + struct device_node *child_np __free(device_node) =3D + of_get_child_by_name(regulators_np, desc->name); + if (!child_np) { + dev_warn(maxreg->dev, "No DT node for regulator %s\n", desc->name); + continue; + } + + config.of_node =3D child_np; + + rdev =3D devm_regulator_register(&client->dev, desc, &config); + if (IS_ERR(rdev)) { + return dev_err_probe(maxreg->dev, PTR_ERR(rdev), + "Failed to register regulator %d (%s)\n", + i, desc->name); + } + } + + 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 "adi,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"); -- 2.34.1