From patchwork Tue Jun 4 07:53:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684864 Received: from mail-lf1-f41.google.com (mail-lf1-f41.google.com [209.85.167.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0B6761420BB; Tue, 4 Jun 2024 07:53:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487636; cv=none; b=IMLa87QJq3aKrpmOSJ6KWATxNmdZWBrJlQgWQ8dZEAJaagXws4k2LymxXCemjxzDJ+IbJEb0Kg885xqivlCNzxuIW07qSC6edrwDWzjT1XJ14gbFCafaRefEXwbb0ZSHQ4FjcyF7IpXVV2Y4JLtfSc1IHVW0RJAVeDJaAzjWH7o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487636; c=relaxed/simple; bh=Qt1UxDzx67PlscS9zxplX6GrtN/rzHghHyXi74rsPgA=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=FCJMzhe30Cc+/LzWV+SrAZ5uOfgiHKw2PyK0UCjhkCpVSI7OXHH+jQEyI+VBYUI/tnQfHZWLcqtbhv3PPuEQc6GwS+6pNXwJEkuzVdEiYfyKnnRvcV81MgGpd3r6tx3cahow9GqEy0J7wSElouTT19UR2N621HkFwHHdWroy6lQ= 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=Lvs9qAIi; arc=none smtp.client-ip=209.85.167.41 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="Lvs9qAIi" Received: by mail-lf1-f41.google.com with SMTP id 2adb3069b0e04-5295e488248so5463194e87.2; Tue, 04 Jun 2024 00:53:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487633; x=1718092433; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=nBfFcC2E1asbHPvw4EnTDAgesuuGLIZ6WxcAdenhakA=; b=Lvs9qAIi7Bl7RliN0y6fvsX0crQ57VJD0WFCCjUVrmq/u7nRWK+3st/KfIkUtzj+cx 8a/YQ5z61VpL+FQveb+ycWKxxUR4WscPPGW/G5ENRW7vMEwABheSFf3ljdXdwFMLEEc0 Iji13wvTd/2grpL/FPLsICELVm3fcVwDpcXVlzFR1Qwe1peDYNRTjw/KRe+VKGG+WIEF XAzPzxJo+rauJvMBffSKRQybSi9XIOKR6n+xbMXIDhBEuZ6U2j/av87QmOsESqsPOPjZ 6KwwIDMXfRfDMeDb0GUb8/xeW1PgYgig0SAjhtQsdOL0GBV1DeEh95TQ4jMZSGOjs3oK ZN6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487633; x=1718092433; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=nBfFcC2E1asbHPvw4EnTDAgesuuGLIZ6WxcAdenhakA=; b=QiWF8fydW/q1QBssaNJo7dC0kzmCh5jAFjenelleidhM4pYaDV8eOOFghfYCk97LJ7 xJBKcmdSYccVjrjArJlXGF+UjmQYrjNELmG/j+ksNbU5nmwJZFhaGD5RVvPOfbKW9z6l U7aKPzJy71RtKoMpvcLrtIH2BNbj0pfqG3KB3deRm++T3g5VaiN6M9KQ+foufdvlxkZq 3LAMzgO3oFcSXcEUsvf/eEjh3lueOBUJ5r7MJvMU++i8gmtM9c1rDXw/Ur63qVcfRMjC /HjPWpYz9V8PxId9fXe0tD8uBTWBeWLVZk6wQgXMaxRkiZuVKKBR7btn8ERkwuT/KYvL I3ng== X-Forwarded-Encrypted: i=1; AJvYcCV5oRai+7kCxgfca1XoX53KjgQ8X7Xh2pg3bAB3JwW6OrOOzqtfGOR21eBgz5DqE1NtNBTLPQKXXruZBaoHYsFaLLTk4L84LwpbHdlRGj4cyK67AZ0EkZa/nXu4emcJJlyJA9OptM8b0InAMfqSgyRTvdJha8ZwVqo/vtR0JP5h4WdsPUkoBfE2 X-Gm-Message-State: AOJu0YwjLwAxN/oE0e/PF+6dGYuHRAvqlvZ6hnDer+JTXC2G5Je1ehJ8 eggx66UAPh+H2tTYU8QTE8ryXZ8hgYDMDJzQJv51ZBeWrhWfnKHH X-Google-Smtp-Source: AGHT+IEYmFpoM6HPa7bleaTijAw+N+sB7DvoZFvscGVt1ROfzws5p9DcQ013WdXPXbDZ/dejw3Wz2A== X-Received: by 2002:ac2:464c:0:b0:528:4841:e4a1 with SMTP id 2adb3069b0e04-52b896aba8fmr6890813e87.40.1717487632712; Tue, 04 Jun 2024 00:53:52 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52b97ff7bfasm667048e87.95.2024.06.04.00.53.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:53:51 -0700 (PDT) Date: Tue, 4 Jun 2024 10:53:47 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 01/10] dt-bindings: ROHM BD96801 PMIC regulators Message-ID: <7bdc1e2c5569dbe2babbce187b0093852fe392e0.1717486682.git.mazziesaccount@gmail.com> References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: ROHM BD96801 is a highly configurable automotive grade PMIC. Introduce DT bindings for the BD96801 regulators. Signed-off-by: Matti Vaittinen Reviewed-by: Krzysztof Kozlowski --- Revision history: v2 => - No changes v1 => v2: - use lowercase node names in example - drop unneeded '|' from description RFCv2 => v1 - Drop regulator-name pattern requirement - do not require regulator-name --- .../regulator/rohm,bd96801-regulator.yaml | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd96801-regulator.yaml diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd96801-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd96801-regulator.yaml new file mode 100644 index 000000000000..b3d2d7d583ce --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/rohm,bd96801-regulator.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/rohm,bd96801-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD96801 Power Management Integrated Circuit regulators + +maintainers: + - Matti Vaittinen + +description: + This module is part of the ROHM BD96801 MFD device. For more details + see Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml. + + The regulator controller is represented as a sub-node of the PMIC node + on the device tree. + + Regulator nodes should be named to buck_ and ldo_. + The valid names for BD96801 regulator nodes are + buck1, buck2, buck3, buck4, ldo5, ldo6, ldo7 + +patternProperties: + "^ldo[5-7]$": + type: object + description: + Properties for single LDO regulator. + $ref: regulator.yaml# + + properties: + rohm,initial-voltage-microvolt: + description: + Initial voltage for regulator. Voltage can be tuned +/-150 mV from + this value. NOTE, This can be modified via I2C only when PMIC is in + STBY state. + minimum: 300000 + maximum: 3300000 + + unevaluatedProperties: false + + "^buck[1-4]$": + type: object + description: + Properties for single BUCK regulator. + $ref: regulator.yaml# + + properties: + rohm,initial-voltage-microvolt: + description: + Initial voltage for regulator. Voltage can be tuned +/-150 mV from + this value. NOTE, This can be modified via I2C only when PMIC is in + STBY state. + minimum: 500000 + maximum: 3300000 + + rohm,keep-on-stby: + description: + Keep the regulator powered when PMIC transitions to STBY state. + type: boolean + + unevaluatedProperties: false + +additionalProperties: false From patchwork Tue Jun 4 07:54:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684865 Received: from mail-lf1-f49.google.com (mail-lf1-f49.google.com [209.85.167.49]) (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 CA1361411FD; Tue, 4 Jun 2024 07:54:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487653; cv=none; b=M/ektmnmp8rMaFlEZoSl5Io9ZVh+EfNWdOQVZGT2oKR22WueGBwzrjrA58/uCZc8+q4kNXoy3XTiRmSDQUEebud3TV3349WOXGPCY6KEQ00Yp1x0yWgxmsYZEciVeLV9uoQT4+ft9bxLlE6ztVwxIL3slOGbt6mdZNW2XkwJX10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487653; c=relaxed/simple; bh=+07XjaCmvSa2PN1d6lMA+SwXTKZqzU2wx3qN8oHNSUM=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=ImmqQIq8AkUegyGT0Sk93+vg0/WPvHGkcEdfjNfgN/WFrvMlxxvIb7k495xNZhveo14lAjZIsv93aWl9h81kCMQd0w43z5XPGRNZi3c7PbxOheD+hEFJUvT6Wc1MIr1D6Aj34j9HttrPLBjPKcaTAs80T+OmEvlXZSJtnDvmAtQ= 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=MP+Clkmi; arc=none smtp.client-ip=209.85.167.49 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="MP+Clkmi" Received: by mail-lf1-f49.google.com with SMTP id 2adb3069b0e04-52b992fd796so777824e87.0; Tue, 04 Jun 2024 00:54:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487650; x=1718092450; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=BoSVUPBHVu1Boko+k4yuvY/1xggpNKidapHYx+cVQow=; b=MP+ClkmiJ7/SCMB3tuggw9iyM2JLiq2qdeCDiee4/oLT4iJ5eOZIs8VGjMBHLILWIg 5p1WQyw0CN7L+8ECdN/kC9z88+HPAyyZTR6G3uOw7olg3+pothbArAdd2EElvuEkM95E WAS//ZZ+qk/geE0isbIQ4rUVsvYeHN6GGjrZ5xPD5xfEdbjkFUtYIV7RibnKqDBbekrN 4lIaXz8SDFVA/wsVlqDuq0lssLZCBgBFGlGrCtcYiFyvMDxWexzcL/AhhE/O5O6t/nfp 7WAQztHI2zRU8+u5I1MJyopHRa0SrjNsBKRRjRHzAuTwBQY7Uh2mvDR70CTOkdWZ92Ro PHWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487650; x=1718092450; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=BoSVUPBHVu1Boko+k4yuvY/1xggpNKidapHYx+cVQow=; b=sA4rAUzX2Npvi1QzTTzr8lgGRGDUbdIOhoV9WbJ/E1cJ1tx+MwFkzAuJNcYkWW3f4n m6LgXOv3NxzfkLK6nR6S9LPLpZlbz+Kgv87hrVOZRvOgyMwUiPhYLtj+ZVguXK5TMHpH 9ga+iIm+j1RyArLQdjXCaA9raHGYJM1aYYNiax8cfJu4GZ3lqQ555Vj5vuX6fqyYzaVH Ebjt8rLTiby9Mpo+0r13yws2T6ufQKxT8oQc7zE48g7GiOBB0MhqzOS7y4JckhCs3boF PGZCUe0sp781+tVb43u+HpymV1j1Cj+wJSfv99fZuYqi8qtSWNtL5W/W3e5XoksmQrWZ b4pg== X-Forwarded-Encrypted: i=1; AJvYcCW46TxxrOrkyNP9HkwS2/ej5n4NxJKTYosldiyG+d+RxqFz4+6p3iWxzULnG8THj4bbw6w5tqvHtdwZdSexIMaSFzHoyw8FSGO4spfgjMY5O4ZEXPPOzI/Cg2neN3k2bTlvh82ndQaGoks+VZ+yeiNeN1Gp1NpQgXP9TVOQbpZ4FdWCzE/htfXN X-Gm-Message-State: AOJu0Yz/6KYicgaSMLkBfZLVwQJcWhXw1oU4iXNHLjThO03UvCc9TVC4 GYjlmsijzX5idfbBX+heuD+30Vf6iJ7MOFML08LFyXJLhn1nFB5B X-Google-Smtp-Source: AGHT+IHzq/IV6y+wMC6pEzqLt2bPySVEN6Iakhv0//gENZjemwN+WDCSwgUzCoMmEtlycllLGYPy6A== X-Received: by 2002:a05:6512:118e:b0:52b:a5bb:12e6 with SMTP id 2adb3069b0e04-52ba5bb136bmr635980e87.35.1717487649543; Tue, 04 Jun 2024 00:54:09 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52b84d7ecbdsm1432069e87.182.2024.06.04.00.54.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:54:08 -0700 (PDT) Date: Tue, 4 Jun 2024 10:54:04 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 02/10] dt-bindings: mfd: bd96801 PMIC core Message-ID: <674f3c69eefb2d31ceb064f898cb0237a5301044.1717486682.git.mazziesaccount@gmail.com> References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: ROHM BD96801 is a highly configurable automotive grade PMIC. Introduce DT bindings for the BD96801 core. Signed-off-by: Matti Vaittinen Reviewed-by: Krzysztof Kozlowski --- Revision history: v2 =>: - No changes v1 => v2: - use lowercase node names in example - minor addition to ERRB use-cases RFCv2 => v1 - minor cleaning - add timeout-sec RFCv1 => RFCv2: - Document rohm,hw-timeout-ms - Document rohm,wdg-action --- .../bindings/mfd/rohm,bd96801-pmic.yaml | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml new file mode 100644 index 000000000000..d381125a0a15 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml @@ -0,0 +1,173 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/rohm,bd96801-pmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD96801 Scalable Power Management Integrated Circuit + +maintainers: + - Matti Vaittinen + +description: + BD96801 is an automotive grade single-chip power management IC. + It integrates 4 buck converters and 3 LDOs with safety features like + over-/under voltage and over current detection and a watchdog. + +properties: + compatible: + const: rohm,bd96801 + + reg: + maxItems: 1 + + interrupts: + description: + The PMIC provides intb and errb IRQ lines. The errb IRQ line is used + for fatal IRQs which will cause the PMIC to shut down power outputs. + In many systems this will shut down the SoC contolling the PMIC and + connecting/handling the errb can be omitted. However, there are cases + where the SoC is not powered by the PMIC or has a short time backup + energy to handle shutdown of critical hardware. In that case it may be + useful to connect the errb and handle errb events. + minItems: 1 + maxItems: 2 + + interrupt-names: + minItems: 1 + items: + - enum: [intb, errb] + - const: errb + + rohm,hw-timeout-ms: + description: + Watchdog timeout value(s). First walue is timeout limit. Second value is + optional value for 'too early' watchdog ping if window timeout mode is + to be used. + minItems: 1 + maxItems: 2 + + rohm,wdg-action: + description: + Whether the watchdog failure must turn off the regulator power outputs or + just toggle the INTB line. + enum: + - prstb + - intb-only + + timeout-sec: + maxItems: 2 + + regulators: + $ref: /schemas/regulator/rohm,bd96801-regulator.yaml + description: + List of child nodes that specify the regulators. + +required: + - compatible + - reg + - interrupts + - interrupt-names + - regulators + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + pmic: pmic@60 { + reg = <0x60>; + compatible = "rohm,bd96801"; + interrupt-parent = <&gpio1>; + interrupts = <29 IRQ_TYPE_LEVEL_LOW>, <6 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "intb", "errb"; + + regulators { + buck1 { + regulator-name = "buck1"; + regulator-ramp-delay = <1250>; + /* 0.5V min INITIAL - 150 mV tune */ + regulator-min-microvolt = <350000>; + /* 3.3V + 150mV tune */ + regulator-max-microvolt = <3450000>; + + /* These can be set only when PMIC is in STBY */ + rohm,initial-voltage-microvolt = <500000>; + regulator-ov-error-microvolt = <230000>; + regulator-uv-error-microvolt = <230000>; + regulator-temp-protection-kelvin = <1>; + regulator-temp-warn-kelvin = <0>; + }; + buck2 { + regulator-name = "buck2"; + regulator-min-microvolt = <350000>; + regulator-max-microvolt = <3450000>; + + rohm,initial-voltage-microvolt = <3000000>; + regulator-ov-error-microvolt = <18000>; + regulator-uv-error-microvolt = <18000>; + regulator-temp-protection-kelvin = <1>; + regulator-temp-warn-kelvin = <1>; + }; + buck3 { + regulator-name = "buck3"; + regulator-min-microvolt = <350000>; + regulator-max-microvolt = <3450000>; + + rohm,initial-voltage-microvolt = <600000>; + regulator-ov-warn-microvolt = <18000>; + regulator-uv-warn-microvolt = <18000>; + regulator-temp-protection-kelvin = <1>; + regulator-temp-error-kelvin = <0>; + }; + buck4 { + regulator-name = "buck4"; + regulator-min-microvolt = <350000>; + regulator-max-microvolt = <3450000>; + + rohm,initial-voltage-microvolt = <600000>; + regulator-ov-warn-microvolt = <18000>; + regulator-uv-warn-microvolt = <18000>; + regulator-temp-protection-kelvin = <1>; + regulator-temp-error-kelvin = <0>; + }; + ldo5 { + regulator-name = "ldo5"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <3300000>; + + rohm,initial-voltage-microvolt = <500000>; + regulator-ov-error-microvolt = <36000>; + regulator-uv-error-microvolt = <34000>; + regulator-temp-protection-kelvin = <1>; + regulator-temp-warn-kelvin = <0>; + }; + ldo6 { + regulator-name = "ldo6"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <3300000>; + + rohm,initial-voltage-microvolt = <300000>; + regulator-ov-error-microvolt = <36000>; + regulator-uv-error-microvolt = <34000>; + regulator-temp-protection-kelvin = <1>; + regulator-temp-warn-kelvin = <0>; + }; + ldo7 { + regulator-name = "ldo7"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <3300000>; + + rohm,initial-voltage-microvolt = <500000>; + regulator-ov-error-microvolt = <36000>; + regulator-uv-error-microvolt = <34000>; + regulator-temp-protection-kelvin = <1>; + regulator-temp-warn-kelvin = <0>; + }; + }; + }; + }; From patchwork Tue Jun 4 07:54:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684866 Received: from mail-lf1-f47.google.com (mail-lf1-f47.google.com [209.85.167.47]) (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 AEA611411FD; Tue, 4 Jun 2024 07:54:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487671; cv=none; b=iaFwIEORO6N6h8OdZDrdoy/pSvTJiNHQtKgvlZw/poofZmlT8z+lDFKN5T6UWfzEjzO8kzkmJ2s/f8fZFQc/F5yWNzX/Yc+3ysR0kClU5Q9/YlTf2MVQ6dwIb4T88P5kZ+5vcAS7mj3RWIH20hJ8mRSUjjGTaZqSMlVHTw8V2oA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487671; c=relaxed/simple; bh=HbqTtoVLC+A0boXGEaAbAoejeuT+J7kYV/q8BnUXUQI=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=gpYYEvImLUbgh9XCTWnoy/QtDz1efVG21Wbq5BUdgoBNgzHCMiY6/999XApcFbr/KKZ3rsDwJ19lBcrzppPbVTPV7uydpLTY/0KcmQhEoEwzSbdrl4z9V6tIBMc74H/ctzZBpT3NY2SwCBjnXMdDz5z/6E4gC8i3SlbPO2Uop98= 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=QCHlwLa0; arc=none smtp.client-ip=209.85.167.47 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="QCHlwLa0" Received: by mail-lf1-f47.google.com with SMTP id 2adb3069b0e04-52b88335dd7so5004073e87.1; Tue, 04 Jun 2024 00:54:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487666; x=1718092466; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=JyUEGfwNIlgcpiL6KOfpy0N+0ntPCCub6Y5dPFU3FaY=; b=QCHlwLa0NghCUb86ge+e5EDlQUQEvZAxxRhaRClmKP/GD5X6qz7oCXYdwKJvhO4MPe jEVVl8rmBhHCY1K6yw9mZhMN3zInpcoQ+cx7vTA11PI2mUy+mp9jVKEtAJ8Ijl8nEhOQ Y8WHZqhTe8DxwBxUHZCWYJZ4ZOGrhOl8NjhHhxzEnEoVwHr/1VMxKU8KHrLEOBgzzx2n UCmuEJHkqN35h+yvbIZVufW2hz96mvtAj5d/NyXWUzORP8qvssbnN0pWfvm0I5hoXk1l GwGwa4IJs6DEKiH0xa637QvkyPK9Bfl4MK4B94B5SbSd0hk20uagmZuxK0MvdkrzqoAi pWtA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487666; x=1718092466; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=JyUEGfwNIlgcpiL6KOfpy0N+0ntPCCub6Y5dPFU3FaY=; b=unzCqgq8hgAm1GYouoiKhRk1Np2NofQqi0DE0/4+8J948npu3IkVAWNaIlZghoQvc3 tPnqtQGoV6JM/B2/6/go535LiBzi6E8cXDIhzpzBD818xWDOsnsESMckhwpXMsiebCWZ 1YcJwZukFIIkW77XXlvnsMm3dBpvPtcMm4edaOIp0BxRTB7iAOASP8n0nyVvcD7KRx/h yOac0L3GRCZUaM/Z7h77V96TzMNh7LTyFtLiDJjBVovOaRsokWOtQMi3ilCnouXzspB8 UGm5CKkQJP0Lm1J7bCmUXpoS8r1I4qCh7zzvXPbOcFQcwxvQDC/uGwQ6hMWMJZA8m2e5 JNHg== X-Forwarded-Encrypted: i=1; AJvYcCVrXn4Z/CHQxyjXFissYXbOYdsuJoXX2I3jn/X7WlMOQ6TLv1QvmmjPxZXqwBE5KbrSKEfYWM5jDIDixkz4Kbp/7y9QrKYRsG3Mpoaht3HkKYBlXpka70WI/XuSJ5ZVBxC2c/tDVKYr8SYEuFXLg4XFwwYrB6oPk4Ri9e0jYH2dQgi7Q7T6jD4Y X-Gm-Message-State: AOJu0Yx8HcqU8WcKs6pSzkBdy85bPuJii9VjSG5BdML7P3iBPyd/ahpR yeuxkOmfURIWM5EBSfuQ3Pt27eVEh3pfvaTRiU3IwEYFwa8ONH0/ X-Google-Smtp-Source: AGHT+IFpUMZlU6Ii2ldx0A0UBfq9XW0giFfAasE+mEDNxBnFjrtYTyrU3KltDVMK5YrdafJPl20aag== X-Received: by 2002:a05:6512:2144:b0:52b:79d6:5c28 with SMTP id 2adb3069b0e04-52b896bfc36mr6901384e87.52.1717487665416; Tue, 04 Jun 2024 00:54:25 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52b84d3ebc4sm1455977e87.66.2024.06.04.00.54.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:54:24 -0700 (PDT) Date: Tue, 4 Jun 2024 10:54:20 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 03/10] mfd: support ROHM BD96801 PMIC core Message-ID: <97cd372d4502597bf051f0ff52f718eab9b186aa.1717486682.git.mazziesaccount@gmail.com> References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The ROHM BD96801 PMIC is highly customizable automotive grade PMIC which integrates regulator and watchdog funtionalities. Provide INTB IRQ and register accesses for regulator/watchdog drivers. Signed-off-by: Matti Vaittinen --- Changelog: v2 =>: - No changes v1 => v2: - Drop unused enum - Improve error prints - improve comments RFCv2 => v1: - drop ERRB interrupts (for now) - bd96801: Unlock registers in core driver Changelog: RFCv1 => RFCv2 - Work-around the IRQ domain name conflict - Add watchdog IRQ - Various styling fixes based on review by Lee --- drivers/mfd/Kconfig | 13 ++ drivers/mfd/Makefile | 1 + drivers/mfd/rohm-bd96801.c | 273 +++++++++++++++++++++++++++++++ include/linux/mfd/rohm-bd96801.h | 215 ++++++++++++++++++++++++ include/linux/mfd/rohm-generic.h | 1 + 5 files changed, 503 insertions(+) create mode 100644 drivers/mfd/rohm-bd96801.c create mode 100644 include/linux/mfd/rohm-bd96801.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 266b4f54af60..68cc7af9ef97 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2089,6 +2089,19 @@ config MFD_ROHM_BD957XMUF BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily designed to be used to power R-Car series processors. +config MFD_ROHM_BD96801 + tristate "ROHM BD96801 Power Management IC" + depends on I2C=y + depends on OF + select REGMAP_I2C + select REGMAP_IRQ + select MFD_CORE + help + Select this option to get support for the ROHM BD96801 Power + Management IC. The ROHM BD96801 is a highly scalable Power Management + IC for industrial and automotive use. The BD96801 can be used as a + master PMIC in a chained PMIC solution with suitable companion PMICs. + config MFD_STM32_LPTIMER tristate "Support for STM32 Low-Power Timer" depends on (ARCH_STM32 && OF) || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index c66f07edcd0e..e792892d4a8b 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -264,6 +264,7 @@ obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o +obj-$(CONFIG_MFD_ROHM_BD96801) += rohm-bd96801.o obj-$(CONFIG_MFD_STMFX) += stmfx.o obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c new file mode 100644 index 000000000000..1c2a9591be7b --- /dev/null +++ b/drivers/mfd/rohm-bd96801.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 ROHM Semiconductors + * + * ROHM BD96801 PMIC driver + * + * This version of the "BD86801 scalable PMIC"'s driver supports only very + * basic set of the PMIC features. Most notably, there is no support for + * the ERRB interrupt and the configurations which should be done when the + * PMIC is in STBY mode. + * + * Supporting the ERRB interrupt would require dropping the regmap-IRQ + * usage or working around (or accepting a presense of) a naming conflict + * in debugFS IRQs. + * + * Being able to reliably do the configurations like changing the + * regulator safety limits (like limits for the over/under -voltages, over + * current, thermal protection) would require the configuring driver to be + * synchronized with entity causing the PMIC state transitions. Eg, one + * should be able to ensure the PMIC is in STBY state when the + * configurations are applied to the hardware. How and when the PMIC state + * transitions are to be done is likely to be very system specific, as will + * be the need to configure these safety limits. Hence it's not simple to + * come up with a generic solution. + * + * Users who require the ERRB handling and STBY state configurations can + * have a look at the original RFC: + * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ + * which implements a workaround to debugFS naming conflict and some of + * the safety limit configurations - but leaves the state change handling + * and synchronization to be implemented. + * + * It would be great to hear (and receive a patch!) if you implement the + * STBY configuration support or a proper fix to the debugFS naming + * conflict in your downstream driver ;) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +static const struct resource regulator_intb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "bd96801-buck1-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPL_STAT, "bd96801-buck1-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPN_STAT, "bd96801-buck1-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVD_STAT, "bd96801-buck1-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVD_STAT, "bd96801-buck1-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_TW_CH_STAT, "bd96801-buck1-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPH_STAT, "bd96801-buck2-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPL_STAT, "bd96801-buck2-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPN_STAT, "bd96801-buck2-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVD_STAT, "bd96801-buck2-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVD_STAT, "bd96801-buck2-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_TW_CH_STAT, "bd96801-buck2-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPH_STAT, "bd96801-buck3-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPL_STAT, "bd96801-buck3-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPN_STAT, "bd96801-buck3-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVD_STAT, "bd96801-buck3-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVD_STAT, "bd96801-buck3-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_TW_CH_STAT, "bd96801-buck3-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPH_STAT, "bd96801-buck4-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPL_STAT, "bd96801-buck4-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPN_STAT, "bd96801-buck4-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVD_STAT, "bd96801-buck4-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVD_STAT, "bd96801-buck4-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_TW_CH_STAT, "bd96801-buck4-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OCPH_STAT, "bd96801-ldo5-overcurr"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVD_STAT, "bd96801-ldo5-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVD_STAT, "bd96801-ldo5-undervolt"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OCPH_STAT, "bd96801-ldo6-overcurr"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVD_STAT, "bd96801-ldo6-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVD_STAT, "bd96801-ldo6-undervolt"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OCPH_STAT, "bd96801-ldo7-overcurr"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVD_STAT, "bd96801-ldo7-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "bd96801-ldo7-undervolt"), +}; + +static const struct resource wdg_intb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96801_WDT_ERR_STAT, "bd96801-wdg"), +}; + +static struct mfd_cell bd96801_mfd_cells[] = { + { + .name = "bd96801-wdt", + .resources = wdg_intb_irqs, + .num_resources = ARRAY_SIZE(wdg_intb_irqs), + }, { + .name = "bd96801-pmic", + .resources = regulator_intb_irqs, + .num_resources = ARRAY_SIZE(regulator_intb_irqs), + }, +}; + +static const struct regmap_range bd96801_volatile_ranges[] = { + /* Status registers */ + regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT), + regmap_reg_range(BD96801_REG_WD_ASK, BD96801_REG_WD_ASK), + regmap_reg_range(BD96801_REG_WD_STATUS, BD96801_REG_WD_STATUS), + regmap_reg_range(BD96801_REG_PMIC_STATE, BD96801_REG_INT_LDO7_INTB), + /* Registers which do not update value unless PMIC is in STBY */ + regmap_reg_range(BD96801_REG_SSCG_CTRL, BD96801_REG_SHD_INTB), + regmap_reg_range(BD96801_REG_BUCK_OVP, BD96801_REG_BOOT_OVERTIME), + /* + * LDO control registers have single bit (LDO MODE) which does not + * change when we write it unless PMIC is in STBY. It's safer to not + * cache it. + */ + regmap_reg_range(BD96801_LDO5_VOL_LVL_REG, BD96801_LDO7_VOL_LVL_REG), +}; + +static const struct regmap_access_table volatile_regs = { + .yes_ranges = bd96801_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges), +}; + +static const struct regmap_irq bd96801_intb_irqs[] = { + /* STATUS SYSTEM INTB */ + REGMAP_IRQ_REG(BD96801_TW_STAT, 0, BD96801_TW_STAT_MASK), + REGMAP_IRQ_REG(BD96801_WDT_ERR_STAT, 0, BD96801_WDT_ERR_STAT_MASK), + REGMAP_IRQ_REG(BD96801_I2C_ERR_STAT, 0, BD96801_I2C_ERR_STAT_MASK), + REGMAP_IRQ_REG(BD96801_CHIP_IF_ERR_STAT, 0, BD96801_CHIP_IF_ERR_STAT_MASK), + /* STATUS BUCK1 INTB */ + REGMAP_IRQ_REG(BD96801_BUCK1_OCPH_STAT, 1, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_OCPL_STAT, 1, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_OCPN_STAT, 1, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_OVD_STAT, 1, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_UVD_STAT, 1, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_TW_CH_STAT, 1, BD96801_BUCK_TW_CH_STAT_MASK), + /* BUCK 2 INTB */ + REGMAP_IRQ_REG(BD96801_BUCK2_OCPH_STAT, 2, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_OCPL_STAT, 2, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_OCPN_STAT, 2, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_OVD_STAT, 2, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_UVD_STAT, 2, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_TW_CH_STAT, 2, BD96801_BUCK_TW_CH_STAT_MASK), + /* BUCK 3 INTB */ + REGMAP_IRQ_REG(BD96801_BUCK3_OCPH_STAT, 3, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_OCPL_STAT, 3, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_OCPN_STAT, 3, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_OVD_STAT, 3, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_UVD_STAT, 3, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_TW_CH_STAT, 3, BD96801_BUCK_TW_CH_STAT_MASK), + /* BUCK 4 INTB */ + REGMAP_IRQ_REG(BD96801_BUCK4_OCPH_STAT, 4, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_OCPL_STAT, 4, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_OCPN_STAT, 4, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_OVD_STAT, 4, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_UVD_STAT, 4, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_TW_CH_STAT, 4, BD96801_BUCK_TW_CH_STAT_MASK), + /* LDO5 INTB */ + REGMAP_IRQ_REG(BD96801_LDO5_OCPH_STAT, 5, BD96801_LDO_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_OVD_STAT, 5, BD96801_LDO_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_UVD_STAT, 5, BD96801_LDO_UVD_STAT_MASK), + /* LDO6 INTB */ + REGMAP_IRQ_REG(BD96801_LDO6_OCPH_STAT, 6, BD96801_LDO_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_OVD_STAT, 6, BD96801_LDO_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_UVD_STAT, 6, BD96801_LDO_UVD_STAT_MASK), + /* LDO7 INTB */ + REGMAP_IRQ_REG(BD96801_LDO7_OCPH_STAT, 7, BD96801_LDO_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_OVD_STAT, 7, BD96801_LDO_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK), +}; + +static struct regmap_irq_chip bd96801_irq_chip_intb = { + .name = "bd96801-irq-intb", + .main_status = BD96801_REG_INT_MAIN, + .num_main_regs = 1, + .irqs = &bd96801_intb_irqs[0], + .num_irqs = ARRAY_SIZE(bd96801_intb_irqs), + .status_base = BD96801_REG_INT_SYS_INTB, + .mask_base = BD96801_REG_MASK_SYS_INTB, + .ack_base = BD96801_REG_INT_SYS_INTB, + .init_ack_masked = true, + .num_regs = 8, + .irq_reg_stride = 1, +}; + +static const struct regmap_config bd96801_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &volatile_regs, + .cache_type = REGCACHE_RBTREE, +}; + +static int bd96801_i2c_probe(struct i2c_client *i2c) +{ + struct regmap_irq_chip_data *intb_irq_data; + const struct fwnode_handle *fwnode; + struct irq_domain *intb_domain; + struct regmap *regmap; + int ret, intb_irq; + + fwnode = dev_fwnode(&i2c->dev); + if (!fwnode) + return dev_err_probe(&i2c->dev, -EINVAL, "Failed to find fwnode\n"); + + intb_irq = fwnode_irq_get_byname(fwnode, "intb"); + if (intb_irq < 0) + return dev_err_probe(&i2c->dev, intb_irq, "INTB IRQ not configured\n"); + + regmap = devm_regmap_init_i2c(i2c, &bd96801_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(regmap), + "Regmap initialization failed\n"); + + ret = regmap_write(regmap, BD96801_LOCK_REG, BD96801_UNLOCK); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Failed to unlock PMIC\n"); + + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, intb_irq, + IRQF_ONESHOT, 0, &bd96801_irq_chip_intb, + &intb_irq_data); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Failed to add INTB IRQ chip\n"); + + intb_domain = regmap_irq_get_domain(intb_irq_data); + + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, + bd96801_mfd_cells, + ARRAY_SIZE(bd96801_mfd_cells), NULL, 0, + intb_domain); + + if (ret) + dev_err(&i2c->dev, "Failed to create subdevices\n"); + + return ret; +} + +static const struct of_device_id bd96801_of_match[] = { + { .compatible = "rohm,bd96801", }, + { } +}; +MODULE_DEVICE_TABLE(of, bd96801_of_match); + +static struct i2c_driver bd96801_i2c_driver = { + .driver = { + .name = "rohm-bd96801", + .of_match_table = bd96801_of_match, + }, + .probe = bd96801_i2c_probe, +}; + +static int __init bd96801_i2c_init(void) +{ + return i2c_add_driver(&bd96801_i2c_driver); +} + +/* Initialise early so consumer devices can complete system boot */ +subsys_initcall(bd96801_i2c_init); + +static void __exit bd96801_i2c_exit(void) +{ + i2c_del_driver(&bd96801_i2c_driver); +} +module_exit(bd96801_i2c_exit); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("ROHM BD96801 Power Management IC driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/rohm-bd96801.h b/include/linux/mfd/rohm-bd96801.h new file mode 100644 index 000000000000..e2d9e10b6364 --- /dev/null +++ b/include/linux/mfd/rohm-bd96801.h @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2024 ROHM Semiconductors */ + +#ifndef __MFD_BD96801_H__ +#define __MFD_BD96801_H__ + +#define BD96801_REG_SSCG_CTRL 0x09 +#define BD96801_REG_SHD_INTB 0x20 +#define BD96801_LDO5_VOL_LVL_REG 0x2c +#define BD96801_LDO6_VOL_LVL_REG 0x2d +#define BD96801_LDO7_VOL_LVL_REG 0x2e +#define BD96801_REG_BUCK_OVP 0x30 +#define BD96801_REG_BUCK_OVD 0x35 +#define BD96801_REG_LDO_OVP 0x31 +#define BD96801_REG_LDO_OVD 0x36 +#define BD96801_REG_BOOT_OVERTIME 0x3a +#define BD96801_REG_WD_TMO 0x40 +#define BD96801_REG_WD_CONF 0x41 +#define BD96801_REG_WD_FEED 0x42 +#define BD96801_REG_WD_FAILCOUNT 0x43 +#define BD96801_REG_WD_ASK 0x46 +#define BD96801_REG_WD_STATUS 0x4a +#define BD96801_REG_PMIC_STATE 0x4f +#define BD96801_REG_EXT_STATE 0x50 + +#define BD96801_STATE_STBY 0x09 + +#define BD96801_LOCK_REG 0x04 +#define BD96801_UNLOCK 0x9d +#define BD96801_LOCK 0x00 + +/* IRQ register area */ +#define BD96801_REG_INT_MAIN 0x51 + +/* + * The BD96801 has two physical IRQ lines, INTB and ERRB. + * + * The 'main status register' is located at 0x51. + * The ERRB status registers are located at 0x52 ... 0x5B + * INTB status registers are at range 0x5c ... 0x63 + */ +#define BD96801_REG_INT_SYS_ERRB1 0x52 +#define BD96801_REG_INT_SYS_INTB 0x5c +#define BD96801_REG_INT_LDO7_INTB 0x63 + +/* MASK registers */ +#define BD96801_REG_MASK_SYS_INTB 0x73 +#define BD96801_REG_MASK_SYS_ERRB 0x69 + +#define BD96801_MAX_REGISTER 0x7a + +#define BD96801_OTP_ERR_MASK BIT(0) +#define BD96801_DBIST_ERR_MASK BIT(1) +#define BD96801_EEP_ERR_MASK BIT(2) +#define BD96801_ABIST_ERR_MASK BIT(3) +#define BD96801_PRSTB_ERR_MASK BIT(4) +#define BD96801_DRMOS1_ERR_MASK BIT(5) +#define BD96801_DRMOS2_ERR_MASK BIT(6) +#define BD96801_SLAVE_ERR_MASK BIT(7) +#define BD96801_VREF_ERR_MASK BIT(0) +#define BD96801_TSD_ERR_MASK BIT(1) +#define BD96801_UVLO_ERR_MASK BIT(2) +#define BD96801_OVLO_ERR_MASK BIT(3) +#define BD96801_OSC_ERR_MASK BIT(4) +#define BD96801_PON_ERR_MASK BIT(5) +#define BD96801_POFF_ERR_MASK BIT(6) +#define BD96801_CMD_SHDN_ERR_MASK BIT(7) +#define BD96801_INT_PRSTB_WDT_ERR_MASK BIT(0) +#define BD96801_INT_CHIP_IF_ERR_MASK BIT(3) +#define BD96801_INT_SHDN_ERR_MASK BIT(7) +#define BD96801_OUT_PVIN_ERR_MASK BIT(0) +#define BD96801_OUT_OVP_ERR_MASK BIT(1) +#define BD96801_OUT_UVP_ERR_MASK BIT(2) +#define BD96801_OUT_SHDN_ERR_MASK BIT(7) + +/* ERRB IRQs */ +enum { + /* Reg 0x52, 0x53, 0x54 - ERRB system IRQs */ + BD96801_OTP_ERR_STAT, + BD96801_DBIST_ERR_STAT, + BD96801_EEP_ERR_STAT, + BD96801_ABIST_ERR_STAT, + BD96801_PRSTB_ERR_STAT, + BD96801_DRMOS1_ERR_STAT, + BD96801_DRMOS2_ERR_STAT, + BD96801_SLAVE_ERR_STAT, + BD96801_VREF_ERR_STAT, + BD96801_TSD_ERR_STAT, + BD96801_UVLO_ERR_STAT, + BD96801_OVLO_ERR_STAT, + BD96801_OSC_ERR_STAT, + BD96801_PON_ERR_STAT, + BD96801_POFF_ERR_STAT, + BD96801_CMD_SHDN_ERR_STAT, + BD96801_INT_PRSTB_WDT_ERR, + BD96801_INT_CHIP_IF_ERR, + BD96801_INT_SHDN_ERR_STAT, + + /* Reg 0x55 BUCK1 ERR IRQs */ + BD96801_BUCK1_PVIN_ERR_STAT, + BD96801_BUCK1_OVP_ERR_STAT, + BD96801_BUCK1_UVP_ERR_STAT, + BD96801_BUCK1_SHDN_ERR_STAT, + + /* Reg 0x56 BUCK2 ERR IRQs */ + BD96801_BUCK2_PVIN_ERR_STAT, + BD96801_BUCK2_OVP_ERR_STAT, + BD96801_BUCK2_UVP_ERR_STAT, + BD96801_BUCK2_SHDN_ERR_STAT, + + /* Reg 0x57 BUCK3 ERR IRQs */ + BD96801_BUCK3_PVIN_ERR_STAT, + BD96801_BUCK3_OVP_ERR_STAT, + BD96801_BUCK3_UVP_ERR_STAT, + BD96801_BUCK3_SHDN_ERR_STAT, + + /* Reg 0x58 BUCK4 ERR IRQs */ + BD96801_BUCK4_PVIN_ERR_STAT, + BD96801_BUCK4_OVP_ERR_STAT, + BD96801_BUCK4_UVP_ERR_STAT, + BD96801_BUCK4_SHDN_ERR_STAT, + + /* Reg 0x59 LDO5 ERR IRQs */ + BD96801_LDO5_PVIN_ERR_STAT, + BD96801_LDO5_OVP_ERR_STAT, + BD96801_LDO5_UVP_ERR_STAT, + BD96801_LDO5_SHDN_ERR_STAT, + + /* Reg 0x5a LDO6 ERR IRQs */ + BD96801_LDO6_PVIN_ERR_STAT, + BD96801_LDO6_OVP_ERR_STAT, + BD96801_LDO6_UVP_ERR_STAT, + BD96801_LDO6_SHDN_ERR_STAT, + + /* Reg 0x5b LDO7 ERR IRQs */ + BD96801_LDO7_PVIN_ERR_STAT, + BD96801_LDO7_OVP_ERR_STAT, + BD96801_LDO7_UVP_ERR_STAT, + BD96801_LDO7_SHDN_ERR_STAT, +}; + +/* INTB IRQs */ +enum { + /* Reg 0x5c (System INTB) */ + BD96801_TW_STAT, + BD96801_WDT_ERR_STAT, + BD96801_I2C_ERR_STAT, + BD96801_CHIP_IF_ERR_STAT, + + /* Reg 0x5d (BUCK1 INTB) */ + BD96801_BUCK1_OCPH_STAT, + BD96801_BUCK1_OCPL_STAT, + BD96801_BUCK1_OCPN_STAT, + BD96801_BUCK1_OVD_STAT, + BD96801_BUCK1_UVD_STAT, + BD96801_BUCK1_TW_CH_STAT, + + /* Reg 0x5e (BUCK2 INTB) */ + BD96801_BUCK2_OCPH_STAT, + BD96801_BUCK2_OCPL_STAT, + BD96801_BUCK2_OCPN_STAT, + BD96801_BUCK2_OVD_STAT, + BD96801_BUCK2_UVD_STAT, + BD96801_BUCK2_TW_CH_STAT, + + /* Reg 0x5f (BUCK3 INTB)*/ + BD96801_BUCK3_OCPH_STAT, + BD96801_BUCK3_OCPL_STAT, + BD96801_BUCK3_OCPN_STAT, + BD96801_BUCK3_OVD_STAT, + BD96801_BUCK3_UVD_STAT, + BD96801_BUCK3_TW_CH_STAT, + + /* Reg 0x60 (BUCK4 INTB)*/ + BD96801_BUCK4_OCPH_STAT, + BD96801_BUCK4_OCPL_STAT, + BD96801_BUCK4_OCPN_STAT, + BD96801_BUCK4_OVD_STAT, + BD96801_BUCK4_UVD_STAT, + BD96801_BUCK4_TW_CH_STAT, + + /* Reg 0x61 (LDO5 INTB) */ + BD96801_LDO5_OCPH_STAT, /* bit [0] */ + BD96801_LDO5_OVD_STAT, /* bit [3] */ + BD96801_LDO5_UVD_STAT, /* bit [4] */ + + /* Reg 0x62 (LDO6 INTB) */ + BD96801_LDO6_OCPH_STAT, /* bit [0] */ + BD96801_LDO6_OVD_STAT, /* bit [3] */ + BD96801_LDO6_UVD_STAT, /* bit [4] */ + + /* Reg 0x63 (LDO7 INTB) */ + BD96801_LDO7_OCPH_STAT, /* bit [0] */ + BD96801_LDO7_OVD_STAT, /* bit [3] */ + BD96801_LDO7_UVD_STAT, /* bit [4] */ +}; + +/* IRQ MASKs */ +#define BD96801_TW_STAT_MASK BIT(0) +#define BD96801_WDT_ERR_STAT_MASK BIT(1) +#define BD96801_I2C_ERR_STAT_MASK BIT(2) +#define BD96801_CHIP_IF_ERR_STAT_MASK BIT(3) + +#define BD96801_BUCK_OCPH_STAT_MASK BIT(0) +#define BD96801_BUCK_OCPL_STAT_MASK BIT(1) +#define BD96801_BUCK_OCPN_STAT_MASK BIT(2) +#define BD96801_BUCK_OVD_STAT_MASK BIT(3) +#define BD96801_BUCK_UVD_STAT_MASK BIT(4) +#define BD96801_BUCK_TW_CH_STAT_MASK BIT(5) + +#define BD96801_LDO_OCPH_STAT_MASK BIT(0) +#define BD96801_LDO_OVD_STAT_MASK BIT(3) +#define BD96801_LDO_UVD_STAT_MASK BIT(4) + +#endif diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 4eeb22876bad..e7d4e6afe388 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -16,6 +16,7 @@ enum rohm_chip_type { ROHM_CHIP_TYPE_BD71828, ROHM_CHIP_TYPE_BD71837, ROHM_CHIP_TYPE_BD71847, + ROHM_CHIP_TYPE_BD96801, ROHM_CHIP_TYPE_AMOUNT }; From patchwork Tue Jun 4 07:54:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684867 Received: from mail-lf1-f53.google.com (mail-lf1-f53.google.com [209.85.167.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 DE0521411FA; Tue, 4 Jun 2024 07:54:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487689; cv=none; b=kXVA596gikPFz6mujPtNhsUJaNi0Kz7HU/g6nhoLxEiphgO2vbPjrZcuzOoXuTnuNNHuwoTIdgwMMKRfZ+3dsAhug5VTqeQ1JM99Q42k0nDQLNbunlu3ugegUOV41zR8ZhZDwMb/oJH+D00yzAuX3M0mr4srPN7Y+MlXItGPK4M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487689; c=relaxed/simple; bh=mlWVLxgfeOiv23Qq03HSX4k+m0WR0TeWu3AwFY6aDgw=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=dmgiy917YGR43lMaRLga/KIOko6e3lYR/gnZdqSKKdw2Nx5SKHCHW9u0cv0eC6DyI5BHkOHrXdkldpr9CqBCV5IDME7mNUG/zlwEOIbjTAEzHA+cnfegL54UBJRti9BrK9BzZSSHdRIpUdS8CVal74oMm3MU5tIEnyW/TbS5e9g= 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=anWILeSE; arc=none smtp.client-ip=209.85.167.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="anWILeSE" Received: by mail-lf1-f53.google.com with SMTP id 2adb3069b0e04-52b88335dd7so5004353e87.1; Tue, 04 Jun 2024 00:54:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487685; x=1718092485; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=Ajl+pJQXb0oY9Ix7CAXyaidBTyvfLQfeQKC/qxxZLgY=; b=anWILeSEAeTvGGjw75X+4Z3WYERi7RO/MVNUE0YhLQdrOf5M3nLWjQ9o2tGR/2ejU0 acVMrQLZSPtVZYqKtPx2aEMs8Y8XtqK5q+2e9qeMcWzxEtfjuxVwnnkD+uoLwTvSpmuM lpytMEZut87of294P9eNwianKxn2pkeUs9qA4u+C0YtHoU5vwe230htJ+IQ596U8KyX0 sUC8TlX29tbrvsTAvuw+kbY1+ZjdrDrTZZVRXzhndysNU8zbAfC7ZUUhyNGjHpPZTkYv 0V5neOsVGi3JOjy/n/JGsVTWGfVSO+NiE60G1igMUnbCIKs5uVzwVnAuLGSMGELvPlVi bYyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487685; x=1718092485; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Ajl+pJQXb0oY9Ix7CAXyaidBTyvfLQfeQKC/qxxZLgY=; b=HUbNqnNbxChwDOWOam6ggMdJZn2ymQlP2shkwgGcREmBa9bk433oHoP0dFmhR0bCTx xY63HsiUAHEyynSkYXQIJn/N3uHi8BFI62pUpzTYh92dOqW3pRzeI8p77r8dwsGqMY1X 1fusLMqq+74r7Iad5ldha6IwDJgxbN3DmPeSWp/Fr897jGg/Hcs6B6jNIngJJC2xYNzt T4FP106NwhyRKtXhwGn8k/9qlDF8l+aRAqwTGuG1bpq3ZYwcy2xM0Mbn5ZVD2aCgS8aG 1bfuJUurq1m/g/ilZxGVd1g5Ej4o73fx5ilrnljp+d53qbHDQ/vuFhKoZzlM1gb+JoUB P3oA== X-Forwarded-Encrypted: i=1; AJvYcCV+7JCCQ9T1BtyZENRnGQldQHzW1q50hsLrOg28YGIkfa42cRbfjGgiUrZ2Ijx2RwV1WU6ZVxAQbHtJ8tfvGkkZx5EFy/QxZYQZGYsIHiky8bm6ACB+3WQZNHg7CWO/GQEQcEws2dfZs0gtvaQ6LMsiWP2hWJ3H0KR6POgjn3IjNaI0Bsg4tM+X X-Gm-Message-State: AOJu0Yx+TC2C/FuV6Yqr7Dap/CmFg5LS+RwrZ7ktqn88X4qDyn7g9/Kd lYFGtNSFXTG4IjWBCPbp/UXNAqel4YJHGVsqsU+fHrooW22xTQEY X-Google-Smtp-Source: AGHT+IH+UXA/rMXm/ybn6KWkTUSILYR0J+CEwkjsRWo4frZ7ah/iqjVHmnoLkAfitT51U8Wb2FpCBg== X-Received: by 2002:a19:4314:0:b0:524:6385:6883 with SMTP id 2adb3069b0e04-52b89597b81mr7395620e87.37.1717487684516; Tue, 04 Jun 2024 00:54:44 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52b98ffe95bsm625061e87.293.2024.06.04.00.54.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:54:43 -0700 (PDT) Date: Tue, 4 Jun 2024 10:54:39 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 04/10] regulator: bd96801: ROHM BD96801 PMIC regulators Message-ID: <9a6cac156f6fd74f02f71833789c62e21ca9011a.1717486682.git.mazziesaccount@gmail.com> References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The ROHM BD96801 "Scalable PMIC" is an automotive grade PMIC which can scale to different applications by allowing chaining of PMICs. The PMIC also supports various protection features which can be configured either to fire IRQs - or to shut down power outputs when failure is detected. The driver implements basic voltage control and sending error notifications. NOTE: The driver does not support doing configuration which require the PMIC to be in STBY state. The omitted feature set includes setting safety limit values, changing LDO voltages and controlling enable state for some regulators. Also, the ERRB IRQ is not handled. Signed-off-by: Matti Vaittinen Reviewed-by: Mark Brown --- Revision history: v2 => - no changes v1 => v2: - regulator: bd96801: lowercase DT node names - split intb registration to own function RFCv2 => v1: - Drop STBY mode configurations - Drop ERRB IRQs - drop PMIC register unlock (moved to MFD to prevent races) RFCv1 => RFCv2: - Use devm_kcalloc() instead of devm_kzalloc() where appropriate - Use devm_kmemdup() - Add MODULE_DEVICE_TABLE - drop MODULE_ALIAS --- drivers/regulator/Kconfig | 12 + drivers/regulator/Makefile | 2 + drivers/regulator/bd96801-regulator.c | 908 ++++++++++++++++++++++++++ 3 files changed, 922 insertions(+) create mode 100644 drivers/regulator/bd96801-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index d333be2bea3b..88b8c1a23bcf 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -268,6 +268,18 @@ config REGULATOR_BD957XMUF This driver can also be built as a module. If so, the module will be called bd9576-regulator. +config REGULATOR_BD96801 + tristate "ROHM BD96801 Power Regulator" + depends on MFD_ROHM_BD96801 + select REGULATOR_ROHM + help + This driver supports voltage regulators on ROHM BD96801 PMIC. + This will enable support for the software controllable buck + and LDO regulators. + + This driver can also be built as a module. If so, the module + will be called bd96801-regulator. + config REGULATOR_CPCAP tristate "Motorola CPCAP regulator" depends on MFD_CPCAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index ba15fa5f30ad..cde21dcb8eca 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -37,6 +37,8 @@ obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o obj-$(CONFIG_REGULATOR_BD957XMUF) += bd9576-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x-regulator.o +obj-$(CONFIG_REGULATOR_BD96801) += bd96801-regulator.o +obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o obj-$(CONFIG_REGULATOR_DA9062) += da9062-regulator.o diff --git a/drivers/regulator/bd96801-regulator.c b/drivers/regulator/bd96801-regulator.c new file mode 100644 index 000000000000..a1ac068c69f8 --- /dev/null +++ b/drivers/regulator/bd96801-regulator.c @@ -0,0 +1,908 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2024 ROHM Semiconductors +// bd96801-regulator.c ROHM BD96801 regulator driver + +/* + * This version of the "BD86801 scalable PMIC"'s driver supports only very + * basic set of the PMIC features. Most notably, there is no support for + * the ERRB interrupt and the configurations which should be done when the + * PMIC is in STBY mode. + * + * Supporting the ERRB interrupt would require dropping the regmap-IRQ + * usage or working around (or accepting a presense of) a naming conflict + * in debugFS IRQs. + * + * Being able to reliably do the configurations like changing the + * regulator safety limits (like limits for the over/under -voltages, over + * current, thermal protection) would require the configuring driver to be + * synchronized with entity causing the PMIC state transitions. Eg, one + * should be able to ensure the PMIC is in STBY state when the + * configurations are applied to the hardware. How and when the PMIC state + * transitions are to be done is likely to be very system specific, as will + * be the need to configure these safety limits. Hence it's not simple to + * come up with a generic solution. + * + * Users who require the ERRB handling and STBY state configurations can + * have a look at the original RFC: + * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ + * which implements a workaround to debugFS naming conflict and some of + * the safety limit configurations - but leaves the state change handling + * and synchronization to be implemented. + * + * It would be great to hear (and receive a patch!) if you implement the + * STBY configuration support or a proper fix to the debugFS naming + * conflict in your downstream driver ;) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + BD96801_BUCK1, + BD96801_BUCK2, + BD96801_BUCK3, + BD96801_BUCK4, + BD96801_LDO5, + BD96801_LDO6, + BD96801_LDO7, + BD96801_REGULATOR_AMOUNT, +}; + +enum { + BD96801_PROT_OVP, + BD96801_PROT_UVP, + BD96801_PROT_OCP, + BD96801_PROT_TEMP, + BD96801_NUM_PROT, +}; + +#define BD96801_ALWAYS_ON_REG 0x3c +#define BD96801_REG_ENABLE 0x0b +#define BD96801_BUCK1_EN_MASK BIT(0) +#define BD96801_BUCK2_EN_MASK BIT(1) +#define BD96801_BUCK3_EN_MASK BIT(2) +#define BD96801_BUCK4_EN_MASK BIT(3) +#define BD96801_LDO5_EN_MASK BIT(4) +#define BD96801_LDO6_EN_MASK BIT(5) +#define BD96801_LDO7_EN_MASK BIT(6) + +#define BD96801_BUCK1_VSEL_REG 0x28 +#define BD96801_BUCK2_VSEL_REG 0x29 +#define BD96801_BUCK3_VSEL_REG 0x2a +#define BD96801_BUCK4_VSEL_REG 0x2b +#define BD96801_LDO5_VSEL_REG 0x25 +#define BD96801_LDO6_VSEL_REG 0x26 +#define BD96801_LDO7_VSEL_REG 0x27 +#define BD96801_BUCK_VSEL_MASK 0x1F +#define BD96801_LDO_VSEL_MASK 0xff + +#define BD96801_MASK_RAMP_DELAY 0xc0 +#define BD96801_INT_VOUT_BASE_REG 0x21 +#define BD96801_BUCK_INT_VOUT_MASK 0xff + +#define BD96801_BUCK_VOLTS 256 +#define BD96801_LDO_VOLTS 256 + +#define BD96801_OVP_MASK 0x03 +#define BD96801_MASK_BUCK1_OVP_SHIFT 0x00 +#define BD96801_MASK_BUCK2_OVP_SHIFT 0x02 +#define BD96801_MASK_BUCK3_OVP_SHIFT 0x04 +#define BD96801_MASK_BUCK4_OVP_SHIFT 0x06 +#define BD96801_MASK_LDO5_OVP_SHIFT 0x00 +#define BD96801_MASK_LDO6_OVP_SHIFT 0x02 +#define BD96801_MASK_LDO7_OVP_SHIFT 0x04 + +#define BD96801_PROT_LIMIT_OCP_MIN 0x00 +#define BD96801_PROT_LIMIT_LOW 0x01 +#define BD96801_PROT_LIMIT_MID 0x02 +#define BD96801_PROT_LIMIT_HI 0x03 + +#define BD96801_REG_BUCK1_OCP 0x32 +#define BD96801_REG_BUCK2_OCP 0x32 +#define BD96801_REG_BUCK3_OCP 0x33 +#define BD96801_REG_BUCK4_OCP 0x33 + +#define BD96801_MASK_BUCK1_OCP_SHIFT 0x00 +#define BD96801_MASK_BUCK2_OCP_SHIFT 0x04 +#define BD96801_MASK_BUCK3_OCP_SHIFT 0x00 +#define BD96801_MASK_BUCK4_OCP_SHIFT 0x04 + +#define BD96801_REG_LDO5_OCP 0x34 +#define BD96801_REG_LDO6_OCP 0x34 +#define BD96801_REG_LDO7_OCP 0x34 + +#define BD96801_MASK_LDO5_OCP_SHIFT 0x00 +#define BD96801_MASK_LDO6_OCP_SHIFT 0x02 +#define BD96801_MASK_LDO7_OCP_SHIFT 0x04 + +#define BD96801_MASK_SHD_INTB BIT(7) +#define BD96801_INTB_FATAL BIT(7) + +#define BD96801_NUM_REGULATORS 7 +#define BD96801_NUM_LDOS 4 + +/* + * Ramp rates for bucks are controlled by bits [7:6] as follows: + * 00 => 1 mV/uS + * 01 => 5 mV/uS + * 10 => 10 mV/uS + * 11 => 20 mV/uS + */ +static const unsigned int buck_ramp_table[] = { 1000, 5000, 10000, 20000 }; + +/* + * This is a voltage range that get's appended to selected + * bd96801_buck_init_volts value. The range from 0x0 to 0xF is actually + * bd96801_buck_init_volts + 0 ... bd96801_buck_init_volts + 150mV + * and the range from 0x10 to 0x1f is bd96801_buck_init_volts - 150mV ... + * bd96801_buck_init_volts - 0. But as the members of linear_range + * are all unsigned I will apply offset of -150 mV to value in + * linear_range - which should increase these ranges with + * 150 mV getting all the values to >= 0. + */ +static const struct linear_range bd96801_tune_volts[] = { + REGULATOR_LINEAR_RANGE(150000, 0x00, 0xF, 10000), + REGULATOR_LINEAR_RANGE(0, 0x10, 0x1F, 10000), +}; + +static const struct linear_range bd96801_buck_init_volts[] = { + REGULATOR_LINEAR_RANGE(500000 - 150000, 0x00, 0xc8, 5000), + REGULATOR_LINEAR_RANGE(1550000 - 150000, 0xc9, 0xec, 50000), + REGULATOR_LINEAR_RANGE(3300000 - 150000, 0xed, 0xff, 0), +}; + +static const struct linear_range bd96801_ldo_int_volts[] = { + REGULATOR_LINEAR_RANGE(300000, 0x00, 0x78, 25000), + REGULATOR_LINEAR_RANGE(3300000, 0x79, 0xff, 0), +}; + +#define BD96801_LDO_SD_VOLT_MASK 0x1 +#define BD96801_LDO_MODE_MASK 0x6 +#define BD96801_LDO_MODE_INT 0x0 +#define BD96801_LDO_MODE_SD 0x2 +#define BD96801_LDO_MODE_DDR 0x4 + +static int ldo_ddr_volt_table[] = {500000, 300000}; +static int ldo_sd_volt_table[] = {3300000, 1800000}; + +/* Constant IRQ initialization data (templates) */ +struct bd96801_irqinfo { + int type; + struct regulator_irq_desc irq_desc; + int err_cfg; + int wrn_cfg; + const char *irq_name; +}; + +#define BD96801_IRQINFO(_type, _name, _irqoff_ms, _irqname) \ +{ \ + .type = (_type), \ + .err_cfg = -1, \ + .wrn_cfg = -1, \ + .irq_name = (_irqname), \ + .irq_desc = { \ + .name = (_name), \ + .irq_off_ms = (_irqoff_ms), \ + .map_event = regulator_irq_map_event_simple, \ + }, \ +} + +static const struct bd96801_irqinfo buck1_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-h", 500, + "bd96801-buck1-overcurr-h"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-l", 500, + "bd96801-buck1-overcurr-l"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-n", 500, + "bd96801-buck1-overcurr-n"), + BD96801_IRQINFO(BD96801_PROT_OVP, "buck1-over-voltage", 500, + "bd96801-buck1-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "buck1-under-voltage", 500, + "bd96801-buck1-undervolt"), + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck1-over-temp", 500, + "bd96801-buck1-thermal") +}; + +static const struct bd96801_irqinfo buck2_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-h", 500, + "bd96801-buck2-overcurr-h"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-l", 500, + "bd96801-buck2-overcurr-l"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-n", 500, + "bd96801-buck2-overcurr-n"), + BD96801_IRQINFO(BD96801_PROT_OVP, "buck2-over-voltage", 500, + "bd96801-buck2-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "buck2-under-voltage", 500, + "bd96801-buck2-undervolt"), + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck2-over-temp", 500, + "bd96801-buck2-thermal") +}; + +static const struct bd96801_irqinfo buck3_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-h", 500, + "bd96801-buck3-overcurr-h"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-l", 500, + "bd96801-buck3-overcurr-l"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-n", 500, + "bd96801-buck3-overcurr-n"), + BD96801_IRQINFO(BD96801_PROT_OVP, "buck3-over-voltage", 500, + "bd96801-buck3-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "buck3-under-voltage", 500, + "bd96801-buck3-undervolt"), + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck3-over-temp", 500, + "bd96801-buck3-thermal") +}; + +static const struct bd96801_irqinfo buck4_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-h", 500, + "bd96801-buck4-overcurr-h"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-l", 500, + "bd96801-buck4-overcurr-l"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-n", 500, + "bd96801-buck4-overcurr-n"), + BD96801_IRQINFO(BD96801_PROT_OVP, "buck4-over-voltage", 500, + "bd96801-buck4-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "buck4-under-voltage", 500, + "bd96801-buck4-undervolt"), + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck4-over-temp", 500, + "bd96801-buck4-thermal") +}; + +static const struct bd96801_irqinfo ldo5_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo5-overcurr", 500, + "bd96801-ldo5-overcurr"), + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo5-over-voltage", 500, + "bd96801-ldo5-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo5-under-voltage", 500, + "bd96801-ldo5-undervolt"), +}; + +static const struct bd96801_irqinfo ldo6_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo6-overcurr", 500, + "bd96801-ldo6-overcurr"), + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo6-over-voltage", 500, + "bd96801-ldo6-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo6-under-voltage", 500, + "bd96801-ldo6-undervolt"), +}; + +static const struct bd96801_irqinfo ldo7_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo7-overcurr", 500, + "bd96801-ldo7-overcurr"), + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo7-over-voltage", 500, + "bd96801-ldo7-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo7-under-voltage", 500, + "bd96801-ldo7-undervolt"), +}; + +struct bd96801_irq_desc { + struct bd96801_irqinfo *irqinfo; + int num_irqs; +}; + +struct bd96801_regulator_data { + struct regulator_desc desc; + const struct linear_range *init_ranges; + int num_ranges; + struct bd96801_irq_desc irq_desc; + int initial_voltage; + int ldo_vol_lvl; + int ldo_errs; +}; + +struct bd96801_pmic_data { + struct bd96801_regulator_data regulator_data[BD96801_NUM_REGULATORS]; + struct regmap *regmap; + int fatal_ind; +}; + +static int ldo_map_notif(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int i; + + for (i = 0; i < rid->num_states; i++) { + struct bd96801_regulator_data *rdata; + struct regulator_dev *rdev; + + rdev = rid->states[i].rdev; + rdata = container_of(rdev->desc, struct bd96801_regulator_data, + desc); + rid->states[i].notifs = regulator_err2notif(rdata->ldo_errs); + rid->states[i].errors = rdata->ldo_errs; + *dev_mask |= BIT(i); + } + return 0; +} + +static int bd96801_list_voltage_lr(struct regulator_dev *rdev, + unsigned int selector) +{ + int voltage; + struct bd96801_regulator_data *data; + + data = container_of(rdev->desc, struct bd96801_regulator_data, desc); + + /* + * The BD096801 has voltage setting in two registers. One giving the + * "initial voltage" (can be changed only when regulator is disabled. + * This driver caches the value and sets it only at startup. The other + * register is voltage tuning value which applies -150 mV ... +150 mV + * offset to the voltage. + * + * Note that the cached initial voltage stored in regulator data is + * 'scaled down' by the 150 mV so that all of our tuning values are + * >= 0. This is done because the linear_ranges uses unsigned values. + * + * As a result, we increase the tuning voltage which we get based on + * the selector by the stored initial_voltage. + */ + voltage = regulator_list_voltage_linear_range(rdev, selector); + if (voltage < 0) + return voltage; + + return voltage + data->initial_voltage; +} + + +static const struct regulator_ops bd96801_ldo_table_ops = { + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static const struct regulator_ops bd96801_buck_ops = { + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = bd96801_list_voltage_lr, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = regulator_set_ramp_delay_regmap, +}; + +static const struct regulator_ops bd96801_ldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static int buck_get_initial_voltage(struct regmap *regmap, struct device *dev, + struct bd96801_regulator_data *data) +{ + int ret = 0, sel, initial_uv; + int reg = BD96801_INT_VOUT_BASE_REG + data->desc.id; + + if (data->num_ranges) { + ret = regmap_read(regmap, reg, &sel); + sel &= BD96801_BUCK_INT_VOUT_MASK; + + ret = linear_range_get_value_array(data->init_ranges, + data->num_ranges, sel, + &initial_uv); + if (ret) + return ret; + + data->initial_voltage = initial_uv; + dev_dbg(dev, "Tune-scaled initial voltage %u\n", + data->initial_voltage); + } + + return 0; +} + +static int get_ldo_initial_voltage(struct regmap *regmap, + struct device *dev, + struct bd96801_regulator_data *data) +{ + int ret; + int cfgreg; + + ret = regmap_read(regmap, data->ldo_vol_lvl, &cfgreg); + if (ret) + return ret; + + switch (cfgreg & BD96801_LDO_MODE_MASK) { + case BD96801_LDO_MODE_DDR: + data->desc.volt_table = ldo_ddr_volt_table; + data->desc.n_voltages = ARRAY_SIZE(ldo_ddr_volt_table); + break; + case BD96801_LDO_MODE_SD: + data->desc.volt_table = ldo_sd_volt_table; + data->desc.n_voltages = ARRAY_SIZE(ldo_sd_volt_table); + break; + default: + dev_info(dev, "Leaving LDO to normal mode"); + return 0; + } + + /* SD or DDR mode => override default ops */ + data->desc.ops = &bd96801_ldo_table_ops, + data->desc.vsel_mask = 1; + data->desc.vsel_reg = data->ldo_vol_lvl; + + return 0; +} + +static int get_initial_voltage(struct device *dev, struct regmap *regmap, + struct bd96801_regulator_data *data) +{ + /* BUCK */ + if (data->desc.id <= BD96801_BUCK4) + return buck_get_initial_voltage(regmap, dev, data); + + /* LDO */ + return get_ldo_initial_voltage(regmap, dev, data); +} + +static int bd96801_walk_regulator_dt(struct device *dev, struct regmap *regmap, + struct bd96801_regulator_data *data, + int num) +{ + int i, ret; + struct device_node *np; + struct device_node *nproot = dev->parent->of_node; + + nproot = of_get_child_by_name(nproot, "regulators"); + if (!nproot) { + dev_err(dev, "failed to find regulators node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) + for (i = 0; i < num; i++) { + if (!of_node_name_eq(np, data[i].desc.of_match)) + continue; + /* + * If STBY configs are supported, we must pass node + * here to extract the initial voltages from the DT. + * Thus we do the initial voltage getting in this + * loop. + */ + ret = get_initial_voltage(dev, regmap, &data[i]); + if (ret) { + dev_err(dev, + "Initializing voltages for %s failed\n", + data[i].desc.name); + of_node_put(np); + of_node_put(nproot); + + return ret; + } + if (of_property_read_bool(np, "rohm,keep-on-stby")) { + ret = regmap_set_bits(regmap, + BD96801_ALWAYS_ON_REG, + 1 << data[i].desc.id); + if (ret) { + dev_err(dev, + "failed to set %s on-at-stby\n", + data[i].desc.name); + of_node_put(np); + of_node_put(nproot); + + return ret; + } + } + } + of_node_put(nproot); + + return 0; +} + +/* + * Template for regulator data. Probe will allocate dynamic / driver instance + * struct so we should be on a safe side even if there were multiple PMICs to + * control. Note that there is a plan to allow multiple PMICs to be used so + * systems can scale better. I am however still slightly unsure how the + * multi-PMIC case will be handled. I don't know if the processor will have I2C + * acces to all of the PMICs or only the first one. I'd guess there will be + * access provided to all PMICs for voltage scaling - but the errors will only + * be informed via the master PMIC. Eg, we should prepare to support multiple + * driver instances - either with or without the IRQs... Well, let's first + * just support the simple and clear single-PMIC setup and ponder the multi PMIC + * case later. What we can easly do for preparing is to not use static global + * data for regulators though. + */ +static const struct bd96801_pmic_data bd96801_data = { + .regulator_data = { + { + .desc = { + .name = "buck1", + .of_match = of_match_ptr("buck1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK1, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK1_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK1_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK1_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .init_ranges = bd96801_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck1_irqinfo), + }, + }, { + .desc = { + .name = "buck2", + .of_match = of_match_ptr("buck2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK2, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK2_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK2_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK2_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck2_irqinfo), + }, + .init_ranges = bd96801_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), + }, { + .desc = { + .name = "buck3", + .of_match = of_match_ptr("buck3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK3, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK3_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK3_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK3_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck3_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck3_irqinfo), + }, + .init_ranges = bd96801_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), + }, { + .desc = { + .name = "buck4", + .of_match = of_match_ptr("buck4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK4, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK4_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK4_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK4_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck4_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck4_irqinfo), + }, + .init_ranges = bd96801_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), + }, { + .desc = { + .name = "ldo5", + .of_match = of_match_ptr("ldo5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_LDO5, + .ops = &bd96801_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_ldo_int_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), + .n_voltages = BD96801_LDO_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_LDO5_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_LDO5_VSEL_REG, + .vsel_mask = BD96801_LDO_VSEL_MASK, + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&ldo5_irqinfo[0], + .num_irqs = ARRAY_SIZE(ldo5_irqinfo), + }, + .ldo_vol_lvl = BD96801_LDO5_VOL_LVL_REG, + }, { + .desc = { + .name = "ldo6", + .of_match = of_match_ptr("ldo6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_LDO6, + .ops = &bd96801_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_ldo_int_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), + .n_voltages = BD96801_LDO_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_LDO6_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_LDO6_VSEL_REG, + .vsel_mask = BD96801_LDO_VSEL_MASK, + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&ldo6_irqinfo[0], + .num_irqs = ARRAY_SIZE(ldo6_irqinfo), + }, + .ldo_vol_lvl = BD96801_LDO6_VOL_LVL_REG, + }, { + .desc = { + .name = "ldo7", + .of_match = of_match_ptr("ldo7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_LDO7, + .ops = &bd96801_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_ldo_int_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), + .n_voltages = BD96801_LDO_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_LDO7_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_LDO7_VSEL_REG, + .vsel_mask = BD96801_LDO_VSEL_MASK, + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&ldo7_irqinfo[0], + .num_irqs = ARRAY_SIZE(ldo7_irqinfo), + }, + .ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG, + }, + }, +}; + +static int initialize_pmic_data(struct device *dev, + struct bd96801_pmic_data *pdata) +{ + int r, i; + + /* + * Allocate and initialize IRQ data for all of the regulators. We + * wish to modify IRQ information independently for each driver + * instance. + */ + for (r = 0; r < BD96801_NUM_REGULATORS; r++) { + const struct bd96801_irqinfo *template; + struct bd96801_irqinfo *new; + int num_infos; + + template = pdata->regulator_data[r].irq_desc.irqinfo; + num_infos = pdata->regulator_data[r].irq_desc.num_irqs; + + new = devm_kcalloc(dev, num_infos, sizeof(*new), GFP_KERNEL); + if (!new) + return -ENOMEM; + + pdata->regulator_data[r].irq_desc.irqinfo = new; + + for (i = 0; i < num_infos; i++) + new[i] = template[i]; + } + + return 0; +} + +static int bd96801_rdev_intb_irqs(struct platform_device *pdev, + struct bd96801_pmic_data *pdata, + struct bd96801_irqinfo *iinfo, + struct regulator_dev *rdev) +{ + struct regulator_dev *rdev_arr[1]; + void *retp; + int err = 0; + int irq; + int err_flags[] = { + [BD96801_PROT_OVP] = REGULATOR_ERROR_REGULATION_OUT, + [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE, + [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT, + [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP, + + }; + int wrn_flags[] = { + [BD96801_PROT_OVP] = REGULATOR_ERROR_OVER_VOLTAGE_WARN, + [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE_WARN, + [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT_WARN, + [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP_WARN, + }; + + /* + * Don't install IRQ handler if both error and warning + * notifications are explicitly disabled + */ + if (!iinfo->err_cfg && !iinfo->wrn_cfg) + return 0; + + if (WARN_ON(iinfo->type >= BD96801_NUM_PROT)) + return -EINVAL; + + if (iinfo->err_cfg) + err = err_flags[iinfo->type]; + else if (iinfo->wrn_cfg) + err = wrn_flags[iinfo->type]; + + iinfo->irq_desc.data = pdata; + irq = platform_get_irq_byname(pdev, iinfo->irq_name); + if (irq < 0) + return irq; + /* Find notifications for this IRQ (WARN/ERR) */ + + rdev_arr[0] = rdev; + retp = devm_regulator_irq_helper(&pdev->dev, + &iinfo->irq_desc, irq, + 0, err, NULL, rdev_arr, + 1); + if (IS_ERR(retp)) + return PTR_ERR(retp); + + return 0; +} + + + +static int bd96801_probe(struct platform_device *pdev) +{ + struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS]; + struct bd96801_regulator_data *rdesc; + struct regulator_config config = {}; + int ldo_errs_arr[BD96801_NUM_LDOS]; + struct bd96801_pmic_data *pdata; + int temp_notif_ldos = 0; + struct device *parent; + int i, ret; + void *retp; + + parent = pdev->dev.parent; + + pdata = devm_kmemdup(&pdev->dev, &bd96801_data, sizeof(bd96801_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (initialize_pmic_data(&pdev->dev, pdata)) + return -ENOMEM; + + pdata->regmap = dev_get_regmap(parent, NULL); + if (!pdata->regmap) { + dev_err(&pdev->dev, "No register map found\n"); + return -ENODEV; + } + + rdesc = &pdata->regulator_data[0]; + + config.driver_data = pdata; + config.regmap = pdata->regmap; + config.dev = parent; + + ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc, + BD96801_NUM_REGULATORS); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(pdata->regulator_data); i++) { + struct regulator_dev *rdev; + struct bd96801_irq_desc *idesc = &rdesc[i].irq_desc; + int j; + + rdev = devm_regulator_register(&pdev->dev, + &rdesc[i].desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "failed to register %s regulator\n", + rdesc[i].desc.name); + return PTR_ERR(rdev); + } + /* + * LDOs don't have own temperature monitoring. If temperature + * notification was requested for this LDO from DT then we will + * add the regulator to be notified if central IC temperature + * exceeds threshold. + */ + if (rdesc[i].ldo_errs) { + ldo_errs_rdev_arr[temp_notif_ldos] = rdev; + ldo_errs_arr[temp_notif_ldos] = rdesc[i].ldo_errs; + temp_notif_ldos++; + } + if (!idesc) + continue; + + /* Register INTB handlers for configured protections */ + for (j = 0; j < idesc->num_irqs; j++) { + ret = bd96801_rdev_intb_irqs(pdev, pdata, + &idesc->irqinfo[j], rdev); + if (ret) + return ret; + } + } + if (temp_notif_ldos) { + int irq; + struct regulator_irq_desc tw_desc = { + .name = "bd96801-core-thermal", + .irq_off_ms = 500, + .map_event = ldo_map_notif, + }; + + irq = platform_get_irq_byname(pdev, "bd96801-core-thermal"); + if (irq < 0) + return irq; + + retp = devm_regulator_irq_helper(&pdev->dev, &tw_desc, irq, 0, + 0, &ldo_errs_arr[0], + &ldo_errs_rdev_arr[0], + temp_notif_ldos); + if (IS_ERR(retp)) + return PTR_ERR(retp); + } + + return 0; +} + +static const struct platform_device_id bd96801_pmic_id[] = { + { "bd96801-pmic", }, + { } +}; +MODULE_DEVICE_TABLE(platform, bd96801_pmic_id); + +static struct platform_driver bd96801_regulator = { + .driver = { + .name = "bd96801-pmic" + }, + .probe = bd96801_probe, + .id_table = bd96801_pmic_id, +}; + +module_platform_driver(bd96801_regulator); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("BD96801 voltage regulator driver"); +MODULE_LICENSE("GPL"); From patchwork Tue Jun 4 07:54:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684868 Received: from mail-lj1-f176.google.com (mail-lj1-f176.google.com [209.85.208.176]) (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 00ADE142900; Tue, 4 Jun 2024 07:55:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487705; cv=none; b=MwRcNwUQkM7CTPp6Ud5PezBWY0Pr9v5jT08Fj7Fr9AKwk7uM1kKIftrvxo7e4po0ZJq6E8ejZr2wYCcXL0DN4Pc3Sn8PG+1yaCt5Tja6perbdj1i/afHiiSH11SH9oTlJ0bkjANAvk1jgXze48I2LAAmRXJuf6DDBMpHJGTvNFM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487705; c=relaxed/simple; bh=D4arnahyLmJAIHJHfDhZWuzeJdCp9jV6WpCtczzfao0=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=pzj95DBqf7Sf31mP9gTSFu6wwjn9+UUJ9bcAPB4cV/BBz1Xw7qL41bXLm4O+nZEzVy5Gox9z3rwVlOToyRjBpfSQ1uMC9FT3nAA20mbsuEK3qJKMbu+rjnKSFDyTcPTnHizINex1MTvM0Q/wO3xXh5F/S/w8kYlDzTJehuws5cQ= 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=Bc/7yPQO; arc=none smtp.client-ip=209.85.208.176 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="Bc/7yPQO" Received: by mail-lj1-f176.google.com with SMTP id 38308e7fff4ca-2e78fe9fc2bso73372711fa.3; Tue, 04 Jun 2024 00:55:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487701; x=1718092501; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=0r09qv4wIa3xu1xRZZhQsHot4rUmDPUzLz78jo/Xvwo=; b=Bc/7yPQO9vRlpOWz61zjSz3KUis5RxJAtL20O1Il5llrQsfK5lPtUFVNtlMA14qTYr yVrC9kdFjGPJYRYQrj+bgoP0OvZypBwQ0A3MUEOQ9vvFv3W7JVbMhvc8FTlqJnn6DPyh Ubt2wxHHdXOlkU1jFFp9OR9MBqMtAmBAfj68g1Fs1ml91a+atSKAO9OXubbvYAVcser5 NjMxxELSPa/e8wJoSSShBG9VF9wvpAR2NsfzIa5yBJ+0ItS9Y3uFYu6FHNKg2vaXlo5X ThxZjU9hcCEH3XqO37J1aghO5Zs518l/WZkLs43/BV5SqEgcAta3M+NVlYlDuGmOF8nG u5NA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487701; x=1718092501; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=0r09qv4wIa3xu1xRZZhQsHot4rUmDPUzLz78jo/Xvwo=; b=CWBtZKnH6fHFlIhUU+z31Ik7HURi+DHHUfzoZ/3YDGPXRMW779o6/GX+R+XCNsqPx2 Cz2HQ8CrY3UzOnMYQLiNgJnX088F2hLi9t/V6tBeDv3mSNgfKTx49MoPToRNZOeKxWc/ rIVUUOex0U8woaV0kmFNCpFTVERBAZTVyaHfZkpEeRfn+fFeP8sxrfguthWLm+HvIiRf woGAyXKZqkjTlwYic+bPyEk9yPkQKOqLBCrOlZQdCfIIJu16LcU8Brivq+GCWoIXI/RZ +lxS8lHsRRYZWEsj3ZOPhaQiNLV5d+PCbdJu2vOEw4dA/YSotBwX2kgbRh1EmJEeEwgn vTZA== X-Forwarded-Encrypted: i=1; AJvYcCV8ZVTSUr8x1YuBY9DaC9kmdT3LLWZFgqhs24JMxXYP1435+cFBZf6kk95gpYBw8u0JyR/+LijxOpzUlMb5NnIGyqEv6wB/4c1rkj/UrSouLe9wvD5uT0CFua+i9AgKFldfk3jOy2CXPfXnuYRW9VV7+vGdl5Br8XP36mtIS1Rmf/+UntMrWLAE X-Gm-Message-State: AOJu0YzTXJOg9byvhA5j5qA3UTZQJC8SZrCZW4aKNNyziFwNCH7grOHy IwEjnCqKIb4ynI7oVLW0psnz27BWBNNz+1fTG/uDXqm/335LFp5L X-Google-Smtp-Source: AGHT+IFGNYfNqCGqRnYKjF+TevV/35s6cwfeq2Jx1Vqz+UlvCkF0+nFw7IGemT8V4tz7jGnGu5aBIQ== X-Received: by 2002:a2e:9c8c:0:b0:2d3:4b73:7b40 with SMTP id 38308e7fff4ca-2ea9512afd3mr66531551fa.17.1717487700852; Tue, 04 Jun 2024 00:55:00 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2ea91b9d5f0sm14323751fa.21.2024.06.04.00.54.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:54:59 -0700 (PDT) Date: Tue, 4 Jun 2024 10:54:55 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 05/10] watchdog: ROHM BD96801 PMIC WDG driver Message-ID: <617d2d779fe96a54dde4e178ce3045dfd48d747b.1717486682.git.mazziesaccount@gmail.com> References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Introduce driver for WDG block on ROHM BD96801 scalable PMIC. This driver only supports watchdog with I2C feeding and delayed response detection. Whether the watchdog toggles PRSTB pin or just causes an interrupt can be configured via device-tree. The BD96801 PMIC HW supports also window watchdog (too early feeding detection) and Q&A mode. These are not supported by this driver. Signed-off-by: Matti Vaittinen --- Revision history: v2 =>: - No changes v1 => v2: - Drop the forward declaration for emergency_reboot() - Typofixes - Do error checks before assignments in find_closest_fast() - Improve prints for unsupported (HW) timeout values - Use FIELD_GET() and FIELD_PREP() - Use error severity when unsupported Q&A WDG mode is tried to be used. - Minor styling fixes RFCv2 => v1: - Fix watchdog time-outs to match DS4 - Fix target timeout overflow - Improve dbg prints RFCv1 => RFCv2: - remove always running - add IRQ handling - call emergency_restart() - drop MODULE_ALIAS and add MODULE_DEVICE_TABLE watchdog: bd96801: styling fix --- drivers/watchdog/Kconfig | 13 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/bd96801_wdt.c | 416 +++++++++++++++++++++++++++++++++ 3 files changed, 430 insertions(+) create mode 100644 drivers/watchdog/bd96801_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 85eea38dbdf4..ceb3431f23b8 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -181,6 +181,19 @@ config BD957XMUF_WATCHDOG watchdog. Alternatively say M to compile the driver as a module, which will be called bd9576_wdt. +config BD96801_WATCHDOG + tristate "ROHM BD96801 PMIC Watchdog" + depends on MFD_ROHM_BD96801 + select WATCHDOG_CORE + help + Support for the watchdog in the ROHM BD96801 PMIC. Watchdog can be + configured to only generate IRQ or to trigger system reset via reset + pin. + + Say Y here to include support for the ROHM BD96801 watchdog. + Alternatively say M to compile the driver as a module, + which will be called bd96801_wdt. + config CROS_EC_WATCHDOG tristate "ChromeOS EC-based watchdog" select WATCHDOG_CORE diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 2d1117564f5b..b51030f035a6 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -218,6 +218,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o # Architecture Independent obj-$(CONFIG_BD957XMUF_WATCHDOG) += bd9576_wdt.o +obj-$(CONFIG_BD96801_WATCHDOG) += bd96801_wdt.o obj-$(CONFIG_CROS_EC_WATCHDOG) += cros_ec_wdt.o obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o diff --git a/drivers/watchdog/bd96801_wdt.c b/drivers/watchdog/bd96801_wdt.c new file mode 100644 index 000000000000..ff51f42ced2a --- /dev/null +++ b/drivers/watchdog/bd96801_wdt.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 ROHM Semiconductors + * + * ROHM BD96801 watchdog driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool nowayout; +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=\"false\")"); + +#define BD96801_WD_TMO_SHORT_MASK 0x70 +#define BD96801_WD_RATIO_MASK 0x3 +#define BD96801_WD_TYPE_MASK 0x4 +#define BD96801_WD_TYPE_SLOW 0x4 +#define BD96801_WD_TYPE_WIN 0x0 + +#define BD96801_WD_EN_MASK 0x3 +#define BD96801_WD_IF_EN 0x1 +#define BD96801_WD_QA_EN 0x2 +#define BD96801_WD_DISABLE 0x0 + +#define BD96801_WD_ASSERT_MASK 0x8 +#define BD96801_WD_ASSERT_RST 0x8 +#define BD96801_WD_ASSERT_IRQ 0x0 + +#define BD96801_WD_FEED_MASK 0x1 +#define BD96801_WD_FEED 0x1 + +/* 1.1 mS */ +#define FASTNG_MIN 11 +#define FASTNG_MAX_US (100 * FASTNG_MIN << 7) +#define SLOWNG_MAX_US (16 * FASTNG_MAX_US) + +#define BD96801_WDT_DEFAULT_MARGIN_MS 1843 +/* Unit is seconds */ +#define DEFAULT_TIMEOUT 30 + +/* + * BD96801 WDG supports window mode so the TMO consists of SHORT and LONG + * timeout values. SHORT time is meaningful only in window mode where feeding + * period shorter than SHORT would be an error. LONG time is used to detect if + * feeding is not occurring within given time limit (SoC SW hangs). The LONG + * timeout time is a multiple of (2, 4, 8 or 16 times) the SHORT timeout. + */ + +struct wdtbd96801 { + struct device *dev; + struct regmap *regmap; + struct watchdog_device wdt; +}; + +static int bd96801_wdt_ping(struct watchdog_device *wdt) +{ + struct wdtbd96801 *w = watchdog_get_drvdata(wdt); + + return regmap_update_bits(w->regmap, BD96801_REG_WD_FEED, + BD96801_WD_FEED_MASK, BD96801_WD_FEED); +} + +static int bd96801_wdt_start(struct watchdog_device *wdt) +{ + struct wdtbd96801 *w = watchdog_get_drvdata(wdt); + + return regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, + BD96801_WD_EN_MASK, BD96801_WD_IF_EN); +} + +static int bd96801_wdt_stop(struct watchdog_device *wdt) +{ + struct wdtbd96801 *w = watchdog_get_drvdata(wdt); + + return regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, + BD96801_WD_EN_MASK, BD96801_WD_DISABLE); +} + +static const struct watchdog_info bd96801_wdt_info = { + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | + WDIOF_SETTIMEOUT, + .identity = "BD96801 Watchdog", +}; + +static const struct watchdog_ops bd96801_wdt_ops = { + .start = bd96801_wdt_start, + .stop = bd96801_wdt_stop, + .ping = bd96801_wdt_ping, +}; + +static int find_closest_fast(unsigned int target, int *sel, unsigned int *val) +{ + unsigned int window = FASTNG_MIN; + int i; + + for (i = 0; i < 8 && window < target; i++) + window <<= 1; + + if (i == 8) + return -EINVAL; + + *val = window; + *sel = i; + + return 0; +} + +static int find_closest_slow_by_fast(unsigned int fast_val, unsigned int *target, + int *slowsel) +{ + static const int multipliers[] = {2, 4, 8, 16}; + int sel; + + for (sel = 0; sel < ARRAY_SIZE(multipliers) && + multipliers[sel] * fast_val < *target; sel++) + ; + + if (sel == ARRAY_SIZE(multipliers)) + return -EINVAL; + + *slowsel = sel; + *target = multipliers[sel] * fast_val; + + return 0; +} + +static int find_closest_slow(unsigned int *target, int *slow_sel, int *fast_sel) +{ + static const int multipliers[] = {2, 4, 8, 16}; + unsigned int window = FASTNG_MIN; + unsigned int val = 0; + int i, j; + + for (i = 0; i < 8; i++) { + for (j = 0; j < ARRAY_SIZE(multipliers); j++) { + unsigned int slow; + + slow = window * multipliers[j]; + if (slow >= *target && (!val || slow < val)) { + val = slow; + *fast_sel = i; + *slow_sel = j; + } + } + window <<= 1; + } + if (!val) + return -EINVAL; + + *target = val; + + return 0; +} + +static int bd96801_set_wdt_mode(struct wdtbd96801 *w, unsigned int hw_margin, + unsigned int hw_margin_min) +{ + int fastng, slowng, type, ret, reg, mask; + struct device *dev = w->dev; + + + if (hw_margin_min * 1000 > FASTNG_MAX_US) { + dev_err(dev, "Unsupported fast timeout %u uS [max %u]\n", + hw_margin_min * 1000, FASTNG_MAX_US); + + return -EINVAL; + } + + if (hw_margin * 1000 > SLOWNG_MAX_US) { + dev_err(dev, "Unsupported slow timeout %u uS [max %u]\n", + hw_margin * 1000, SLOWNG_MAX_US); + + return -EINVAL; + } + + /* + * Convert to 100uS to guarantee reasonable timeouts fit in + * 32bit maintaining also a decent accuracy. + */ + hw_margin *= 10; + hw_margin_min *= 10; + + if (hw_margin_min) { + unsigned int min; + + type = BD96801_WD_TYPE_WIN; + dev_dbg(dev, "Setting type WINDOW 0x%x\n", type); + ret = find_closest_fast(hw_margin_min, &fastng, &min); + if (ret) + return ret; + + ret = find_closest_slow_by_fast(min, &hw_margin, &slowng); + if (ret) { + dev_err(dev, + "can't support slow timeout %u uS using fast %u uS. [max slow %u uS]\n", + hw_margin * 100, min * 100, min * 100 * 16); + + return ret; + } + w->wdt.min_hw_heartbeat_ms = min / 10; + } else { + type = BD96801_WD_TYPE_SLOW; + dev_dbg(dev, "Setting type SLOW 0x%x\n", type); + ret = find_closest_slow(&hw_margin, &slowng, &fastng); + if (ret) + return ret; + } + + w->wdt.max_hw_heartbeat_ms = hw_margin / 10; + + fastng = FIELD_PREP(BD96801_WD_TMO_SHORT_MASK, fastng); + + reg = slowng | fastng; + mask = BD96801_WD_RATIO_MASK | BD96801_WD_TMO_SHORT_MASK; + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_TMO, + mask, reg); + if (ret) + return ret; + + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, + BD96801_WD_TYPE_MASK, type); + + return ret; +} + +static int bd96801_set_heartbeat_from_hw(struct wdtbd96801 *w, + unsigned int conf_reg) +{ + int ret; + unsigned int val, sel, fast; + + /* + * The BD96801 supports a somewhat peculiar QA-mode, which we do not + * support in this driver. If the QA-mode is enabled then we just + * warn and bail-out. + */ + if ((conf_reg & BD96801_WD_EN_MASK) != BD96801_WD_IF_EN) { + dev_err(w->dev, "watchdog set to Q&A mode - exiting\n"); + return -EINVAL; + } + + ret = regmap_read(w->regmap, BD96801_REG_WD_TMO, &val); + if (ret) + return ret; + + sel = FIELD_GET(BD96801_WD_TMO_SHORT_MASK, val); + fast = FASTNG_MIN << sel; + + sel = (val & BD96801_WD_RATIO_MASK) + 1; + w->wdt.max_hw_heartbeat_ms = (fast << sel) / USEC_PER_MSEC; + + if ((conf_reg & BD96801_WD_TYPE_MASK) == BD96801_WD_TYPE_WIN) + w->wdt.min_hw_heartbeat_ms = fast / USEC_PER_MSEC; + + return 0; +} + +static int init_wdg_hw(struct wdtbd96801 *w) +{ + u32 hw_margin[2]; + int count, ret; + u32 hw_margin_max = BD96801_WDT_DEFAULT_MARGIN_MS, hw_margin_min = 0; + + count = device_property_count_u32(w->dev->parent, "rohm,hw-timeout-ms"); + if (count < 0 && count != -EINVAL) + return count; + + if (count > 0) { + if (count > ARRAY_SIZE(hw_margin)) + return -EINVAL; + + ret = device_property_read_u32_array(w->dev->parent, + "rohm,hw-timeout-ms", + &hw_margin[0], count); + if (ret < 0) + return ret; + + if (count == 1) + hw_margin_max = hw_margin[0]; + + if (count == 2) { + if (hw_margin[1] > hw_margin[0]) { + hw_margin_max = hw_margin[1]; + hw_margin_min = hw_margin[0]; + } else { + hw_margin_max = hw_margin[0]; + hw_margin_min = hw_margin[1]; + } + } + } + + ret = bd96801_set_wdt_mode(w, hw_margin_max, hw_margin_min); + if (ret) + return ret; + + ret = device_property_match_string(w->dev->parent, "rohm,wdg-action", + "prstb"); + if (ret >= 0) { + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, + BD96801_WD_ASSERT_MASK, + BD96801_WD_ASSERT_RST); + return ret; + } + + ret = device_property_match_string(w->dev->parent, "rohm,wdg-action", + "intb-only"); + if (ret >= 0) { + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, + BD96801_WD_ASSERT_MASK, + BD96801_WD_ASSERT_IRQ); + return ret; + } + + return 0; +} + +static irqreturn_t bd96801_irq_hnd(int irq, void *data) +{ + emergency_restart(); + + return IRQ_NONE; +} + +static int bd96801_wdt_probe(struct platform_device *pdev) +{ + struct wdtbd96801 *w; + int ret, irq; + unsigned int val; + + w = devm_kzalloc(&pdev->dev, sizeof(*w), GFP_KERNEL); + if (!w) + return -ENOMEM; + + w->regmap = dev_get_regmap(pdev->dev.parent, NULL); + w->dev = &pdev->dev; + + w->wdt.info = &bd96801_wdt_info; + w->wdt.ops = &bd96801_wdt_ops; + w->wdt.parent = pdev->dev.parent; + w->wdt.timeout = DEFAULT_TIMEOUT; + watchdog_set_drvdata(&w->wdt, w); + + ret = regmap_read(w->regmap, BD96801_REG_WD_CONF, &val); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to get the watchdog state\n"); + + /* + * If the WDG is already enabled we assume it is configured by boot. + * In this case we just update the hw-timeout based on values set to + * the timeout / mode registers and leave the hardware configs + * untouched. + */ + if ((val & BD96801_WD_EN_MASK) != BD96801_WD_DISABLE) { + dev_dbg(&pdev->dev, "watchdog was running during probe\n"); + ret = bd96801_set_heartbeat_from_hw(w, val); + if (ret) + return ret; + + set_bit(WDOG_HW_RUNNING, &w->wdt.status); + } else { + /* If WDG is not running so we will initializate it */ + ret = init_wdg_hw(w); + if (ret) + return ret; + } + + dev_dbg(w->dev, "heartbeat set to %u - %u\n", + w->wdt.min_hw_heartbeat_ms, w->wdt.max_hw_heartbeat_ms); + + watchdog_init_timeout(&w->wdt, 0, pdev->dev.parent); + watchdog_set_nowayout(&w->wdt, nowayout); + watchdog_stop_on_reboot(&w->wdt); + + irq = platform_get_irq_byname(pdev, "bd96801-wdg"); + if (irq > 0) { + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + bd96801_irq_hnd, + IRQF_ONESHOT, "bd96801-wdg", + NULL); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to register IRQ\n"); + } + + return devm_watchdog_register_device(&pdev->dev, &w->wdt); +} + +static const struct platform_device_id bd96801_wdt_id[] = { + { "bd96801-wdt", }, + { } +}; +MODULE_DEVICE_TABLE(platform, bd96801_wdt_id); + +static struct platform_driver bd96801_wdt = { + .driver = { + .name = "bd96801-wdt" + }, + .probe = bd96801_wdt_probe, + .id_table = bd96801_wdt_id, +}; +module_platform_driver(bd96801_wdt); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("BD96801 watchdog driver"); +MODULE_LICENSE("GPL"); From patchwork Tue Jun 4 07:55:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684869 Received: from mail-lj1-f175.google.com (mail-lj1-f175.google.com [209.85.208.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 EA525140E22; Tue, 4 Jun 2024 07:55:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487725; cv=none; b=JXj6m/qwPdsdmEDODWcTb1PYi6dxv0YNCCEDHi4jqdwFLYl0fG2hzCXg6Z1hf/zTmn/bNrzrXAjzJ7MvzxYwKFj4ukg5cdxLc5fiB9YcBOu/v3SHaJEdvmLQrctV45uztdjzO+ArFCRd2T2HZEba7yFc9TUsLulpbGKU9YaDHEg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487725; c=relaxed/simple; bh=cKCy+oWY0h+rEhutkL8EOrTmWwMttRhbA0ARRfYezbc=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=TvaP2iq0prjNywKAyD0yYxfQH82KzAqK1i+ISv0mP+uSlGlyO42A12wvjJvQdqez4Z40KsBE4/CVGtyznTSdIqj+yHYZeAD4f4u93X2hj1hiOsCCm5M8uMXuNnpibt+TAUIJOxmBWVHJ9G7oW+xR5U4Yfj3fB2PynCrCiab+gJA= 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=ib3GDr+u; arc=none smtp.client-ip=209.85.208.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="ib3GDr+u" Received: by mail-lj1-f175.google.com with SMTP id 38308e7fff4ca-2eaa80cb550so10316671fa.0; Tue, 04 Jun 2024 00:55:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487722; x=1718092522; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=CR7EzWSYNbnwc1q6qNQZ5dkYY+ZH0oWfFYQmDXHB9Nk=; b=ib3GDr+udSt9kJ1TxG/nD38LlvSnsHPIZ/Q/4WwgWFb0Ki2LVphYgmdLVBbwqE1JMo TQdS8o6kiokuURjef1WENUogsdc2k7f42ZHsSSTcLM8RHxGr8csP4uRG+OajnYVPYaB7 hgXwB2yck9FRM+HWUoVXy6MObTF80kA6bBT+ILwEIl5wrBLwioYOlIqAoY85/6VovnYO nZfY1IK1lJYUZNT88m6FCDVOTn7W0mmeTtcaP0m54TwoD8JQqRs7FipND7maSMRBF2Dl gSuEkvT7neQnyVZLvCXyMVqDf/DNZsMVtRdYwF18FU2nHONi+RXgG3SqU87fbYmLcKdQ xc1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487722; x=1718092522; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=CR7EzWSYNbnwc1q6qNQZ5dkYY+ZH0oWfFYQmDXHB9Nk=; b=IinwX+adPs3+izUBjbHnMu3cbFfYCXzUZBHZYIBy3bvUHv+XGD3VYyY4g4DhFakLSt 5D7E6D1IyYuzvNvZEOFGTqg/TTbTs3yABR/oRhqHUcJ/bwsxAGsZTBKSosdppKcHC6ty wA5n7fpGU/hMpldcPTsR8sBxqsvCYSNs7NYyBz3M5yU0Jkq+Z6MXQvraTF0KfT6Sr2fn FaQFe3deC2E4mns6t2dXkZx6iuX5avjsQh7c57Gf2XOls0mBZqvuLm72bC1WqN0Hsh24 0Oo66vd7AtnjsdfpTnluXOjacbfMv2/WQYPMPvBwCOvyKzKOZCZD/YLzQWeujL8LvOmN JDtw== X-Forwarded-Encrypted: i=1; AJvYcCUIOT15OBh5BggQkvCYDJroe1O+Zw62nf51U9DMTChbkRWDy4q5X/b1TIXGcPxSdQ0Lmt/0D9aWVmbg06TuMjdWMdld/QsbaDHmEynZNAzPx280oRtK3iUr0idjt11XKmmgmxmiXrqf3Ss3Gq7WvXRMzMopEgjYNXbtWPhqOhQH8pa6UNLGT9d4 X-Gm-Message-State: AOJu0YytU8bJT1TkFa78S5Tx4JbZDAw3CdfQQAsHLSLupjlii9XuKWyM vyM2a7K2o+dQS9iwKLAMmWMs1+jyD7JXY727q7xxI7VFj3rn7BYI X-Google-Smtp-Source: AGHT+IHVcMx40582ZYla5OZeU2SaNMPt9n+2IEdqzPVpHQhbhFjwH0omKiQr5jntvCj2DJCoZSMfFg== X-Received: by 2002:a2e:870d:0:b0:2de:73b5:427c with SMTP id 38308e7fff4ca-2ea950b5396mr69437171fa.9.1717487721731; Tue, 04 Jun 2024 00:55:21 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2ea91cefc42sm14394611fa.117.2024.06.04.00.55.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:55:20 -0700 (PDT) Date: Tue, 4 Jun 2024 10:55:16 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 06/10] MAINTAINERS: Add ROHM BD96801 'scalable PMIC' entries Message-ID: <951c2f61a781f259f21ac307a4a411dc9b1453e5.1717486682.git.mazziesaccount@gmail.com> References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Add maintainer entries for ROHM BD96801 a.k.a 'scalable PMIC' drivers to be reviewed by ROHM people. Signed-off-by: Matti Vaittinen --- Revision history: RFC1 =>: - No changes --- MAINTAINERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d6c90161c7bf..dc79a45c763e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19446,17 +19446,21 @@ F: drivers/gpio/gpio-bd71828.c F: drivers/mfd/rohm-bd71828.c F: drivers/mfd/rohm-bd718x7.c F: drivers/mfd/rohm-bd9576.c +F: drivers/mfd/rohm-bd96801.c F: drivers/regulator/bd71815-regulator.c F: drivers/regulator/bd71828-regulator.c F: drivers/regulator/bd718x7-regulator.c F: drivers/regulator/bd9576-regulator.c +F: drivers/regulator/bd96801-regulator.c F: drivers/regulator/rohm-regulator.c F: drivers/rtc/rtc-bd70528.c F: drivers/watchdog/bd9576_wdt.c +F: drivers/watchdog/bd96801_wdt.c F: include/linux/mfd/rohm-bd71815.h F: include/linux/mfd/rohm-bd71828.h F: include/linux/mfd/rohm-bd718x7.h F: include/linux/mfd/rohm-bd957x.h +F: include/linux/mfd/rohm-bd96801.h F: include/linux/mfd/rohm-generic.h F: include/linux/mfd/rohm-shared.h From patchwork Tue Jun 4 07:55:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684870 Received: from mail-lf1-f49.google.com (mail-lf1-f49.google.com [209.85.167.49]) (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 52CEE1419A0; Tue, 4 Jun 2024 07:55:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487754; cv=none; b=lueVmT8TBtMrax/YI0KAK0aqoy7uxLWiSQIFpTa40yyBqrZ04KPXLRwzNs2SgF1zWMBES5BesFMtE/9pRLEGl2RlnZwsghS5xfViwndWxfTm3aJ8nQYSJaBclBwGB96S3z1/K4M6R3xWhdEH/rRSxh1ikoh/yNKJulWVRrVIpX0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487754; c=relaxed/simple; bh=C5o5SBN8uXgKhyh/zkbsNvoU/ikohgWwgjdQR5iPB4o=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=ERH3KYtdbaM1FVJh5ALnQB7fqzA2UP639lIYAPIZPyb20zCFT9pCJVEYvnw3O66wF1TPFeYy4wu/rUibuHR4dyRfTJnzx0GH/2jdqiXMF9dvAdEYJ+z2HXSKTu3AYojLfbfSgePHWTefNEf6W27QaB9uMrlePEFn0q6FDtO5Cjk= 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=LcsYFcLq; arc=none smtp.client-ip=209.85.167.49 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="LcsYFcLq" Received: by mail-lf1-f49.google.com with SMTP id 2adb3069b0e04-52b962c4bb6so3333822e87.3; Tue, 04 Jun 2024 00:55:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487750; x=1718092550; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=4JduBG3L5CKqrZRQ+K3JTNgyGjUZ6PHYmMbEbdzsGj8=; b=LcsYFcLqAJZMdOuHNcWIPT/INUdBD0oh1rvl9JqpTiofq50iTRsa/Pe6QoC2m8Cfzn gGPOso6sxhfdU/LSY3hzyPwi9Q4H0WsaXxnG4yzud0S1FrgkI38zQQjli394gw2aYoaJ 0QZ3RglvM9lA535/N42S9zKAwzT3fOWwQoyz78xjgyyQ7jbqUSqtZGGwRaJHnpt9kLFJ cc6HDySPD0VoBfx6XArVLGocd1+8FbRVXYdSjKkLM0b5gFQ9tMciOoqMUXfS1OgeONq4 pVdEdr/hqX5xzfWZmCl0aaHkpVm7ET943yR/wxeIAdp5hOGsJzgyszInPEcYiJR/xSse stlg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487750; x=1718092550; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=4JduBG3L5CKqrZRQ+K3JTNgyGjUZ6PHYmMbEbdzsGj8=; b=gLgQQ9vx5UKkI/Ozj1CoYpO72LWATThcFuK+d9YVFRIGRk5jVAbZ1h5RF63I9EyDJ4 xDTRXfc9Hl/mOluZ9uEaMgcA1R0plv1c1F/cscIwgyOHDtRrWpDB7PNLBQGzuq9wz4DO XWg5ZtesC7rcQbgmBTkd11bG2KNzdMU007tb3qNQj90UmnBxFS31Uze4/61qPETiP1ny VAtJX4d0t+52avK2gxUkI/wyWKN4Na3V0r1Xd5wyG0KG/OCyOeE/rR8bm6D88xy8cOZb oMZFQC6LyKGM105vq7S+1Hw11vVxEez6NvH/p2uknlVNXqB/C6DM8lbXSH2z+SRF2HtA zobw== X-Forwarded-Encrypted: i=1; AJvYcCUjlRis7xOM99ZY+/IJ/0/p9Y1+cv4t0NkOtZ6BrV7ylswczxIz5jtB6Ehw3Rr1rsaOHlaO+lkkv/4LP8qxBPyeaYdzjJoiPanlZFtD1FLNB8yFqBzrB4jftAY8SJCA1VytVPUTn9+Mn6FbCItXjwrE5XqZRAn17SZnRlYuD/bkbnqFT275KzqA X-Gm-Message-State: AOJu0Yzq52P5t+FaWRapZdHSiJmYyhfFaR7jOTT+u3+nBlr0HfH2jxpE kTGoXdCptP0GMvbenFAlE4keZsiKZm/bbnHtWct4q4RpirnctN7z X-Google-Smtp-Source: AGHT+IEv0NwZnn8rdvjSaxjfYlbFRiLMXClL8ErhUqzyDiMvoCACa459pZ0gciIz4YrrnUlSeDvp2A== X-Received: by 2002:a05:6512:2391:b0:52b:8aa1:bdca with SMTP id 2adb3069b0e04-52b8aa1be8emr11296775e87.49.1717487750229; Tue, 04 Jun 2024 00:55:50 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52b97984553sm689274e87.19.2024.06.04.00.55.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:55:49 -0700 (PDT) Date: Tue, 4 Jun 2024 10:55:45 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 07/10] irqdomain: Allow giving name suffix for domain Message-ID: References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Devices can provide multiple interrupt lines. One reason for this is that a device has multiple subfunctions, each providing its own interrupt line. Another reason is that a device can be designed to be used (also) on a system where some of the interrupts can be routed to another processor. A line often further acts as a demultiplex for specific interrupts and has it's respective set of interrupt (status, mask, ack, ...) registers. Regmap supports the handling of these registers and demultiplexing interrupts, but interrupt domain code ends up assigning the same name for the per interrupt line domains. This will cause a naming collision in the debugFS code and can also lead to confusion, as /proc/interrupts would show two separate interrupts with the same domain name and hardware interrupt number. Instead of adding a workaround in regmap or driver code, allow giving a name suffix for the domain name when the domain is created. Add support for name suffix in __irq_domain_add() and allow using it via new irq_domain_create_linear_named() function. This is the only function required by the regmap code to support such setups because no new drivers are expected to be using legacy domains. Signed-off-by: Matti Vaittinen --- Revision history: v2 => v3: - Improve the commit message - Drop the new name-suffix API for legacy domains Some devices which could use this are ROHM's BD96801, BD96802 and BD96811 PMICs. BD96801 is being upstreamed, others are on my TODO list - but I believe this may be beneficial to any other devices as well. Especially for those which provide IRQs that are clearly different from each other. Some discussion about this can be found from: https://lore.kernel.org/all/Zjzt8mOW6dO_7XNV@finisterre.sirena.org.uk/ --- include/linux/irqdomain.h | 22 ++++++++++++++++------ kernel/irq/irqdomain.c | 37 +++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 21ecf582a0fe..0d829495bf9e 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -260,7 +260,7 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode); struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size, irq_hw_number_t hwirq_max, int direct_max, const struct irq_domain_ops *ops, - void *host_data); + void *host_data, const char *name_suffix); struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode, unsigned int size, unsigned int first_irq, @@ -350,7 +350,8 @@ static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_no const struct irq_domain_ops *ops, void *host_data) { - return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data); + return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, + host_data, NULL); } #ifdef CONFIG_IRQ_DOMAIN_NOMAP @@ -359,7 +360,8 @@ static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_nod const struct irq_domain_ops *ops, void *host_data) { - return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data); + return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, + ops, host_data, NULL); } extern unsigned int irq_create_direct_mapping(struct irq_domain *host); @@ -369,7 +371,7 @@ static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node const struct irq_domain_ops *ops, void *host_data) { - return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data); + return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data, NULL); } static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode, @@ -377,14 +379,22 @@ static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle * const struct irq_domain_ops *ops, void *host_data) { - return __irq_domain_add(fwnode, size, size, 0, ops, host_data); + return __irq_domain_add(fwnode, size, size, 0, ops, host_data, NULL); +} + +static inline struct irq_domain *irq_domain_create_linear_named(struct fwnode_handle *fwnode, + unsigned int size, + const struct irq_domain_ops *ops, + void *host_data, const char *name_suffix) +{ + return __irq_domain_add(fwnode, size, size, 0, ops, host_data, name_suffix); } static inline struct irq_domain *irq_domain_create_tree(struct fwnode_handle *fwnode, const struct irq_domain_ops *ops, void *host_data) { - return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data); + return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data, NULL); } extern void irq_domain_remove(struct irq_domain *host); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index aadc8891cc16..c2a565aeada8 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -132,7 +132,8 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode, irq_hw_number_t hwirq_max, int direct_max, const struct irq_domain_ops *ops, - void *host_data) + void *host_data, + const char *name_suffix) { struct irqchip_fwid *fwid; struct irq_domain *domain; @@ -150,6 +151,17 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode, return NULL; if (is_fwnode_irqchip(fwnode)) { + /* + * The name_suffix is only intended to be used to avoid a name + * collison, when multiple domains are created for a single + * device and the name is picked using a real device node. + * (Typical use-case is regmap-IRQ controllers for devices + * providing more than one physical IRQ.) There should be no + * need to use name_suffix with irqchip-fwnode. + */ + if (name_suffix) + return NULL; + fwid = container_of(fwnode, struct irqchip_fwid, fwnode); switch (fwid->type) { @@ -177,7 +189,11 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode, * unhappy about. Replace them with ':', which does * the trick and is not as offensive as '\'... */ - name = kasprintf(GFP_KERNEL, "%pfw", fwnode); + if (!name_suffix) + name = kasprintf(GFP_KERNEL, "%pfw", fwnode); + else + name = kasprintf(GFP_KERNEL, "%pfw-%s", fwnode, + name_suffix); if (!name) { kfree(domain); return NULL; @@ -249,6 +265,8 @@ static void __irq_domain_publish(struct irq_domain *domain) * direct mapping * @ops: domain callbacks * @host_data: Controller private data pointer + * @name_suffix: Optional name suffix to avoid collisions when multiple domains + * are added using same fwnode * * Allocates and initializes an irq_domain structure. * Returns pointer to IRQ domain, or NULL on failure. @@ -256,12 +274,12 @@ static void __irq_domain_publish(struct irq_domain *domain) struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size, irq_hw_number_t hwirq_max, int direct_max, const struct irq_domain_ops *ops, - void *host_data) + void *host_data, const char *name_suffix) { struct irq_domain *domain; domain = __irq_domain_create(fwnode, size, hwirq_max, direct_max, - ops, host_data); + ops, host_data, name_suffix); if (domain) __irq_domain_publish(domain); @@ -362,7 +380,7 @@ struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode, { struct irq_domain *domain; - domain = __irq_domain_add(fwnode, size, size, 0, ops, host_data); + domain = __irq_domain_add(fwnode, size, size, 0, ops, host_data, NULL); if (!domain) return NULL; @@ -418,7 +436,8 @@ struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode, { struct irq_domain *domain; - domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size, 0, ops, host_data); + domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size, + 0, ops, host_data, NULL); if (domain) irq_domain_associate_many(domain, first_irq, first_hwirq, size); @@ -1147,9 +1166,11 @@ struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent, struct irq_domain *domain; if (size) - domain = __irq_domain_create(fwnode, size, size, 0, ops, host_data); + domain = __irq_domain_create(fwnode, size, size, 0, ops, + host_data, NULL); else - domain = __irq_domain_create(fwnode, 0, ~0, 0, ops, host_data); + domain = __irq_domain_create(fwnode, 0, ~0, 0, ops, host_data, + NULL); if (domain) { if (parent) From patchwork Tue Jun 4 07:56:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684877 Received: from mail-lj1-f174.google.com (mail-lj1-f174.google.com [209.85.208.174]) (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 BC3B4143880; Tue, 4 Jun 2024 07:56:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487771; cv=none; b=Nq92dIK3wGM4JepbfDK1OVAoP5yCIaL57M2j1/XcoCf0wPdJuYpevgMJSPAg2k9bUopGURo7VCKaMgFhXyfVkB0ZKwtlKlWKHdKQSFHiaE/hSROZYJPMbBlnAOo1y7mnjvRylYom+EfwyGRyfPAPkcufx0z8/nARKgDpDwPtNfw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487771; c=relaxed/simple; bh=Th2X0P0NR+EYfy5Fht2yUCRMhtyLvZfQvaqQZUcH8hU=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=KcJ6mHwKsHHEJbOwfFE7wE0NxKoC1KnpMqqle/CqHlaQQHJy7Ck7t7SlvklWG9g3vewrcBAOFVo8STfwMwCw0qF/0LQkAPig6q5bywTHhTBFyoSKZLCnDSH9ATBNDhtMcc7tjtj79NLGOwekVrq1Dq/KB85kkSw/6nB6zHqiA+g= 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=hZVKQr3E; arc=none smtp.client-ip=209.85.208.174 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="hZVKQr3E" Received: by mail-lj1-f174.google.com with SMTP id 38308e7fff4ca-2eaa80cb573so37038751fa.1; Tue, 04 Jun 2024 00:56:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487768; x=1718092568; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=/osOaeGzL7NBtD1GUS86QPUM+BgjTKgchC2AVQ2xiQM=; b=hZVKQr3EdJEtzrm5qLr+F/R1G4p4ENvQ5vAkmbmNgLXQkXOhDf8phNbZ1ZYBdKCDi7 IByyIADosbKfjPMpT0r2stJXbNrbqz1axlfwnG5hJJJD5GMCsL2cdAlqbRvBkqL2sPy/ zhJdVf/oazhqDqaorWyb6P0BImzlrRpm5Li4fdiRxz3XS3DCeYCPL9b4PJ12mGCGno9/ Ay0N+l0Ej87+yq6Q4OxLXwjnq2H6QkNUVzO1L04Ijqv1eXn51qehNSnVRiRMYUNhedfD L/ApZfbFv+6zTho0yBIT18uTUI+2Kh8IZvYbBgSS50vVcEYQ12Z6TjOzW9qk2B06DseO u5Pw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487768; x=1718092568; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=/osOaeGzL7NBtD1GUS86QPUM+BgjTKgchC2AVQ2xiQM=; b=pshD/sMeLtiiQkTqZlP5At1H/dHYtaGiraeTAJunZYCF9mdLtWTI3YRZSSBpO/INei WUo96k6kLd2Dnltb9EoE4JLB+lzGPx1tEZJRfsWF+t0jCc9588umws6yfb/LIX6E5Qp/ 6wn2kJgEN1qN/GSBOdsYABL4pXygrDjyKzkDIoRtJgNWINZPWjKQNZeKo0sC+np59C9N HYtEP/SG57VCV53JFMwsv4ZqYOAdICMGCguxQUHXoP7UIj/1kGDCF/b5VJZPy7zVNfgm Fzq8psTCjBf2Wy8miohQBH14MwiuBlJIifADRrZagdUTI7qSkdufo8oOH/AcGsj/6NEl k2ig== X-Forwarded-Encrypted: i=1; AJvYcCWUijz7rMCQPzQtQ6fBOP9FhYMQ4To3QHGt/nCiAP1RLU8nUt5bkf06597mUynYc1F+lm+YiPpgitMRpQXp6Zl6OSCefdl3nXMFORcXEMYk24RkMpMKxSsMx69SS1mgwRkarAdedLbopue4tcvmAbS7KIIsjDXs7M4y9iJMlDvzLacl78eINOoo X-Gm-Message-State: AOJu0YzRqh+moOaX9yHtPwib1ZyCPomd0nO4O1GZdwtT6OLZlbvL2CyL Wer5EXbaigoGBngFgFIztmzarc+R4w7+Z2pZ59gpx4o+e6fJ5DsyOq7aqg== X-Google-Smtp-Source: AGHT+IHUShnGdSs9YZ4e0VIuGjqGVsSLb7X17+DQ/K7Ple5rFiNH+vzrjNFHS83dE0xPwsx/lG3rNA== X-Received: by 2002:a2e:838a:0:b0:2d9:eb66:6d39 with SMTP id 38308e7fff4ca-2ea950f66e8mr77375821fa.19.1717487767746; Tue, 04 Jun 2024 00:56:07 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2eaac556d6fsm7040091fa.87.2024.06.04.00.56.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:56:06 -0700 (PDT) Date: Tue, 4 Jun 2024 10:56:01 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 08/10] regmap: Allow setting IRQ domain name suffix Message-ID: References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: When multiple IRQ domains are created from the same device-tree node they will get the same name based on the device-tree path. This will cause a naming collision in debugFS when IRQ domain specific entries are created. The regmap-IRQ creates per instance IRQ domains. This will lead to a domain name conflict when a device which provides more than one interrupt line uses the regmap-IRQ. Add support for specifying an IRQ domain name suffix when creating a regmap-IRQ controller. The regmap-IRQ supports both the legacy IRQ domains and the linear IRQ domains. New devices are not expected to be using the legacy domains so support name suffixes only for linear domains and warn if suffix is tried to be added for a legacy domain. Signed-off-by: Matti Vaittinen --- Revision history: v2 => v3: - Drop name suffix support for the legacy domains --- drivers/base/regmap/regmap-irq.c | 15 +++++++++++---- include/linux/regmap.h | 4 ++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 45fd13ef13fc..79247202aa9d 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -856,13 +856,20 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, } } - if (irq_base) + if (irq_base) { + if (chip->domain_suffix) + dev_warn(map->dev, + "Can't add name suffix for legacy domain\n"); + d->domain = irq_domain_create_legacy(fwnode, chip->num_irqs, irq_base, 0, ®map_domain_ops, d); - else - d->domain = irq_domain_create_linear(fwnode, chip->num_irqs, - ®map_domain_ops, d); + } else { + d->domain = irq_domain_create_linear_named(fwnode, + chip->num_irqs, ®map_domain_ops, + d, chip->domain_suffix); + } + if (!d->domain) { dev_err(map->dev, "Failed to create IRQ domain\n"); ret = -ENOMEM; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index a6bc2980a98b..b0b6cd3afefa 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -1519,6 +1519,9 @@ struct regmap_irq_chip_data; * struct regmap_irq_chip - Description of a generic regmap irq_chip. * * @name: Descriptive name for IRQ controller. + * @domain_suffix: Name suffix to be appended to end of IRQ domain name. Needed + * when multiple regmap-IRQ controllers are created from same + * device. * * @main_status: Base main status register address. For chips which have * interrupts arranged in separate sub-irq blocks with own IRQ @@ -1604,6 +1607,7 @@ struct regmap_irq_chip_data; */ struct regmap_irq_chip { const char *name; + const char *domain_suffix; unsigned int main_status; unsigned int num_main_status_bits; From patchwork Tue Jun 4 07:56:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684878 Received: from mail-lj1-f179.google.com (mail-lj1-f179.google.com [209.85.208.179]) (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 B4FEC142640; Tue, 4 Jun 2024 07:56:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487791; cv=none; b=IGCsrddrhvChjQBhysL9EpLlrJm1jxjCQQwaD8O9RBVaFSz2aOL9VslHrGhpHOAbZXJm+3G1waOV61vSgxFpJo7Lc+8CQENN7vrzVV4UTjO8GseAwAfzpJZ28/FVRMmURZT9G9jElWDybs3J4msU4PVMYN8WpTlzeR4SdyuciK4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487791; c=relaxed/simple; bh=feaIqaihD8R/vxH6jQ9TH/pIyCnGS+fT5q8C0Cpwa8M=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=jDCyUcsxmSrqni4VyaYP1MI3trgK9PqZzEKAXjQ0fIjQFQ39BUq93PzXnEq43MLuiIMx/lRfGgWNbWoOcqyXWCDbvaIod+fki6+K7mMbIMrqyQYtSRN9nTj3mOYxYptsURI6V1TrbfikTuRd1zhGefI0mZTBrRiTcW9nartTHi8= 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=JgZ94qm2; arc=none smtp.client-ip=209.85.208.179 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="JgZ94qm2" Received: by mail-lj1-f179.google.com with SMTP id 38308e7fff4ca-2e6f2534e41so45597831fa.0; Tue, 04 Jun 2024 00:56:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487787; x=1718092587; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=MVbdsvtFL9jT3Uzv4EwBY07SpsdfsNJUaB3GkizM14Q=; b=JgZ94qm2akNIt8bHRF96fNQsKmVatGEq3fVdTJmQU2rbhz3C7UCsITdr2ISQKFuonF F9iGCHChzVHVN4+9MLHR1GR1E60xWTRKzwfjt5wZoA/zK/i0/AP6VElt+YRLMrOcLq2+ 3i4u2Mt3M2Lp2FHTg5o4Ooiq7cqMEZkVTZSAqFa+Lhsmdut+wfsbkCS4hrPEKa1qeCvt DHBw1/I0T5Ws9pBdqS6lKHQrkhhBloNjNpLRbSVq3FXOTvUpAhh6b8dM+txcUpkna6pW mGTO3dlRzDCJmzIwP+cYkwmWIhQpem2/hrO3DcV3MdGu/6uIKywHWziQIWaljIyN3tjR p+/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487787; x=1718092587; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=MVbdsvtFL9jT3Uzv4EwBY07SpsdfsNJUaB3GkizM14Q=; b=vc5QZ5dp5Q+EAuiD2EgXc1vHFVPcRReKPgC9BZvcZfUxHrefRj09ud7MyyHDzEAyXQ 33uu0eOFhuZoS+2qZ66j5CORH8tini0oUKJSTqUISXXHV5qW1LY01svThbIVE9AtrT6F BihsVR8+DnU39pIODlJ/Y9td4SrgVcqFaZcCT9mi8u/1PBjOQ3RF/KdrV2Dv3NrbTAOJ G21vz355ShyZzSchfVRKbrJPAKx2LkoQhSOl73GjbMfu/6UKqaSdKjFHkYfQ0j7/BBee C3B8U7OH0WljV7Vkg+EOlSSMQrBdWT5jt78FmcfejMGVPR7z0CXRn1yLV5bzpBbW/Z/q e6Dg== X-Forwarded-Encrypted: i=1; AJvYcCU+0wYzs5o/HrV8s9q4ZmPDiD72vFLisKCksTUxjreHhHzfzBeI13lIVAD6eCcwuTBTocX5xOx1EXTW8vuwvMaDJdKDa71v1ftZx5ZpcN2YHQd2S445JzCBQuyHMcNNWDVCqB9KPkagju15jpMiYzX5X5tpagX4aMP9wWFlDycIOMmVaOgAPSPS X-Gm-Message-State: AOJu0Yz54qqz/Lymu3rSmzsieaAfw1T0spdM2g1NJKg89/o3OucUAoWE Eji2+vchbkGxpb/hqYdHXM3EAv2tFuwOFYLM+kKDYWeh+yQYzeV+ X-Google-Smtp-Source: AGHT+IEvirsyZDE5UR7D1dOsXlq1UmLrRlTdaFYQrrBOaphZLiEAleo7GsSRId1DkzBkn4hejIJeVA== X-Received: by 2002:a2e:7c12:0:b0:2ea:804a:18b2 with SMTP id 38308e7fff4ca-2ea951ac739mr69679711fa.35.1717487786554; Tue, 04 Jun 2024 00:56:26 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2ea91b9d65fsm14881601fa.27.2024.06.04.00.56.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:56:25 -0700 (PDT) Date: Tue, 4 Jun 2024 10:56:20 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 09/10] mfd: bd96801: Add ERRB IRQ Message-ID: <332a2d2429e2ba3c96afd28c1ccc18efc38e1fd3.1717486682.git.mazziesaccount@gmail.com> References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The ROHM BD96801 "scalable PMIC" provides two physical IRQs. The ERRB handling can in many cases be omitted because it is used to inform fatal IRQs, which usually kill the power from the SOC. There may however be use-cases where the SOC has a 'back-up' emergency power source which allows some very short time of operation to try to gracefully shut down sensitive hardware. Furthermore, it is possible the processor controlling the PMIC is not powered by the PMIC. In such cases handling the ERRB IRQs may be beneficial. Add support for ERRB IRQs. Signed-off-by: Matti Vaittinen --- Revision history: v2 =>: - No changes v1 => v2: - New patch --- drivers/mfd/rohm-bd96801.c | 291 ++++++++++++++++++++++++++++++++----- 1 file changed, 253 insertions(+), 38 deletions(-) diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c index 1c2a9591be7b..b7f073318873 100644 --- a/drivers/mfd/rohm-bd96801.c +++ b/drivers/mfd/rohm-bd96801.c @@ -5,13 +5,9 @@ * ROHM BD96801 PMIC driver * * This version of the "BD86801 scalable PMIC"'s driver supports only very - * basic set of the PMIC features. Most notably, there is no support for - * the ERRB interrupt and the configurations which should be done when the - * PMIC is in STBY mode. - * - * Supporting the ERRB interrupt would require dropping the regmap-IRQ - * usage or working around (or accepting a presense of) a naming conflict - * in debugFS IRQs. + * basic set of the PMIC features. + * Most notably, there is no support for the configurations which should + * be done when the PMIC is in STBY mode. * * Being able to reliably do the configurations like changing the * regulator safety limits (like limits for the over/under -voltages, over @@ -23,16 +19,14 @@ * be the need to configure these safety limits. Hence it's not simple to * come up with a generic solution. * - * Users who require the ERRB handling and STBY state configurations can - * have a look at the original RFC: + * Users who require the STBY state configurations can have a look at the + * original RFC: * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ - * which implements a workaround to debugFS naming conflict and some of - * the safety limit configurations - but leaves the state change handling - * and synchronization to be implemented. + * which implements some of the safety limit configurations - but leaves the + * state change handling and synchronization to be implemented. * * It would be great to hear (and receive a patch!) if you implement the - * STBY configuration support or a proper fix to the debugFS naming - * conflict in your downstream driver ;) + * STBY configuration support or a proper fix in your downstream driver ;) */ #include @@ -45,6 +39,65 @@ #include #include + +static const struct resource regulator_errb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96801_OTP_ERR_STAT, "bd96801-otp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_DBIST_ERR_STAT, "bd96801-dbist-err"), + DEFINE_RES_IRQ_NAMED(BD96801_EEP_ERR_STAT, "bd96801-eep-err"), + DEFINE_RES_IRQ_NAMED(BD96801_ABIST_ERR_STAT, "bd96801-abist-err"), + DEFINE_RES_IRQ_NAMED(BD96801_PRSTB_ERR_STAT, "bd96801-prstb-err"), + DEFINE_RES_IRQ_NAMED(BD96801_DRMOS1_ERR_STAT, "bd96801-drmoserr1"), + DEFINE_RES_IRQ_NAMED(BD96801_DRMOS2_ERR_STAT, "bd96801-drmoserr2"), + DEFINE_RES_IRQ_NAMED(BD96801_SLAVE_ERR_STAT, "bd96801-slave-err"), + DEFINE_RES_IRQ_NAMED(BD96801_VREF_ERR_STAT, "bd96801-vref-err"), + DEFINE_RES_IRQ_NAMED(BD96801_TSD_ERR_STAT, "bd96801-tsd"), + DEFINE_RES_IRQ_NAMED(BD96801_UVLO_ERR_STAT, "bd96801-uvlo-err"), + DEFINE_RES_IRQ_NAMED(BD96801_OVLO_ERR_STAT, "bd96801-ovlo-err"), + DEFINE_RES_IRQ_NAMED(BD96801_OSC_ERR_STAT, "bd96801-osc-err"), + DEFINE_RES_IRQ_NAMED(BD96801_PON_ERR_STAT, "bd96801-pon-err"), + DEFINE_RES_IRQ_NAMED(BD96801_POFF_ERR_STAT, "bd96801-poff-err"), + DEFINE_RES_IRQ_NAMED(BD96801_CMD_SHDN_ERR_STAT, "bd96801-cmd-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_INT_PRSTB_WDT_ERR, "bd96801-prstb-wdt-err"), + DEFINE_RES_IRQ_NAMED(BD96801_INT_CHIP_IF_ERR, "bd96801-chip-if-err"), + DEFINE_RES_IRQ_NAMED(BD96801_INT_SHDN_ERR_STAT, "bd96801-int-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_PVIN_ERR_STAT, "bd96801-buck1-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVP_ERR_STAT, "bd96801-buck1-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVP_ERR_STAT, "bd96801-buck1-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_SHDN_ERR_STAT, "bd96801-buck1-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_PVIN_ERR_STAT, "bd96801-buck2-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVP_ERR_STAT, "bd96801-buck2-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVP_ERR_STAT, "bd96801-buck2-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_SHDN_ERR_STAT, "bd96801-buck2-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_PVIN_ERR_STAT, "bd96801-buck3-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVP_ERR_STAT, "bd96801-buck3-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVP_ERR_STAT, "bd96801-buck3-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_SHDN_ERR_STAT, "bd96801-buck3-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_PVIN_ERR_STAT, "bd96801-buck4-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVP_ERR_STAT, "bd96801-buck4-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVP_ERR_STAT, "bd96801-buck4-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_SHDN_ERR_STAT, "bd96801-buck4-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_PVIN_ERR_STAT, "bd96801-ldo5-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVP_ERR_STAT, "bd96801-ldo5-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVP_ERR_STAT, "bd96801-ldo5-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_SHDN_ERR_STAT, "bd96801-ldo5-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_PVIN_ERR_STAT, "bd96801-ldo6-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVP_ERR_STAT, "bd96801-ldo6-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVP_ERR_STAT, "bd96801-ldo6-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_SHDN_ERR_STAT, "bd96801-ldo6-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_PVIN_ERR_STAT, "bd96801-ldo7-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVP_ERR_STAT, "bd96801-ldo7-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVP_ERR_STAT, "bd96801-ldo7-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_SHDN_ERR_STAT, "bd96801-ldo7-shdn-err"), +}; + static const struct resource regulator_intb_irqs[] = { DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"), @@ -89,20 +142,14 @@ static const struct resource regulator_intb_irqs[] = { DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "bd96801-ldo7-undervolt"), }; -static const struct resource wdg_intb_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD96801_WDT_ERR_STAT, "bd96801-wdg"), +enum { + WDG_CELL = 0, + REGULATOR_CELL, }; static struct mfd_cell bd96801_mfd_cells[] = { - { - .name = "bd96801-wdt", - .resources = wdg_intb_irqs, - .num_resources = ARRAY_SIZE(wdg_intb_irqs), - }, { - .name = "bd96801-pmic", - .resources = regulator_intb_irqs, - .num_resources = ARRAY_SIZE(regulator_intb_irqs), - }, + [WDG_CELL] = { .name = "bd96801-wdt", }, + [REGULATOR_CELL] = { .name = "bd96801-pmic", }, }; static const struct regmap_range bd96801_volatile_ranges[] = { @@ -127,6 +174,91 @@ static const struct regmap_access_table volatile_regs = { .n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges), }; +/* + * For ERRB we need main register bit mapping as bit(0) indicates active IRQ + * in one of the first 3 sub IRQ registers, For INTB we can use default 1 to 1 + * mapping. + */ +static unsigned int bit0_offsets[] = {0, 1, 2}; /* System stat, 3 registers */ +static unsigned int bit1_offsets[] = {3}; /* Buck 1 stat */ +static unsigned int bit2_offsets[] = {4}; /* Buck 2 stat */ +static unsigned int bit3_offsets[] = {5}; /* Buck 3 stat */ +static unsigned int bit4_offsets[] = {6}; /* Buck 4 stat */ +static unsigned int bit5_offsets[] = {7}; /* LDO 5 stat */ +static unsigned int bit6_offsets[] = {8}; /* LDO 6 stat */ +static unsigned int bit7_offsets[] = {9}; /* LDO 7 stat */ + +static struct regmap_irq_sub_irq_map errb_sub_irq_offsets[] = { + REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), +}; + +static const struct regmap_irq bd96801_errb_irqs[] = { + /* Reg 0x52 Fatal ERRB1 */ + REGMAP_IRQ_REG(BD96801_OTP_ERR_STAT, 0, BD96801_OTP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_DBIST_ERR_STAT, 0, BD96801_DBIST_ERR_MASK), + REGMAP_IRQ_REG(BD96801_EEP_ERR_STAT, 0, BD96801_EEP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_ABIST_ERR_STAT, 0, BD96801_ABIST_ERR_MASK), + REGMAP_IRQ_REG(BD96801_PRSTB_ERR_STAT, 0, BD96801_PRSTB_ERR_MASK), + REGMAP_IRQ_REG(BD96801_DRMOS1_ERR_STAT, 0, BD96801_DRMOS1_ERR_MASK), + REGMAP_IRQ_REG(BD96801_DRMOS2_ERR_STAT, 0, BD96801_DRMOS2_ERR_MASK), + REGMAP_IRQ_REG(BD96801_SLAVE_ERR_STAT, 0, BD96801_SLAVE_ERR_MASK), + /* 0x53 Fatal ERRB2 */ + REGMAP_IRQ_REG(BD96801_VREF_ERR_STAT, 1, BD96801_VREF_ERR_MASK), + REGMAP_IRQ_REG(BD96801_TSD_ERR_STAT, 1, BD96801_TSD_ERR_MASK), + REGMAP_IRQ_REG(BD96801_UVLO_ERR_STAT, 1, BD96801_UVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96801_OVLO_ERR_STAT, 1, BD96801_OVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96801_OSC_ERR_STAT, 1, BD96801_OSC_ERR_MASK), + REGMAP_IRQ_REG(BD96801_PON_ERR_STAT, 1, BD96801_PON_ERR_MASK), + REGMAP_IRQ_REG(BD96801_POFF_ERR_STAT, 1, BD96801_POFF_ERR_MASK), + REGMAP_IRQ_REG(BD96801_CMD_SHDN_ERR_STAT, 1, BD96801_CMD_SHDN_ERR_MASK), + /* 0x54 Fatal INTB shadowed to ERRB */ + REGMAP_IRQ_REG(BD96801_INT_PRSTB_WDT_ERR, 2, BD96801_INT_PRSTB_WDT_ERR_MASK), + REGMAP_IRQ_REG(BD96801_INT_CHIP_IF_ERR, 2, BD96801_INT_CHIP_IF_ERR_MASK), + REGMAP_IRQ_REG(BD96801_INT_SHDN_ERR_STAT, 2, BD96801_INT_SHDN_ERR_MASK), + /* Reg 0x55 BUCK1 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK1_PVIN_ERR_STAT, 3, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_OVP_ERR_STAT, 3, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_UVP_ERR_STAT, 3, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_SHDN_ERR_STAT, 3, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x56 BUCK2 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK2_PVIN_ERR_STAT, 4, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_OVP_ERR_STAT, 4, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_UVP_ERR_STAT, 4, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_SHDN_ERR_STAT, 4, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x57 BUCK3 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK3_PVIN_ERR_STAT, 5, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_OVP_ERR_STAT, 5, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_UVP_ERR_STAT, 5, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_SHDN_ERR_STAT, 5, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x58 BUCK4 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK4_PVIN_ERR_STAT, 6, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_OVP_ERR_STAT, 6, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_UVP_ERR_STAT, 6, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_SHDN_ERR_STAT, 6, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x59 LDO5 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_LDO5_PVIN_ERR_STAT, 7, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_OVP_ERR_STAT, 7, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_UVP_ERR_STAT, 7, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_SHDN_ERR_STAT, 7, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x5a LDO6 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_LDO6_PVIN_ERR_STAT, 8, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_OVP_ERR_STAT, 8, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_UVP_ERR_STAT, 8, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_SHDN_ERR_STAT, 8, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x5b LDO7 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_LDO7_PVIN_ERR_STAT, 9, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_OVP_ERR_STAT, 9, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_UVP_ERR_STAT, 9, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_SHDN_ERR_STAT, 9, BD96801_OUT_SHDN_ERR_MASK), +}; + static const struct regmap_irq bd96801_intb_irqs[] = { /* STATUS SYSTEM INTB */ REGMAP_IRQ_REG(BD96801_TW_STAT, 0, BD96801_TW_STAT_MASK), @@ -175,8 +307,25 @@ static const struct regmap_irq bd96801_intb_irqs[] = { REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK), }; +static struct regmap_irq_chip bd96801_irq_chip_errb = { + .name = "bd96801-irq-errb", + .domain_suffix = "errb", + .main_status = BD96801_REG_INT_MAIN, + .num_main_regs = 1, + .irqs = &bd96801_errb_irqs[0], + .num_irqs = ARRAY_SIZE(bd96801_errb_irqs), + .status_base = BD96801_REG_INT_SYS_ERRB1, + .mask_base = BD96801_REG_MASK_SYS_ERRB, + .ack_base = BD96801_REG_INT_SYS_ERRB1, + .init_ack_masked = true, + .num_regs = 10, + .irq_reg_stride = 1, + .sub_reg_offsets = &errb_sub_irq_offsets[0], +}; + static struct regmap_irq_chip bd96801_irq_chip_intb = { .name = "bd96801-irq-intb", + .domain_suffix = "intb", .main_status = BD96801_REG_INT_MAIN, .num_main_regs = 1, .irqs = &bd96801_intb_irqs[0], @@ -198,11 +347,14 @@ static const struct regmap_config bd96801_regmap_config = { static int bd96801_i2c_probe(struct i2c_client *i2c) { - struct regmap_irq_chip_data *intb_irq_data; + int i, ret, intb_irq, errb_irq, num_regu_irqs, num_intb, num_errb = 0; + int wdg_irq_no; + struct regmap_irq_chip_data *intb_irq_data, *errb_irq_data; + struct irq_domain *intb_domain, *errb_domain; + struct resource wdg_irq; const struct fwnode_handle *fwnode; - struct irq_domain *intb_domain; + struct resource *regulator_res; struct regmap *regmap; - int ret, intb_irq; fwnode = dev_fwnode(&i2c->dev); if (!fwnode) @@ -212,10 +364,28 @@ static int bd96801_i2c_probe(struct i2c_client *i2c) if (intb_irq < 0) return dev_err_probe(&i2c->dev, intb_irq, "INTB IRQ not configured\n"); + num_intb = ARRAY_SIZE(regulator_intb_irqs); + + /* ERRB may be omitted if processor is powered by the PMIC */ + errb_irq = fwnode_irq_get_byname(fwnode, "errb"); + if (errb_irq < 0) + errb_irq = 0; + + if (errb_irq) + num_errb = ARRAY_SIZE(regulator_errb_irqs); + + num_regu_irqs = num_intb + num_errb; + + regulator_res = kcalloc(num_regu_irqs, sizeof(*regulator_res), GFP_KERNEL); + if (!regulator_res) + return -ENOMEM; + regmap = devm_regmap_init_i2c(i2c, &bd96801_regmap_config); - if (IS_ERR(regmap)) - return dev_err_probe(&i2c->dev, PTR_ERR(regmap), + if (IS_ERR(regmap)) { + ret = dev_err_probe(&i2c->dev, PTR_ERR(regmap), "Regmap initialization failed\n"); + goto free_out; + } ret = regmap_write(regmap, BD96801_LOCK_REG, BD96801_UNLOCK); if (ret) @@ -224,18 +394,63 @@ static int bd96801_i2c_probe(struct i2c_client *i2c) ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, intb_irq, IRQF_ONESHOT, 0, &bd96801_irq_chip_intb, &intb_irq_data); - if (ret) - return dev_err_probe(&i2c->dev, ret, "Failed to add INTB IRQ chip\n"); + if (ret) { + dev_err_probe(&i2c->dev, ret, "Failed to add INTB irq_chip\n"); + goto free_out; + } intb_domain = regmap_irq_get_domain(intb_irq_data); - ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, - bd96801_mfd_cells, - ARRAY_SIZE(bd96801_mfd_cells), NULL, 0, - intb_domain); - + /* + * MFD core code is built to handle only one IRQ domain. BD96801 + * has two domains so we do IRQ mapping here and provide the + * already mapped IRQ numbers to sub-devices. + */ + for (i = 0; i < num_intb; i++) { + struct resource *res = ®ulator_res[i]; + + *res = regulator_intb_irqs[i]; + res->start = res->end = irq_create_mapping(intb_domain, + res->start); + } + + wdg_irq_no = irq_create_mapping(intb_domain, BD96801_WDT_ERR_STAT); + wdg_irq = DEFINE_RES_IRQ_NAMED(wdg_irq_no, "bd96801-wdg"); + bd96801_mfd_cells[WDG_CELL].resources = &wdg_irq; + bd96801_mfd_cells[WDG_CELL].num_resources = 1; + + if (num_errb) { + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, errb_irq, + IRQF_ONESHOT, 0, + &bd96801_irq_chip_errb, + &errb_irq_data); + if (ret) { + dev_err_probe(&i2c->dev, ret, + "Failed to add ERRB (%d) irq_chip\n", + errb_irq); + goto free_out; + } + errb_domain = regmap_irq_get_domain(errb_irq_data); + + for (i = 0; i < num_errb; i++) { + struct resource *res = ®ulator_res[num_intb + i]; + + *res = regulator_errb_irqs[i]; + res->start = res->end = irq_create_mapping(errb_domain, + res->start); + } + } + + bd96801_mfd_cells[REGULATOR_CELL].resources = regulator_res; + bd96801_mfd_cells[REGULATOR_CELL].num_resources = num_regu_irqs; + + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, bd96801_mfd_cells, + ARRAY_SIZE(bd96801_mfd_cells), NULL, 0, NULL); if (ret) - dev_err(&i2c->dev, "Failed to create subdevices\n"); + dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); + +free_out: + kfree(regulator_res); return ret; } From patchwork Tue Jun 4 07:56:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13684879 Received: from mail-lf1-f46.google.com (mail-lf1-f46.google.com [209.85.167.46]) (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 561E6142905; Tue, 4 Jun 2024 07:56:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487805; cv=none; b=F85fxVvwmblggxa6PXWd/DEzBsuLqFb9XO8TeSdwPSgOU3jBpZzHsGIUnFN5Jo1GSYhzdCSGYhkT78ipvKs3mQe7Bf7amaVLWO0BBgpkxJUEiq+gf+oFX54PnOAP46HGsZbSFwPBwnL5sR+UsI1ZmEjxXBTMMmb1XZIt0l4nGDk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717487805; c=relaxed/simple; bh=l/XyvCGS+PrP4ROgzHCnOkqa7jCy28PZpvTxS+CwZro=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=grhxiadnah5sZSOD/eWW5TI63u0adrgzu00AQqDN59dAfihLZtU8HJ7hWIx5Jw99Y4byFc5UqmHLwJ345tpaxm4su4MdtLWJt1CZhn0wI/cWYOLAcQI6nm4Hhng0GgiIvk6/rDiI8+f3Lo+rMwVeEEZZg096NPmcQj4+8RxjkZ4= 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=cKs8G3KE; arc=none smtp.client-ip=209.85.167.46 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="cKs8G3KE" Received: by mail-lf1-f46.google.com with SMTP id 2adb3069b0e04-52b962c4bb6so3334932e87.3; Tue, 04 Jun 2024 00:56:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717487801; x=1718092601; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=fQcOotaSPSL/kfYX/AiUNrk4z/j38OzBj/92nUZIbcs=; b=cKs8G3KETsyly59WkMSXHZLwDXjI6IeDl4Gc2F+EtE1N0hjkaNss+6mZN6/Qth/91W A+V8KaF9g6bqFHgaTvyJwlyYM/0CSwQfSIQN7/eQpjCmlW0ZX9LqYozq4poIFU014fsp 3UwuPvAjRJDQO6lpebeAuEz2wFe2vgSSAFIrlsC6NX67mCRTFqfjF+FScrLhdd/4yWo4 kyJ8sVegJIv6qdR6rFuAIiuwUGWhUgBPVCcujWB1EZT3JHvr1okMS/dg9JrjXNi6tHNi +5yhwIDV83kWHVT0jQPCO0vHlaPVlryxDpZE7wKfeG3OY8CgCBSLj/+undb3tjMfgib4 A0sw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717487801; x=1718092601; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=fQcOotaSPSL/kfYX/AiUNrk4z/j38OzBj/92nUZIbcs=; b=Ms/DYdgcgEy8nGcQHBFsieGBqwmaU+85r/95+2d1dt2rwu3R9dteqZDU/uDhonVWAC DvGnGnL1qKrkeQUSlBj67RrjlfC2qUOsKeBfy77PVjVqnXEwr6jBeRkNNNW+mBxKDdaP oQpY0Lq/+SAJXuso+JKfjwDX8QJZCXW7ZXemy0MOqz07SMFA6Ku0Yptme41K5WLaM/Ap N94wJipjKYGqqZuOn47ANMh15Cgv4me1iKsM3z9m6ty/VCKlC1zpH8eoDykjp3AosDaN bHOEPvLyrIS0/lNdkLYTvzBpk7iZmPgr2bEx8TOzL6lPq8wZUnShcvrE4+yeegY3n/o2 X4HQ== X-Forwarded-Encrypted: i=1; AJvYcCV7tdliKM0i98lp2prbzs3tgOBdikNXiIbzlhHLaSmCS4qkm4jcWq4b/1+CCJ5RERl1W8pQfZT8PWb/V3lDK9VduIodHIeb6HFJLATJvQ9137vHJdoe+K9Gy7ubG8JINu7xVS98qgR+06tf1e/7T1DDOTJMWdHQ+SQVXvoluc5hqd2oU6FQY6MM X-Gm-Message-State: AOJu0YxKjUWtdytjIBsTPOMuRGr8zjt8y8Ce8fSl9bGpds3oDpd9fTwb BtvWrI5Ay9mlyXXMiUAcLSPXMKuH9fuXegOKfd8oC7ykSi0ooNIw X-Google-Smtp-Source: AGHT+IERgdTVY1aR1YufVnprJNU1ikg7ILZzkhy5LdVDZ2HD8AwGg5mzxoDejvWJTdIKpDa//go7Ng== X-Received: by 2002:a05:6512:2391:b0:52b:8aa1:bdca with SMTP id 2adb3069b0e04-52b8aa1be8emr11298672e87.49.1717487801125; Tue, 04 Jun 2024 00:56:41 -0700 (PDT) Received: from fedora ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-52b9ea8ca6asm307543e87.245.2024.06.04.00.56.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Jun 2024 00:56:40 -0700 (PDT) Date: Tue, 4 Jun 2024 10:56:36 +0300 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , "Rafael J. Wysocki" , Matti Vaittinen , Wim Van Sebroeck , Guenter Roeck , Thomas Gleixner , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v3 10/10] regulator: bd96801: Add ERRB IRQ Message-ID: References: Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The ROHM BD96801 "scalable PMIC" provides two physical IRQs. The ERRB handling can in many cases be omitted because it is used to inform fatal IRQs, which usually kill the power from the SOC. There may however be use-cases where the SOC has a 'back-up' emergency power source which allows some very short time of operation to try to gracefully shut down sensitive hardware. Furthermore, it is possible the processor controlling the PMIC is not powered by the PMIC. In such cases handling the ERRB IRQs may be beneficial. Add support for ERRB IRQs. Signed-off-by: Matti Vaittinen Reviewed-by: Mark Brown --- Revision history: v2 =>: - No changes v1 => v2: - New patch --- drivers/regulator/bd96801-regulator.c | 130 +++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 15 deletions(-) diff --git a/drivers/regulator/bd96801-regulator.c b/drivers/regulator/bd96801-regulator.c index a1ac068c69f8..e49a9948223e 100644 --- a/drivers/regulator/bd96801-regulator.c +++ b/drivers/regulator/bd96801-regulator.c @@ -5,12 +5,7 @@ /* * This version of the "BD86801 scalable PMIC"'s driver supports only very * basic set of the PMIC features. Most notably, there is no support for - * the ERRB interrupt and the configurations which should be done when the - * PMIC is in STBY mode. - * - * Supporting the ERRB interrupt would require dropping the regmap-IRQ - * usage or working around (or accepting a presense of) a naming conflict - * in debugFS IRQs. + * the configurations which should be done when the PMIC is in STBY mode. * * Being able to reliably do the configurations like changing the * regulator safety limits (like limits for the over/under -voltages, over @@ -22,16 +17,14 @@ * be the need to configure these safety limits. Hence it's not simple to * come up with a generic solution. * - * Users who require the ERRB handling and STBY state configurations can - * have a look at the original RFC: + * Users who require the STBY state configurations can have a look at the + * original RFC: * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ - * which implements a workaround to debugFS naming conflict and some of - * the safety limit configurations - but leaves the state change handling - * and synchronization to be implemented. + * which implements some of the safety limit configurations - but leaves the + * state change handling and synchronization to be implemented. * * It would be great to hear (and receive a patch!) if you implement the - * STBY configuration support or a proper fix to the debugFS naming - * conflict in your downstream driver ;) + * STBY configuration support in your downstream driver ;) */ #include @@ -733,6 +726,95 @@ static int initialize_pmic_data(struct device *dev, return 0; } +static int bd96801_map_event_all(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int i; + + for (i = 0; i < rid->num_states; i++) { + rid->states[i].notifs = REGULATOR_EVENT_FAIL; + rid->states[i].errors = REGULATOR_ERROR_FAIL; + *dev_mask |= BIT(i); + } + + return 0; +} + +static int bd96801_rdev_errb_irqs(struct platform_device *pdev, + struct regulator_dev *rdev) +{ + int i; + void *retp; + static const char * const single_out_errb_irqs[] = { + "bd96801-%s-pvin-err", "bd96801-%s-ovp-err", + "bd96801-%s-uvp-err", "bd96801-%s-shdn-err", + }; + + for (i = 0; i < ARRAY_SIZE(single_out_errb_irqs); i++) { + struct regulator_irq_desc id = { + .map_event = bd96801_map_event_all, + .irq_off_ms = 1000, + }; + struct regulator_dev *rdev_arr[1]; + char tmp[255]; + int irq; + + snprintf(tmp, 255, single_out_errb_irqs[i], rdev->desc->name); + tmp[254] = 0; + id.name = tmp; + + irq = platform_get_irq_byname(pdev, tmp); + if (irq < 0) + continue; + + rdev_arr[0] = rdev; + retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0, + REGULATOR_ERROR_FAIL, NULL, + rdev_arr, 1); + if (IS_ERR(retp)) + return PTR_ERR(retp); + + } + return 0; +} + +static int bd96801_global_errb_irqs(struct platform_device *pdev, + struct regulator_dev **rdev, int num_rdev) +{ + int i, num_irqs; + void *retp; + static const char * const global_errb_irqs[] = { + "bd96801-otp-err", "bd96801-dbist-err", "bd96801-eep-err", + "bd96801-abist-err", "bd96801-prstb-err", "bd96801-drmoserr1", + "bd96801-drmoserr2", "bd96801-slave-err", "bd96801-vref-err", + "bd96801-tsd", "bd96801-uvlo-err", "bd96801-ovlo-err", + "bd96801-osc-err", "bd96801-pon-err", "bd96801-poff-err", + "bd96801-cmd-shdn-err", "bd96801-int-shdn-err" + }; + + num_irqs = ARRAY_SIZE(global_errb_irqs); + for (i = 0; i < num_irqs; i++) { + int irq; + struct regulator_irq_desc id = { + .name = global_errb_irqs[i], + .map_event = bd96801_map_event_all, + .irq_off_ms = 1000, + }; + + irq = platform_get_irq_byname(pdev, global_errb_irqs[i]); + if (irq < 0) + continue; + + retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0, + REGULATOR_ERROR_FAIL, NULL, + rdev, num_rdev); + if (IS_ERR(retp)) + return PTR_ERR(retp); + } + + return 0; +} + static int bd96801_rdev_intb_irqs(struct platform_device *pdev, struct bd96801_pmic_data *pdata, struct bd96801_irqinfo *iinfo, @@ -788,11 +870,10 @@ static int bd96801_rdev_intb_irqs(struct platform_device *pdev, return 0; } - - static int bd96801_probe(struct platform_device *pdev) { struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS]; + struct regulator_dev *all_rdevs[BD96801_NUM_REGULATORS]; struct bd96801_regulator_data *rdesc; struct regulator_config config = {}; int ldo_errs_arr[BD96801_NUM_LDOS]; @@ -800,6 +881,7 @@ static int bd96801_probe(struct platform_device *pdev) int temp_notif_ldos = 0; struct device *parent; int i, ret; + bool use_errb; void *retp; parent = pdev->dev.parent; @@ -824,6 +906,13 @@ static int bd96801_probe(struct platform_device *pdev) config.regmap = pdata->regmap; config.dev = parent; + ret = of_property_match_string(pdev->dev.parent->of_node, + "interrupt-names", "errb"); + if (ret < 0) + use_errb = false; + else + use_errb = true; + ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc, BD96801_NUM_REGULATORS); if (ret) @@ -842,6 +931,7 @@ static int bd96801_probe(struct platform_device *pdev) rdesc[i].desc.name); return PTR_ERR(rdev); } + all_rdevs[i] = rdev; /* * LDOs don't have own temperature monitoring. If temperature * notification was requested for this LDO from DT then we will @@ -863,6 +953,12 @@ static int bd96801_probe(struct platform_device *pdev) if (ret) return ret; } + /* Register per regulator ERRB notifiers */ + if (use_errb) { + ret = bd96801_rdev_errb_irqs(pdev, rdev); + if (ret) + return ret; + } } if (temp_notif_ldos) { int irq; @@ -884,6 +980,10 @@ static int bd96801_probe(struct platform_device *pdev) return PTR_ERR(retp); } + if (use_errb) + return bd96801_global_errb_irqs(pdev, all_rdevs, + ARRAY_SIZE(all_rdevs)); + return 0; }