* Re: [PATCH v5 01/36] mm: refactor find_next_best_node to find_next_best_node_in
From: Balbir Singh @ 2026-07-21 5:46 UTC (permalink / raw)
To: Gregory Price, linux-mm
Cc: Zhigang.Luo, arun.george, brendan.jackman, yuzenghui, apopple,
alucerop, matthew.brost, akpm, david, ljs, liam, vbabka, rppt,
surenb, mhocko, corbet, skhan, gregkh, rafael, dakr, djbw,
vishal.l.verma, dave.jiang, alison.schofield, osandov, jannh,
pfalcato, jackmanb, hannes, ziy, pbonzini, osalvador,
joshua.hahnjy, rakie.kim, byungchul, ying.huang, kasong, qi.zheng,
shakeel.butt, baohua, axelrasmussen, yuanchu, weixugc, yury.norov,
linux, longman, ridong.chen, tj, mkoutny, sj, jgg, jhubbard,
peterx, baolin.wang, npache, ryan.roberts, dev.jain, lance.yang,
usama.arif, xu.xin16, chengming.zhou, roman.gushchin, muchun.song,
linux-kernel, linux-doc, driver-core, nvdimm, linux-cxl,
linux-debuggers, linux-fsdevel, kvm, cgroups, damon,
linux-kselftest, kernel-team
In-Reply-To: <20260720193431.3841992-2-gourry@gourry.net>
On 7/21/26 5:33 AM, Gregory Price wrote:
> find_next_best_node() picks the next-closest node for a fallback list
> from the full N_MEMORY set. Refactor it into find_next_best_node_in(),
> which takes an explicit candidates nodemask.
>
> This enables building fallback lists with non-N_MEMORY candidates.
>
> No functional change: every caller still selects from N_MEMORY.
>
> Signed-off-by: Gregory Price <gourry@gourry.net>
> ---
> mm/internal.h | 6 ++++--
> mm/memory-tiers.c | 7 ++++---
> mm/page_alloc.c | 13 ++++++++-----
> 3 files changed, 16 insertions(+), 10 deletions(-)
>
> diff --git a/mm/internal.h b/mm/internal.h
> index f26423de4ca28..96d78a7778e88 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -1103,7 +1103,8 @@ extern int node_reclaim_mode;
>
> extern unsigned long node_reclaim(struct pglist_data *pgdat,
> gfp_t gfp_mask, unsigned int order);
> -extern int find_next_best_node(int node, nodemask_t *used_node_mask);
> +extern int find_next_best_node_in(int node, nodemask_t *used_node_mask,
> + const nodemask_t *candidates);
> #else
> #define node_reclaim_mode 0
>
> @@ -1112,7 +1113,8 @@ static inline unsigned long node_reclaim(struct pglist_data *pgdat,
> {
> return 0;
> }
> -static inline int find_next_best_node(int node, nodemask_t *used_node_mask)
> +static inline int find_next_best_node_in(int node, nodemask_t *used_node_mask,
> + const nodemask_t *candidates)
> {
> return NUMA_NO_NODE;
> }
> diff --git a/mm/memory-tiers.c b/mm/memory-tiers.c
> index 54851d8a195b0..25e121851b586 100644
> --- a/mm/memory-tiers.c
> +++ b/mm/memory-tiers.c
> @@ -370,7 +370,7 @@ int next_demotion_node(int node, const nodemask_t *allowed_mask)
> * closest demotion target.
> */
> nodes_complement(mask, *allowed_mask);
> - return find_next_best_node(node, &mask);
> + return find_next_best_node_in(node, &mask, &node_states[N_MEMORY]);
> }
>
> static void disable_all_demotion_targets(void)
> @@ -450,7 +450,7 @@ static void establish_demotion_targets(void)
> memtier = list_next_entry(memtier, list);
> tier_nodes = get_memtier_nodemask(memtier);
> /*
> - * find_next_best_node, use 'used' nodemask as a skip list.
> + * find_next_best_node_in, use 'used' nodemask as a skip list.
> * Add all memory nodes except the selected memory tier
> * nodelist to skip list so that we find the best node from the
> * memtier nodelist.
> @@ -463,7 +463,8 @@ static void establish_demotion_targets(void)
> * in the preferred mask when allocating pages during demotion.
> */
> do {
> - target = find_next_best_node(node, &tier_nodes);
> + target = find_next_best_node_in(node, &tier_nodes,
> + &node_states[N_MEMORY]);
> if (target == NUMA_NO_NODE)
> break;
>
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index f93a6bb9a872d..acf096f525f49 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -5743,9 +5743,10 @@ static int numa_zonelist_order_handler(const struct ctl_table *table, int write,
> static int node_load[MAX_NUMNODES];
>
> /**
> - * find_next_best_node - find the next node that should appear in a given node's fallback list
> + * find_next_best_node_in - find the next node that should appear in a given node's fallback list
> * @node: node whose fallback list we're appending
> * @used_node_mask: nodemask_t of already used nodes
> + * @candidates: nodemask_t of nodes eligible for selection
> *
> * We use a number of factors to determine which is the next node that should
> * appear on a given node's fallback list. The node should not have appeared
> @@ -5757,7 +5758,8 @@ static int node_load[MAX_NUMNODES];
> *
> * Return: node id of the found node or %NUMA_NO_NODE if no node is found.
> */
> -int find_next_best_node(int node, nodemask_t *used_node_mask)
> +int find_next_best_node_in(int node, nodemask_t *used_node_mask,
> + const nodemask_t *candidates)
> {
> int n, val;
> int min_val = INT_MAX;
> @@ -5767,12 +5769,12 @@ int find_next_best_node(int node, nodemask_t *used_node_mask)
> * Use the local node if we haven't already, but for memoryless local
> * node, we should skip it and fall back to other nodes.
> */
> - if (!node_isset(node, *used_node_mask) && node_state(node, N_MEMORY)) {
> + if (!node_isset(node, *used_node_mask) && node_isset(node, *candidates)) {
> node_set(node, *used_node_mask);
> return node;
> }
>
> - for_each_node_state(n, N_MEMORY) {
> + for_each_node_mask(n, *candidates) {
>
> /* Don't want a node to appear more than once */
> if (node_isset(n, *used_node_mask))
> @@ -5857,7 +5859,8 @@ static void build_zonelists(pg_data_t *pgdat)
> prev_node = local_node;
>
> memset(node_order, 0, sizeof(node_order));
> - while ((node = find_next_best_node(local_node, &used_mask)) >= 0) {
> + while ((node = find_next_best_node_in(local_node, &used_mask,
> + &node_states[N_MEMORY])) >= 0) {
> /*
> * We don't want to pressure a particular node.
> * So adding penalty to the first node in same
Looks good!
Acked-by: Balbir Singh <balbirs@nvidia.com>
^ permalink raw reply
* Re: [PATCH v3] docs: dt: maintainer: Add Devicetree and OF maintainer profile document
From: Krzysztof Kozlowski @ 2026-07-21 6:05 UTC (permalink / raw)
To: Rob Herring
Cc: Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet, Shuah Khan,
devicetree, workflows, linux-doc, linux-kernel, Saravana Kannan
In-Reply-To: <CAL_JsqKkxVTVE=o-uar=JEVvqw9NhBAQcBrJ0ukf+RBXCwFZJA@mail.gmail.com>
On 20/07/2026 22:12, Rob Herring wrote:
> On Mon, Jul 20, 2026 at 1:40 PM Krzysztof Kozlowski
> <krzysztof.kozlowski@oss.qualcomm.com> wrote:
>>
>> Document how Devicetree and Open Firmware maintainers handle their
>> subsystem, especially focusing on two caveats:
>>
>> Devicetree subsystem handles patches with a minor difference comparing
>> to other subsystems: while DT maintainers pick up OF code, they only
>> provide review of DT bindings without applying these.
>>
>> All three DT bindings maintainers rely currently on Patchwork and due to
>> enormous amount of emails per day, regardless how much DT maintainers
>> try, they cannot read all the emails.
>>
>> Cc: Rob Herring <robh@kernel.org>
>> Cc: Conor Dooley <conor+dt@kernel.org>
>> Cc: Saravana Kannan <saravanak@kernel.org>
>> Cc: devicetree@vger.kernel.org
>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>>
>> ---
>>
>> I expect patch to be picked up by Rob, after review.
>>
>> Changes in v3:
>> 1. Add also F: entry
>>
>> Changes in v2:
>> 1. Correct typos and trailing white spaces.
>> 2. Fix order of P: after C: in maintainers.
>> ---
>> .../process/maintainer-devicetree.rst | 70 +++++++++++++++++++
>> MAINTAINERS | 3 +
>> 2 files changed, 73 insertions(+)
>> create mode 100644 Documentation/process/maintainer-devicetree.rst
>>
>> diff --git a/Documentation/process/maintainer-devicetree.rst b/Documentation/process/maintainer-devicetree.rst
>> new file mode 100644
>> index 000000000000..d8ffe752bf5d
>> --- /dev/null
>> +++ b/Documentation/process/maintainer-devicetree.rst
>> @@ -0,0 +1,70 @@
>> +.. SPDX-License-Identifier: GPL-2.0
>> +
>> +======================================
>> +Devicetree and Open Firmware Subsystem
>> +======================================
>> +
>> +Other Process Documents
>> +-----------------------
>> +
>> +Please see the documents in Documentation/devicetree/bindings/ for information
>> +on how to write proper Devicetree bindings and how to submit patches.
>> +
>> +Patch Review and Handling
>> +-------------------------
>> +
>> +Patches handled by Devicetree maintainers are processed differently depending
>> +on the patch type:
>> +
>> +1. Core OF driver code, e.g. drivers/of/:
>> + patches are reviewed and applied by DT maintainers.
>> +
>> +2. Devicetree bindings:
>> + patches are reviewed by DT maintainers but, except in certain cases, should
>> + be applied by subsystem maintainers. See also *For kernel maintainers* in
>> + Documentation/devicetree/bindings/submitting-patches.rst.
>
> I would reword:
>
> patches are reviewed by DT maintainers, but should be applied by
> subsystem maintainers except in certain cases.
>
>> +
>> +3. DTS and drivers:
>> + DT maintainers might provide comments, but review is generally not expected.
>
> For DTS, we expect to pass schema checks or at least not add new warnings.
>
> I can address these 2 when applying.
>
I'll make a v4, no problem.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v4] docs: dt: maintainer: Add Devicetree and OF maintainer profile document
From: Krzysztof Kozlowski @ 2026-07-21 6:09 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet,
Shuah Khan, devicetree, workflows, linux-doc, linux-kernel
Cc: Krzysztof Kozlowski, Saravana Kannan, Frank Li
Document how Devicetree and Open Firmware maintainers handle their
subsystem, especially focusing on two caveats:
Devicetree subsystem handles patches with a minor difference comparing
to other subsystems: while DT maintainers pick up OF code, they only
provide review of DT bindings without applying these.
All three DT bindings maintainers rely currently on Patchwork and due to
enormous amount of emails per day, regardless how much DT maintainers
try, they cannot read all the emails.
Cc: Rob Herring <robh@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Saravana Kannan <saravanak@kernel.org>
Cc: devicetree@vger.kernel.org
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
I expect patch to be picked up by Rob, after review.
Changes in v4:
1. Add Rb
2. Reword as Rob requested, add DTS passing dtbs_check
Changes in v3:
1. Add also F: entry
Changes in v2:
1. Correct typos and trailing white spaces.
2. Fix order of P: after C: in maintainers.
---
.../process/maintainer-devicetree.rst | 72 +++++++++++++++++++
MAINTAINERS | 3 +
2 files changed, 75 insertions(+)
create mode 100644 Documentation/process/maintainer-devicetree.rst
diff --git a/Documentation/process/maintainer-devicetree.rst b/Documentation/process/maintainer-devicetree.rst
new file mode 100644
index 000000000000..ecc3ed638725
--- /dev/null
+++ b/Documentation/process/maintainer-devicetree.rst
@@ -0,0 +1,72 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================
+Devicetree and Open Firmware Subsystem
+======================================
+
+Other Process Documents
+-----------------------
+
+Please see the documents in Documentation/devicetree/bindings/ for information
+on how to write proper Devicetree bindings and how to submit patches.
+
+Patch Review and Handling
+-------------------------
+
+Patches handled by Devicetree maintainers are processed differently depending
+on the patch type:
+
+1. Core OF driver code, e.g. drivers/of/:
+ patches are reviewed and applied by DT maintainers.
+
+2. Devicetree bindings:
+ patches are reviewed by DT maintainers, but should be applied by subsystem
+ maintainers except in certain cases. See also *For kernel maintainers* in
+ Documentation/devicetree/bindings/submitting-patches.rst.
+
+3. DTS and drivers:
+ DT maintainers might provide comments, but review is generally not expected.
+ DTS must pass schema checks (dtbs_check) or at least do not add any
+ new warnings.
+
+Patchwork
+~~~~~~~~~
+
+Devicetree maintainers review patches using Patchwork, so the current status of
+a patch can be checked there. For typical driver submissions, Patchwork
+receives the entire patch set, but only a few patches are usually Devicetree
+bindings that are reviewed by DT maintainers.
+
+Explanation of Patchwork statuses:
+
+ - **New**: Not yet processed by the automation toolset.
+ - **Needs ACK**: Waiting for review by DT maintainers.
+ - **Handled Elsewhere**: Non-DT patch; not being reviewed here.
+ - **RFC**: Patch was likely ignored because it was an incomplete RFC.
+ - **Changes Requested**: Patch was reviewed and DT maintainers expect changes.
+ - **Accepted**: Patch was reviewed and applied by DT maintainers to their tree.
+ - **Not Applicable**: Patch was reviewed and is likely in good shape, with a
+ *Reviewed-by* or *Acked-by* tag provided, but DT maintainers expect someone
+ else to apply it.
+
+Patch Re-review and Pinging
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Due to the high volume of email traffic, Devicetree maintainers do not read
+every email they receive and instead rely on Patchwork during the review
+process. They also often skip patches that have already been reviewed.
+
+As a result, maintainers might miss:
+
+1. Questions about already reviewed patches.
+2. Pings, for example when a patch has been reviewed by DT maintainers but has
+ not been picked up by subsystem maintainers.
+
+Such cases can be addressed by:
+
+1. Pinging DT maintainers on the IRC channel.
+2. Dropping the DT maintainer’s *Acked-by* or *Reviewed-by* tag when sending a new
+ version of the patch set, together with an explanation in the patch
+ changelog describing why the tag was removed and what is expected from DT
+ maintainers.
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 0b6b9e6b3900..be6aa5d174c5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20285,6 +20285,7 @@ S: Maintained
Q: http://patchwork.kernel.org/project/devicetree/list/
W: http://www.devicetree.org/
C: irc://irc.libera.chat/devicetree
+P: Documentation/process/maintainer-devicetree.rst
T: git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
F: Documentation/ABI/testing/sysfs-firmware-ofw
F: drivers/of/
@@ -20306,8 +20307,10 @@ L: devicetree@vger.kernel.org
S: Maintained
Q: http://patchwork.kernel.org/project/devicetree/list/
C: irc://irc.libera.chat/devicetree
+P: Documentation/process/maintainer-devicetree.rst
T: git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
F: Documentation/devicetree/
+F: Documentation/process/maintainer-devicetree.rst
F: arch/*/boot/dts/
F: include/dt-bindings/
--
2.53.0
^ permalink raw reply related
* [PATCH v3 0/4] hwmon: Add Kandou KB9002 PCIe retimer driver
From: Andy Chung via B4 Relay @ 2026-07-21 6:31 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andy Chung,
Guenter Roeck, Jonathan Corbet, Shuah Khan
Cc: devicetree, linux-kernel, linux-hwmon, linux-doc, Andy Chung
The Kandou KB9002 is an 8-lane PCIe 5.0 retimer with an integrated
microcontroller that exposes an SMBus 3.0 target (with mandatory PEC)
on its sideband interface. Its firmware aggregates per-lane die
temperatures and publishes the maximum through a register window.
This series adds a hwmon driver for it. The driver reports the
aggregated maximum die temperature as temp1_input, and exposes the
running firmware version and boot status under debugfs.
The series is organised as:
1/4 add the "kandou" vendor prefix
2/4 device tree binding for the retimer
3/4 the driver, Kconfig/Makefile and MAINTAINERS entry
4/4 hwmon documentation
Signed-off-by: Andy Chung <Andy.Chung@amd.com>
---
Changes in v3:
- Drop the private register-access mutex. The temperature read is
already serialised by the hwmon core lock; the debugfs files
(fw_ver, fw_load_status) now take hwmon_lock() to serialise
against it, since they are read outside the core lock.
- Use a named initialiser for the i2c_device_id entry.
- dt-bindings: constrain the reg address range under 'items' rather
than applying minimum/maximum to the array.
- Link to v2: https://patch.msgid.link/20260715-kb9002-upstream-v2-0-2fd390383da5@amd.com
Changes in v2:
- Drop the unconditional I2C_FUNC_I2C requirement at probe; require raw
I2C only in the host-interface switch path, so the driver loads on
SMBus-only adapters when the chip is already strapped to SMBus.
- kb9002_read_revid(): return immediately on a hard I2C read error
instead of retrying the FIFO drain, avoiding needless bus traffic when
the device is absent.
- Link to v1: https://lore.kernel.org/all/20260714-kb9002-upstream-v1-0-8fd2f0b135d8@amd.com
---
Andy Chung (4):
dt-bindings: Add vendor prefix for Kandou
dt-bindings: hwmon: Add Kandou KB9002
hwmon: (kb9002) Add driver for Kandou KB9002 retimer
hwmon: (kb9002) Add documentation
.../devicetree/bindings/hwmon/kandou,kb9002.yaml | 46 ++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
Documentation/hwmon/index.rst | 1 +
Documentation/hwmon/kb9002.rst | 65 +++
MAINTAINERS | 8 +
drivers/hwmon/Kconfig | 11 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/kb9002.c | 469 +++++++++++++++++++++
8 files changed, 603 insertions(+)
---
base-commit: ca078d004cf58137bcf8cb24a8b271397431ba58
change-id: 20260713-kb9002-upstream-06c686e37833
Best regards,
--
Andy Chung <Andy.Chung@amd.com>
^ permalink raw reply
* [PATCH v3 1/4] dt-bindings: Add vendor prefix for Kandou
From: Andy Chung via B4 Relay @ 2026-07-21 6:31 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andy Chung,
Guenter Roeck, Jonathan Corbet, Shuah Khan
Cc: devicetree, linux-kernel, linux-hwmon, linux-doc, Andy Chung
In-Reply-To: <20260721-kb9002-upstream-v3-0-70563922be8d@amd.com>
From: Andy Chung <Andy.Chung@amd.com>
Kandou Bus, S.A. is the vendor of the KB9002 PCIe retimer.
Signed-off-by: Andy Chung <Andy.Chung@amd.com>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 396044f368e7..727871970d97 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -879,6 +879,8 @@ patternProperties:
description: JuTouch Technology Co., Ltd.
"^kam,.*":
description: Kamstrup A/S
+ "^kandou,.*":
+ description: Kandou Bus, S.A.
"^karo,.*":
description: Ka-Ro electronics GmbH
"^keithkoep,.*":
--
2.34.1
^ permalink raw reply related
* [PATCH v3 3/4] hwmon: (kb9002) Add driver for Kandou KB9002 retimer
From: Andy Chung via B4 Relay @ 2026-07-21 6:31 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andy Chung,
Guenter Roeck, Jonathan Corbet, Shuah Khan
Cc: devicetree, linux-kernel, linux-hwmon, linux-doc, Andy Chung
In-Reply-To: <20260721-kb9002-upstream-v3-0-70563922be8d@amd.com>
From: Andy Chung <Andy.Chung@amd.com>
The Kandou KB9002 is an 8-lane PCIe 5.0 retimer that exposes an SMBus
target with mandatory PEC. Add a hwmon driver reporting the firmware
aggregated maximum die temperature as temp1_input, with the firmware
version and boot status under debugfs.
Signed-off-by: Andy Chung <Andy.Chung@amd.com>
---
MAINTAINERS | 8 +
drivers/hwmon/Kconfig | 11 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/kb9002.c | 469 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 489 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9b4b1575bdbd..1d80ac2660e2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13931,6 +13931,14 @@ S: Maintained
F: Documentation/hwmon/k8temp.rst
F: drivers/hwmon/k8temp.c
+KANDOU KB9002 PCIE RETIMER HWMON DRIVER
+M: Andy Chung <andy.chung@amd.com>
+L: linux-hwmon@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/hwmon/kandou,kb9002.yaml
+F: Documentation/hwmon/kb9002.rst
+F: drivers/hwmon/kb9002.c
+
KASAN
M: Andrey Ryabinin <ryabinin.a.a@gmail.com>
R: Alexander Potapenko <glider@google.com>
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 08c29685126a..300329773e87 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -335,6 +335,17 @@ config SENSORS_K10TEMP
This driver can also be built as a module. If so, the module
will be called k10temp.
+config SENSORS_KB9002
+ tristate "Kandou KB9002 PCIe retimer"
+ depends on I2C
+ help
+ If you say yes here you get support for the integrated
+ temperature sensor and firmware version readout on Kandou
+ KB9002 PCIe 5.0 retimers, accessed over SMBus.
+
+ This driver can also be built as a module. If so, the module
+ will be called kb9002.
+
config SENSORS_KBATT
tristate "KEBA battery controller support"
depends on KEBA_CP500
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 63809eeec2f4..0cad7e21634c 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -113,6 +113,7 @@ obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_JC42) += jc42.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o
+obj-$(CONFIG_SENSORS_KB9002) += kb9002.o
obj-$(CONFIG_SENSORS_KBATT) += kbatt.o
obj-$(CONFIG_SENSORS_KFAN) += kfan.o
obj-$(CONFIG_SENSORS_LAN966X) += lan966x-hwmon.o
diff --git a/drivers/hwmon/kb9002.c b/drivers/hwmon/kb9002.c
new file mode 100644
index 000000000000..61a6e522e770
--- /dev/null
+++ b/drivers/hwmon/kb9002.c
@@ -0,0 +1,469 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Kandou KB9002 PCIe 5.0 retimer hwmon driver.
+ *
+ * The retimer exposes a system management bus (SMBus 3.0 with PEC)
+ * target for firmware-managed status registers. This driver assumes
+ * the chip is strapped to SMBus mode and exports the aggregated
+ * maximum die temperature as hwmon temp1_input (millidegrees Celsius)
+ * plus the firmware version and boot status under debugfs.
+ *
+ * Datasheet: Kandou KB9002 PCIe retimer (KA-015171-PD).
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#define KB9002_DEV_NAME "kb9002"
+
+/*
+ * SMBus read command codes. Each read is a two-phase PEC-protected
+ * transaction: prime writes the target address, data reads it back with
+ * the register contents. FW reads use a 16-bit address, HW reads 32-bit.
+ */
+#define KB9002_CC_FW_READ_PRIME 0x82
+#define KB9002_CC_FW_READ_DATA 0x81
+#define KB9002_CC_HW_READ_PRIME 0x8a
+#define KB9002_CC_HW_READ_DATA 0x89
+
+/* Firmware register offsets (16-bit). */
+#define KB9002_FW_REG_VID 0x0004
+#define KB9002_FW_REG_FW_VERSION 0x0500
+#define KB9002_FW_REG_TEMP_MAXIMUM 0x0550
+
+#define KB9002_VID_MASK GENMASK(31, 16)
+#define KB9002_VID_KANDOU 0x1e6f
+
+/* Firmware boot status: 0xe8 in the top byte means init completed OK. */
+#define KB9002_HW_REG_FW_BOOT_STATUS 0xe0090008
+#define KB9002_FW_BOOT_STATUS_OK_MSB 0xe8
+
+/*
+ * Hardware registers reached over raw I2C (32-bit addressing). The
+ * host-interface bit selects SMBus (set) vs raw-I2C target; parts
+ * strapped to raw I2C need it set before SMBus access works.
+ */
+#define KB9002_HW_REG_REVID 0x00480004
+#define KB9002_HW_REG_HOST_IF 0x00480008
+#define KB9002_HOST_IF_SMBUS BIT(1)
+
+#define KB9002_REVID_MASK GENMASK(7, 0)
+#define KB9002_REVID_B0 0x10
+#define KB9002_REVID_B1 0x11
+
+/* Retries to drain a stray leading 0xff from the raw-I2C FIFO. */
+#define KB9002_REVID_READ_RETRIES 16
+
+/* Temperature: 32-bit Q16.16 absolute Kelvin. */
+#define KB9002_TEMP_FRAC_BITS 16
+#define KB9002_ABS_ZERO_MILLI_C (-273150)
+
+/* Firmware takes up to ~2s to respond after a host-interface change. */
+#define KB9002_FW_READY_POLL_US (25 * USEC_PER_MSEC)
+#define KB9002_FW_READY_TIMEOUT_US (2 * USEC_PER_SEC)
+
+struct kb9002_data {
+ struct i2c_client *client;
+ struct device *hwmon_dev;
+};
+
+/* Raw-I2C read: write the 32-bit BE address, then read 4 BE data bytes. */
+static int kb9002_i2c_read(struct i2c_client *client, u32 reg, u32 *val)
+{
+ u8 addr[4];
+ u8 rbuf[4];
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = sizeof(addr),
+ .buf = addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = sizeof(rbuf),
+ .buf = rbuf,
+ },
+ };
+ int ret;
+
+ put_unaligned_be32(reg, addr);
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return ret;
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *val = get_unaligned_be32(rbuf);
+ return 0;
+}
+
+/* Raw-I2C write: 4 BE address bytes followed by 4 BE data bytes. */
+static int kb9002_i2c_write(struct i2c_client *client, u32 reg, u32 val)
+{
+ u8 buf[8];
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ };
+ int ret;
+
+ put_unaligned_be32(reg, &buf[0]);
+ put_unaligned_be32(val, &buf[4]);
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ return ret;
+ if (ret != 1)
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * Read the silicon revision ID. A fresh FIFO may start with a stray
+ * 0xff that shifts the result, so drain one byte between retries until
+ * the top byte is no longer 0xff.
+ */
+static int kb9002_read_revid(struct i2c_client *client, u32 *revid)
+{
+ u8 dummy;
+ int ret;
+ int i;
+
+ for (i = 0; i < KB9002_REVID_READ_RETRIES; i++) {
+ ret = kb9002_i2c_read(client, KB9002_HW_REG_REVID, revid);
+ if (ret)
+ return ret;
+ if ((*revid >> 24) != 0xff)
+ return 0;
+ /* Drain one byte from the chip to re-align the I2C FIFO. */
+ i2c_master_recv(client, &dummy, 1);
+ }
+
+ return -EIO;
+}
+
+/*
+ * Read a 32-bit firmware register over SMBus: block-write the 16-bit LE
+ * address, then block-read the echoed address plus 4 LE data bytes.
+ */
+static int kb9002_fw_read(struct kb9002_data *data, u16 reg, u32 *val)
+{
+ struct i2c_client *client = data->client;
+ u8 addr[2];
+ u8 rbuf[I2C_SMBUS_BLOCK_MAX];
+ int ret;
+
+ put_unaligned_le16(reg, addr);
+
+ ret = i2c_smbus_write_block_data(client, KB9002_CC_FW_READ_PRIME,
+ sizeof(addr), addr);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_block_data(client, KB9002_CC_FW_READ_DATA, rbuf);
+ if (ret < 0)
+ return ret;
+ if (ret < (int)(sizeof(addr) + sizeof(*val)))
+ return -EIO;
+
+ *val = get_unaligned_le32(&rbuf[sizeof(addr)]);
+ return 0;
+}
+
+/* Like kb9002_fw_read but for a hardware register (32-bit LE address). */
+static int kb9002_smbus_hw_read(struct kb9002_data *data, u32 reg, u32 *val)
+{
+ struct i2c_client *client = data->client;
+ u8 addr[4];
+ u8 rbuf[I2C_SMBUS_BLOCK_MAX];
+ int ret;
+
+ put_unaligned_le32(reg, addr);
+
+ ret = i2c_smbus_write_block_data(client, KB9002_CC_HW_READ_PRIME,
+ sizeof(addr), addr);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_block_data(client, KB9002_CC_HW_READ_DATA, rbuf);
+ if (ret < 0)
+ return ret;
+ if (ret < (int)(sizeof(addr) + sizeof(*val)))
+ return -EIO;
+
+ *val = get_unaligned_le32(&rbuf[sizeof(addr)]);
+ return 0;
+}
+
+/*
+ * Switch the host interface from raw-I2C to SMBus and wait for firmware
+ * to come back up. Called only when SMBus access failed in probe, i.e.
+ * the chip is strapped to raw-I2C mode. Confirms the revision, sets the
+ * SMBus-mode bit, then polls until firmware responds again.
+ */
+static int kb9002_enable_smbus_target(struct kb9002_data *data)
+{
+ struct i2c_client *client = data->client;
+ u32 revid;
+ u32 val;
+ int op_ret;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return dev_err_probe(&client->dev, -ENODEV,
+ "raw I2C required to switch to SMBus mode\n");
+
+ ret = kb9002_read_revid(client, &revid);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "revision ID read failed\n");
+
+ switch (FIELD_GET(KB9002_REVID_MASK, revid)) {
+ case KB9002_REVID_B0:
+ case KB9002_REVID_B1:
+ break;
+ default:
+ return dev_err_probe(&client->dev, -ENODEV,
+ "unsupported revision ID 0x%08x\n", revid);
+ }
+
+ ret = kb9002_i2c_read(client, KB9002_HW_REG_HOST_IF, &val);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "host interface read failed\n");
+
+ val |= KB9002_HOST_IF_SMBUS;
+
+ ret = kb9002_i2c_write(client, KB9002_HW_REG_HOST_IF, val);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "host interface write failed\n");
+
+ /* Wait until firmware re-initialisation completes. */
+ ret = read_poll_timeout(kb9002_fw_read, op_ret, op_ret == 0,
+ KB9002_FW_READY_POLL_US,
+ KB9002_FW_READY_TIMEOUT_US, true,
+ data, KB9002_FW_REG_VID, &val);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "firmware not responding over SMBus\n");
+
+ return 0;
+}
+
+/* Convert Q16.16 absolute Kelvin to millidegrees Celsius. */
+static long kb9002_temp_to_milli_c(u32 raw)
+{
+ s64 milli_k = ((s64)raw * 1000) >> KB9002_TEMP_FRAC_BITS;
+
+ return (long)milli_k + KB9002_ABS_ZERO_MILLI_C;
+}
+
+static int kb9002_read_temp(struct kb9002_data *data, long *val)
+{
+ u32 raw;
+ int ret;
+
+ ret = kb9002_fw_read(data, KB9002_FW_REG_TEMP_MAXIMUM, &raw);
+ if (ret)
+ return ret;
+
+ *val = kb9002_temp_to_milli_c(raw);
+ return 0;
+}
+
+static umode_t kb9002_is_visible(const void *drvdata,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ if (type == hwmon_temp &&
+ (attr == hwmon_temp_input || attr == hwmon_temp_label))
+ return 0444;
+ return 0;
+}
+
+static int kb9002_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct kb9002_data *data = dev_get_drvdata(dev);
+
+ if (type == hwmon_temp && attr == hwmon_temp_input)
+ return kb9002_read_temp(data, val);
+
+ return -EOPNOTSUPP;
+}
+
+static int kb9002_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ if (type == hwmon_temp && attr == hwmon_temp_label) {
+ *str = KB9002_DEV_NAME;
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
+static const struct hwmon_ops kb9002_hwmon_ops = {
+ .is_visible = kb9002_is_visible,
+ .read = kb9002_read,
+ .read_string = kb9002_read_string,
+};
+
+static const struct hwmon_channel_info * const kb9002_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL),
+ NULL,
+};
+
+static const struct hwmon_chip_info kb9002_chip_info = {
+ .ops = &kb9002_hwmon_ops,
+ .info = kb9002_hwmon_info,
+};
+
+static int kb9002_fw_version_show(struct seq_file *s, void *unused)
+{
+ struct kb9002_data *data = s->private;
+ u32 ver;
+ int ret;
+
+ guard(hwmon_lock)(data->hwmon_dev);
+
+ ret = kb9002_fw_read(data, KB9002_FW_REG_FW_VERSION, &ver);
+ if (ret)
+ return ret;
+
+ seq_printf(s, "%u.%02u.%02u.%u\n",
+ (ver >> 24) & 0xff, (ver >> 16) & 0xff,
+ (ver >> 8) & 0xff, (ver >> 0) & 0xff);
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(kb9002_fw_version);
+
+static int kb9002_fw_load_status_show(struct seq_file *s, void *unused)
+{
+ struct kb9002_data *data = s->private;
+ u32 status;
+ int ret;
+
+ guard(hwmon_lock)(data->hwmon_dev);
+
+ ret = kb9002_smbus_hw_read(data, KB9002_HW_REG_FW_BOOT_STATUS, &status);
+ if (ret)
+ return ret;
+
+ seq_printf(s, "%s\n",
+ (status >> 24) == KB9002_FW_BOOT_STATUS_OK_MSB ?
+ "normal" : "abnormal");
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(kb9002_fw_load_status);
+
+static void kb9002_debugfs_init(struct kb9002_data *data)
+{
+ struct dentry *dir = data->client->debugfs;
+
+ debugfs_create_file("fw_ver", 0444, dir, data,
+ &kb9002_fw_version_fops);
+ debugfs_create_file("fw_load_status", 0444, dir, data,
+ &kb9002_fw_load_status_fops);
+}
+
+static int kb9002_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct kb9002_data *data;
+ struct device *hwmon_dev;
+ u32 vid;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_PEC))
+ return -ENODEV;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->client = client;
+
+ /* All firmware register accesses are PEC-protected. */
+ client->flags |= I2C_CLIENT_PEC;
+
+ i2c_set_clientdata(client, data);
+
+ /*
+ * Try SMBus first. If the chip is strapped to raw-I2C mode it
+ * will not respond to SMBus framing, so fall back to switching
+ * the host interface over raw I2C and retry.
+ */
+ ret = kb9002_fw_read(data, KB9002_FW_REG_VID, &vid);
+ if (ret) {
+ dev_dbg(dev, "SMBus probe failed (%d), trying raw-I2C host-interface switch\n",
+ ret);
+ ret = kb9002_enable_smbus_target(data);
+ if (ret)
+ return ret;
+ ret = kb9002_fw_read(data, KB9002_FW_REG_VID, &vid);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "VID read failed after host-interface switch\n");
+ }
+ if (FIELD_GET(KB9002_VID_MASK, vid) != KB9002_VID_KANDOU)
+ return dev_err_probe(dev, -ENODEV,
+ "unexpected VID 0x%08x\n", vid);
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, KB9002_DEV_NAME,
+ data,
+ &kb9002_chip_info,
+ NULL);
+ if (IS_ERR(hwmon_dev))
+ return PTR_ERR(hwmon_dev);
+
+ data->hwmon_dev = hwmon_dev;
+ kb9002_debugfs_init(data);
+ return 0;
+}
+
+static const struct i2c_device_id kb9002_id[] = {
+ { .name = KB9002_DEV_NAME },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, kb9002_id);
+
+static const struct of_device_id kb9002_of_match[] = {
+ { .compatible = "kandou,kb9002" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, kb9002_of_match);
+
+static struct i2c_driver kb9002_driver = {
+ .driver = {
+ .name = KB9002_DEV_NAME,
+ .of_match_table = kb9002_of_match,
+ },
+ .probe = kb9002_probe,
+ .id_table = kb9002_id,
+};
+module_i2c_driver(kb9002_driver);
+
+MODULE_AUTHOR("Andy Chung <andy.chung@amd.com>");
+MODULE_DESCRIPTION("Kandou KB9002 PCIe retimer hwmon driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related
* [PATCH v3 2/4] dt-bindings: hwmon: Add Kandou KB9002
From: Andy Chung via B4 Relay @ 2026-07-21 6:31 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andy Chung,
Guenter Roeck, Jonathan Corbet, Shuah Khan
Cc: devicetree, linux-kernel, linux-hwmon, linux-doc, Andy Chung
In-Reply-To: <20260721-kb9002-upstream-v3-0-70563922be8d@amd.com>
From: Andy Chung <Andy.Chung@amd.com>
Add device tree bindings for the Kandou KB9002 PCIe 5.0 retimer, an
SMBus target that exposes an aggregated die temperature.
Signed-off-by: Andy Chung <Andy.Chung@amd.com>
---
.../devicetree/bindings/hwmon/kandou,kb9002.yaml | 46 ++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/Documentation/devicetree/bindings/hwmon/kandou,kb9002.yaml b/Documentation/devicetree/bindings/hwmon/kandou,kb9002.yaml
new file mode 100644
index 000000000000..0d939c8aa734
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/kandou,kb9002.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/kandou,kb9002.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Kandou KB9002 PCIe 5.0 retimer
+
+maintainers:
+ - Andy Chung <andy.chung@amd.com>
+
+description: |
+ The Kandou KB9002 is an 8-lane PCIe 5.0 retimer that exposes a
+ firmware-controlled SMBus 3.0 target on its sideband interface.
+ The host can query the aggregated maximum die temperature and the
+ running firmware version through that target.
+
+ The 7-bit SMBus address is selected by three SMB_ADDR straps and
+ ranges from 0x20 to 0x27.
+
+properties:
+ compatible:
+ const: kandou,kb9002
+
+ reg:
+ items:
+ - minimum: 0x20
+ maximum: 0x27
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ retimer@20 {
+ compatible = "kandou,kb9002";
+ reg = <0x20>;
+ };
+ };
--
2.34.1
^ permalink raw reply related
* [PATCH v3 4/4] hwmon: (kb9002) Add documentation
From: Andy Chung via B4 Relay @ 2026-07-21 6:31 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andy Chung,
Guenter Roeck, Jonathan Corbet, Shuah Khan
Cc: devicetree, linux-kernel, linux-hwmon, linux-doc, Andy Chung
In-Reply-To: <20260721-kb9002-upstream-v3-0-70563922be8d@amd.com>
From: Andy Chung <Andy.Chung@amd.com>
Document the sysfs and debugfs interfaces of the Kandou KB9002 hwmon
driver.
Signed-off-by: Andy Chung <Andy.Chung@amd.com>
---
Documentation/hwmon/index.rst | 1 +
Documentation/hwmon/kb9002.rst | 65 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 226789376217..9dc796d087dc 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -112,6 +112,7 @@ Hardware Monitoring Kernel Drivers
jc42
k10temp
k8temp
+ kb9002
kbatt
kfan
lan966x
diff --git a/Documentation/hwmon/kb9002.rst b/Documentation/hwmon/kb9002.rst
new file mode 100644
index 000000000000..e6d8d9c78923
--- /dev/null
+++ b/Documentation/hwmon/kb9002.rst
@@ -0,0 +1,65 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+Kernel driver kb9002
+====================
+
+Supported chips:
+
+ * Kandou KB9002
+
+ Prefix: 'kb9002'
+
+ Addresses scanned: -
+
+ Datasheet: KA-015171-PD (available from Kandou under NDA)
+
+Author: Andy Chung <andy.chung@amd.com>
+
+Description
+-----------
+
+The Kandou KB9002 is an 8-lane PCIe 5.0 retimer with an integrated
+microcontroller. It exposes an SMBus 3.0 target (with mandatory PEC)
+on its sideband interface. The internal firmware aggregates per-lane
+die temperatures and publishes the maximum value through a 16-bit
+addressed register window.
+
+This driver reports that aggregated maximum as the only hwmon
+temperature channel. The running firmware version and the firmware
+boot status are exposed under debugfs.
+
+sysfs interface
+---------------
+
+================== ===============================================
+temp1_input Aggregated maximum die temperature across all
+ active lanes (millidegrees Celsius).
+temp1_label Always "kb9002".
+================== ===============================================
+
+debugfs interface
+-----------------
+
+Files live in the per-client debugfs directory created by the I2C
+core: ``/sys/kernel/debug/i2c/i2c-<bus>/<bus>-<addr>/``.
+
+================== ===============================================
+fw_ver Running firmware version in
+ "major.minor.patch.suffix" format. Read-only.
+fw_load_status Firmware boot status: "normal" once firmware has
+ finished initialising, "abnormal" otherwise.
+ Read-only.
+================== ===============================================
+
+Notes
+-----
+
+The driver requires ``I2C_FUNC_SMBUS_BLOCK_DATA``,
+``I2C_FUNC_SMBUS_PEC`` and ``I2C_FUNC_I2C`` from the host adapter. The
+last is needed only during probe for the host-interface mode switch;
+runtime accesses use SMBus block transactions exclusively.
+
+The retimer's SMBus address is configurable on three strap pins and
+ranges from 0x20 to 0x27. The address is selected through device tree
+(or i2c board info) the same way as any other I2C device; the driver
+does not auto-detect.
--
2.34.1
^ permalink raw reply related
* Re: [RFC PATCH 0/2] KVM: x86/pmu: Let userspace disable SW accounting of emulated instructions
From: David Woodhouse @ 2026-07-21 7:32 UTC (permalink / raw)
To: Luka Absandze, Sean Christopherson, Paolo Bonzini, kvm
Cc: linux-kernel, linux-doc, Alexander Graf
In-Reply-To: <20260720192221.72912-1-absandze@amazon.de>
[-- Attachment #1: Type: text/plain, Size: 769 bytes --]
On Mon, 2026-07-20 at 19:22 +0000, Luka Absandze wrote:
> On hosts that run guests with an *emulated* vPMU -- guest PMU MSR
> accesses trap into KVM and each guest counter is backed by a host
> perf_event -- the per-emulated-instruction PMU accounting added by commit
> 9cd803d496e7 ("KVM: x86: Update vPMCs when retiring instructions") is
> pathologically expensive.
Given that the guest PMU MSR accesses are trapped... is there a reason
we can't fold a *separate* count of emulated instructions into the
value we return to the guest?
I guess the overflow would come late... but isn't that tolerable? And
we could probably impose a limit on how large the addend could be —
even if we only reprogram the PMU once every 100 times, that's still a
win?
[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 6179 bytes --]
^ permalink raw reply
* Re: [RFC PATCH 1/2] KVM: x86/pmu: Add CAP to disable SW accounting of emulated instructions
From: David Woodhouse @ 2026-07-21 7:33 UTC (permalink / raw)
To: Sean Christopherson, Luka Absandze
Cc: Paolo Bonzini, kvm, linux-kernel, linux-doc, Alexander Graf
In-Reply-To: <al6g4VA4l-ZIAr9Q@google.com>
[-- Attachment #1: Type: text/plain, Size: 1203 bytes --]
On Mon, 2026-07-20 at 15:27 -0700, Sean Christopherson wrote:
> On Mon, Jul 20, 2026, Luka Absandze wrote:
> > The only functional change for an opted-in VM is reduced accuracy: a
> > guest counting instructions-retired or branches-retired undercounts by
> > the instructions KVM emulates in host context, i.e. the behavior that
> > predates the accounting cited above. Hardware-executed guest
> > instructions continue to be counted by the backing perf_event, and its
> > overflow/PMI path is unchanged.
>
> Do you *need* per-VM control, or would a module param (or a magic value for
> enable_pmu) suffice? While I mostly buy the "it used to work this way" argument
> (just "mostly", because that commit landed 4.5 years ago), I'm not exactly keen
> on adding uAPI that is effectively "re-introduce a bug to workaround fundamental
> design issues in KVM's emulated PMU implementation".
Which is the bug? Some would argue that timer interrupts running 50
times slower is also a bug. We just get to choose *which* bug we want
the guest to experience :)
And I think that is a per-guest choice, if we can't find a way to do it
with *sufficient* correctness *and* efficiency (qv).
[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 6179 bytes --]
^ permalink raw reply
* Re: [PATCH 1/6] dt-bindings: iio: adc: Add AD7768
From: Janani Sunil @ 2026-07-21 8:03 UTC (permalink / raw)
To: David Lechner, Janani Sunil, Nuno Sá, Michael Hennerich,
Jonathan Cameron, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, Philipp Zabel,
Linus Walleij, Bartosz Golaszewski, Jonathan Corbet, Shuah Khan
Cc: linux, linux-iio, devicetree, linux-kernel, linux-gpio, linux-doc
In-Reply-To: <e791f4f9-63dd-40f5-aec4-5b540bcee5ff@baylibre.com>
On 7/21/26 03:39, David Lechner wrote:
> On 7/20/26 9:00 AM, Janani Sunil wrote:
>> On 7/9/26 17:43, David Lechner wrote:
>>> On 7/9/26 3:50 AM, Janani Sunil wrote:
>>>> Devicetree Bindings for AD7768-4 (4 channel) and AD7768 (8 channel)
>>>> simultaneous sampling ADC
>>>>
>>>> Signed-off-by: Janani Sunil <janani.sunil@analog.com>
>>>> ---
>>>>
>>>> +
>>>> + adi,power-mode:
>>>> + $ref: /schemas/types.yaml#/definitions/string
>>>> + enum:
>>>> + - low
>>>> + - median
>>>> + - fast
>>>> + description:
>>>> + Power mode selection.
>>> Unless there are pins that control this, it seems like it should be
>>> left up to the driver to decide how to set this.
>>>
>>> In this case, it looks like the power mode also influences sample rate
>>> which is normally something controlled at runtime.
> Looking at this again, there is also an MCLK divider that influences
> sample rate, so sampling_frequency to power mode is not straight-forward
> anyway.
>
>> Hi David,
>>
>> The reason we'd like to retain power mode control is that certain ODRs are supported across all three power modes (low/median/fast), and the RMS noise and power consumption differ significantly between them at the same ODR.
>>
>> The higher the power mode, the better the noise performance, but power consumption nearly doubles for every ~3 dB improvement in dynamic range. Silently selecting one power mode in the driver would remove a meaningful hardware tradeoff from the user.
>>
>> We'd like to propose the following instead:
>> - Remove adi,power-mode from the DT as suggested.
>> - Expose power mode as a per-device sysfs attribute.
>> - in_voltage<N>_sampling_frequency_available dynamically reflects only the ODRs valid for the currently selected power mode.
>>
>> This keeps the DT clean while still giving the user explicit control over the noise versus power trade off. Would this approach be acceptable?
>>
>> Thanks,
>> Jan
>>
>>
> Jonathan usually pushes back against userspace power controls. We do have
> this for accelerometers, but not ADCs currently.
>
> If we can't think of anything better, maybe we could use this. It only
> has low_noise and low_power options though, so the driver would still
> need to chose the best power mode of the 3 based on the other requested
> parameters. E.g. always make all sampling_frequency available and just
> pick the highest power or lowest power mode that can provide that rate
> based on the power_mode attribute.
>
> I wanted to suggest maybe adding some kind of noise attribute instead,
> but I'm not sure how we could do that in a way using SI units since the
> value would depend on so many things (at least V_REF voltage, filter type,
> temperature and even the physical input).
We considered the low_power/balanced/low_noise approach, but the customers typically use the datasheet alongside the driver and the datasheet explicitly uses the terms "low power", "median" and "fast" for the three modes. Abstracting them with different names in the sysfs attribute would create a confusion- the users would have to mentally translate between the two naming conventions.
The noise attribute would not actually configure anything on a register level- it would purely be informational. Furthermore, noise performance is not solely determined by the power mode. There are other parameters (eg. filter mode) that has a significant impact. A power_mode attribute directly configures the hardware register and has a deterministic effect on the device.
Jonathan, could we keep the power_mode as an attribute in this case?
^ permalink raw reply
* Re: [patch 00/18] entry: Consolidate and rework syscall entry handling
From: Thomas Gleixner @ 2026-07-21 8:17 UTC (permalink / raw)
To: Magnus Lindholm
Cc: LKML, Peter Zijlstra, Michael Ellerman, Shrikanth Hegde,
linuxppc-dev, Kees Cook, Huacai Chen, loongarch, Paul Walmsley,
Palmer Dabbelt, linux-riscv, Sven Schnelle, linux-s390, x86,
Mark Rutland, Jinjie Ruan, Andy Lutomirski, Oleg Nesterov,
Richard Henderson, Russell King, Catalin Marinas, Guo Ren,
Geert Uytterhoeven, Thomas Bogendoerfer, Helge Deller,
Yoshinori Sato, Richard Weinberger, Chris Zankel,
linux-arm-kernel, linux-alpha, linux-csky, linux-m68k, linux-mips,
linux-parisc, linux-sh, linux-um, Arnd Bergmann, Vineet Gupta,
Will Deacon, Brian Cain, Michal Simek, Dinh Nguyen,
David S. Miller, Andreas Larsson, linux-snps-arc, linux-hexagon,
linux-openrisc, sparclinux, linux-arch, Michal Suchánek,
Jonathan Corbet, linux-doc
In-Reply-To: <CA+=Fv5Sd5+-K3-MOiEc2N8z_5CoLQPVPUwjiugSj3u8cBWJXXQ@mail.gmail.com>
Magnus!
On Tue, Jul 21 2026 at 00:01, Magnus Lindholm wrote:
> On Mon, Jul 20, 2026 at 9:21 PM Thomas Gleixner <tglx@kernel.org> wrote:
>> If you want to base your stuff on that for 7.3, I can add a tag which
>> makes it immutable so it can be pulled into the alpha tree.
>
> Yes, please. There is still some ongoing testing/review of my Alpha
> GENERIC_ENTRY series, but assuming it is ready in time for the 7.3 merge
> window, an immutable tag would be very helpful.
Here you go:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core-entry-for-arch-07-21-26
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH v2 1/4] dt-bindings: Add vendor prefix for Kandou
From: Krzysztof Kozlowski @ 2026-07-21 8:24 UTC (permalink / raw)
To: Andy Chung
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Jonathan Corbet, Shuah Khan, devicetree, linux-kernel,
linux-hwmon, linux-doc
In-Reply-To: <20260715-kb9002-upstream-v2-1-2fd390383da5@amd.com>
On Wed, Jul 15, 2026 at 05:08:35PM +0800, Andy Chung wrote:
> Kandou Bus, S.A. is the vendor of the KB9002 PCIe retimer.
>
> Signed-off-by: Andy Chung <Andy.Chung@amd.com>
> ---
> Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
> 1 file changed, 2 insertions(+)
What's the domain or ticker name? I find only Kandou AI, so not the
"bus" variant...
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3 1/4] dt-bindings: Add vendor prefix for Kandou
From: Krzysztof Kozlowski @ 2026-07-21 8:27 UTC (permalink / raw)
To: Andy.Chung, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Guenter Roeck, Jonathan Corbet, Shuah Khan
Cc: devicetree, linux-kernel, linux-hwmon, linux-doc
In-Reply-To: <20260721-kb9002-upstream-v3-1-70563922be8d@amd.com>
On 21/07/2026 08:31, Andy Chung via B4 Relay wrote:
> From: Andy Chung <Andy.Chung@amd.com>
>
> Kandou Bus, S.A. is the vendor of the KB9002 PCIe retimer.
>
> Signed-off-by: Andy Chung <Andy.Chung@amd.com>
> ---
Bad timing, I replied under v2.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v18 11/13] PCI: Cache PCI DSN into pci_dev->dsn during probe
From: Lukas Wunner @ 2026-07-21 8:37 UTC (permalink / raw)
To: Bowman, Terry
Cc: Bjorn Helgaas, Dan Williams, Dave Jiang, Ira Weiny,
Jonathan Cameron, Len Brown, Rafael J . Wysocki, Robert Richter,
linux-acpi, linux-cxl, linux-doc, linux-kernel, linux-pci,
linuxppc-dev, Alejandro Lucero, Alison Schofield, Ankit Agrawal,
Ard Biesheuvel, Ben Cheatham, Borislav Petkov, Breno Leitao,
Davidlohr Bueso, Fabio M . De Francesco, Gregory Price,
Hanjun Guo, Jonathan Corbet, Kees Cook,
Kuppuswamy Sathyanarayanan, Li Ming, Mahesh J Salgaonkar,
Mauro Carvalho Chehab, Oliver O'Halloran, Shiju Jose,
Shuah Khan, Shuai Xue, Smita Koralahalli, Tony Luck, Vishal Verma
In-Reply-To: <91e35807-9483-45f5-b4a8-0388aa48ff6f@amd.com>
On Mon, Jul 20, 2026 at 10:48:06AM -0500, Bowman, Terry wrote:
> +++ b/drivers/pci/hotplug/pciehp.h
> @@ -90,7 +90,6 @@ extern int pciehp_poll_time;
> */
> struct controller {
> struct pcie_device *pcie;
> - u64 dsn;
>
Please drop the kernel-doc for this struct member as well.
> +++ b/drivers/pci/hotplug/pciehp_hpc.c
> @@ -1086,8 +1086,6 @@ struct controller *pcie_init(struct pcie_device *dev)
> }
>
> pdev = pci_get_slot(subordinate, PCI_DEVFN(0, 0));
> - if (pdev)
> - ctrl->dsn = pci_get_dsn(pdev);
> pci_dev_put(pdev);
>
Please drop the pci_get_slot() + pci_dev_put() as well,
they're obviously superfluous now.
> +++ b/drivers/pci/hotplug/pciehp_pci.c
> @@ -73,7 +73,6 @@ int pciehp_configure_device(struct controller *ctrl)
> down_read_nested(&ctrl->reset_lock, ctrl->depth);
>
> dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
> - ctrl->dsn = pci_get_dsn(dev);
> pci_dev_put(dev);
>
Same here.
Thanks,
Lukas
^ permalink raw reply
* Re: [PATCH net-next v5 10/13] net: phy: add generic helpers for direct C45 MMD access
From: Paolo Abeni @ 2026-07-21 8:46 UTC (permalink / raw)
To: Selvamani Rajagopal, ciprian.regus@analog.com,
Parthiban Veerasooran, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Simon Horman, Jonathan Corbet, Shuah Khan,
Andrew Lunn, Heiner Kallweit, Russell King, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-doc@vger.kernel.org, devicetree@vger.kernel.org
In-Reply-To: <CYYPR02MB9828A0F83559EF025D01A14C83FE2@CYYPR02MB9828.namprd02.prod.outlook.com>
On 7/9/26 4:29 AM, Selvamani Rajagopal wrote:
>
>> +int genphy_read_mmd_c45(struct phy_device *phydev, int devnum, u16 regnum)
>> +{
>> + struct mii_bus *bus = phydev->mdio.bus;
>> + int addr = phydev->mdio.addr;
>
> You may want to insert the lockdep_assert here. That'll ensure that read/write APIs are called
> after the mdio-lock is taken. Andrew's suggestion.
>
> lockdep_assert_held(&bus->mdio_lock)
Since this looks like the only pending item and has no functional
implication, I think it's better handled as a (separate) follow-up.
/P
^ permalink raw reply
* Re: [PATCH net-next v5 13/13] net: ethernet: adi: Add a driver for the ADIN1140 MACPHY
From: Paolo Abeni @ 2026-07-21 8:52 UTC (permalink / raw)
To: ciprian.regus, Parthiban Veerasooran, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Simon Horman,
Jonathan Corbet, Shuah Khan, Andrew Lunn, Heiner Kallweit,
Russell King, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: netdev, linux-kernel, linux-doc, devicetree
In-Reply-To: <20260708-adin1140-driver-v5-13-4aca7b51a58b@analog.com>
On 7/8/26 12:33 AM, Ciprian Regus via B4 Relay wrote:
> +static void adin1140_get_eth_mac_stats(struct net_device *netdev,
> + struct ethtool_eth_mac_stats *mac_stats)
> +{
> + struct adin1140_priv *priv = netdev_priv(netdev);
> +
> + scoped_guard(spinlock, &priv->stat_lock)
> + __adin1140_eth_mac_stats(priv, mac_stats);
I understand that past reviews suggested scoped_guard usage explicitly,
but FYI this is not the netdev preference, especially in trivial case
like the above, where it has very little - if any - advantages over
plain spin_lock.
Not a blocker anyway, just a note for future submissions.
/P
^ permalink raw reply
* Re: [PATCH net-next v5 00/13] net: Add ADIN1140 support
From: patchwork-bot+netdevbpf @ 2026-07-21 9:00 UTC (permalink / raw)
To: Ciprian Regus
Cc: parthiban.veerasooran, andrew+netdev, davem, edumazet, kuba,
pabeni, horms, corbet, skhan, andrew, hkallweit1, linux, robh,
krzk+dt, conor+dt, netdev, linux-kernel, linux-doc, devicetree,
conor.dooley
In-Reply-To: <20260708-adin1140-driver-v5-0-4aca7b51a58b@analog.com>
Hello:
This series was applied to netdev/net-next.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Wed, 08 Jul 2026 01:33:28 +0300 you wrote:
> This series introduces support for the ADIN1140 (also called AD3306)
> 10BASE-T1S single port MACPHY. The device integrates the MAC and PHY in
> the same package. The communication with the host CPU is done through an
> SPI interface, using the Open Alliance TC6 protocol for control and data
> transactions. As a result, the oa_tc6 framework is used to implement
> the communication with the device (register accesses and Ethernet frame
> RX/TX).
>
> [...]
Here is the summary with links:
- [net-next,v5,01/13] dt-bindings: net: Add ADIN1140
https://git.kernel.org/netdev/net-next/c/2aa955bc52e9
- [net-next,v5,02/13] net: ethernet: oa_tc6: Handle the OA TC6 SPI protected mode
https://git.kernel.org/netdev/net-next/c/7d0e4c4b8c85
- [net-next,v5,03/13] net: ethernet: oa_tc6: add OA_TC6_BROKEN_PHY quirk flag
https://git.kernel.org/netdev/net-next/c/1d030cdd52ee
- [net-next,v5,04/13] net: ethernet: oa_tc6: Export the C45 access functions
https://git.kernel.org/netdev/net-next/c/87ac7ea2153c
- [net-next,v5,05/13] net: ethernet: oa_tc6: Export standard defined registers
https://git.kernel.org/netdev/net-next/c/9210d402bdf5
- [net-next,v5,06/13] net: ethernet: oa_tc6: Add the OA_TC6_ prefix to standard registers
https://git.kernel.org/netdev/net-next/c/31bc75f17c1f
- [net-next,v5,07/13] net: ethernet: oa_tc6: Add read_mms/write_mms register access functions
https://git.kernel.org/netdev/net-next/c/6ad250179486
- [net-next,v5,08/13] net: ethernet: oa_tc6: Use the read_mms/write_mms functions for C45
https://git.kernel.org/netdev/net-next/c/92ec8d69ddb0
- [net-next,v5,09/13] net: ethernet: oa_tc6: Add new register address defines
https://git.kernel.org/netdev/net-next/c/638b41f770ad
- [net-next,v5,10/13] net: phy: add generic helpers for direct C45 MMD access
https://git.kernel.org/netdev/net-next/c/aa63217916e1
- [net-next,v5,11/13] net: phy: microchip-t1s: use generic C45 MMD access helpers
https://git.kernel.org/netdev/net-next/c/85032df227f9
- [net-next,v5,12/13] net: phy: Add support for the ADIN1140 PHY
https://git.kernel.org/netdev/net-next/c/0feaf415b782
- [net-next,v5,13/13] net: ethernet: adi: Add a driver for the ADIN1140 MACPHY
https://git.kernel.org/netdev/net-next/c/20e69e671070
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH v2 0/6] hwmon: (lm63) Add Sensylink CTF2301 support
From: Troy Mitchell @ 2026-07-21 9:48 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Yixun Lan, Jonathan Corbet, Shuah Khan
Cc: Troy Mitchell, devicetree, linux-kernel, linux-hwmon, linux-riscv,
spacemit, linux-doc, Jean Delvare
Sensylink CTF2301 is a system-level thermal management solution chip.
The CTF2301 is an I2C/SMBus compatible device featuring:
- One local temperature sensor with +/-0.5 degree C accuracy and
0.0625 degree C resolution.
- One remote temperature sensor for external diode-connected
transistors, offering +/-1 degree C accuracy and 0.125 degree C
resolution (temperature range: -40 degree C to +125 degree C).
- An integrated PWM fan controller capable of operating in two modes:
1. Direct-DCY: Open-loop direct duty cycle control.
2. Auto-Temp: Closed-loop automatic fan speed control based on
measured temperature.
- A 1-channel fan speed monitor (TACH input) for RPM measurement.
As Guenter pointed out on v1, the CTF2301 register map is a near match
for the LM63/LM96163 family (local and remote temperature, tachometer and
PWM fan control), so this version drops the standalone ctf2301 driver
and instead adds CTF2301 as a new chip type in the existing lm63 driver.
This reuses the shared temperature, limit, alarm and PWM handling instead
of duplicating it.
The CTF2301-specific differences are handled on top of lm63: 12-bit local
temperature input and high-limit values, nine conversion rates, 12
fan-control lookup table entries, and optional 22.5 kHz high-resolution
PWM. When no IRQ is described, the shared ALERT/TACH pin is configured as
a tachometer input. The LM63 family can also register as a thermal cooling
device when the device tree provides the #cooling-cells property.
The required SpacemiT I2C controller clock series has been merged but is
not yet included in an rc release:
https://lore.kernel.org/all/20260508-k1-i2c-ilcr-v7-0-8c2dde5c3ed5@linux.spacemit.com/
Apply that series before testing this series on K3. Without it, the I2C
controller cannot generate an accurate 400 kHz SCL clock and CTF2301
accesses may fail.
Tested on a SpacemiT K3 CoM260 by booting an initramfs and verifying the
CTF2301 probe. Temperature, tachometer, PWM, and conversion-rate behavior
were checked against direct I2C register accesses and the datasheet.
Datasheet:
https://www.sensylink.com/upload/1/net.sensylink.portal/1689557281035.pdf
Register description:
https://github.com/TroyMitchell911/ctf2301-datasheet
Signed-off-by: Troy Mitchell <troy.mitchell@linux.dev>
---
Changes in v2:
- Replace the standalone CTF2301 driver with a new lm63 chip type, as
suggested by Guenter, reusing the existing temperature, limit, alarm,
tachometer, PWM, and automatic fan-control paths.
- Add the temperature thresholds, alarms, and automatic fan-control lookup
table support which were missing from the v1 driver.
- Handle CTF2301-specific 12-bit local temperature values, nine conversion
rates, 12 lookup table entries, shared ALERT/TACH pin, and optional
22.5 kHz high-resolution PWM.
- Propagate SMBus failures from lm63 initialization and write paths.
- Add optional thermal cooling-device support for the LM63 family using
the existing manual PWM control path.
- Move the National LM63-family compatibles from trivial-devices.yaml to a
dedicated binding which permits #cooling-cells.
- Add CTF2301 to the LM63-family binding instead of keeping the standalone
schema from v1. Do not declare #cooling-cells on K3 CoM260 yet because
the board has no thermal consumer.
- Fix the binding errors reported by Rob by using a plain compatible string
and wrapping the description.
- Document CTF2301 support in the lm63 hwmon documentation and provide the
detailed register description used for review.
- Add the K3 CoM260 I2C6 pinctrl state and CTF2301 device node for hardware
testing.
- Link to v1: https://lore.kernel.org/r/20250916-ctl2301-v1-0-97e7c84f2c47@linux.dev
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: Guenter Roeck <linux@roeck-us.net>
To: Paul Walmsley <pjw@kernel.org>
To: Palmer Dabbelt <palmer@dabbelt.com>
To: Albert Ou <aou@eecs.berkeley.edu>
To: Alexandre Ghiti <alex@ghiti.fr>
To: Yixun Lan <dlan@kernel.org>
To: Jonathan Corbet <corbet@lwn.net>
To: Shuah Khan <skhan@linuxfoundation.org>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-hwmon@vger.kernel.org
Cc: linux-riscv@lists.infradead.org
Cc: spacemit@lists.linux.dev
Cc: linux-doc@vger.kernel.org
---
Troy Mitchell (6):
dt-bindings: vendor-prefixes: Add Sensylink
dt-bindings: hwmon: Move LM63 family to a dedicated binding
dt-bindings: hwmon: Add Sensylink CTF2301
hwmon: (lm63) Add Sensylink CTF2301 support
riscv: dts: spacemit: Add K3 I2C6 pinctrl state
riscv: dts: spacemit: Add CTF2301 on K3 CoM260
.../devicetree/bindings/hwmon/national,lm63.yaml | 52 +++
.../devicetree/bindings/trivial-devices.yaml | 6 -
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
Documentation/hwmon/lm63.rst | 22 ++
arch/riscv/boot/dts/spacemit/k3-com260.dtsi | 19 +
arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi | 11 +
drivers/hwmon/Kconfig | 8 +-
drivers/hwmon/lm63.c | 393 +++++++++++++++++----
8 files changed, 433 insertions(+), 80 deletions(-)
---
base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
change-id: 20250916-ctl2301-0416b073c280
Best regards,
--
Troy Mitchell <troy.mitchell@linux.dev>
^ permalink raw reply
* [PATCH v2 1/6] dt-bindings: vendor-prefixes: Add Sensylink
From: Troy Mitchell @ 2026-07-21 9:48 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Yixun Lan, Jonathan Corbet, Shuah Khan
Cc: Troy Mitchell, devicetree, linux-kernel, linux-hwmon, linux-riscv,
spacemit, linux-doc
In-Reply-To: <20260721-ctl2301-v2-0-ef5fb342872a@linux.dev>
Add the vendor prefix for Sensylink Microelectronics.
Signed-off-by: Troy Mitchell <troy.mitchell@linux.dev>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 396044f368e7..22d0d26f1bbd 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1467,6 +1467,8 @@ patternProperties:
description: Sensirion AG
"^sensortek,.*":
description: Sensortek Technology Corporation
+ "^sensylink,.*":
+ description: Sensylink Microelectronics Technology Co., Ltd.
"^sercomm,.*":
description: Sercomm (Suzhou) Corporation
"^sff,.*":
--
2.55.0
^ permalink raw reply related
* [PATCH v2 2/6] dt-bindings: hwmon: Move LM63 family to a dedicated binding
From: Troy Mitchell @ 2026-07-21 9:48 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Yixun Lan, Jonathan Corbet, Shuah Khan
Cc: Troy Mitchell, devicetree, linux-kernel, linux-hwmon, linux-riscv,
spacemit, linux-doc
In-Reply-To: <20260721-ctl2301-v2-0-ef5fb342872a@linux.dev>
Move the National Semiconductor LM63, LM64, and LM96163 compatibles out
of trivial-devices.yaml and into a dedicated binding. Describe their
integrated fan control and permit use as thermal cooling devices through
the #cooling-cells property.
Signed-off-by: Troy Mitchell <troy.mitchell@linux.dev>
---
.../devicetree/bindings/hwmon/national,lm63.yaml | 50 ++++++++++++++++++++++
.../devicetree/bindings/trivial-devices.yaml | 6 ---
2 files changed, 50 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/hwmon/national,lm63.yaml b/Documentation/devicetree/bindings/hwmon/national,lm63.yaml
new file mode 100644
index 000000000000..92b0094ff303
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/national,lm63.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/national,lm63.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LM63-compatible temperature sensors with integrated fan control
+
+maintainers:
+ - Guenter Roeck <linux@roeck-us.net>
+
+description: |
+ The LM63 family provides local and remote temperature monitoring together
+ with fan speed monitoring and PWM fan control. Supported devices include
+ the National Semiconductor LM63, LM64 and LM96163.
+
+allOf:
+ - $ref: hwmon-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - national,lm63
+ - national,lm64
+ - national,lm96163
+
+ reg:
+ maxItems: 1
+
+ "#cooling-cells":
+ const: 2
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ temperature-sensor@4c {
+ compatible = "national,lm63";
+ reg = <0x4c>;
+ #cooling-cells = <2>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
index 435c4baab436..aa62d245464c 100644
--- a/Documentation/devicetree/bindings/trivial-devices.yaml
+++ b/Documentation/devicetree/bindings/trivial-devices.yaml
@@ -364,16 +364,10 @@ properties:
- mps,mp9945
# Murata D1U74T-W power supply unit
- murata,d1u74t
- # Temperature sensor with integrated fan control
- - national,lm63
- # Temperature sensor with integrated fan control
- - national,lm64
# Temperature sensor
- national,lm95235
# Temperature sensor
- national,lm95245
- # Temperature sensor with integrated fan control
- - national,lm96163
# Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor
- national,lm80
# Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor
--
2.55.0
^ permalink raw reply related
* [PATCH v2 3/6] dt-bindings: hwmon: Add Sensylink CTF2301
From: Troy Mitchell @ 2026-07-21 9:48 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Yixun Lan, Jonathan Corbet, Shuah Khan
Cc: Troy Mitchell, devicetree, linux-kernel, linux-hwmon, linux-riscv,
spacemit, linux-doc
In-Reply-To: <20260721-ctl2301-v2-0-ef5fb342872a@linux.dev>
Add the Sensylink CTF2301 temperature sensor and fan controller to the
LM63 family binding. The chip follows the LM63 register model and can
provide a thermal cooling device when #cooling-cells is present.
Signed-off-by: Troy Mitchell <troy.mitchell@linux.dev>
---
Documentation/devicetree/bindings/hwmon/national,lm63.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/hwmon/national,lm63.yaml b/Documentation/devicetree/bindings/hwmon/national,lm63.yaml
index 92b0094ff303..4a1ffebfdbef 100644
--- a/Documentation/devicetree/bindings/hwmon/national,lm63.yaml
+++ b/Documentation/devicetree/bindings/hwmon/national,lm63.yaml
@@ -12,7 +12,8 @@ maintainers:
description: |
The LM63 family provides local and remote temperature monitoring together
with fan speed monitoring and PWM fan control. Supported devices include
- the National Semiconductor LM63, LM64 and LM96163.
+ the National Semiconductor LM63, LM64 and LM96163, and the Sensylink
+ CTF2301.
allOf:
- $ref: hwmon-common.yaml#
@@ -23,6 +24,7 @@ properties:
- national,lm63
- national,lm64
- national,lm96163
+ - sensylink,ctf2301
reg:
maxItems: 1
--
2.55.0
^ permalink raw reply related
* [PATCH v2 4/6] hwmon: (lm63) Add Sensylink CTF2301 support
From: Troy Mitchell @ 2026-07-21 9:48 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Yixun Lan, Jonathan Corbet, Shuah Khan
Cc: Troy Mitchell, devicetree, linux-kernel, linux-hwmon, linux-riscv,
spacemit, linux-doc, Jean Delvare
In-Reply-To: <20260721-ctl2301-v2-0-ef5fb342872a@linux.dev>
Add Sensylink CTF2301 support to the LM63 driver. CTF2301 follows
the LM63-style temperature, tachometer, and PWM register layout,
while using a 12-bit local temperature register and requiring the
ALERT/TACH pin to be configured for tachometer input.
Register an optional thermal cooling device when the device tree
node provides #cooling-cells, allowing thermal zones to control
the fan through the existing PWM path without changing behavior
for existing LM63-family users.
Signed-off-by: Troy Mitchell <troy.mitchell@linux.dev>
---
Documentation/hwmon/lm63.rst | 22 +++
drivers/hwmon/Kconfig | 8 +-
drivers/hwmon/lm63.c | 393 +++++++++++++++++++++++++++++++++++--------
3 files changed, 349 insertions(+), 74 deletions(-)
diff --git a/Documentation/hwmon/lm63.rst b/Documentation/hwmon/lm63.rst
index 9e27367d7405..c40bd0dfe591 100644
--- a/Documentation/hwmon/lm63.rst
+++ b/Documentation/hwmon/lm63.rst
@@ -33,6 +33,16 @@ Supported chips:
http://www.national.com/pf/LM/LM96163.html
+ * Sensylink CTF2301
+
+ Prefix: 'ctf2301'
+
+ Addresses scanned: none
+
+ Datasheet: https://www.sensylink.com/upload/1/net.sensylink.portal/1689557281035.pdf
+
+ Register description: https://github.com/TroyMitchell911/ctf2301-datasheet
+
Author: Jean Delvare <jdelvare@suse.de>
@@ -62,6 +72,8 @@ value have to be masked out. The value is still 16 bit in width.
All temperature values are given in degrees Celsius. Resolution is 1.0
degree for the local temperature, 0.125 degree for the remote temperature.
+The CTF2301 local temperature input and limit have a resolution of 0.0625
+degree.
The fan speed is measured using a tachometer. Contrary to most chips which
store the value in an 8-bit register and have a selectable clock divider
@@ -93,3 +105,13 @@ support these GPIO lines at present.
The LM96163 is an enhanced version of LM63 with improved temperature accuracy
and better PWM resolution. For LM96163, the external temperature sensor type is
configurable as CPU embedded diode(1) or 3904 transistor(2).
+
+The CTF2301 is register-compatible with the LM63 family and provides 12 fan
+control lookup table entries. It supports 8-bit PWM resolution when configured
+for a 22.5 kHz PWM frequency.
+
+Device tree nodes may declare ``#cooling-cells`` to register the fan controller
+with the thermal framework. The cooling state is mapped to the existing
+``pwm1`` range from 0 to 255. The driver keeps the current automatic or manual
+fan control mode during probe and switches to manual control when the thermal
+framework first requests a cooling state.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2bfbcc033d59..abb1af8664fb 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1501,10 +1501,10 @@ config SENSORS_LM63
depends on I2C
help
If you say yes here you get support for the National
- Semiconductor LM63, LM64, and LM96163 remote diode digital temperature
- sensors with integrated fan control. Such chips are found
- on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
- others.
+ Semiconductor LM63, LM64, LM96163, and Sensylink CTF2301
+ remote diode digital temperature sensors with integrated fan
+ control. Such chips are found on the Tyan S4882 (Thunder K8QS
+ Pro) motherboard, among others.
This driver can also be built as a module. If so, the module
will be called lm63.
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index e2a429e579ac..764a7467afa6 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -35,13 +35,14 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/sysfs.h>
+#include <linux/thermal.h>
#include <linux/types.h>
/*
* Addresses to scan
* Address is fully defined internally and cannot be changed except for
* LM64 which has one pin dedicated to address selection.
- * LM63 and LM96163 have address 0x4c.
+ * LM63, LM96163, and CTF2301 have address 0x4c.
* LM64 can have address 0x18 or 0x4e.
*/
@@ -70,6 +71,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
#define LM63_REG_LOCAL_TEMP 0x00
#define LM63_REG_LOCAL_HIGH 0x05
+#define CTF2301_REG_LOCAL_TEMP_LSB 0x15
+#define CTF2301_REG_LOCAL_HIGH_LSB 0x06
+
#define LM63_REG_REMOTE_TEMP_MSB 0x01
#define LM63_REG_REMOTE_TEMP_LSB 0x10
#define LM63_REG_REMOTE_OFFSET_MSB 0x11
@@ -94,6 +98,7 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
#define LM63_PWM_BASE_FAST_HZ 180000
#define LM63_PWM_BASE_SLOW_HZ 700
+#define LM63_MAX_PWM 255
#define LM63_MAX_CONVRATE 9
@@ -121,6 +126,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
127000), 1000)
#define TEMP8U_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val((val), 0, \
255000), 1000)
+#define TEMP12_FROM_REG(reg) DIV_ROUND_CLOSEST((s16)(reg) * 1000, 256)
+#define TEMP12_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val((val), -128000, \
+ 127937) * 256, 1000)
#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125)
#define TEMP11_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val((val), -128000, \
127875), 125) * 32)
@@ -132,7 +140,11 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
#define UPDATE_INTERVAL(max, rate) \
((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
-enum chips { lm63, lm64, lm96163 };
+enum chips { lm63, lm64, lm96163, ctf2301 };
+
+static const unsigned int ctf2301_update_intervals[] = {
+ 20000, 10000, 4902, 2463, 1000, 615, 307, 154, 107
+};
/*
* Client data (each client gets its own)
@@ -164,6 +176,8 @@ struct lm63_data {
1: local high limit
2: remote critical limit
3-14: lookup table */
+ s16 temp1_input; /* local input for chips with extended resolution */
+ s16 temp1_max; /* local limit for chips with extended resolution */
s16 temp11[4]; /* 0: remote input
1: remote low limit
2: remote high limit
@@ -256,8 +270,16 @@ static struct lm63_data *lm63_update_device(struct device *dev)
data->temp8[0] = i2c_smbus_read_byte_data(client,
LM63_REG_LOCAL_TEMP);
+ if (data->kind == ctf2301)
+ data->temp1_input = ((u16)(u8)data->temp8[0] << 8)
+ | i2c_smbus_read_byte_data(client,
+ CTF2301_REG_LOCAL_TEMP_LSB);
data->temp8[1] = i2c_smbus_read_byte_data(client,
LM63_REG_LOCAL_HIGH);
+ if (data->kind == ctf2301)
+ data->temp1_max = ((u16)(u8)data->temp8[1] << 8)
+ | i2c_smbus_read_byte_data(client,
+ CTF2301_REG_LOCAL_HIGH_LSB);
/* order matters for temp2_input */
data->temp11[0] = i2c_smbus_read_byte_data(client,
@@ -277,7 +299,7 @@ static struct lm63_data *lm63_update_device(struct device *dev)
| i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_OFFSET_LSB);
- if (data->kind == lm96163)
+ if (data->kind == lm96163 || data->kind == ctf2301)
data->temp11u = (i2c_smbus_read_byte_data(client,
LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
| i2c_smbus_read_byte_data(client,
@@ -367,6 +389,41 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
return count;
}
+static int lm63_pwm_from_reg(struct lm63_data *data, u8 reg)
+{
+ if (data->pwm_highres)
+ return reg;
+
+ return reg >= 2 * data->pwm1_freq ?
+ LM63_MAX_PWM :
+ (reg * LM63_MAX_PWM + data->pwm1_freq) / (2 * data->pwm1_freq);
+}
+
+static u8 lm63_pwm_to_reg(struct lm63_data *data, unsigned long val)
+{
+ val = clamp_val(val, 0, LM63_MAX_PWM);
+
+ if (data->pwm_highres)
+ return val;
+
+ return (val * data->pwm1_freq * 2 + LM63_MAX_PWM / 2) / LM63_MAX_PWM;
+}
+
+static int lm63_write_pwm(struct lm63_data *data, int nr, unsigned long val)
+{
+ struct i2c_client *client = data->client;
+ u8 reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
+ u8 regval = lm63_pwm_to_reg(data, val);
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, reg, regval);
+ if (ret)
+ return ret;
+ data->pwm1[nr] = regval;
+
+ return 0;
+}
+
static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
char *buf)
{
@@ -376,12 +433,7 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
int pwm;
mutex_lock(&data->update_lock);
- if (data->pwm_highres)
- pwm = data->pwm1[nr];
- else
- pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
- 255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
- (2 * data->pwm1_freq);
+ pwm = lm63_pwm_from_reg(data, data->pwm1[nr]);
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", pwm);
@@ -392,11 +444,9 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm63_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
int nr = attr->index;
unsigned long val;
int err;
- u8 reg;
if (!(data->config_fan & 0x20)) /* register is read-only */
return -EPERM;
@@ -405,15 +455,11 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,
if (err)
return err;
- reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
- val = clamp_val(val, 0, 255);
-
mutex_lock(&data->update_lock);
- data->pwm1[nr] = data->pwm_highres ? val :
- (val * data->pwm1_freq * 2 + 127) / 255;
- i2c_smbus_write_byte_data(client, reg, data->pwm1[nr]);
+ err = lm63_write_pwm(data, nr, val);
mutex_unlock(&data->update_lock);
- return count;
+
+ return err ? err : count;
}
static ssize_t pwm1_enable_show(struct device *dev,
@@ -486,7 +532,9 @@ static ssize_t pwm1_freq_store(struct device *dev,
struct lm63_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long val, pfr_fast, pfr_slow, err_fast, err_slow, pfr;
+ u8 config_fan;
bool slow_clock;
+ int config_enhanced = 0;
int ret;
ret = kstrtoul(buf, 10, &val);
@@ -512,35 +560,55 @@ static ssize_t pwm1_freq_store(struct device *dev,
mutex_lock(&data->update_lock);
ret = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG_FAN);
- if (ret < 0) {
- mutex_unlock(&data->update_lock);
- return ret;
- }
- data->config_fan = ret;
+ if (ret < 0)
+ goto unlock;
+ config_fan = ret;
- if (!(data->config_fan & 0x20)) { /* register is read-only */
- mutex_unlock(&data->update_lock);
- return -EPERM;
+ if (!(config_fan & 0x20)) { /* register is read-only */
+ ret = -EPERM;
+ goto unlock;
}
- if (data->kind == lm96163) {
- ret = i2c_smbus_read_byte_data(client, LM96163_REG_CONFIG_ENHANCED);
- if (ret < 0) {
- mutex_unlock(&data->update_lock);
- return ret;
+ if (data->kind == lm96163 || data->kind == ctf2301) {
+ ret = i2c_smbus_read_byte_data(client,
+ LM96163_REG_CONFIG_ENHANCED);
+ if (ret < 0)
+ goto unlock;
+ config_enhanced = ret;
+
+ if (data->kind == ctf2301) {
+ if (!slow_clock && pfr == 8)
+ config_enhanced |= 0x10;
+ else
+ config_enhanced &= ~0x10;
+ ret = i2c_smbus_write_byte_data(client,
+ LM96163_REG_CONFIG_ENHANCED,
+ config_enhanced);
+ if (ret)
+ goto unlock;
}
- data->pwm_highres = !slow_clock && pfr == 8 && (ret & 0x10);
}
if (slow_clock)
- data->config_fan |= 0x08;
+ config_fan |= 0x08;
else
- data->config_fan &= ~0x08;
- i2c_smbus_write_byte_data(client, LM63_REG_CONFIG_FAN, data->config_fan);
- i2c_smbus_write_byte_data(client, LM63_REG_PWM_FREQ, pfr);
+ config_fan &= ~0x08;
+ ret = i2c_smbus_write_byte_data(client, LM63_REG_PWM_FREQ, pfr);
+ if (ret)
+ goto unlock;
+ ret = i2c_smbus_write_byte_data(client, LM63_REG_CONFIG_FAN,
+ config_fan);
+ if (ret)
+ goto unlock;
+
+ data->config_fan = config_fan;
data->pwm1_freq = pfr;
+ data->pwm_highres = !slow_clock && pfr == 8 &&
+ (config_enhanced & 0x10);
+unlock:
mutex_unlock(&data->update_lock);
- return count;
+
+ return ret ? ret : count;
}
/*
@@ -555,6 +623,11 @@ static ssize_t show_local_temp8(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm63_data *data = lm63_update_device(dev);
+
+ if (data->kind == ctf2301)
+ return sprintf(buf, "%d\n", TEMP12_FROM_REG(attr->index ?
+ data->temp1_max : data->temp1_input));
+
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]));
}
@@ -595,6 +668,23 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
return err;
mutex_lock(&data->update_lock);
+ if (data->kind == ctf2301 && nr == 1) {
+ temp = TEMP12_TO_REG(val);
+ err = i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH,
+ temp >> 8);
+ if (!err)
+ err = i2c_smbus_write_byte_data(client,
+ CTF2301_REG_LOCAL_HIGH_LSB,
+ temp & 0xf0);
+ if (!err) {
+ data->temp8[nr] = temp >> 8;
+ data->temp1_max = temp;
+ }
+ mutex_unlock(&data->update_lock);
+
+ return err ? err : count;
+ }
+
switch (nr) {
case 2:
reg = LM63_REG_REMOTE_TCRIT;
@@ -611,10 +701,12 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
reg = LM63_REG_LUT_TEMP(nr - 3);
temp = lut_temp_to_reg(data, val);
}
- data->temp8[nr] = temp;
- i2c_smbus_write_byte_data(client, reg, temp);
+ err = i2c_smbus_write_byte_data(client, reg, temp);
+ if (!err)
+ data->temp8[nr] = temp;
mutex_unlock(&data->update_lock);
- return count;
+
+ return err ? err : count;
}
static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
@@ -788,11 +880,40 @@ static ssize_t temp2_crit_hyst_store(struct device *dev,
* Set conversion rate.
* client->update_lock must be held when calling this function.
*/
-static void lm63_set_convrate(struct lm63_data *data, unsigned int interval)
+static unsigned int lm63_update_interval(struct lm63_data *data, u8 rate)
+{
+ if (data->kind == ctf2301)
+ return ctf2301_update_intervals[min_t(unsigned int, rate,
+ ARRAY_SIZE(ctf2301_update_intervals) - 1)];
+
+ return UPDATE_INTERVAL(data->max_convrate_hz, rate);
+}
+
+static int lm63_set_convrate(struct lm63_data *data, unsigned int interval)
{
struct i2c_client *client = data->client;
- unsigned int update_interval;
- int i;
+ unsigned int update_interval, error, best_error = ~0U;
+ unsigned int best = 0;
+ unsigned int i;
+ int ret;
+
+ if (data->kind == ctf2301) {
+ for (i = 0; i < ARRAY_SIZE(ctf2301_update_intervals); i++) {
+ error = abs_diff(interval, ctf2301_update_intervals[i]);
+ if (error < best_error) {
+ best_error = error;
+ best = i;
+ }
+ }
+
+ ret = i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE,
+ best);
+ if (ret)
+ return ret;
+ data->update_interval = ctf2301_update_intervals[best];
+
+ return 0;
+ }
/* Shift calculations to avoid rounding errors */
interval <<= 6;
@@ -804,8 +925,12 @@ static void lm63_set_convrate(struct lm63_data *data, unsigned int interval)
if (interval >= update_interval * 3 / 4)
break;
- i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i);
+ ret = i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i);
+ if (ret)
+ return ret;
data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i);
+
+ return 0;
}
static ssize_t update_interval_show(struct device *dev,
@@ -829,10 +954,10 @@ static ssize_t update_interval_store(struct device *dev,
return err;
mutex_lock(&data->update_lock);
- lm63_set_convrate(data, clamp_val(val, 0, 100000));
+ err = lm63_set_convrate(data, clamp_val(val, 0, 100000));
mutex_unlock(&data->update_lock);
- return count;
+ return err ? err : count;
}
static ssize_t temp2_type_show(struct device *dev,
@@ -997,6 +1122,75 @@ static DEVICE_ATTR_RO(alarms);
static DEVICE_ATTR_RW(update_interval);
+static int lm63_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ *state = LM63_MAX_PWM;
+
+ return 0;
+}
+
+static int lm63_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct lm63_data *data = cdev->devdata;
+ int ret;
+
+ mutex_lock(&data->update_lock);
+ ret = i2c_smbus_read_byte_data(data->client, LM63_REG_PWM_VALUE);
+ if (ret < 0)
+ goto unlock;
+
+ data->pwm1[0] = ret;
+ *state = lm63_pwm_from_reg(data, data->pwm1[0]);
+unlock:
+ mutex_unlock(&data->update_lock);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int lm63_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct lm63_data *data = cdev->devdata;
+ int config_fan;
+ int ret;
+
+ if (state > LM63_MAX_PWM)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ config_fan = i2c_smbus_read_byte_data(data->client,
+ LM63_REG_CONFIG_FAN);
+ if (config_fan < 0) {
+ ret = config_fan;
+ goto unlock;
+ }
+ data->config_fan = config_fan;
+
+ if (!(config_fan & 0x20)) {
+ config_fan |= 0x20;
+ ret = i2c_smbus_write_byte_data(data->client,
+ LM63_REG_CONFIG_FAN,
+ config_fan);
+ if (ret)
+ goto unlock;
+ data->config_fan = config_fan;
+ }
+
+ ret = lm63_write_pwm(data, 0, state);
+unlock:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static const struct thermal_cooling_device_ops lm63_cooling_ops = {
+ .get_max_state = lm63_get_max_state,
+ .get_cur_state = lm63_get_cur_state,
+ .set_cur_state = lm63_set_cur_state,
+};
+
static struct attribute *lm63_attributes[] = {
&sensor_dev_attr_pwm1.dev_attr.attr,
&dev_attr_pwm1_enable.attr,
@@ -1079,8 +1273,8 @@ static const struct attribute_group lm63_group_extra_lut = {
* On LM63, temp2_crit can be set only once, which should be job
* of the bootloader.
* On LM64, temp2_crit can always be set.
- * On LM96163, temp2_crit can be set if bit 1 of the configuration
- * register is true.
+ * On LM96163 and CTF2301, temp2_crit can be set if bit 1 of the
+ * configuration register is true.
*/
static umode_t lm63_attribute_mode(struct kobject *kobj,
struct attribute *attr, int index)
@@ -1090,7 +1284,8 @@ static umode_t lm63_attribute_mode(struct kobject *kobj,
if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr
&& (data->kind == lm64 ||
- (data->kind == lm96163 && (data->config & 0x02))))
+ ((data->kind == lm96163 || data->kind == ctf2301) &&
+ (data->config & 0x02))))
return attr->mode | S_IWUSR;
return attr->mode;
@@ -1165,29 +1360,48 @@ static int lm63_detect(struct i2c_client *client,
* Ideally we shouldn't have to initialize anything, since the BIOS
* should have taken care of everything
*/
-static void lm63_init_client(struct lm63_data *data)
+static int lm63_init_client(struct lm63_data *data)
{
struct i2c_client *client = data->client;
struct device *dev = &client->dev;
u8 convrate;
+ int ret;
- data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
- data->config_fan = i2c_smbus_read_byte_data(client,
- LM63_REG_CONFIG_FAN);
+ ret = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
+ if (ret < 0)
+ return ret;
+ data->config = ret;
+ ret = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG_FAN);
+ if (ret < 0)
+ return ret;
+ data->config_fan = ret;
/* Start converting if needed */
if (data->config & 0x40) { /* standby */
dev_dbg(dev, "Switching to operational mode\n");
data->config &= 0xA7;
- i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
- data->config);
+ ret = i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
+ data->config);
+ if (ret)
+ return ret;
}
/* Tachometer is always enabled on LM64 */
if (data->kind == lm64)
data->config |= 0x04;
+ if (data->kind == ctf2301 && !client->irq && !(data->config & 0x04)) {
+ dev_dbg(dev, "Configuring ALERT/TACH pin for tachometer input\n");
+ data->config |= 0x04;
+ ret = i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
+ data->config);
+ if (ret)
+ return ret;
+ }
/* We may need pwm1_freq before ever updating the client data */
- data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
+ ret = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
+ if (ret < 0)
+ return ret;
+ data->pwm1_freq = ret;
if (data->pwm1_freq == 0)
data->pwm1_freq = 1;
@@ -1200,25 +1414,38 @@ static void lm63_init_client(struct lm63_data *data)
case lm96163:
data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ;
data->lut_size = 12;
- data->trutherm
- = i2c_smbus_read_byte_data(client,
- LM96163_REG_TRUTHERM) & 0x02;
+ ret = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM);
+ if (ret < 0)
+ return ret;
+ data->trutherm = ret & 0x02;
+ break;
+ case ctf2301:
+ data->lut_size = 12;
break;
}
- convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE);
- if (unlikely(convrate > LM63_MAX_CONVRATE))
+ ret = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE);
+ if (ret < 0)
+ return ret;
+ convrate = ret;
+ if (data->kind == ctf2301 &&
+ convrate >= ARRAY_SIZE(ctf2301_update_intervals))
+ convrate = ARRAY_SIZE(ctf2301_update_intervals) - 1;
+ else if (unlikely(convrate > LM63_MAX_CONVRATE))
convrate = LM63_MAX_CONVRATE;
- data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz,
- convrate);
+ data->update_interval = lm63_update_interval(data, convrate);
/*
- * For LM96163, check if high resolution PWM
+ * For LM96163 and CTF2301, check if high resolution PWM
* and unsigned temperature format is enabled.
*/
- if (data->kind == lm96163) {
- u8 config_enhanced
- = i2c_smbus_read_byte_data(client,
- LM96163_REG_CONFIG_ENHANCED);
+ if (data->kind == lm96163 || data->kind == ctf2301) {
+ u8 config_enhanced;
+
+ ret = i2c_smbus_read_byte_data(client,
+ LM96163_REG_CONFIG_ENHANCED);
+ if (ret < 0)
+ return ret;
+ config_enhanced = ret;
if (config_enhanced & 0x20)
data->lut_temp_highres = true;
if ((config_enhanced & 0x10)
@@ -1239,6 +1466,8 @@ static void lm63_init_client(struct lm63_data *data)
dev_dbg(dev, "PWM output active %s, %s mode\n",
(data->config_fan & 0x10) ? "low" : "high",
(data->config_fan & 0x20) ? "manual" : "auto");
+
+ return 0;
}
static const struct i2c_device_id lm63_id[];
@@ -1246,9 +1475,11 @@ static const struct i2c_device_id lm63_id[];
static int lm63_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
+ struct thermal_cooling_device *cdev;
struct device *hwmon_dev;
struct lm63_data *data;
int groups = 0;
+ int ret;
data = devm_kzalloc(dev, sizeof(struct lm63_data), GFP_KERNEL);
if (!data)
@@ -1263,7 +1494,9 @@ static int lm63_probe(struct i2c_client *client)
data->temp2_offset = 16000;
/* Initialize chip */
- lm63_init_client(data);
+ ret = lm63_init_client(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize device\n");
/* Register sysfs hooks */
data->groups[groups++] = &lm63_group;
@@ -1273,11 +1506,26 @@ static int lm63_probe(struct i2c_client *client)
if (data->kind == lm96163) {
data->groups[groups++] = &lm63_group_temp2_type;
data->groups[groups++] = &lm63_group_extra_lut;
+ } else if (data->kind == ctf2301) {
+ data->groups[groups++] = &lm63_group_extra_lut;
}
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data, data->groups);
- return PTR_ERR_OR_ZERO(hwmon_dev);
+ if (IS_ERR(hwmon_dev))
+ return PTR_ERR(hwmon_dev);
+
+ if (IS_ENABLED(CONFIG_THERMAL_OF) &&
+ of_property_present(dev->of_node, "#cooling-cells")) {
+ cdev = devm_thermal_of_cooling_device_register(dev, 0,
+ client->name,
+ data,
+ &lm63_cooling_ops);
+ if (IS_ERR(cdev))
+ return PTR_ERR(cdev);
+ }
+
+ return 0;
}
/*
@@ -1288,6 +1536,7 @@ static const struct i2c_device_id lm63_id[] = {
{ .name = "lm63", .driver_data = lm63 },
{ .name = "lm64", .driver_data = lm64 },
{ .name = "lm96163", .driver_data = lm96163 },
+ { .name = "ctf2301", .driver_data = ctf2301 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm63_id);
@@ -1305,6 +1554,10 @@ static const struct of_device_id __maybe_unused lm63_of_match[] = {
.compatible = "national,lm96163",
.data = (void *)lm96163
},
+ {
+ .compatible = "sensylink,ctf2301",
+ .data = (void *)ctf2301
+ },
{ },
};
MODULE_DEVICE_TABLE(of, lm63_of_match);
--
2.55.0
^ permalink raw reply related
* [PATCH v2 5/6] riscv: dts: spacemit: Add K3 I2C6 pinctrl state
From: Troy Mitchell @ 2026-07-21 9:48 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Yixun Lan, Jonathan Corbet, Shuah Khan
Cc: Troy Mitchell, devicetree, linux-kernel, linux-hwmon, linux-riscv,
spacemit, linux-doc
In-Reply-To: <20260721-ctl2301-v2-0-ef5fb342872a@linux.dev>
Add the K3 I2C6 pinctrl state used by boards that route I2C6 to
pads 7 and 8. Leave board-specific IO voltage selection to board
files.
Signed-off-by: Troy Mitchell <troy.mitchell@linux.dev>
---
arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi b/arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi
index 3ee1471f3798..91cd08099e27 100644
--- a/arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi
@@ -78,6 +78,17 @@ gmac1-phy-0-pins {
};
};
+ /omit-if-no-ref/
+ i2c6_1_cfg: i2c6-1-cfg {
+ i2c6-1-pins {
+ pinmux = <K3_PADCONF(7, 6)>, /* i2c6 scl */
+ <K3_PADCONF(8, 6)>; /* i2c6 sda */
+
+ bias-pull-up = <0>;
+ drive-strength = <18>;
+ };
+ };
+
/omit-if-no-ref/
i2c8_cfg: i2c8-cfg {
i2c8-pins {
--
2.55.0
^ permalink raw reply related
* [PATCH v2 6/6] riscv: dts: spacemit: Add CTF2301 on K3 CoM260
From: Troy Mitchell @ 2026-07-21 9:48 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Yixun Lan, Jonathan Corbet, Shuah Khan
Cc: Troy Mitchell, devicetree, linux-kernel, linux-hwmon, linux-riscv,
spacemit, linux-doc
In-Reply-To: <20260721-ctl2301-v2-0-ef5fb342872a@linux.dev>
Enable I2C6 on the K3 CoM260 module and describe the Sensylink
CTF2301 temperature sensor and fan controller at address 0x4c.
Set the I2C6 pin power source in the board-level pinctrl node
because the IO rail voltage is board-specific.
Signed-off-by: Troy Mitchell <troy.mitchell@linux.dev>
---
arch/riscv/boot/dts/spacemit/k3-com260.dtsi | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/riscv/boot/dts/spacemit/k3-com260.dtsi b/arch/riscv/boot/dts/spacemit/k3-com260.dtsi
index a38d7b738258..95a60fbb411f 100644
--- a/arch/riscv/boot/dts/spacemit/k3-com260.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k3-com260.dtsi
@@ -26,6 +26,25 @@ reg_5v_sys: regulator-5v-sys {
};
};
+&pinctrl {
+ i2c6-1-cfg {
+ i2c6-1-pins {
+ power-source = <3300>;
+ };
+ };
+};
+
+&i2c6 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c6_1_cfg>;
+ status = "okay";
+
+ temperature-sensor@4c {
+ compatible = "sensylink,ctf2301";
+ reg = <0x4c>;
+ };
+};
+
&i2c8 {
pinctrl-names = "default";
pinctrl-0 = <&i2c8_cfg>;
--
2.55.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox