Linux Documentation
 help / color / mirror / Atom feed
* Re: [PATCH] checkpatch: add --json output mode
From: Sasha Levin @ 2026-04-06 19:13 UTC (permalink / raw)
  To: Konstantin Ryabitsev
  Cc: dwaipayanray1, lukas.bulwahn, joe, corbet, skhan, apw, workflows,
	linux-doc, linux-kernel
In-Reply-To: <20260406-true-whippet-of-luck-d3c2ba@lemur>

On Mon, Apr 06, 2026 at 03:00:25PM -0400, Konstantin Ryabitsev wrote:
>On Mon, Apr 06, 2026 at 01:00:39PM -0400, Sasha Levin wrote:
>> Add a --json flag to checkpatch.pl that emits structured JSON output,
>> making results machine-parseable for CI systems, IDE integrations, and
>> AI-assisted code review tools.
>>
>> The JSON output includes per-file totals (errors, warnings, checks,
>> lines) and an array of individual issues with structured fields for
>> level, type, message, file path, and line number.
>>
>> The --json flag is mutually exclusive with --terse and --emacs.
>> Normal text output behavior is completely unchanged when --json is
>> not specified.
>
>I see that it's writing json out manually, implementing its own escaping.
>While there are upsides to not requiring a perl json library, I think it's
>fair to expect that people who would want to get json output can probably make
>sure that JSON::XS is installed.
>
>Not a strong object, but seems cleaner that way.

No objection here, but from what I saw the checkpatch code only uses core perl
packages so I wanted to keep it that way.

-- 
Thanks,
Sasha

^ permalink raw reply

* Re: [PATCH v2 00/33] rust: bump minimum Rust and `bindgen` versions
From: John Hubbard @ 2026-04-06 19:07 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Miguel Ojeda, Nathan Chancellor, Nicolas Schier, Danilo Krummrich,
	Andreas Hindborg, Catalin Marinas, Will Deacon, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Courbot, Simona Vetter,
	Brendan Higgins, David Gow, Greg Kroah-Hartman,
	Arve Hjønnevåg, Todd Kjos, Christian Brauner,
	Carlos Llamas, Alice Ryhl, Jonathan Corbet, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Trevor Gross, rust-for-linux,
	linux-kbuild, Lorenzo Stoakes, Vlastimil Babka, Liam R . Howlett,
	Uladzislau Rezki, linux-block, moderated for non-subscribers,
	Alexandre Ghiti, linux-riscv, nouveau, dri-devel, Rae Moar,
	linux-kselftest, kunit-dev, Nick Desaulniers, Bill Wendling,
	Justin Stitt, llvm, linux-kernel, Shuah Khan, linux-doc
In-Reply-To: <CANiq72n4tmTzqbcHCnzUBFyLVmJzB-AJng_1FgELJCWr7hDg4A@mail.gmail.com>

On 4/6/26 12:01 PM, Miguel Ojeda wrote:
> On Mon, Apr 6, 2026 at 8:51 PM John Hubbard <jhubbard@nvidia.com> wrote:
>>
>> Looks good from the perspective of this patchset. I am seeing
>> one remaining problem that we previously came up with a fix for,
>> so I expect that that fix is staged in another branch. But in
>> case it's not, here is the report:
>>
>> On today's rust-next, using rustc 1.85.0, at commit 232e79c72f57
>> ("rust: kbuild: allow `clippy::precedence` for Rust < 1.86.0"):
>>
>>   CLIPPY [M] drivers/gpu/drm/nova/nova.o
>> warning: consider removing unnecessary double parentheses
>>     --> rust/doctests_kernel_generated.rs:4240:14
>>      |
>> 4240 |     pr_info!("The policy details are: {:?}\n", (policy.cpu(), policy.cur()));
>>      |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>      |
>>      = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
>>      = note: `-W clippy::double-parens` implied by `-W clippy::all`
>>      = help: to override `-W clippy::all` add `#[allow(clippy::double_parens)]`
>>
>> warning: 1 warning emitted
> 
> That is already fixed and in mainline: 487f9b3dc6e5 ("rust: cpufreq:
> suppress clippy::double_parens in Policy doctest").
> 

That's what I thought I recalled, too. Weird that it is not in rust-next
already, though.


thanks,
-- 
John Hubbard


^ permalink raw reply

* Re: [PATCH v2 00/33] rust: bump minimum Rust and `bindgen` versions
From: Miguel Ojeda @ 2026-04-06 19:01 UTC (permalink / raw)
  To: John Hubbard
  Cc: Miguel Ojeda, Nathan Chancellor, Nicolas Schier, Danilo Krummrich,
	Andreas Hindborg, Catalin Marinas, Will Deacon, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Courbot, Simona Vetter,
	Brendan Higgins, David Gow, Greg Kroah-Hartman,
	Arve Hjønnevåg, Todd Kjos, Christian Brauner,
	Carlos Llamas, Alice Ryhl, Jonathan Corbet, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Trevor Gross, rust-for-linux,
	linux-kbuild, Lorenzo Stoakes, Vlastimil Babka, Liam R . Howlett,
	Uladzislau Rezki, linux-block, moderated for non-subscribers,
	Alexandre Ghiti, linux-riscv, nouveau, dri-devel, Rae Moar,
	linux-kselftest, kunit-dev, Nick Desaulniers, Bill Wendling,
	Justin Stitt, llvm, linux-kernel, Shuah Khan, linux-doc
In-Reply-To: <cf28afe0-ede5-4d1a-9824-65a1448f8161@nvidia.com>

On Mon, Apr 6, 2026 at 8:51 PM John Hubbard <jhubbard@nvidia.com> wrote:
>
> Looks good from the perspective of this patchset. I am seeing
> one remaining problem that we previously came up with a fix for,
> so I expect that that fix is staged in another branch. But in
> case it's not, here is the report:
>
> On today's rust-next, using rustc 1.85.0, at commit 232e79c72f57
> ("rust: kbuild: allow `clippy::precedence` for Rust < 1.86.0"):
>
>   CLIPPY [M] drivers/gpu/drm/nova/nova.o
> warning: consider removing unnecessary double parentheses
>     --> rust/doctests_kernel_generated.rs:4240:14
>      |
> 4240 |     pr_info!("The policy details are: {:?}\n", (policy.cpu(), policy.cur()));
>      |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>      |
>      = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
>      = note: `-W clippy::double-parens` implied by `-W clippy::all`
>      = help: to override `-W clippy::all` add `#[allow(clippy::double_parens)]`
>
> warning: 1 warning emitted

That is already fixed and in mainline: 487f9b3dc6e5 ("rust: cpufreq:
suppress clippy::double_parens in Policy doctest").

Cheers,
Miguel

^ permalink raw reply

* Re: [PATCH] checkpatch: add --json output mode
From: Konstantin Ryabitsev @ 2026-04-06 19:00 UTC (permalink / raw)
  To: Sasha Levin
  Cc: dwaipayanray1, lukas.bulwahn, joe, corbet, skhan, apw, workflows,
	linux-doc, linux-kernel
In-Reply-To: <20260406170039.4034716-1-sashal@kernel.org>

On Mon, Apr 06, 2026 at 01:00:39PM -0400, Sasha Levin wrote:
> Add a --json flag to checkpatch.pl that emits structured JSON output,
> making results machine-parseable for CI systems, IDE integrations, and
> AI-assisted code review tools.
> 
> The JSON output includes per-file totals (errors, warnings, checks,
> lines) and an array of individual issues with structured fields for
> level, type, message, file path, and line number.
> 
> The --json flag is mutually exclusive with --terse and --emacs.
> Normal text output behavior is completely unchanged when --json is
> not specified.

I see that it's writing json out manually, implementing its own escaping.
While there are upsides to not requiring a perl json library, I think it's
fair to expect that people who would want to get json output can probably make
sure that JSON::XS is installed.

Not a strong object, but seems cleaner that way.

-K

^ permalink raw reply

* Re: [PATCH v10 02/21] gpu: nova-core: gsp: Extract usable FB region from GSP
From: Joel Fernandes @ 2026-04-06 18:56 UTC (permalink / raw)
  To: Eliot Courtney, linux-kernel
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple,
	Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
	Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
	Elle Rhumsaa, alexeyi, joel, linux-doc, amd-gfx, intel-gfx,
	intel-xe, linux-fbdev
In-Reply-To: <DHIFMDLKTUSR.14QI5EHNMK18I@nvidia.com>



On 4/2/2026 1:49 AM, Eliot Courtney wrote:
> On Thu Apr 2, 2026 at 8:24 AM JST, Joel Fernandes wrote:
>>
>>
>> On 4/1/2026 4:27 AM, Eliot Courtney wrote:
>>> On Wed Apr 1, 2026 at 6:20 AM JST, Joel Fernandes wrote:
>>>> Add first_usable_fb_region() to GspStaticConfigInfo to extract the first
>>>> usable FB region from GSP's fbRegionInfoParams. Usable regions are those
>>>> that are not reserved or protected.
>>>>
>>>> The extracted region is stored in GetGspStaticInfoReply and exposed as
>>>> usable_fb_region field for use by the memory subsystem.
>>>>
>>>> Cc: Nikola Djukic <ndjukic@nvidia.com>
>>>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
>>>> ---
>>>
>>> Please see my feedback from v9[1] which still applies.
>>>
>>> [1]: https://lore.kernel.org/all/DH1GK30TUB4V.2GR6ANXIZDFFQ@nvidia.com/
>>
>> Yeah, I am seeing it now. Amidst making the earlier 7.1 merge window for
>> the DRM buddy and earlier patches in the series, I missed this. They seem
>> to be simple nits and I will address them in the next revision. thanks,
>>
>> --
>> Joel Fernandes
> 
> No worries. Sorry I have not gotten to more of the patches yet. Trying
> to get through some more now. Thanks!
So far all the comments have been good ones, so thanks. ;-)


--
Joel Fernandes


^ permalink raw reply

* Re: [PATCH v2 00/33] rust: bump minimum Rust and `bindgen` versions
From: John Hubbard @ 2026-04-06 18:51 UTC (permalink / raw)
  To: Miguel Ojeda, Miguel Ojeda
  Cc: Nathan Chancellor, Nicolas Schier, Danilo Krummrich,
	Andreas Hindborg, Catalin Marinas, Will Deacon, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Courbot, Simona Vetter,
	Brendan Higgins, David Gow, Greg Kroah-Hartman,
	Arve Hjønnevåg, Todd Kjos, Christian Brauner,
	Carlos Llamas, Alice Ryhl, Jonathan Corbet, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Trevor Gross, rust-for-linux,
	linux-kbuild, Lorenzo Stoakes, Vlastimil Babka, Liam R . Howlett,
	Uladzislau Rezki, linux-block, moderated for non-subscribers,
	Alexandre Ghiti, linux-riscv, nouveau, dri-devel, Rae Moar,
	linux-kselftest, kunit-dev, Nick Desaulniers, Bill Wendling,
	Justin Stitt, llvm, linux-kernel, Shuah Khan, linux-doc
In-Reply-To: <CANiq72mnGArtgAbe7xXZCYW1x7Zd5hozfnzoftaGy9rxoLO4ew@mail.gmail.com>

On 4/6/26 2:03 AM, Miguel Ojeda wrote:
> On Mon, Apr 6, 2026 at 1:53 AM Miguel Ojeda <ojeda@kernel.org> wrote:
... 
> Applied series to `rust-next` -- thanks everyone!
> 
> Let's see if we find any issue in -next.
> 

Looks good from the perspective of this patchset. I am seeing
one remaining problem that we previously came up with a fix for,
so I expect that that fix is staged in another branch. But in
case it's not, here is the report:

On today's rust-next, using rustc 1.85.0, at commit 232e79c72f57
("rust: kbuild: allow `clippy::precedence` for Rust < 1.86.0"):

  CLIPPY [M] drivers/gpu/drm/nova/nova.o
warning: consider removing unnecessary double parentheses
    --> rust/doctests_kernel_generated.rs:4240:14
     |
4240 |     pr_info!("The policy details are: {:?}\n", (policy.cpu(), policy.cur()));
     |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
     = note: `-W clippy::double-parens` implied by `-W clippy::all`
     = help: to override `-W clippy::all` add `#[allow(clippy::double_parens)]`

warning: 1 warning emitted



thanks,
-- 
John Hubbard


^ permalink raw reply

* Re: [PATCH net-next] docs: netdev: improve wording of reviewer guidance
From: Nicolai Buchwitz @ 2026-04-06 18:37 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
	skhan, workflows, linux-doc
In-Reply-To: <20260406175334.3153451-1-kuba@kernel.org>

On 6.4.2026 19:53, Jakub Kicinski wrote:
> Reword the reviewer guidance based on behavior we see on the list.
> Steer folks:
>  - towards sending tags
>  - away from process issues.
> 
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> CC: corbet@lwn.net
> CC: skhan@linuxfoundation.org
> CC: workflows@vger.kernel.org
> CC: linux-doc@vger.kernel.org
> ---
>  Documentation/process/maintainer-netdev.rst | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/process/maintainer-netdev.rst 
> b/Documentation/process/maintainer-netdev.rst
> index 3aa13bc2405d..bda93b459a05 100644
> --- a/Documentation/process/maintainer-netdev.rst
> +++ b/Documentation/process/maintainer-netdev.rst
> @@ -551,10 +551,12 @@ helpful tips please see 
> :ref:`development_advancedtopics_reviews`.
> 
>  It's safe to assume that netdev maintainers know the community and the 
> level
>  of expertise of the reviewers. The reviewers should not be concerned 
> about
> -their comments impeding or derailing the patch flow.
> +their comments impeding or derailing the patch flow. A Reviewed-by tag
> +is understood to mean "I have reviewed this code to the best of my 
> ability"
> +rather than "I can attest this code is correct".
> 

I had the same hesitation when starting to review on netdev, unsure if 
my R-b
carried any value. Therefore I appreciate the addition.

> -Less experienced reviewers are highly encouraged to do more in-depth
> -review of submissions and not focus exclusively on trivial or 
> subjective
> +Reviewers are highly encouraged to do more in-depth review of 
> submissions
> +and not focus exclusively on process issues, trivial or subjective
>  matters like code formatting, tags etc.
> 
>  Testimonials / feedback

Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>

^ permalink raw reply

* Re: [PATCH net-next] docs: netdev: improve wording of reviewer guidance
From: Joe Damato @ 2026-04-06 18:09 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
	skhan, workflows, linux-doc
In-Reply-To: <20260406175334.3153451-1-kuba@kernel.org>

On Mon, Apr 06, 2026 at 10:53:34AM -0700, Jakub Kicinski wrote:
> Reword the reviewer guidance based on behavior we see on the list.
> Steer folks:
>  - towards sending tags
>  - away from process issues.
> 
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> CC: corbet@lwn.net
> CC: skhan@linuxfoundation.org
> CC: workflows@vger.kernel.org
> CC: linux-doc@vger.kernel.org
> ---
>  Documentation/process/maintainer-netdev.rst | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 

Reviewed-by: Joe Damato <joe@dama.to>

^ permalink raw reply

* Re: [PATCH v3 02/24] PCI: Add API to track PCI devices preserved across Live Update
From: Yanjun.Zhu @ 2026-04-06 18:09 UTC (permalink / raw)
  To: David Matlack, Zhu Yanjun
  Cc: Alex Williamson, Bjorn Helgaas, Adithya Jayachandran,
	Alexander Graf, Alex Mastro, Andrew Morton, Ankit Agrawal,
	Arnd Bergmann, Askar Safin, Borislav Petkov (AMD), Chris Li,
	Dapeng Mi, David Rientjes, Feng Tang, Jacob Pan, Jason Gunthorpe,
	Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Kees Cook,
	Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
	linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
	Li RongQing, Lukas Wunner, Marco Elver, Michał Winiarski,
	Mike Rapoport, Parav Pandit, Pasha Tatashin, Paul E. McKenney,
	Pawan Gupta, Peter Zijlstra (Intel), Pranjal Shrivastava,
	Pratyush Yadav, Raghavendra Rao Ananta, Randy Dunlap,
	Rodrigo Vivi, Saeed Mahameed, Samiullah Khawaja, Shuah Khan,
	Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu
In-Reply-To: <CALzav=ei_xSfM0MTdPFhGDjNwe3EQ0vHPiEk=vszFX-Xi_KjQw@mail.gmail.com>


On 4/6/26 9:06 AM, David Matlack wrote:
> On Sun, Apr 5, 2026 at 9:56 AM Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
>> 在 2026/4/3 14:58, David Matlack 写道:
>>> On Thu, Apr 2, 2026 at 2:29 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
>>>> On 3/23/26 4:57 PM, David Matlack wrote:
>>>>> +config PCI_LIVEUPDATE
>>>>> +     bool "PCI Live Update Support (EXPERIMENTAL)"
>>>>> +     depends on PCI && LIVEUPDATE
>>>>> +     help
>>>>> +       Support for preserving PCI devices across a Live Update. This option
>>>>> +       should only be enabled by developers working on implementing this
>>>>> +       support. Once enough support as landed in the kernel, this option
>>>>> +       will no longer be marked EXPERIMENTAL.
>>>>> +
>>>>> +       If unsure, say N.
>>>> Currently, it only supports 'n' or 'y'. Is it possible to add 'm'
>>>> (modular support)?
>>>>
>>>> This would allow the feature to be built as a kernel module. For
>>>> development
>>>>
>>>> purposes, modularization means we only need to recompile a single module
>>>>
>>>> for testing, rather than rebuilding the entire kernel. Compiling a
>>>> module should
>>>>
>>>> be significantly faster than a full kernel build.
>>> I don't think it is possible for CONFIG_PCI_LIVEUPDATE to support 'm'.
>>> pci_setup_device() (which is under CONFIG_PCI) needs to call
>>> pci_liveupdate_setup_device(), and CONFIG_PCI cannot be built as a
>>> module. This call is necessary so the PCI core knows whether a device
>>> being enumerated was preserved across a previous Live Update.
>> After the following changes, the liveupdate.ko can be generated
>> successfully.
> Sure but you've broken the feature. Now devices can be probed before
> liveupdate.ko is loaded and the PCI core will have an incorrect view

 From this perspective, I think it makes sense.

Zhu Yanjun

> of which devices were preserved by the previous kernel.

^ permalink raw reply

* Re: [PATCH] cpufreq: CPPC: add autonomous mode boot parameter support
From: Sumit Gupta @ 2026-04-06 18:08 UTC (permalink / raw)
  To: Pierre Gondois
  Cc: linux-tegra, linux-kernel, linux-doc, zhenglifeng1, treding,
	viresh.kumar, jonathanh, vsethi, ionela.voinescu, ksitaraman,
	sanjayc, zhanjie9, corbet, mochs, skhan, bbasu, rdunlap, linux-pm,
	mario.limonciello, rafael, sumitg
In-Reply-To: <4b1f100b-e699-43c1-a06b-5545056d174c@arm.com>

Hi Pierre,

Thank you for the comments.
Sorry for late reply as I was on vacation.


On 24/03/26 23:48, Pierre Gondois wrote:
> External email: Use caution opening links or attachments
>
>
> Hello Sumit,
>
> On 3/17/26 16:10, Sumit Gupta wrote:
>> Add kernel boot parameter 'cppc_cpufreq.auto_sel_mode' to enable CPPC
>> autonomous performance selection on all CPUs at system startup without
>> requiring runtime sysfs manipulation. When autonomous mode is enabled,
>> the hardware automatically adjusts CPU performance based on workload
>> demands using Energy Performance Preference (EPP) hints.
>>
>> When auto_sel_mode=1:
>> - Configure all CPUs for autonomous operation on first init
>> - Set EPP to performance preference (0x0)
>> - Use HW min/max when set; otherwise program from policy limits (caps)
>> - Clamp desired_perf to bounds before enabling autonomous mode
>> - Hardware controls frequency instead of the OS governor
>>
>> The boot parameter is applied only during first policy initialization.
>> On hotplug, skip applying it so that the user's runtime sysfs
>> configuration is preserved.
>>
>> Reviewed-by: Randy Dunlap <rdunlap@infradead.org> (Documentation)
>> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
>> ---
>> Part 1 [1] of this series was applied for 7.1 and present in next.
>> Sending this patch as reworked version of 'patch 11' from [2] based
>> on next.
>>
>> [1] 
>> https://lore.kernel.org/lkml/20260206142658.72583-1-sumitg@nvidia.com/
>> [2] 
>> https://lore.kernel.org/lkml/20251223121307.711773-1-sumitg@nvidia.com/
>> ---
>>   .../admin-guide/kernel-parameters.txt         | 13 +++
>>   drivers/cpufreq/cppc_cpufreq.c                | 84 +++++++++++++++++--
>>   2 files changed, 92 insertions(+), 5 deletions(-)
>>
>> diff --git a/Documentation/admin-guide/kernel-parameters.txt 
>> b/Documentation/admin-guide/kernel-parameters.txt
>> index fa6171b5fdd5..de4b4c89edfe 100644
>> --- a/Documentation/admin-guide/kernel-parameters.txt
>> +++ b/Documentation/admin-guide/kernel-parameters.txt
>> @@ -1060,6 +1060,19 @@ Kernel parameters
>>                       policy to use. This governor must be registered 
>> in the
>>                       kernel before the cpufreq driver probes.
>>
>> +     cppc_cpufreq.auto_sel_mode=
>> +                     [CPU_FREQ] Enable ACPI CPPC autonomous performance
>> +                     selection. When enabled, hardware automatically 
>> adjusts
>> +                     CPU frequency on all CPUs based on workload 
>> demands.
>> +                     In Autonomous mode, Energy Performance 
>> Preference (EPP)
>> +                     hints guide hardware toward performance (0x0) 
>> or energy
>> +                     efficiency (0xff).
>> +                     Requires ACPI CPPC autonomous selection 
>> register support.
>> +                     Format: <bool>
>> +                     Default: 0 (disabled)
>> +                     0: use cpufreq governors
>> +                     1: enable if supported by hardware
>> +
>>       cpu_init_udelay=N
>>                       [X86,EARLY] Delay for N microsec between assert 
>> and de-assert
>>                       of APIC INIT to start processors.  This delay 
>> occurs
>> diff --git a/drivers/cpufreq/cppc_cpufreq.c 
>> b/drivers/cpufreq/cppc_cpufreq.c
>> index 5dfb109cf1f4..49c148b2a0a4 100644
>> --- a/drivers/cpufreq/cppc_cpufreq.c
>> +++ b/drivers/cpufreq/cppc_cpufreq.c
>> @@ -28,6 +28,9 @@
>>
>>   static struct cpufreq_driver cppc_cpufreq_driver;
>>
>> +/* Autonomous Selection boot parameter */
>> +static bool auto_sel_mode;
>> +
>>   #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
>>   static enum {
>>       FIE_UNSET = -1,
>> @@ -708,11 +711,74 @@ static int cppc_cpufreq_cpu_init(struct 
>> cpufreq_policy *policy)
>>       policy->cur = cppc_perf_to_khz(caps, caps->highest_perf);
>>       cpu_data->perf_ctrls.desired_perf = caps->highest_perf;
>>
>> -     ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
>> -     if (ret) {
>> -             pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
>> -                      caps->highest_perf, cpu, ret);
>> -             goto out;
>> +     /*
>> +      * Enable autonomous mode on first init if boot param is set.
>> +      * Check last_governor to detect first init and skip if auto_sel
>> +      * is already enabled.
>> +      */
> If the goal is to set autosel only once at the driver init,
> shouldn't this be done in cppc_cpufreq_init() ?
> I understand that cpu_data doesn't exist yet in
> cppc_cpufreq_init(), but this seems more appropriate to do
> it there IMO.
>
> This means the cpudata should be updated accordingly
> in this cppc_cpufreq_cpu_init() function.

In an earlier version [1], the setup was in cppc_cpufreq_init() but
was moved to cppc_cpufreq_cpu_init() to improve per-CPU error handling.
Keeping the setup in cppc_cpufreq_init() helps to avoid the last_governor
check. We can warn for a CPU failing to enable and continue so other
CPUs keep autonomous mode.
cppc_cpufreq_cpu_init() would then just check the auto_sel state
from register and sync policy limits from min/max_perf registers when
autonomous mode is active.
Please let me know your thoughts.

[1] 
https://lore.kernel.org/lkml/5593d364-ca37-41c5-b33f-f7e245d6d626@nvidia.com/


>
>> +     if (auto_sel_mode && policy->last_governor[0] == '\0' &&
>> +         !cpu_data->perf_ctrls.auto_sel) {
>> +             /* Enable CPPC - optional register, some platforms need 
>> it */
> The documentation of the CPPC Enable Register is subject to
> interpretation, but IIUC the field should be set to use the CPPC
> controls, so I assume this should be set in cppc_cpufreq_init()
> instead ?

Agree that the CPPC Enable is about using the CPPC control path
in general and not only for autonomous selection.
Will move cppc_set_enable() into cppc_cpufreq_init() or outside the
autonomous mode block in cppc_cpufreq_cpu_init() as per conclusion
of previous comment.

>> +             ret = cppc_set_enable(cpu, true);
>> +             if (ret && ret != -EOPNOTSUPP)
>> +                     pr_warn("Failed to enable CPPC for CPU%d 
>> (%d)\n", cpu, ret);
>> +
>> +             /*
>> +              * Prefer HW min/max_perf when set; otherwise program from
>> +              * policy limits derived earlier from caps.
>> +              * Clamp desired_perf to bounds and sync policy->cur.
>> +              */
>> +             if (!cpu_data->perf_ctrls.min_perf || 
>> !cpu_data->perf_ctrls.max_perf)
>
> The function doesn't seem to exist.

It is newly added in [2].
Don't need to call it if we move the setup to cppc_cpufreq_init().

[2] 
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=ea3db45ae476889a1ba0ab3617e6afdeeefbda3d 



>
>> + cppc_cpufreq_update_perf_limits(cpu_data, policy);
>> +
>> +             cpu_data->perf_ctrls.desired_perf =
>> +                     clamp_t(u32, cpu_data->perf_ctrls.desired_perf,
>> +                             cpu_data->perf_ctrls.min_perf,
>> +                             cpu_data->perf_ctrls.max_perf);
>> +
>> +             policy->cur = cppc_perf_to_khz(caps,
>> + cpu_data->perf_ctrls.desired_perf);
>> +
>
> Maybe this should also be done in cppc_cpufreq_init()
> if the auto_sel_mode parameter is set ?

Yes.

>
>> +             /* EPP is optional - some platforms may not support it */
>> +             ret = cppc_set_epp(cpu, CPPC_EPP_PERFORMANCE_PREF);
>> +             if (ret && ret != -EOPNOTSUPP)
>> +                     pr_warn("Failed to set EPP for CPU%d (%d)\n", 
>> cpu, ret);
>> +             else if (!ret)
>> +                     cpu_data->perf_ctrls.energy_perf = 
>> CPPC_EPP_PERFORMANCE_PREF;
>> +
>> +             ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
>> +             if (ret) {
>> +                     pr_debug("Err setting perf for autonomous mode 
>> CPU:%d ret:%d\n",
>> +                              cpu, ret);
>> +                     goto out;
>> +             }
>> +
>> +             ret = cppc_set_auto_sel(cpu, true);
>> +             if (ret && ret != -EOPNOTSUPP) {
>> +                     pr_warn("Failed autonomous config for CPU%d 
>> (%d)\n",
>> +                             cpu, ret);
>> +                     goto out;
>> +             }
>> +             if (!ret)
>> +                     cpu_data->perf_ctrls.auto_sel = true;
>> +     }
>> +
>> +     if (cpu_data->perf_ctrls.auto_sel) {
>
> There is a patchset ongoing which tries to remove
> setting policy->min/max from driver initialization.
> Indeed, these values are only temporarily valid,
> until the governor override them.
> It is not sure yet the patch will be accepted though.
>
> https://lore.kernel.org/lkml/20260317101753.2284763-4-pierre.gondois@arm.com/ 
>


You are right that policy->min/max from .init() are temporary today
as cpufreq_set_policy() overwrites them before the governor starts.

On my test platform (highest == nominal, lowest_nonlinear == lowest),
this had no visible effect because the BIOS bounds and cpuinfo range
end up identical. But on platforms where they differ, the governor
would widen the range to full cpuinfo limits.

I think your patch [3] fixes this by giving these the right semantic as
initial QoS requests. With it, cpufreq_set_policy() preserves the policy
limits set from min/max_perf registers in .init(), which can either be
BIOS values on first boot or last user configured values before hotplug.

I will update the comment in v2 to reflect QoS seeding intent.

I see that the first two patches of your series [3] is applied for 7.1.
Do you plan to send the pending patch (3/4) from [3]?

[3] 
https://lore.kernel.org/lkml/20260317101753.2284763-4-pierre.gondois@arm.com/


>
>
>> +             /* Sync policy limits from HW when autonomous mode is 
>> active */
>> +             policy->min = cppc_perf_to_khz(caps,
>> + cpu_data->perf_ctrls.min_perf ?:
>> + caps->lowest_nonlinear_perf);
>> +             policy->max = cppc_perf_to_khz(caps,
>> + cpu_data->perf_ctrls.max_perf ?:
>> + caps->nominal_perf);
>> +     } else {
>> +             /* Normal mode: governors control frequency */
>> +             ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
>> +             if (ret) {
>> +                     pr_debug("Err setting perf value:%d on CPU:%d. 
>> ret:%d\n",
>> +                              caps->highest_perf, cpu, ret);
>> +                     goto out;
>> +             }
>>       }
>>
>>       cppc_cpufreq_cpu_fie_init(policy);
>> @@ -1038,10 +1104,18 @@ static int __init cppc_cpufreq_init(void)
>>
>>   static void __exit cppc_cpufreq_exit(void)
>>   {
>> +     unsigned int cpu;
>> +
>> +     for_each_present_cpu(cpu)
>> +             cppc_set_auto_sel(cpu, false);
>
> If the firmware has a default EPP value, it means that loading
> and the unloading the driver will reset this default EPP value.
> Maybe the initial EPP value and/or the auto_sel value should be
> cached somewhere and restored on exit ?
> I don't know if this is actually an issue, this is just to signal it.

The auto_sel_mode boot path programs EPP to performance preference(0),
not the firmware’s previous value. On unload we only call
cppc_set_auto_sel(false); we do not restore EPP, min/max perf,
or other CPPC fields to firmware defaults.

Thank you,
Sumit Gupta

....



^ permalink raw reply

* [PATCH net-next] docs: netdev: improve wording of reviewer guidance
From: Jakub Kicinski @ 2026-04-06 17:53 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, andrew+netdev, horms, Jakub Kicinski,
	corbet, skhan, workflows, linux-doc

Reword the reviewer guidance based on behavior we see on the list.
Steer folks:
 - towards sending tags
 - away from process issues.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: corbet@lwn.net
CC: skhan@linuxfoundation.org
CC: workflows@vger.kernel.org
CC: linux-doc@vger.kernel.org
---
 Documentation/process/maintainer-netdev.rst | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/Documentation/process/maintainer-netdev.rst b/Documentation/process/maintainer-netdev.rst
index 3aa13bc2405d..bda93b459a05 100644
--- a/Documentation/process/maintainer-netdev.rst
+++ b/Documentation/process/maintainer-netdev.rst
@@ -551,10 +551,12 @@ helpful tips please see :ref:`development_advancedtopics_reviews`.
 
 It's safe to assume that netdev maintainers know the community and the level
 of expertise of the reviewers. The reviewers should not be concerned about
-their comments impeding or derailing the patch flow.
+their comments impeding or derailing the patch flow. A Reviewed-by tag
+is understood to mean "I have reviewed this code to the best of my ability"
+rather than "I can attest this code is correct".
 
-Less experienced reviewers are highly encouraged to do more in-depth
-review of submissions and not focus exclusively on trivial or subjective
+Reviewers are highly encouraged to do more in-depth review of submissions
+and not focus exclusively on process issues, trivial or subjective
 matters like code formatting, tags etc.
 
 Testimonials / feedback
-- 
2.53.0


^ permalink raw reply related

* [PATCH 1/1] Documentation: leds: leds-class: Document keyboard backlight LED class naming
From: Hans de Goede @ 2026-04-06 17:46 UTC (permalink / raw)
  To: Lee Jones, Pavel Machek, Jonathan Corbet, Shuah Khan
  Cc: Hans de Goede, Rishit Bansal, Carlos Ferreira, Edip Hazuri,
	Mustafa Ekşi, Xavier Bestel, linux-leds, linux-doc
In-Reply-To: <20260406174638.320135-1-johannes.goede@oss.qualcomm.com>

From: Carlos Ferreira <carlosmiguelferreira.2003@gmail.com>

Document the existing practice of always using 'kbd_backlight' for
the function part of LED class device names for LED class devices which
control single-zone keyboard backlights.

Also extend this existing practice with a new naming scheme for keyboards
with zoned backlight control. There are several drivers in the works (see
the Link:tags below) which offer backlight control for keyboards where
the keyboard backlight is divided in a limited number of zones, e.g.
"main", "cursor" and "numpad" zones.

It is important to agree on a consistent naming scheme for these now,
so that userspace can support multiple different models / vendors through
a single unified naming scheme.

Link: https://lore.kernel.org/platform-driver-x86/20230131235027.36304-1-rishitbansal0@gmail.com/
Link: https://lore.kernel.org/platform-driver-x86/20240719100011.16656-1-carlosmiguelferreira.2003@gmail.com/
Link: https://lore.kernel.org/platform-driver-x86/20260304105831.119349-3-edip@medip.dev/
Link: https://lore.kernel.org/platform-driver-x86/20240806205001.191551-2-mustafa.eskieksi@gmail.com/
Link: https://lore.kernel.org/linux-input/20260402075239.3829699-1-xav@bes.tel/
Signed-off-by: Carlos Ferreira <carlosmiguelferreira.2003@gmail.com>
Co-authored-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
 Documentation/leds/leds-class.rst | 63 +++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/Documentation/leds/leds-class.rst b/Documentation/leds/leds-class.rst
index 5db620ed27aa..d2b042519a66 100644
--- a/Documentation/leds/leds-class.rst
+++ b/Documentation/leds/leds-class.rst
@@ -116,6 +116,69 @@ above leaves scope for further attributes should they be needed. If sections
 of the name don't apply, just leave that section blank.
 
 
+Keyboard backlight control LED Device Naming
+============================================
+
+For backlit keyboards with a single brightness / color settings a single
+(multicolor) LED class device should be used to allow userspace to change
+the backlight brightness (and if possible the color). This LED class device
+must use "kbd_backlight" for the function part of the LED class device name.
+IOW the name must end with ":kbd_backlight".
+
+For backlit keyboards with multiple control zones, one (multicolor) LED class
+device should be used per zone. These LED class devices' name must follow:
+
+	"<devicename>:<color>:kbd_zoned_backlight-<zone_name>"
+
+and <devicename> must be the same for all zones of the same keyboard.
+
+<zone_name> should be descriptive of which part of the keyboard backlight
+the zone covers and should be suitable for userspace to show to an end user
+in an UI for controlling the zones.
+
+Where possible <zone_name> should be a value already used by other
+zoned keyboards with a similar or identical zone layout, e.g.:
+
+<devicename>:<color>:kbd_zoned_backlight-right
+<devicename>:<color>:kbd_zoned_backlight-middle
+<devicename>:<color>:kbd_zoned_backlight-left
+<devicename>:<color>:kbd_zoned_backlight-corners
+<devicename>:<color>:kbd_zoned_backlight-wasd
+
+or:
+
+<devicename>:<color>:kbd_zoned_backlight-main
+<devicename>:<color>:kbd_zoned_backlight-cursor
+<devicename>:<color>:kbd_zoned_backlight-numpad
+<devicename>:<color>:kbd_zoned_backlight-corners
+<devicename>:<color>:kbd_zoned_backlight-wasd
+
+Note that this is intended for keyboards with a limited number of zones,
+keyboards with per key addressable backlighting must not use LED class devices
+since the sysfs API is not suitable for rapidly change multiple LEDs in one
+"commit" as is necessary to do animations / special effects on such keyboards.
+
+An exception to the rule that all zones must follow:
+
+	"<devicename>:<color>:kbd_zoned_backlight-<zone_name>"
+
+is made for the special case where there is a single big zone which controls
+the backlighting of almost all of the keyboard and there are some small areas
+with separate control, like just the 4 cursor keys, or the WASD keys. In this
+case the main zone should use 'kbd_backlight' for the function part of the name
+for compatiblity with (older) userspace code which is not aware of
+the "kbd_zoned_backlight-<zone_name>" function naming scheme.
+
+While the smaller zones should use the new zoned naming scheme. Such a setup
+would result in e.g.:
+
+<devicename>:<color>:kbd_backlight
+<devicename>:<color>:kbd_zoned_backlight-wasd
+
+"kbd_zoned_backlight-<zone_name>" aware userspace should be aware of this
+exception and check for a main zone with a "kbd_backlight" function-name.
+
+
 Brightness setting API
 ======================
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH 0/1] Documentation: leds: leds-class: Document keyboard backlight LED class naming
From: Hans de Goede @ 2026-04-06 17:46 UTC (permalink / raw)
  To: Lee Jones, Pavel Machek, Jonathan Corbet, Shuah Khan
  Cc: Hans de Goede, Rishit Bansal, Carlos Ferreira, Edip Hazuri,
	Mustafa Ekşi, Xavier Bestel, linux-leds, linux-doc

Hi All,

Over the last couple of years there have been several attempts to add
upstream kernel support for controlling keyboard backlights consisting of
a small number of backlight zones, think e.g. : "main", "cursor" and
"keypad" zones.

All of these attempts have gotten or are stuck on the lack of consensus on
a userspace API (1) for controlling such zoned keyboard backlights.

Previous discussion can be summarized as there being consensus that
these backlights should be represented as (multi-color) LED class devices
with one LED class device per zone, mirroring the existing use of
a LED class device for controlling single zone keyboard backlights.

The only thing which really still needs to be agreed upon is a naming
scheme for the per zone LED class devices so that userspace can detect:

1. That the function of these is to control a zoned keyboard backlight.
2. How to group the per zone devices together for a single keyboard.

The single patch in this series documents the currently undocumented naming
scheme for single zone keyboard backlights and extends this with a naming
scheme to use for multi-zone keyboard backlights.

This is send out as a separate patch rather then as part of a series
implementing this in the hope to get multiple drivers which are in
the process of being upstreamed unstuck wrt the LED class naming problem.

Drivers which need this are:

1. HP WMI laptop driver Omen gaming keyboards backlight control support:
First 2023 attempt:
https://lore.kernel.org/platform-driver-x86/20230131235027.36304-1-rishitbansal0@gmail.com/
Later 2024 attempt which includes an earlier version of this doc patch:
https://lore.kernel.org/platform-driver-x86/20240719100011.16656-1-carlosmiguelferreira.2003@gmail.com/
Current ongoing 2026 attempt:
https://lore.kernel.org/platform-driver-x86/20260304105831.119349-3-edip@medip.dev/

2. Casper Excalibur laptop driver (inc. multi-zone kbd backlight control):
https://lore.kernel.org/platform-driver-x86/20240806205001.191551-2-mustafa.eskieksi@gmail.com/
This one unfortunately seems to have stalled.

3. Logitech G710/G710+ gaming keyboards HID driver:
https://lore.kernel.org/linux-input/20260402075239.3829699-1-xav@bes.tel/
Posted a week ago, needs an agreement on the LED class dev naming scheme
to continue.

Regards,

Hans


1) The lack of such an API may not always have been the sole reason these
drivers have gotten stuck, but it was always a factor.


Carlos Ferreira (1):
  Documentation: leds: leds-class: Document keyboard backlight LED class
    naming

 Documentation/leds/leds-class.rst | 63 +++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

-- 
2.53.0


^ permalink raw reply

* Re: [PATCH V10 00/10] famfs: port into fuse
From: Joanne Koong @ 2026-04-06 17:43 UTC (permalink / raw)
  To: John Groves
  Cc: John Groves, Miklos Szeredi, Dan Williams, Bernd Schubert,
	Alison Schofield, John Groves, Jonathan Corbet, Shuah Khan,
	Vishal Verma, Dave Jiang, Matthew Wilcox, Jan Kara,
	Alexander Viro, David Hildenbrand, Christian Brauner,
	Darrick J . Wong, Randy Dunlap, Jeff Layton, Amir Goldstein,
	Jonathan Cameron, Stefan Hajnoczi, Josef Bacik, Bagas Sanjaya,
	Chen Linxuan, James Morse, Fuad Tabba, Sean Christopherson,
	Shivank Garg, Ackerley Tng, Gregory Price, Aravind Ramesh,
	Ajay Joshi, venkataravis@micron.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, nvdimm@lists.linux.dev,
	linux-cxl@vger.kernel.org, linux-fsdevel@vger.kernel.org
In-Reply-To: <0100019d43e5f632-f5862a3e-361c-4b54-a9a6-96c242a8f17a-000000@email.amazonses.com>

On Tue, Mar 31, 2026 at 5:37 AM John Groves <john@jagalactic.com> wrote:
>
> From: John Groves <john@groves.net>
>
> NOTE: this series depends on the famfs dax series in Ira's for-7.1/dax-famfs
> branch [0]
>
> Changes v9 -> v10
> - Rebased to Ira's for-7.1/dax-famfs branch [0], which contains the required
>   dax patches
> - Add parentheses to FUSE_IS_VIRTIO_DAX() macro, in case something bad is
>   passed in as fuse_inode (thanks Jonathan's AI)
>
> Description:
>
> This patch series introduces famfs into the fuse file system framework.
> Famfs depends on the bundled dax patch set.
>
> The famfs user space code can be found at [1].
>
> Fuse Overview:
>
> Famfs started as a standalone file system, but this series is intended to
> permanently supersede that implementation. At a high level, famfs adds
> two new fuse server messages:
>
> GET_FMAP   - Retrieves a famfs fmap (the file-to-dax map for a famfs
>              file)
> GET_DAXDEV - Retrieves the details of a particular daxdev that was
>              referenced by an fmap
>
> Famfs Overview
>
> Famfs exposes shared memory as a file system. Famfs consumes shared
> memory from dax devices, and provides memory-mappable files that map
> directly to the memory - no page cache involvement. Famfs differs from
> conventional file systems in fs-dax mode, in that it handles in-memory
> metadata in a sharable way (which begins with never caching dirty shared
> metadata).
>
> Famfs started as a standalone file system [2,3], but the consensus at
> LSFMM was that it should be ported into fuse [4,5].
>
> The key performance requirement is that famfs must resolve mapping faults
> without upcalls. This is achieved by fully caching the file-to-devdax
> metadata for all active files. This is done via two fuse client/server
> message/response pairs: GET_FMAP and GET_DAXDEV.
>
> Famfs remains the first fs-dax file system that is backed by devdax
> rather than pmem in fs-dax mode (hence the need for the new dax mode).
>
> Notes
>
> - When a file is opened in a famfs mount, the OPEN is followed by a
>   GET_FMAP message and response. The "fmap" is the full file-to-dax
>   mapping, allowing the fuse/famfs kernel code to handle
>   read/write/fault without any upcalls.
>
> - After each GET_FMAP, the fmap is checked for extents that reference
>   previously-unknown daxdevs. Each such occurrence is handled with a
>   GET_DAXDEV message and response.
>
> - Daxdevs are stored in a table (which might become an xarray at some
>   point). When entries are added to the table, we acquire exclusive
>   access to the daxdev via the fs_dax_get() call (modeled after how
>   fs-dax handles this with pmem devices). Famfs provides
>   holder_operations to devdax, providing a notification path in the
>   event of memory errors or forced reconfiguration.
>
> - If devdax notifies famfs of memory errors on a dax device, famfs
>   currently blocks all subsequent accesses to data on that device. The
>   recovery is to re-initialize the memory and file system. Famfs is
>   memory, not storage...
>
> - Because famfs uses backing (devdax) devices, only privileged mounts are
>   supported (i.e. the fuse server requires CAP_SYS_RAWIO).
>
> - The famfs kernel code never accesses the memory directly - it only
>   facilitates read, write and mmap on behalf of user processes, using
>   fmap metadata provided by its privileged fuse server. As such, the
>   RAS of the shared memory affects applications, but not the kernel.
>
> - Famfs has backing device(s), but they are devdax (char) rather than
>   block. Right now there is no way to tell the vfs layer that famfs has a
>   char backing device (unless we say it's block, but it's not). Currently
>   we use the standard anonymous fuse fs_type - but I'm not sure that's
>   ultimately optimal (thoughts?)
>
> Changes v8 -> v9
> - Kconfig: fs/fuse/Kconfig:CONFIG_FUSE_FAMFS_DAX now depends on the
>   new CONFIG_DEV_DAX_FSDEV (from drivers/dax/Kconfig) rather than
>   just CONFIG_DEV_DAX and CONFIG_FS_DAX. (CONFIG_FUSE_FAMFS_DAX
>   depends on those...)
>
> Changes v7 -> v8
> - Moved to inline __free declaration in fuse_get_fmap() and
>   famfs_fuse_meta_alloc(), famfs_teardown()
> - Adopted FIELD_PREP() macro rather than manual bitfield manipulation
> - Minor doc edits
> - I dropped adding magic numbers to include/uapi/linux/magic.h. That
>   can be done later if appropriate
>
> Changes v6 -> v7
> - Fixed a regression in famfs_interleave_fileofs_to_daxofs() that
>   was reported by Intel's kernel test robot
> - Added a check in __fsdev_dax_direct_access() for negative return
>   from pgoff_to_phys(), which would indicate an out-of-range offset
> - Fixed a bug in __famfs_meta_free(), where not all interleaved
>   extents were freed
> - Added chunksize alignment checks in famfs_fuse_meta_alloc() and
>   famfs_interleave_fileofs_to_daxofs() as interleaved chunks must
>   be PTE or PMD aligned
> - Simplified famfs_file_init_dax() a bit
> - Re-ran CM's kernel code review prompts on the entire series and
>   fixed several minor issues
>
> Changes v4 -> v5 -> v6
> - None. Re-sending due to technical difficulties
>
> Changes v3 [9] -> v4
> - The patch "dax: prevent driver unbind while filesystem holds device"
>   has been dropped. Dan Williams indicated that the favored behavior is
>   for a file system to stop working if an underlying driver is unbound,
>   rather than preventing the unbind.
> - The patch "famfs_fuse: Famfs mount opt: -o shadow=<shadowpath>" has
>   been dropped. Found a way for the famfs user space to do without the
>   -o opt (via getxattr).
> - Squashed the fs/fuse/Kconfig patch into the first subsequent patch
>   that needed the change
>   ("famfs_fuse: Basic fuse kernel ABI enablement for famfs")
> - Many review comments addressed.
> - Addressed minor kerneldoc infractions reported by test robot.
>
> Changes v2 [7] -> v3
> - Dax: Completely new fsdev driver (drivers/dax/fsdev.c) replaces the
>   dev_dax_iomap modifications to bus.c/device.c. Devdax devices can now
>   be switched among 'devdax', 'famfs' and 'system-ram' modes via daxctl
>   or sysfs.
> - Dax: fsdev uses MEMORY_DEVICE_FS_DAX type and leaves folios at order-0
>   (no vmemmap_shift), allowing fs-dax to manage folio lifecycles
>   dynamically like pmem does.
> - Dax: The "poisoned page" problem is properly fixed via
>   fsdev_clear_folio_state(), which clears stale mapping/compound state
>   when fsdev binds. The temporary WARN_ON_ONCE workaround in fs/dax.c
>   has been removed.
> - Dax: Added dax_set_ops() so fsdev can set dax_operations at bind time
>   (and clear them on unbind), since the dax_device is created before we
>   know which driver will bind.
> - Dax: Added custom bind/unbind sysfs handlers; unbind return -EBUSY if a
>   filesystem holds the device, preventing unbind while famfs is mounted.
> - Fuse: Famfs mounts now require that the fuse server/daemon has
>   CAP_SYS_RAWIO because they expose raw memory devices.
> - Fuse: Added DAX address_space_operations with noop_dirty_folio since
>   famfs is memory-backed with no writeback required.
> - Rebased to latest kernels, fully compatible with Alistair Popple
>   et. al's recent dax refactoring.
> - Ran this series through Chris Mason's code review AI prompts to check
>   for issues - several subtle problems found and fixed.
> - Dropped RFC status - this version is intended to be mergeable.
>
> Changes v1 [8] -> v2:
>
> - The GET_FMAP message/response has been moved from LOOKUP to OPEN, as
>   was the pretty much unanimous consensus.
> - Made the response payload to GET_FMAP variable sized (patch 12)
> - Dodgy kerneldoc comments cleaned up or removed.
> - Fixed memory leak of fc->shadow in patch 11 (thanks Joanne)
> - Dropped many pr_debug and pr_notice calls
>
>
> References
>
> [0] - https://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git/
> [1] - https://famfs.org (famfs user space)
> [2] - https://lore.kernel.org/linux-cxl/cover.1708709155.git.john@groves.net/
> [3] - https://lore.kernel.org/linux-cxl/cover.1714409084.git.john@groves.net/
> [4] - https://lwn.net/Articles/983105/ (lsfmm 2024)
> [5] - https://lwn.net/Articles/1020170/ (lsfmm 2025)
> [6] - https://lore.kernel.org/linux-cxl/cover.8068ad144a7eea4a813670301f4d2a86a8e68ec4.1740713401.git-series.apopple@nvidia.com/
> [7] - https://lore.kernel.org/linux-fsdevel/20250703185032.46568-1-john@groves.net/ (famfs fuse v2)
> [8] - https://lore.kernel.org/linux-fsdevel/20250421013346.32530-1-john@groves.net/ (famfs fuse v1)
> [9] - https://lore.kernel.org/linux-fsdevel/20260107153244.64703-1-john@groves.net/T/#mb2c868801be16eca82dab239a1d201628534aea7 (famfs fuse v3)
>
>
> John Groves (10):
>   famfs_fuse: Update macro s/FUSE_IS_DAX/FUSE_IS_VIRTIO_DAX/
>   famfs_fuse: Basic fuse kernel ABI enablement for famfs
>   famfs_fuse: Plumb the GET_FMAP message/response
>   famfs_fuse: Create files with famfs fmaps
>   famfs_fuse: GET_DAXDEV message and daxdev_table
>   famfs_fuse: Plumb dax iomap and fuse read/write/mmap
>   famfs_fuse: Add holder_operations for dax notify_failure()
>   famfs_fuse: Add DAX address_space_operations with noop_dirty_folio
>   famfs_fuse: Add famfs fmap metadata documentation
>   famfs_fuse: Add documentation
>
>  Documentation/filesystems/famfs.rst |  142 ++++
>  Documentation/filesystems/index.rst |    1 +
>  MAINTAINERS                         |   10 +
>  fs/fuse/Kconfig                     |   13 +
>  fs/fuse/Makefile                    |    1 +
>  fs/fuse/dir.c                       |    2 +-
>  fs/fuse/famfs.c                     | 1180 +++++++++++++++++++++++++++
>  fs/fuse/famfs_kfmap.h               |  167 ++++
>  fs/fuse/file.c                      |   45 +-
>  fs/fuse/fuse_i.h                    |  116 ++-
>  fs/fuse/inode.c                     |   35 +-
>  fs/fuse/iomode.c                    |    2 +-
>  fs/namei.c                          |    1 +
>  include/uapi/linux/fuse.h           |   88 ++
>  14 files changed, 1790 insertions(+), 13 deletions(-)
>  create mode 100644 Documentation/filesystems/famfs.rst
>  create mode 100644 fs/fuse/famfs.c
>  create mode 100644 fs/fuse/famfs_kfmap.h
>
>
> base-commit: 2ae624d5a555d47a735fb3f4d850402859a4db77
> --
> 2.53.0
>

Hi John,

I’m curious to hear your thoughts on whether you think it makes sense
for the famfs-specific logic in this series to be moved to a bpf
program that goes through a generic fuse iomap dax layer.

Based on [1], this gives feature-parity with the famfs logic in this
series. In my opinion, having famfs go through a generic fuse iomap
dax layer makes the fuse kernel code more extensible for future
servers that will also want to use dax iomap, and keeps the fuse code
cleaner by not having famfs-specific logic hardcoded in and having to
introduce new fuse uapis for something famfs-specific. In my
understanding of it, fuse is meant to be generic and it feels like
adding server-specific logic goes against that design philosophy and
sets a precedent for other servers wanting similar special-casing in
the future. I'd like to explore whether the bpf and generic fuse iomap
dax layer approach can preserve that philosophy while still giving
famfs the flexibility it needs.

I think moving the famfs logic to bpf benefits famfs as well:
- Instead of needing to issue a FUSE_GET_FMAP request after a file is
opened, the server can directly populate the metadata map from
userspace with the mapping info when it processes the FUSE_OPEN
request, which gets rid of the roundtrip cost
- The server can dynamically update the metadata / bpf maps during
runtime from userspace if any mapping info needs to change
- Future code changes / updates for famfs are all server-side and can
be deployed immediately instead of needing to go through the upstream
kernel mailing list process
- Famfs updates / new releases can ship independently of kernel releases

I'd appreciate the chance to discuss tradeoffs or if you'd rather
discuss this at the fuse BoF at lsf, that sounds great too.

Thanks,
Joanne

[1] https://lore.kernel.org/linux-fsdevel/CAJnrk1YMqDKA5gDZasrxGjJtfdbhmjxX5uhUv=OSPyA=G5EE+Q@mail.gmail.com/

>

^ permalink raw reply

* [PATCH] checkpatch: add --json output mode
From: Sasha Levin @ 2026-04-06 17:00 UTC (permalink / raw)
  To: dwaipayanray1, lukas.bulwahn
  Cc: joe, corbet, skhan, apw, workflows, linux-doc, linux-kernel,
	Sasha Levin

Add a --json flag to checkpatch.pl that emits structured JSON output,
making results machine-parseable for CI systems, IDE integrations, and
AI-assisted code review tools.

The JSON output includes per-file totals (errors, warnings, checks,
lines) and an array of individual issues with structured fields for
level, type, message, file path, and line number.

The --json flag is mutually exclusive with --terse and --emacs.
Normal text output behavior is completely unchanged when --json is
not specified.

Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 Documentation/dev-tools/checkpatch.rst |  7 +++
 scripts/checkpatch.pl                  | 86 ++++++++++++++++++++++++--
 2 files changed, 87 insertions(+), 6 deletions(-)

diff --git a/Documentation/dev-tools/checkpatch.rst b/Documentation/dev-tools/checkpatch.rst
index dccede68698ca..17e5744d3dee6 100644
--- a/Documentation/dev-tools/checkpatch.rst
+++ b/Documentation/dev-tools/checkpatch.rst
@@ -64,6 +64,13 @@ Available options:
 
    Output only one line per report.
 
+ - --json
+
+   Output results as a JSON object.  The object includes total error, warning,
+   and check counts, plus an array of individual issues with structured fields
+   for level, type, message, file, and line number.  Cannot be used with
+   --terse or --emacs.
+
  - --showfile
 
    Show the diffed file position instead of the input file position.
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index e56374662ff79..ed70753ba1afc 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -33,6 +33,7 @@ my $chk_patch = 1;
 my $tst_only;
 my $emacs = 0;
 my $terse = 0;
+my $json = 0;
 my $showfile = 0;
 my $file = 0;
 my $git = 0;
@@ -93,6 +94,7 @@ Options:
   --patch                    treat FILE as patchfile (default)
   --emacs                    emacs compile window format
   --terse                    one line per report
+  --json                     output results as JSON
   --showfile                 emit diffed file position, not input file position
   -g, --git                  treat FILE as a single commit or git revision range
                              single git commit with:
@@ -320,6 +322,7 @@ GetOptions(
 	'patch!'	=> \$chk_patch,
 	'emacs!'	=> \$emacs,
 	'terse!'	=> \$terse,
+	'json!'		=> \$json,
 	'showfile!'	=> \$showfile,
 	'f|file!'	=> \$file,
 	'g|git!'	=> \$git,
@@ -379,6 +382,7 @@ help($help - 1) if ($help);
 
 die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix));
 die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse);
+die "$P: --json cannot be used with --terse or --emacs\n" if ($json && ($terse || $emacs));
 
 if ($color =~ /^[01]$/) {
 	$color = !$color;
@@ -1351,7 +1355,7 @@ for my $filename (@ARGV) {
 	}
 	close($FILE);
 
-	if ($#ARGV > 0 && $quiet == 0) {
+	if (!$json && $#ARGV > 0 && $quiet == 0) {
 		print '-' x length($vname) . "\n";
 		print "$vname\n";
 		print '-' x length($vname) . "\n";
@@ -1372,7 +1376,7 @@ for my $filename (@ARGV) {
 	$file = $oldfile if ($is_git_file);
 }
 
-if (!$quiet) {
+if (!$quiet && !$json) {
 	hash_show_words(\%use_type, "Used");
 	hash_show_words(\%ignore_type, "Ignored");
 
@@ -2395,6 +2399,18 @@ sub report {
 
 	push(our @report, $output);
 
+	if ($json) {
+		our ($realfile, $realline);
+		my %issue = (
+			level => $level,
+			type => $type,
+			message => $msg,
+		);
+		$issue{file} = $realfile if (defined $realfile && $realfile ne '');
+		$issue{line} = $realline + 0 if (defined $realline && $realline);
+		push(our @json_issues, \%issue);
+	}
+
 	return 1;
 }
 
@@ -2402,6 +2418,34 @@ sub report_dump {
 	our @report;
 }
 
+sub json_escape {
+	my ($str) = @_;
+	$str =~ s/\\/\\\\/g;
+	$str =~ s/"/\\"/g;
+	$str =~ s/\n/\\n/g;
+	$str =~ s/\r/\\r/g;
+	$str =~ s/\t/\\t/g;
+	$str =~ s/\x08/\\b/g;
+	$str =~ s/\x0c/\\f/g;
+	$str =~ s/([\x00-\x07\x0b\x0e-\x1f])/sprintf("\\u%04x", ord($1))/ge;
+	return $str;
+}
+
+sub json_encode_issue {
+	my ($issue) = @_;
+	my @fields;
+	push(@fields, '"level":"' . json_escape($issue->{level}) . '"');
+	push(@fields, '"type":"' . json_escape($issue->{type}) . '"');
+	push(@fields, '"message":"' . json_escape($issue->{message}) . '"');
+	if (defined $issue->{file}) {
+		push(@fields, '"file":"' . json_escape($issue->{file}) . '"');
+	}
+	if (defined $issue->{line}) {
+		push(@fields, '"line":' . ($issue->{line} + 0));
+	}
+	return '{' . join(',', @fields) . '}';
+}
+
 sub fixup_current_range {
 	my ($lineRef, $offset, $length) = @_;
 
@@ -2690,14 +2734,15 @@ sub process {
 	my $last_coalesced_string_linenr = -1;
 
 	our @report = ();
+	our @json_issues = ();
 	our $cnt_lines = 0;
 	our $cnt_error = 0;
 	our $cnt_warn = 0;
 	our $cnt_chk = 0;
 
 	# Trace the real file/line as we go.
-	my $realfile = '';
-	my $realline = 0;
+	our $realfile = '';
+	our $realline = 0;
 	my $realcnt = 0;
 	my $here = '';
 	my $context_function;		#undef'd unless there's a known function
@@ -7791,18 +7836,33 @@ sub process {
 	# If we have no input at all, then there is nothing to report on
 	# so just keep quiet.
 	if ($#rawlines == -1) {
+		if ($json) {
+			print '{"filename":"' . json_escape($filename) .
+			      '","total_errors":0,"total_warnings":0,' .
+			      '"total_checks":0,"total_lines":0,"issues":[]}' . "\n";
+		}
 		exit(0);
 	}
 
 	# In mailback mode only produce a report in the negative, for
 	# things that appear to be patches.
 	if ($mailback && ($clean == 1 || !$is_patch)) {
+		if ($json) {
+			print '{"filename":"' . json_escape($filename) .
+			      '","total_errors":0,"total_warnings":0,' .
+			      '"total_checks":0,"total_lines":0,"issues":[]}' . "\n";
+		}
 		exit(0);
 	}
 
 	# This is not a patch, and we are in 'no-patch' mode so
 	# just keep quiet.
 	if (!$chk_patch && !$is_patch) {
+		if ($json) {
+			print '{"filename":"' . json_escape($filename) .
+			      '","total_errors":0,"total_warnings":0,' .
+			      '"total_checks":0,"total_lines":0,"issues":[]}' . "\n";
+		}
 		exit(0);
 	}
 
@@ -7850,6 +7910,19 @@ sub process {
 		}
 	}
 
+	if ($json) {
+		my @issue_strings;
+		foreach my $issue (@json_issues) {
+			push(@issue_strings, json_encode_issue($issue));
+		}
+		print '{"filename":"' . json_escape($filename) . '",' .
+		      '"total_errors":' . ($cnt_error + 0) . ',' .
+		      '"total_warnings":' . ($cnt_warn + 0) . ',' .
+		      '"total_checks":' . ($cnt_chk + 0) . ',' .
+		      '"total_lines":' . ($cnt_lines + 0) . ',' .
+		      '"issues":[' . join(',', @issue_strings) . ']' .
+		      '}' . "\n";
+	} else {
 	print report_dump();
 	if ($summary && !($clean == 1 && $quiet == 1)) {
 		print "$filename " if ($summary_file);
@@ -7878,8 +7951,9 @@ NOTE: Whitespace errors detected.
 EOM
 		}
 	}
+	} # end !$json
 
-	if ($clean == 0 && $fix &&
+	if (!$json && $clean == 0 && $fix &&
 	    ("@rawlines" ne "@fixed" ||
 	     $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) {
 		my $newfile = $filename;
@@ -7918,7 +7992,7 @@ EOM
 		}
 	}
 
-	if ($quiet == 0) {
+	if (!$json && $quiet == 0) {
 		print "\n";
 		if ($clean == 1) {
 			print "$vname has no obvious style problems and is ready for submission.\n";
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH net-next V4 10/12] devlink: Add resource scope filtering to resource dump
From: Or Har-Toov @ 2026-04-06 16:18 UTC (permalink / raw)
  To: Jakub Kicinski, Tariq Toukan
  Cc: Eric Dumazet, Paolo Abeni, Andrew Lunn, David S. Miller,
	Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Mark Bloch,
	Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0), Carolina Jubran,
	Moshe Shemesh, Dragos Tatulea, Shahar Shitrit, Daniel Zahka,
	Jacob Keller, Cosmin Ratiu, Parav Pandit, Shay Drori,
	Adithya Jayachandran, Kees Cook, Daniel Jurgens, netdev,
	linux-kernel, linux-doc, linux-rdma, linux-kselftest,
	Gal Pressman
In-Reply-To: <20260402190219.61ea7da1@kernel.org>



On 03/04/2026 5:02, Jakub Kicinski wrote:
> 
> On Wed, 1 Apr 2026 21:49:45 +0300 Tariq Toukan wrote:
>> @@ -873,6 +881,16 @@ attribute-sets:
>>           doc: Unique devlink instance index.
>>           checks:
>>             max: u32-max
>> +      -
>> +        name: resource-scope-mask
>> +        type: bitfield32
> 
> no need for a bitfield here, this is a simpler selector
> bitfield is for cases when we need to update some persistent
> state, in that case we want to indicate which bits we intend
> to update:
> 
>          cfg = (cfg & ~bf.mask) | bf.val
> 
> scope is a straight attribute, there's no updating of anything.
> 
> u32 or unit would do

ack, will use u32 for resource scope mask

> 
>> +        enum: resource-scope
>> +        enum-as-flags: true
>> +        doc: |
>> +          Bitmask selecting which resource classes to include in a
>> +          resource-dump response. Bit 0 (dev) selects device-level
>> +          resources; bit 1 (port) selects port-level resources.
>> +          When absent all classes are returned.
>>     -
>>       name: dl-dev-stats
>>       subset-of: devlink
>> @@ -1775,7 +1793,11 @@ operations:
>>               - resource-list
>>         dump:
>>           request:
>> -          attributes: *dev-id-attrs
>> +          attributes:
>> +            - bus-name
>> +            - dev-name
>> +            - index
>> +            - resource-scope-mask
>>           reply: *resource-dump-reply
>>
>>       -
>> diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
>> index 7de2d8cc862f..e0a0b523ce5c 100644
>> --- a/include/uapi/linux/devlink.h
>> +++ b/include/uapi/linux/devlink.h
>> @@ -645,6 +645,7 @@ enum devlink_attr {
>>        DEVLINK_ATTR_PARAM_RESET_DEFAULT,       /* flag */
>>
>>        DEVLINK_ATTR_INDEX,                     /* uint */
>> +     DEVLINK_ATTR_RESOURCE_SCOPE_MASK,       /* bitfield32 */
>>
>>        /* Add new attributes above here, update the spec in
>>         * Documentation/netlink/specs/devlink.yaml and re-generate
>> @@ -704,6 +705,22 @@ enum devlink_resource_unit {
>>        DEVLINK_RESOURCE_UNIT_ENTRY,
>>   };
>>
>> +enum devlink_resource_scope {
>> +     DEVLINK_RESOURCE_SCOPE_DEV_BIT,
>> +     DEVLINK_RESOURCE_SCOPE_PORT_BIT,
>> +
>> +     __DEVLINK_RESOURCE_SCOPE_MAX_BIT,
>> +     DEVLINK_RESOURCE_SCOPE_MAX_BIT =
> 
> do we need this? it's not an attr enum all we care about here is
> the mask, really so just a trailing value which is max real value + 1
> is enough for all users?
> 

ok, can manage without max at all, can manage also without 
DEVLINK_RESOURCE_SCOPE_VALID_MASK

>> +             __DEVLINK_RESOURCE_SCOPE_MAX_BIT - 1
>> +};
>> +
>> +#define DEVLINK_RESOURCE_SCOPE_DEV \
>> +     _BITUL(DEVLINK_RESOURCE_SCOPE_DEV_BIT)
>> +#define DEVLINK_RESOURCE_SCOPE_PORT \
>> +     _BITUL(DEVLINK_RESOURCE_SCOPE_PORT_BIT)
>> +#define DEVLINK_RESOURCE_SCOPE_VALID_MASK \
>> +     (_BITUL(__DEVLINK_RESOURCE_SCOPE_MAX_BIT) - 1)
>> +
>>   enum devlink_port_fn_attr_cap {
>>        DEVLINK_PORT_FN_ATTR_CAP_ROCE_BIT,
>>        DEVLINK_PORT_FN_ATTR_CAP_MIGRATABLE_BIT,
> 
>> +static u32 devlink_resource_scope_get(struct nlattr **attrs, int *flags)
>> +{
>> +     struct nla_bitfield32 scope;
>> +     u32 value;
>> +
>> +     if (!attrs || !attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK])
>> +             return DEVLINK_RESOURCE_SCOPE_VALID_MASK;
>> +
>> +     scope = nla_get_bitfield32(attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK]);
>> +     value = scope.value & scope.selector;
>> +     if (value != DEVLINK_RESOURCE_SCOPE_VALID_MASK)
>> +             *flags |= NLM_F_DUMP_FILTERED;
>> +
>> +     return value;
>> +}
>> +
>>   static int
>>   devlink_resource_dump_fill_one(struct sk_buff *skb, struct devlink *devlink,
>>                               struct devlink_port *devlink_port,
>> @@ -400,16 +416,27 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
>>        struct devlink_nl_dump_state *state = devlink_dump_state(cb);
>>        struct devlink_port *devlink_port;
>>        unsigned long port_idx;
>> +     u32 scope;
>>        int err;
>>
>> -     if (!state->port_number) {
>> +     scope = devlink_resource_scope_get(genl_info_dump(cb)->attrs, &flags);
>> +     if (!scope) {
>> +             NL_SET_ERR_MSG_ATTR(genl_info_dump(cb)->extack,
>> +                                 genl_info_dump(cb)->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK],
> 
> we have genl_info_dump(cb) 3 times here, let's save the pointer
> on the stack to make the lines shorter.
> 

ack

>> +                                 "empty resource scope selection");
>> +             return -EINVAL;
>> +     }
>> +     if (!state->port_number && (scope & DEVLINK_RESOURCE_SCOPE_DEV)) {
>>                err = devlink_resource_dump_fill_one(skb, devlink, NULL,
>> -                                                  cb, flags, &state->idx);
>> +                                                  cb, flags,
>> +                                                  &state->idx);
>>                if (err)
>>                        return err;
>>                state->idx = 0;
>>        }
>>
>> +     if (!(scope & DEVLINK_RESOURCE_SCOPE_PORT))
>> +             goto out;
>>        xa_for_each_start(&devlink->ports, port_idx, devlink_port,
>>                          state->port_number ? state->port_number - 1 : 0) {
>>                err = devlink_resource_dump_fill_one(skb, devlink, devlink_port,
>> @@ -420,6 +447,7 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
>>                }
>>                state->idx = 0;
>>        }
>> +out:
>>        state->port_number = 0;
>>        return 0;
>>   }
> 


^ permalink raw reply

* Re: [PATCH v3 02/24] PCI: Add API to track PCI devices preserved across Live Update
From: David Matlack @ 2026-04-06 16:06 UTC (permalink / raw)
  To: Zhu Yanjun
  Cc: Alex Williamson, Bjorn Helgaas, Adithya Jayachandran,
	Alexander Graf, Alex Mastro, Andrew Morton, Ankit Agrawal,
	Arnd Bergmann, Askar Safin, Borislav Petkov (AMD), Chris Li,
	Dapeng Mi, David Rientjes, Feng Tang, Jacob Pan, Jason Gunthorpe,
	Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Kees Cook,
	Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
	linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
	Li RongQing, Lukas Wunner, Marco Elver, Michał Winiarski,
	Mike Rapoport, Parav Pandit, Pasha Tatashin, Paul E. McKenney,
	Pawan Gupta, Peter Zijlstra (Intel), Pranjal Shrivastava,
	Pratyush Yadav, Raghavendra Rao Ananta, Randy Dunlap,
	Rodrigo Vivi, Saeed Mahameed, Samiullah Khawaja, Shuah Khan,
	Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu
In-Reply-To: <c4138f66-edf2-4689-b5fe-16dc4839e9c3@linux.dev>

On Sun, Apr 5, 2026 at 9:56 AM Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
> 在 2026/4/3 14:58, David Matlack 写道:
> > On Thu, Apr 2, 2026 at 2:29 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
> >> On 3/23/26 4:57 PM, David Matlack wrote:
> >>> +config PCI_LIVEUPDATE
> >>> +     bool "PCI Live Update Support (EXPERIMENTAL)"
> >>> +     depends on PCI && LIVEUPDATE
> >>> +     help
> >>> +       Support for preserving PCI devices across a Live Update. This option
> >>> +       should only be enabled by developers working on implementing this
> >>> +       support. Once enough support as landed in the kernel, this option
> >>> +       will no longer be marked EXPERIMENTAL.
> >>> +
> >>> +       If unsure, say N.
> >> Currently, it only supports 'n' or 'y'. Is it possible to add 'm'
> >> (modular support)?
> >>
> >> This would allow the feature to be built as a kernel module. For
> >> development
> >>
> >> purposes, modularization means we only need to recompile a single module
> >>
> >> for testing, rather than rebuilding the entire kernel. Compiling a
> >> module should
> >>
> >> be significantly faster than a full kernel build.
> > I don't think it is possible for CONFIG_PCI_LIVEUPDATE to support 'm'.
> > pci_setup_device() (which is under CONFIG_PCI) needs to call
> > pci_liveupdate_setup_device(), and CONFIG_PCI cannot be built as a
> > module. This call is necessary so the PCI core knows whether a device
> > being enumerated was preserved across a previous Live Update.
>
> After the following changes, the liveupdate.ko can be generated
> successfully.

Sure but you've broken the feature. Now devices can be probed before
liveupdate.ko is loaded and the PCI core will have an incorrect view
of which devices were preserved by the previous kernel.

^ permalink raw reply

* Re: [PATCH v2 07/33] rust: allow globally `clippy::incompatible_msrv`
From: Tamir Duberstein @ 2026-04-06 15:30 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Miguel Ojeda, Nathan Chancellor, Nicolas Schier, Danilo Krummrich,
	Andreas Hindborg, Catalin Marinas, Will Deacon, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Courbot, David Airlie,
	Simona Vetter, Brendan Higgins, David Gow, Greg Kroah-Hartman,
	Arve Hjønnevåg, Todd Kjos, Christian Brauner,
	Carlos Llamas, Alice Ryhl, Jonathan Corbet, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Trevor Gross, rust-for-linux,
	linux-kbuild, Lorenzo Stoakes, Vlastimil Babka, Liam R . Howlett,
	Uladzislau Rezki, linux-block, linux-arm-kernel, Alexandre Ghiti,
	linux-riscv, nouveau, dri-devel, Rae Moar, linux-kselftest,
	kunit-dev, Nick Desaulniers, Bill Wendling, Justin Stitt, llvm,
	linux-kernel, Shuah Khan, linux-doc
In-Reply-To: <CANiq72ne_JYPodnROckyNto10ZF0PqadRxSrng5-mZyqVovxFg@mail.gmail.com>

On Mon, Apr 6, 2026 at 10:38 AM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Mon, Apr 6, 2026 at 4:29 PM Tamir Duberstein <tamird@kernel.org> wrote:
> >
> > Could you add a reference to the upstream bug report [0] here?
>
> Of course, thanks for the tags!

You're welcome! Actually it seems the lint was already improved
upstream, starting with 1.90.0.

Link: https://github.com/rust-lang/rust-clippy/commit/c0dc3b61 [0]

^ permalink raw reply

* [PATCH] kconfig: add optional warnings for changed input values
From: Pengpeng Hou @ 2026-04-06 15:06 UTC (permalink / raw)
  To: Nathan Chancellor, Nicolas Schier, Masahiro Yamada, linux-kbuild
  Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Thomas Meyer,
	Miguel Ojeda, linux-doc, linux-kernel, pengpeng

When reading .config input, Kconfig stores user-provided values first and
then resolves the final value after applying dependencies, ranges, and
other constraints.

If the final value differs from the user's input, Kconfig already tracks
that state internally, but it does not provide any focused diagnostic to
show which explicit inputs were adjusted. This is particularly confusing
for requested values that get forced down by unmet dependencies or clamped
by ranges.

Add an opt-in diagnostic controlled by KCONFIG_WARN_CHANGED_INPUT.
Emit the warnings from conf_write() and conf_write_defconfig() after
value resolution and through the existing message callback path so the
default behavior stays unchanged and interactive frontends remain usable.

Document the new environment variable and add tests for both olddefconfig
and savedefconfig.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
 Documentation/kbuild/kconfig.rst         |  5 ++
 scripts/kconfig/confdata.c               | 94 +++++++++++++++++++++++++++++++-
 .../tests/warn_changed_input/Kconfig     | 27 +++++++++
 .../tests/warn_changed_input/__init__.py | 27 +++++++++
 .../tests/warn_changed_input/config      |  2 +
 .../warn_changed_input/expected_config   |  6 ++
 .../expected_defconfig                   |  1 +
 .../warn_changed_input/expected_stdout   |  3 +
 8 files changed, 162 insertions(+), 3 deletions(-)

diff --git a/Documentation/kbuild/kconfig.rst b/Documentation/kbuild/kconfig.rst
index d213c4f599a4..e35dd1d5f9d3 100644
--- a/Documentation/kbuild/kconfig.rst
+++ b/Documentation/kbuild/kconfig.rst
@@ -59,6 +59,11 @@ Environment variables for ``*config``:
     This environment variable makes Kconfig warn about all unrecognized
     symbols in the config input.
 
+``KCONFIG_WARN_CHANGED_INPUT``
+    If set to a non-blank value, Kconfig prints optional warnings for
+    user-provided values that change after Kconfig resolves dependencies
+    or applies other constraints such as ranges.
+
 ``KCONFIG_WERROR``
     If set, Kconfig treats warnings as errors.
 
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 9599a0408862..bcbac5a204e9 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -206,6 +206,72 @@ static void conf_message(const char *fmt, ...)
 	va_end(ap);
 }
 
+static bool conf_warn_changed_input_enabled(void)
+{
+	const char *env = getenv("KCONFIG_WARN_CHANGED_INPUT");
+
+	return env && *env;
+}
+
+static const char *sym_get_user_value_string(struct symbol *sym)
+{
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (sym->def[S_DEF_USER].tri) {
+		case yes:
+			return "y";
+		case mod:
+			return "m";
+		default:
+			return "n";
+		}
+	default:
+		return sym->def[S_DEF_USER].val ?: "";
+	}
+}
+
+static bool sym_user_value_changed(struct symbol *sym)
+{
+	if (!sym_has_value(sym) || sym->type == S_UNKNOWN)
+		return false;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		return sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym);
+	default:
+		return strcmp(sym_get_user_value_string(sym),
+			      sym_get_string_value(sym));
+	}
+}
+
+static void conf_clear_written_flags(void)
+{
+	struct symbol *sym;
+
+	for_all_symbols(sym)
+		sym->flags &= ~SYMBOL_WRITTEN;
+}
+
+static void conf_append_changed_input_warning(struct gstr *gs,
+					      struct symbol *sym, bool *found)
+{
+	if (!sym_user_value_changed(sym))
+		return;
+
+	if (!*found) {
+		str_printf(gs,
+			   "warning: user-provided values changed by Kconfig:\n");
+		*found = true;
+	}
+
+	str_printf(gs, "  %s%s: %s -> %s\n",
+		   CONFIG_, sym->name,
+		   sym_get_user_value_string(sym),
+		   sym_get_string_value(sym));
+}
+
 const char *conf_get_configname(void)
 {
 	char *name = getenv("KCONFIG_CONFIG");
@@ -759,7 +825,10 @@ int conf_write_defconfig(const char *filename)
 {
 	struct symbol *sym;
 	struct menu *menu;
+	struct gstr gs = str_new();
 	FILE *out;
+	bool warn_changed_input = conf_warn_changed_input_enabled();
+	bool found = false;
 
 	out = fopen(filename, "w");
 	if (!out)
@@ -772,10 +841,13 @@ int conf_write_defconfig(const char *filename)
 
 		sym = menu->sym;
 
-		if (!sym || sym_is_choice(sym))
+		if (!sym || sym_is_choice(sym) || sym->flags & SYMBOL_WRITTEN)
 			continue;
 
 		sym_calc_value(sym);
+		if (warn_changed_input)
+			conf_append_changed_input_warning(&gs, sym, &found);
+		sym->flags |= SYMBOL_WRITTEN;
 		if (!(sym->flags & SYMBOL_WRITE))
 			continue;
 		sym->flags &= ~SYMBOL_WRITE;
@@ -798,6 +870,13 @@ int conf_write_defconfig(const char *filename)
 		print_symbol_for_dotconfig(out, sym);
 	}
 	fclose(out);
+
+	conf_clear_written_flags();
+
+	if (found)
+		conf_message("%s", str_get(&gs));
+
+	str_free(&gs);
 	return 0;
 }
 
@@ -809,7 +888,10 @@ int conf_write(const char *name)
 	const char *str;
 	char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
 	char *env;
+	struct gstr gs = str_new();
 	bool need_newline = false;
+	bool warn_changed_input = conf_warn_changed_input_enabled();
+	bool found = false;
 
 	if (!name)
 		name = conf_get_configname();
@@ -859,6 +941,8 @@ int conf_write(const char *name)
 		} else if (!sym_is_choice(sym) &&
 			   !(sym->flags & SYMBOL_WRITTEN)) {
 			sym_calc_value(sym);
+			if (warn_changed_input)
+				conf_append_changed_input_warning(&gs, sym, &found);
 			if (!(sym->flags & SYMBOL_WRITE))
 				goto next;
 			if (need_newline) {
@@ -892,8 +976,12 @@ int conf_write(const char *name)
 	}
 	fclose(out);
 
-	for_all_symbols(sym)
-		sym->flags &= ~SYMBOL_WRITTEN;
+	conf_clear_written_flags();
+
+	if (found)
+		conf_message("%s", str_get(&gs));
+
+	str_free(&gs);
 
 	if (*tmpname) {
 		if (is_same(name, tmpname)) {
diff --git a/scripts/kconfig/tests/warn_changed_input/Kconfig b/scripts/kconfig/tests/warn_changed_input/Kconfig
new file mode 100644
index 000000000000..4b749eccbe28
--- /dev/null
+++ b/scripts/kconfig/tests/warn_changed_input/Kconfig
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config DEP
+	bool "DEP"
+	help
+	  Test dependency symbol for Kconfig warning coverage.
+	  This is used by the warn_changed_input selftest.
+	  It intentionally stays unset in the input fragment.
+	  The test checks how dependent user input is adjusted.
+
+config A
+	bool "A"
+	depends on DEP
+	help
+	  Test bool symbol for changed-input diagnostics.
+	  The input fragment requests this symbol as built-in.
+	  The unmet dependency on DEP forces the final value to n.
+	  The warning should report that downgrade.
+
+config NUM
+	int "NUM"
+	range 10 20
+	help
+	  Test integer symbol for changed-input diagnostics.
+	  The input fragment requests a value outside the allowed range.
+	  Kconfig resolves it to the constrained in-range value.
+	  The warning should report that adjustment.
diff --git a/scripts/kconfig/tests/warn_changed_input/__init__.py b/scripts/kconfig/tests/warn_changed_input/__init__.py
new file mode 100644
index 000000000000..5a2b68fb1033
--- /dev/null
+++ b/scripts/kconfig/tests/warn_changed_input/__init__.py
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Test optional warnings for user-provided values changed by Kconfig.
+
+Warnings should stay disabled by default, and should only appear when
+KCONFIG_WARN_CHANGED_INPUT is enabled.
+"""
+
+
+def test(conf):
+    assert conf.olddefconfig('config') == 0
+    assert 'user-provided values changed by Kconfig' not in conf.stdout
+
+    assert conf._run_conf('--olddefconfig', dot_config='config',
+                          extra_env={
+                              'KCONFIG_WARN_CHANGED_INPUT': '1',
+                          }) == 0
+    assert conf.stdout_contains('expected_stdout')
+    assert conf.config_matches('expected_config')
+
+    assert conf._run_conf('--savedefconfig=defconfig', dot_config='config',
+                          out_file='defconfig',
+                          extra_env={
+                              'KCONFIG_WARN_CHANGED_INPUT': '1',
+                          }) == 0
+    assert conf.stdout_contains('expected_stdout')
+    assert conf.config_matches('expected_defconfig')
diff --git a/scripts/kconfig/tests/warn_changed_input/config b/scripts/kconfig/tests/warn_changed_input/config
new file mode 100644
index 000000000000..91156997e58d
--- /dev/null
+++ b/scripts/kconfig/tests/warn_changed_input/config
@@ -0,0 +1,2 @@
+CONFIG_A=y
+CONFIG_NUM=30
diff --git a/scripts/kconfig/tests/warn_changed_input/expected_config b/scripts/kconfig/tests/warn_changed_input/expected_config
new file mode 100644
index 000000000000..fe8bbec66c53
--- /dev/null
+++ b/scripts/kconfig/tests/warn_changed_input/expected_config
@@ -0,0 +1,6 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+# CONFIG_DEP is not set
+CONFIG_NUM=20
diff --git a/scripts/kconfig/tests/warn_changed_input/expected_defconfig b/scripts/kconfig/tests/warn_changed_input/expected_defconfig
new file mode 100644
index 000000000000..af9e34851d2a
--- /dev/null
+++ b/scripts/kconfig/tests/warn_changed_input/expected_defconfig
@@ -0,0 +1 @@
+CONFIG_NUM=20
diff --git a/scripts/kconfig/tests/warn_changed_input/expected_stdout b/scripts/kconfig/tests/warn_changed_input/expected_stdout
new file mode 100644
index 000000000000..83ca08b7187f
--- /dev/null
+++ b/scripts/kconfig/tests/warn_changed_input/expected_stdout
@@ -0,0 +1,3 @@
+warning: user-provided values changed by Kconfig:
+  CONFIG_A: y -> n
+  CONFIG_NUM: 30 -> 20
-- 
2.50.1 (Apple Git-155)



^ permalink raw reply related

* Re: [PATCH v5 0/3] PCI Controller event and LTSSM tracepoint support
From: Steven Rostedt @ 2026-04-06 15:08 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Shawn Lin, Bjorn Helgaas, linux-rockchip, linux-pci,
	linux-trace-kernel, linux-doc
In-Reply-To: <u2dh2os5qyuuv636uwzttvohfyics7tvqiobheftjzdnuegq33@n77svn2nlqu2>

On Sat, 4 Apr 2026 22:23:32 +0530
Manivannan Sadhasivam <mani@kernel.org> wrote:

> On Wed, Mar 25, 2026 at 09:58:29AM +0800, Shawn Lin wrote:
> > 
> > This patch-set adds new pci controller event and LTSSM tracepoint used by host drivers
> > which provide LTSSM trace functionality. The first user is pcie-dw-rockchip with a 256
> > Bytes FIFO for recording LTSSM transition.
> >   
> 
> Steve, could you please take a look at the tracing part?

I already have but didn't say anything because I didn't find anything ;-)

Anyway, for the tracing part:

Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>

-- Steve

^ permalink raw reply

* Re: [PATCH v6 4/4] iio: adc: ad4691: add SPI offload support
From: David Lechner @ 2026-04-06 15:02 UTC (permalink / raw)
  To: Sabau, Radu bogdan, Lars-Peter Clausen, Hennerich, Michael,
	Jonathan Cameron, Sa, Nuno, Andy Shevchenko, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Uwe Kleine-König,
	Liam Girdwood, Mark Brown, Linus Walleij, Bartosz Golaszewski,
	Philipp Zabel, Jonathan Corbet, Shuah Khan
  Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org
In-Reply-To: <LV9PR03MB8414CB15DEC3EBBDB8F5FDD0F75DA@LV9PR03MB8414.namprd03.prod.outlook.com>

On 4/6/26 9:16 AM, Sabau, Radu bogdan wrote:
> 
> 
>> -----Original Message-----
>> From: David Lechner <dlechner@baylibre.com>
>> Sent: Monday, April 6, 2026 4:44 PM
> 
> ...
> 
>>>
>>> This is bad documentation on my part. "channel byte" isn't used anymore,
>>> this is previous version behaviour. Right now, only 16-bits worth of actual
>>> channel data are used.
>>>
>> Then why do we need the shift if there is no other data? Can't we rework
>> the SPI message so that there is no shift?
> 
> I thought the shift is needed since DMA size is 32 bits, and value comes on the
> upper word 16 bits, not on the lower ones as for CNV Burst.

That should only happen if we are reading 32-bits instead of 16 bits.
We should be able to set up the SPI xfers so that we only read 16 bits.

> 
> Manual Mode layout: TX [CMD_HI CMD_LO DUMMY DUMMY], RX [DATA_HI DATA_LO DUMMY DUMMY]

> CNV Burst layout: TX [REG_HI REG_LO DUMMY DUMMY], RX [DUMMY DUMMY DATA_HI DATA_LO]

This can be split in two xfers.

CNV Burst layout:
	TX [REG_HI REG_LO]
	RX [DATA_HI DATA_LO]

And we could even set bits_per_word to 16 so that the data is CPU
endian instead of big endian when doing SPI offloading.


^ permalink raw reply

* Re: [PATCH RESEND v10 0/8] ACPI: Unify CPU UID interface and fix ARM64 TPH steer-tag issue
From: Rafael J. Wysocki @ 2026-04-06 14:58 UTC (permalink / raw)
  To: Chengwen Feng
  Cc: Bjorn Helgaas, Catalin Marinas, Will Deacon, Rafael J . Wysocki,
	Jonathan Corbet, WANG Xuerui, Thomas Gleixner, Dave Hansen,
	H . Peter Anvin, Juergen Gross, Boris Ostrovsky, Len Brown,
	Sunil V L, Mark Rutland, Jonathan Cameron, Kees Cook, Yanteng Si,
	Sean Christopherson, Kai Huang, Tom Lendacky, Thomas Huth,
	Thorsten Blum, Kevin Loughlin, Zheyun Shen, Peter Zijlstra,
	Pawan Gupta, Xin Li, Ahmed S . Darwish, Sohil Mehta,
	Ilkka Koskinen, Robin Murphy, James Clark, Besar Wicaksono, Ma Ke,
	Wei Huang, Andy Gospodarek, Somnath Kotur, punit.agrawal,
	guohanjun, suzuki.poulose, ryan.roberts, chenl311, masahiroy,
	wangyuquan1236, anshuman.khandual, heinrich.schuchardt,
	Eric.VanTassell, wangzhou1, wanghuiqiang, liuyonglong, linux-pci,
	linux-doc, linux-kernel, linux-arm-kernel, loongarch, linux-riscv,
	xen-devel, linux-acpi, linux-perf-users, stable, x86
In-Reply-To: <20260401081640.26875-1-fengchengwen@huawei.com>

On Wed, Apr 1, 2026 at 10:16 AM Chengwen Feng <fengchengwen@huawei.com> wrote:
>
> This patchset unifies ACPI Processor UID retrieval across
> arm64/loongarch/riscv/x86 via acpi_get_cpu_uid() (with input validation)
> and fixes ARM64 CPU steer-tag retrieval failure in PCI/TPH:
>
> 1-4: Add acpi_get_cpu_uid() for arm64/loongarch/riscv/x86 (update
>      respective users)
> 5: Centralize acpi_get_cpu_uid() declaration in include/linux/acpi.h
> 6: Clean up perf/arm_cspmu
> 7: Clean up ACPI/PPTT and remove unused get_acpi_id_for_cpu()
> 8: Pass ACPI Processor UID to Cache Locality _DSM
>
> The interface refactor ensures consistent CPU UID retrieval across
> architectures (no functional changes for valid inputs) and provides the
> unified interface required for the ARM64 TPH fix
>
> ---
> Changes in v10-resend:
> - Add Catalin's ack-by for arm64 commit
> - Add CC to x86@kernel.org
>
> Changes in v10:
> - Refine commit header&log according to Punit's and Bjorn's review
> - Split perf/arm_cspmu as a separate commit which address Punit's
>   review
>
> Changes in v9:
> - Address Bjorn's review: split commits to each platform so that make
>   them easy to review
>
> Changes in v8:
> - Moving arm64's get_cpu_for_acpi_id() to kernel/acpi.c which address
>   Jeremy's review
>
> Chengwen Feng (8):
>   arm64: acpi: Add acpi_get_cpu_uid() for unified ACPI CPU UID retrieval
>   LoongArch: Add acpi_get_cpu_uid() for unified ACPI CPU UID retrieval
>   RISC-V: ACPI: Add acpi_get_cpu_uid() for unified ACPI CPU UID
>     retrieval
>   x86/acpi: Add acpi_get_cpu_uid() for unified ACPI CPU UID retrieval
>   ACPI: Centralize acpi_get_cpu_uid() declaration in
>     include/linux/acpi.h
>   perf: arm_cspmu: Switch to acpi_get_cpu_uid() from
>     get_acpi_id_for_cpu()
>   ACPI: PPTT: Use acpi_get_cpu_uid() and remove get_acpi_id_for_cpu()
>   PCI/TPH: Pass ACPI Processor UID to Cache Locality _DSM
>
>  Documentation/PCI/tph.rst          |  4 +--
>  arch/arm64/include/asm/acpi.h      | 17 +---------
>  arch/arm64/kernel/acpi.c           | 30 ++++++++++++++++++
>  arch/loongarch/include/asm/acpi.h  |  5 ---
>  arch/loongarch/kernel/acpi.c       |  9 ++++++
>  arch/riscv/include/asm/acpi.h      |  4 ---
>  arch/riscv/kernel/acpi.c           | 16 ++++++++++
>  arch/riscv/kernel/acpi_numa.c      |  9 ++++--
>  arch/x86/include/asm/cpu.h         |  1 -
>  arch/x86/include/asm/smp.h         |  1 -
>  arch/x86/kernel/acpi/boot.c        | 20 ++++++++++++
>  arch/x86/xen/enlighten_hvm.c       |  5 +--
>  drivers/acpi/pptt.c                | 50 ++++++++++++++++++++++--------
>  drivers/acpi/riscv/rhct.c          |  7 ++++-
>  drivers/pci/tph.c                  | 16 +++++++---
>  drivers/perf/arm_cspmu/arm_cspmu.c |  6 ++--
>  include/linux/acpi.h               | 11 +++++++
>  include/linux/pci-tph.h            |  4 +--
>  18 files changed, 158 insertions(+), 57 deletions(-)
>
> --

Applied as 7.1 material, but please note that I haven't tagged it
explicitly for "stable".

The last patch carries a Fixes: tag which should be suitable for
"stable" to pick it up and you may as well request the whole series to
be picked up by "stable" when it hits the mainline.

Thanks!

^ permalink raw reply

* Re: [RFC net-next 15/15] Documentation: networking: add ipxlat translator guide
From: Xavier Hsinyuan @ 2026-04-06 14:50 UTC (permalink / raw)
  To: ralf
  Cc: antonio, corbet, davem, dxld, edumazet, horms, kuba, linux-doc,
	linux-kernel, netdev, pabeni, skhan
In-Reply-To: <20260319151230.655687-16-ralf@mandelbit.com>

Hi Ralf,

>+    $ ./tools/net/ynl/pyynl/cli.py --family ipxlat --json '{"ifindex": $IID, \
>+        "config": {"xlat-prefix6": "'$HEX_ADDR'", "prefix-len": 96} }'
Should this be like:
$ python3 /extends/pyynl/cli.py --spec ipxlat.yaml --do dev-set --json \
'{"ifindex": "'$IID'", "config": {"xlat-prefix6": \
{"prefix":"'$ADDR_HEX'", "prefix-len": 96}}}'

>+Address Translation
>+-------------------
>+
>+The ipxlat address translation algorithm is stateless, per RFC-ADDR_, all
>+possible IPv4 addressess are mapped one-to-one into the translation prefix,
>+optionally including a non-standard "suffix". See `RFC-ADDR Section 2.2
>+<https://datatracker.ietf.org/doc/html/rfc6052#section-2.2>`_.
>+
>+.. _RFC-ADDR: https://datatracker.ietf.org/doc/html/rfc6052
>+
>+IPv6 addressess outside this prefix are rejected with ICMPv6 errors with
>+the notable exception of ICMPv6 errors originating from untranslatable
>+source addressess. These are translated to be sourced from the IPv4 Dummy
>+Address ``192.0.0.8`` (per I-D-dummy_) instead to maintain IPv4 traceroute
>+visibility.
Would it help to add a few example? For instance,
 - Interface ipxlat0 with prefix6=64:ff9b::/96.
 - A IPv6 packet with src=64:ff9b::192.0.2.1 dst=64:ff9b::198.51.100.1,
   was send to ipxlat0.
 - Then a IPv4 packet with src=192.0.2.1 dst=198.51.100.1 was received from
   ipxlat0.

Best regards,
Xavier

^ permalink raw reply

* [PATCH v9 2/3] hwmon: ltc4283: Add support for the LTC4283 Swap Controller
From: Nuno Sá via B4 Relay @ 2026-04-06 14:31 UTC (permalink / raw)
  To: linux-gpio, linux-hwmon, devicetree, linux-doc
  Cc: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jonathan Corbet, Linus Walleij, Bartosz Golaszewski
In-Reply-To: <20260406-ltc4283-support-v9-0-b66cfc749261@analog.com>

From: Nuno Sá <nuno.sa@analog.com>

Support the LTC4283 Hot Swap Controller. The device features programmable
current limit with foldback and independently adjustable inrush current to
optimize the MOSFET safe operating area (SOA). The SOA timer limits MOSFET
temperature rise for reliable protection against overstresses.

An I2C interface and onboard ADC allow monitoring of board current,
voltage, power, energy, and fault status.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 Documentation/hwmon/index.rst   |    1 +
 Documentation/hwmon/ltc4283.rst |  266 ++++++
 MAINTAINERS                     |    1 +
 drivers/hwmon/Kconfig           |   12 +
 drivers/hwmon/Makefile          |    1 +
 drivers/hwmon/ltc4283.c         | 1808 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 2089 insertions(+)

diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 199f35a75282..d54dda83ab6e 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -144,6 +144,7 @@ Hardware Monitoring Kernel Drivers
    ltc4260
    ltc4261
    ltc4282
+   ltc4283
    ltc4286
    macsmc-hwmon
    max127
diff --git a/Documentation/hwmon/ltc4283.rst b/Documentation/hwmon/ltc4283.rst
new file mode 100644
index 000000000000..ba88445e45f4
--- /dev/null
+++ b/Documentation/hwmon/ltc4283.rst
@@ -0,0 +1,266 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+Kernel drivers ltc4283
+==========================================
+
+Supported chips:
+
+  * Analog Devices LTC4283
+
+    Prefix: 'ltc4283'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+        https://www.analog.com/media/en/technical-documentation/data-sheets/ltc4283.pdf
+
+Author: Nuno Sá <nuno.sa@analog.com>
+
+Description
+___________
+
+The LTC4283 negative voltage hot swap controller drives an external N-channel
+MOSFET to allow a board to be safely inserted and removed from a live backplane.
+The device features programmable current limit with foldback and independently
+adjustable inrush current to optimize the MOSFET safe operating area (SOA). The
+SOA timer limits MOSFET temperature rise for reliable protection against
+overstresses. An I2C interface and onboard gear-shift ADC allow monitoring of
+board current, voltage, power, energy, and fault status.  Additional features
+respond to input UV/OV, interrupt the host when a fault has occurred, notify
+when output power is good, detect insertion of a board, turn off the MOSFET
+if an external supply monitor fails to indicate power good within a timeout
+period, and auto-reboot after a programmable delay following a host commanded
+turn-off.
+
+Sysfs entries
+_____________
+
+The following attributes are supported. Limits are read-write and all the other
+attributes are read-only. Note that the VADIOx channels might not be available
+if the ADIO pins are used as GPIOs (naturally also affects the respective
+differential channels).
+
+======================= ==========================================
+in0_lcrit_alarm         Critical Undervoltage alarm
+in0_crit_alarm          Critical Overvoltage alarm
+in0_label		Channel label (VIN)
+
+in1_input		Output voltage (mV).
+in1_min			Undervoltage threshold
+in1_max			Overvoltage threshold
+in1_lowest		Lowest measured voltage
+in1_highest		Highest measured voltage
+in1_reset_history	Write 1 to reset history.
+in1_min_alarm		Undervoltage alarm
+in1_max_alarm		Overvoltage alarm
+in1_label		Channel label (VPWR)
+
+in2_input		Output voltage (mV).
+in2_min			Undervoltage threshold
+in2_max			Overvoltage threshold
+in2_lowest		Lowest measured voltage
+in2_highest		Highest measured voltage
+in2_reset_history	Write 1 to reset history.
+in2_min_alarm		Undervoltage alarm
+in2_max_alarm		Overvoltage alarm
+in2_enable		Enable/Disable monitoring.
+in2_label		Channel label (VADI1)
+
+in3_input		Output voltage (mV).
+in3_min			Undervoltage threshold
+in3_max			Overvoltage threshold
+in3_lowest		Lowest measured voltage
+in3_highest		Highest measured voltage
+in3_reset_history	Write 1 to reset history.
+in3_min_alarm		Undervoltage alarm
+in3_max_alarm		Overvoltage alarm
+in3_enable		Enable/Disable monitoring.
+in3_label		Channel label (VADI2)
+
+in4_input		Output voltage (mV).
+in4_min			Undervoltage threshold
+in4_max			Overvoltage threshold
+in4_lowest		Lowest measured voltage
+in4_highest		Highest measured voltage
+in4_reset_history	Write 1 to reset history.
+in4_min_alarm		Undervoltage alarm
+in4_max_alarm		Overvoltage alarm
+in4_enable		Enable/Disable monitoring.
+in4_label		Channel label (VADI3)
+
+in5_input		Output voltage (mV).
+in5_min			Undervoltage threshold
+in5_max			Overvoltage threshold
+in5_lowest		Lowest measured voltage
+in5_highest		Highest measured voltage
+in5_reset_history	Write 1 to reset history.
+in5_min_alarm		Undervoltage alarm
+in5_max_alarm		Overvoltage alarm
+in5_enable		Enable/Disable monitoring.
+in5_label		Channel label (VADI4)
+
+in6_input		Output voltage (mV).
+in6_min			Undervoltage threshold
+in6_max			Overvoltage threshold
+in6_lowest		Lowest measured voltage
+in6_highest		Highest measured voltage
+in6_reset_history	Write 1 to reset history.
+in6_min_alarm		Undervoltage alarm
+in6_max_alarm		Overvoltage alarm
+in6_enable		Enable/Disable monitoring.
+in6_label		Channel label (VADIO1)
+
+in7_input		Output voltage (mV).
+in7_min			Undervoltage threshold
+in7_max			Overvoltage threshold
+in7_lowest		Lowest measured voltage
+in7_highest		Highest measured voltage
+in7_reset_history	Write 1 to reset history.
+in7_min_alarm		Undervoltage alarm
+in7_max_alarm		Overvoltage alarm
+in7_enable		Enable/Disable monitoring.
+in7_label		Channel label (VADIO2)
+
+in8_input		Output voltage (mV).
+in8_min			Undervoltage threshold
+in8_max			Overvoltage threshold
+in8_lowest		Lowest measured voltage
+in8_highest		Highest measured voltage
+in8_reset_history	Write 1 to reset history.
+in8_min_alarm		Undervoltage alarm
+in8_max_alarm		Overvoltage alarm
+in8_enable		Enable/Disable monitoring.
+in8_label		Channel label (VADIO3)
+
+in9_input		Output voltage (mV).
+in9_min			Undervoltage threshold
+in9_max			Overvoltage threshold
+in9_lowest		Lowest measured voltage
+in9_highest		Highest measured voltage
+in9_reset_history	Write 1 to reset history.
+in9_min_alarm		Undervoltage alarm
+in9_max_alarm		Overvoltage alarm
+in9_enable		Enable/Disable monitoring.
+in9_label		Channel label (VADIO4)
+
+in10_input		Output voltage (mV).
+in10_min		Undervoltage threshold
+in10_max		Overvoltage threshold
+in10_lowest		Lowest measured voltage
+in10_highest		Highest measured voltage
+in10_reset_history	Write 1 to reset history.
+in10_min_alarm		Undervoltage alarm
+in10_max_alarm		Overvoltage alarm
+in10_enable		Enable/Disable monitoring.
+in10_label		Channel label (DRNS)
+
+in11_input		Output voltage (mV).
+in11_min		Undervoltage threshold
+in11_max		Overvoltage threshold
+in11_lowest		Lowest measured voltage
+in11_highest		Highest measured voltage
+in11_reset_history	Write 1 to reset history.
+			Also clears fet bad and short fault logs.
+in11_min_alarm		Undervoltage alarm
+in11_max_alarm		Overvoltage alarm
+in11_enable		Enable/Disable monitoring
+in11_fault		Failure in the MOSFET. Either bad or shorted FET.
+in11_label		Channel label (DRAIN)
+
+in12_input		Output voltage (mV).
+in12_min		Undervoltage threshold
+in12_max		Overvoltage threshold
+in12_lowest		Lowest measured voltage
+in12_highest		Highest measured voltage
+in12_reset_history	Write 1 to reset history.
+in12_min_alarm		Undervoltage alarm
+in12_max_alarm		Overvoltage alarm
+in12_enable		Enable/Disable monitoring.
+in12_label		Channel label (ADIN2-ADIN1)
+
+in13_input		Output voltage (mV).
+in13_min		Undervoltage threshold
+in13_max		Overvoltage threshold
+in13_lowest		Lowest measured voltage
+in13_highest		Highest measured voltage
+in13_reset_history	Write 1 to reset history.
+in13_min_alarm		Undervoltage alarm
+in13_max_alarm		Overvoltage alarm
+in13_enable		Enable/Disable monitoring.
+in13_label		Channel label (ADIN4-ADIN3)
+
+in14_input		Output voltage (mV).
+in14_min		Undervoltage threshold
+in14_max		Overvoltage threshold
+in14_lowest		Lowest measured voltage
+in14_highest		Highest measured voltage
+in14_reset_history	Write 1 to reset history.
+in14_min_alarm		Undervoltage alarm
+in14_max_alarm		Overvoltage alarm
+in14_enable		Enable/Disable monitoring.
+in14_label		Channel label (ADIO2-ADIO1)
+
+in15_input		Output voltage (mV).
+in15_min		Undervoltage threshold
+in15_max		Overvoltage threshold
+in15_lowest		Lowest measured voltage
+in15_highest		Highest measured voltage
+in15_reset_history	Write 1 to reset history.
+in15_min_alarm		Undervoltage alarm
+in15_max_alarm		Overvoltage alarm
+in15_enable		Enable/Disable monitoring.
+in15_label		Channel label (ADIO4-ADIO3)
+
+curr1_input		Sense current (mA)
+curr1_min		Undercurrent threshold
+curr1_max		Overcurrent threshold
+curr1_lowest		Lowest measured current
+curr1_highest		Highest measured current
+curr1_reset_history	Write 1 to reset curr1 history.
+			Also clears overcurrent fault logs.
+curr1_min_alarm		Undercurrent alarm
+curr1_max_alarm		Overcurrent alarm
+curr1_crit_alarm        Critical Overcurrent alarm
+curr1_label		Channel label (ISENSE)
+
+power1_input		Power (in uW)
+power1_min		Low power threshold
+power1_max		High power threshold
+power1_input_lowest	Historical minimum power use
+power1_input_highest	Historical maximum power use
+power1_reset_history	Write 1 to reset power1 history.
+			Also clears power fault logs.
+power1_min_alarm	Low power alarm
+power1_max_alarm	High power alarm
+power1_label		Channel label (Power)
+
+energy1_input		Measured energy over time (in microJoule)
+energy1_enable		Enable/Disable Energy accumulation
+======================= ==========================================
+
+DebugFs entries
+_______________
+
+The chip also has a fault log register where failures can be logged. Hence,
+as these are logging events, we give access to them in debugfs. Note that
+even if some failure is detected in these logs, it does necessarily mean
+that the failure is still present. As mentioned in the proper Sysfs entries,
+these logs can be cleared by writing in the proper reset_history attribute.
+
+.. warning:: The debugfs interface is subject to change without notice
+             and is only available when the kernel is compiled with
+             ``CONFIG_DEBUG_FS`` defined.
+
+``/sys/kernel/debug/i2c/i2c-[X]/[X]-addr/``
+contains the following attributes:
+
+=======================		==========================================
+power1_failed_fault_log		Set to 1 by a power1 fault occurring.
+power1_good_input_fault_log	Set to 1 by a power1 good input fault occurring at PGIO3.
+in11_fet_short_fault_log	Set to 1 when a FET-short fault occurs.
+in11_fet_bad_fault_log		Set to 1 when a FET-BAD fault occurs.
+in0_lcrit_fault_log		Set to 1 by a VIN undervoltage fault occurring.
+in0_crit_fault_log		Set to 1 by a VIN overvoltage fault occurring.
+curr1_crit_fault_log		Set to 1 by an overcurrent fault occurring.
+======================= 	==========================================
diff --git a/MAINTAINERS b/MAINTAINERS
index 3f727d7fdfa4..a63833b6fe8b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15166,6 +15166,7 @@ M:	Nuno Sá <nuno.sa@analog.com>
 L:	linux-hwmon@vger.kernel.org
 S:	Supported
 F:	Documentation/devicetree/bindings/hwmon/adi,ltc4283.yaml
+F:	drivers/hwmon/ltc4283.c
 
 LTC4286 HARDWARE MONITOR DRIVER
 M:	Delphine CC Chiu <Delphine_CC_Chiu@Wiwynn.com>
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index fb847ab40ab4..4d9f500ae6ee 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1157,6 +1157,18 @@ config SENSORS_LTC4282
 	  This driver can also be built as a module. If so, the module will
 	  be called ltc4282.
 
+config SENSORS_LTC4283
+	tristate "Analog Devices LTC4283"
+	depends on I2C
+	select REGMAP_I2C
+	select AUXILIARY_BUS
+	help
+	  If you say yes here you get support for Analog Devices LTC4283
+	  Negative Voltage Hot Swap Controller I2C interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc4283.
+
 config SENSORS_LTQ_CPUTEMP
 	bool "Lantiq cpu temperature sensor driver"
 	depends on SOC_XWAY
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 0fce31b43eb1..b9d7b0287b9c 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -147,6 +147,7 @@ obj-$(CONFIG_SENSORS_LTC4245)	+= ltc4245.o
 obj-$(CONFIG_SENSORS_LTC4260)	+= ltc4260.o
 obj-$(CONFIG_SENSORS_LTC4261)	+= ltc4261.o
 obj-$(CONFIG_SENSORS_LTC4282)	+= ltc4282.o
+obj-$(CONFIG_SENSORS_LTC4283)	+= ltc4283.o
 obj-$(CONFIG_SENSORS_LTQ_CPUTEMP) += ltq-cputemp.o
 obj-$(CONFIG_SENSORS_MACSMC_HWMON)	+= macsmc-hwmon.o
 obj-$(CONFIG_SENSORS_MAX1111)	+= max1111.o
diff --git a/drivers/hwmon/ltc4283.c b/drivers/hwmon/ltc4283.c
new file mode 100644
index 000000000000..2a2674a55167
--- /dev/null
+++ b/drivers/hwmon/ltc4283.c
@@ -0,0 +1,1808 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices LTC4283 I2C Negative Voltage Hot Swap Controller (HWMON)
+ *
+ * Copyright 2025 Analog Devices Inc.
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/bits.h>
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/device/devres.h>
+#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/math.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+
+#include <linux/mod_devicetable.h>
+#include <linux/overflow.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+
+#define LTC4283_SYSTEM_STATUS		0x00
+#define LTC4283_FAULT_STATUS		0x03
+#define   LTC4283_OV_MASK		BIT(0)
+#define   LTC4283_UV_MASK		BIT(1)
+#define   LTC4283_OC_MASK		BIT(2)
+#define   LTC4283_FET_BAD_MASK		BIT(3)
+#define   LTC4283_FET_SHORT_MASK	BIT(6)
+#define LTC4283_FAULT_LOG		0x04
+#define   LTC4283_OV_FAULT_MASK		BIT(0)
+#define   LTC4283_UV_FAULT_MASK		BIT(1)
+#define   LTC4283_OC_FAULT_MASK		BIT(2)
+#define   LTC4283_FET_BAD_FAULT_MASK	BIT(3)
+#define   LTC4283_PGI_FAULT_MASK	BIT(4)
+#define   LTC4283_PWR_FAIL_FAULT_MASK	BIT(5)
+#define   LTC4283_FET_SHORT_FAULT_MASK	BIT(6)
+#define LTC4283_ADC_ALM_LOG_1		0x05
+#define   LTC4283_POWER_LOW_ALM		BIT(0)
+#define   LTC4283_POWER_HIGH_ALM	BIT(1)
+#define   LTC4283_SENSE_LOW_ALM		BIT(4)
+#define   LTC4283_SENSE_HIGH_ALM	BIT(5)
+#define LTC4283_ADC_ALM_LOG_2		0x06
+#define LTC4283_ADC_ALM_LOG_3		0x07
+#define LTC4283_ADC_ALM_LOG_4		0x08
+#define LTC4283_ADC_ALM_LOG_5		0x09
+#define LTC4283_CONTROL_1		0x0a
+#define   LTC4283_RW_PAGE_MASK		BIT(0)
+#define   LTC4283_PIGIO2_ACLB_MASK	BIT(2)
+#define   LTC4283_PWRGD_RST_CTRL_MASK	BIT(3)
+#define   LTC4283_FET_BAD_OFF_MASK	BIT(4)
+#define   LTC4283_THERM_TMR_MASK	BIT(5)
+#define   LTC4283_DVDT_MASK		BIT(6)
+#define LTC4283_CONTROL_2		0x0b
+#define   LTC4283_OV_RETRY_MASK		BIT(0)
+#define   LTC4283_UV_RETRY_MASK		BIT(1)
+#define   LTC4283_OC_RETRY_MASK		GENMASK(3, 2)
+#define   LTC4283_FET_BAD_RETRY_MASK	GENMASK(5, 4)
+#define   LTC4283_EXT_FAULT_RETRY_MASK	BIT(7)
+#define LTC4283_RESERVED_OC		0x0c
+#define LTC4283_CONFIG_1		0x0d
+#define   LTC4283_FB_MASK		GENMASK(3, 2)
+#define   LTC4283_ILIM_MASK		GENMASK(7, 4)
+#define LTC4283_CONFIG_2		0x0e
+#define   LTC4283_COOLING_DL_MASK	GENMASK(3, 1)
+#define   LTC4283_FTBD_DL_MASK		GENMASK(5, 4)
+#define LTC4283_CONFIG_3		0x0f
+#define   LTC4283_VPWR_DRNS_MASK	BIT(6)
+#define   LTC4283_EXTFLT_TURN_OFF_MASK	BIT(7)
+#define LTC4283_PGIO_CONFIG		0x10
+#define   LTC4283_PGIO1_CFG_MASK	GENMASK(1, 0)
+#define   LTC4283_PGIO2_CFG_MASK	GENMASK(3, 2)
+#define   LTC4283_PGIO3_CFG_MASK	GENMASK(5, 4)
+#define   LTC4283_PGIO4_CFG_MASK	GENMASK(7, 6)
+#define LTC4283_PGIO_CONFIG_2		0x11
+#define   LTC4283_ADC_MASK		GENMASK(2, 0)
+#define LTC4283_ADC_SELECT(c)		(0x13 + (c) / 8)
+#define   LTC4283_ADC_SELECT_MASK(c)	BIT((c) % 8)
+#define LTC4283_SENSE_MIN_TH		0x1b
+#define LTC4283_SENSE_MAX_TH		0x1c
+#define LTC4283_VPWR_MIN_TH		0x1d
+#define LTC4283_VPWR_MAX_TH		0x1e
+#define LTC4283_POWER_MIN_TH		0x1f
+#define LTC4283_POWER_MAX_TH		0x20
+#define LTC4283_ADC_2_MIN_TH(c)		(0x21 + (c) * 2)
+#define LTC4283_ADC_2_MAX_TH(c)		(0x22 + (c) * 2)
+#define LTC4283_ADC_2_MIN_TH_DIFF(c)	(0x39 + (c) * 2)
+#define LTC4283_ADC_2_MAX_TH_DIFF(c)	(0x3a + (c) * 2)
+#define LTC4283_SENSE			0x41
+#define LTC4283_SENSE_MIN		0x42
+#define LTC4283_SENSE_MAX		0x43
+#define LTC4283_VPWR			0x44
+#define LTC4283_VPWR_MIN		0x45
+#define LTC4283_VPWR_MAX		0x46
+#define LTC4283_POWER			0x47
+#define LTC4283_POWER_MIN		0x48
+#define LTC4283_POWER_MAX		0x49
+#define LTC4283_RESERVED_68		0x68
+#define LTC4283_RESERVED_6D		0x6D
+/* get channels from ADC 2 */
+#define LTC4283_ADC_2(c)		(0x4a + (c) * 3)
+#define LTC4283_ADC_2_MIN(c)		(0x4b + (c) * 3)
+#define LTC4283_ADC_2_MAX(c)		(0x4c + (c) * 3)
+#define LTC4283_ADC_2_DIFF(c)		(0x6e + (c) * 3)
+#define LTC4283_ADC_2_MIN_DIFF(c)	(0x6f + (c) * 3)
+#define LTC4283_ADC_2_MAX_DIFF(c)	(0x70 + (c) * 3)
+#define LTC4283_ENERGY			0x7a
+#define LTC4283_METER_CONTROL		0x84
+#define   LTC4283_INTEGRATE_I_MASK	BIT(0)
+#define   LTC4283_METER_HALT_MASK	BIT(6)
+#define LTC4283_RESERVED_86		0x86
+#define LTC4283_RESERVED_8F		0x8F
+#define LTC4283_FAULT_LOG_CTRL		0x90
+#define   LTC4283_FAULT_LOG_EN_MASK	BIT(7)
+#define LTC4283_RESERVED_91		0x91
+#define LTC4283_RESERVED_A1		0xA1
+#define LTC4283_RESERVED_A3		0xA3
+#define LTC4283_RESERVED_AC		0xAC
+#define LTC4283_POWER_PLAY_MSB		0xE7
+#define LTC4283_POWER_PLAY_LSB		0xE8
+#define LTC4283_RESERVED_F1		0xF1
+#define LTC4283_RESERVED_FF		0xFF
+
+/* also applies for differential channels */
+#define LTC4283_ADC1_FS_uV		32768
+#define LTC4283_ADC2_FS_mV		2048
+#define LTC4283_TCONV_uS		64103
+#define LTC4283_VILIM_MIN_uV		15000
+#define LTC4283_VILIM_MAX_uV		30000
+#define LTC4283_VILIM_RANGE	\
+	(LTC4283_VILIM_MAX_uV - LTC4283_VILIM_MIN_uV + 1)
+
+#define LTC4283_PGIO_FUNC_GPIO		2
+#define LTC4283_PGIO2_FUNC_ACLB		3
+
+/*
+ * Maximum value for rsense in nano ohms. The reasoning for this value is that
+ * it's the max value for which multiplying by 256 does not overflow long on
+ * 32bits. For the minimum value, is a sane minimum rsense for which power_max
+ * does not overflow 32bits.
+ */
+#define LTC4283_MAX_RSENSE	1677721599
+#define LTC4283_MIN_RSENSE	50000
+
+/* voltage channels */
+enum {
+	LTC4283_CHAN_VIN,
+	LTC4283_CHAN_VPWR,
+	LTC4283_CHAN_ADI_1,
+	LTC4283_CHAN_ADI_2,
+	LTC4283_CHAN_ADI_3,
+	LTC4283_CHAN_ADI_4,
+	LTC4283_CHAN_ADIO_1,
+	LTC4283_CHAN_ADIO_2,
+	LTC4283_CHAN_ADIO_3,
+	LTC4283_CHAN_ADIO_4,
+	LTC4283_CHAN_DRNS,
+	LTC4283_CHAN_DRAIN,
+	/* differential channels */
+	LTC4283_CHAN_ADIN12,
+	LTC4283_CHAN_ADIN34,
+	LTC4283_CHAN_ADIO12,
+	LTC4283_CHAN_ADIO34,
+	LTC4283_CHAN_MAX
+};
+
+/* Just for ease of use on the regmap  */
+#define LTC4283_ADIO34_MAX \
+	LTC4283_ADC_2_MAX_DIFF(LTC4283_CHAN_ADIO34 - LTC4283_CHAN_ADIN12)
+
+struct ltc4283_hwmon {
+	struct regmap *map;
+	struct i2c_client *client;
+	unsigned long gpio_mask;
+	unsigned long ch_enable_mask;
+	/* in microwatt */
+	long power_max;
+	/* in millivolt */
+	u32 vsense_max;
+	/* in tenths of microohm*/
+	u32 rsense;
+	bool energy_en;
+	bool ext_fault;
+};
+
+static int ltc4283_read_voltage_word(const struct ltc4283_hwmon *st,
+				     u32 reg, u32 fs, long *val)
+{
+	unsigned int __raw;
+	int ret;
+
+	ret = regmap_read(st->map, reg, &__raw);
+	if (ret)
+		return ret;
+
+	*val = DIV_ROUND_CLOSEST(__raw * fs, BIT(16));
+	return 0;
+}
+
+static int ltc4283_read_voltage_byte(const struct ltc4283_hwmon *st,
+				     u32 reg, u32 fs, long *val)
+{
+	int ret;
+	u32 in;
+
+	ret = regmap_read(st->map, reg, &in);
+	if (ret)
+		return ret;
+
+	*val = DIV_ROUND_CLOSEST(in * fs, BIT(8));
+	return 0;
+}
+
+static u32 ltc4283_in_reg(u32 attr, u32 channel)
+{
+	switch (attr) {
+	case hwmon_in_input:
+		if (channel == LTC4283_CHAN_VPWR)
+			return LTC4283_VPWR;
+		if (channel >= LTC4283_CHAN_ADI_1 && channel <= LTC4283_CHAN_DRAIN)
+			return LTC4283_ADC_2(channel - LTC4283_CHAN_ADI_1);
+		return LTC4283_ADC_2_DIFF(channel - LTC4283_CHAN_ADIN12);
+	case hwmon_in_highest:
+		if (channel == LTC4283_CHAN_VPWR)
+			return LTC4283_VPWR_MAX;
+		if (channel >= LTC4283_CHAN_ADI_1 && channel <= LTC4283_CHAN_DRAIN)
+			return LTC4283_ADC_2_MAX(channel - LTC4283_CHAN_ADI_1);
+		return LTC4283_ADC_2_MAX_DIFF(channel - LTC4283_CHAN_ADIN12);
+	case hwmon_in_lowest:
+		if (channel == LTC4283_CHAN_VPWR)
+			return LTC4283_VPWR_MIN;
+		if (channel >= LTC4283_CHAN_ADI_1 && channel <= LTC4283_CHAN_DRAIN)
+			return LTC4283_ADC_2_MIN(channel - LTC4283_CHAN_ADI_1);
+		return LTC4283_ADC_2_MIN_DIFF(channel - LTC4283_CHAN_ADIN12);
+	case hwmon_in_max:
+		if (channel == LTC4283_CHAN_VPWR)
+			return LTC4283_VPWR_MAX_TH;
+		if (channel >= LTC4283_CHAN_ADI_1 && channel <= LTC4283_CHAN_DRAIN)
+			return LTC4283_ADC_2_MAX_TH(channel - LTC4283_CHAN_ADI_1);
+		return LTC4283_ADC_2_MAX_TH_DIFF(channel - LTC4283_CHAN_ADIN12);
+	default:
+		if (channel == LTC4283_CHAN_VPWR)
+			return LTC4283_VPWR_MIN_TH;
+		if (channel >= LTC4283_CHAN_ADI_1 && channel <= LTC4283_CHAN_DRAIN)
+			return LTC4283_ADC_2_MIN_TH(channel - LTC4283_CHAN_ADI_1);
+		return LTC4283_ADC_2_MIN_TH_DIFF(channel - LTC4283_CHAN_ADIN12);
+	}
+}
+
+static int ltc4283_read_in_vals(const struct ltc4283_hwmon *st,
+				u32 attr, u32 channel, long *val)
+{
+	u32 reg = ltc4283_in_reg(attr, channel);
+	int ret;
+
+	if (channel < LTC4283_CHAN_ADIN12) {
+		if (attr != hwmon_in_max && attr != hwmon_in_min)
+			return ltc4283_read_voltage_word(st, reg,
+							 LTC4283_ADC2_FS_mV,
+							 val);
+
+		return ltc4283_read_voltage_byte(st, reg,
+						 LTC4283_ADC2_FS_mV, val);
+	}
+
+	if (attr != hwmon_in_max && attr != hwmon_in_min)
+		ret = ltc4283_read_voltage_word(st, reg,
+						LTC4283_ADC1_FS_uV, val);
+	else
+		ret = ltc4283_read_voltage_byte(st, reg,
+						LTC4283_ADC1_FS_uV, val);
+	if (ret)
+		return ret;
+
+	*val = DIV_ROUND_CLOSEST(*val, MILLI);
+	return 0;
+}
+
+static int ltc4283_read_alarm(struct ltc4283_hwmon *st, u32 reg,
+			      u32 mask, long *val)
+{
+	u32 alarm;
+	int ret;
+
+	ret = regmap_read(st->map, reg, &alarm);
+	if (ret)
+		return ret;
+
+	*val = !!(alarm & mask);
+
+	/* If not status/fault logs, clear the alarm after reading it. */
+	if (reg != LTC4283_FAULT_STATUS && reg != LTC4283_FAULT_LOG)
+		return regmap_clear_bits(st->map, reg, mask);
+
+	return 0;
+}
+
+static int ltc4283_read_in_alarm(struct ltc4283_hwmon *st, u32 channel,
+				 bool max_alm, long *val)
+{
+	if (channel == LTC4283_VPWR)
+		return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_1,
+					  BIT(2 + max_alm), val);
+
+	if (channel >= LTC4283_CHAN_ADI_1 && channel <= LTC4283_CHAN_ADI_4) {
+		u32 bit = (channel - LTC4283_CHAN_ADI_1) * 2;
+		/*
+		 * Lower channels go to higher bits. We also want to go +1 down
+		 * in the min_alarm case.
+		 */
+		return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_2,
+					  BIT(7 - bit - !max_alm), val);
+	}
+
+	if (channel >= LTC4283_CHAN_ADIO_1 && channel <= LTC4283_CHAN_ADIO_4) {
+		u32 bit = (channel - LTC4283_CHAN_ADIO_1) * 2;
+
+		return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_3,
+					  BIT(7 - bit - !max_alm), val);
+	}
+
+	if (channel >= LTC4283_CHAN_ADIN12 && channel <= LTC4283_CHAN_ADIO34) {
+		u32 bit = (channel - LTC4283_CHAN_ADIN12) * 2;
+
+		return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_5,
+					  BIT(7 - bit - !max_alm), val);
+	}
+
+	if (channel == LTC4283_CHAN_DRNS)
+		return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_4,
+					  BIT(6 + max_alm), val);
+
+	return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_4, BIT(4 + max_alm),
+				  val);
+}
+
+static int ltc4283_read_in(struct ltc4283_hwmon *st, u32 attr, u32 channel,
+			   long *val)
+{
+	switch (attr) {
+	case hwmon_in_input:
+		if (!test_bit(channel, &st->ch_enable_mask))
+			return -ENODATA;
+
+		return ltc4283_read_in_vals(st, attr, channel, val);
+	case hwmon_in_highest:
+	case hwmon_in_lowest:
+	case hwmon_in_max:
+	case hwmon_in_min:
+		return ltc4283_read_in_vals(st, attr, channel, val);
+	case hwmon_in_max_alarm:
+		return ltc4283_read_in_alarm(st, channel, true, val);
+	case hwmon_in_min_alarm:
+		return ltc4283_read_in_alarm(st, channel, false, val);
+	case hwmon_in_crit_alarm:
+		return ltc4283_read_alarm(st, LTC4283_FAULT_STATUS,
+					  LTC4283_OV_MASK, val);
+	case hwmon_in_lcrit_alarm:
+		return ltc4283_read_alarm(st, LTC4283_FAULT_STATUS,
+					  LTC4283_UV_MASK, val);
+	case hwmon_in_fault:
+		/*
+		 * We report failure if we detect either a fer_bad or a
+		 * fet_short in the status register.
+		 */
+		return ltc4283_read_alarm(st, LTC4283_FAULT_STATUS,
+					  LTC4283_FET_BAD_MASK | LTC4283_FET_SHORT_MASK, val);
+	case hwmon_in_enable:
+		*val = test_bit(channel, &st->ch_enable_mask);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+static int ltc4283_read_current_word(const struct ltc4283_hwmon *st, u32 reg,
+				     long *val)
+{
+	u64 temp = (u64)LTC4283_ADC1_FS_uV * DECA * MILLI;
+	unsigned int __raw;
+	int ret;
+
+	ret = regmap_read(st->map, reg, &__raw);
+	if (ret)
+		return ret;
+
+	*val = DIV64_U64_ROUND_CLOSEST(__raw * temp,
+				       BIT_ULL(16) * st->rsense);
+
+	return 0;
+}
+
+static int ltc4283_read_current_byte(const struct ltc4283_hwmon *st, u32 reg,
+				     long *val)
+{
+	u64 temp = (u64)LTC4283_ADC1_FS_uV * DECA * MILLI;
+	u32 curr;
+	int ret;
+
+	ret = regmap_read(st->map, reg, &curr);
+	if (ret)
+		return ret;
+
+	*val = DIV_ROUND_CLOSEST_ULL(curr * temp, BIT(8) * st->rsense);
+	return 0;
+}
+
+static int ltc4283_read_curr(struct ltc4283_hwmon *st, u32 attr, long *val)
+{
+	switch (attr) {
+	case hwmon_curr_input:
+		return ltc4283_read_current_word(st, LTC4283_SENSE, val);
+	case hwmon_curr_highest:
+		return ltc4283_read_current_word(st, LTC4283_SENSE_MAX, val);
+	case hwmon_curr_lowest:
+		return ltc4283_read_current_word(st, LTC4283_SENSE_MIN, val);
+	case hwmon_curr_max:
+		return ltc4283_read_current_byte(st, LTC4283_SENSE_MAX_TH, val);
+	case hwmon_curr_min:
+		return ltc4283_read_current_byte(st, LTC4283_SENSE_MIN_TH, val);
+	case hwmon_curr_max_alarm:
+		return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_1,
+					  LTC4283_SENSE_HIGH_ALM, val);
+	case hwmon_curr_min_alarm:
+		return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_1,
+					  LTC4283_SENSE_LOW_ALM, val);
+	case hwmon_curr_crit_alarm:
+		return ltc4283_read_alarm(st, LTC4283_FAULT_STATUS,
+					  LTC4283_OC_MASK, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int ltc4283_read_power_word(const struct ltc4283_hwmon *st,
+				   u32 reg, long *val)
+{
+	u64 temp = (u64)LTC4283_ADC1_FS_uV * LTC4283_ADC2_FS_mV * DECA * MILLI;
+	unsigned int __raw;
+	int ret;
+
+	ret = regmap_read(st->map, reg, &__raw);
+	if (ret)
+		return ret;
+
+	/*
+	 * Power is given by:
+	 *     P = CODE(16b) * 32.768mV * 2.048V / (2^16 * Rsense)
+	 */
+	*val = DIV64_U64_ROUND_CLOSEST(temp * __raw, BIT_ULL(16) * st->rsense);
+
+	return 0;
+}
+
+static int ltc4283_read_power_byte(const struct ltc4283_hwmon *st,
+				   u32 reg, long *val)
+{
+	u64 temp = (u64)LTC4283_ADC1_FS_uV * LTC4283_ADC2_FS_mV * DECA * MILLI;
+	u32 power;
+	int ret;
+
+	ret = regmap_read(st->map, reg, &power);
+	if (ret)
+		return ret;
+
+	*val = DIV_ROUND_CLOSEST_ULL(power * temp, BIT(8) * st->rsense);
+
+	return 0;
+}
+
+static int ltc4283_read_power(struct ltc4283_hwmon *st, u32 attr, long *val)
+{
+	switch (attr) {
+	case hwmon_power_input:
+		return ltc4283_read_power_word(st, LTC4283_POWER, val);
+	case hwmon_power_input_highest:
+		return ltc4283_read_power_word(st, LTC4283_POWER_MAX, val);
+	case hwmon_power_input_lowest:
+		return ltc4283_read_power_word(st, LTC4283_POWER_MIN, val);
+	case hwmon_power_max_alarm:
+		return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_1,
+					  LTC4283_POWER_HIGH_ALM, val);
+	case hwmon_power_min_alarm:
+		return ltc4283_read_alarm(st, LTC4283_ADC_ALM_LOG_1,
+					  LTC4283_POWER_LOW_ALM, val);
+	case hwmon_power_max:
+		return ltc4283_read_power_byte(st, LTC4283_POWER_MAX_TH, val);
+	case hwmon_power_min:
+		return ltc4283_read_power_byte(st, LTC4283_POWER_MIN_TH, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int ltc4283_read_energy(struct ltc4283_hwmon *st, u32 attr, s64 *val)
+{
+	u64 temp = LTC4283_ADC1_FS_uV * LTC4283_ADC2_FS_mV, energy, temp_2;
+	u8 raw[8] = {};
+	int ret;
+
+	if (!st->energy_en)
+		return -ENODATA;
+
+	ret = i2c_smbus_read_i2c_block_data(st->client, LTC4283_ENERGY, 6, raw);
+	if (ret < 0)
+		return ret;
+	if (ret != 6)
+		return -EIO;
+
+	energy = get_unaligned_be64(raw) >> 16;
+
+	/*
+	 * The formula for energy is given by:
+	 *	E = CODE(48b) * 32.768mV * 2.048V * Tconv / 2^24 * Rsense
+	 *
+	 * As Rsense can have tenths of micro-ohm resolution, we need to
+	 * multiply by DECA to get microjoule.
+	 */
+	if (check_mul_overflow(temp * LTC4283_TCONV_uS, energy, &temp_2)) {
+		/*
+		 * We multiply again by 1000 to make sure that we don't get 0
+		 * in the following division which could happen for big rsense
+		 * values. OTOH, we then divide energy first by 1000 so that
+		 * we do not overflow u64 again for very small rsense values.
+		 * We add 100 factor for proper conversion to microjoule.
+		 */
+		temp_2 = DIV64_U64_ROUND_CLOSEST(temp * LTC4283_TCONV_uS * MILLI,
+						 BIT_ULL(24) * st->rsense);
+		energy = DIV_ROUND_CLOSEST_ULL(energy, MILLI * CENTI) * temp_2;
+	} else {
+		/* Put rsense back into nanoohm so we get microjoule. */
+		energy = DIV64_U64_ROUND_CLOSEST(temp_2, BIT_ULL(24) * st->rsense * CENTI);
+	}
+
+	*val = energy;
+	return 0;
+}
+
+static int ltc4283_read(struct device *dev, enum hwmon_sensor_types type,
+			u32 attr, int channel, long *val)
+{
+	struct ltc4283_hwmon *st = dev_get_drvdata(dev);
+
+	switch (type) {
+	case hwmon_in:
+		return ltc4283_read_in(st, attr, channel, val);
+	case hwmon_curr:
+		return ltc4283_read_curr(st, attr, val);
+	case hwmon_power:
+		return ltc4283_read_power(st, attr, val);
+	case hwmon_energy:
+		*val = st->energy_en;
+		return 0;
+	case hwmon_energy64:
+		return ltc4283_read_energy(st, attr, (s64 *)val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int ltc4283_write_power_byte(const struct ltc4283_hwmon *st, u32 reg,
+				    long val)
+{
+	u64 temp = (u64)LTC4283_ADC1_FS_uV * LTC4283_ADC2_FS_mV * DECA * MILLI;
+	u32 __raw;
+
+	val = clamp_val(val, 0, st->power_max);
+	__raw = DIV64_U64_ROUND_CLOSEST(val * BIT_ULL(8) * st->rsense, temp);
+
+	return regmap_write(st->map, reg, __raw);
+}
+
+static int ltc4283_write_power_word(const struct ltc4283_hwmon *st,
+				    u32 reg, long val)
+{
+	u64 temp = st->rsense * BIT_ULL(16), temp_2;
+	u16 __raw;
+
+	if (check_mul_overflow(val, temp, &temp_2)) {
+		temp = DIV_ROUND_CLOSEST_ULL(temp, DECA * MILLI);
+		__raw = DIV_ROUND_CLOSEST_ULL(temp * val, LTC4283_ADC1_FS_uV * LTC4283_ADC2_FS_mV);
+	} else {
+		temp = (u64)LTC4283_ADC1_FS_uV * LTC4283_ADC2_FS_mV * DECA * MILLI;
+		__raw = DIV64_U64_ROUND_CLOSEST(temp_2, temp);
+	}
+
+	return regmap_write(st->map, reg, __raw);
+}
+
+static int ltc4283_reset_power_hist(struct ltc4283_hwmon *st)
+{
+	int ret;
+
+	ret = ltc4283_write_power_word(st, LTC4283_POWER_MIN, st->power_max);
+	if (ret)
+		return ret;
+
+	ret = ltc4283_write_power_word(st, LTC4283_POWER_MAX, 0);
+	if (ret)
+		return ret;
+
+	/* Clear possible power faults. */
+	return regmap_clear_bits(st->map, LTC4283_FAULT_LOG,
+				 LTC4283_PWR_FAIL_FAULT_MASK | LTC4283_PGI_FAULT_MASK);
+}
+
+static int ltc4283_write_power(struct ltc4283_hwmon *st, u32 attr, long val)
+{
+	switch (attr) {
+	case hwmon_power_max:
+		return ltc4283_write_power_byte(st, LTC4283_POWER_MAX_TH, val);
+	case hwmon_power_min:
+		return ltc4283_write_power_byte(st, LTC4283_POWER_MIN_TH, val);
+	case hwmon_power_reset_history:
+		return ltc4283_reset_power_hist(st);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int ltc4283_write_in_history(struct ltc4283_hwmon *st, u32 reg,
+				    long lowest, u32 fs)
+{
+	u32 __raw;
+	int ret;
+
+	__raw = DIV_ROUND_CLOSEST(BIT(16) * lowest, fs);
+	if (__raw == BIT(16))
+		__raw = U16_MAX;
+
+	ret = regmap_write(st->map, reg, __raw);
+	if (ret)
+		return ret;
+
+	return regmap_write(st->map, reg + 1, 0);
+}
+
+static int ltc4283_write_in_byte(const struct ltc4283_hwmon *st,
+				 u32 reg, u32 fs, long val)
+{
+	u32 __raw;
+
+	val = clamp_val(val, 0, fs);
+	__raw = DIV_ROUND_CLOSEST(val * BIT(8), fs);
+	if (__raw == BIT(8))
+		__raw = U8_MAX;
+
+	return regmap_write(st->map, reg, __raw);
+}
+
+static int ltc4283_reset_in_hist(struct ltc4283_hwmon *st, u32 channel)
+{
+	u32 reg, fs;
+	int ret;
+
+	/*
+	 * Make sure to clear possible under/over voltage faults. Otherwise the
+	 * chip won't latch on again.
+	 */
+	if (channel == LTC4283_CHAN_VIN)
+		return regmap_clear_bits(st->map, LTC4283_FAULT_LOG,
+					 LTC4283_OV_FAULT_MASK | LTC4283_UV_FAULT_MASK);
+
+	if (channel == LTC4283_CHAN_VPWR)
+		return ltc4283_write_in_history(st, LTC4283_VPWR_MIN,
+						LTC4283_ADC2_FS_mV,
+						LTC4283_ADC2_FS_mV);
+
+	if (channel >= LTC4283_CHAN_ADI_1 && channel <= LTC4283_CHAN_DRAIN) {
+		fs = LTC4283_ADC2_FS_mV;
+		reg = LTC4283_ADC_2_MIN(channel - LTC4283_CHAN_ADI_1);
+	} else {
+		fs = LTC4283_ADC1_FS_uV;
+		reg = LTC4283_ADC_2_MIN_DIFF(channel - LTC4283_CHAN_ADIN12);
+	}
+
+	ret = ltc4283_write_in_history(st, reg, fs, fs);
+	if (ret)
+		return ret;
+	if (channel != LTC4283_CHAN_DRAIN)
+		return 0;
+
+	/* Then, let's also clear possible fet faults. Same as above. */
+	return regmap_clear_bits(st->map, LTC4283_FAULT_LOG,
+				 LTC4283_FET_BAD_FAULT_MASK | LTC4283_FET_SHORT_FAULT_MASK);
+}
+
+static int ltc4283_write_in_en(struct ltc4283_hwmon *st, u32 channel, bool en)
+{
+	unsigned int bit, adc_idx = channel - LTC4283_CHAN_ADI_1;
+	unsigned int reg = LTC4283_ADC_SELECT(adc_idx);
+	int ret;
+
+	bit = LTC4283_ADC_SELECT_MASK(adc_idx);
+	if (channel > LTC4283_CHAN_DRAIN)
+		/* Account for two reserved fields after DRAIN. */
+		bit <<= 2;
+
+	if (en)
+		ret = regmap_set_bits(st->map, reg, bit);
+	else
+		ret = regmap_clear_bits(st->map, reg, bit);
+	if (ret)
+		return ret;
+
+	__assign_bit(channel, &st->ch_enable_mask, en);
+	return 0;
+}
+
+static int ltc4283_write_minmax(struct ltc4283_hwmon *st, long val,
+				u32 channel, bool is_max)
+{
+	u32 reg;
+
+	if (channel == LTC4283_CHAN_VPWR) {
+		if (is_max)
+			return ltc4283_write_in_byte(st, LTC4283_VPWR_MAX_TH,
+						     LTC4283_ADC2_FS_mV, val);
+
+		return ltc4283_write_in_byte(st, LTC4283_VPWR_MIN_TH,
+					     LTC4283_ADC2_FS_mV, val);
+	}
+
+	if (channel >= LTC4283_CHAN_ADI_1 && channel <= LTC4283_CHAN_DRAIN) {
+		if (is_max) {
+			reg = LTC4283_ADC_2_MAX_TH(channel - LTC4283_CHAN_ADI_1);
+			return ltc4283_write_in_byte(st, reg,
+						     LTC4283_ADC2_FS_mV, val);
+		}
+
+		reg = LTC4283_ADC_2_MIN_TH(channel - LTC4283_CHAN_ADI_1);
+		return ltc4283_write_in_byte(st, reg, LTC4283_ADC2_FS_mV, val);
+	}
+
+	/* Just sanity check we do not overflow val for 32bit */
+	val = clamp_val(val * MILLI, 0, LTC4283_ADC1_FS_uV);
+
+	if (is_max) {
+		reg = LTC4283_ADC_2_MAX_TH_DIFF(channel - LTC4283_CHAN_ADIN12);
+		return ltc4283_write_in_byte(st, reg, LTC4283_ADC1_FS_uV, val);
+	}
+
+	reg = LTC4283_ADC_2_MIN_TH_DIFF(channel - LTC4283_CHAN_ADIN12);
+	return ltc4283_write_in_byte(st, reg, LTC4283_ADC1_FS_uV, val);
+}
+
+static int ltc4283_write_in(struct ltc4283_hwmon *st, u32 attr, long val,
+			    int channel)
+{
+	switch (attr) {
+	case hwmon_in_max:
+		return ltc4283_write_minmax(st, val, channel, true);
+	case hwmon_in_min:
+		return ltc4283_write_minmax(st, val, channel, false);
+	case hwmon_in_reset_history:
+		return ltc4283_reset_in_hist(st, channel);
+	case hwmon_in_enable:
+		return ltc4283_write_in_en(st, channel, !!val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int ltc4283_write_curr_byte(const struct ltc4283_hwmon *st,
+				   u32 reg, long val)
+{
+	u32 temp = LTC4283_ADC1_FS_uV * DECA * MILLI;
+	u32 reg_val, isense_max;
+
+	isense_max = DIV_ROUND_CLOSEST(st->vsense_max * MICRO * DECA, st->rsense);
+	val = clamp_val(val, 0, isense_max);
+	reg_val = DIV_ROUND_CLOSEST_ULL(val * BIT_ULL(8) * st->rsense, temp);
+
+	return regmap_write(st->map, reg, reg_val);
+}
+
+static int ltc4283_write_curr_history(struct ltc4283_hwmon *st)
+{
+	int ret;
+
+	ret = ltc4283_write_in_history(st, LTC4283_SENSE_MIN,
+				       st->vsense_max * MILLI,
+				       LTC4283_ADC1_FS_uV);
+	if (ret)
+		return ret;
+
+	/* Now, let's also clear possible overcurrent logs. */
+	return regmap_clear_bits(st->map, LTC4283_FAULT_LOG,
+				 LTC4283_OC_FAULT_MASK);
+}
+
+static int ltc4283_write_curr(struct ltc4283_hwmon *st, u32 attr, long val)
+{
+	switch (attr) {
+	case hwmon_curr_max:
+		return ltc4283_write_curr_byte(st, LTC4283_SENSE_MAX_TH, val);
+	case hwmon_curr_min:
+		return ltc4283_write_curr_byte(st, LTC4283_SENSE_MIN_TH, val);
+	case hwmon_curr_reset_history:
+		return ltc4283_write_curr_history(st);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int ltc4283_energy_enable_set(struct ltc4283_hwmon *st, long val)
+{
+	int ret;
+
+	/* Setting the bit halts the meter. */
+	val = !!val;
+	ret = regmap_update_bits(st->map, LTC4283_METER_CONTROL,
+				 LTC4283_METER_HALT_MASK,
+				 FIELD_PREP(LTC4283_METER_HALT_MASK, !val));
+	if (ret)
+		return ret;
+
+	st->energy_en = val;
+
+	return 0;
+}
+
+static int ltc4283_write(struct device *dev, enum hwmon_sensor_types type,
+			 u32 attr, int channel, long val)
+{
+	struct ltc4283_hwmon *st = dev_get_drvdata(dev);
+
+	switch (type) {
+	case hwmon_power:
+		return ltc4283_write_power(st, attr, val);
+	case hwmon_in:
+		return ltc4283_write_in(st, attr, val, channel);
+	case hwmon_curr:
+		return ltc4283_write_curr(st, attr, val);
+	case hwmon_energy:
+		return ltc4283_energy_enable_set(st, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static umode_t ltc4283_in_is_visible(const struct ltc4283_hwmon *st,
+				     u32 attr, int channel)
+{
+	/* If ADIO is set as a GPIO, don´t make it visible. */
+	if (channel >= LTC4283_CHAN_ADIO_1 && channel <= LTC4283_CHAN_ADIO_4) {
+		/* ADIOX pins come at index 0 in the gpio mask. */
+		channel -= LTC4283_CHAN_ADIO_1;
+		if (test_bit(channel, &st->gpio_mask))
+			return 0;
+	}
+
+	/* Also take care of differential channels. */
+	if (channel >= LTC4283_CHAN_ADIO12 && channel <= LTC4283_CHAN_ADIO34) {
+		channel -= LTC4283_CHAN_ADIO12;
+		/* If one channel in the pair is used, make it invisible. */
+		if (test_bit(channel * 2, &st->gpio_mask) ||
+		    test_bit(channel * 2 + 1, &st->gpio_mask))
+			return 0;
+	}
+
+	switch (attr) {
+	case hwmon_in_input:
+	case hwmon_in_highest:
+	case hwmon_in_lowest:
+	case hwmon_in_max_alarm:
+	case hwmon_in_min_alarm:
+	case hwmon_in_label:
+	case hwmon_in_lcrit_alarm:
+	case hwmon_in_crit_alarm:
+	case hwmon_in_fault:
+		return 0444;
+	case hwmon_in_max:
+	case hwmon_in_min:
+	case hwmon_in_enable:
+		return 0644;
+	case hwmon_in_reset_history:
+		return 0200;
+	default:
+		return 0;
+	}
+}
+
+static umode_t ltc4283_curr_is_visible(u32 attr)
+{
+	switch (attr) {
+	case hwmon_curr_input:
+	case hwmon_curr_highest:
+	case hwmon_curr_lowest:
+	case hwmon_curr_max_alarm:
+	case hwmon_curr_min_alarm:
+	case hwmon_curr_crit_alarm:
+	case hwmon_curr_label:
+		return 0444;
+	case hwmon_curr_max:
+	case hwmon_curr_min:
+		return 0644;
+	case hwmon_curr_reset_history:
+		return 0200;
+	default:
+		return 0;
+	}
+}
+
+static umode_t ltc4283_power_is_visible(u32 attr)
+{
+	switch (attr) {
+	case hwmon_power_input:
+	case hwmon_power_input_highest:
+	case hwmon_power_input_lowest:
+	case hwmon_power_label:
+	case hwmon_power_max_alarm:
+	case hwmon_power_min_alarm:
+		return 0444;
+	case hwmon_power_max:
+	case hwmon_power_min:
+		return 0644;
+	case hwmon_power_reset_history:
+		return 0200;
+	default:
+		return 0;
+	}
+}
+
+static umode_t ltc4283_is_visible(const void *data,
+				  enum hwmon_sensor_types type,
+				  u32 attr, int channel)
+{
+	switch (type) {
+	case hwmon_in:
+		return ltc4283_in_is_visible(data, attr, channel);
+	case hwmon_curr:
+		return ltc4283_curr_is_visible(attr);
+	case hwmon_power:
+		return ltc4283_power_is_visible(attr);
+	case hwmon_energy:
+		/* hwmon_energy_enable */
+		return 0644;
+	case hwmon_energy64:
+		/* hwmon_energy_input */
+		return 0444;
+	default:
+		return 0;
+	}
+}
+
+static const char * const ltc4283_in_strs[] = {
+	"VIN", "VPWR", "VADI1", "VADI2", "VADI3", "VADI4", "VADIO1", "VADIO2",
+	"VADIO3", "VADIO4", "DRNS", "DRAIN", "ADIN2-ADIN1", "ADIN4-ADIN3",
+	"ADIO2-ADIO1", "ADIO4-ADIO3"
+};
+
+static int ltc4283_read_labels(struct device *dev,
+			       enum hwmon_sensor_types type,
+			       u32 attr, int channel, const char **str)
+{
+	switch (type) {
+	case hwmon_in:
+		*str = ltc4283_in_strs[channel];
+		return 0;
+	case hwmon_curr:
+		*str = "ISENSE";
+		return 0;
+	case hwmon_power:
+		*str = "Power";
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/*
+ * Set max limits for ISENSE and Power as that depends on the max voltage on
+ * rsense that is defined in ILIM_ADJUST. This is specially important for power
+ * because for some rsense and vfsout values, if we allow the default raw 255
+ * value, that would overflow long in 32bit archs when reading back the max
+ * power limit.
+ */
+static int ltc4283_set_max_limits(struct ltc4283_hwmon *st, struct device *dev)
+{
+	u32 temp = st->vsense_max * DECA * MICRO;
+	int ret;
+
+	ret = ltc4283_write_in_byte(st, LTC4283_SENSE_MAX_TH, LTC4283_ADC1_FS_uV,
+				    st->vsense_max * MILLI);
+	if (ret)
+		return ret;
+
+	/* Power is given by ISENSE * Vout. */
+	st->power_max = DIV_ROUND_CLOSEST(temp, st->rsense) * LTC4283_ADC2_FS_mV;
+	return ltc4283_write_power_byte(st, LTC4283_POWER_MAX_TH, st->power_max);
+}
+
+static int ltc4283_parse_array_prop(const struct ltc4283_hwmon *st,
+				    struct device *dev, const char *prop,
+				    const u32 *vals, u32 n_vals)
+{
+	u32 prop_val;
+	int ret;
+	u32 i;
+
+	ret = device_property_read_u32(dev, prop, &prop_val);
+	if (ret)
+		return n_vals;
+
+	for (i = 0; i < n_vals; i++) {
+		if (prop_val != vals[i])
+			continue;
+
+		return i;
+	}
+
+	return dev_err_probe(dev, -EINVAL,
+			     "Invalid %s property value %u, expected one of: %*ph\n",
+			     prop, prop_val, n_vals, vals);
+}
+
+static int ltc4283_get_defaults(struct ltc4283_hwmon *st)
+{
+	u32 reg_val, ilm_adjust, c;
+	int ret;
+
+	ret = regmap_read(st->map, LTC4283_METER_CONTROL, &reg_val);
+	if (ret)
+		return ret;
+
+	st->energy_en = !FIELD_GET(LTC4283_METER_HALT_MASK, reg_val);
+
+	ret = regmap_read(st->map, LTC4283_CONFIG_1, &reg_val);
+	if (ret)
+		return ret;
+
+	ilm_adjust = FIELD_GET(LTC4283_ILIM_MASK, reg_val);
+	st->vsense_max = LTC4283_VILIM_MIN_uV / MILLI + ilm_adjust;
+
+	ret = regmap_read(st->map, LTC4283_PGIO_CONFIG, &reg_val);
+	if (ret)
+		return ret;
+
+	/* Can be latter overwritten in ltc4283_pgio_config() */
+	if (FIELD_GET(LTC4283_PGIO4_CFG_MASK, reg_val) < LTC4283_PGIO_FUNC_GPIO)
+		st->ext_fault = true;
+
+	/* VPWR and VIN are always enabled */
+	__set_bit(LTC4283_CHAN_VIN, &st->ch_enable_mask);
+	__set_bit(LTC4283_CHAN_VPWR, &st->ch_enable_mask);
+	for (c = LTC4283_CHAN_ADI_1; c < LTC4283_CHAN_MAX; c++) {
+		u32 chan = c - LTC4283_CHAN_ADI_1, bit;
+
+		ret = regmap_read(st->map, LTC4283_ADC_SELECT(chan), &reg_val);
+		if (ret)
+			return ret;
+
+		bit = LTC4283_ADC_SELECT_MASK(chan);
+		if (c > LTC4283_CHAN_DRAIN)
+			/* account for two reserved fields after DRAIN */
+			bit <<= 2;
+
+		if (!(bit & reg_val))
+			continue;
+
+		__set_bit(c, &st->ch_enable_mask);
+	}
+
+	return 0;
+}
+
+static const char * const ltc4283_pgio1_funcs[] = {
+	"inverted_power_good", "power_good", "gpio"
+};
+
+static const char * const ltc4283_pgio2_funcs[] = {
+	 "inverted_power_good", "power_good", "gpio", "active_current_limiting"
+};
+
+static const char * const ltc4283_pgio3_funcs[] = {
+	"inverted_power_good_input", "power_good_input", "gpio"
+};
+
+static const char * const ltc4283_pgio4_funcs[] = {
+	"inverted_external_fault", "external_fault", "gpio"
+};
+
+enum {
+	LTC4283_PIN_ADIO1,
+	LTC4283_PIN_ADIO2,
+	LTC4283_PIN_ADIO3,
+	LTC4283_PIN_ADIO4,
+	LTC4283_PIN_PGIO1,
+	LTC4283_PIN_PGIO2,
+	LTC4283_PIN_PGIO3,
+	LTC4283_PIN_PGIO4,
+};
+
+static int ltc4283_pgio_config(struct ltc4283_hwmon *st, struct device *dev)
+{
+	int ret, func;
+
+	func = device_property_match_property_string(dev, "adi,pgio1-func",
+						     ltc4283_pgio1_funcs,
+						     ARRAY_SIZE(ltc4283_pgio1_funcs));
+	if (func < 0 && func != -EINVAL)
+		return dev_err_probe(dev, func,
+				     "Invalid adi,pgio1-func property\n");
+	if (func >= 0) {
+		if (func == LTC4283_PGIO_FUNC_GPIO) {
+			__set_bit(LTC4283_PIN_PGIO1, &st->gpio_mask);
+			/* If GPIO, default to an input pin. */
+			func++;
+		}
+
+		ret = regmap_update_bits(st->map, LTC4283_PGIO_CONFIG,
+					 LTC4283_PGIO1_CFG_MASK,
+					 FIELD_PREP(LTC4283_PGIO1_CFG_MASK, func));
+		if (ret)
+			return ret;
+	}
+
+	func = device_property_match_property_string(dev, "adi,pgio2-func",
+						     ltc4283_pgio2_funcs,
+						     ARRAY_SIZE(ltc4283_pgio2_funcs));
+
+	if (func < 0 && func != -EINVAL)
+		return dev_err_probe(dev, func,
+				     "Invalid adi,pgio2-func property\n");
+	if (func >= 0) {
+		if (func != LTC4283_PGIO2_FUNC_ACLB) {
+			if (func == LTC4283_PGIO_FUNC_GPIO)  {
+				__set_bit(LTC4283_PIN_PGIO2, &st->gpio_mask);
+				func++;
+			}
+
+			ret = regmap_update_bits(st->map, LTC4283_PGIO_CONFIG,
+						 LTC4283_PGIO2_CFG_MASK,
+						 FIELD_PREP(LTC4283_PGIO2_CFG_MASK, func));
+		} else {
+			ret = regmap_set_bits(st->map, LTC4283_CONTROL_1,
+					      LTC4283_PIGIO2_ACLB_MASK);
+		}
+
+		if (ret)
+			return ret;
+	}
+
+	func = device_property_match_property_string(dev, "adi,pgio3-func",
+						     ltc4283_pgio3_funcs,
+						     ARRAY_SIZE(ltc4283_pgio3_funcs));
+
+	if (func < 0 && func != -EINVAL)
+		return dev_err_probe(dev, func,
+				     "Invalid adi,pgio3-func property\n");
+	if (func >= 0) {
+		if (func == LTC4283_PGIO_FUNC_GPIO) {
+			__set_bit(LTC4283_PIN_PGIO3, &st->gpio_mask);
+			func++;
+		}
+
+		ret = regmap_update_bits(st->map, LTC4283_PGIO_CONFIG,
+					 LTC4283_PGIO3_CFG_MASK,
+					 FIELD_PREP(LTC4283_PGIO3_CFG_MASK, func));
+		if (ret)
+			return ret;
+	}
+
+	func = device_property_match_property_string(dev, "adi,pgio4-func",
+						     ltc4283_pgio4_funcs,
+						     ARRAY_SIZE(ltc4283_pgio4_funcs));
+
+	if (func < 0 && func != -EINVAL)
+		return dev_err_probe(dev, func,
+				     "Invalid adi,pgio4-func property\n");
+	if (func >= 0) {
+		if (func == LTC4283_PGIO_FUNC_GPIO) {
+			__set_bit(LTC4283_PIN_PGIO4, &st->gpio_mask);
+			func++;
+			st->ext_fault = false;
+		} else {
+			st->ext_fault = true;
+		}
+
+		ret = regmap_update_bits(st->map, LTC4283_PGIO_CONFIG,
+					 LTC4283_PGIO4_CFG_MASK,
+					 FIELD_PREP(LTC4283_PGIO4_CFG_MASK, func));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ltc4283_adio_config(struct ltc4283_hwmon *st, struct device *dev,
+			       const char *prop, u32 pin)
+{
+	u32 adc_idx;
+	int ret;
+
+	if (!device_property_read_bool(dev, prop))
+		return 0;
+
+	adc_idx = LTC4283_CHAN_ADIO_1 - LTC4283_CHAN_ADI_1 + pin;
+	ret = regmap_clear_bits(st->map, LTC4283_ADC_SELECT(adc_idx),
+				LTC4283_ADC_SELECT_MASK(adc_idx));
+	if (ret)
+		return ret;
+
+	__set_bit(pin, &st->gpio_mask);
+	return 0;
+}
+
+static int ltc4283_pin_config(struct ltc4283_hwmon *st, struct device *dev)
+{
+	int ret;
+
+	ret = ltc4283_pgio_config(st, dev);
+	if (ret)
+		return ret;
+
+	ret = ltc4283_adio_config(st, dev, "adi,gpio-on-adio1", LTC4283_PIN_ADIO1);
+	if (ret)
+		return ret;
+
+	ret = ltc4283_adio_config(st, dev, "adi,gpio-on-adio2", LTC4283_PIN_ADIO2);
+	if (ret)
+		return ret;
+
+	ret = ltc4283_adio_config(st, dev, "adi,gpio-on-adio3", LTC4283_PIN_ADIO3);
+	if (ret)
+		return ret;
+
+	return ltc4283_adio_config(st, dev, "adi,gpio-on-adio4", LTC4283_PIN_ADIO4);
+}
+
+static const char * const ltc4283_oc_fet_retry[] = {
+	"latch-off", "1", "7", "unlimited"
+};
+
+static const u32 ltc4283_fb_factor[] = {
+	100, 50, 20, 10
+};
+
+static const u32 ltc4283_cooling_dl[] = {
+	512, 1002, 2005, 4100, 8190, 16400, 32800, 65600
+};
+
+static const u32 ltc4283_fet_bad_delay[] = {
+	256, 512, 1002, 2005
+};
+
+static int ltc4283_setup(struct ltc4283_hwmon *st, struct device *dev)
+{
+	u32 val;
+	int ret;
+
+	/* The part has an eeprom so let's get the needed defaults from it */
+	ret = ltc4283_get_defaults(st);
+	if (ret)
+		return ret;
+
+	/*
+	 * Default to LTC4283_MIN_RSENSE so we can probe without FW properties.
+	 */
+	st->rsense = LTC4283_MIN_RSENSE;
+	ret = device_property_read_u32(dev, "adi,rsense-nano-ohms",
+				       &st->rsense);
+	if (!ret) {
+		if (st->rsense < LTC4283_MIN_RSENSE || st->rsense > LTC4283_MAX_RSENSE)
+			return dev_err_probe(dev, -EINVAL,
+					     "adi,rsense-nano-ohms(%u) too small or too large [%u %u]\n",
+					     st->rsense, LTC4283_MIN_RSENSE, LTC4283_MAX_RSENSE);
+	}
+
+	/*
+	 * The resolution for rsense is tenths of micro (eg: 62.5 uOhm) which
+	 * means we need nano in the bindings. However, to make things easier to
+	 * handle (with respect to overflows) we divide it by 100 as we don't
+	 * really need the last two digits.
+	 */
+	st->rsense /= CENTI;
+
+	ret = device_property_read_u32(dev, "adi,current-limit-sense-microvolt",
+				       &st->vsense_max);
+	if (!ret) {
+		u32 reg_val;
+
+		if (!in_range(st->vsense_max, LTC4283_VILIM_MIN_uV,
+			      LTC4283_VILIM_RANGE)) {
+			return dev_err_probe(dev, -EINVAL,
+					     "adi,current-limit-sense-microvolt (%u) out of range [%u %u]\n",
+					     st->vsense_max, LTC4283_VILIM_MIN_uV,
+					     LTC4283_VILIM_MAX_uV);
+		}
+
+		st->vsense_max /= MILLI;
+		reg_val = FIELD_PREP(LTC4283_ILIM_MASK,
+				     st->vsense_max - LTC4283_VILIM_MIN_uV / MILLI);
+		ret = regmap_update_bits(st->map, LTC4283_CONFIG_1,
+					 LTC4283_ILIM_MASK, reg_val);
+		if (ret)
+			return ret;
+	}
+
+	ret = ltc4283_parse_array_prop(st, dev, "adi,current-limit-foldback-factor",
+				       ltc4283_fb_factor, ARRAY_SIZE(ltc4283_fb_factor));
+	if (ret < 0)
+		return ret;
+	if (ret < ARRAY_SIZE(ltc4283_fb_factor)) {
+		ret = regmap_update_bits(st->map, LTC4283_CONFIG_1, LTC4283_FB_MASK,
+					 FIELD_PREP(LTC4283_FB_MASK, ret));
+		if (ret)
+			return ret;
+	}
+
+	ret = ltc4283_parse_array_prop(st, dev, "adi,cooling-delay-ms",
+				       ltc4283_cooling_dl, ARRAY_SIZE(ltc4283_cooling_dl));
+	if (ret < 0)
+		return ret;
+	if (ret < ARRAY_SIZE(ltc4283_cooling_dl)) {
+		ret = regmap_update_bits(st->map, LTC4283_CONFIG_2, LTC4283_COOLING_DL_MASK,
+					 FIELD_PREP(LTC4283_COOLING_DL_MASK, ret));
+		if (ret)
+			return ret;
+	}
+
+	ret = ltc4283_parse_array_prop(st, dev, "adi,fet-bad-timer-delay-ms",
+				       ltc4283_fet_bad_delay, ARRAY_SIZE(ltc4283_fet_bad_delay));
+	if (ret < 0)
+		return ret;
+	if (ret < ARRAY_SIZE(ltc4283_fet_bad_delay)) {
+		ret = regmap_update_bits(st->map, LTC4283_CONFIG_2, LTC4283_FTBD_DL_MASK,
+					 FIELD_PREP(LTC4283_FTBD_DL_MASK, ret));
+		if (ret)
+			return ret;
+	}
+
+	ret = ltc4283_set_max_limits(st, dev);
+	if (ret)
+		return ret;
+
+	ret = ltc4283_pin_config(st, dev);
+	if (ret)
+		return ret;
+
+	if (device_property_read_bool(dev, "adi,power-good-reset-on-fet")) {
+		ret = regmap_clear_bits(st->map, LTC4283_CONTROL_1,
+					LTC4283_PWRGD_RST_CTRL_MASK);
+		if (ret)
+			return ret;
+	}
+
+	if (device_property_read_bool(dev, "adi,fet-turn-off-disable")) {
+		ret = regmap_clear_bits(st->map, LTC4283_CONTROL_1,
+					LTC4283_FET_BAD_OFF_MASK);
+		if (ret)
+			return ret;
+	}
+
+	if (device_property_read_bool(dev, "adi,tmr-pull-down-disable")) {
+		ret = regmap_set_bits(st->map, LTC4283_CONTROL_1,
+				      LTC4283_THERM_TMR_MASK);
+		if (ret)
+			return ret;
+	}
+
+	if (device_property_read_bool(dev, "adi,dvdt-inrush-control-disable")) {
+		ret = regmap_clear_bits(st->map, LTC4283_CONTROL_1,
+					LTC4283_DVDT_MASK);
+		if (ret)
+			return ret;
+	}
+
+	if (device_property_read_bool(dev, "adi,undervoltage-retry-disable")) {
+		ret = regmap_clear_bits(st->map, LTC4283_CONTROL_2,
+					LTC4283_UV_RETRY_MASK);
+		if (ret)
+			return ret;
+	}
+
+	if (device_property_read_bool(dev, "adi,overvoltage-retry-disable")) {
+		ret = regmap_clear_bits(st->map, LTC4283_CONTROL_2,
+					LTC4283_OV_RETRY_MASK);
+		if (ret)
+			return ret;
+	}
+
+	if (device_property_read_bool(dev, "adi,external-fault-retry-enable")) {
+		if (!st->ext_fault)
+			return dev_err_probe(dev, -EINVAL,
+					     "adi,external-fault-retry-enable set but PGIO4 not configured\n");
+		ret = regmap_set_bits(st->map, LTC4283_CONTROL_2,
+				      LTC4283_EXT_FAULT_RETRY_MASK);
+		if (ret)
+			return ret;
+	}
+
+	if (device_property_read_bool(dev, "adi,fault-log-enable")) {
+		ret = regmap_set_bits(st->map, LTC4283_FAULT_LOG_CTRL,
+				      LTC4283_FAULT_LOG_EN_MASK);
+		if (ret)
+			return ret;
+	}
+
+	ret = device_property_match_property_string(dev, "adi,overcurrent-retries",
+						    ltc4283_oc_fet_retry,
+						    ARRAY_SIZE(ltc4283_oc_fet_retry));
+	/* We still want to catch when an invalid string is given. */
+	if (ret < 0 && ret != -EINVAL)
+		return dev_err_probe(dev, ret,
+				     "adi,overcurrent-retries invalid value\n");
+	if (ret >= 0) {
+		ret = regmap_update_bits(st->map, LTC4283_CONTROL_2,
+					 LTC4283_OC_RETRY_MASK,
+					 FIELD_PREP(LTC4283_OC_RETRY_MASK, ret));
+		if (ret)
+			return ret;
+	}
+
+	ret = device_property_match_property_string(dev, "adi,fet-bad-retries",
+						    ltc4283_oc_fet_retry,
+						    ARRAY_SIZE(ltc4283_oc_fet_retry));
+	if (ret < 0 && ret != -EINVAL)
+		return dev_err_probe(dev, ret,
+				     "adi,fet-bad-retries invalid value\n");
+	if (ret >= 0) {
+		ret = regmap_update_bits(st->map, LTC4283_CONTROL_2,
+					 LTC4283_FET_BAD_RETRY_MASK,
+					 FIELD_PREP(LTC4283_FET_BAD_RETRY_MASK, ret));
+		if (ret)
+			return ret;
+	}
+
+	if (device_property_read_bool(dev, "adi,external-fault-fet-off-enable")) {
+		if (!st->ext_fault)
+			return dev_err_probe(dev, -EINVAL,
+					     "adi,external-fault-fet-off-enable set but PGIO4 not configured\n");
+		ret = regmap_set_bits(st->map, LTC4283_CONFIG_3,
+				      LTC4283_EXTFLT_TURN_OFF_MASK);
+		if (ret)
+			return ret;
+	}
+
+	if (device_property_read_bool(dev, "adi,vpower-drns-enable")) {
+		u32 chan = LTC4283_CHAN_DRNS - LTC4283_CHAN_ADI_1;
+
+		__clear_bit(LTC4283_CHAN_DRNS, &st->ch_enable_mask);
+		/*
+		 * Then, let's by default disable DRNS from ADC2 given that it
+		 * is already being monitored by the VPWR channel. One can still
+		 * enable it later on if needed.
+		 */
+		ret = regmap_clear_bits(st->map, LTC4283_ADC_SELECT(chan),
+					LTC4283_ADC_SELECT_MASK(chan));
+		if (ret)
+			return ret;
+
+		val = 1;
+	} else {
+		val = 0;
+	}
+
+	ret = regmap_update_bits(st->map, LTC4283_CONFIG_3,
+				 LTC4283_VPWR_DRNS_MASK,
+				 FIELD_PREP(LTC4283_VPWR_DRNS_MASK, val));
+	if (ret)
+		return ret;
+
+	/* Make sure the ADC has 12bit resolution since we're assuming that. */
+	ret = regmap_update_bits(st->map, LTC4283_PGIO_CONFIG_2,
+				 LTC4283_ADC_MASK,
+				 FIELD_PREP(LTC4283_ADC_MASK, 3));
+	if (ret)
+		return ret;
+
+	/* Energy reads (which are 6 byte block reads) rely on page access */
+	ret = regmap_set_bits(st->map, LTC4283_CONTROL_1, LTC4283_RW_PAGE_MASK);
+	if (ret)
+		return ret;
+
+	/*
+	 * Make sure we are integrating power as we only support reporting
+	 * consumed energy.
+	 */
+	return regmap_clear_bits(st->map, LTC4283_METER_CONTROL,
+				 LTC4283_INTEGRATE_I_MASK);
+}
+
+static const struct hwmon_channel_info * const ltc4283_info[] = {
+	HWMON_CHANNEL_INFO(in,
+			   HWMON_I_LCRIT_ALARM | HWMON_I_CRIT_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_MAX_ALARM | HWMON_I_RESET_HISTORY |
+			   HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_FAULT | HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
+			   HWMON_I_MAX | HWMON_I_MIN | HWMON_I_MIN_ALARM |
+			   HWMON_I_RESET_HISTORY | HWMON_I_MAX_ALARM |
+			   HWMON_I_ENABLE | HWMON_I_LABEL),
+	HWMON_CHANNEL_INFO(curr,
+			   HWMON_C_INPUT | HWMON_C_LOWEST | HWMON_C_HIGHEST |
+			   HWMON_C_MAX | HWMON_C_MIN | HWMON_C_MIN_ALARM |
+			   HWMON_C_MAX_ALARM | HWMON_C_CRIT_ALARM |
+			   HWMON_C_RESET_HISTORY | HWMON_C_LABEL),
+	HWMON_CHANNEL_INFO(power,
+			   HWMON_P_INPUT | HWMON_P_INPUT_LOWEST |
+			   HWMON_P_INPUT_HIGHEST | HWMON_P_MAX | HWMON_P_MIN |
+			   HWMON_P_MAX_ALARM | HWMON_P_MIN_ALARM |
+			   HWMON_P_RESET_HISTORY | HWMON_P_LABEL),
+	HWMON_CHANNEL_INFO(energy,
+			   HWMON_E_ENABLE),
+	HWMON_CHANNEL_INFO(energy64,
+			   HWMON_E_INPUT),
+	NULL
+};
+
+static const struct hwmon_ops ltc4283_ops = {
+	.read = ltc4283_read,
+	.write = ltc4283_write,
+	.is_visible = ltc4283_is_visible,
+	.read_string = ltc4283_read_labels,
+};
+
+static const struct hwmon_chip_info ltc4283_chip_info = {
+	.ops = &ltc4283_ops,
+	.info = ltc4283_info,
+};
+
+static int ltc4283_show_fault_log(void *arg, u64 *val, u32 mask)
+{
+	struct ltc4283_hwmon *st = arg;
+	long alarm;
+	int ret;
+
+	ret = ltc4283_read_alarm(st, LTC4283_FAULT_LOG, mask, &alarm);
+	if (ret)
+		return ret;
+
+	*val = alarm;
+
+	return 0;
+}
+
+static int ltc4283_show_in0_lcrit_fault_log(void *arg, u64 *val)
+{
+	return ltc4283_show_fault_log(arg, val, LTC4283_UV_FAULT_MASK);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(ltc4283_in0_lcrit_fault_log,
+			 ltc4283_show_in0_lcrit_fault_log, NULL, "%llu\n");
+
+static int ltc4283_show_in0_crit_fault_log(void *arg, u64 *val)
+{
+	return ltc4283_show_fault_log(arg, val, LTC4283_OV_FAULT_MASK);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(ltc4283_in0_crit_fault_log,
+			 ltc4283_show_in0_crit_fault_log, NULL, "%llu\n");
+
+static int ltc4283_show_fet_bad_fault_log(void *arg, u64 *val)
+{
+	return ltc4283_show_fault_log(arg, val, LTC4283_FET_BAD_FAULT_MASK);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(ltc4283_fet_bad_fault_log,
+			 ltc4283_show_fet_bad_fault_log, NULL, "%llu\n");
+
+static int ltc4283_show_fet_short_fault_log(void *arg, u64 *val)
+{
+	return ltc4283_show_fault_log(arg, val, LTC4283_FET_SHORT_FAULT_MASK);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(ltc4283_fet_short_fault_log,
+			 ltc4283_show_fet_short_fault_log, NULL, "%llu\n");
+
+static int ltc4283_show_curr1_crit_fault_log(void *arg, u64 *val)
+{
+	return ltc4283_show_fault_log(arg, val, LTC4283_OC_FAULT_MASK);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(ltc4283_curr1_crit_fault_log,
+			 ltc4283_show_curr1_crit_fault_log, NULL, "%llu\n");
+
+static int ltc4283_show_power1_failed_fault_log(void *arg, u64 *val)
+{
+	return ltc4283_show_fault_log(arg, val, LTC4283_PWR_FAIL_FAULT_MASK);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(ltc4283_power1_failed_fault_log,
+			 ltc4283_show_power1_failed_fault_log, NULL, "%llu\n");
+
+static int ltc4283_show_power1_good_input_fault_log(void *arg, u64 *val)
+{
+	return ltc4283_show_fault_log(arg, val, LTC4283_PGI_FAULT_MASK);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(ltc4283_power1_good_input_fault_log,
+			 ltc4283_show_power1_good_input_fault_log, NULL, "%llu\n");
+
+static void ltc4283_debugfs_init(struct ltc4283_hwmon *st, struct i2c_client *i2c)
+{
+	debugfs_create_file_unsafe("in0_crit_fault_log", 0400, i2c->debugfs, st,
+				   &ltc4283_in0_crit_fault_log);
+	debugfs_create_file_unsafe("in0_lcrit_fault_log", 0400, i2c->debugfs, st,
+				   &ltc4283_in0_lcrit_fault_log);
+	debugfs_create_file_unsafe("in0_fet_bad_fault_log", 0400, i2c->debugfs, st,
+				   &ltc4283_fet_bad_fault_log);
+	debugfs_create_file_unsafe("in0_fet_short_fault_log", 0400, i2c->debugfs, st,
+				   &ltc4283_fet_short_fault_log);
+	debugfs_create_file_unsafe("curr1_crit_fault_log", 0400, i2c->debugfs, st,
+				   &ltc4283_curr1_crit_fault_log);
+	debugfs_create_file_unsafe("power1_failed_fault_log", 0400, i2c->debugfs, st,
+				   &ltc4283_power1_failed_fault_log);
+	debugfs_create_file_unsafe("power1_good_input_fault_log", 0400, i2c->debugfs,
+				   st, &ltc4283_power1_good_input_fault_log);
+}
+
+static bool ltc4283_is_word_reg(unsigned int reg)
+{
+	return reg >= LTC4283_SENSE && reg <= LTC4283_ADIO34_MAX;
+}
+
+static int ltc4283_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct i2c_client *client = context;
+	int ret;
+
+	if (ltc4283_is_word_reg(reg))
+		ret = i2c_smbus_read_word_swapped(client, reg);
+	else
+		ret = i2c_smbus_read_byte_data(client, reg);
+
+	if (ret < 0)
+		return ret;
+
+	*val = ret;
+	return 0;
+}
+
+static int ltc4283_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct i2c_client *client = context;
+
+	if (ltc4283_is_word_reg(reg))
+		return i2c_smbus_write_word_swapped(client, reg, val);
+
+	return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static const struct regmap_bus ltc4283_regmap_bus = {
+	.reg_read = ltc4283_reg_read,
+	.reg_write = ltc4283_reg_write,
+};
+
+static bool ltc4283_writable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case LTC4283_SYSTEM_STATUS ... LTC4283_FAULT_STATUS:
+		return false;
+	case LTC4283_RESERVED_OC:
+		return false;
+	case LTC4283_RESERVED_86 ... LTC4283_RESERVED_8F:
+		return false;
+	case LTC4283_RESERVED_91 ... LTC4283_RESERVED_A1:
+		return false;
+	case LTC4283_RESERVED_A3:
+		return false;
+	case LTC4283_RESERVED_AC:
+		return false;
+	case LTC4283_POWER_PLAY_MSB ... LTC4283_POWER_PLAY_LSB:
+		return false;
+	case LTC4283_RESERVED_F1 ... LTC4283_RESERVED_FF:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static const struct regmap_config ltc4283_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.max_register = 0xFF,
+	.writeable_reg = ltc4283_writable_reg,
+};
+
+static int ltc4283_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev, *hwmon;
+	struct auxiliary_device *adev;
+	struct ltc4283_hwmon *st;
+	int ret, id;
+
+	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return -ENOMEM;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WORD_DATA |
+				     I2C_FUNC_SMBUS_READ_I2C_BLOCK))
+		return -EOPNOTSUPP;
+
+	st->client = client;
+	st->map = devm_regmap_init(dev, &ltc4283_regmap_bus, client,
+				   &ltc4283_regmap_config);
+	if (IS_ERR(st->map))
+		return dev_err_probe(dev, PTR_ERR(st->map),
+				     "Failed to create regmap\n");
+
+	ret = ltc4283_setup(st, dev);
+	if (ret)
+		return ret;
+
+	hwmon = devm_hwmon_device_register_with_info(dev, "ltc4283", st,
+						     &ltc4283_chip_info, NULL);
+
+	if (IS_ERR(hwmon))
+		return PTR_ERR(hwmon);
+
+	ltc4283_debugfs_init(st, client);
+
+	if (!st->gpio_mask)
+		return 0;
+
+	id = (client->adapter->nr << 10) | client->addr;
+	adev = __devm_auxiliary_device_create(dev, KBUILD_MODNAME, "gpio",
+					      NULL, id);
+	if (!adev)
+		return dev_err_probe(dev, -ENODEV, "Failed to add GPIO device\n");
+
+	return 0;
+}
+
+static const struct of_device_id ltc4283_of_match[] = {
+	{ .compatible = "adi,ltc4283" },
+	{ }
+};
+
+static const struct i2c_device_id ltc4283_i2c_id[] = {
+	{ "ltc4283" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ltc4283_i2c_id);
+
+static struct i2c_driver ltc4283_driver = {
+	.driver	= {
+		.name = "ltc4283",
+		.of_match_table = ltc4283_of_match,
+	},
+	.probe = ltc4283_probe,
+	.id_table = ltc4283_i2c_id,
+};
+module_i2c_driver(ltc4283_driver);
+
+MODULE_AUTHOR("Nuno Sá <nuno.sa@analog.com>");
+MODULE_DESCRIPTION("LTC4283 Hot Swap Controller driver");
+MODULE_LICENSE("GPL");

-- 
2.53.0



^ permalink raw reply related

* [PATCH v9 0/3] hwmon: Add support for the LTC4283 Hot Swap Controller
From: Nuno Sá via B4 Relay @ 2026-04-06 14:31 UTC (permalink / raw)
  To: linux-gpio, linux-hwmon, devicetree, linux-doc
  Cc: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jonathan Corbet, Linus Walleij, Bartosz Golaszewski,
	Bartosz Golaszewski

This is v8 for the LTC4283 how swap controller. 

Similar to the LTC4282 device, we're clearing some fault logs in the
reset_history attributes.

Guenter, for my last email worrying about rsense low values, this is
what I got internally:

"10uOhm at the smallest sense voltage of 15mV would be 1500A and 72kW, which
seems a tad excessive. The highest currents I’ve seen are around 200A, and
the -48V market 4283 serves is generally a lot lower than that. Normal values
are around 200uOhm.  I’d say the resolution should be around 1uohm and if a
minimum is needed, 50uOhm is probably safe."

For the resolution, I'm pretty sure I got the tenths of micro
resolution for ltc4282 so I just kept it in here. So, if you don't mind
I would prefer to keep it this way to be safer and changing that now would
require me to change some formulas and I would prefer not to do that at
this stage.

---
Changes in v9:
- Patch 2:
  * Add max and min rsense values to avoid 32bit overflows in power and
    rsense * 256;
  * Fix typo in ltc4283_read_in_alarm() s/LTC4283_CHAN_ADIN34/LTC4283_CHAN_ADIO34;
  * Clamp 'val * MILLI' for LTC4283_ADC1_FS_uV in ltc4283_read_in_alarm();
  * Adapt rsense default and property reading for the new range values.
  * Properly construct an auxdev id from the i2c client.
- Link to v8: https://patch.msgid.link/20260327-ltc4283-support-v8-0-471de255d728@analog.com
---

---
Nuno Sá (3):
      dt-bindings: hwmon: Document the LTC4283 Swap Controller
      hwmon: ltc4283: Add support for the LTC4283 Swap Controller
      gpio: gpio-ltc4283: Add support for the LTC4283 Swap Controller

 .../devicetree/bindings/hwmon/adi,ltc4283.yaml     |  272 +++
 Documentation/hwmon/index.rst                      |    1 +
 Documentation/hwmon/ltc4283.rst                    |  266 +++
 MAINTAINERS                                        |    9 +
 drivers/gpio/Kconfig                               |   15 +
 drivers/gpio/Makefile                              |    1 +
 drivers/gpio/gpio-ltc4283.c                        |  218 +++
 drivers/hwmon/Kconfig                              |   12 +
 drivers/hwmon/Makefile                             |    1 +
 drivers/hwmon/ltc4283.c                            | 1808 ++++++++++++++++++++
 10 files changed, 2603 insertions(+)
---
base-commit: 30a90fa04af6937493fbba20e3e923b5b5a162b4
change-id: 20260303-ltc4283-support-063f78acc5a4
--

Thanks!
- Nuno Sá



^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox