* [PATCH] clk: sunxi-ng: div: implement set_rate_and_parent
From: Aureal @ 2026-07-19 15:31 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland
Cc: Brian Masney, linux-clk, linux-arm-kernel, linux-sunxi,
linux-kernel, Juan Manuel López Carrillo
From: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com>
When a rate change on a ccu_div clock also switches its parent, the
clk core, in the absence of a .set_rate_and_parent op, programs the
parent first and the divider second. If the new parent is faster than
the old one, the clock transiently runs at new_parent_rate/old_divider
between the two register writes, overshooting both the old and the
requested rate and potentially violating the consumer's maximum
allowed frequency.
This is not theoretical. On the Allwinner A523/T527 the GPU clock is
a ccu_div muxing between pll-gpu and the fixed pll-periph0 outputs:
going from 600 MHz (pll-periph0-600M, M=1) down to 400 or 200 MHz
(both derived from pll-periph0-800M) makes the Mali G57 run at 800 MHz
for the window between the two writes, 33% above the vendor's maximum
operating point. Observed and validated on an Orange Pi 4A (T527)
with a downstream GPU devfreq setup; mainline does not yet describe
GPU OPPs for this SoC, but any ccu_div consumer whose set_rate ends up
crossing parents is affected.
Implement .set_rate_and_parent with the same ordering rule as
clk_composite_set_rate_and_parent(): if keeping the current divider
while switching the mux would overshoot the requested rate, program
the divider first, otherwise switch the mux first. The intermediate
rate then never exceeds both the old and the new rate.
Clocks using a prediv feature keep the historical mux-then-divider
order: the prediv helpers look the prediv up by the current parent,
which is ambiguous while both are changing.
Fixes: e9b93213103f ("clk: sunxi-ng: Add divider")
Signed-off-by: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com>
---
Note: this touches the same area of ccu_div.c as patch 2/4 of the
pending series "clk: sun6i-rtc: Add support for Allwinner A733 SoC" v5
(<20260717-a733-rtc-v5-2-3874cc26abf7@baylibre.com>), which adds
ccu_rodiv_ops right after ccu_div_ops. The conflict is trivial
(context only); happy to rebase on top of it if it lands first.
drivers/clk/sunxi-ng/ccu_div.c | 36 ++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c
index 62d680ccb..9024bcd8c 100644
--- a/drivers/clk/sunxi-ng/ccu_div.c
+++ b/drivers/clk/sunxi-ng/ccu_div.c
@@ -130,6 +130,41 @@ static int ccu_div_set_parent(struct clk_hw *hw, u8 index)
return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index);
}
+static int ccu_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate, u8 index)
+{
+ struct ccu_div *cd = hw_to_ccu_div(hw);
+
+ /*
+ * The predivider helpers look it up through the current parent,
+ * which is ambiguous while both the parent and the divider are
+ * changing, so keep the mux-then-divider order the core would
+ * have used for those clocks.
+ */
+ if (cd->common.features & (CCU_FEATURE_VARIABLE_PREDIV |
+ CCU_FEATURE_FIXED_PREDIV |
+ CCU_FEATURE_ALL_PREDIV)) {
+ ccu_div_set_parent(hw, index);
+ return ccu_div_set_rate(hw, rate, parent_rate);
+ }
+
+ /*
+ * Same ordering rule as clk_composite_set_rate_and_parent(): if
+ * switching the mux with the current divider would overshoot the
+ * requested rate, program the divider first, so the intermediate
+ * rate never exceeds both the old and the new rate.
+ */
+ if (ccu_div_recalc_rate(hw, parent_rate) > rate) {
+ ccu_div_set_rate(hw, rate, parent_rate);
+ ccu_div_set_parent(hw, index);
+ } else {
+ ccu_div_set_parent(hw, index);
+ ccu_div_set_rate(hw, rate, parent_rate);
+ }
+
+ return 0;
+}
+
const struct clk_ops ccu_div_ops = {
.disable = ccu_div_disable,
.enable = ccu_div_enable,
@@ -141,5 +176,6 @@ const struct clk_ops ccu_div_ops = {
.determine_rate = ccu_div_determine_rate,
.recalc_rate = ccu_div_recalc_rate,
.set_rate = ccu_div_set_rate,
+ .set_rate_and_parent = ccu_div_set_rate_and_parent,
};
EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU");
base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
--
2.47.3
^ permalink raw reply related
* Re: [PATCH] mfd: macsmc: Fix key count endianness annotation
From: Joshua Peisach @ 2026-07-19 15:28 UTC (permalink / raw)
To: Sven Peter, Joshua Peisach
Cc: asahi, Janne Grunau, Lee Jones, Neal Gompa, linux-arm-kernel,
linux-kernel, kernel test robot
In-Reply-To: <07d37cf5-d49d-4507-82c8-7c6d8c9e01af@kernel.org>
On Sun Jul 19, 2026 at 11:15 AM EDT, Sven Peter wrote:
>
>
> On 7/19/26 17:02, Joshua Peisach wrote:
>> On Sun Jul 19, 2026 at 9:00 AM EDT, Sven Peter wrote:
>>> SMC firmware returns the value of the #KEY key in big-endian unlike most
>>> other keys. Reading it through apple_smc_read_u32() into a plain u32
>>> and then converting with be32_to_cpu() makes sparse complain:
>>>
>>> drivers/mfd/macsmc.c:462:26: sparse: cast to restricted __be32
>>>
>>> Read the raw value into a __be32 using apple_smc_read() instead.
>>>
>>> Fixes: e038d985c982 ("mfd: Add Apple Silicon System Management
>>> Controller")
>>> Reported-by: kernel test robot <lkp@intel.com>
>>> Closes:
>>> https://lore.kernel.org/oe-kbuild-all/202607181046.OANjIoqR-lkp@intel.com/
>>> Signed-off-by: Sven Peter <sven@kernel.org>
>>> ---
>>> drivers/mfd/macsmc.c | 8 +++++---
>>> 1 file changed, 5 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
>>> index 358feec2d088..514cba7dc897 100644
>>> --- a/drivers/mfd/macsmc.c
>>> +++ b/drivers/mfd/macsmc.c
>>> @@ -410,7 +410,7 @@ static int apple_smc_probe(struct platform_device
>>> *pdev)
>>> {
>>> struct device *dev = &pdev->dev;
>>> struct apple_smc *smc;
>>> - u32 count;
>>> + __be32 count;
>>> int ret;
>>>
>>> smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL);
>>> @@ -461,8 +461,10 @@ static int apple_smc_probe(struct
>>> platform_device *pdev)
>>> dev_set_drvdata(&pdev->dev, smc);
>>> BLOCKING_INIT_NOTIFIER_HEAD(&smc->event_handlers);
>>>
>>> - ret = apple_smc_read_u32(smc, SMC_KEY(#KEY), &count);
>>> - if (ret)
>>> + ret = apple_smc_read(smc, SMC_KEY(#KEY), &count, sizeof(count));
>>> + if (ret >= 0 && ret != sizeof(count))
>>> + ret = -EINVAL;
>>> + if (ret < 0)
>>> return dev_err_probe(smc->dev, ret, "Failed to get key count");
>>> smc->key_count = be32_to_cpu(count);
>>
>> This makes sense, it just feels weird reading because u32 is.. not a
>> be32 (that gets passed into be32_to_cpu).
>
> count is __be32 now (the SMC firmware returns that value as big-endian
> because Apple likes to think different) and we read that using
> apple_smc_read now which just reads raw bytes. be32_to_cpu then converts
> that to a u32, i.e. the type of smc->key_count. There's no functional
> change here. What's weird about that?
>
>
> Sven
Pfft, brain fart. I thought you were going other way around.
Reviewed-by: Joshua Peisach <jpeisach@ubuntu.com>
^ permalink raw reply
* [PATCH v12 5/7] i2c: davinci: add support for setting bus frequency
From: Marcus Folkesson @ 2026-07-19 14:59 UTC (permalink / raw)
To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson,
Bartosz Golaszewski
In-Reply-To: <20260719-i2c-mux-v12-0-a5010d623a57@gmail.com>
Populate adapter with clock_Hz and .set_clk_freq() to enable support for
dynamic bus frequency.
Remove bus_freq_Hz entirely and only use clock_Hz instead.
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
drivers/i2c/busses/i2c-davinci.c | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index f543997c31e9..87fef17bca55 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -132,8 +132,6 @@ struct davinci_i2c_dev {
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
- /* standard bus frequency */
- unsigned int bus_freq_Hz;
/* Chip has a ICPFUNC register */
bool has_pfunc;
};
@@ -171,6 +169,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
u32 clkh;
u32 clkl;
u32 input_clock = clk_get_rate(dev->clk);
+ u32 bus_freq_Hz = dev->adapter.clock_Hz;
/* NOTE: I2C Clock divider programming info
* As per I2C specs the following formulas provide prescaler
@@ -207,16 +206,16 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
if (device_is_compatible(dev->dev, "ti,keystone-i2c"))
d = 6;
- clk = (input_clock / (psc + 1)) / (dev->bus_freq_Hz);
+ clk = (input_clock / (psc + 1)) / (bus_freq_Hz);
/* Avoid driving the bus too fast because of rounding errors above */
- if (input_clock / (psc + 1) / clk > dev->bus_freq_Hz)
+ if (input_clock / (psc + 1) / clk > bus_freq_Hz)
clk++;
/*
* According to I2C-BUS Spec 2.1, in FAST-MODE LOW period should be at
* least 1.3uS, which is not the case with 50% duty cycle. Driving HIGH
* to LOW ratio as 1 to 2 is more safe.
*/
- if (dev->bus_freq_Hz > I2C_MAX_STANDARD_MODE_FREQ)
+ if (bus_freq_Hz > I2C_MAX_STANDARD_MODE_FREQ)
clkl = (clk << 1) / 3;
else
clkl = (clk >> 1);
@@ -267,7 +266,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
dev_dbg(dev->dev, "CLKH = %d\n",
davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
- dev_dbg(dev->dev, "bus_freq_Hz = %dHz\n", dev->bus_freq_Hz);
+ dev_dbg(dev->dev, "bus_freq_Hz = %dHz\n", dev->adapter.clock_Hz);
/* Take the I2C module out of reset: */
@@ -279,6 +278,23 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
return 0;
}
+static int davinci_i2c_set_clk(struct i2c_adapter *adap, u32 clock_Hz)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ /* put I2C into reset */
+ davinci_i2c_reset_ctrl(dev, 0);
+
+ /* compute clock dividers */
+ adap->clock_Hz = clock_Hz;
+ i2c_davinci_calc_clk_dividers(dev);
+
+ /* Take the I2C module out of reset: */
+ davinci_i2c_reset_ctrl(dev, 1);
+
+ return clock_Hz;
+}
+
/*
* This routine does i2c bus recovery by using i2c_generic_scl_recovery
* which is provided by I2C Bus recovery infrastructure.
@@ -755,12 +771,13 @@ static int davinci_i2c_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
dev->irq = irq;
platform_set_drvdata(pdev, dev);
+ adap = &dev->adapter;
r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
if (r)
prop = I2C_MAX_STANDARD_MODE_FREQ;
- dev->bus_freq_Hz = prop;
+ adap->clock_Hz = prop;
dev->has_pfunc = device_property_present(&pdev->dev, "ti,has-pfunc");
@@ -800,7 +817,6 @@ static int davinci_i2c_probe(struct platform_device *pdev)
goto err_unuse_clocks;
}
- adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_DEPRECATED;
@@ -809,6 +825,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
adap->dev.parent = &pdev->dev;
adap->timeout = DAVINCI_I2C_TIMEOUT;
adap->dev.of_node = dev_of_node(&pdev->dev);
+ adap->set_clk_freq = davinci_i2c_set_clk;
if (dev->has_pfunc)
adap->bus_recovery_info = &davinci_i2c_scl_recovery_info;
--
2.54.0
^ permalink raw reply related
* [PATCH v12 7/7] docs: i2c: i2c-topology: add section about bus speed
From: Marcus Folkesson @ 2026-07-19 14:59 UTC (permalink / raw)
To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson
In-Reply-To: <20260719-i2c-mux-v12-0-a5010d623a57@gmail.com>
Describe what needs to be consideraed and taken into account
when using different bus speeds for different mux channels.
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
Documentation/i2c/i2c-topology.rst | 178 +++++++++++++++++++++++++++++++++++++
1 file changed, 178 insertions(+)
diff --git a/Documentation/i2c/i2c-topology.rst b/Documentation/i2c/i2c-topology.rst
index 48fce0f7491b..1ee0de6dbcb4 100644
--- a/Documentation/i2c/i2c-topology.rst
+++ b/Documentation/i2c/i2c-topology.rst
@@ -367,6 +367,184 @@ When D1 or D2 are accessed, accesses to D3 and D4 are locked out while
accesses to D5 may interleave. When D3 or D4 are accessed, accesses to
all other devices are locked out.
+Bus Speed and I2C Multiplexers
+================================
+
+I2C bus multiplexers allow multiple downstream channels to be exposed
+as separate I2C adapters which also could set their own bus speed.
+
+The multiplexer itself cannot change the bus speed as it uses the upstream
+clock and data lines to communicate with the downstream devices. The speed
+is therefore changed in the root adapter resulting in that the whole bus is
+affected.
+
+This increases the complexity of the topology and some considerations must
+be taken into account.
+
+Bus speed
+----------
+
+Downstream channels of an I2C multiplexer can only operate at the same or
+lower bus speed as the upstream bus. This is because the upstream bus may
+have devices that cannot operate at higher speeds and those will be affected
+by the speed change.
+
+The example below illustrates the problem.
+The root adapter is operating at 100kHz. D2 can only operate with 100kHz,
+but D1 can operate at 400kHz. When D1 is selected, the bus speed of the
+root adapter would have to be set to 400kHz, a speed that D2 may not support.
+
+This topology is therefore not allowed: ::
+
+ .----------. 400kHz .--------.
+ .--------. 100kHz | mux- |--------| dev D1 |
+ | root |--+-----| locked | '--------'
+ '--------' | | mux M1 |
+ | '----------'
+ | .--------.
+ '--| dev D2 |
+ '--------'
+
+
+This topology is allowed: ::
+
+ .----------. 100kHz .--------.
+ .--------. 400kHz | mux- |--------| dev D2 |
+ | root |--+-----| locked | '--------'
+ '--------' | mux M1 |--. 400kHz .--------.
+ '----------' '--------| dev D1 |
+ '--------'
+
+Preferred topology
+-------------------
+
+The preferred topology when using different bus speeds is to have the multiplexer
+connected directly to the root adapter without any devices as siblings.
+By this arrangement, the bus speed can be changed without affecting any other devices
+and many of the caveats are avoided.
+
+Other multiplexers in parallel are still okay as those are locked out during transfers.
+
+This is the preferred topology: ::
+
+ .----------. 100kHz .--------.
+ .--------. 400kHz | mux- |--------| dev D2 |
+ | root |--+-----| locked | '--------'
+ '--------' | mux M1 |--. 400kHz .--------.
+ '----------' '--------| dev D1 |
+ '--------'
+
+Locking
+--------
+
+If the multiplexer is mux-locked, transfers to D3 may interleave between the
+select-transfer-deselect to D1 or D2.
+This results in a situation where the bus speed to D3 may be lower than it
+is supposed to be. This is usually not a problem.
+
+This topology is allowed but some transfers to D3 may be at 100kHz: ::
+
+ .----------. 100kHz .--------.
+ .--------. 400kHz | mux- |--------| dev D1 |
+ | root |--+-----| locked | '--------'
+ '--------' | | mux M1 |--. 400kHz .--------.
+ | '----------' '--------| dev D2 |
+ | .--------. '--------'
+ '--| dev D3 |
+ '--------'
+
+Multiple muxes in series
+--------------------------
+
+When multiple muxes are used in series the same rules apply.
+
+Transfers to D3 may interleave between select-transfer-deselect to D1, which
+results in that the bus speed to D2 or D3 will be at 100KHz.
+
+Transfers to D2 may interleave between select-transfer-deselect to D1, which
+results in that the bus speed to D1 may be at 400kHz as the transfer to D2
+will set the bus speed to before the transfer to D1 starts.
+
+This is probably a bad topology ::
+
+ .----------. 400kHz .----------. 100kHz .--------.
+ .--------.400kHz | mux- |--------| mux- |--------| dev D1 |
+ | root |--+----| locked | 400kHz | locked | '--------'
+ '--------' | | mux M1 |--. | mux M2 |
+ | '----------' | '----------'
+ | .--------. | .--------.
+ '--| dev D3 | '--| dev D2 |
+ '--------' '--------'
+
+Multiple muxes in parallel
+----------------------------
+
+When multiple muxes are used in parallel all access to other muxes are locked out
+so this is not a problem.
+
+If the muxes are mux-locked, access to D3 may still interleave though.
+
+In the example below, D3 may not interleave between select-transfer-deselect for D1
+or D2 as both muxes are parent-locked: ::
+
+
+ .----------. 100kHz .--------.
+ | parent- |----------| dev D1 |
+ .--| locked | '--------'
+ | | mux M1 |
+ | '----------'
+ | .----------. 400KHz .--------.
+ .--------. 400kHz | parent- |---------| dev D2 |
+ | root |--+------| locked | '--------'
+ '--------' | | mux M2 |
+ | '----------'
+ | .--------.
+ '--| dev D3 |
+ '--------'
+
+Idle state
+-----------
+
+Muxes have an idle state, which is the state the channels are put into when no channel
+is active. The state is typically one of the following:
+
+- All channels are disconnected
+- The last selected channel is left as-is
+- A predefined channel is selected
+
+Muxes that support an idle state where all channels are disconnected are preferred when using
+different bus speeds. Otherwise high bus speeds may "leak" through to devices that
+may not support that higher speed.
+
+Consider the following example: ::
+
+ .----------. 100kHz .--------.
+ .--------. 400kHz | mux- |--------| dev D1 |
+ | root |--+-----| locked | '--------'
+ '--------' | | mux M1 |--. 400kHz .--------.
+ | '----------' '--------| dev D2 |
+ | .--------. '--------'
+ '--| dev D3 |
+ '--------'
+
+If the idle state of M1 is:
+
+- All channels disconnected: No problem, D1 and D2 are not affected by communication
+ to D3.
+- Last selected channel: Problem if D1 was the last selected channel. High speed
+ communication to D3 will be "leaked" to D1.
+- Predefined channel: Problem if the predefined channel is D1. Set predefined channel
+ to D2 as D2 may handle 400kHz.
+
+Supported controllers
+-----------------------
+
+Not all I2C controllers support setting the bus speed dynamically.
+At the time of writing, the following controllers have support:
+
+============================ =============================================
+i2c-davinci Supports dynamic bus speed
+============================ =============================================
Mux type of existing device drivers
===================================
--
2.54.0
^ permalink raw reply related
* [PATCH v12 3/7] i2c: mux: add support for per channel bus frequency
From: Marcus Folkesson @ 2026-07-19 14:59 UTC (permalink / raw)
To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson
In-Reply-To: <20260719-i2c-mux-v12-0-a5010d623a57@gmail.com>
There may be several reasons why you may need to use a certain speed
on an I2C bus. E.g.
- When several devices are attached to the bus, the speed must be
selected according to the slowest device.
- Electrical conditions may limit the usable speed on the bus for
different reasons.
With an I2C multiplexer, it is possible to group the attached devices
after their preferred speed by e.g. putting all "slow" devices on a
separate channel on the multiplexer.
Consider the following topology:
.----------. 100kHz .--------.
.--------. 400kHz | |--------| dev D1 |
| root |--+-----| I2C MUX | '--------'
'--------' | | |--. 400kHz .--------.
| '----------' '-------| dev D2 |
| .--------. '--------'
'--| dev D3 |
'--------'
One requirement with this design is that a multiplexer may only use the
same or lower bus speed as its parent.
Otherwise, if the multiplexer would have to increase the bus frequency,
then all siblings (D3 in this case) would run into a clock speed it may
not support.
The bus frequency for each channel is set in the devicetree. As the
i2c-mux bindings import the i2c-controller schema, the clock-frequency
property is already allowed.
If no clock-frequency property is set, the channel inherits their parent
bus speed.
The following example uses dt bindings to illustrate the topology above:
i2c {
clock-frequency = <400000>;
i2c-mux {
i2c@0 {
clock-frequency = <100000>;
D1 {
...
};
};
i2c@1 {
D2 {
...
};
};
};
D3 {
...
}
};
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
drivers/i2c/i2c-mux.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 149 insertions(+), 12 deletions(-)
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index b126ce7338c2..00de5f124132 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -36,21 +36,118 @@ struct i2c_mux_priv {
u32 chan_id;
};
+static inline int
+__i2c_adapter_set_clk_freq(struct i2c_adapter *adapter, u32 clock_Hz)
+{
+ /* If the clock frequency is already set to the requested value, do nothing. */
+ if (adapter->clock_Hz == clock_Hz)
+ return 0;
+
+ if (adapter->set_clk_freq) {
+ adapter->clock_Hz = adapter->set_clk_freq(adapter, clock_Hz);
+ if (adapter->clock_Hz != clock_Hz)
+ dev_warn(&adapter->dev, "Could not set requested frequency. Requested %uHz, got %uHz\n",
+ clock_Hz, adapter->clock_Hz);
+
+ return 0;
+ }
+
+ /*
+ * If the adapter is a root adapter without .set_clk_freq() implemented, this feature is not
+ * supported.
+ */
+ if (!i2c_parent_is_i2c_adapter(adapter))
+ return -EOPNOTSUPP;
+
+ /*
+ * Update the clock_Hz for non-root adapters, even if .set_clk_freq() is not implemented,
+ * to allow the clock frequency to be propagated to root adapters that do support it.
+ */
+ adapter->clock_Hz = clock_Hz;
+ return 0;
+}
+
+static inline int
+i2c_adapter_set_clk_freq(struct i2c_adapter *adapter, u32 clock_Hz)
+{
+ int ret;
+
+ i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
+ ret = __i2c_adapter_set_clk_freq(adapter, clock_Hz);
+ i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
+
+ return ret;
+}
+
+static int i2c_mux_select_chan(struct i2c_adapter *adap, u32 chan_id, u32 *oldclock)
+{
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_mux_core *muxc = priv->muxc;
+ struct i2c_adapter *parent = muxc->parent;
+ int ret;
+
+ if (priv->adap.clock_Hz && priv->adap.clock_Hz < parent->clock_Hz) {
+ *oldclock = parent->clock_Hz;
+
+ if (muxc->mux_locked)
+ ret = i2c_adapter_set_clk_freq(parent, priv->adap.clock_Hz);
+ else
+ ret = __i2c_adapter_set_clk_freq(parent, priv->adap.clock_Hz);
+
+ dev_dbg(&adap->dev, "Set clock frequency %uHz on %s\n",
+ priv->adap.clock_Hz, parent->name);
+
+ if (ret)
+ dev_err(&adap->dev,
+ "Failed to set clock frequency %uHz on adapter %s: %d\n",
+ *oldclock, parent->name, ret);
+ }
+
+ return muxc->select(muxc, priv->chan_id);
+}
+
+static void i2c_mux_deselect_chan(struct i2c_adapter *adap, u32 chan_id, u32 oldclock)
+{
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_mux_core *muxc = priv->muxc;
+ struct i2c_adapter *parent = muxc->parent;
+ int ret;
+
+ if (muxc->deselect)
+ muxc->deselect(muxc, priv->chan_id);
+
+ if (oldclock && oldclock != priv->adap.clock_Hz) {
+ if (muxc->mux_locked)
+ ret = i2c_adapter_set_clk_freq(parent, oldclock);
+ else
+ ret = __i2c_adapter_set_clk_freq(parent, oldclock);
+
+ dev_dbg(&adap->dev, "Restored clock frequency %uHz on %s\n",
+ oldclock, parent->name);
+
+ if (ret)
+ dev_err(&adap->dev,
+ "Failed to set clock frequency %uHz on adapter %s: %d\n",
+ oldclock, parent->name, ret);
+ }
+}
+
static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[], int num)
{
struct i2c_mux_priv *priv = adap->algo_data;
struct i2c_mux_core *muxc = priv->muxc;
struct i2c_adapter *parent = muxc->parent;
+ u32 oldclock = 0;
int ret;
/* Switch to the right mux port and perform the transfer. */
- ret = muxc->select(muxc, priv->chan_id);
+ ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
if (ret >= 0)
ret = __i2c_transfer(parent, msgs, num);
- if (muxc->deselect)
- muxc->deselect(muxc, priv->chan_id);
+
+ i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
return ret;
}
@@ -61,15 +158,16 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
struct i2c_mux_priv *priv = adap->algo_data;
struct i2c_mux_core *muxc = priv->muxc;
struct i2c_adapter *parent = muxc->parent;
+ u32 oldclock = 0;
int ret;
/* Switch to the right mux port and perform the transfer. */
- ret = muxc->select(muxc, priv->chan_id);
+ ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
if (ret >= 0)
ret = i2c_transfer(parent, msgs, num);
- if (muxc->deselect)
- muxc->deselect(muxc, priv->chan_id);
+
+ i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
return ret;
}
@@ -82,16 +180,17 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
struct i2c_mux_priv *priv = adap->algo_data;
struct i2c_mux_core *muxc = priv->muxc;
struct i2c_adapter *parent = muxc->parent;
+ u32 oldclock = 0;
int ret;
/* Select the right mux port and perform the transfer. */
- ret = muxc->select(muxc, priv->chan_id);
+ ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
if (ret >= 0)
ret = __i2c_smbus_xfer(parent, addr, flags,
read_write, command, size, data);
- if (muxc->deselect)
- muxc->deselect(muxc, priv->chan_id);
+
+ i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
return ret;
}
@@ -104,16 +203,17 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
struct i2c_mux_priv *priv = adap->algo_data;
struct i2c_mux_core *muxc = priv->muxc;
struct i2c_adapter *parent = muxc->parent;
+ u32 oldclock = 0;
int ret;
/* Select the right mux port and perform the transfer. */
- ret = muxc->select(muxc, priv->chan_id);
+ ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
if (ret >= 0)
ret = i2c_smbus_xfer(parent, addr, flags,
read_write, command, size, data);
- if (muxc->deselect)
- muxc->deselect(muxc, priv->chan_id);
+
+ i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
return ret;
}
@@ -363,6 +463,43 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
}
}
+ of_property_read_u32(child, "clock-frequency", &priv->adap.clock_Hz);
+
+ /* If the mux adapter has no clock-frequency property, inherit from parent */
+ if (!priv->adap.clock_Hz)
+ priv->adap.clock_Hz = parent->clock_Hz;
+
+ if (priv->adap.clock_Hz < parent->clock_Hz)
+ if (muxc->idle_state != I2C_MUX_IDLE_DISCONNECT ||
+ muxc->idle_state == chan_id) {
+ dev_err(muxc->dev,
+ "channel %u has improper idle state for this configuration\n",
+ chan_id);
+ of_node_put(mux_node);
+ ret = -EINVAL;
+ goto err_free_priv;
+ }
+
+ /*
+ * Warn if the mux adapter is not parent-locked as
+ * this may cause issues for some hardware topologies.
+ */
+ if ((priv->adap.clock_Hz < parent->clock_Hz) && muxc->mux_locked)
+ dev_warn(muxc->dev,
+ "channel %u is slower than parent on a non parent-locked mux\n",
+ chan_id);
+
+ /* We don't support mux adapters faster than their parent */
+ if (priv->adap.clock_Hz > parent->clock_Hz) {
+ dev_err(muxc->dev,
+ "channel (%u) is faster (%u) than parent (%u)\n",
+ chan_id, priv->adap.clock_Hz, parent->clock_Hz);
+
+ of_node_put(mux_node);
+ ret = -EINVAL;
+ goto err_free_priv;
+ }
+
priv->adap.dev.of_node = child;
of_node_put(mux_node);
}
--
2.54.0
^ permalink raw reply related
* [PATCH v12 4/7] i2c: davinci: calculate bus freq from Hz instead of kHz
From: Marcus Folkesson @ 2026-07-19 14:59 UTC (permalink / raw)
To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson,
Bartosz Golaszewski
In-Reply-To: <20260719-i2c-mux-v12-0-a5010d623a57@gmail.com>
The bus frequency is unnecessarily converted between Hz and kHz in
several places.
This is probably an old legacy from the old times (pre-devicetrees)
when the davinci_i2c_platform_data took the bus_freq in kHz.
Stick to Hz.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
drivers/i2c/busses/i2c-davinci.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index e15eef163a8f..f543997c31e9 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -132,8 +132,8 @@ struct davinci_i2c_dev {
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
- /* standard bus frequency (kHz) */
- unsigned int bus_freq;
+ /* standard bus frequency */
+ unsigned int bus_freq_Hz;
/* Chip has a ICPFUNC register */
bool has_pfunc;
};
@@ -207,16 +207,16 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
if (device_is_compatible(dev->dev, "ti,keystone-i2c"))
d = 6;
- clk = ((input_clock / (psc + 1)) / (dev->bus_freq * 1000));
+ clk = (input_clock / (psc + 1)) / (dev->bus_freq_Hz);
/* Avoid driving the bus too fast because of rounding errors above */
- if (input_clock / (psc + 1) / clk > dev->bus_freq * 1000)
+ if (input_clock / (psc + 1) / clk > dev->bus_freq_Hz)
clk++;
/*
* According to I2C-BUS Spec 2.1, in FAST-MODE LOW period should be at
* least 1.3uS, which is not the case with 50% duty cycle. Driving HIGH
* to LOW ratio as 1 to 2 is more safe.
*/
- if (dev->bus_freq > 100)
+ if (dev->bus_freq_Hz > I2C_MAX_STANDARD_MODE_FREQ)
clkl = (clk << 1) / 3;
else
clkl = (clk >> 1);
@@ -240,7 +240,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
- dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
+ dev_dbg(dev->dev, "input_clock = %u, CLK = %u\n", input_clock, clk);
}
/*
@@ -267,7 +267,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
dev_dbg(dev->dev, "CLKH = %d\n",
davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
- dev_dbg(dev->dev, "bus_freq = %dkHz\n", dev->bus_freq);
+ dev_dbg(dev->dev, "bus_freq_Hz = %dHz\n", dev->bus_freq_Hz);
/* Take the I2C module out of reset: */
@@ -760,7 +760,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
if (r)
prop = I2C_MAX_STANDARD_MODE_FREQ;
- dev->bus_freq = prop / 1000;
+ dev->bus_freq_Hz = prop;
dev->has_pfunc = device_property_present(&pdev->dev, "ti,has-pfunc");
--
2.54.0
^ permalink raw reply related
* [PATCH v12 6/7] i2c: mux: ltc4306: set correct idle_state in i2c_mux_core
From: Marcus Folkesson @ 2026-07-19 14:59 UTC (permalink / raw)
To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson
In-Reply-To: <20260719-i2c-mux-v12-0-a5010d623a57@gmail.com>
Inform the core if we intend to disconnect channels during idle.
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
drivers/i2c/muxes/i2c-mux-ltc4306.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c
index 18228f5b80e8..df7136b7b042 100644
--- a/drivers/i2c/muxes/i2c-mux-ltc4306.c
+++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c
@@ -232,6 +232,9 @@ static int ltc4306_probe(struct i2c_client *client)
data = i2c_mux_priv(muxc);
data->chip = chip;
+ if (idle_disc)
+ i2c_mux_set_idle_state(muxc, I2C_MUX_IDLE_DISCONNECT);
+
i2c_set_clientdata(client, muxc);
data->regmap = devm_regmap_init_i2c(client, <c4306_regmap_config);
--
2.54.0
^ permalink raw reply related
* [PATCH v12 2/7] i2c: mux: add idle_state property to i2c_mux_core
From: Marcus Folkesson @ 2026-07-19 14:59 UTC (permalink / raw)
To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson
In-Reply-To: <20260719-i2c-mux-v12-0-a5010d623a57@gmail.com>
Muxes treat their channels differently when idle.
Let the mux core have this information to make it available for
internal use.
Possible idle states are:
- I2C_MUX_IDLE_AS_IS: Leave channels as is when idle
- I2C_MUX_IDLE_DISCONNECT: Disconnect channel (set HiZ when idle)
- I2C_MUX_IDLE_UNKNOWN: Unknown idle state
- <n>: Enable channel n (starting from 0) when idle"
Default value is set to I2C_MUX_IDLE_UNKNOWN.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
drivers/i2c/i2c-mux.c | 1 +
include/linux/i2c-mux.h | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 681a201c239b..b126ce7338c2 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -247,6 +247,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
muxc->select = select;
muxc->deselect = deselect;
muxc->max_adapters = max_adapters;
+ muxc->idle_state = I2C_MUX_IDLE_UNKNOWN;
return muxc;
}
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 1784ac7afb11..a348f81e7a90 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -15,6 +15,10 @@
#include <linux/bitops.h>
+#define I2C_MUX_IDLE_AS_IS (-1)
+#define I2C_MUX_IDLE_DISCONNECT (-2)
+#define I2C_MUX_IDLE_UNKNOWN (-3)
+
struct i2c_mux_core {
struct i2c_adapter *parent;
struct device *dev;
@@ -22,6 +26,18 @@ struct i2c_mux_core {
unsigned int arbitrator:1;
unsigned int gate:1;
+ /*
+ * The mux state used by the driver when idle.
+ * Possible idle states are:
+ * - I2C_MUX_IDLE_AS_IS: Leave channels as is when idle
+ * - I2C_MUX_IDLE_DISCONNECT: Disconnect channel (set HiZ when idle)
+ * - I2C_MUX_IDLE_UNKNOWN: Unknown idle state
+ * - <n>: Enable channel n (starting from 0) when idle"
+ *
+ * Default value is set to I2C_MUX_IDLE_UNKNOWN.
+ */
+ int idle_state;
+
void *priv;
int (*select)(struct i2c_mux_core *, u32 chan_id);
@@ -38,6 +54,20 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
int (*select)(struct i2c_mux_core *, u32),
int (*deselect)(struct i2c_mux_core *, u32));
+/*
+ * Mux drivers may only change idle_state, and may only do so
+ * between allocation and registration of the mux controller.
+ */
+static inline void i2c_mux_set_idle_state(struct i2c_mux_core *muxc, int state)
+{
+ muxc->idle_state = state;
+}
+
+static inline int i2c_mux_idle_state(struct i2c_mux_core *muxc)
+{
+ return muxc->idle_state;
+}
+
/* flags for i2c_mux_alloc */
#define I2C_MUX_LOCKED BIT(0)
#define I2C_MUX_ARBITRATOR BIT(1)
--
2.54.0
^ permalink raw reply related
* [PATCH v12 1/7] i2c: core: add callback to change bus frequency
From: Marcus Folkesson @ 2026-07-19 14:59 UTC (permalink / raw)
To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson
In-Reply-To: <20260719-i2c-mux-v12-0-a5010d623a57@gmail.com>
All devices on the same I2C bus share the same clock line and the bus
frequency has therefor be chosen so that all attached devices are able
to tolarate that clock rate. IOW, the bus speed must be set for the
slowest attached device.
With I2C multiplexers/switches on the other hand, it would be possible
to have different "domains" that runs with different speeds.
Prepare for such a feature by provide an optional callback function to
change bus frequency.
As a side effect, several bus drivers keep the bus speed in a
private structure and can now have this value stored in a uniform way
instead.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
include/linux/i2c.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 20fd41b51d5c..b3b0d16b4ddd 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -729,6 +729,9 @@ struct i2c_adapter_quirks {
/*
* i2c_adapter is the structure used to identify a physical i2c bus along
* with the access algorithms necessary to access it.
+ *
+ * @set_clk_freq: Set clock frequency for the adapter. Returns the actual set frequency.
+ * This function is optional.
*/
struct i2c_adapter {
struct module *owner;
@@ -742,6 +745,8 @@ struct i2c_adapter {
struct rt_mutex mux_lock;
int timeout; /* in jiffies */
+ u32 clock_Hz; /* bus clock speed */
+ int (*set_clk_freq)(struct i2c_adapter *adap, u32 clock_Hz); /* Optional */
int retries;
struct device dev; /* the adapter device */
unsigned long locked_flags; /* owned by the I2C core */
--
2.54.0
^ permalink raw reply related
* [PATCH v12 0/7] I2C Mux per channel bus speed
From: Marcus Folkesson @ 2026-07-19 14:59 UTC (permalink / raw)
To: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, Peter Rosin, Peter Rosin
Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson,
Bartosz Golaszewski
This was a RFC on how to implement a feature to have different bus
speeds on different channels with an I2C multiplexer/switch.
As no major complaints on the design came up during the review, I
decided to submit the series without the RFC tag.
The benefit with this feature is that you may group devices after
the fastest bus speed they can handle.
A real-world example is that you could have e.g. a display running @400kHz
and a smart battery running @100kHz using the same I2C controller.
There are many corner cases where this may cause a problem for some
hardware topologies. I've tried to describe those I could think of
in the documentation, see Patch #5.
E.g. one risk is that if the mux driver does not disconnect channels
when Idle, this may cause a higher frequency to "leak" through to
devices that are supposed to run at lower bus speed.
This is not only a "problem" for changing bus speed but could also be
an issue for potential address conflicts.
This patchset has been used and tested heavily the last months
on a custom board based on a da850 (DaVinci) platform.
The implementation is split up into several patches:
Patch #1 Introduce a callback for the i2c controller to set bus speed
Patch #2 Introduce functionality to adjust bus speed depending on mux
channel.
Patch #3 Cleanup i2c-davinci driver a bit to prepare it for set_clk_freq
Parch #4 Implement set_clk_freq for the i2c-davinci driver
Parch #5 Update documentation with this feature
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
Changes in v12:
- Defined new idle states in i2c-mux.h
- Replaced _hz with _Hz where appropriate
- Reword comment and commit message about idle states
- Link to v11: https://patch.msgid.link/20260713-i2c-mux-v11-0-72bb8af8ee8c@gmail.com
Changes in v11:
- Rebased on i2c-next
- Use _Hz instead of _hz for local variables in i2c-davinci.c.
- Link to v10: https://patch.msgid.link/20260708-i2c-mux-v10-0-09dca03c8a15@gmail.com
Changes in v10:
- Fix gramatics in documentation
- Move {__,}i2c_adapter_set_clk_freq() to i2c-mux.c
- Make set_clk_freq() return actual frequency
- Reimplement idle_state (from earlier version)
- Implement example on idle_state for ltc4306
- Link to v9: https://lore.kernel.org/r/20260324-i2c-mux-v9-0-5292b0608243@gmail.com
Changes in v9:
- Fix stray blank line
- Link to v8: https://lore.kernel.org/r/20260314-i2c-mux-v8-0-fb1738a4df0a@gmail.com
Changes in v8:
- Fix gramatics and change %d to %u were appropriate
- Link to v7: https://lore.kernel.org/r/20260223-i2c-mux-v7-0-ec75b214718a@gmail.com
Changes in v7:
- Remove code for finding first mux-locked ancestor
- Introduce a unlocked (i2c_adapter_set_clk_freq) and unlocked
(__i2c_adapter_set_clk_freq) variant
- Let the locking be handled in __i2c_adapter_set_clk_freq
- Use I2C_MAX_STANDARD_MODE_FREQ instead of magic numbers where
appropriate
- Link to v6: https://lore.kernel.org/r/20260216-i2c-mux-v6-0-9be28ecfd7e3@gmail.com
Changes in v6:
- Change logic to find which ancestor to lock with I2C_LOCK_ROOT_ADAPTER
It now find the first mux-locked ancestor and then lock its parent.
- Remove bus_freq_hz in i2c-davinci and only use clock_hz instead
- Mention in commit message that clock_hz can be used to store frequency in an uniform way
- Swap order for change freq/deselect to keep symmetry
- Only allow bus frequency to be lowered in select()
This to not allow an intermediate frequency to be set when it is not
supposed to
- check if(ret) instead of ret(<0) where appropriate
- Fix typos in documentation
- Change i2c_adapter.clock_hz from int to u32
- Simplify i2c_adapter_set_clk_freq() by removing 'ret'
- Link to v5: https://lore.kernel.org/r/20260213-i2c-mux-v5-0-fb2cbf9979b3@gmail.com
Changes in v5:
- Take the lock of the top-most mutex locked mux to make sure that the
root is locked
- Link to v4: https://lore.kernel.org/r/20260128-i2c-mux-v4-0-dee49ce276c0@gmail.com
Changes in v4:
- Rebase on master
- Swap order for printing warning about "channel %u is slower than
parent on a non parent-locked mux\n"
- Fix typo in comment, adaper->adapter
- Link to v3: https://lore.kernel.org/r/20251020-i2c-mux-v3-0-908ac5cf9223@gmail.com
Changes in v3:
- Return -EINVAL if channel is faster than parent (kernel test robot)
- Link to v2: https://lore.kernel.org/r/20251002-i2c-mux-v2-0-b698564cd956@gmail.com
Changes in v2:
- Changed bus_freq field to bus_freq_hz in davinci_i2c_dev (Bartosz Golaszewski)
- Removed idle_state from mux core (Peter Rosin)
- Link to v1: https://lore.kernel.org/r/20250922-i2c-mux-v1-0-28c94a610930@gmail.com
To: Andi Shyti <andi.shyti@kernel.org>
To: Peter Rosin <peda@lysator.liu.se>
To: Bartosz Golaszewski <brgl@kernel.org>
To: Michael Hennerich <michael.hennerich@analog.com>
Cc: linux-i2c@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
---
Marcus Folkesson (7):
i2c: core: add callback to change bus frequency
i2c: mux: add idle_state property to i2c_mux_core
i2c: mux: add support for per channel bus frequency
i2c: davinci: calculate bus freq from Hz instead of kHz
i2c: davinci: add support for setting bus frequency
i2c: mux: ltc4306: set correct idle_state in i2c_mux_core
docs: i2c: i2c-topology: add section about bus speed
Documentation/i2c/i2c-topology.rst | 178 ++++++++++++++++++++++++++++++++++++
drivers/i2c/busses/i2c-davinci.c | 35 +++++--
drivers/i2c/i2c-mux.c | 162 +++++++++++++++++++++++++++++---
drivers/i2c/muxes/i2c-mux-ltc4306.c | 3 +
include/linux/i2c-mux.h | 30 ++++++
include/linux/i2c.h | 5 +
6 files changed, 392 insertions(+), 21 deletions(-)
---
base-commit: 5489063ced8c6afdd1f4134a1a05a666b0834b31
change-id: 20250913-i2c-mux-b0063de2ae4d
Best regards,
--
Marcus Folkesson <marcus.folkesson@gmail.com>
^ permalink raw reply
* Re: [PATCH] mfd: macsmc: Fix key count endianness annotation
From: Sven Peter @ 2026-07-19 15:15 UTC (permalink / raw)
To: Joshua Peisach
Cc: asahi, Janne Grunau, Lee Jones, Neal Gompa, linux-arm-kernel,
linux-kernel, kernel test robot
In-Reply-To: <DK2N0ITFL309.1Y5VHF18YIQ7M@ubuntu.com>
On 7/19/26 17:02, Joshua Peisach wrote:
> On Sun Jul 19, 2026 at 9:00 AM EDT, Sven Peter wrote:
>> SMC firmware returns the value of the #KEY key in big-endian unlike most
>> other keys. Reading it through apple_smc_read_u32() into a plain u32
>> and then converting with be32_to_cpu() makes sparse complain:
>>
>> drivers/mfd/macsmc.c:462:26: sparse: cast to restricted __be32
>>
>> Read the raw value into a __be32 using apple_smc_read() instead.
>>
>> Fixes: e038d985c982 ("mfd: Add Apple Silicon System Management
>> Controller")
>> Reported-by: kernel test robot <lkp@intel.com>
>> Closes:
>> https://lore.kernel.org/oe-kbuild-all/202607181046.OANjIoqR-lkp@intel.com/
>> Signed-off-by: Sven Peter <sven@kernel.org>
>> ---
>> drivers/mfd/macsmc.c | 8 +++++---
>> 1 file changed, 5 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
>> index 358feec2d088..514cba7dc897 100644
>> --- a/drivers/mfd/macsmc.c
>> +++ b/drivers/mfd/macsmc.c
>> @@ -410,7 +410,7 @@ static int apple_smc_probe(struct platform_device
>> *pdev)
>> {
>> struct device *dev = &pdev->dev;
>> struct apple_smc *smc;
>> - u32 count;
>> + __be32 count;
>> int ret;
>>
>> smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL);
>> @@ -461,8 +461,10 @@ static int apple_smc_probe(struct
>> platform_device *pdev)
>> dev_set_drvdata(&pdev->dev, smc);
>> BLOCKING_INIT_NOTIFIER_HEAD(&smc->event_handlers);
>>
>> - ret = apple_smc_read_u32(smc, SMC_KEY(#KEY), &count);
>> - if (ret)
>> + ret = apple_smc_read(smc, SMC_KEY(#KEY), &count, sizeof(count));
>> + if (ret >= 0 && ret != sizeof(count))
>> + ret = -EINVAL;
>> + if (ret < 0)
>> return dev_err_probe(smc->dev, ret, "Failed to get key count");
>> smc->key_count = be32_to_cpu(count);
>
> This makes sense, it just feels weird reading because u32 is.. not a
> be32 (that gets passed into be32_to_cpu).
count is __be32 now (the SMC firmware returns that value as big-endian
because Apple likes to think different) and we read that using
apple_smc_read now which just reads raw bytes. be32_to_cpu then converts
that to a u32, i.e. the type of smc->key_count. There's no functional
change here. What's weird about that?
Sven
^ permalink raw reply
* Re: [PATCH] mfd: macsmc: Fix key count endianness annotation
From: Joshua Peisach @ 2026-07-19 15:02 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Lee Jones
Cc: asahi, linux-arm-kernel, linux-kernel, kernel test robot
In-Reply-To: <20260719-b4-macsmc-be32-fix-v1-1-c7b1936307fa@kernel.org>
On Sun Jul 19, 2026 at 9:00 AM EDT, Sven Peter wrote:
> SMC firmware returns the value of the #KEY key in big-endian unlike most
> other keys. Reading it through apple_smc_read_u32() into a plain u32
> and then converting with be32_to_cpu() makes sparse complain:
>
> drivers/mfd/macsmc.c:462:26: sparse: cast to restricted __be32
>
> Read the raw value into a __be32 using apple_smc_read() instead.
>
> Fixes: e038d985c982 ("mfd: Add Apple Silicon System Management Controller")
> Reported-by: kernel test robot <lkp@intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202607181046.OANjIoqR-lkp@intel.com/
> Signed-off-by: Sven Peter <sven@kernel.org>
> ---
> drivers/mfd/macsmc.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
> index 358feec2d088..514cba7dc897 100644
> --- a/drivers/mfd/macsmc.c
> +++ b/drivers/mfd/macsmc.c
> @@ -410,7 +410,7 @@ static int apple_smc_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> struct apple_smc *smc;
> - u32 count;
> + __be32 count;
> int ret;
>
> smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL);
> @@ -461,8 +461,10 @@ static int apple_smc_probe(struct platform_device *pdev)
> dev_set_drvdata(&pdev->dev, smc);
> BLOCKING_INIT_NOTIFIER_HEAD(&smc->event_handlers);
>
> - ret = apple_smc_read_u32(smc, SMC_KEY(#KEY), &count);
> - if (ret)
> + ret = apple_smc_read(smc, SMC_KEY(#KEY), &count, sizeof(count));
> + if (ret >= 0 && ret != sizeof(count))
> + ret = -EINVAL;
> + if (ret < 0)
> return dev_err_probe(smc->dev, ret, "Failed to get key count");
> smc->key_count = be32_to_cpu(count);
This makes sense, it just feels weird reading because u32 is.. not a
be32 (that gets passed into be32_to_cpu).
I guess it doesn't really matter.
-Josh
^ permalink raw reply
* Re: [PATCH 6.6.y 0/6] cBPF JIT spray hardening
From: Sasha Levin @ 2026-07-19 15:00 UTC (permalink / raw)
To: stable, Greg Kroah-Hartman
Cc: Sasha Levin, bpf, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, x86, Alexei Starovoitov, Daniel Borkmann,
Dave Hansen, Pawan Gupta
In-Reply-To: <20260717-cbpf-jit-spray-hardening-6-6-y-v1-0-e04f1b2893de@linux.intel.com>
> These backports harden BPF JIT against spectre-v2 class of attacks. Without
> a predictor flush, execution of new BPF program may use stale prediction
> left behind by the freed one.
Queued the series for 6.6, thanks.
--
Thanks,
Sasha
^ permalink raw reply
* Re: [PATCH v2 00/12] arm64: dts: apple: Add SMC hwmon nodes
From: Sven Peter @ 2026-07-19 14:11 UTC (permalink / raw)
To: James Calligeros, Janne Grunau, Neal Gompa, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260714-smc-subdev-dt-v2-0-13fa78873121@gmail.com>
On 7/14/26 08:28, James Calligeros wrote:
> Hi folks,
>
> Following on from the series which added SMC hwmon driver[1], this
> series spins out and adds the Devicetree nodes required for the hwmon
> driver to operate. These were missed back in December.
>
> The System Management Controller on Apple Silicon devices exposes
> the temperature, voltage, power and fan speed data from numerous
> (potentially hundreds) of sensors scattered about the SoC and
> device at large. Unfortunately there is very little rhyme or reason
> to how Apple expose these using the SMC firmware's FourCC key-value
> system. Some sensors are reliably common across all devices and
> all SoCs, like PSTR which measures the total platform power consumption.
> Others are specific to a class of device, like the fan control
> keys, which are only present on devices with fans. Some are specific
> to a single SoC, and others still are specific to a single device.
> To complicate matters further, some SoCs are not even consistent
> across devices; the application core temperature sensors for a
> given SoC are read from different keys depending on the device
> that SoC is in...
>
Applied to sven/linux (apple-soc/dt-7.3), thanks!
[01/12] arm64: dts: apple: t8112: Add SMC hwmon node
https://github.com/AsahiLinux/linux/commit/89efdbd8ea62
[02/12] arm64: dts: apple: t8103: Add SMC hwmon node
https://github.com/AsahiLinux/linux/commit/4dea4ee249ec
[03/12] arm64: dts: apple: t600x: Add SMC hwmon node
https://github.com/AsahiLinux/linux/commit/d02aeb6980b6
[04/12] arm64: dts: apple: t602x: Add SMC hwmon node
https://github.com/AsahiLinux/linux/commit/f424abc3075b
[05/12] arm64: dts: apple: Add common SMC hwmon infrastructure
https://github.com/AsahiLinux/linux/commit/56c65dc95f3d
[06/12] arm64: dts: apple: t8103: Add common SMC hwmon sensors
https://github.com/AsahiLinux/linux/commit/d77603e44f55
[07/12] arm64: dts: apple: t8112: Add common SMC hwmon sensors
https://github.com/AsahiLinux/linux/commit/ae42d7fe0793
[08/12] arm64: dts: apple: t600x: Add common SMC hwmon sensors
https://github.com/AsahiLinux/linux/commit/fe521d15d9c5
[09/12] arm64: dts: apple: t602x: Add common SMC hwmon sensors
https://github.com/AsahiLinux/linux/commit/fd42ff865357
[10/12] arm64: dts: apple: t8103: jxxx: Add device-specific SMC hwmon
sensors
https://github.com/AsahiLinux/linux/commit/b6935375d536
[11/12] arm64: dts: apple: t8112: jxxx: Add device-specific SMC hwmon
sensors
https://github.com/AsahiLinux/linux/commit/da160f258c36
[12/12] arm64: dts: apple: t60xx: jxxx: Add device-specific SMC hwmon
sensors
https://github.com/AsahiLinux/linux/commit/e88070b74578
Best regards,
--
Sven Peter <sven@kernel.org>
^ permalink raw reply
* Re: [PATCH v11 2/7] i2c: mux: add idle_state property to i2c_mux_core
From: Marcus Folkesson @ 2026-07-19 14:07 UTC (permalink / raw)
To: Peter Rosin
Cc: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, linux-i2c, linux-kernel,
linux-arm-kernel
In-Reply-To: <c0b47180-d3df-4b58-9311-d02734213716@lysator.liu.se>
Hi Peter!
On Sun, Jul 19, 2026 at 02:39:34PM +0200, Peter Rosin wrote:
> On 2026-07-15 21:02, Marcus Folkesson wrote:
> > Hi Peter,
> >
> > On Tue, Jul 14, 2026 at 01:29:01PM +0200, Peter Rosin wrote:
> > > Hi Marcus,
> > >
> > > Sorry for the very late feedback.
> > >
> > > On 2026-07-13 09:19, Marcus Folkesson wrote:
> > > > Muxes treat their channels differently when idle.
> > > > Let the mux core have this information to make it available for
> > > > internal use.
> > > > Reuse the same state values used by CONFIG_MULTIPLEXER.
> > > >
> > > > Possible idle states are:
> > > > - MUX_IDLE_AS_IS: Leave channels as is when idle
> > > > - MUX_IDLE_DISCONNECT: Disconnect channel (set HiZ when idle)
> > > > - <n>: Enable channel n when idle
> > > >
> > > > Default value is set to MUX_IDLE_AS_IS.
> > > >
> > > > Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
[...]
> > I think I will introduce a few defines in i2c-mux.c then;
> >
> >
> > #define I2C_MUX_IDLE_UNKNOWN (-1)
> > #define I2C_MUX_IDLE_AS_IS (-2)
> > #define I2C_MUX_IDLE_DISCONNECT (-3)
>
> Hi!
>
> Please keep AS_IS as -1 and DISCONNECT as -2. Using different
> values will make it difficult to get rid of the use of the
> defines belonging to the mux subsystem in case the actual
> value has crept into some .dtb or something like that.
Got it!
>
> Also, I think the right thing to do is to put these defines
> in the i2c-mux.h header so that the drivers can find them.
> I assume .c was a typo?
Yep, it should be i2c-mux.h.
>
> > [...]
> >
> > struct i2c_mux_core {
> >
> > [...]
> >
> > /*
> > * The mux state to use when not active.
>
> This is not 100% accurate. The value stored here is never
> actually used to set the idle state. The idle_state here is
> only what the driver has declared that the idle_state is.
> Perhaps word it like this instead?
>
> * The mux state used by the driver when idle.
>
> Agreed, subtle difference, but...
... even better. I will change to that.
>
> In the future, drivers (most of them) could be changed to
> use this variable to store the actual idle state. But, as
> mentioned, that's not easy for i2c-mux-gpmux since the idle
> state is under the control of the the mux subsystem in that
> case.
>
> Cheers,
> Peter
>
> > * Possible idle states are:
> > * - I2C_MUX_IDLE_UNKNOWN: Unknown idle state
> > * - I2C_MUX_IDLE_AS_IS: Leave channels as is when idle
> > * - I2C_MUX_IDLE_DISCONNECT: Disconnect channel (set HiZ when idle)
> > * - <n>: Enable channel n (starting from 0) when idle"
> > *
> > * Default value is set to I2C_MUX_IDLE_UNKNOWN.
> > */
> > int idle_state;
> >
> > [...]
> > };
Thanks,
Marcus Folkesson
^ permalink raw reply
* Re: [PATCH RESEND] Bluetooth: hci_bcm4377: Use named initializers for pci_device_id array
From: Sven Peter @ 2026-07-19 13:15 UTC (permalink / raw)
To: Uwe Kleine-König (The Capable Hub), Janne Grunau,
Marcel Holtmann, Luiz Augusto von Dentz
Cc: Neal Gompa, asahi, linux-arm-kernel, linux-bluetooth,
linux-kernel
In-Reply-To: <20260718172513.986134-2-u.kleine-koenig@baylibre.com>
On 7/18/26 19:25, Uwe Kleine-König (The Capable Hub) wrote:
> Initializing a struct using list initializers is hard to read, compared
> to that using named initializers is more ideomatic. Convert the macro
> used to assign values in the driver's pci_device_id array accordingly.
>
> This change doesn't introduce any changes to the compiled array on an
> x86 and an arm64 build.
>
> Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> ---
Acked-by: Sven Peter <sven@kernel.org>
Best,
Sven
^ permalink raw reply
* [PATCH] mfd: macsmc: Fix key count endianness annotation
From: Sven Peter @ 2026-07-19 13:00 UTC (permalink / raw)
To: Janne Grunau, Neal Gompa, Lee Jones
Cc: asahi, linux-arm-kernel, linux-kernel, kernel test robot,
Sven Peter
SMC firmware returns the value of the #KEY key in big-endian unlike most
other keys. Reading it through apple_smc_read_u32() into a plain u32
and then converting with be32_to_cpu() makes sparse complain:
drivers/mfd/macsmc.c:462:26: sparse: cast to restricted __be32
Read the raw value into a __be32 using apple_smc_read() instead.
Fixes: e038d985c982 ("mfd: Add Apple Silicon System Management Controller")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202607181046.OANjIoqR-lkp@intel.com/
Signed-off-by: Sven Peter <sven@kernel.org>
---
drivers/mfd/macsmc.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index 358feec2d088..514cba7dc897 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -410,7 +410,7 @@ static int apple_smc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct apple_smc *smc;
- u32 count;
+ __be32 count;
int ret;
smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL);
@@ -461,8 +461,10 @@ static int apple_smc_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, smc);
BLOCKING_INIT_NOTIFIER_HEAD(&smc->event_handlers);
- ret = apple_smc_read_u32(smc, SMC_KEY(#KEY), &count);
- if (ret)
+ ret = apple_smc_read(smc, SMC_KEY(#KEY), &count, sizeof(count));
+ if (ret >= 0 && ret != sizeof(count))
+ ret = -EINVAL;
+ if (ret < 0)
return dev_err_probe(smc->dev, ret, "Failed to get key count");
smc->key_count = be32_to_cpu(count);
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260719-b4-macsmc-be32-fix-637e8bb1692a
Best regards,
--
Sven Peter <sven@kernel.org>
^ permalink raw reply related
* Re: [PATCH v12 02/29] arm64/fpsimd: Update FA64 and ZT0 enables when loading SME state
From: Mark Brown @ 2026-07-19 12:59 UTC (permalink / raw)
To: Marc Zyngier
Cc: Fuad Tabba, Mark Rutland, Joey Gouly, Catalin Marinas,
Suzuki K Poulose, Will Deacon, Paolo Bonzini, Jonathan Corbet,
Shuah Khan, Oliver Upton, Dave Martin, Ben Horgan,
Jean-Philippe Brucker, linux-arm-kernel, kvmarm, linux-kernel,
kvm, linux-doc, linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <18229974-b26d-4eed-82f7-7af7e1c26634@sirena.org.uk>
[-- Attachment #1: Type: text/plain, Size: 925 bytes --]
On Sun, Jul 19, 2026 at 01:40:28PM +0100, Mark Brown wrote:
> On Sun, Jul 19, 2026 at 09:35:53AM +0100, Marc Zyngier wrote:
> > So leave this is a straight ISB, no optimisation. Once you come back
> > with actual data showing that this is a terrible bottleneck affecting
> > real workloads on real HW, we'll look at it. But until then, please
> > keep it as stupid as possible.
> I've already left the KVM hypervisor code like that - I only updated the
> code here in the main kernel since that keeps the end effect for
> existing systems and workloads the same. I am aware that there has been
> a great deal of attention paid to the barriers we have in the context
> switch path so I am concerned that other people might have a different
> view on adding one.
It does also look odd do a conditional update of SMCR_EL1 and then
unconditionally add a barrier after it, even if the conditional
update suppressed the write.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH 3/3] usb: typec: Use %pe to print error pointers
From: Subasri S @ 2026-07-19 12:55 UTC (permalink / raw)
To: Peter Chen, Greg Kroah-Hartman, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Duncan Sands,
Chas Williams, Minas Harutyunyan, Hans de Goede, Heikki Krogerus,
Badhri Jagan Sridharan
Cc: linux-usb, imx, linux-arm-kernel, linux-kernel, linux-atm-general,
netdev, Subasri S
In-Reply-To: <20260719-usb-ptr_err_patchset-v1-0-85f7f2e4fefb@gmail.com>
Use the %pe format specifier instead of %ld with PTR_ERR() for printing
error pointers in various typec drivers. This prints symbolic
error names (e.g.-ENOMEM) instead of errno numbers (e.g. -12),
making error logs more readable.
This patch fixes coccinelle reported warnings:
./typec/tcpm/tcpm.c:4799:60-67: WARNING: Consider using %pe to print PTR_ERR()
./typec/mux/pi3usb30532.c:143:3-10: WARNING: Consider using %pe to print PTR_ERR()
./typec/mux/pi3usb30532.c:155:3-10: WARNING: Consider using %pe to print PTR_ERR()
./typec/wusb3801.c:281:5-12: WARNING: Consider using %pe to print PTR_ERR()
Compile tested only.
Signed-off-by: Subasri S <subasris1210@gmail.com>
---
drivers/usb/typec/mux/pi3usb30532.c | 8 ++++----
drivers/usb/typec/tcpm/tcpm.c | 2 +-
drivers/usb/typec/wusb3801.c | 4 ++--
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/usb/typec/mux/pi3usb30532.c b/drivers/usb/typec/mux/pi3usb30532.c
index 985683fe49e9..a2357a28ecf4 100644
--- a/drivers/usb/typec/mux/pi3usb30532.c
+++ b/drivers/usb/typec/mux/pi3usb30532.c
@@ -139,8 +139,8 @@ static int pi3usb30532_probe(struct i2c_client *client)
pi->sw = typec_switch_register(dev, &sw_desc);
if (IS_ERR(pi->sw)) {
- dev_err(dev, "Error registering typec switch: %ld\n",
- PTR_ERR(pi->sw));
+ dev_err(dev, "Error registering typec switch: %pe\n",
+ pi->sw);
return PTR_ERR(pi->sw);
}
@@ -151,8 +151,8 @@ static int pi3usb30532_probe(struct i2c_client *client)
pi->mux = typec_mux_register(dev, &mux_desc);
if (IS_ERR(pi->mux)) {
typec_switch_unregister(pi->sw);
- dev_err(dev, "Error registering typec mux: %ld\n",
- PTR_ERR(pi->mux));
+ dev_err(dev, "Error registering typec mux: %pe\n",
+ pi->mux);
return PTR_ERR(pi->mux);
}
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 89eec20a2064..ad10470ea73b 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -4796,7 +4796,7 @@ static void tcpm_typec_connect(struct tcpm_port *port)
port->partner_desc.accessory = TYPEC_ACCESSORY_NONE;
partner = typec_register_partner(port->typec_port, &port->partner_desc);
if (IS_ERR(partner)) {
- dev_err(port->dev, "Failed to register partner (%ld)\n", PTR_ERR(partner));
+ dev_err(port->dev, "Failed to register partner (%pe)\n", partner);
return;
}
diff --git a/drivers/usb/typec/wusb3801.c b/drivers/usb/typec/wusb3801.c
index 6062875fb04a..86d13ab41670 100644
--- a/drivers/usb/typec/wusb3801.c
+++ b/drivers/usb/typec/wusb3801.c
@@ -277,8 +277,8 @@ static void wusb3801_hw_update(struct wusb3801 *wusb3801)
if (partner_type != WUSB3801_STAT_PARTNER_STANDBY) {
wusb3801->partner = typec_register_partner(port, &desc);
if (IS_ERR(wusb3801->partner))
- dev_err(dev, "Failed to register partner: %ld\n",
- PTR_ERR(wusb3801->partner));
+ dev_err(dev, "Failed to register partner: %pe\n",
+ wusb3801->partner);
}
data_role = pwr_role == TYPEC_SOURCE ? TYPEC_HOST : TYPEC_DEVICE;
--
2.43.0
^ permalink raw reply related
* [PATCH 2/3] usb: misc: Use %pe to print error pointers
From: Subasri S @ 2026-07-19 12:55 UTC (permalink / raw)
To: Peter Chen, Greg Kroah-Hartman, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Duncan Sands,
Chas Williams, Minas Harutyunyan, Hans de Goede, Heikki Krogerus,
Badhri Jagan Sridharan
Cc: linux-usb, imx, linux-arm-kernel, linux-kernel, linux-atm-general,
netdev, Subasri S
In-Reply-To: <20260719-usb-ptr_err_patchset-v1-0-85f7f2e4fefb@gmail.com>
Use the %pe format specifier instead of %ld with PTR_ERR() for printing
error pointers in various drivers across usb subsystem.
This prints symbolic error names (e.g.-ENOMEM) instead of
errno numbers (e.g. -12), making error logs more readable.
This patch fixes coccinelle reported warnings:
./misc/usb3503.c:206:5-12: WARNING: Consider using %pe to print PTR_ERR()
./atm/usbatm.c:983:14-21: WARNING: Consider using %pe to print PTR_ERR()
./core/hub.c:5675:6-13: WARNING: Consider using %pe to print PTR_ERR()
./gadget/function/u_serial.c:1315:24-31: WARNING: Consider using %pe to print PTR_ERR()
./dwc2/pci.c:72:3-10: WARNING: Consider using %pe to print PTR_ERR()
Compile tested only.
Signed-off-by: Subasri S <subasris1210@gmail.com>
---
drivers/usb/atm/usbatm.c | 4 ++--
drivers/usb/core/hub.c | 4 ++--
drivers/usb/dwc2/pci.c | 4 ++--
drivers/usb/gadget/function/u_serial.c | 4 ++--
drivers/usb/misc/usb3503.c | 4 ++--
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 9600e1ec0993..c78caa1b57c9 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -979,8 +979,8 @@ static int usbatm_heavy_init(struct usbatm_data *instance)
t = kthread_create(usbatm_do_heavy_init, instance, "%s",
instance->driver->driver_name);
if (IS_ERR(t)) {
- usb_err(instance, "%s: failed to create kernel_thread (%ld)!\n",
- __func__, PTR_ERR(t));
+ usb_err(instance, "%s: failed to create kernel_thread (%pe)!\n",
+ __func__, t);
return PTR_ERR(t);
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5262e11c12cd..5e33e3984499 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -5671,8 +5671,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
descr = usb_get_device_descriptor(udev);
if (IS_ERR(descr)) {
dev_dbg(&udev->dev,
- "can't read device descriptor %ld\n",
- PTR_ERR(descr));
+ "can't read device descriptor %pe\n",
+ descr);
} else {
if (descriptors_changed(udev, descr,
udev->bos)) {
diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c
index f3a1e4232a31..9845327f95c5 100644
--- a/drivers/usb/dwc2/pci.c
+++ b/drivers/usb/dwc2/pci.c
@@ -68,8 +68,8 @@ static int dwc2_pci_probe(struct pci_dev *pci,
phy = usb_phy_generic_register();
if (IS_ERR(phy)) {
- dev_err(dev, "error registering generic PHY (%ld)\n",
- PTR_ERR(phy));
+ dev_err(dev, "error registering generic PHY (%pe)\n",
+ phy);
return PTR_ERR(phy);
}
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index cdd1dfc666c4..da31e5cea0a5 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -1311,8 +1311,8 @@ int gserial_alloc_line_no_console(unsigned char *line_num)
tty_dev = tty_port_register_device(&port->port,
gs_tty_driver, port_num, NULL);
if (IS_ERR(tty_dev)) {
- pr_err("%s: failed to register tty for port %d, err %ld\n",
- __func__, port_num, PTR_ERR(tty_dev));
+ pr_err("%s: failed to register tty for port %d, err %pe\n",
+ __func__, port_num, tty_dev);
ret = PTR_ERR(tty_dev);
mutex_lock(&ports[port_num].lock);
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c
index 759770a13260..3ac57d31376c 100644
--- a/drivers/usb/misc/usb3503.c
+++ b/drivers/usb/misc/usb3503.c
@@ -202,8 +202,8 @@ static int usb3503_probe(struct usb3503 *hub)
hub->clk = devm_clk_get_optional(dev, "refclk");
if (IS_ERR(hub->clk)) {
- dev_err(dev, "unable to request refclk (%ld)\n",
- PTR_ERR(hub->clk));
+ dev_err(dev, "unable to request refclk (%pe)\n",
+ hub->clk);
return PTR_ERR(hub->clk);
}
--
2.43.0
^ permalink raw reply related
* [PATCH 1/3] usb: chipidea: Use %pe to print error pointers
From: Subasri S @ 2026-07-19 12:55 UTC (permalink / raw)
To: Peter Chen, Greg Kroah-Hartman, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Duncan Sands,
Chas Williams, Minas Harutyunyan, Hans de Goede, Heikki Krogerus,
Badhri Jagan Sridharan
Cc: linux-usb, imx, linux-arm-kernel, linux-kernel, linux-atm-general,
netdev, Subasri S
In-Reply-To: <20260719-usb-ptr_err_patchset-v1-0-85f7f2e4fefb@gmail.com>
Use the %pe format specifier instead of %ld with PTR_ERR() for printing
error pointers in imx_get_clks(), ci_hdrc_imx_probe(), and
ci_get_platdata(). This prints symbolic error names (e.g. -ENOMEM)
instead of errno numbers (e.g. -12), making error logs more readable.
This patch fixes coccinelle reported warnings:
./chipidea/ci_hdrc_imx.c:452:5-12: WARNING: Consider using %pe to print PTR_ERR()
./chipidea/ci_hdrc_imx.c:468:5-12: WARNING: Consider using %pe to print PTR_ERR()
./chipidea/ci_hdrc_imx.c:222:4-11: WARNING: Consider using %pe to print PTR_ERR()
./chipidea/ci_hdrc_imx.c:222:24-31: WARNING: Consider using %pe to print PTR_ERR()
./chipidea/core.c:684:4-11: WARNING: Consider using %pe to print PTR_ERR()
Compile-tested only.
Signed-off-by: Subasri S <subasris1210@gmail.com>
---
drivers/usb/chipidea/ci_hdrc_imx.c | 12 ++++++------
drivers/usb/chipidea/core.c | 4 ++--
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 56d2ba824a0b..7bfe37ed68ae 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -218,8 +218,8 @@ static int imx_get_clks(struct device *dev)
if (IS_ERR(data->clk)) {
ret = PTR_ERR(data->clk);
dev_err(dev,
- "Failed to get clks, err=%ld,%ld\n",
- PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
+ "Failed to get clks, err=%pe,%pe\n",
+ data->clk, data->clk_ipg);
return ret;
}
/* Get wakeup clock. Not all of the platforms need to
@@ -448,8 +448,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle");
if (IS_ERR(pinctrl_hsic_idle)) {
dev_err(dev,
- "pinctrl_hsic_idle lookup failed, err=%ld\n",
- PTR_ERR(pinctrl_hsic_idle));
+ "pinctrl_hsic_idle lookup failed, err=%pe\n",
+ pinctrl_hsic_idle);
ret = PTR_ERR(pinctrl_hsic_idle);
goto err_put;
}
@@ -464,8 +464,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
"active");
if (IS_ERR(data->pinctrl_hsic_active)) {
dev_err(dev,
- "pinctrl_hsic_active lookup failed, err=%ld\n",
- PTR_ERR(data->pinctrl_hsic_active));
+ "pinctrl_hsic_active lookup failed, err=%pe\n",
+ data->pinctrl_hsic_active);
ret = PTR_ERR(data->pinctrl_hsic_active);
goto err_put;
}
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 07563be0013f..09db8a4eace2 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -680,8 +680,8 @@ static int ci_get_platdata(struct device *dev,
/* no vbus regulator is needed */
platdata->reg_vbus = NULL;
} else if (IS_ERR(platdata->reg_vbus)) {
- dev_err(dev, "Getting regulator error: %ld\n",
- PTR_ERR(platdata->reg_vbus));
+ dev_err(dev, "Getting regulator error: %pe\n",
+ platdata->reg_vbus);
return PTR_ERR(platdata->reg_vbus);
}
/* Get TPL support */
--
2.43.0
^ permalink raw reply related
* [PATCH 0/3] usb: Use %pe to print error pointers
From: Subasri S @ 2026-07-19 12:55 UTC (permalink / raw)
To: Peter Chen, Greg Kroah-Hartman, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Duncan Sands,
Chas Williams, Minas Harutyunyan, Hans de Goede, Heikki Krogerus,
Badhri Jagan Sridharan
Cc: linux-usb, imx, linux-arm-kernel, linux-kernel, linux-atm-general,
netdev, Subasri S
This patchset replaces PTR_ERR() in format strings with
%pe format specifier across the USB subsystem. %pe prints
symbolic error names (e.g., -ENOMEM) instead of
raw numbers (e.g., -12), making error logs more readable.
These patches fix coccinelle reported warning: "Consider
using %pe to print PTR_ERR()" in usb subsystem.
The patches are grouped by subsystem:
1/3 - chipidea
2/3 - miscellaneous USB drivers
3/3 - typec
All patches are compile-tested on x86_64. Please let me know if
any more testing is needed for any patch.
Signed-off-by: Subasri S <subasris1210@gmail.com>
---
Subasri S (3):
usb: chipidea: Use %pe to print error pointers
usb: misc: Use %pe to print error pointers
usb: typec: Use %pe to print error pointers
drivers/usb/atm/usbatm.c | 4 ++--
drivers/usb/chipidea/ci_hdrc_imx.c | 12 ++++++------
drivers/usb/chipidea/core.c | 4 ++--
drivers/usb/core/hub.c | 4 ++--
drivers/usb/dwc2/pci.c | 4 ++--
drivers/usb/gadget/function/u_serial.c | 4 ++--
drivers/usb/misc/usb3503.c | 4 ++--
drivers/usb/typec/mux/pi3usb30532.c | 8 ++++----
drivers/usb/typec/tcpm/tcpm.c | 2 +-
drivers/usb/typec/wusb3801.c | 4 ++--
10 files changed, 25 insertions(+), 25 deletions(-)
---
base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
change-id: 20260718-usb-ptr_err_patchset-7c5d1547bee7
Best regards,
--
Subasri S <subasris1210@gmail.com>
^ permalink raw reply
* Re: [PATCH] remoteproc: Remove redundant dev_err()/dev_err_probe()
From: Paul Cercueil @ 2026-07-19 12:55 UTC (permalink / raw)
To: Pan Chuang, Bjorn Andersson, Mathieu Poirier, Matthias Brugger,
AngeloGioacchino Del Regno, Maxime Coquelin, Alexandre Torgue,
open list:REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM, open list,
open list:INGENIC JZ47xx SoCs,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support,
open list:ARM/QUALCOMM MAILING LIST,
moderated list:ARM/STM32 ARCHITECTURE
In-Reply-To: <20260717065224.600593-1-panchuang@vivo.com>
Hi,
Le vendredi 17 juillet 2026 à 14:52 +0800, Pan Chuang a écrit :
> Since commit 55b48e23f5c4 ("genirq/devres: Add error handling in
> devm_request_*_irq()"), devm_request_irq() and
> devm_request_threaded_irq()
> automatically log detailed error messages on failure. Remove the
> now-redundant driver-specific dev_err() and dev_err_probe() calls.
>
> Signed-off-by: Pan Chuang <panchuang@vivo.com>
For Ingenic:
Acked-by: Paul Cercueil <paul@crapouillou.net>
Cheers,
-Paul
> ---
> drivers/remoteproc/da8xx_remoteproc.c | 2 +-
> drivers/remoteproc/ingenic_rproc.c | 4 +---
> drivers/remoteproc/keystone_remoteproc.c | 4 ++--
> drivers/remoteproc/mtk_scp.c | 4 +---
> drivers/remoteproc/qcom_q6v5.c | 20 +++++---------------
> drivers/remoteproc/qcom_sysmon.c | 2 --
> drivers/remoteproc/qcom_wcnss.c | 4 +---
> drivers/remoteproc/stm32_rproc.c | 3 +--
> 8 files changed, 12 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/remoteproc/da8xx_remoteproc.c
> b/drivers/remoteproc/da8xx_remoteproc.c
> index 23fca7176539..006fa7b56727 100644
> --- a/drivers/remoteproc/da8xx_remoteproc.c
> +++ b/drivers/remoteproc/da8xx_remoteproc.c
> @@ -298,7 +298,7 @@ static int da8xx_rproc_probe(struct
> platform_device *pdev)
> handle_event, 0, "da8xx-
> remoteproc",
> rproc);
> if (ret)
> - return dev_err_probe(dev, ret,
> "devm_request_threaded_irq error\n");
> + return ret;
>
> /*
> * rproc_add() can end up enabling the DSP's clk with the
> DSP
> diff --git a/drivers/remoteproc/ingenic_rproc.c
> b/drivers/remoteproc/ingenic_rproc.c
> index 1b78d8ddeacf..252519f48964 100644
> --- a/drivers/remoteproc/ingenic_rproc.c
> +++ b/drivers/remoteproc/ingenic_rproc.c
> @@ -219,10 +219,8 @@ static int ingenic_rproc_probe(struct
> platform_device *pdev)
>
> ret = devm_request_irq(dev, vpu->irq, vpu_interrupt,
> IRQF_NO_AUTOEN,
> "VPU", rproc);
> - if (ret < 0) {
> - dev_err(dev, "Failed to request IRQ\n");
> + if (ret < 0)
> return ret;
> - }
>
> ret = devm_rproc_add(dev, rproc);
> if (ret) {
> diff --git a/drivers/remoteproc/keystone_remoteproc.c
> b/drivers/remoteproc/keystone_remoteproc.c
> index 83763d640c4e..407d6034f748 100644
> --- a/drivers/remoteproc/keystone_remoteproc.c
> +++ b/drivers/remoteproc/keystone_remoteproc.c
> @@ -411,7 +411,7 @@ static int keystone_rproc_probe(struct
> platform_device *pdev)
> ret = devm_request_irq(dev, ksproc->irq_ring,
> keystone_rproc_vring_interrupt,
> IRQF_NO_AUTOEN, dev_name(dev),
> ksproc);
> if (ret)
> - return dev_err_probe(dev, ret, "failed to request
> vring interrupt\n");
> + return ret;
>
> ksproc->irq_fault = platform_get_irq_byname(pdev,
> "exception");
> if (ksproc->irq_fault < 0)
> @@ -419,7 +419,7 @@ static int keystone_rproc_probe(struct
> platform_device *pdev)
> ret = devm_request_irq(dev, ksproc->irq_fault,
> keystone_rproc_exception_interrupt,
> IRQF_NO_AUTOEN, dev_name(dev),
> ksproc);
> if (ret)
> - return dev_err_probe(dev, ret, "failed to enable
> exception interrupt\n");
> + return ret;
>
> ksproc->kick_gpio = devm_gpiod_get(dev, "kick", GPIOD_ASIS);
> ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio);
> diff --git a/drivers/remoteproc/mtk_scp.c
> b/drivers/remoteproc/mtk_scp.c
> index 436656bdfa8b..9751acc2bf83 100644
> --- a/drivers/remoteproc/mtk_scp.c
> +++ b/drivers/remoteproc/mtk_scp.c
> @@ -1246,10 +1246,8 @@ static struct mtk_scp *scp_rproc_init(struct
> platform_device *pdev,
> scp_irq_handler,
> IRQF_ONESHOT,
> pdev->name, scp);
>
> - if (ret) {
> - dev_err(dev, "failed to request irq\n");
> + if (ret)
> goto remove_subdev;
> - }
>
> return scp;
>
> diff --git a/drivers/remoteproc/qcom_q6v5.c
> b/drivers/remoteproc/qcom_q6v5.c
> index 0206a4a19254..1075ef4027b7 100644
> --- a/drivers/remoteproc/qcom_q6v5.c
> +++ b/drivers/remoteproc/qcom_q6v5.c
> @@ -302,10 +302,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5,
> struct platform_device *pdev,
> NULL, q6v5_wdog_interrupt,
> IRQF_TRIGGER_RISING |
> IRQF_ONESHOT,
> "q6v5 wdog", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
> if (q6v5->fatal_irq < 0)
> @@ -315,10 +313,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5,
> struct platform_device *pdev,
> NULL, q6v5_fatal_interrupt,
> IRQF_TRIGGER_RISING |
> IRQF_ONESHOT,
> "q6v5 fatal", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire fatal
> IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
> if (q6v5->ready_irq < 0)
> @@ -328,10 +324,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5,
> struct platform_device *pdev,
> NULL, q6v5_ready_interrupt,
> IRQF_TRIGGER_RISING |
> IRQF_ONESHOT,
> "q6v5 ready", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire ready
> IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->handover_irq = platform_get_irq_byname(pdev,
> "handover");
> if (q6v5->handover_irq < 0)
> @@ -342,10 +336,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5,
> struct platform_device *pdev,
> IRQF_TRIGGER_RISING |
> IRQF_ONESHOT |
> IRQF_NO_AUTOEN,
> "q6v5 handover", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire handover
> IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
> if (q6v5->stop_irq < 0)
> @@ -355,10 +347,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5,
> struct platform_device *pdev,
> NULL, q6v5_stop_interrupt,
> IRQF_TRIGGER_RISING |
> IRQF_ONESHOT,
> "q6v5 stop", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire stop-ack
> IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop",
> &q6v5->stop_bit);
> if (IS_ERR(q6v5->state)) {
> diff --git a/drivers/remoteproc/qcom_sysmon.c
> b/drivers/remoteproc/qcom_sysmon.c
> index a0830a48b1f4..61e1038328e8 100644
> --- a/drivers/remoteproc/qcom_sysmon.c
> +++ b/drivers/remoteproc/qcom_sysmon.c
> @@ -662,8 +662,6 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct
> rproc *rproc,
> IRQF_TRIGGER_RISING
> | IRQF_ONESHOT,
> "q6v5 shutdown-ack",
> sysmon);
> if (ret) {
> - dev_err(sysmon->dev,
> - "failed to acquire shutdown-ack
> IRQ\n");
> kfree(sysmon);
> return ERR_PTR(ret);
> }
> diff --git a/drivers/remoteproc/qcom_wcnss.c
> b/drivers/remoteproc/qcom_wcnss.c
> index 3392c9380202..e9a00efe97f6 100644
> --- a/drivers/remoteproc/qcom_wcnss.c
> +++ b/drivers/remoteproc/qcom_wcnss.c
> @@ -521,10 +521,8 @@ static int wcnss_request_irq(struct qcom_wcnss
> *wcnss,
> NULL, thread_fn,
> IRQF_TRIGGER_RISING |
> IRQF_ONESHOT,
> "wcnss", wcnss);
> - if (ret) {
> - dev_err(&pdev->dev, "request %s IRQ failed\n",
> name);
> + if (ret)
> return ret;
> - }
>
> /* Return the IRQ number if the IRQ was successfully
> acquired */
> return irq_number;
> diff --git a/drivers/remoteproc/stm32_rproc.c
> b/drivers/remoteproc/stm32_rproc.c
> index 0e5d64fbe52c..1fe4cdc0a13a 100644
> --- a/drivers/remoteproc/stm32_rproc.c
> +++ b/drivers/remoteproc/stm32_rproc.c
> @@ -682,8 +682,7 @@ static int stm32_rproc_parse_dt(struct
> platform_device *pdev,
> err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
> dev_name(dev), pdev);
> if (err)
> - return dev_err_probe(dev, err,
> - "failed to request wdg
> irq\n");
> + return err;
>
> ddata->wdg_irq = irq;
>
^ permalink raw reply
* Re: [PATCH v12 02/29] arm64/fpsimd: Update FA64 and ZT0 enables when loading SME state
From: Mark Brown @ 2026-07-19 12:40 UTC (permalink / raw)
To: Marc Zyngier
Cc: Fuad Tabba, Mark Rutland, Joey Gouly, Catalin Marinas,
Suzuki K Poulose, Will Deacon, Paolo Bonzini, Jonathan Corbet,
Shuah Khan, Oliver Upton, Dave Martin, Ben Horgan,
Jean-Philippe Brucker, linux-arm-kernel, kvmarm, linux-kernel,
kvm, linux-doc, linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <87a4rnqsuu.wl-maz@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1146 bytes --]
On Sun, Jul 19, 2026 at 09:35:53AM +0100, Marc Zyngier wrote:
> Mark Brown <broonie@kernel.org> wrote:
> > I've gone and implemented the first which will suppress the isb() for
> > current host kernel SME usage, the second two are starting to get more
> > fiddly than seems sensible to do right now.
> I really wish you didn't optimise anything at all at this stage.
> "Optimisation" is exactly what got us into so much trouble over the
> past two years, and I really don't want SME in KVM to follow the same
> trajectory.
> So leave this is a straight ISB, no optimisation. Once you come back
> with actual data showing that this is a terrible bottleneck affecting
> real workloads on real HW, we'll look at it. But until then, please
> keep it as stupid as possible.
I've already left the KVM hypervisor code like that - I only updated the
code here in the main kernel since that keeps the end effect for
existing systems and workloads the same. I am aware that there has been
a great deal of attention paid to the barriers we have in the context
switch path so I am concerned that other people might have a different
view on adding one.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v11 2/7] i2c: mux: add idle_state property to i2c_mux_core
From: Peter Rosin @ 2026-07-19 12:39 UTC (permalink / raw)
To: Marcus Folkesson
Cc: Wolfram Sang, Michael Hennerich, Bartosz Golaszewski, Andi Shyti,
Andy Shevchenko, Bartosz Golaszewski, linux-i2c, linux-kernel,
linux-arm-kernel
In-Reply-To: <alfZYOKCjf6CKN6i@gmail.com>
On 2026-07-15 21:02, Marcus Folkesson wrote:
> Hi Peter,
>
> On Tue, Jul 14, 2026 at 01:29:01PM +0200, Peter Rosin wrote:
>> Hi Marcus,
>>
>> Sorry for the very late feedback.
>>
>> On 2026-07-13 09:19, Marcus Folkesson wrote:
>>> Muxes treat their channels differently when idle.
>>> Let the mux core have this information to make it available for
>>> internal use.
>>> Reuse the same state values used by CONFIG_MULTIPLEXER.
>>>
>>> Possible idle states are:
>>> - MUX_IDLE_AS_IS: Leave channels as is when idle
>>> - MUX_IDLE_DISCONNECT: Disconnect channel (set HiZ when idle)
>>> - <n>: Enable channel n when idle
>>>
>>> Default value is set to MUX_IDLE_AS_IS.
>>>
>>> Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
>>> ---
>>> drivers/i2c/i2c-mux.c | 1 +
>>> include/linux/i2c-mux.h | 26 ++++++++++++++++++++++++++
>>> 2 files changed, 27 insertions(+)
>>>
>>> diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
>>> index 681a201c239b..edf16683dc83 100644
>>> --- a/drivers/i2c/i2c-mux.c
>>> +++ b/drivers/i2c/i2c-mux.c
>>> @@ -247,6 +247,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
>>> muxc->select = select;
>>> muxc->deselect = deselect;
>>> muxc->max_adapters = max_adapters;
>>> + muxc->idle_state = MUX_IDLE_AS_IS;
>>
>> This is insufficient. AS_IS is simply not an adequate default.
>>
>> For i2c-mux-gpmux, there is currently no way to dig out what
>> the idle state is, as it is not exposed by the mux subsystem. For
>> i2c-mux-gpio, the idle state depends on both the idle-state /and/
>> the i2c-mux-idle-disconnect props. For i2c-mux-pca954x the idle
>> state can be adjusted at runtime. Etc.
>>
>> In short, idle state handling is a bit diverse, and I think this
>> adds to that mess.
>>
>> I think it will be a bit of work to come up with a scheme for the
>> I2C mux core to accurately keep track of what the idle state is.
>> One way to deal with that is to introduce a new "unknown" value
>> that can be the default for all drivers that has not yet figured
>> out how to feed the correct idle state to the core.
>>
>> And that hints at why I think reusing the mux.h bindings #include
>> is bad. The mux subsystem simply has no need for an unknown state,
>> and adding that to mux.h is therefore out of place.
>
> I see.
>
> I think I will introduce a few defines in i2c-mux.c then;
>
>
> #define I2C_MUX_IDLE_UNKNOWN (-1)
> #define I2C_MUX_IDLE_AS_IS (-2)
> #define I2C_MUX_IDLE_DISCONNECT (-3)
Hi!
Please keep AS_IS as -1 and DISCONNECT as -2. Using different
values will make it difficult to get rid of the use of the
defines belonging to the mux subsystem in case the actual
value has crept into some .dtb or something like that.
Also, I think the right thing to do is to put these defines
in the i2c-mux.h header so that the drivers can find them.
I assume .c was a typo?
> [...]
>
> struct i2c_mux_core {
>
> [...]
>
> /*
> * The mux state to use when not active.
This is not 100% accurate. The value stored here is never
actually used to set the idle state. The idle_state here is
only what the driver has declared that the idle_state is.
Perhaps word it like this instead?
* The mux state used by the driver when idle.
Agreed, subtle difference, but...
In the future, drivers (most of them) could be changed to
use this variable to store the actual idle state. But, as
mentioned, that's not easy for i2c-mux-gpmux since the idle
state is under the control of the the mux subsystem in that
case.
Cheers,
Peter
> * Possible idle states are:
> * - I2C_MUX_IDLE_UNKNOWN: Unknown idle state
> * - I2C_MUX_IDLE_AS_IS: Leave channels as is when idle
> * - I2C_MUX_IDLE_DISCONNECT: Disconnect channel (set HiZ when idle)
> * - <n>: Enable channel n (starting from 0) when idle"
> *
> * Default value is set to I2C_MUX_IDLE_UNKNOWN.
> */
> int idle_state;
>
> [...]
> };
^ permalink raw reply
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