* [PATCH v9 6/6] mux: add NXP MC33978/MC34978 AMUX driver
From: Oleksij Rempel @ 2026-03-31 17:16 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Lee Jones, Peter Rosin, Linus Walleij
Cc: Oleksij Rempel, kernel, linux-kernel, devicetree, linux-hwmon,
linux-gpio, David Jander
In-Reply-To: <20260331171612.102018-1-o.rempel@pengutronix.de>
Add a mux-control driver for the 24-to-1 analog multiplexer (AMUX)
embedded in the NXP MC33978/MC34978 Multiple Switch Detection
Interface (MSDI) devices.
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
changes v9:
- rename mc33978-mux to mux-mc33978 in the Kconfig help
- fail if fwnode is NULL
changes v8:
- no chnages
changes v7:
- Simplify the return path and local variable assignment in
mc33978_mux_set().
- Change idle_state to a signed integer to properly handle negative MUX
subsystem constants.
- Default to MUX_IDLE_AS_IS when the "idle-state" device tree property
is missing.
- Explicitly reject MUX_IDLE_DISCONNECT since the hardware does not
support disconnecting the multiplexer.
changes v6:
- parse optional idle-state property
- validate idle-state against available AMUX channels
- lower-case probe error messages
changes v5:
- no changes
changes v4:
- no changes
changes v3:
- no changes
changes v2:
- Add missing <linux/err.h> include.
- Add platform_device_id table
---
drivers/mux/Kconfig | 14 ++++
drivers/mux/Makefile | 2 +
drivers/mux/mc33978-mux.c | 141 ++++++++++++++++++++++++++++++++++++++
3 files changed, 157 insertions(+)
create mode 100644 drivers/mux/mc33978-mux.c
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index c68132e38138..ffe92a714096 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -45,6 +45,20 @@ config MUX_GPIO
To compile the driver as a module, choose M here: the module will
be called mux-gpio.
+config MUX_MC33978
+ tristate "NXP MC33978/MC34978 Analog Multiplexer"
+ depends on MFD_MC33978
+ help
+ MC33978/MC34978 24-to-1 analog multiplexer (AMUX) driver.
+
+ This driver provides mux-control for the analog multiplexer,
+ which can route switch voltages, temperature, and battery voltage
+ to an external ADC. Typically used with IIO ADC drivers to measure
+ analog values from the 22 switch inputs plus temperature and VBATP.
+
+ To compile the driver as a module, choose M here: the module will
+ be called mux-mc33978.
+
config MUX_MMIO
tristate "MMIO/Regmap register bitfield-controlled Multiplexer"
depends on OF
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 6e9fa47daf56..339c44b4d4f4 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -7,10 +7,12 @@ mux-core-objs := core.o
mux-adg792a-objs := adg792a.o
mux-adgs1408-objs := adgs1408.o
mux-gpio-objs := gpio.o
+mux-mc33978-objs := mc33978-mux.o
mux-mmio-objs := mmio.o
obj-$(CONFIG_MULTIPLEXER) += mux-core.o
obj-$(CONFIG_MUX_ADG792A) += mux-adg792a.o
obj-$(CONFIG_MUX_ADGS1408) += mux-adgs1408.o
obj-$(CONFIG_MUX_GPIO) += mux-gpio.o
+obj-$(CONFIG_MUX_MC33978) += mux-mc33978.o
obj-$(CONFIG_MUX_MMIO) += mux-mmio.o
diff --git a/drivers/mux/mc33978-mux.c b/drivers/mux/mc33978-mux.c
new file mode 100644
index 000000000000..b44c862f0dbe
--- /dev/null
+++ b/drivers/mux/mc33978-mux.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2026 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
+/*
+ * MC33978/MC34978 Analog Multiplexer (AMUX) Driver
+ *
+ * This driver provides mux-control for the 24-to-1 analog multiplexer.
+ * The AMUX routes one of the following signals to the external AMUX pin:
+ * - Channels 0-13: SG0-SG13 switch voltages
+ * - Channels 14-21: SP0-SP7 switch voltages
+ * - Channel 22: Internal temperature diode
+ * - Channel 23: Battery voltage (VBATP)
+ *
+ * Consumer drivers (typically IIO ADC drivers) use the mux-control
+ * subsystem to select which signal to measure.
+ *
+ * Architecture:
+ * The MC33978 does not have an internal ADC. Instead, it routes analog
+ * signals to an external AMUX pin that must be connected to an external
+ * ADC (such as the SoC's internal ADC). The IIO subsystem is responsible
+ * for coordinating the mux selection and ADC sampling.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mux/driver.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/mc33978.h>
+
+/* AMUX_CTRL register field definitions */
+#define MC33978_AMUX_CTRL_MASK GENMASK(5, 0) /* 6-bit channel select */
+
+struct mc33978_mux_priv {
+ struct device *dev;
+ struct regmap *map;
+};
+
+static int mc33978_mux_set(struct mux_control *mux, int state)
+{
+ struct mux_chip *mux_chip = mux->chip;
+ struct mc33978_mux_priv *priv = mux_chip_priv(mux_chip);
+ int ret;
+
+ if (state < 0 || state >= MC33978_NUM_AMUX_CH)
+ return -EINVAL;
+
+ ret = regmap_update_bits(priv->map, MC33978_REG_AMUX_CTRL,
+ MC33978_AMUX_CTRL_MASK, state);
+ if (ret)
+ dev_err(priv->dev, "failed to set AMUX channel %d: %d\n",
+ state, ret);
+
+ return ret;
+}
+
+static const struct mux_control_ops mc33978_mux_ops = {
+ .set = mc33978_mux_set,
+};
+
+static int mc33978_mux_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mc33978_mux_priv *priv;
+ struct fwnode_handle *fwnode;
+ struct mux_chip *mux_chip;
+ struct mux_control *mux;
+ s32 idle_state;
+ int ret;
+
+ mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*priv));
+ if (IS_ERR(mux_chip))
+ return dev_err_probe(dev, PTR_ERR(mux_chip), "failed to allocate mux chip\n");
+
+ fwnode = dev_fwnode(dev->parent);
+ if (!fwnode)
+ return dev_err_probe(dev, -ENODEV, "missing parent firmware node\n");
+
+ /* Borrow the parent's firmware node so consumers can find this mux chip */
+ device_set_node(&mux_chip->dev, fwnode);
+
+ priv = mux_chip_priv(mux_chip);
+ priv->dev = dev;
+
+ priv->map = dev_get_regmap(dev->parent, NULL);
+ if (!priv->map)
+ return dev_err_probe(dev, -ENODEV, "failed to get parent regmap\n");
+
+ mux_chip->ops = &mc33978_mux_ops;
+
+ mux = &mux_chip->mux[0];
+ mux->states = MC33978_NUM_AMUX_CH;
+
+ ret = device_property_read_u32(&mux_chip->dev, "idle-state",
+ (u32 *)&idle_state);
+ if (ret < 0 && ret != -EINVAL) {
+ return dev_err_probe(dev, ret, "failed to parse idle-state\n");
+ } else if (ret == -EINVAL) {
+ mux->idle_state = MUX_IDLE_AS_IS;
+ } else {
+ if (idle_state == MUX_IDLE_DISCONNECT)
+ return dev_err_probe(dev, -EINVAL,
+ "idle-disconnect not supported by hardware\n");
+ if (idle_state != MUX_IDLE_AS_IS &&
+ (idle_state < 0 || idle_state >= MC33978_NUM_AMUX_CH))
+ return dev_err_probe(dev, -EINVAL, "invalid idle-state %d\n",
+ idle_state);
+ mux->idle_state = idle_state;
+ }
+
+ ret = devm_mux_chip_register(dev, mux_chip);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register mux chip\n");
+
+ platform_set_drvdata(pdev, mux_chip);
+
+ return 0;
+}
+
+static const struct platform_device_id mc33978_mux_id[] = {
+ { "mc33978-mux", },
+ { "mc34978-mux", },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, mc33978_mux_id);
+
+static struct platform_driver mc33978_mux_driver = {
+ .driver = {
+ .name = "mc33978-mux",
+ },
+ .probe = mc33978_mux_probe,
+ .id_table = mc33978_mux_id,
+};
+module_platform_driver(mc33978_mux_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("NXP MC33978/MC34978 Analog Multiplexer Driver");
+MODULE_LICENSE("GPL");
--
2.47.3
^ permalink raw reply related
* [PATCH v9 3/6] pinctrl: core: Make pin group callbacks optional for pin-only drivers
From: Oleksij Rempel @ 2026-03-31 17:16 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Lee Jones, Peter Rosin, Linus Walleij
Cc: Oleksij Rempel, kernel, linux-kernel, devicetree, linux-hwmon,
linux-gpio, David Jander
In-Reply-To: <20260331171612.102018-1-o.rempel@pengutronix.de>
Currently, the pinctrl core strictly requires all drivers to implement
.get_groups_count and .get_group_name callbacks in their pinctrl_ops.
However, for simple pinctrl drivers that act purely as GPIO controllers
and pin-specific configuration proxies, without any concept of muxing or
pin groups, this strict requirement forces the implementation of dummy
callbacks just to satisfy pinctrl_check_ops().
Relax this requirement for pin-only drivers by making the group callbacks
optional when no muxing or group pin configuration support is provided.
Update the core and debugfs helpers to check for the existence of these
callbacks before invoking them.
Drivers that provide muxing or group pin configuration operations still
must implement group enumeration and naming callbacks, and are rejected
at registration time if they do not.
Suggested-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Linus Walleij <linusw@kernel.org>
---
changes v9:
- no changes
changes v8:
- no changes
changes v7:
- no changes
changes v6:
- Reject drivers in pinctrl_check_ops() that use pmxops or group confops
without providing group callbacks.
- Add <linux/pinctrl/pinconf.h> to core.c.
- Revert the unnecessary NULL check in pinconf_show_setting(), since
group settings are now strictly gated.
- Keep debugfs group listings tolerant of drivers without group callbacks.
changes v5:
- no changes
changes v4:
- add Reviewed-by: Linus Walleij ...
changes v3:
- no changes
---
drivers/pinctrl/core.c | 41 ++++++++++++++++++++++++++++++++++-----
drivers/pinctrl/pinconf.c | 9 +++++++--
2 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index b5e97689589f..19a9a370d7b9 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -30,6 +30,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include "core.h"
@@ -621,8 +622,13 @@ static int pinctrl_generic_group_name_to_selector(struct pinctrl_dev *pctldev,
const char *function)
{
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
- int ngroups = ops->get_groups_count(pctldev);
int selector = 0;
+ int ngroups;
+
+ if (!ops->get_groups_count || !ops->get_group_name)
+ return -EINVAL;
+
+ ngroups = ops->get_groups_count(pctldev);
/* See if this pctldev has this group */
while (selector < ngroups) {
@@ -737,8 +743,15 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
const char *pin_group)
{
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
- unsigned int ngroups = pctlops->get_groups_count(pctldev);
unsigned int group_selector = 0;
+ unsigned int ngroups;
+
+ if (!pctlops->get_groups_count || !pctlops->get_group_name) {
+ dev_err(pctldev->dev, "does not support pin groups\n");
+ return -EINVAL;
+ }
+
+ ngroups = pctlops->get_groups_count(pctldev);
while (group_selector < ngroups) {
const char *gname = pctlops->get_group_name(pctldev,
@@ -1769,6 +1782,11 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
mutex_lock(&pctldev->mutex);
+ if (!ops->get_groups_count || !ops->get_group_name) {
+ mutex_unlock(&pctldev->mutex);
+ return 0;
+ }
+
ngroups = ops->get_groups_count(pctldev);
seq_puts(s, "registered pin groups:\n");
@@ -2049,12 +2067,25 @@ static void pinctrl_remove_device_debugfs(struct pinctrl_dev *pctldev)
static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
{
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
+ const struct pinconf_ops *confops = pctldev->desc->confops;
+ bool needs_groups = false;
- if (!ops ||
- !ops->get_groups_count ||
- !ops->get_group_name)
+ if (!ops)
return -EINVAL;
+ if (pctldev->desc->pmxops)
+ needs_groups = true;
+
+ if (confops && (confops->pin_config_group_get ||
+ confops->pin_config_group_set))
+ needs_groups = true;
+
+ if (needs_groups && (!ops->get_groups_count || !ops->get_group_name)) {
+ dev_err(pctldev->dev,
+ "driver needs group callbacks for mux or group config\n");
+ return -EINVAL;
+ }
+
return 0;
}
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index dca963633b5d..81686844dfa5 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -275,7 +275,7 @@ void pinconf_show_setting(struct seq_file *s,
case PIN_MAP_TYPE_CONFIGS_GROUP:
seq_printf(s, "group %s (%d)",
pctlops->get_group_name(pctldev,
- setting->data.configs.group_or_pin),
+ setting->data.configs.group_or_pin),
setting->data.configs.group_or_pin);
break;
default:
@@ -348,8 +348,13 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
- unsigned int ngroups = pctlops->get_groups_count(pctldev);
unsigned int selector = 0;
+ unsigned int ngroups;
+
+ if (!pctlops->get_groups_count || !pctlops->get_group_name)
+ return 0;
+
+ ngroups = pctlops->get_groups_count(pctldev);
seq_puts(s, "Pin config settings per pin group\n");
seq_puts(s, "Format: group (name): configs\n");
--
2.47.3
^ permalink raw reply related
* [PATCH v9 0/6] mfd: Add support for NXP MC33978/MC34978 MSDI
From: Oleksij Rempel @ 2026-03-31 17:16 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Lee Jones, Peter Rosin, Linus Walleij
Cc: Oleksij Rempel, kernel, linux-kernel, devicetree, linux-hwmon,
linux-gpio, David Jander
changes v7:
- drop gpiolib irq fix and make pinctrl more robust against NULL point
dereference.
This series adds support for the NXP MC33978/MC34978 Multiple Switch Detection
Interface (MSDI) via the MFD framework.
Architecture overview:
* mfd: Core driver handling 2-frame pipelined SPI, regulator sequencing, and
linear irq_domain. Harvests status bits from SPI MISO MSB.
* pinctrl: Exposes 22 physical switch inputs as standard GPIOs. Proxies IRQs to
the MFD domain.
* hwmon: Exposes thermal limits, VBATP/VDDQ voltage boundaries, and dynamic
fault alarms.
* mux: Controls the 24-to-1 AMUX routing analog signals (switch voltages,
temperature, VBATP) to an external ADC.
Initial pinctrl implementation by David Jander, reworked into this MFD
architecture.
Best regards,
Oleksij
David Jander (1):
pinctrl: add NXP MC33978/MC34978 pinctrl driver
Oleksij Rempel (5):
dt-bindings: pinctrl: add NXP MC33978/MC34978 MSDI
mfd: add NXP MC33978/MC34978 core driver
pinctrl: core: Make pin group callbacks optional for pin-only drivers
hwmon: add NXP MC33978/MC34978 driver
mux: add NXP MC33978/MC34978 AMUX driver
.../bindings/pinctrl/nxp,mc33978.yaml | 158 +++
drivers/hwmon/Kconfig | 10 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/mc33978-hwmon.c | 548 +++++++++
drivers/mfd/Kconfig | 15 +
drivers/mfd/Makefile | 2 +
drivers/mfd/mc33978.c | 1061 +++++++++++++++++
drivers/mux/Kconfig | 14 +
drivers/mux/Makefile | 2 +
drivers/mux/mc33978-mux.c | 141 +++
drivers/pinctrl/Kconfig | 16 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/core.c | 41 +-
drivers/pinctrl/pinconf.c | 9 +-
drivers/pinctrl/pinctrl-mc33978.c | 865 ++++++++++++++
include/linux/mfd/mc33978.h | 92 ++
16 files changed, 2969 insertions(+), 7 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pinctrl/nxp,mc33978.yaml
create mode 100644 drivers/hwmon/mc33978-hwmon.c
create mode 100644 drivers/mfd/mc33978.c
create mode 100644 drivers/mux/mc33978-mux.c
create mode 100644 drivers/pinctrl/pinctrl-mc33978.c
create mode 100644 include/linux/mfd/mc33978.h
--
2.47.3
^ permalink raw reply
* [PATCH v9 5/6] hwmon: add NXP MC33978/MC34978 driver
From: Oleksij Rempel @ 2026-03-31 17:16 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Lee Jones, Peter Rosin, Linus Walleij
Cc: Oleksij Rempel, kernel, linux-kernel, devicetree, linux-hwmon,
linux-gpio, David Jander
In-Reply-To: <20260331171612.102018-1-o.rempel@pengutronix.de>
Add hardware monitoring support for the NXP MC33978/MC34978 Multiple
Switch Detection Interface (MSDI).
The hardware utilizes a clear-on-read FAULT register, but physical
faults remain asserted as long as the underlying condition exists. This
asserts a global FAULT_STAT bit on the SPI bus. To handle this without
trapping the CPU in an interrupt storm, this driver implements the
following architecture:
- Requests a rising-edge nested IRQ (IRQF_TRIGGER_RISING) from the MFD
core to catch the initial 0 -> 1 transition of the global fault state.
- Caches hwmon-specific alarm bits and calculates state edges (XOR) to
isolate alarm transitions from system integrity faults.
- Implements a 1Hz delayed workqueue that polls the hardware as long as
any alarm is active. This compensates for the edge-triggered IRQ by
discovering secondary faults that occur without a rising edge, and
detecting when the hardware clears.
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Acked-by: Guenter Roeck <linux@roeck-us.net>
---
changes v9:
- add Acked-by: Guenter Roeck <linux@roeck-us.net>
changes v8:
- no changes
changes v7:
- Fix fault monitoring stall by unconditionally rearming on SPI read
errors.
- Fix use-after-free race during unbind by correcting devm registration
order.
changes v6:
- Protect clear-on-read FAULT register and state updates with hwmon_lock().
- Isolate hwmon alarm bits from system integrity bits to fix edge detection.
- Log system faults (SPI/HASH) as level-triggered and add temperature warning
logs.
- Refactor sysfs read callback into smaller subsystem-specific helpers.
- Fix probe race condition by calling mc33978_hwmon_update_faults() at the end
of probe instead of reading raw faults early.
- Expose static datasheet temperature limits via temp1_rated_min and
temp1_rated_max
- Introduce variant-specific hw_info data to correctly report the max
temperature
- Add a 1Hz delayed workqueue that polls the SPI bus while any alarm is active.
changes v5:
- no changes
changes v4:
- no changes
changes v3:
- no changes
changes v2:
- Switch from OF match table to platform_device_id
---
drivers/hwmon/Kconfig | 10 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/mc33978-hwmon.c | 548 ++++++++++++++++++++++++++++++++++
3 files changed, 559 insertions(+)
create mode 100644 drivers/hwmon/mc33978-hwmon.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 328867242cb3..0c52e8268a20 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -700,6 +700,16 @@ config SENSORS_MC13783_ADC
help
Support for the A/D converter on MC13783 and MC13892 PMIC.
+config SENSORS_MC33978
+ tristate "NXP MC33978/MC34978 fault monitoring"
+ depends on MFD_MC33978
+ help
+ If you say yes here you get fault monitoring support for the
+ NXP MC33978/MC34978 Multiple Switch Detection Interface (MSDI).
+
+ This driver can also be built as a module. If so, the module
+ will be called mc33978-hwmon.
+
config SENSORS_MC33XS2410
tristate "MC33XS2410 HWMON support"
depends on PWM_MC33XS2410
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 5833c807c688..4c3db5433a10 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -167,6 +167,7 @@ obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
obj-$(CONFIG_MAX31827) += max31827.o
obj-$(CONFIG_SENSORS_MAX77705) += max77705-hwmon.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_MC33978) += mc33978-hwmon.o
obj-$(CONFIG_SENSORS_MC33XS2410) += mc33xs2410_hwmon.o
obj-$(CONFIG_SENSORS_MC34VR500) += mc34vr500.o
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
diff --git a/drivers/hwmon/mc33978-hwmon.c b/drivers/hwmon/mc33978-hwmon.c
new file mode 100644
index 000000000000..0333c0315e06
--- /dev/null
+++ b/drivers/hwmon/mc33978-hwmon.c
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2026 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
+/*
+ * MC33978/MC34978 Hardware Monitor Driver
+ *
+ * Fault handling model:
+ *
+ * The FAULT register is clear-on-read for most bits, but persistent fault
+ * conditions remain asserted. The MFD core only harvests the aggregate
+ * FAULT_STAT indication from SPI responses and dispatches the hwmon child
+ * IRQ on that basis. Because a persistent fault can keep FAULT_STAT asserted,
+ * secondary fault assertions and fault clear events may not generate a fresh
+ * interrupt edge visible to the hwmon child.
+ *
+ * To provide stable hwmon alarm state, this driver:
+ * - caches only hwmon-relevant alarm bits
+ * - serializes FAULT register reads with cache updates
+ * - polls while any alarm remains active to detect secondary alarms and
+ * clearing edges
+ *
+ * Raw integrity bits such as SPI_ERROR and HASH are logged, but are not
+ * exported through hwmon alarm attributes.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/mc33978.h>
+
+/* Operating Temperature Ranges (Datasheet Rated) */
+#define MC33978_TEMP_MIN_MC (-40000)
+#define MC33978_TEMP_MAX_MC 125000
+#define MC34978_TEMP_MAX_MC 105000
+
+/* Thermal Warning threshold (~120C) */
+#define MC33978_TEMP_WARN_MC 120000
+
+/* Thermal Limit / tLIM (>155C) - Hardware enters CWET throttling */
+#define MC33978_TEMP_CRIT_MC 155000
+
+/* Hysteresis for tLIM recovery (Silicon must cool to <140C) */
+#define MC33978_TEMP_HYST_MC 15000
+
+/* VBATP (in0) IC Level thresholds */
+#define MC33978_VBATP_OV_MV 36000 /* Overvoltage limit */
+#define MC33978_VBATP_FUNC_MV 28000 /* Functional/Normal boundary */
+#define MC33978_VBATP_DEGRADED_MV 6000 /* Degraded parametrics start */
+#define MC33978_VBATP_UVLO_MV 4500 /* UV Rising Threshold max */
+
+/* VDDQ (in1) Logic Supply thresholds */
+#define MC33978_VDDQ_MAX_MV 5250 /* Operating Condition max */
+#define MC33978_VDDQ_MIN_MV 3000 /* Operating Condition min */
+#define MC33978_VDDQ_UV_MV 2800 /* UV Falling Threshold max */
+
+#define MC33978_FAULT_POLL_INTERVAL_MS 1000
+
+enum mc33978_hwmon_in_channels {
+ MC33978_IN_VBATP,
+ MC33978_IN_VDDQ,
+};
+
+struct mc33978_hwmon_priv {
+ struct device *dev;
+ struct device *hwmon_dev;
+ struct regmap *map;
+
+ const struct mc33978_hwmon_hw_info *hw_info;
+
+ int fault_irq;
+
+ /* Cached hwmon alarm bits, serialized by hwmon_lock(). */
+ u32 last_faults;
+
+ /*
+ * Background polling worker. Active only when faults are present
+ * to compensate for the lack of clearing/secondary edge interrupts.
+ */
+ struct delayed_work poll_work;
+};
+
+struct mc33978_hwmon_hw_info {
+ long rated_max_temp;
+};
+
+static const struct mc33978_hwmon_hw_info hwmon_hwinfo_mc33978 = {
+ .rated_max_temp = MC33978_TEMP_MAX_MC,
+};
+
+static const struct mc33978_hwmon_hw_info hwmon_hwinfo_mc34978 = {
+ .rated_max_temp = MC34978_TEMP_MAX_MC,
+};
+
+static int mc33978_hwmon_read_fault(struct mc33978_hwmon_priv *priv,
+ u32 *faults)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(priv->map, MC33978_REG_FAULT, &val);
+ if (ret)
+ return ret;
+
+ *faults = val;
+
+ return 0;
+}
+
+static void mc33978_hwmon_report_faults(struct mc33978_hwmon_priv *priv,
+ u32 new_faults)
+{
+ if (!new_faults)
+ return;
+
+ if (new_faults & MC33978_FAULT_TEMP_WARN)
+ dev_warn_ratelimited(priv->dev, "Temperature warning threshold reached\n");
+
+ if (new_faults & MC33978_FAULT_OT)
+ dev_crit_ratelimited(priv->dev, "Over-temperature fault detected!\n");
+
+ if (new_faults & MC33978_FAULT_OV)
+ dev_crit_ratelimited(priv->dev, "Over-voltage fault detected!\n");
+
+ if (new_faults & MC33978_FAULT_UV)
+ dev_err_ratelimited(priv->dev, "Under-voltage fault detected!\n");
+}
+
+static int mc33978_hwmon_update_faults(struct mc33978_hwmon_priv *priv)
+{
+ u32 old_faults, new_faults, changed_faults;
+ u32 alarm_faults = 0;
+ u32 faults = 0;
+ bool rearm;
+ int ret;
+
+ /*
+ * Serialize clear-on-read FAULT register access with cached alarm state
+ * updates and hwmon sysfs readers.
+ */
+ hwmon_lock(priv->hwmon_dev);
+ old_faults = priv->last_faults;
+
+ ret = mc33978_hwmon_read_fault(priv, &faults);
+ if (ret) {
+ hwmon_unlock(priv->hwmon_dev);
+ dev_err_ratelimited(priv->dev,
+ "failed to read fault register: %pe\n",
+ ERR_PTR(ret));
+ /*
+ * Always retry on read failure. If we drop the heartbeat during
+ * the initial fault before caching it, the edge-triggered IRQ
+ * will never fire again and permanently stall fault monitoring.
+ */
+ rearm = true;
+ goto out_poll;
+ }
+
+ /* Isolate hwmon alarm bits from system integrity bits */
+ alarm_faults = faults & MC33978_FAULT_ALARM_MASK;
+ changed_faults = alarm_faults ^ old_faults;
+ new_faults = alarm_faults & ~old_faults;
+ priv->last_faults = alarm_faults;
+
+ hwmon_unlock(priv->hwmon_dev);
+
+ if (faults & MC33978_FAULT_SPI_ERROR)
+ dev_err_ratelimited(priv->dev, "SPI communication error detected\n");
+ if (faults & MC33978_FAULT_HASH)
+ dev_err_ratelimited(priv->dev, "SPI register hash mismatch detected\n");
+
+ if (new_faults)
+ mc33978_hwmon_report_faults(priv, new_faults);
+
+ if (changed_faults & MC33978_FAULT_UV)
+ hwmon_notify_event(priv->hwmon_dev, hwmon_in,
+ hwmon_in_lcrit_alarm, MC33978_IN_VBATP);
+
+ if (changed_faults & MC33978_FAULT_OV)
+ hwmon_notify_event(priv->hwmon_dev, hwmon_in,
+ hwmon_in_crit_alarm, MC33978_IN_VBATP);
+
+ if (changed_faults & MC33978_FAULT_TEMP_WARN)
+ hwmon_notify_event(priv->hwmon_dev, hwmon_temp,
+ hwmon_temp_max_alarm, 0);
+
+ if (changed_faults & MC33978_FAULT_OT)
+ hwmon_notify_event(priv->hwmon_dev, hwmon_temp,
+ hwmon_temp_crit_alarm, 0);
+
+ if (changed_faults)
+ hwmon_notify_event(priv->hwmon_dev, hwmon_chip,
+ hwmon_chip_alarms, 0);
+
+ rearm = !!alarm_faults;
+
+out_poll:
+ /*
+ * If any alarms are currently active, the global FAULT_STAT bit remains
+ * asserted. The hardware will not generate a new rising edge interrupt
+ * if a secondary fault occurs, nor will it interrupt when faults clear.
+ * Schedule a poll to detect both clearing edges and secondary alarms.
+ */
+ if (rearm)
+ mod_delayed_work(system_wq, &priv->poll_work,
+ msecs_to_jiffies(MC33978_FAULT_POLL_INTERVAL_MS));
+
+ return ret;
+}
+
+static irqreturn_t mc33978_hwmon_fault_irq(int irq, void *data)
+{
+ struct mc33978_hwmon_priv *priv = data;
+
+ mc33978_hwmon_update_faults(priv);
+
+ return IRQ_HANDLED;
+}
+
+static void mc33978_hwmon_poll_work(struct work_struct *work)
+{
+ struct mc33978_hwmon_priv *priv =
+ container_of(work, struct mc33978_hwmon_priv, poll_work.work);
+
+ mc33978_hwmon_update_faults(priv);
+}
+
+static umode_t mc33978_hwmon_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ switch (type) {
+ case hwmon_chip:
+ if (attr == hwmon_chip_alarms)
+ return 0444;
+ break;
+
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_max:
+ case hwmon_temp_crit:
+ case hwmon_temp_crit_hyst:
+ case hwmon_temp_max_alarm:
+ case hwmon_temp_crit_alarm:
+ case hwmon_temp_rated_min:
+ case hwmon_temp_rated_max:
+ return 0444;
+ default:
+ break;
+ }
+ break;
+
+ case hwmon_in:
+ switch (attr) {
+ case hwmon_in_label:
+ case hwmon_in_max:
+ case hwmon_in_min:
+ case hwmon_in_lcrit:
+ return 0444;
+ case hwmon_in_crit:
+ if (channel == MC33978_IN_VBATP)
+ return 0444;
+ break;
+ case hwmon_in_crit_alarm:
+ case hwmon_in_lcrit_alarm:
+ if (channel == MC33978_IN_VBATP)
+ return 0444;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mc33978_hwmon_read_chip(struct mc33978_hwmon_priv *priv, u32 attr,
+ long *val)
+{
+ if (attr == hwmon_chip_alarms) {
+ *val = priv->last_faults;
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int mc33978_hwmon_read_in_vbatp(struct mc33978_hwmon_priv *priv,
+ u32 attr, long *val)
+{
+ switch (attr) {
+ case hwmon_in_crit:
+ *val = MC33978_VBATP_OV_MV;
+ return 0;
+ case hwmon_in_max:
+ *val = MC33978_VBATP_FUNC_MV;
+ return 0;
+ case hwmon_in_min:
+ *val = MC33978_VBATP_DEGRADED_MV;
+ return 0;
+ case hwmon_in_lcrit:
+ *val = MC33978_VBATP_UVLO_MV;
+ return 0;
+ case hwmon_in_crit_alarm:
+ *val = !!(priv->last_faults & MC33978_FAULT_OV);
+ return 0;
+ case hwmon_in_lcrit_alarm:
+ *val = !!(priv->last_faults & MC33978_FAULT_UV);
+ return 0;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int mc33978_hwmon_read_in_vddq(u32 attr, long *val)
+{
+ switch (attr) {
+ case hwmon_in_max:
+ *val = MC33978_VDDQ_MAX_MV;
+ return 0;
+ case hwmon_in_min:
+ *val = MC33978_VDDQ_MIN_MV;
+ return 0;
+ case hwmon_in_lcrit:
+ *val = MC33978_VDDQ_UV_MV;
+ return 0;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int mc33978_hwmon_read_in(struct mc33978_hwmon_priv *priv, u32 attr,
+ int channel, long *val)
+{
+ switch (channel) {
+ case MC33978_IN_VBATP:
+ return mc33978_hwmon_read_in_vbatp(priv, attr, val);
+ case MC33978_IN_VDDQ:
+ return mc33978_hwmon_read_in_vddq(attr, val);
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int mc33978_hwmon_read_temp(struct mc33978_hwmon_priv *priv, u32 attr,
+ long *val)
+{
+ switch (attr) {
+ case hwmon_temp_max:
+ *val = MC33978_TEMP_WARN_MC;
+ return 0;
+ case hwmon_temp_crit:
+ *val = MC33978_TEMP_CRIT_MC;
+ return 0;
+ case hwmon_temp_crit_hyst:
+ *val = MC33978_TEMP_CRIT_MC - MC33978_TEMP_HYST_MC;
+ return 0;
+ case hwmon_temp_max_alarm:
+ *val = !!(priv->last_faults & MC33978_FAULT_TEMP_WARN);
+ return 0;
+ case hwmon_temp_crit_alarm:
+ *val = !!(priv->last_faults & MC33978_FAULT_OT);
+ return 0;
+ case hwmon_temp_rated_min:
+ *val = MC33978_TEMP_MIN_MC;
+ return 0;
+ case hwmon_temp_rated_max:
+ *val = priv->hw_info->rated_max_temp;
+ return 0;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int mc33978_hwmon_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct mc33978_hwmon_priv *priv = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_chip:
+ return mc33978_hwmon_read_chip(priv, attr, val);
+ case hwmon_in:
+ return mc33978_hwmon_read_in(priv, attr, channel, val);
+ case hwmon_temp:
+ return mc33978_hwmon_read_temp(priv, attr, val);
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int mc33978_hwmon_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ /* Only in_label is supported for string reads */
+ if (type != hwmon_in || attr != hwmon_in_label)
+ return -EOPNOTSUPP;
+
+ switch (channel) {
+ case MC33978_IN_VBATP:
+ *str = "VBATP";
+ return 0;
+ case MC33978_IN_VDDQ:
+ *str = "VDDQ";
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct hwmon_channel_info * const mc33978_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(chip,
+ HWMON_C_ALARMS),
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_CRIT_HYST |
+ HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM |
+ HWMON_T_RATED_MIN | HWMON_T_RATED_MAX),
+ HWMON_CHANNEL_INFO(in,
+ /* Index 0: MC33978_IN_VBATP */
+ HWMON_I_LABEL | HWMON_I_CRIT | HWMON_I_MAX |
+ HWMON_I_MIN | HWMON_I_LCRIT |
+ HWMON_I_CRIT_ALARM | HWMON_I_LCRIT_ALARM,
+
+ /* Index 1: MC33978_IN_VDDQ */
+ HWMON_I_LABEL | HWMON_I_MAX | HWMON_I_MIN |
+ HWMON_I_LCRIT),
+ NULL
+};
+
+static const struct hwmon_ops mc33978_hwmon_ops = {
+ .is_visible = mc33978_hwmon_is_visible,
+ .read_string = mc33978_hwmon_read_string,
+ .read = mc33978_hwmon_read,
+};
+
+static const struct hwmon_chip_info mc33978_hwmon_chip_info = {
+ .ops = &mc33978_hwmon_ops,
+ .info = mc33978_hwmon_info,
+};
+
+static void mc33978_hwmon_action_cancel_work(void *data)
+{
+ struct mc33978_hwmon_priv *priv = data;
+
+ cancel_delayed_work_sync(&priv->poll_work);
+}
+
+static int mc33978_hwmon_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *id;
+ struct device *dev = &pdev->dev;
+ struct mc33978_hwmon_priv *priv;
+ struct device *hwmon_dev;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+
+ id = platform_get_device_id(pdev);
+ if (!id || !id->driver_data)
+ return dev_err_probe(dev, -EINVAL, "missing device match data\n");
+
+ priv->hw_info = (const struct mc33978_hwmon_hw_info *)id->driver_data;
+
+ priv->map = dev_get_regmap(dev->parent, NULL);
+ if (!priv->map)
+ return dev_err_probe(dev, -ENODEV, "failed to get regmap\n");
+
+ platform_set_drvdata(pdev, priv);
+
+ INIT_DELAYED_WORK(&priv->poll_work, mc33978_hwmon_poll_work);
+
+ priv->fault_irq = platform_get_irq(pdev, 0);
+ if (priv->fault_irq < 0)
+ return priv->fault_irq;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, "mc33978", priv,
+ &mc33978_hwmon_chip_info,
+ NULL);
+ if (IS_ERR(hwmon_dev))
+ return dev_err_probe(dev, PTR_ERR(hwmon_dev),
+ "failed to register hwmon device\n");
+
+ priv->hwmon_dev = hwmon_dev;
+
+ ret = devm_add_action_or_reset(dev, mc33978_hwmon_action_cancel_work,
+ priv);
+ if (ret)
+ return ret;
+
+ /*
+ * The FAULT child IRQ is generated by the MFD core from transitions of
+ * the aggregated FAULT_STAT bus state. Request a rising-edge nested
+ * IRQ so the core dispatches the hwmon fault handler when faults become
+ * active.
+ *
+ * Fault clearing and secondary faults while FAULT_STAT remains asserted
+ * are handled by the hwmon polling path.
+ */
+ ret = devm_request_threaded_irq(dev, priv->fault_irq, NULL,
+ mc33978_hwmon_fault_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ dev_name(dev), priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request fault IRQ\n");
+
+ return mc33978_hwmon_update_faults(priv);
+}
+
+static const struct platform_device_id mc33978_hwmon_id[] = {
+ { "mc33978-hwmon", (kernel_ulong_t)&hwmon_hwinfo_mc33978 },
+ { "mc34978-hwmon", (kernel_ulong_t)&hwmon_hwinfo_mc34978 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, mc33978_hwmon_id);
+
+static struct platform_driver mc33978_hwmon_driver = {
+ .driver = {
+ .name = "mc33978-hwmon",
+ },
+ .probe = mc33978_hwmon_probe,
+ .id_table = mc33978_hwmon_id,
+};
+module_platform_driver(mc33978_hwmon_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("NXP MC33978/MC34978 Hardware Monitor Driver");
+MODULE_LICENSE("GPL");
--
2.47.3
^ permalink raw reply related
* [PATCH 2/2] riscv: dts: sophgo: Add dma-coherent to SG2042 PCIe controllers
From: Han Gao @ 2026-03-31 17:12 UTC (permalink / raw)
To: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen Wang, Inochi Amaoto, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Han Gao, Zixian Zeng
Cc: linux-pci, devicetree, sophgo, linux-kernel, linux-riscv, Han Gao,
stable
In-Reply-To: <20260331171248.973014-1-gaohan@iscas.ac.cn>
SG2042's PCIe root complexes are cache-coherent with the CPU. Mark all
four PCIe controller nodes (pcie_rc0 through pcie_rc3) as dma-coherent
so the kernel uses coherent DMA mappings instead of non-coherent bounce
buffering.
Cc: stable@vger.kernel.org
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
---
arch/riscv/boot/dts/sophgo/sg2042.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
index 9fddf3f0b3b9..3af770549742 100644
--- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi
+++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
@@ -417,6 +417,7 @@ pcie_rc0: pcie@7060000000 {
vendor-id = <0x1f1c>;
device-id = <0x2042>;
cdns,no-bar-match-nbits = <48>;
+ dma-coherent;
msi-parent = <&msi>;
status = "disabled";
};
@@ -439,6 +440,7 @@ pcie_rc1: pcie@7060800000 {
vendor-id = <0x1f1c>;
device-id = <0x2042>;
cdns,no-bar-match-nbits = <48>;
+ dma-coherent;
msi-parent = <&msi>;
status = "disabled";
};
@@ -461,6 +463,7 @@ pcie_rc2: pcie@7062000000 {
vendor-id = <0x1f1c>;
device-id = <0x2042>;
cdns,no-bar-match-nbits = <48>;
+ dma-coherent;
msi-parent = <&msi>;
status = "disabled";
};
@@ -483,6 +486,7 @@ pcie_rc3: pcie@7062800000 {
vendor-id = <0x1f1c>;
device-id = <0x2042>;
cdns,no-bar-match-nbits = <48>;
+ dma-coherent;
msi-parent = <&msi>;
status = "disabled";
};
--
2.47.3
^ permalink raw reply related
* [PATCH 0/2] riscv: sophgo: sg2042: Enable PCIe DMA coherence
From: Han Gao @ 2026-03-31 17:12 UTC (permalink / raw)
To: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen Wang, Inochi Amaoto, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Han Gao, Zixian Zeng
Cc: linux-pci, devicetree, sophgo, linux-kernel, linux-riscv, Han Gao
The SG2042 hardware design supports cache-coherent PCIe.
With recent firmware updates [1], it allows to use DMA coherent.
[1] https://github.com/sophgo/edk2-non-osi/commit/017a5aea26a066fd2bf501b7893937183165af36
Han Gao (2):
dt-bindings: pci: sophgo: Add dma-coherent property for SG2042
riscv: dts: sophgo: Add dma-coherent to SG2042 PCIe controllers
.../devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml | 3 +++
arch/riscv/boot/dts/sophgo/sg2042.dtsi | 4 ++++
2 files changed, 7 insertions(+)
--
2.47.3
^ permalink raw reply
* [PATCH 1/2] dt-bindings: pci: sophgo: Add dma-coherent property for SG2042
From: Han Gao @ 2026-03-31 17:12 UTC (permalink / raw)
To: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen Wang, Inochi Amaoto, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Han Gao, Zixian Zeng
Cc: linux-pci, devicetree, sophgo, linux-kernel, linux-riscv, Han Gao
In-Reply-To: <20260331171248.973014-1-gaohan@iscas.ac.cn>
Add dma-coherent as an allowed property in the SG2042 PCIe host
controller binding. SG2042's PCIe root complexes are cache-coherent
with the CPU.
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
---
.../devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml b/Documentation/devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml
index f8b7ca57fff1..ab482488b047 100644
--- a/Documentation/devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml
+++ b/Documentation/devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml
@@ -30,6 +30,8 @@ properties:
device-id:
const: 0x2042
+ dma-coherent: true
+
msi-parent: true
allOf:
@@ -60,5 +62,6 @@ examples:
vendor-id = <0x1f1c>;
device-id = <0x2042>;
cdns,no-bar-match-nbits = <48>;
+ dma-coherent;
msi-parent = <&msi>;
};
--
2.47.3
^ permalink raw reply related
* [PATCH v4 3/3] ARM: dts: qcom: msm8960: expressatt: Add camera flash
From: Rudraksha Gupta via B4 Relay @ 2026-03-31 17:08 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bjorn Andersson, Konrad Dybcio,
Liam Girdwood, Mark Brown
Cc: linux-leds, devicetree, linux-kernel, linux-arm-msm, phone-devel,
Rudraksha Gupta, David Heidelberg, Konrad Dybcio
In-Reply-To: <20260331-expressatt_camera_flash-v4-0-f1e99f474513@gmail.com>
From: Rudraksha Gupta <guptarud@gmail.com>
Add camera flash support for the Samsung Galaxy Express (expressatt).
The flash IC uses a one-wire pulse-count protocol on GPIO 3, powered
by a GPIO-controlled fixed regulator on PMIC MPP 4. The regulator is
modeled as a regulator-fixed node and supplied to the flash IC via
vin-supply.
Downstream references:
Link: https://github.com/LineageOS/android_kernel_samsung_d2/blob/stable/cm-12.0-YNG4N/drivers/leds/Makefile#L51
Link: https://github.com/LineageOS/android_kernel_samsung_d2/blob/stable/cm-12.0-YNG4N/arch/arm/mach-msm/board-apexq-camera.c#L591
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: David Heidelberg <david@ixit.cz>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Rudraksha Gupta <guptarud@gmail.com>
---
.../dts/qcom/qcom-msm8960-samsung-expressatt.dts | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts
index c4b98af6955d..35514fd53e3d 100644
--- a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts
+++ b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
#include <dt-bindings/reset/qcom,gcc-msm8960.h>
#include "qcom-msm8960.dtsi"
@@ -61,6 +62,32 @@ touchkey_enable: touchkey-enable {
regulator-boot-on;
};
+ vreg_flash: regulator-flash {
+ compatible = "regulator-fixed";
+ regulator-name = "VREG_FLASH_3P3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&pm8921_mpps 4 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ pinctrl-0 = <&flash_led_unlock>;
+ pinctrl-names = "default";
+ };
+
+ led-controller {
+ compatible = "richtek,rt8515";
+ enf-gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
+ vin-supply = <&vreg_flash>;
+ richtek,rfs-ohms = <16000>;
+ pinctrl-0 = <&cam_flash_en>;
+ pinctrl-names = "default";
+
+ led {
+ function = LED_FUNCTION_FLASH;
+ color = <LED_COLOR_ID_WHITE>;
+ flash-max-timeout-us = <250000>;
+ };
+ };
+
i2c-gpio-touchkey {
compatible = "i2c-gpio";
#address-cells = <1>;
@@ -172,6 +199,13 @@ touchscreen@4a {
};
&tlmm {
+ cam_flash_en: cam-flash-en-state {
+ pins = "gpio3";
+ function = "gpio";
+ drive-strength = <16>;
+ bias-pull-down;
+ };
+
spi1_default: spi1-default-state {
mosi-pins {
pins = "gpio6";
@@ -572,3 +606,12 @@ magnetometer@2e {
/* TODO: Figure out Mount Matrix */
};
};
+
+&pm8921_mpps {
+ flash_led_unlock: flash-led-unlock-state {
+ pins = "mpp4";
+ function = "digital";
+ output-low;
+ power-source = <PM8921_GPIO_S4>;
+ };
+};
--
2.53.0
^ permalink raw reply related
* [PATCH v4 2/3] leds: flash: rt8515: Support single-GPIO flash ICs with vin supply
From: Rudraksha Gupta via B4 Relay @ 2026-03-31 17:08 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bjorn Andersson, Konrad Dybcio,
Liam Girdwood, Mark Brown
Cc: linux-leds, devicetree, linux-kernel, linux-arm-msm, phone-devel,
Rudraksha Gupta
In-Reply-To: <20260331-expressatt_camera_flash-v4-0-f1e99f474513@gmail.com>
From: Rudraksha Gupta <guptarud@gmail.com>
Extend the RT8515 driver to support flash ICs that use only a single
GPIO for both flash and torch modes (no separate ENT pin), with an
optional vin regulator that gates power to the flash IC.
When vin-supply is provided, the driver enables the regulator before
activating the LED and disables it when turning off.
Make ent-gpios optional and validate at probe time that exactly one of
ent-gpios or vin-supply is provided. When ent-gpios is absent, the
driver uses enf-gpios for both flash and torch brightness control.
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Rudraksha Gupta <guptarud@gmail.com>
---
drivers/leds/flash/leds-rt8515.c | 100 ++++++++++++++++++++++++++++++++-------
1 file changed, 83 insertions(+), 17 deletions(-)
diff --git a/drivers/leds/flash/leds-rt8515.c b/drivers/leds/flash/leds-rt8515.c
index f6b439674c03..c7f0bdf804a7 100644
--- a/drivers/leds/flash/leds-rt8515.c
+++ b/drivers/leds/flash/leds-rt8515.c
@@ -63,16 +63,44 @@ static struct rt8515 *to_rt8515(struct led_classdev_flash *fled)
return container_of(fled, struct rt8515, fled);
}
-static void rt8515_gpio_led_off(struct rt8515 *rt)
+static int rt8515_gpio_led_off(struct rt8515 *rt)
{
+ int ret;
+
gpiod_set_value(rt->enable_flash, 0);
- gpiod_set_value(rt->enable_torch, 0);
+ if (rt->enable_torch)
+ gpiod_set_value(rt->enable_torch, 0);
+
+ /* Disable regulator */
+ ret = regulator_is_enabled(rt->reg);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ return regulator_disable(rt->reg);
+
+ return 0;
}
-static void rt8515_gpio_brightness_commit(struct gpio_desc *gpiod,
- int brightness)
+static int rt8515_gpio_brightness_commit(struct rt8515 *rt,
+ struct gpio_desc *gpiod,
+ int brightness)
{
int i;
+ int ret;
+
+ /*
+ * Reset the IC to start brightness from zero,
+ * then re-enable and pulse to the desired level.
+ */
+ ret = rt8515_gpio_led_off(rt);
+ if (ret)
+ return ret;
+ /* IC needs time to reset its brightness counter */
+ usleep_range(100, 200);
+ /* Enable regulator */
+ ret = regulator_enable(rt->reg);
+ if (ret)
+ return ret;
/*
* Toggling a GPIO line with a small delay increases the
@@ -84,6 +112,8 @@ static void rt8515_gpio_brightness_commit(struct gpio_desc *gpiod,
gpiod_set_value(gpiod, 1);
udelay(1);
}
+
+ return 0;
}
/* This is setting the torch light level */
@@ -92,23 +122,39 @@ static int rt8515_led_brightness_set(struct led_classdev *led,
{
struct led_classdev_flash *fled = lcdev_to_flcdev(led);
struct rt8515 *rt = to_rt8515(fled);
+ int ret = 0;
mutex_lock(&rt->lock);
if (brightness == LED_OFF) {
/* Off */
- rt8515_gpio_led_off(rt);
+ ret = rt8515_gpio_led_off(rt);
+ if (ret)
+ goto out;
} else if (brightness < RT8515_TORCH_MAX) {
- /* Step it up to movie mode brightness using the flash pin */
- rt8515_gpio_brightness_commit(rt->enable_torch, brightness);
+ /*
+ * Step it up to movie mode brightness.
+ * If there is no separate torch pin, use the flash pin
+ * for torch as well.
+ */
+ ret = rt8515_gpio_brightness_commit(rt, rt->enable_torch ?
+ rt->enable_torch : rt->enable_flash, brightness);
+ if (ret)
+ goto out;
} else {
- /* Max torch brightness requested */
- gpiod_set_value(rt->enable_torch, 1);
+ /*
+ * Max torch brightness requested.
+ * If there is no separate torch pin, use the flash pin
+ * for torch as well.
+ */
+ gpiod_set_value(rt->enable_torch ? rt->enable_torch :
+ rt->enable_flash, 1);
}
+out:
mutex_unlock(&rt->lock);
- return 0;
+ return ret;
}
static int rt8515_led_flash_strobe_set(struct led_classdev_flash *fled,
@@ -117,27 +163,33 @@ static int rt8515_led_flash_strobe_set(struct led_classdev_flash *fled,
struct rt8515 *rt = to_rt8515(fled);
struct led_flash_setting *timeout = &fled->timeout;
int brightness = rt->flash_max_intensity;
+ int ret = 0;
mutex_lock(&rt->lock);
if (state) {
/* Enable LED flash mode and set brightness */
- rt8515_gpio_brightness_commit(rt->enable_flash, brightness);
+ ret = rt8515_gpio_brightness_commit(rt, rt->enable_flash, brightness);
+ if (ret)
+ goto out;
/* Set timeout */
mod_timer(&rt->powerdown_timer,
jiffies + usecs_to_jiffies(timeout->val));
} else {
timer_delete_sync(&rt->powerdown_timer);
/* Turn the LED off */
- rt8515_gpio_led_off(rt);
+ ret = rt8515_gpio_led_off(rt);
+ if (ret)
+ goto out;
}
fled->led_cdev.brightness = LED_OFF;
/* After this the torch LED will be disabled */
+out:
mutex_unlock(&rt->lock);
- return 0;
+ return ret;
}
static int rt8515_led_flash_strobe_get(struct led_classdev_flash *fled,
@@ -166,9 +218,12 @@ static const struct led_flash_ops rt8515_flash_ops = {
static void rt8515_powerdown_timer(struct timer_list *t)
{
struct rt8515 *rt = timer_container_of(rt, t, powerdown_timer);
+ int ret;
/* Turn the LED off */
- rt8515_gpio_led_off(rt);
+ ret = rt8515_gpio_led_off(rt);
+ if (ret)
+ dev_err(rt->dev, "failed to turn off LED (%d)\n", ret);
}
static void rt8515_init_flash_timeout(struct rt8515 *rt)
@@ -298,12 +353,18 @@ static int rt8515_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(rt->enable_flash),
"cannot get ENF (enable flash) GPIO\n");
- /* ENT - Enable Torch line */
- rt->enable_torch = devm_gpiod_get(dev, "ent", GPIOD_OUT_LOW);
+ /* ENT - Enable Torch line (optional for single-GPIO flash ICs) */
+ rt->enable_torch = devm_gpiod_get_optional(dev, "ent", GPIOD_OUT_LOW);
if (IS_ERR(rt->enable_torch))
return dev_err_probe(dev, PTR_ERR(rt->enable_torch),
"cannot get ENT (enable torch) GPIO\n");
+ /* Optional VIN supply */
+ rt->reg = devm_regulator_get(dev, "vin");
+ if (IS_ERR(rt->reg))
+ return dev_err_probe(dev, PTR_ERR(rt->reg),
+ "failed to get vin supply\n");
+
child = device_get_next_child_node(dev, NULL);
if (!child) {
dev_err(dev,
@@ -333,7 +394,12 @@ static int rt8515_probe(struct platform_device *pdev)
fled->ops = &rt8515_flash_ops;
- led->max_brightness = rt->torch_max_intensity;
+ /*
+ * If there is no separate torch pin, use the flash max intensity
+ * as the max brightness instead.
+ */
+ led->max_brightness = rt->enable_torch ?
+ rt->torch_max_intensity : rt->flash_max_intensity;
led->brightness_set_blocking = rt8515_led_brightness_set;
led->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH;
--
2.53.0
^ permalink raw reply related
* [PATCH v4 1/3] dt-bindings: leds: rt8515: Support single-GPIO flash ICs with vin supply
From: Rudraksha Gupta via B4 Relay @ 2026-03-31 17:08 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bjorn Andersson, Konrad Dybcio,
Liam Girdwood, Mark Brown
Cc: linux-leds, devicetree, linux-kernel, linux-arm-msm, phone-devel,
Rudraksha Gupta, Conor Dooley
In-Reply-To: <20260331-expressatt_camera_flash-v4-0-f1e99f474513@gmail.com>
From: Rudraksha Gupta <guptarud@gmail.com>
Some flash ICs use the same one-wire pulse-count protocol as the RT8515
but have only a single enable line for both flash and torch modes, plus
an optional input voltage supply (e.g. a GPIO-controlled fixed
regulator) that gates power to the chip.
Make ent-gpios optional and add a vin-supply property to support these
variants. Add a oneOf constraint requiring exactly one of ent-gpios or
vin-supply. Add a binding example showing the single-GPIO configuration
with an input supply.
Assisted-by: Claude:claude-opus-4.6
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Rudraksha Gupta <guptarud@gmail.com>
---
.../devicetree/bindings/leds/richtek,rt8515.yaml | 34 +++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml b/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml
index 0356371a6b01..ab3c5139132c 100644
--- a/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml
+++ b/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml
@@ -15,6 +15,10 @@ description: |
current for each mode is defined in hardware using two resistors
RFS and RTS.
+ Some flash ICs use the same one-wire pulse-count protocol but have
+ only a single enable line for both flash and torch modes. For these
+ single-channel variants, only enf-gpios is needed.
+
properties:
compatible:
const: richtek,rt8515
@@ -26,6 +30,11 @@ properties:
ent-gpios:
maxItems: 1
description: A connection to the 'ENT' (enable torch) pin.
+ Not present on single-channel flash ICs that use only one enable
+ line for both flash and torch modes.
+
+ vin-supply:
+ description: Optional input supply for the flash IC.
richtek,rfs-ohms:
minimum: 7680
@@ -81,10 +90,15 @@ properties:
required:
- compatible
- - ent-gpios
- enf-gpios
- led
+oneOf:
+ - required:
+ - ent-gpios
+ - required:
+ - vin-supply
+
additionalProperties: false
examples:
@@ -108,4 +122,22 @@ examples:
};
};
+ - |
+ /* Single-channel flash IC with input supply */
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/leds/common.h>
+
+ led-controller {
+ compatible = "richtek,rt8515";
+ enf-gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
+ vin-supply = <&flash_reg>;
+ richtek,rfs-ohms = <16000>;
+
+ led {
+ function = LED_FUNCTION_FLASH;
+ color = <LED_COLOR_ID_WHITE>;
+ flash-max-timeout-us = <250000>;
+ };
+ };
+
...
--
2.53.0
^ permalink raw reply related
* [PATCH v4 0/3] Samsung Expressatt: Camera Flash
From: Rudraksha Gupta via B4 Relay @ 2026-03-31 17:08 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bjorn Andersson, Konrad Dybcio,
Liam Girdwood, Mark Brown
Cc: linux-leds, devicetree, linux-kernel, linux-arm-msm, phone-devel,
Rudraksha Gupta, Conor Dooley, David Heidelberg, Konrad Dybcio
This small series adds camera flash to an existing similar mainline
driver and adds it to the Samsung Expressatt's DTS
// Tests
// # Navigate to LED
sudo su
cd /sys/class/leds/white:flash
// # Should stay at dim brightness
echo 1 > brightness
echo 1 > brightness
echo 1 > brightness
echo 1 > brightness
echo 0 > brightness # LED_OFF
// # Max Brightness
echo 50 > brightness
echo 0 > brightness # LED_OFF
echo 99 > brightness
echo 0 > brightness # LED_OFF
echo 1000 > brightness
echo 0 > brightness # LED_OFF
echo 100 > brightness
echo 0 > brightness # LED_OFF
// # Should increase in brightness
for i in $(seq 1 16); do echo $i > brightness; sleep 1; done
echo 0 > brightness # LED_OFF
// # Test flash strobe (rt8515_led_flash_strobe_set)
cat max_flash_timeout # check max
echo 200000 > flash_timeout # 200ms
echo 1 > flash_strobe # strobe ON → brightness_commit + timer
cat flash_strobe # should read 1, then 0 after timeout
sleep 1
cat flash_strobe # should be 0 (timer fired)
// # Test manual strobe cancel
echo 1 > flash_strobe ; echo 0 > flash_strobe # immediate off
// # Check regulator error handling
dmesg | tail -20 # look for any "failed to turn off LED" msgs
Downstream reference:
Link: https://github.com/LineageOS/android_kernel_samsung_d2/blob/stable/cm-12.0-YNG4N/drivers/leds/Makefile#L51
Link: https://github.com/LineageOS/android_kernel_samsung_d2/blob/stable/cm-12.0-YNG4N/arch/arm/mach-msm/board-apexq-camera.c#L591
Signed-off-by: Rudraksha Gupta <guptarud@gmail.com>
---
Changes in v4:
- Driver:
- revert function renames
- add comment to use flash instead if torch pin not available
- Link to v3: https://lore.kernel.org/r/20260326-expressatt_camera_flash-v3-0-e75e5d58990f@gmail.com
Changes in v3:
- DTS:
- Renamed and reordered nodes
- Driver:
- Use regulator_is_enabled() instead of reg_enabled
- remove ent xor vin check
- remove rt->reg == -ENODEV check
- rename functions to reflect what they do and added ret's
- Fixed: LED was increasing in brightness when setting the same
brightness multiple times
- Link to v2: https://lore.kernel.org/r/20260318-expressatt_camera_flash-v2-0-5c2b9a623dcb@gmail.com
Changes in v2:
- dt-bindings: Explain the hardware and not the driver
- **/*: Use vin-supply instead of unlock-gpio
- expressatt DTS: Reorder pinctrl-*
- expressatt DTS: Define rfs-ohms to a default (couldn't find
information about this)
- Link to v1: https://lore.kernel.org/r/20260306-expressatt_camera_flash-v1-0-b1996f7cdfdd@gmail.com
---
Rudraksha Gupta (3):
dt-bindings: leds: rt8515: Support single-GPIO flash ICs with vin supply
leds: flash: rt8515: Support single-GPIO flash ICs with vin supply
ARM: dts: qcom: msm8960: expressatt: Add camera flash
.../devicetree/bindings/leds/richtek,rt8515.yaml | 34 ++++++-
.../dts/qcom/qcom-msm8960-samsung-expressatt.dts | 43 +++++++++
drivers/leds/flash/leds-rt8515.c | 100 +++++++++++++++++----
3 files changed, 159 insertions(+), 18 deletions(-)
---
base-commit: e9ec05addd1a067fc7cb218f20ecdc1b1b0898c0
change-id: 20260306-expressatt_camera_flash-13c15a7427aa
prerequisite-message-id: <20251205-expressatt-touchkey-v1-1-1444b927c9f3@gmail.com>
prerequisite-patch-id: 8de4de7909722ccaf385c4224f25a623eaa72c28
Best regards,
--
Rudraksha Gupta <guptarud@gmail.com>
^ permalink raw reply
* RE: [PATCH v5 2/4] iio: adc: ad4691: add initial driver for AD4691 family
From: Sabau, Radu bogdan @ 2026-03-31 17:05 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Andy Shevchenko, Lars-Peter Clausen, Hennerich, Michael,
Jonathan Cameron, David Lechner, Sa, Nuno, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Uwe Kleine-König, Liam Girdwood, Mark Brown, Linus Walleij,
Bartosz Golaszewski, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org,
linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org
In-Reply-To: <acuMxjX_rsfsJvMp@ashevche-desk.local>
> -----Original Message-----
> From: Andy Shevchenko <andriy.shevchenko@intel.com>
> Sent: Tuesday, March 31, 2026 11:59 AM
> To: Sabau, Radu bogdan <Radu.Sabau@analog.com>
> Cc: Andy Shevchenko <andy.shevchenko@gmail.com>; Lars-Peter Clausen
> <lars@metafoo.de>; Hennerich, Michael <Michael.Hennerich@analog.com>;
> Jonathan Cameron <jic23@kernel.org>; David Lechner
> <dlechner@baylibre.com>; Sa, Nuno <Nuno.Sa@analog.com>; Andy
> Shevchenko <andy@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof
> Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Uwe
> Kleine-König <ukleinek@kernel.org>; Liam Girdwood <lgirdwood@gmail.com>;
> Mark Brown <broonie@kernel.org>; Linus Walleij <linusw@kernel.org>;
> Bartosz Golaszewski <brgl@kernel.org>; Philipp Zabel
> <p.zabel@pengutronix.de>; Jonathan Corbet <corbet@lwn.net>; Shuah Khan
> <skhan@linuxfoundation.org>; linux-iio@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> pwm@vger.kernel.org; linux-gpio@vger.kernel.org; linux-doc@vger.kernel.org
> Subject: Re: [PATCH v5 2/4] iio: adc: ad4691: add initial driver for AD4691
> family
>
> [External]
>
> On Tue, Mar 31, 2026 at 08:36:42AM +0000, Sabau, Radu bogdan wrote:
> > > -----Original Message-----
> > > From: Andy Shevchenko <andy.shevchenko@gmail.com>
> > > Sent: Monday, March 30, 2026 8:24 PM
>
> ...
>
> > > > > > +#include <linux/bitfield.h>
> > > > > > +#include <linux/bitops.h>
> > > > > > +#include <linux/cleanup.h>
> > > > > > +#include <linux/delay.h>
> > > > > > +#include <linux/device.h>
> > > > >
> > > > > Hmm... Is it used? Or perhaps you need only
> > > > > dev_printk.h
> > > > > device/devres.h
> > > > > ?
> > >
> > > > I have checked this out and it seems device.h doesn't actually need
> > > > to be included anyway since spi.h directly includes device.h, and since
> > > > this is a SPI driver that's never going away, it's covered. Will drop it!
> > >
> > > No, this is the wrong justification. IWYU principle is about exact
> > > match between what is used and included in a file (module). spi.h is
> > > not dev_*() provider and may not be considered for that.
> > >
> >
> > You are right, my justification was incorrect. Under IWYU, relying on
> > spi.h's transitive pull of device.h is not valid. However, I think device.h
> > is still needed in this case since struct device is used directly in the code
> > both as local variables and in the regmap callbacks.
>
> Really? I can't see that.
> (Hint: use of the data type and use of its pointer is a huge difference.)
>
> > Also dev_err_probe() is called directly and lives in device.h.
>
> No, as I started with my replies. The proper header that provides it is
> dev_printk.h.
>
Yep, my bad... device.h can be removed and devres and dev_printk be
used instead. Sorry for the confusion from my end, I thought I was
looking at device.h, but was instead looking at dev_printk.h.
^ permalink raw reply
* Re: [PATCH v2] arm64: dts: qcom: x1e80100-dell-xps13-9345: enable onboard accelerometers
From: Val Packett @ 2026-03-31 17:04 UTC (permalink / raw)
To: Aleksandrs Vinarskis, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: laurentiu.tudor1, linux-arm-msm, devicetree, linux-kernel,
Dmitry Baryshkov
In-Reply-To: <20260331-dell-xps-9345-accel-v2-1-7dacbd24b43d@vinarskis.com>
On 3/31/26 10:36 AM, Aleksandrs Vinarskis wrote:
> Particular laptop comes with two sets of sensors:
> 1. Motherboard: accelerometer
> 2. Display/Camera module: accelerometer, ambient ligth (and more)
> sensor
>
> Both i2c busses are bound to Snapdragon Sensor Core (SSC) and are
> typically controlled by (A)DSP thus allowing for great power
> efficiency. This however requires DSP libraries matching ADSP firmware,
> sensors descriptions (must be extracted from Windows) and other
> potentially closed-source libraries. Opensource tooling includes
> `libssc` and `hexagonrpcd`, but they were not verified to be working.
>
> Until SSC support for X1E lands, bitbang both i2c busses to enable
> accelerometer functionality. In the future if/when sensors on this
> platform can be used from DSP directly, this commit can be reverted.
>
> [..]
WDYM by "support lands"? It's a userspace setup thing, nothing new
should be required in the kernel.
It is amazing that this bitbanging works here, I don't think it was
expected to ever work on anything newer than msm89x7 o.0
But this is likely inefficient… and "stealing" GPIOs from ADSP like this
sounds rather scary. And would definitely break SSC initialization for
anyone wanting to bring up hexagonrpcd/iio-sensor-proxy.
~val
^ permalink raw reply
* [PATCH] arm64: dts: qcom: sm8750: Fix DSI1 phy reference clock rate
From: Krzysztof Kozlowski @ 2026-03-31 16:56 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Dmitry Baryshkov, linux-arm-msm, devicetree,
linux-kernel
Cc: Krzysztof Kozlowski
The DSI PHY CXO clock input is the SoC CXO divided by two. DSI0 already
uses correct one, but DSI1 got copy-paste from SM8650. Wrong clock
parent will cause incorrect DSI1 PHY PLL frequencies to be used making
the DSI panel non-working, although there is no upstream user of DSI1.
Fixes: 818ae2b389bc ("arm64: dts: qcom: sm8750: Add display (MDSS) with Display CC")
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Fix for next branch.
---
arch/arm64/boot/dts/qcom/sm8750.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi
index 18fb52c14acd..320aec62e462 100644
--- a/arch/arm64/boot/dts/qcom/sm8750.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi
@@ -3313,7 +3313,7 @@ mdss_dsi1_phy: phy@ae97000 {
"dsi_pll";
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
- <&rpmhcc RPMH_CXO_CLK>;
+ <&bi_tcxo_div2>;
clock-names = "iface",
"ref";
--
2.51.0
^ permalink raw reply related
* Re: [PATCH 7/8] mfd: omap-usb-host: Add pbias regulator support
From: Lee Jones @ 2026-03-31 16:55 UTC (permalink / raw)
To: Thomas Richard
Cc: Aaro Koskinen, Andreas Kemnade, Kevin Hilman, Roger Quadros,
Tony Lindgren, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thomas Petazzoni, linux-omap,
linux-kernel, devicetree
In-Reply-To: <20260323-omap4-fix-usb-support-v1-7-b668132124ac@bootlin.com>
On Mon, 23 Mar 2026, Thomas Richard wrote:
> Add pbias regulator support to enable SIM_VDDS supply and unlock USB I/O
> cell. Previously, this was handled by the bootloader, now the kernel can
> take responsibility for managing the PBIAS regulator, ensuring correct
> operation regardless of the bootloader.
>
> Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
> ---
> drivers/mfd/omap-usb-host.c | 41 ++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 40 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
> index ac974285be341fa579ef198d1893b77af428b5f8..9e254e00183e940b775d5bde6e891f0d26af27b0 100644
> --- a/drivers/mfd/omap-usb-host.c
> +++ b/drivers/mfd/omap-usb-host.c
> @@ -15,6 +15,9 @@
> #include <linux/pm_runtime.h>
> #include <linux/of.h>
> #include <linux/of_platform.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/string_choices.h>
> +
?
>
> #include "omap-usb.h"
>
> @@ -95,6 +98,8 @@ struct usbhs_hcd_omap {
> struct usbhs_omap_platform_data *pdata;
>
> u32 usbhs_rev;
> +
> + struct regulator *pbias;
> };
> /*-------------------------------------------------------------------------*/
>
> @@ -270,6 +275,25 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
> }
> }
>
> +static int omap_usbhs_set_pbias(struct device *dev, bool power_on)
> +{
> + struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
> + int ret;
> +
> + if (!omap->pbias)
> + return 0;
> +
> + if (power_on)
> + ret = regulator_enable(omap->pbias);
> + else
> + ret = regulator_disable(omap->pbias);
> +
> + if (ret)
> + dev_err(dev, "pbias reg %s failed\n", str_enable_disable(power_on));
> +
> + return ret;
> +}
> +
> static int usbhs_runtime_resume(struct device *dev)
> {
> struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
> @@ -278,6 +302,10 @@ static int usbhs_runtime_resume(struct device *dev)
>
> dev_dbg(dev, "usbhs_runtime_resume\n");
>
> + r = omap_usbhs_set_pbias(dev, true);
> + if (r)
> + return r;
> +
> omap_tll_enable(pdata);
>
> if (!IS_ERR(omap->ehci_logic_fck))
> @@ -355,7 +383,7 @@ static int usbhs_runtime_suspend(struct device *dev)
>
> omap_tll_disable(pdata);
>
> - return 0;
> + return omap_usbhs_set_pbias(dev, false);
> }
>
> static unsigned omap_usbhs_rev1_hostconfig(struct usbhs_hcd_omap *omap,
> @@ -564,6 +592,11 @@ static int usbhs_omap_probe(struct platform_device *pdev)
>
> omap->pdata = pdata;
>
> + omap->pbias = devm_regulator_get_optional(dev, "pbias");
> + if (IS_ERR(omap->pbias))
> + return dev_err_probe(dev, PTR_ERR(omap->pbias),
> + "unable to get pbias regulator\n");
You need to check for '-ENODEV' here or you are ignoring the optional part.
> +
> /* Initialize the TLL subsystem */
> omap_tll_init(pdata);
>
> @@ -759,6 +792,10 @@ static int usbhs_omap_probe(struct platform_device *pdev)
> }
>
> initialize:
> + ret = omap_usbhs_set_pbias(dev, true);
> + if (ret)
> + goto err_mem;
Since this regulator is also managed by 'usbhs_runtime_resume' and
'usbhs_runtime_suspend', could manually enabling it here in probe and
disabling it in remove interfere with the reference counting during runtime
PM transitions? Should we consider relying entirely on runtime PM to manage
its state?
> +
> omap_usbhs_init(dev);
>
> if (dev->of_node) {
> @@ -806,6 +843,8 @@ static void usbhs_omap_remove(struct platform_device *pdev)
> of_platform_depopulate(&pdev->dev);
> else
> device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child);
> +
> + omap_usbhs_set_pbias(&pdev->dev, false);
> }
>
> static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
>
> --
> 2.53.0
>
--
Lee Jones [李琼斯]
^ permalink raw reply
* Re: [PATCH v2 2/6] phy: realtek: usb2: introduce read and write functions to driver data
From: Michael Zavertkin @ 2026-03-31 16:34 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Rustam Adilov, Vinod Koul, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Stanley Chang, linux-phy,
devicetree, linux-kernel
In-Reply-To: <20260330213227.zujvcvsxdfknzltz@skbuf>
On Tue, Mar 31, 2026 at 12:32:27AM +0300, Vladimir Oltean wrote:
> On Tue, Mar 31, 2026 at 12:19:18AM +0300, Vladimir Oltean wrote:
> > On Fri, Mar 27, 2026 at 09:06:34PM +0500, Rustam Adilov wrote:
> > > +static inline u32 phy_read(void __iomem *reg)
> > > +{
> > > + return readl(reg);
> > > +}
> > > +
> > > +static inline u32 phy_read_le(void __iomem *reg)
> > > +{
> > > + return le32_to_cpu(readl(reg));
> > > +}
> > > +
> > > +static inline void phy_write(u32 val, void __iomem *reg)
> > > +{
> > > + writel(val, reg);
> > > +}
> > > +
> > > +static inline void phy_write_le(u32 val, void __iomem *reg)
> > > +{
> > > + writel(cpu_to_le32(val), reg);
> > > +}
> >
> > Please don't name driver-level functions phy_read() and phy_write().
> > That will collide with networking API functions of the same name and
> > will make grep-based code searching more difficult.
> >
> > Also, have you looked at regmap? It has native support for endianness;
> > it supports regmap_field_read()/regmap_field_write() for abstracting
> > registers which may be found at different places for different HW;
> > it offers regmap_read_poll_timeout() so you don't have to pass the
> > function pointer to utmi_wait_register(). It seems the result would be a
> > bit more elegant.
>
> Even if you decide not to use regmap. I thought I should let you know
> that LLM review says:
>
> Are these double byte-swaps intentional?
>
> Since readl() and writel() inherently perform little-endian memory accesses
> and handle byte-swapping on big-endian architectures automatically, won't
> wrapping them in le32_to_cpu() and cpu_to_le32() apply a second, redundant
> byte-swap?
>
> On big-endian systems, wouldn't these double swaps cancel each other out
> and result in a native big-endian access instead of the intended
> little-endian access? If the SoC bus bridge implicitly swaps and requires
> a native access, should __raw_readl() and __raw_writel() (or ioread32be /
> iowrite32be) be used instead to avoid obfuscating it with double-swaps?
>
> Also, does passing the __le32 restricted type returned by cpu_to_le32()
> into writel() (which expects a native u32) trigger Sparse static analysis
> warnings for an incorrect type in argument?
>
> For reference:
> https://elixir.bootlin.com/linux/v6.19.10/source/include/asm-generic/io.h#L184
> /*
> * {read,write}{b,w,l,q}() access little endian memory and return result in
> * native endianness.
> */
There is readl() (and family) function. For most hosts it returns native
endian value (because most systems LE nowadays).
I don't know all context, and don't know exactly why... but for MIPS readl()
returns value in native endianess.
Reference - https://elixir.bootlin.com/linux/v6.19.10/source/arch/mips/include/asm/io.h
So we are in interesting situation, when readl() returns native-endian values (BE in our case),
readl_be() returns BE too, because cpu_to_be32() does nothing on BE system, ioread32() returns BE,
but ioread32be() returns LE because of unconditional swab32(). Using *be
to get LE value... kinda weird. That's why we ended up with these two
functions.
Not a perfect solution, so it would be good to hear others opinions and
come to a more proper solution.
UPD. regmap looks like a pretty good solution for endianess stuff, but
it seems to interfere with current register handling (using struct
offsets as register addresses). So it has to be a big work.
For example, Realtek solves this issue that way -
https://github.com/jameywine/GPL-for-GP3000/blob/5090fbcb6ba743dd7b1314811ef557bad0460147/linux-5.10.x/drivers/usb/host/ehci.h#L742
>
> and yes, your patch does trigger sparse warnings:
> ../drivers/phy/realtek/phy-rtk-usb2.c:153:16: warning: cast to restricted __le32
> ../drivers/phy/realtek/phy-rtk-usb2.c:163:16: warning: incorrect type in argument 1 (different base types)
> ../drivers/phy/realtek/phy-rtk-usb2.c:163:16: expected unsigned int val
> ../drivers/phy/realtek/phy-rtk-usb2.c:163:16: got restricted __le32 [usertype]
>
> Furthermore, please drop the 'inline' keyword from C files and let the
> compiler decide. Your use of this keyword has no value - you declare
> phy_read(), phy_read_le() etc as inline but then assign function
> pointers to them. How can the compiler inline the indirect calls?
Thanks for all other review comments, going to be fixed in next patch
series version.
^ permalink raw reply
* Re: [PATCH v2 6/6] phy: realtek: usb2: Make configs available for MACH_REALTEK_RTL
From: Rustam Adilov @ 2026-03-31 16:48 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel
In-Reply-To: <20260330215207.stx6qbjr7kctm4xt@skbuf>
On 2026-03-30 21:52, Vladimir Oltean wrote:
> On Fri, Mar 27, 2026 at 09:06:38PM +0500, Rustam Adilov wrote:
>> Add the MACH_REALTEK_RTL to the if statement to make the config
>> options available for Realtek RTL SoCs as well.
>>
>> Signed-off-by: Rustam Adilov <adilov@disroot.org>
>> ---
>> drivers/phy/realtek/Kconfig | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/phy/realtek/Kconfig b/drivers/phy/realtek/Kconfig
>> index 75ac7e7c31ae..f9eadffacd18 100644
>> --- a/drivers/phy/realtek/Kconfig
>> +++ b/drivers/phy/realtek/Kconfig
>> @@ -3,7 +3,7 @@
>> # Phy drivers for Realtek platforms
>> #
>>
>> -if ARCH_REALTEK || COMPILE_TEST
>> +if ARCH_REALTEK || MACH_REALTEK_RTL || COMPILE_TEST
>>
>> config PHY_RTK_RTD_USB2PHY
>> tristate "Realtek RTD USB2 PHY Transceiver Driver"
>> --
>> 2.53.0
>>
>>
>
> The file now reads:
>
> if ARCH_REALTEK || MACH_REALTEK_RTL || COMPILE_TEST
>
> ...
>
> endif # ARCH_REALTEK || COMPILE_TEST
>
> Please update the end comment as well.
Good notice, will change it.
^ permalink raw reply
* Re: [PATCH v2 5/6] phy: realtek: usb2: add support for RTL9607C USB2 PHY
From: Rustam Adilov @ 2026-03-31 16:48 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel,
Michael Zavertkin
In-Reply-To: <20260330215033.ven3bllyw3jverfg@skbuf>
On 2026-03-30 21:50, Vladimir Oltean wrote:
> On Fri, Mar 27, 2026 at 09:06:37PM +0500, Rustam Adilov wrote:
>> Add support for the usb2 phy of RTL9607C series based SoCs.
>> Add the macros and phy config struct for rtl9607.
>>
>> RTL9607C requires to clear a "force host disconnect" bit in the
>> specific register (which is at an offset from reg_wrap_vstatus)
>> before proceeding with phy parameter writes.
>>
>> Add the bool variable to the driver data struct and hide this whole
>> procedure under the if statement that checks this new variable.
>>
>> Co-developed-by: Michael Zavertkin <misha.zavertkin@mail.ru>
>> Signed-off-by: Michael Zavertkin <misha.zavertkin@mail.ru>
>> Signed-off-by: Rustam Adilov <adilov@disroot.org>
>> ---
>> drivers/phy/realtek/phy-rtk-usb2.c | 57 ++++++++++++++++++++++++++++++
>> 1 file changed, 57 insertions(+)
>>
>> diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c
>> index 070cba1e0e0a..bf22d12681dc 100644
>> --- a/drivers/phy/realtek/phy-rtk-usb2.c
>> +++ b/drivers/phy/realtek/phy-rtk-usb2.c
>> @@ -26,6 +26,12 @@
>> #define PHY_VCTRL_SHIFT 8
>> #define PHY_REG_DATA_MASK 0xff
>>
>> +#define PHY_9607_VSTS_BUSY BIT(17)
>> +#define PHY_9607_NEW_REG_REQ BIT(13)
>> +
>> +#define PHY_9607_FORCE_DISCONNECT_REG 0x10
>> +#define PHY_9607_FORCE_DISCONNECT_BIT BIT(5)
>> +
>> #define GET_LOW_NIBBLE(addr) ((addr) & 0x0f)
>> #define GET_HIGH_NIBBLE(addr) (((addr) & 0xf0) >> 4)
>>
>> @@ -109,6 +115,7 @@ struct phy_cfg {
>>
>> u32 (*read)(void __iomem *reg);
>> void (*write)(u32 val, void __iomem *reg);
>> + bool force_host_disconnect;
>> };
>>
>> struct phy_parameter {
>> @@ -614,6 +621,16 @@ static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
>> goto do_toggle;
>> }
>>
>> + if (phy_cfg->force_host_disconnect) {
>> + /* disable force-host-disconnect */
>> + u32 temp = readl(phy_reg->reg_wrap_vstatus + PHY_9607_FORCE_DISCONNECT_REG);
>> +
>> + temp &= ~PHY_9607_FORCE_DISCONNECT_BIT;
>> + writel(temp, phy_reg->reg_wrap_vstatus + PHY_9607_FORCE_DISCONNECT_REG);
>> +
>> + mdelay(10);
>
> LLM review:
>
> Could we use msleep(10) or usleep_range(10000, 11000) here instead of
> mdelay(10)?
> Since do_rtk_phy_init() executes as part of the phy_ops->init callback
> with a mutex held from a sleepable process context, spinning the CPU for
> 10ms wastes CPU resources and increases scheduling latency.
I can change it to msleep instead.
>> + }
>> +
>> /* Set page 0 */
>> phy_data_page = phy_cfg->page0;
>> rtk_phy_set_page(phy_reg, 0);
>> @@ -1141,6 +1158,7 @@ static const struct phy_cfg rtd1295_phy_cfg = {
>> .new_reg_req = PHY_NEW_REG_REQ,
>> .read = phy_read,
>> .write = phy_write,
>> + .force_host_disconnect = false,
>
> You don't need to initialize rodata struct fields with false/0/NULL.
From what i can see, it lines up with other phy_cfg structs, and thats how they
did it and it did get accepted. You can check the rtd1295_phy_cfg as an example.
I am personally fine with removing the "force_host_disconnect = false" and other
falses in rtl9607_phy_cfg but i am debating because it wouldn't line up with the rest.
>> };
>>
>> static const struct phy_cfg rtd1395_phy_cfg = {
>> @@ -1170,6 +1188,7 @@ static const struct phy_cfg rtd1395_phy_cfg = {
>> .new_reg_req = PHY_NEW_REG_REQ,
>> .read = phy_read,
>> .write = phy_write,
>> + .force_host_disconnect = false,
>> };
>>
>> static const struct phy_cfg rtd1395_phy_cfg_2port = {
>> @@ -1199,6 +1218,7 @@ static const struct phy_cfg rtd1395_phy_cfg_2port = {
>> .new_reg_req = PHY_NEW_REG_REQ,
>> .read = phy_read,
>> .write = phy_write,
>> + .force_host_disconnect = false,
>> };
>>
>> static const struct phy_cfg rtd1619_phy_cfg = {
>> @@ -1226,6 +1246,7 @@ static const struct phy_cfg rtd1619_phy_cfg = {
>> .new_reg_req = PHY_NEW_REG_REQ,
>> .read = phy_read,
>> .write = phy_write,
>> + .force_host_disconnect = false,
>> };
>>
>> static const struct phy_cfg rtd1319_phy_cfg = {
>> @@ -1257,6 +1278,7 @@ static const struct phy_cfg rtd1319_phy_cfg = {
>> .new_reg_req = PHY_NEW_REG_REQ,
>> .read = phy_read,
>> .write = phy_write,
>> + .force_host_disconnect = false,
>> };
>>
>> static const struct phy_cfg rtd1312c_phy_cfg = {
>> @@ -1287,6 +1309,7 @@ static const struct phy_cfg rtd1312c_phy_cfg = {
>> .new_reg_req = PHY_NEW_REG_REQ,
>> .read = phy_read,
>> .write = phy_write,
>> + .force_host_disconnect = false,
>> };
>>
>> static const struct phy_cfg rtd1619b_phy_cfg = {
>> @@ -1317,6 +1340,7 @@ static const struct phy_cfg rtd1619b_phy_cfg = {
>> .new_reg_req = PHY_NEW_REG_REQ,
>> .read = phy_read,
>> .write = phy_write,
>> + .force_host_disconnect = false,
>> };
>>
>> static const struct phy_cfg rtd1319d_phy_cfg = {
>> @@ -1347,6 +1371,7 @@ static const struct phy_cfg rtd1319d_phy_cfg = {
>> .new_reg_req = PHY_NEW_REG_REQ,
>> .read = phy_read,
>> .write = phy_write,
>> + .force_host_disconnect = false,
>> };
>>
>> static const struct phy_cfg rtd1315e_phy_cfg = {
>> @@ -1378,6 +1403,37 @@ static const struct phy_cfg rtd1315e_phy_cfg = {
>> .new_reg_req = PHY_NEW_REG_REQ,
>> .read = phy_read,
>> .write = phy_write,
>> + .force_host_disconnect = false,
>> +};
>> +
>> +static const struct phy_cfg rtl9607_phy_cfg = {
>> + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
>> + .page0 = { [0] = {0xe0, 0x95},
>> + [4] = {0xe4, 0x6a},
>> + [12] = {0xf3, 0x31}, },
>> + .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE,
>> + .page1 = { [0] = {0xe0, 0x26}, },
>> + .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
>> + .page2 = { [7] = {0xe7, 0x33}, },
>> + .num_phy = 1,
>> + .check_efuse = false,
>
> Similar for these (+do_toggle_driving, use_default_parameter).
>
>> + .check_efuse_version = CHECK_EFUSE_V2,
>> + .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
>> + .dc_driving_mask = 0x1f,
>> + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
>> + .dc_disconnect_mask = 0xf,
>> + .usb_dc_disconnect_at_page0 = true,
>> + .do_toggle = true,
>> + .do_toggle_driving = false,
>> + .driving_updated_for_dev_dis = 0x8,
>> + .use_default_parameter = false,
>> + .is_double_sensitivity_mode = true,
>> + .vstatus_offset = 0xc,
>> + .vstatus_busy = PHY_9607_VSTS_BUSY,
>> + .new_reg_req = PHY_9607_NEW_REG_REQ,
>> + .read = phy_read_le,
>> + .write = phy_write_le,
>> + .force_host_disconnect = true,
>> };
>>
>> static const struct of_device_id usbphy_rtk_dt_match[] = {
>> @@ -1390,6 +1446,7 @@ static const struct of_device_id usbphy_rtk_dt_match[] = {
>> { .compatible = "realtek,rtd1395-usb2phy-2port", .data = &rtd1395_phy_cfg_2port },
>> { .compatible = "realtek,rtd1619-usb2phy", .data = &rtd1619_phy_cfg },
>> { .compatible = "realtek,rtd1619b-usb2phy", .data = &rtd1619b_phy_cfg },
>> + { .compatible = "realtek,rtl9607-usb2phy", .data = &rtl9607_phy_cfg },
>> {},
>> };
>> MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match);
>> --
>> 2.53.0
>>
>>
^ permalink raw reply
* Re: [PATCH v5 0/2] Add support for Texas Instruments INA4230 power monitor
From: Alexey Charkov @ 2026-03-31 16:46 UTC (permalink / raw)
To: Guenter Roeck
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-hwmon,
devicetree, linux-kernel, Krzysztof Kozlowski
In-Reply-To: <20872ef8-f68c-4916-a05f-404fd49fff00@roeck-us.net>
On Tue, Mar 31, 2026 at 8:10 PM Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 3/31/26 08:52, Rob Herring wrote:
> > On Mon, Mar 30, 2026 at 09:07:32AM -0700, Guenter Roeck wrote:
> >> On 3/30/26 08:14, Alexey Charkov wrote:
> >>> TI INA4230 is a 4-channel power monitor with I2C interface, similar in
> >>> operation to INA3221 (3-channel) and INA219 (single-channel) but with
> >>> a different register layout, different alerting mechanism and slightly
> >>> different support for directly reading calculated current/power/energy
> >>> values (pre-multiplied by the device itself and needing only to be scaled
> >>> by the driver depending on its selected LSB unit values).
> >>>
> >>> In this initial implementation, the driver supports reading voltage,
> >>> current, power and energy values, but does not yet support alerts, which
> >>> can be added separately if needed. Also the overflows during hardware
> >>> calculations are not yet handled, nor is the support for the device's
> >>> internal 32-bit energy counter reset.
> >>>
> >>> An example device tree using this binding and driver is available at [1]
> >>> (not currently upstreamed, as the device in question is in engineering
> >>> phase and not yet publicly available)
> >>>
> >>> [1] https://github.com/flipperdevices/flipper-linux-kernel/blob/flipper-devel/arch/arm64/boot/dts/rockchip/rk3576-flipper-one-rev-f0b0c1.dts
> >>>
> >>> Signed-off-by: Alexey Charkov <alchark@flipper.net>
> >>> ---
> >>> Changes in v5:
> >>> - Reworded per-channel subnodes description in the binding for clarity (Sashiko)
> >>> - NB: Sashiko's suggestion to allow interrupts in the binding sounds premature,
> >>> as the alerts mechanism is not implemented yet and there are no known users
> >>> to test it. If anyone has hardware with the alert pins wired to an interrupt
> >>> line - please shout and we can test/extend it together
> >>
> >> The bindings are supposed to be complete, even if not implemented, so I am not sure
> >> if the DT maintainers will agree here. We'll see.
> >
> > Given ti,alert-polarity-active-high is added seems like the interrupt
> > should be too. And the interrupt can specify the polarity, so is that
> > property really needed? There's alway the possibility that you have some
> > inverter on the board too and the interrupt polarity is not enough, but
> > solve that problem when it actually exists.
> >
>
> The alert pin can be attached to a board interrupt, or (more likely) it can
> be attached to the I2C controller's alert pin. In the latter case there is
> no interrupt property.
Alright, I will add the interrupt property and keep the dedicated flag
for alert polarity.
Following the logic of binding completeness, should I add a flag for
the single-shot mode too, even though I dropped that functionality
from the driver in one of the prior iterations?
Thanks a lot,
Alexey
^ permalink raw reply
* Re: [PATCH v9 5/6] reset: rzv2h-usb2phy: Convert to regmap API
From: Philipp Zabel @ 2026-03-31 16:36 UTC (permalink / raw)
To: Tommaso Merciai, tomm.merciai, peda
Cc: linux-renesas-soc, biju.das.jz, Fabrizio Castro, Lad Prabhakar,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Greg Kroah-Hartman, Josua Mayer,
Ulf Hansson, devicetree, linux-kernel
In-Reply-To: <0259040014396ea03d58a87c2ce2a3f9eff2b0b6.1774601289.git.tommaso.merciai.xr@bp.renesas.com>
On Fr, 2026-03-27 at 19:08 +0100, Tommaso Merciai wrote:
> Replace raw MMIO accesses (void __iomem *, readl/writel) with
> regmap_read/regmap_write via devm_regmap_init_mmio(). Regmap
> provides its own internal locking, so the manual spinlock and
> scoped_guard() wrappers are no longer needed.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
> v8->v9:
> - New patch
>
> drivers/reset/Kconfig | 1 +
> drivers/reset/reset-rzv2h-usb2phy.c | 42 ++++++++++++++++-------------
> 2 files changed, 24 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index 5165006be693..c539ca88518f 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -257,6 +257,7 @@ config RESET_RZG2L_USBPHY_CTRL
> config RESET_RZV2H_USB2PHY
> tristate "Renesas RZ/V2H(P) (and similar SoCs) USB2PHY Reset driver"
> depends on ARCH_RENESAS || COMPILE_TEST
> + select REGMAP_MMIO
> help
> Support for USB2PHY Port reset Control found on the RZ/V2H(P) SoC
> (and similar SoCs).
> diff --git a/drivers/reset/reset-rzv2h-usb2phy.c b/drivers/reset/reset-rzv2h-usb2phy.c
> index 5bdd39274612..4014eff0f017 100644
> --- a/drivers/reset/reset-rzv2h-usb2phy.c
> +++ b/drivers/reset/reset-rzv2h-usb2phy.c
> @@ -5,13 +5,13 @@
> * Copyright (C) 2025 Renesas Electronics Corporation
> */
>
> -#include <linux/cleanup.h>
> #include <linux/delay.h>
> #include <linux/io.h>
> #include <linux/module.h>
> #include <linux/of.h>
> #include <linux/platform_device.h>
> #include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> #include <linux/reset.h>
> #include <linux/reset-controller.h>
>
> @@ -37,10 +37,9 @@ struct rzv2h_usb2phy_reset_of_data {
>
> struct rzv2h_usb2phy_reset_priv {
> const struct rzv2h_usb2phy_reset_of_data *data;
> - void __iomem *base;
> + struct regmap *regmap;
> struct device *dev;
> struct reset_controller_dev rcdev;
> - spinlock_t lock; /* protects register accesses */
> };
>
> static inline struct rzv2h_usb2phy_reset_priv
> @@ -55,10 +54,8 @@ static int rzv2h_usbphy_reset_assert(struct reset_controller_dev *rcdev,
> struct rzv2h_usb2phy_reset_priv *priv = rzv2h_usbphy_rcdev_to_priv(rcdev);
> const struct rzv2h_usb2phy_reset_of_data *data = priv->data;
>
> - scoped_guard(spinlock, &priv->lock) {
> - writel(data->reset2_acquire_val, priv->base + data->reset2_reg);
> - writel(data->reset_assert_val, priv->base + data->reset_reg);
> - }
> + regmap_write(priv->regmap, data->reset2_reg, data->reset2_acquire_val);
> + regmap_write(priv->regmap, data->reset_reg, data->reset_assert_val);
What is the spinlock protecting? acquire/assert registers being set
together, without another acquire/assert or deassert/release register
access pair interleaving?
In that case you still need the lock. Or use regmap_multi_reg_write().
You could even directly store the sequences as struct reg_sequence in
rzv2h_usb2phy_reset_of_data.
> usleep_range(11, 20);
>
> @@ -71,11 +68,9 @@ static int rzv2h_usbphy_reset_deassert(struct reset_controller_dev *rcdev,
> struct rzv2h_usb2phy_reset_priv *priv = rzv2h_usbphy_rcdev_to_priv(rcdev);
> const struct rzv2h_usb2phy_reset_of_data *data = priv->data;
>
> - scoped_guard(spinlock, &priv->lock) {
> - writel(data->reset_deassert_val, priv->base + data->reset_reg);
> - writel(data->reset2_release_val, priv->base + data->reset2_reg);
> - writel(data->reset_release_val, priv->base + data->reset_reg);
> - }
> + regmap_write(priv->regmap, data->reset_reg, data->reset_deassert_val);
> + regmap_write(priv->regmap, data->reset2_reg, data->reset2_release_val);
> + regmap_write(priv->regmap, data->reset_reg, data->reset_release_val);
Same as above.
[...]
> @@ -149,7 +153,7 @@ static int rzv2h_usb2phy_reset_probe(struct platform_device *pdev)
> return dev_err_probe(dev, error, "unable to register cleanup action\n");
>
> for (unsigned int i = 0; i < data->init_val_count; i++)
> - writel(data->init_vals[i].val, priv->base + data->init_vals[i].reg);
> + regmap_write(priv->regmap, data->init_vals[i].reg, data->init_vals[i].val);
Not required for locking, but this could use regmap_multi_reg_write()
as well.
regards
Philipp
^ permalink raw reply
* Re: [PATCH v2 4/6] phy: realtek: usb2: introduce reset controller struct
From: Rustam Adilov @ 2026-03-31 16:35 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel,
Michael Zavertkin
In-Reply-To: <20260330213955.udqpa77ek7n4arsq@skbuf>
On 2026-03-30 21:39, Vladimir Oltean wrote:
> On Fri, Mar 27, 2026 at 09:06:36PM +0500, Rustam Adilov wrote:
>> In RTL9607C, there is so called "IP Enable Controller" which resemble
>> reset controller with reset lines and is used for various things like
>> USB, PCIE, GMAC and such.
>>
>> Introduce the reset_control struct to this driver to handle deasserting
>> usb2 phy reset line.
>>
>> Make use of the function devm_reset_control_array_get_optional_exclusive()
>> function to get the reset controller and since existing RTD SoCs don't
>> specify the resets we can have a cleaner code.
>>
>> Co-developed-by: Michael Zavertkin <misha.zavertkin@mail.ru>
>> Signed-off-by: Michael Zavertkin <misha.zavertkin@mail.ru>
>> Signed-off-by: Rustam Adilov <adilov@disroot.org>
>> ---
>> drivers/phy/realtek/phy-rtk-usb2.c | 12 ++++++++++++
>> 1 file changed, 12 insertions(+)
>>
>> diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c
>> index e65b8525b88b..070cba1e0e0a 100644
>> --- a/drivers/phy/realtek/phy-rtk-usb2.c
>> +++ b/drivers/phy/realtek/phy-rtk-usb2.c
>> @@ -17,6 +17,7 @@
>> #include <linux/sys_soc.h>
>> #include <linux/mfd/syscon.h>
>> #include <linux/phy/phy.h>
>> +#include <linux/reset.h>
>> #include <linux/usb.h>
>>
>> /* GUSB2PHYACCn register */
>> @@ -130,6 +131,7 @@ struct rtk_phy {
>> struct phy_cfg *phy_cfg;
>> int num_phy;
>> struct phy_parameter *phy_parameter;
>> + struct reset_control *phy_rst;
>>
>> struct dentry *debug_dir;
>> };
>> @@ -602,6 +604,10 @@ static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
>> phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
>> phy_reg = &phy_parameter->phy_reg;
>>
>> + reset_control_deassert(rtk_phy->phy_rst);
>
> LLM review says:
>
> (less important)
> Can reset_control_deassert() fail here? If there is a hardware communication
> error with the reset controller, should this check the return value and
> propagate the error up instead of proceeding to configure the PHY?
> Additionally, since the exclusive reset line is deasserted here, does this
> code need a corresponding reset_control_assert() in the driver's teardown
> or exit path? Leaving the IP block permanently enabled after shutdown could
> lead to power leaks and prevent proper hardware re-initialization.
It realistically shouldn't fail. But I can add the return error for this.
And no, it doesn't need the reset_control_assert.
>> +
>> + mdelay(5);
>
> (more important)
> This code unnecessarily penalizes existing platforms. If rtk_phy->phy_rst
> is NULL (as on older platforms where the optional reset is not defined), the
> delay still executes.
>
> Also, since PHY initialization callbacks run in a sleepable context, would it
> be better to use a sleep-based delay like usleep_range(5000, 6000) to yield
> the CPU instead of busy-waiting with mdelay(5)?
I can change mdelay to msleep and wrap it around something like if (rtk_phy->phy_rst).
>> +
>> if (phy_cfg->use_default_parameter) {
>> dev_dbg(rtk_phy->dev, "%s phy#%d use default parameter\n",
>> __func__, index);
>> @@ -1069,6 +1075,12 @@ static int rtk_usb2phy_probe(struct platform_device *pdev)
>>
>> rtk_phy->num_phy = phy_cfg->num_phy;
>>
>> + rtk_phy->phy_rst = devm_reset_control_array_get_optional_exclusive(dev);
>> + if (IS_ERR(rtk_phy->phy_rst)) {
>> + dev_err(dev, "usb2 phy resets are not working\n");
>> + return PTR_ERR(rtk_phy->phy_rst);
>> + }
>> +
>
> (still LLM review)
> If the reset controller driver is not yet ready, this will return
> -EPROBE_DEFER and print an error message to the kernel log.
> Should this use dev_err_probe() to silently handle probe deferral while
> correctly logging actual errors?
I can change it to dev_err_probe, no problem with that.
>> ret = parse_phy_data(rtk_phy);
>> if (ret)
>> goto err;
>> --
>> 2.53.0
>>
>>
^ permalink raw reply
* Re: [PATCH v6 3/3] arm64: dts: qcom: Add Samsung Galaxy Book4 Edge DTS/DTSI
From: Maxim Storetvedt @ 2026-03-31 16:34 UTC (permalink / raw)
To: Konrad Dybcio, andersson, robh, krzk+dt, conor+dt
Cc: marcus, marijn.suijten, linux-arm-msm, devicetree, linux-kernel,
abel.vesa, abel.vesa, johan, konradybcio, kirill
In-Reply-To: <12ee3569-16a6-4787-a874-bc802a50175f@oss.qualcomm.com>
On 3/30/26 12:41, Konrad Dybcio wrote:
> On 3/26/26 7:30 PM, Maxim Storetvedt wrote:
>>
>>
>> On 3/26/26 12:33, Konrad Dybcio wrote:
>>> On 3/25/26 7:30 PM, Maxim Storetvedt wrote:
>>>>
>>>>
>>>> On 3/23/26 13:17, Konrad Dybcio wrote:
>>>>> On 3/22/26 5:03 PM, Maxim Storetvedt wrote:
>>>>>> Adds devicetrees for the 14-inch and 16-inch SKUs of the Samsung Galaxy Book4 Edge.
>>>>>>
>>>>>> These use a common dtsi derived from nodes that were able to work on Linux
>>>>>> from the initial Galaxy Book4 Edge DTS by Marcus:
>>>>>>
>>>>>> Link: https://lore.kernel.org/all/p3mhtj2rp6y2ezuwpd2gu7dwx5cbckfu4s4pazcudi4j2wogtr@4yecb2bkeyms/
>>>>>>
>>>>>> combined with the ongoing patch for the Honor Magicbook Art 14, and its downstream by
>>>>>> Valentin Manea, which shares device similarities:
>>>>>
>>>>> [...]
>>>>>
>>>>>> +&i2c8 {
>>>>>> + clock-frequency = <400000>;
>>>>>> +
>>>>>> + status = "okay";
>>>>>> +
>>>>>> + touchscreen@5d {
>>>>>> + compatible = "hid-over-i2c";
>>>>>> + reg = <0x5d>;
>>>>>> +
>>>>>> + hid-descr-addr = <0x1>;
>>>>>> + interrupts-extended = <&tlmm 34 IRQ_TYPE_LEVEL_LOW>;
>>>>>> +
>>>>>> + vdd-supply = <&vreg_misc_3p3>;
>>>>>> + /* Lower power supply is not enoug to work. */
>>>>>> + // vddl-supply = <&vreg_l15b_1p8>;
>>>>>
>>>>> How should we interpret that?
>>>>>
>>>>
>>>> This was in the original patch, but using that same regulator appears to
>>>> be enough to also get touchscreen working on the 16" book4e. That said,
>>>> it still does not work on the 14". Something to revisit later...
>>>>
>>>>>
>>>>> [...]
>>>>>
>>>>>> +&panel {
>>>>>> + compatible = "samsung,atna40cu07", "samsung,atna33xc20";
>>>>>
>>>>> I think it'd make sense to move the compatible from 'common' to the
>>>>> 16in DTS then too
>>>>>
>>>>>> + enable-gpios = <&pmc8380_3_gpios 4 GPIO_ACTIVE_HIGH>;
>>>>>
>>>>> this matches the common definition
>>>>>
>>>>>> + power-supply = <&vreg_edp_3p3>;
>>>>>
>>>>> ditto
>>>>>
>>>>>> + no-hpd;
>>>>>
>>>>> really??
>>>>>
>>>> One less thing to debug while previously attempting to work around the
>>>> "illegal link rate" error, which turned out to be related to eDP 1.4
>>>> (similar to the sp11). I've kept it as-is in case other SKUs attempt
>>>> booting from this dts, such as the x1e80100 16" (as it might be getting
>>>> a black screen using the current x1e84100 16" dts, though this is not
>>>> fully tested).
>>>
>>> So do the 80100 and 84100-equipped SKUs of the laptop come with different
>>> displays?
>>>
>>> Konrad
>>
>> So far assumed both 16" variants to be fairly similar, though one
>> valiant 16" 80100 user over in the debug thread did try to boot via the
>> 84100 dts, with no success. Instead having the screen go dark after the
>> first post-tux kernel prints.
>
> Does switching to the generic edp-panel compatible (which will parse the
> EDID and try not to be overly smart about it) help here?
>
>> This was strapped together via WSL though, so could be there was
>> something else at fault, but strange it didn't at least fall back to a
>> visible initramfs shell.
>
> You mean the kernel had been compiled via WSL? That shouldn't be a problem..
>
> Konrad
Kernel was one shared by me in advance (same I've been using as a
daily), so it should be OK, but there was an uphill battle in creating
the modified system image afaik (that would boot).
Can only speculate until there is another go at this, but could likewise
be something completely unrelated that's simple to fix, e.g. older mesa
in image, but final attempt at boot used a dts with gpu node enabled.
Cheers,
-Max
^ permalink raw reply
* Re: [PATCH v6 6/9] dt-bindings: connector: m2: Add M.2 1620 LGA soldered down connector
From: Stephan Gerhold @ 2026-03-31 16:29 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Mark Pearson, Dmitry Baryshkov, Rob Herring,
Manivannan Sadhasivam, Greg KH, Jiri Slaby, Nathan Chancellor,
Nicolas Schier, Hans de Goede, Ilpo Järvinen,
Derek J . Clark, Krzysztof Kozlowski, Conor Dooley,
Marcel Holtmann, Luiz Augusto von Dentz, Bartosz Golaszewski,
Andy Shevchenko, Bartosz Golaszewski, linux-serial, linux-kernel,
linux-kbuild, platform-driver-x86@vger.kernel.org, linux-pci,
devicetree, linux-arm-msm, linux-bluetooth, linux-pm,
linux-acpi@vger.kernel.org
In-Reply-To: <cvqdbqnzjmzoowxkvz2lyv4avropu5jw7h2r6zng3ecf245hgg@fsysjqflqd35>
On Wed, Mar 25, 2026 at 05:36:08PM +0530, Manivannan Sadhasivam wrote:
> On Mon, Mar 23, 2026 at 01:23:07PM -0400, Mark Pearson wrote:
> > On Mon, Mar 23, 2026, at 12:52 PM, Manivannan Sadhasivam wrote:
> > > On Mon, Mar 23, 2026 at 06:45:15PM +0200, Dmitry Baryshkov wrote:
> > >> On Mon, Mar 23, 2026 at 09:26:04PM +0530, Manivannan Sadhasivam wrote:
> > >> > On Mon, Mar 23, 2026 at 05:14:30PM +0200, Dmitry Baryshkov wrote:
> > >> > > On Mon, Mar 23, 2026 at 07:14:25PM +0530, Manivannan Sadhasivam wrote:
> > >> > > > On Mon, Mar 23, 2026 at 08:39:55AM -0500, Rob Herring wrote:
> > >> > > > > On Mon, Mar 23, 2026 at 7:16 AM Manivannan Sadhasivam <mani@kernel.org> wrote:
> > >> > > > > >
> > >> > > > > > On Sun, Mar 22, 2026 at 06:37:13PM -0500, Rob Herring wrote:
> > >> > > > > > > On Tue, Mar 17, 2026 at 09:59:56AM +0530, Manivannan Sadhasivam wrote:
> > >> > > > > > > > Lenovo Thinkpad T14s is found to have a soldered down version of M.2 1620
> > >> > > > > > > > LGA connector. Though, there is no 1620 LGA form factor defined in the M.2
> > >> > > > > > > > spec, it looks very similar to the M.2 Key E connector. So add the
> > >> > > > > > > > "pcie-m2-1620-lga-connector" compatible with "pcie-m2-e-connector" fallback
> > >> > > > > > > > to reuse the Key E binding.
> > >> > > > > > >
> > >> > > > > > > What is LGA?
> > >> > > > > > >
> > >> > > > > >
> > >> > > > > > Land Grid Array
> > >> > > > > >
> > >> > > > > > > If not in the spec, is it really something generic?
> > >> > > > > > >
> > >> > > > > >
> > >> > > > > > Good question. Yes and No! LGA is not something that Lenovo only uses. Other
> > >> > > > > > vendors may also use this form factor. PCIe connectors are full of innovation as
> > >> > > > > > the spec gives room for hardware designers to be as innovative as possible to
> > >> > > > > > save the BOM cost.
> > >> > > > >
> > >> > > > > innovation == incompatible changes
> > >> > > > >
> > >> > > >
> > >> > > > Yes, I was trying to sound nice :)
> > >> > > >
> > >> > > > > > This is why I do not want to make it Lenovo specific. But if you prefer that, I
> > >> > > > > > can name it as "lenovo,pcie-m2-1620-lga-connector".
> > >> > > > >
> > >> > > > > Depends if you think that s/w needs to know the differences. Hard to
> > >> > > > > say with a sample size of 1.
> > >> > > > >
> > >> > > >
> > >> > > > Sure. Will add the 'lenovo' prefix then.
> > >> > >
> > >> > > Is it really Lenovo? Or is it some other module vendor, whose LGAs are
> > >> > > being used by Lenovo?
> > >> > >
> > >> > > I remember that DB820c also used some kind of a module for the WiFi card
> > >> > > (which might be M.2 compatible or might not, I can't find exact docs at
> > >> > > this point).
> > >> > >
> > >> >
> > >> > I don't know. These kind of designs might be reused by several vendors. But
> > >> > considering that we should not make it generic, I'd go with Lenovo as that's
> > >> > the only vendor we know as of now.
> > >>
> > >> ... and later we learn that other vendors use the same idea /pinout,
> > >> then nothing stops us from still telling that it's a
> > >> "lenovo,pcie-m2-something-lga".
> > >>
> > >
> > > How do you possibly know whether a single vendor has introduced this form factor
> > > or reused by multiple ones? Atleast, I don't have access to such a source to
> > > confirm.
> > >
> > I've not really been following this thread/patchset in detail; but want me to try and check with the T14s platform team if this device is specifically made for us (Lenovo) or not?
> > I doubt it is - we just don't do that usually, but I can go and ask the question if it will help resolve this (with the caveat that it could hold up the review for a bit and I may not be able to get a straight answer)
> >
>
> I can drop this specific patch in the meantime.
>
> > My vote (for what little it's worth) would be to make it non-Lenovo specific. Then when the same part causes issues on another vendors platform I won't get asked questions about why Lenovo is breaking <other vendor> :)
> >
>
> Even if Lenovo prefix is used, it won't break other vendors. Just that we will
> end up adding more compatibles.
>
> Anyhow, I'll wait for your reply and drop this patch for next revision.
>
If you need a vendor prefix, I think "qcom," would be more appropriate
than Lenovo. This form factor is used by most vendors for recent
soldered Qualcomm-based wireless cards, not just Lenovo:
- Dell XPS 13 9345 has exactly the same soldered M.2 card, I assume
there are several other vendors as well.
- https://www.sparklan.com/product/wnsq-290be/ is a third-party
(Qualcomm-based) M.2 LGA 1620 card, in the block diagram the
pinout is called "QM.2 1620 LGA 168pin".
- If you press F9 while booting the ThinkPad T14s, you should get to a
screen with "Regulatory Information". For the T14s, this screen says
"Contains FCC ID: J9C-QCNCM825". This is the WiFi/BT module in the
soldered form factor. If you look that up on the FCC website, the
applicant for this module is "Qualcomm Technologies, Inc.". This
seems to be some kind of "modular certification" that vendors can
reuse/adapt without going through the whole process again.
Perhaps you should ask around inside Qualcomm? :-)
Thanks,
Stephan
^ permalink raw reply
* [PATCH v4 1/3] riscv: dts: spacemit: Enable i2c8 adapter for OrangePi RV2
From: Han Gao @ 2026-03-31 16:27 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Yixun Lan, Chukun Pan
Cc: devicetree, linux-riscv, spacemit, linux-kernel, Han Gao, Han Gao
In-Reply-To: <cover.1774974017.git.gaohan@iscas.ac.cn>
The adapter is used to access the SpacemiT P1 PMIC present in this board.
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
---
arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
index 7b7331cb3c72..93880ba7bdfe 100644
--- a/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
@@ -87,6 +87,12 @@ &pdma {
status = "okay";
};
+&i2c8 {
+ pinctrl-0 = <&i2c8_cfg>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_2_cfg>;
--
2.47.3
^ permalink raw reply related
* [PATCH v4 2/3] riscv: dts: spacemit: Define the P1 PMIC regulators for OrangePi RV2
From: Han Gao @ 2026-03-31 16:27 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Yixun Lan, Chukun Pan
Cc: devicetree, linux-riscv, spacemit, linux-kernel, Han Gao, Han Gao
In-Reply-To: <cover.1774974017.git.gaohan@iscas.ac.cn>
Define the DC power input and the 4v power as fixed regulator supplies.
Define the SpacemiT P1 PMIC voltage regulators and their constraints.
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
---
.../boot/dts/spacemit/k1-orangepi-rv2.dts | 97 +++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
index 93880ba7bdfe..e5e358d49c09 100644
--- a/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
@@ -23,6 +23,15 @@ chosen {
stdout-path = "serial0";
};
+ reg_vcc_4v: regulator-vcc-4v {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc4v0";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <4000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
leds {
compatible = "gpio-leds";
@@ -91,6 +100,94 @@ &i2c8 {
pinctrl-0 = <&i2c8_cfg>;
pinctrl-names = "default";
status = "okay";
+
+ pmic@41 {
+ compatible = "spacemit,p1";
+ reg = <0x41>;
+ interrupts = <64>;
+ vin1-supply = <®_vcc_4v>;
+ vin2-supply = <®_vcc_4v>;
+ vin3-supply = <®_vcc_4v>;
+ vin4-supply = <®_vcc_4v>;
+ vin5-supply = <®_vcc_4v>;
+ vin6-supply = <®_vcc_4v>;
+ aldoin-supply = <®_vcc_4v>;
+ dldoin1-supply = <&buck5>;
+ dldoin2-supply = <&buck5>;
+
+ regulators {
+ buck1 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3450000>;
+ regulator-ramp-delay = <5000>;
+ regulator-always-on;
+ };
+
+ buck2 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3450000>;
+ regulator-ramp-delay = <5000>;
+ regulator-always-on;
+ };
+
+ buck3_1v8: buck3 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-ramp-delay = <5000>;
+ regulator-always-on;
+ };
+
+ buck4 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-ramp-delay = <5000>;
+ regulator-always-on;
+ };
+
+ buck5: buck5 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3450000>;
+ regulator-ramp-delay = <5000>;
+ regulator-always-on;
+ };
+
+ buck6 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3450000>;
+ regulator-ramp-delay = <5000>;
+ regulator-always-on;
+ };
+
+ aldo1 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ };
+
+ dldo1 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ };
+
+ dldo4 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-always-on;
+ };
+
+ dldo5 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3400000>;
+ };
+
+ dldo6 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-always-on;
+ };
+ };
+ };
};
&uart0 {
--
2.47.3
^ 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