* Re: [PATCH v2 1/3] dt-bindings: power: limits: Describe Qualcomm SPEL hardware
From: Krzysztof Kozlowski @ 2026-06-24 10:45 UTC (permalink / raw)
To: Manaf Meethalavalappu Pallikunhi
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Rafael J. Wysocki,
Bjorn Andersson, Konrad Dybcio, Daniel Lezcano, Gaurav Kohli,
linux-arm-msm, devicetree, linux-kernel, linux-pm
In-Reply-To: <db8f06fa-0dda-4a22-baaf-8a708d43e113@oss.qualcomm.com>
On 23/06/2026 11:47, Manaf Meethalavalappu Pallikunhi wrote:
> Hi Krzysztof,
>
>
> On 6/22/2026 5:58 PM, Krzysztof Kozlowski wrote:
>> On Sat, Jun 20, 2026 at 02:09:08AM +0530, Manaf Meethalavalappu Pallikunhi wrote:
>>> The Qualcomm SoC Power and Electrical Limits (SPEL) provides hardware
>>> based power monitoring and limiting capabilities for various domains.
>>>
>>> Add a DeviceTree binding to describe the SPEL block on Qualcomm's SoC.
>>>
>>> Signed-off-by: Manaf Meethalavalappu Pallikunhi <manaf.pallikunhi@oss.qualcomm.com>
>>> ---
>>> .../bindings/power/limits/qcom,spel.yaml | 47 ++++++++++++++++++++++
>>> MAINTAINERS | 6 +++
>>> 2 files changed, 53 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/power/limits/qcom,spel.yaml b/Documentation/devicetree/bindings/power/limits/qcom,spel.yaml
>>
>> What is "limits" directory for? What sort of class of devices fit there?
>
> Added for devices that integrate with the powercap framework (exposed
> via sys/class/powercap). These devices are responsible for enforcing and
That's a driver answer. I asked about class of devices. powercap
framework is Linux thing, not a class of devices.
Please describe hardware, not Linux frameworks.
> monitoring power consumption limits across different domains, such as
> the system, SoC, or specific subsystems. Any other better directory ?
I don't know what is this hardware doing and commit msg is quite short
on explanation. Power monitoring is usually hwmon, but probably this is
not a hwmon.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3 07/15] drm/tidss: oldi: Remove define for unused register OLDI_LB_CTRL
From: Swamil Jain @ 2026-06-24 10:43 UTC (permalink / raw)
To: Tomi Valkeinen, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lee Jones, Aradhya Bhatia,
Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Louis Chauvet
Cc: devicetree, dri-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <20260529-beagley-ai-display-v3-7-7fefdc5d1adf@ideasonboard.com>
On 29-05-2026 14:15, Tomi Valkeinen wrote:
> OLDI_LB_CTRL define is not used, and doesn't seem to exist at least on
> some SoCs. Let's remove the define.
>
> Tested-by: Swamil Jain <s-jain1@ti.com>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> ---
Reviewed-by: Swamil Jain <s-jain1@ti.com>
> drivers/gpu/drm/tidss/tidss_oldi.h | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/tidss/tidss_oldi.h b/drivers/gpu/drm/tidss/tidss_oldi.h
> index 8cd535c5ee65..a361e6dbfce3 100644
> --- a/drivers/gpu/drm/tidss/tidss_oldi.h
> +++ b/drivers/gpu/drm/tidss/tidss_oldi.h
> @@ -20,7 +20,6 @@ struct tidss_oldi;
>
> /* Register offsets */
> #define OLDI_PD_CTRL 0x100
> -#define OLDI_LB_CTRL 0x104
>
> /* Power control bits */
> #define OLDI_PWRDOWN_TX(n) BIT(n)
>
^ permalink raw reply
* Re: [PATCH v5 04/12] i3c: master: Add support for devices using SETAASA
From: sashiko-bot @ 2026-06-24 10:43 UTC (permalink / raw)
To: Akhil R; +Cc: linux-hwmon, devicetree, robh, linux-i3c, conor+dt, Frank.Li
In-Reply-To: <20260624102153.1770072-5-akhilrajeev@nvidia.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] SETAASA broadcast is sent before SETDASA direct assignments, which breaks initialization for devices that natively support SETAASA but are configured for SETDASA.
Pre-existing issues:
- [High] Missing RSTDAA on error path due to premature address slot clearing leads to bus address collision.
- [High] Double free and Use-After-Free of `desc->dev` when `device_register()` fails.
--
commit 08b7cd00b36fcaa4fe6292af27e273df6dc64b5a
Author: Akhil R <akhilrajeev@nvidia.com>
i3c: master: Add support for devices using SETAASA
Add support for devices using SETAASA attached to DDR5 memory modules that
do not support ENTDAA. Devices using SETAASA assign their pre-defined static
addresses as dynamic addresses during DAA.
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index 4bba2bad897a7..3deae8cdae525 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
[ ... ]
> @@ -1878,6 +1924,22 @@ static int i3c_master_early_i3c_dev_add(struct i3c_master_controller *master,
> if (ret)
> goto err_free_dev;
>
> + /*
> + * For devices using SETAASA instead of ENTDAA, the address is statically
> + * assigned. Update the dynamic address to the provided static address.
> + * Reattach the I3C device after updating the dynamic address with the same
> + * static address. It is not mandatory for such devices to implement CCC
> + * commands like GETPID, GETDCR etc. Hence, we can return after reattaching.
> + */
> + if (i3cdev->boardinfo->static_addr_method & I3C_ADDR_METHOD_SETAASA) {
> + i3cdev->info.dyn_addr = i3cdev->boardinfo->static_addr;
> + ret = i3c_master_reattach_i3c_dev_locked(i3cdev, 0);
> + if (ret)
> + goto err_rstdaa;
> +
> + return 0;
> + }
> +
[Severity: High]
This is a pre-existing issue, but missing RSTDAA on the error path due to
premature address slot clearing can lead to bus address collisions.
In i3c_master_early_i3c_dev_add(), the driver assigns the dynamic address
with SETDASA and reattaches the device. If reattaching fails, the error
path internally calls i3c_master_put_i3c_addrs(), which clears the
init_dyn_addr slot status back to I3C_ADDR_SLOT_FREE.
When the code jumps to err_rstdaa:
err_rstdaa:
i3c_master_rstdaa_locked(master, i3cdev->boardinfo->init_dyn_addr);
It calls i3c_master_rstdaa_locked() to reset the device's dynamic address.
However, i3c_master_rstdaa_locked() verifies the slot status:
drivers/i3c/master.c:i3c_master_rstdaa_locked() {
...
if (addr != I3C_BROADCAST_ADDR && addrstat != I3C_ADDR_SLOT_I3C_DEV)
return -EINVAL;
...
}
Because the slot was just freed, the function silently returns without
sending the RSTDAA CCC command.
Will this allow the hardware device to continue squatting on the dynamic
address while the master considers the slot free, causing collisions later?
> ret = i3c_master_setdasa_locked(master, i3cdev->info.static_addr,
> i3cdev->boardinfo->init_dyn_addr);
[ ... ]
> @@ -2232,6 +2294,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
> if (ret)
> goto err_bus_cleanup;
>
> + if (master->addr_method & I3C_ADDR_METHOD_SETAASA) {
> + ret = i3c_master_setaasa_locked(master);
> + if (ret)
> + goto err_bus_cleanup;
> + }
> +
[Severity: High]
Is it possible that sending the SETAASA broadcast before direct SETDASA
assignments breaks initialization for devices that natively support SETAASA
but are configured for SETDASA?
According to the I3C specification, any device on the bus natively supporting
SETAASA will respond to this broadcast by adopting its static address as its
dynamic address.
After this broadcast, the driver iterates through devices and attempts to
assign custom dynamic addresses via direct SETDASA commands:
drivers/i3c/master.c:i3c_master_early_i3c_dev_add() {
...
ret = i3c_master_setdasa_locked(master, i3cdev->info.static_addr,
i3cdev->boardinfo->init_dyn_addr);
...
}
Since the target device already adopted its dynamic address during the
SETAASA broadcast, it is no longer in the unassigned state and will NACK
the subsequent SETDASA command.
Could this cause device initialization to abort entirely?
Should SETDASA direct assignments be executed before broadcasting SETAASA?
> /*
> * Reserve init_dyn_addr first, and then try to pre-assign dynamic
> * address and retrieve device information if needed.
[ ... ]
[Severity: High]
This isn't a bug introduced by this patch, but there is a potential double
free and use-after-free of desc->dev when device_register() fails.
In i3c_master_register_new_i3c_devs(), if device_register() fails,
put_device() is called:
drivers/i3c/master.c:i3c_master_register_new_i3c_devs() {
...
ret = device_register(&desc->dev->dev);
if (ret) {
dev_err(&master->dev, "Failed to add I3C device (err = %d)\n", ret);
put_device(&desc->dev->dev);
}
...
}
This drops the reference count to 0 and triggers i3c_device_release(), which
frees desc->dev via kfree(i3cdev). However, the pointer desc->dev is not set
to NULL and remains dangling in the master->bus.devs.i3c list.
Later, when the master module is unloaded or unregistered, the cleanup
iterates over the list:
drivers/i3c/master.c:i3c_master_unregister_i3c_devs() {
...
if (!i3cdev->dev)
continue;
i3cdev->dev->desc = NULL;
if (device_is_registered(&i3cdev->dev->dev))
device_unregister(&i3cdev->dev->dev);
else
put_device(&i3cdev->dev->dev);
i3cdev->dev = NULL;
...
}
Because i3cdev->dev is a dangling pointer, the check passes. This leads to
writing to i3cdev->dev->desc (use-after-free) and calling put_device() again
(double free).
Could we set desc->dev to NULL after put_device() in the registration error
path?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624102153.1770072-1-akhilrajeev@nvidia.com?part=4
^ permalink raw reply
* Re: [PATCH v5 06/12] i3c: master: match I3C device through DT and ACPI
From: sashiko-bot @ 2026-06-24 10:42 UTC (permalink / raw)
To: Akhil R; +Cc: robh, conor+dt, Frank.Li, linux-i3c, linux-hwmon, devicetree
In-Reply-To: <20260624102153.1770072-7-akhilrajeev@nvidia.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Suppressing the native I3C modalias breaks module autoloading for standard (non-SETAASA) I3C devices that possess an OF or ACPI node.
Pre-existing issues:
- [Critical] Kernel stack memory disclosure in `i3c_device_uevent`, `modalias_show`, and `i3c_device_match_id` when `i3cdev->desc` is NULL.
- [High] Lockless access to `i3cdev->desc` in `i3c_device_match()` can lead to a Use-After-Free during concurrent DAA or Hot-Join operations.
--
commit 027ebb9082e984584613be936bd42a0829ebd9c6
Author: Akhil R <akhilrajeev@nvidia.com>
i3c: master: match I3C device through DT and ACPI
This patch allows SETAASA-based I3C devices to match through Device Tree
or ACPI when they cannot be identified by PID or DCR. It emits OF and ACPI
modaliases so firmware-matched devices can autoload their drivers.
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -320,6 +321,15 @@ static int i3c_device_uevent(const struct device *dev, struct kobj_uevent_env *e
> const struct i3c_device *i3cdev = dev_to_i3cdev(dev);
> struct i3c_device_info devinfo;
> u16 manuf, part, ext;
> + int rc;
> +
> + rc = of_device_uevent_modalias(dev, env);
> + if (rc != -ENODEV)
> + return rc;
[Severity: High]
Does returning early here break module autoloading for standard I3C devices
that have an OF or ACPI node?
If a standard non-SETAASA device has an OF node, it will only emit the
of: modalias and skip generating the standard i3c: modalias.
If the device's driver only provides an I3C id_table, udev might fail to
find a matching module. Furthermore, since i3c_device_match() restricts
of_driver_match_device() strictly to devices with the
I3C_ADDR_METHOD_SETAASA flag, standard I3C devices wouldn't be able to match
via Device Tree either.
> +
> + rc = acpi_device_uevent_modalias(dev, env);
> + if (rc != -ENODEV)
> + return rc;
>
> if (i3cdev->desc)
> devinfo = i3cdev->desc->info;
[Severity: Critical]
This is a pre-existing issue, but can this leak uninitialized stack memory
to userspace?
When a device is unregistered, i3c_master_unregister_i3c_devs() sets
i3cdev->dev->desc = NULL before calling device_unregister(). This triggers
a uevent that calls i3c_device_uevent().
If i3cdev->desc is NULL, the devinfo stack variable is never initialized,
but its contents (like devinfo.pid and devinfo.dcr) are still used to
construct the modalias string right below this block.
Could this expose kernel stack memory via netlink messages, or via sysfs
reads in modalias_show()? A similar uninitialized read also occurs in
i3c_device_match_id() when i3c_device_get_info() is called with a NULL
descriptor.
[ ... ]
> @@ -345,15 +355,32 @@ static int i3c_device_match(struct device *dev, const struct device_driver *drv)
> {
> struct i3c_device *i3cdev;
> const struct i3c_driver *i3cdrv;
> + u8 static_addr_method = 0;
>
> if (dev->type != &i3c_device_type)
> return 0;
>
> i3cdev = dev_to_i3cdev(dev);
> i3cdrv = drv_to_i3cdrv(drv);
> - if (i3c_device_match_id(i3cdev, i3cdrv->id_table))
> +
> + if (i3cdev->desc && i3cdev->desc->boardinfo)
> + static_addr_method = i3cdev->desc->boardinfo->static_addr_method;
[Severity: High]
This is a pre-existing issue, but is it safe to access i3cdev->desc here
without holding the bus read lock?
During dynamic address assignment or hot-join operations,
__i3c_master_add_i3c_dev_locked() may find a duplicate device, reassign
a new descriptor, and free the old descriptor.
Since i3c_device_match() is called by the driver core without acquiring
the bus lock, might a concurrent hot-join thread free i3cdev->desc while
it is being dereferenced here, leading to a use-after-free? This same race
could happen when i3cdev->desc->info is accessed by i3c_device_get_info()
during matching.
> +
> + /*
> + * SETAASA-based devices need not always have a matching ID since
> + * it is not mandatory for such devices to implement deviceinfo
> + * CCC commands. Allow them to register through DT or ACPI.
> + */
> + if (i3cdrv->id_table && i3c_device_match_id(i3cdev, i3cdrv->id_table))
> return 1;
>
> + if (static_addr_method & I3C_ADDR_METHOD_SETAASA) {
> + if (of_driver_match_device(dev, drv))
> + return 1;
> + if (acpi_driver_match_device(dev, drv))
> + return 1;
> + }
> +
> return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624102153.1770072-1-akhilrajeev@nvidia.com?part=6
^ permalink raw reply
* Re: [PATCH v3 1/8] dt-bindings: remoteproc: qcom,pas: add thermal mitigation properties
From: Krzysztof Kozlowski @ 2026-06-24 10:42 UTC (permalink / raw)
To: Daniel Lezcano, Gaurav Kohli
Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Amit Kucheria,
Manivannan Sadhasivam, Konrad Dybcio, Kees Cook,
Gustavo A. R. Silva, cros-qcom-dts-watchers, linux-arm-msm,
linux-remoteproc, devicetree, linux-kernel, linux-pm,
linux-hardening, Manaf Meethalavalappu Pallikunhi
In-Reply-To: <61765401-3397-497d-a0ca-e9bf9d76cc6a@oss.qualcomm.com>
On 18/06/2026 09:17, Daniel Lezcano wrote:
> On 6/16/26 06:21, Krzysztof Kozlowski wrote:
>> On 15/06/2026 14:30, Daniel Lezcano wrote:
>>> Hi Gaurav,
>>>>>> thanks for review, shall i use driver data, which is basically pas
>>>>>> data structure like below:
>>>>>>
>>>>>> static const struct qcom_pas_data {
>>>>>> .crash_reason_smem = 601,
>>>>>> .firmware_name = "cdsp.mdt",
>>>>>> .tmd_names = (const char *[]){"xyz", NULL},
>>>>>> .num_tmds = 1,
>>>>>>
>>>>>> Is something like above acceptable? and this will also help to filter
>>>>>> tmd names as well?
>>>>>
>>>>>
>>>>> How the thermal framework will bind the thermal zone with the TMD ?
>>>>> (node pointer, id) ?
>>>>>
>>>>
>>>> Hi Daniel,
>>>>
>>>> thanks for review.
>>>>
>>>> With id only, in this case instead of taking tmd names from device tree,
>>>> qmi_tmd will take tmd name from pas_data(driver) and register with the
>>>> cooling framework with id only. Please let us know if this looks fine.
>>> May be I'm missing something but:
>>>
>>> - The QMI TMD returns a list of names, not ids
>>> - The QMI TMD may return the list in different order than assumed
>>> - The cooling map index points to the name of the TMD in the DT
>>> - This name is used to match the name in the aformentionned list
>>> - The index in the list and the id in the DT can differ
>>>
>>> Krzysztof , I don't get why having the TMD names as properties is wrong,
>>> they describes the existing TMDs on the system and the cooling maps
>>> index points to the one to be connected with thermal zone.
>>
>>
>> 'xxx-names' have a fixed meaning in DT by convention - assign
>> identifiable strings to the 'xxx'. I miss the property 'tmd' in such
>> case - its definition and meaning. Where is it?
>>
>> But maybe you just want list of strings, so I am open to discuss it - I
>> don't understand the need for this property and commit and property
>> description tell me nothing.
>>
>> Really, this commit message is basically non-existing. It explains what
>> it did and provides that much explanation WHY:
>>
>> "- tmd-names (thermal mitigation device names)"
>>
>> Really? This is the explanation why this change is being made, why this
>> property is needed?
>>
>> So sure, describe the problem being solved and WHY this problem is being
>> solved that way. Maybe it will fit DT.
>
> Ok, I understand
>
> Let me try to clarify.
>
> When the QMI TMD protocol is initialized, the list of available TMDs
> provided by the service is requested. They are identified by a *string*
> not a numerical id.
>
> We can not assume the list is always in the same order because the QMI
> TMD is a separate subsystem and the interface is the protocol. The
> protocol does not refer to any TMD with an index but its name.
> Hardcoding an index here is not possible.
Still given device (remoteproc) will provide a fixed, one name for TMD.
That name is fully deducible from the compatible.
>
> The name identifies the TMD we connect to and in return we receive a
> handler to use when sending the QMI messages.
>
> That is for the driver part.
>
> I understand for the DT, it is possible to not give the tmd-names
> because the it can go into the driver's data structure.
>
> But the thermal framework won't be able to associate a cooling device
> (one TMD) with a thermal zone because the cooling mapping must point to
> a cooling device in the DT.
>
> Initially, Gaurav sent a description where each TMD was a child node of
> the remote proc node. And you rightfully told us it is no longer the way
> to go as stated in the documentation. And you suggested to replace the
> child nodes with an array with the tmd-names and add an index in the
> cooling map pointing to this array.
There was only one child node. It was one-to-one mapping, thus I don't
think I suggested using any tmd-names.
Here is the code:
https://lore.kernel.org/linux-devicetree/20251223123227.1317244-4-gaurav.kohli@oss.qualcomm.com/
and I clearly see one cooling only:
+ cooling:
+ $ref: /schemas/thermal/qcom,qmi-cooling.yaml#
Therefore I still do not see the need of tmd-names. You know the name of
cooling device, because you have strict one-to-one mapping.
>
> The thermal framework has been extended to support this new format and
> associate the cooling device with the thermal zone. This change is now
> upstream for v7.2 [1]
>
> The resulting implementation is the driver gets the tmd-names array
> property. For each name, it connects to the QMI TMD and register the
> cooling device with the index corresponding to the name position on the
> tmd-names array.
>
> On the other side, the thermal framework parses the cooling-map, gets
> the index and do the association (binding).
>
> The tmd-names array property replaces the child nodes and allows to do
> the mapping between the string based identifier with a numerical id.
>
> I hope that clarifies the approach.
>
> -- Daniel
>
> [1]
> https://lore.kernel.org/all/20260526140802.1059293-12-daniel.lezcano@oss.qualcomm.com/
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v5 12/12] arm64: defconfig: Enable I3C and SPD5118 hwmon
From: sashiko-bot @ 2026-06-24 10:40 UTC (permalink / raw)
To: Akhil R; +Cc: conor+dt, linux-hwmon, robh, devicetree, linux-i3c, Frank.Li
In-Reply-To: <20260624102153.1770072-13-akhilrajeev@nvidia.com>
> Enable I3C subsystem (I3C), Synopsys DesignWare I3C master controller
> (DW_I3C_MASTER), and SPD5118 hwmon temperature sensor (SENSORS_SPD5118)
> as modules.
>
> The NVIDIA Vera CPU uses SOCAMM LPDDR5X memory module, which contains
> SPD5118 (JEDEC JESD300) compliant temperature sensor. This sensor is
> accessible over the I3C bus through the DesignWare I3C controller present
> on the SoC. Enabling these configs allows monitoring memory module
> temperatures on platforms such as Vera Rubin. Vera is an ACPI-based
> platform and does not use device tree.
>
> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624102153.1770072-1-akhilrajeev@nvidia.com?part=12
^ permalink raw reply
* Re: [PATCH v3 06/15] drm/tidss: Remove extra pm_runtime_mark_last_busy
From: Swamil Jain @ 2026-06-24 10:39 UTC (permalink / raw)
To: Tomi Valkeinen, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lee Jones, Aradhya Bhatia,
Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Louis Chauvet
Cc: devicetree, dri-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <20260529-beagley-ai-display-v3-6-7fefdc5d1adf@ideasonboard.com>
On 29-05-2026 14:15, Tomi Valkeinen wrote:
> pm_runtime_put_autosuspend() calls pm_runtime_mark_last_busy(), so no
> need to call pm_runtime_mark_last_busy() explicitly in the driver.
>
> Tested-by: Swamil Jain <s-jain1@ti.com>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> ---
Reviewed-by: Swamil Jain <s-jain1@ti.com>
> drivers/gpu/drm/tidss/tidss_drv.c | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c
> index 1c8cc18bc53c..5cb3e746aeb3 100644
> --- a/drivers/gpu/drm/tidss/tidss_drv.c
> +++ b/drivers/gpu/drm/tidss/tidss_drv.c
> @@ -42,8 +42,6 @@ void tidss_runtime_put(struct tidss_device *tidss)
> {
> int r;
>
> - pm_runtime_mark_last_busy(tidss->dev);
> -
> r = pm_runtime_put_autosuspend(tidss->dev);
> WARN_ON(r < 0);
> }
>
^ permalink raw reply
* Re: [PATCH v5 03/12] i3c: master: Support ACPI enumeration of child devices
From: sashiko-bot @ 2026-06-24 10:38 UTC (permalink / raw)
To: Akhil R; +Cc: robh, devicetree, conor+dt, linux-hwmon, linux-i3c, Frank.Li
In-Reply-To: <20260624102153.1770072-4-akhilrajeev@nvidia.com>
> Although the existing subsystem allows host controllers to register
> through the ACPI table, it was not possible to describe I3C or I2C
> devices when using ACPI. This is because the driver relied on the reg
> property to retrieve the PID, static address, etc., whereas ACPI uses
> _ADR or serial resources to describe such devices.
>
> Read _ADR and LVR from ACPI resources and extract the data as per the
> ACPI specification for an I3C bus. Also read mipi-i3c-static-address as
> per the MIPI DISCO specifications [1] to get the static address to be
> used.
>
> Enable describing I3C or I2C devices in the ACPI table. This is required
> if the device uses a static address or if it needs device-specific
> properties.
>
> [1] https://www.mipi.org/mipi-disco-for-i3c-download
>
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624102153.1770072-1-akhilrajeev@nvidia.com?part=3
^ permalink raw reply
* Re: [PATCH v5 07/12] i3c: dw-i3c-master: Add SETAASA as supported CCC
From: sashiko-bot @ 2026-06-24 10:34 UTC (permalink / raw)
To: Akhil R; +Cc: linux-i3c, robh, Frank.Li, conor+dt, devicetree, linux-hwmon
In-Reply-To: <20260624102153.1770072-8-akhilrajeev@nvidia.com>
> Add SETAASA and SETHID to the supported list of CCC commands for
> DesignWare I3C host controller.
>
> SETAASA is a broadcast command that assigns predefined static addresses
> to all I3C devices on the bus.
>
> SETHID is to stop HID bit flipping by the SPD Hub to which the SPD devices
> are connected. It is a prerequisite command to be sent before SETAASA as
> recommended by JESD300-5 and JESD403 sideband bus specifications.
>
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624102153.1770072-1-akhilrajeev@nvidia.com?part=7
^ permalink raw reply
* Re: [PATCH 2/2] arm64: dts: axiado: Add initial support for AX3005 SoC and eval board
From: sashiko-bot @ 2026-06-24 10:34 UTC (permalink / raw)
To: Swark Yang; +Cc: robh, conor+dt, devicetree
In-Reply-To: <20260624-upstream-axiado-ax3005-upstream-v1-2-c05bd0bc9124@axiado.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] All secondary CPUs share the exact same `cpu-release-addr` for the SMP spin-table.
- [Medium] The ARMv8 architectural timer and GIC maintenance interrupts are incorrectly configured as active-high.
- [Low] Mismatch between the memory node's unit address and its `reg` base address.
- [Low] Missing `clock-frequency` property in the `timer` node despite indicating firmware did not configure registers.
--
commit 9c7369abb8e810cca148d4bf6cc3f8266fdfad15
Author: Swark Yang <syang@axiado.com>
Subject: arm64: dts: axiado: Add initial support for AX3005 SoC and eval board
This commit adds initial device tree support for the AX3005 SoC and its
evaluation board. The AX3005 is a multi-core SoC featuring 4 Cortex-A53
cores, and this adds the CPUs, timer, GPIO, UART, I2C, I3C, SPI and USB
controllers.
Link: None
> diff --git a/arch/arm64/boot/dts/axiado/ax3005-evk.dts b/arch/arm64/boot/dts/axiado/ax3005-evk.dts
> new file mode 100644
> --- /dev/null
> +++ b/arch/arm64/boot/dts/axiado/ax3005-evk.dts
[ ... ]
> + memory@0 {
> + device_type = "memory";
> + /* Cortex-A53 will use following memory map */
> + reg = <0x0 0x81000000 0x0 0x7f000000>;
> + };
[Severity: Low]
Should this unit address match the base address? The memory node specifies a
base address of 0x81000000 in its reg property, but the unit address is @0.
This will cause a dtc compilation warning for unit_address_vs_reg.
[ ... ]
> diff --git a/arch/arm64/boot/dts/axiado/ax3005.dtsi b/arch/arm64/boot/dts/axiado/ax3005.dtsi
> new file mode 100644
> --- /dev/null
> +++ b/arch/arm64/boot/dts/axiado/ax3005.dtsi
[ ... ]
> + cpu1: cpu@1 {
> + compatible = "arm,cortex-a53";
> + device_type = "cpu";
> + reg = <0x0 0x1>;
> + enable-method = "spin-table";
> + cpu-release-addr = <0x0 0x80002fa0>;
[Severity: High]
Are all secondary CPUs supposed to share the exact same cpu-release-addr?
If cpu1, cpu2, and cpu3 all poll 0x80002fa0, the first wake event will
trigger all of them simultaneously. Will this cause concurrent jumps into
secondary_startup and corrupt the stack during SMP bring-up since they would
all attempt to consume the single cpu_boot_task?
[ ... ]
> + timer {
> + compatible = "arm,armv8-timer";
> + interrupt-parent = <&gic500>;
> + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_PPI 10 IRQ_TYPE_LEVEL_HIGH>;
[Severity: Medium]
Should the ARMv8 architectural timer PPIs be active-low? The generic timer
output signals usually generate active-low level-sensitive interrupts
(IRQ_TYPE_LEVEL_LOW), but these are defined as IRQ_TYPE_LEVEL_HIGH here.
> + arm,cpu-registers-not-fw-configured;
[Severity: Low]
Does this timer node need a clock-frequency property?
The arm,cpu-registers-not-fw-configured property indicates firmware did not
initialize the timer frequency register. If CNTFRQ_EL0 is actually
unconfigured, omitting the fallback frequency can cause boot warnings or
failure in the timer subsystem.
> + };
[ ... ]
> + gic500: interrupt-controller@40400000 {
> + compatible = "arm,gic-v3";
> + reg = <0x0 0x40400000 0x0 0x10000>,
> + <0x0 0x40500000 0x0 0xc0000>;
> + #address-cells = <2>;
> + #size-cells = <2>;
> + ranges;
> + #interrupt-cells = <3>;
> + interrupt-controller;
> + #redistributor-regions = <1>;
> + interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
[Severity: Medium]
Does the GICv3 VGIC maintenance interrupt need to be active-low? Similar to
the timer interrupts, the architecture specifies this as an active-low
level-sensitive interrupt, but it is declared as IRQ_TYPE_LEVEL_HIGH here.
> + };
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624-upstream-axiado-ax3005-upstream-v1-0-c05bd0bc9124@axiado.com?part=2
^ permalink raw reply
* Re: [PATCH v5 10/12] hwmon: spd5118: Remove 16-bit addressing
From: sashiko-bot @ 2026-06-24 10:33 UTC (permalink / raw)
To: Akhil R; +Cc: linux-i3c, devicetree, conor+dt, robh, linux-hwmon, Frank.Li
In-Reply-To: <20260624102153.1770072-11-akhilrajeev@nvidia.com>
> The intent of introducing 16-bit addressing was to support I3C, but it
> turns out that I3C does not require reading the Legacy Mode register,
> nor any specific encoding for page translation. The testing of 16-bit
> code was limited and there are no known users for this feature. Remove
> the sections that support 16-bit addressing and prepare the driver to
> support I3C appropriately.
>
> Suggested-by: Guenter Roeck <linux@roeck-us.net>
> Acked-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624102153.1770072-1-akhilrajeev@nvidia.com?part=10
^ permalink raw reply
* Re: [PATCH v5 09/12] i3c: dw-i3c-master: Add ACPI ID for Tegra410
From: sashiko-bot @ 2026-06-24 10:32 UTC (permalink / raw)
To: Akhil R; +Cc: robh, conor+dt, devicetree, linux-i3c, Frank.Li, linux-hwmon
In-Reply-To: <20260624102153.1770072-10-akhilrajeev@nvidia.com>
> Update variable names to generic names and add Tegra410 ACPI ID to
> support the I3C controller in Tegra410, which is a DesignWare I3C host
> controller.
>
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624102153.1770072-1-akhilrajeev@nvidia.com?part=9
^ permalink raw reply
* Re: [PATCH v5 01/12] dt-bindings: i3c: Add mipi-i3c-static-method to support SETAASA
From: sashiko-bot @ 2026-06-24 10:30 UTC (permalink / raw)
To: Akhil R; +Cc: linux-hwmon, linux-i3c, Frank.Li, devicetree, conor+dt, robh
In-Reply-To: <20260624102153.1770072-2-akhilrajeev@nvidia.com>
> Add the 'mipi-i3c-static-method' property mentioned in the MIPI I3C
> Discovery and Configuration Specification [1] to specify which discovery
> method an I3C device supports during bus initialization. The property is
> a bitmap, where a bit value of 1 indicates support for that method, and 0
> indicates lack of support.
>
> Bit 0: SETDASA CCC (Direct)
> Bit 1: SETAASA CCC (Broadcast)
> Bit 2: Other CCC (vendor / standards extension)
> All other bits are reserved.
>
> It is specifically needed when an I3C device requires SETAASA for the
> address assignment. SETDASA will be supported by default if this property
> is absent, which means for now the property just serves as a flag to
> enable SETAASA, but keep the property as a bitmap to align with the
> specifications.
>
> [1] https://www.mipi.org/mipi-disco-for-i3c-download
>
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624102153.1770072-1-akhilrajeev@nvidia.com?part=1
^ permalink raw reply
* Re: [PATCH 2/2] arm64: dts: socfpga: agilex7-gen2: Add initial device tree
From: Krzysztof Kozlowski @ 2026-06-24 10:26 UTC (permalink / raw)
To: Nazle Asmade, Muhammad Nazim Amirul
Cc: dinguyen@kernel.org, robh@kernel.org, krzk+dt@kernel.org,
conor+dt@kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <4acdd3ee-c7eb-4871-bb59-c2e3eeedda28@altera.com>
On 24/06/2026 12:17, Nazle Asmade, Muhammad Nazim Amirul wrote:
>> SoC without any interface, serial or storage or network, is close to
>> useless one.
>>
>> I don't see a point in having it in mainline. Serial is usually ABSOLUTE
>> minimum.
>>
>> Best regards,
>> Krzysztof
>>
> Hi Krzysztof,
>
> Thank you for the review and fast response!
>
> I ran both dt_binding_check and dtbs_check (with CHECK_DTBS=y) locally —
> both passed without errors. Could you clarify which specific test you
> believe is failing?
I would expect simple-bus schema warning or W=1, because node is placed
outside of soc@, but maybe there is no such.
>
> Regarding "MMIO goes to MMIO" — are you referring to the GIC
Comments are placed in very specific and intentional place. Please read
guides how mailing list in-line review works before posting patches.
> (interrupt-controller@7000000) being placed at the root level instead of
> under the soc bus node?
>
> Regarding the serial console — the platform clock driver is not yet
> upstream, so the UART depends on clkmgr. Would adding the UART with
> clock-frequency be acceptable as an interim solution?
Add complete working serial. Why can't you use fixed placeholder clock?
There are probably multiple ways to solve it, not necessary
clock-frequency and I do not even remember if clock-frequency is allowed.
But if you cannot bring serial, then my comment stays valid: this is
unusable upstream thus is not ready to be posted and merged.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v5 12/12] arm64: defconfig: Enable I3C and SPD5118 hwmon
From: Akhil R @ 2026-06-24 10:21 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
Enable I3C subsystem (I3C), Synopsys DesignWare I3C master controller
(DW_I3C_MASTER), and SPD5118 hwmon temperature sensor (SENSORS_SPD5118)
as modules.
The NVIDIA Vera CPU uses SOCAMM LPDDR5X memory module, which contains
SPD5118 (JEDEC JESD300) compliant temperature sensor. This sensor is
accessible over the I3C bus through the DesignWare I3C controller present
on the SoC. Enabling these configs allows monitoring memory module
temperatures on platforms such as Vera Rubin. Vera is an ACPI-based
platform and does not use device tree.
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
arch/arm64/configs/defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index f2e6ae93e533..65d9eb56e978 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -640,6 +640,8 @@ CONFIG_I2C_UNIPHIER_F=y
CONFIG_I2C_XILINX=m
CONFIG_I2C_RCAR=y
CONFIG_I2C_CROS_EC_TUNNEL=y
+CONFIG_I3C=m
+CONFIG_DW_I3C_MASTER=m
CONFIG_SPI=y
CONFIG_SPI_APPLE=m
CONFIG_SPI_ARMADA_3700=y
@@ -769,6 +771,7 @@ CONFIG_SENSORS_SL28CPLD=m
CONFIG_SENSORS_AMC6821=m
CONFIG_SENSORS_INA2XX=m
CONFIG_SENSORS_INA3221=m
+CONFIG_SENSORS_SPD5118=m
CONFIG_SENSORS_TMP102=m
CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
CONFIG_CPU_THERMAL=y
--
2.43.0
^ permalink raw reply related
* [PATCH v5 11/12] hwmon: spd5118: Add I3C support
From: Akhil R @ 2026-06-24 10:21 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
Add a regmap config and a probe function to support I3C-based
communication with SPD5118 devices.
On an I3C bus, SPD5118 devices are enumerated via SETAASA and always
require an ACPI or device tree entry. Device matching is hence through
the OF match tables only and does not need an I3C class match table. The
device identity is verified in the type registers before proceeding to
the common probe function.
Acked-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/hwmon/Kconfig | 9 ++++---
drivers/hwmon/spd5118.c | 56 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 61 insertions(+), 4 deletions(-)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 5c2d3ff5fce8..c4bf5475fcb3 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -2354,12 +2354,15 @@ config SENSORS_INA3221
config SENSORS_SPD5118
tristate "SPD5118 Compliant Temperature Sensors"
- depends on I2C
+ depends on I3C_OR_I2C
select REGMAP_I2C
+ select REGMAP_I3C if I3C
help
If you say yes here you get support for SPD5118 (JEDEC JESD300)
- compliant temperature sensors. Such sensors are found on DDR5 memory
- modules.
+ compliant temperature sensors using I2C or I3C bus interface.
+ Such sensors are found on DDR5 memory modules.
+
+ This driver supports both I2C and I3C interfaces.
This driver can also be built as a module. If so, the module
will be called spd5118.
diff --git a/drivers/hwmon/spd5118.c b/drivers/hwmon/spd5118.c
index 6ba37a719300..9724cf70b61d 100644
--- a/drivers/hwmon/spd5118.c
+++ b/drivers/hwmon/spd5118.c
@@ -18,6 +18,7 @@
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/i2c.h>
+#include <linux/i3c/device.h>
#include <linux/hwmon.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -464,6 +465,27 @@ static const struct regmap_config spd5118_regmap8_config = {
.num_ranges = ARRAY_SIZE(spd5118_i2c_regmap_range_cfg),
};
+/*
+ * SPD5118 2-byte register address format (JESD300-5, Tables 7 & 20):
+ * Byte 1 (on wire first): MemReg | BlkAddr[0] | Address[5:0]
+ * Byte 2 (on wire second): 0000 | BlkAddr[4:1]
+ *
+ * The address byte (with MemReg and lower address bits) must be sent first,
+ * followed by the upper block address byte. With regmap 16-bit register
+ * format, this maps to little-endian: the low byte of the 16-bit value is
+ * transmitted first. No range config is needed since I3C does not use MR11
+ * page switching.
+ */
+static const struct regmap_config spd5118_regmap_i3c_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0x7ff,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .writeable_reg = spd5118_writeable_reg,
+ .volatile_reg = spd5118_volatile_reg,
+ .cache_type = REGCACHE_MAPLE,
+};
+
static int spd5118_suspend(struct device *dev)
{
struct spd5118_data *data = dev_get_drvdata(dev);
@@ -701,7 +723,39 @@ static struct i2c_driver spd5118_i2c_driver = {
.address_list = IS_ENABLED(CONFIG_SENSORS_SPD5118_DETECT) ? normal_i2c : NULL,
};
-module_i2c_driver(spd5118_i2c_driver);
+/* I3C */
+
+static int spd5118_i3c_probe(struct i3c_device *i3cdev)
+{
+ struct device *dev = i3cdev_to_dev(i3cdev);
+ struct regmap *regmap;
+ u8 regval[2];
+ int err;
+
+ regmap = devm_regmap_init_i3c(i3cdev, &spd5118_regmap_i3c_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed\n");
+
+ err = regmap_bulk_read(regmap, SPD5118_REG_TYPE, regval, 2);
+ if (err)
+ return dev_err_probe(dev, err, "failed to read device type\n");
+
+ if (regval[0] != 0x51 || regval[1] != 0x18)
+ return -ENODEV;
+
+ return spd5118_common_probe(dev, regmap);
+}
+
+static struct i3c_driver spd5118_i3c_driver = {
+ .driver = {
+ .name = "spd5118_i3c",
+ .of_match_table = spd5118_of_ids,
+ .pm = pm_sleep_ptr(&spd5118_pm_ops),
+ },
+ .probe = spd5118_i3c_probe,
+};
+
+module_i3c_i2c_driver(spd5118_i3c_driver, &spd5118_i2c_driver);
MODULE_AUTHOR("René Rebe <rene@exactcode.de>");
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
--
2.43.0
^ permalink raw reply related
* [PATCH v5 10/12] hwmon: spd5118: Remove 16-bit addressing
From: Akhil R @ 2026-06-24 10:21 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
The intent of introducing 16-bit addressing was to support I3C, but it
turns out that I3C does not require reading the Legacy Mode register,
nor any specific encoding for page translation. The testing of 16-bit
code was limited and there are no known users for this feature. Remove
the sections that support 16-bit addressing and prepare the driver to
support I3C appropriately.
Suggested-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/hwmon/spd5118.c | 79 +++--------------------------------------
1 file changed, 5 insertions(+), 74 deletions(-)
diff --git a/drivers/hwmon/spd5118.c b/drivers/hwmon/spd5118.c
index cc40661cab21..6ba37a719300 100644
--- a/drivers/hwmon/spd5118.c
+++ b/drivers/hwmon/spd5118.c
@@ -66,9 +66,6 @@ static const unsigned short normal_i2c[] = {
#define SPD5118_EEPROM_BASE 0x80
#define SPD5118_EEPROM_SIZE (SPD5118_PAGE_SIZE * SPD5118_NUM_PAGES)
-#define PAGE_ADDR0(page) (((page) & BIT(0)) << 6)
-#define PAGE_ADDR1_4(page) (((page) & GENMASK(4, 1)) >> 1)
-
/* Temperature unit in millicelsius */
#define SPD5118_TEMP_UNIT (MILLIDEGREE_PER_DEGREE / 4)
/* Representable temperature range in millicelsius */
@@ -78,7 +75,6 @@ static const unsigned short normal_i2c[] = {
struct spd5118_data {
struct regmap *regmap;
struct mutex nvmem_lock;
- bool is_16bit;
};
/* hwmon */
@@ -348,12 +344,7 @@ static ssize_t spd5118_nvmem_read_page(struct spd5118_data *data, char *buf,
if (offset + count > SPD5118_PAGE_SIZE)
count = SPD5118_PAGE_SIZE - offset;
- if (data->is_16bit) {
- addr = SPD5118_EEPROM_BASE | PAGE_ADDR0(page) |
- (PAGE_ADDR1_4(page) << 8);
- } else {
- addr = page * 0x100 + SPD5118_EEPROM_BASE;
- }
+ addr = page * 0x100 + SPD5118_EEPROM_BASE;
err = regmap_bulk_read(regmap, addr + offset, buf, count);
if (err)
return err;
@@ -473,15 +464,6 @@ static const struct regmap_config spd5118_regmap8_config = {
.num_ranges = ARRAY_SIZE(spd5118_i2c_regmap_range_cfg),
};
-static const struct regmap_config spd5118_regmap16_config = {
- .reg_bits = 16,
- .val_bits = 8,
- .max_register = 0x7ff,
- .writeable_reg = spd5118_writeable_reg,
- .volatile_reg = spd5118_volatile_reg,
- .cache_type = REGCACHE_MAPLE,
-};
-
static int spd5118_suspend(struct device *dev)
{
struct spd5118_data *data = dev_get_drvdata(dev);
@@ -519,8 +501,7 @@ static int spd5118_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(spd5118_pm_ops, spd5118_suspend, spd5118_resume);
-static int spd5118_common_probe(struct device *dev, struct regmap *regmap,
- bool is_16bit)
+static int spd5118_common_probe(struct device *dev, struct regmap *regmap)
{
unsigned int capability, revision, vendor, bank;
struct spd5118_data *data;
@@ -537,8 +518,6 @@ static int spd5118_common_probe(struct device *dev, struct regmap *regmap,
if (!(capability & SPD5118_CAP_TS_SUPPORT))
return -ENODEV;
- data->is_16bit = is_16bit;
-
err = regmap_read(regmap, SPD5118_REG_REVISION, &revision);
if (err)
return err;
@@ -680,69 +659,21 @@ static int spd5118_i2c_init(struct i2c_client *client)
return 0;
}
-/*
- * 16-bit addressing note:
- *
- * If I2C_FUNC_I2C is not supported by an I2C adapter driver, regmap uses
- * SMBus operations as alternative. To simulate a read operation with a 16-bit
- * address, it writes the address using i2c_smbus_write_byte_data(), followed
- * by one or more calls to i2c_smbus_read_byte() to read the data.
- * Per spd5118 standard, a read operation after writing the address must start
- * with <Sr> (Repeat Start). However, a SMBus read byte operation starts with
- * <S> (Start). This resets the register address in the spd5118 chip. As result,
- * i2c_smbus_read_byte() always returns data from register address 0x00.
- *
- * A working alternative to access chips with 16-bit register addresses in the
- * absence of I2C_FUNC_I2C support is not known.
- *
- * For this reason, 16-bit addressing can only be supported with I2C if the
- * adapter supports I2C_FUNC_I2C.
- *
- * For I2C, the addressing mode selected by the BIOS must not be changed.
- * Experiments show that at least some PC BIOS versions will not change the
- * addressing mode on a soft reboot and end up in setup, claiming that some
- * configuration change happened. This will happen again after a power cycle,
- * which does reset the addressing mode. To prevent this from happening,
- * detect if 16-bit addressing is enabled and always use the currently
- * configured addressing mode.
- */
-
static int spd5118_i2c_probe(struct i2c_client *client)
{
- const struct regmap_config *config;
struct device *dev = &client->dev;
struct regmap *regmap;
- int err, mode;
- bool is_16bit;
+ int err;
err = spd5118_i2c_init(client);
if (err)
return err;
- mode = i2c_smbus_read_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE);
- if (mode < 0)
- return mode;
-
- is_16bit = mode & SPD5118_LEGACY_MODE_ADDR;
- if (is_16bit) {
- /*
- * See 16-bit addressing note above explaining why it is
- * necessary to check for I2C_FUNC_I2C support here.
- */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(dev, "Adapter does not support 16-bit register addresses\n");
- return -ENODEV;
- }
- config = &spd5118_regmap16_config;
- } else {
- config = &spd5118_regmap8_config;
- }
-
- regmap = devm_regmap_init_i2c(client, config);
+ regmap = devm_regmap_init_i2c(client, &spd5118_regmap8_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed\n");
- return spd5118_common_probe(dev, regmap, is_16bit);
+ return spd5118_common_probe(dev, regmap);
}
static const struct i2c_device_id spd5118_i2c_id[] = {
--
2.43.0
^ permalink raw reply related
* [PATCH v5 09/12] i3c: dw-i3c-master: Add ACPI ID for Tegra410
From: Akhil R @ 2026-06-24 10:21 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
Update variable names to generic names and add Tegra410 ACPI ID to
support the I3C controller in Tegra410, which is a DesignWare I3C host
controller.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i3c/master/dw-i3c-master.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 8e40d178d500..0753f6c853b7 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -1855,11 +1855,12 @@ static const struct of_device_id dw_i3c_master_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
-static const struct acpi_device_id amd_i3c_device_match[] = {
+static const struct acpi_device_id dw_i3c_master_acpi_match[] = {
{ "AMDI0015", AMD_I3C_OD_PP_TIMING },
+ { "NVDA2018", DW_I3C_ACPI_SKIP_CLK_RST },
{ }
};
-MODULE_DEVICE_TABLE(acpi, amd_i3c_device_match);
+MODULE_DEVICE_TABLE(acpi, dw_i3c_master_acpi_match);
static struct platform_driver dw_i3c_driver = {
.probe = dw_i3c_probe,
@@ -1868,7 +1869,7 @@ static struct platform_driver dw_i3c_driver = {
.driver = {
.name = "dw-i3c-master",
.of_match_table = dw_i3c_master_of_match,
- .acpi_match_table = amd_i3c_device_match,
+ .acpi_match_table = dw_i3c_master_acpi_match,
.pm = &dw_i3c_pm_ops,
},
};
--
2.43.0
^ permalink raw reply related
* [PATCH v5 08/12] i3c: dw-i3c-master: Add ACPI core clock frequency quirk
From: Akhil R @ 2026-06-24 10:21 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
Some ACPI-enumerated devices like Tegra410 do not expose the controller
core clock through the clk framework. Unlike device tree, ACPI on Arm does
not model clock providers. The hardware is expected to have its clocks
enabled by firmware before the OS takes over.
Make the core clock optional and allow selected ACPI devices to provide the
core clock rate through the "clock-frequency" _DSD property when the core
clock is absent.
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i3c/master/dw-i3c-master.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 29030fd9594a..8e40d178d500 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -242,6 +242,7 @@
/* List of quirks */
#define AMD_I3C_OD_PP_TIMING BIT(1)
#define DW_I3C_DISABLE_RUNTIME_PM_QUIRK BIT(2)
+#define DW_I3C_ACPI_SKIP_CLK_RST BIT(3)
struct dw_i3c_cmd {
u32 cmd_lo;
@@ -556,13 +557,33 @@ static void dw_i3c_master_set_intr_regs(struct dw_i3c_master *master)
writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT);
}
+static unsigned long dw_i3c_master_get_core_rate(struct dw_i3c_master *master)
+{
+ unsigned int core_rate_prop;
+
+ if (master->core_clk)
+ return clk_get_rate(master->core_clk);
+
+ if (!(master->quirks & DW_I3C_ACPI_SKIP_CLK_RST)) {
+ dev_err(master->dev, "missing core clock\n");
+ return 0;
+ }
+
+ if (device_property_read_u32(master->dev, "clock-frequency", &core_rate_prop)) {
+ dev_err(master->dev, "missing clock-frequency property\n");
+ return 0;
+ }
+
+ return core_rate_prop;
+}
+
static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
{
unsigned long core_rate, core_period;
u32 scl_timing;
u8 hcnt, lcnt;
- core_rate = clk_get_rate(master->core_clk);
+ core_rate = dw_i3c_master_get_core_rate(master);
if (!core_rate)
return -EINVAL;
@@ -615,7 +636,7 @@ static int dw_i2c_clk_cfg(struct dw_i3c_master *master)
u16 hcnt, lcnt;
u32 scl_timing;
- core_rate = clk_get_rate(master->core_clk);
+ core_rate = dw_i3c_master_get_core_rate(master);
if (!core_rate)
return -EINVAL;
@@ -1577,7 +1598,7 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
if (IS_ERR(master->regs))
return PTR_ERR(master->regs);
- master->core_clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ master->core_clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
if (IS_ERR(master->core_clk))
return PTR_ERR(master->core_clk);
--
2.43.0
^ permalink raw reply related
* [PATCH v5 07/12] i3c: dw-i3c-master: Add SETAASA as supported CCC
From: Akhil R @ 2026-06-24 10:21 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
Add SETAASA and SETHID to the supported list of CCC commands for
DesignWare I3C host controller.
SETAASA is a broadcast command that assigns predefined static addresses
to all I3C devices on the bus.
SETHID is to stop HID bit flipping by the SPD Hub to which the SPD devices
are connected. It is a prerequisite command to be sent before SETAASA as
recommended by JESD300-5 and JESD403 sideband bus specifications.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i3c/master/dw-i3c-master.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 2f8c0c4683e0..29030fd9594a 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -309,6 +309,8 @@ static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
case I3C_CCC_GETSTATUS:
case I3C_CCC_GETMXDS:
case I3C_CCC_GETHDRCAP:
+ case I3C_CCC_SETAASA:
+ case I3C_CCC_VENDOR(0, true): /* SETHID */
return true;
default:
return false;
--
2.43.0
^ permalink raw reply related
* [PATCH v5 06/12] i3c: master: match I3C device through DT and ACPI
From: Akhil R @ 2026-06-24 10:21 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
SETAASA-based devices cannot always be identified by PID or DCR; the
standard I3C id_table matching may not be applicable. Allow such devices to
match through Device Tree or ACPI.
Emit OF and ACPI modaliases so firmware-matched devices can autoload their
drivers.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i3c/master.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index bd0dc76c7ba1..f513169ac395 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/slab.h>
@@ -320,6 +321,15 @@ static int i3c_device_uevent(const struct device *dev, struct kobj_uevent_env *e
const struct i3c_device *i3cdev = dev_to_i3cdev(dev);
struct i3c_device_info devinfo;
u16 manuf, part, ext;
+ int rc;
+
+ rc = of_device_uevent_modalias(dev, env);
+ if (rc != -ENODEV)
+ return rc;
+
+ rc = acpi_device_uevent_modalias(dev, env);
+ if (rc != -ENODEV)
+ return rc;
if (i3cdev->desc)
devinfo = i3cdev->desc->info;
@@ -345,15 +355,32 @@ static int i3c_device_match(struct device *dev, const struct device_driver *drv)
{
struct i3c_device *i3cdev;
const struct i3c_driver *i3cdrv;
+ u8 static_addr_method = 0;
if (dev->type != &i3c_device_type)
return 0;
i3cdev = dev_to_i3cdev(dev);
i3cdrv = drv_to_i3cdrv(drv);
- if (i3c_device_match_id(i3cdev, i3cdrv->id_table))
+
+ if (i3cdev->desc && i3cdev->desc->boardinfo)
+ static_addr_method = i3cdev->desc->boardinfo->static_addr_method;
+
+ /*
+ * SETAASA-based devices need not always have a matching ID since
+ * it is not mandatory for such devices to implement deviceinfo
+ * CCC commands. Allow them to register through DT or ACPI.
+ */
+ if (i3cdrv->id_table && i3c_device_match_id(i3cdev, i3cdrv->id_table))
return 1;
+ if (static_addr_method & I3C_ADDR_METHOD_SETAASA) {
+ if (of_driver_match_device(dev, drv))
+ return 1;
+ if (acpi_driver_match_device(dev, drv))
+ return 1;
+ }
+
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v5 05/12] i3c: master: Add support for devices without PID
From: Akhil R @ 2026-06-24 10:20 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
Devices using SETAASA for address assignment are not required to have
a 48-bit PID according to the I3C specification. Allow such devices to
register and use the static address where PID was required.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i3c/master.c | 51 ++++++++++++++++++++++++++++++++++----------
1 file changed, 40 insertions(+), 11 deletions(-)
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 3deae8cdae52..bd0dc76c7ba1 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -1989,8 +1989,17 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
desc->dev->dev.type = &i3c_device_type;
desc->dev->dev.bus = &i3c_bus_type;
desc->dev->dev.release = i3c_device_release;
- dev_set_name(&desc->dev->dev, "%d-%llx", master->bus.id,
- desc->info.pid);
+
+ /*
+ * For devices without PID (e.g., SETAASA devices), use
+ * static address for naming instead.
+ */
+ if (desc->info.pid)
+ dev_set_name(&desc->dev->dev, "%d-%llx", master->bus.id,
+ desc->info.pid);
+ else
+ dev_set_name(&desc->dev->dev, "%d-%02x", master->bus.id,
+ desc->info.static_addr);
if (desc->boardinfo)
device_set_node(&desc->dev->dev,
@@ -2383,8 +2392,18 @@ static void i3c_master_attach_boardinfo(struct i3c_dev_desc *i3cdev)
struct i3c_dev_boardinfo *i3cboardinfo;
list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) {
- if (i3cdev->info.pid != i3cboardinfo->pid)
- continue;
+ /*
+ * For devices without PID (e.g., SETAASA devices), match by
+ * static address. For devices with PID, match by PID.
+ */
+ if (i3cboardinfo->pid) {
+ if (i3cdev->info.pid != i3cboardinfo->pid)
+ continue;
+ } else {
+ if (!i3cboardinfo->static_addr ||
+ i3cdev->info.static_addr != i3cboardinfo->static_addr)
+ continue;
+ }
i3cdev->boardinfo = i3cboardinfo;
i3cdev->info.static_addr = i3cboardinfo->static_addr;
@@ -2398,8 +2417,12 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
struct i3c_master_controller *master = i3c_dev_get_master(refdev);
struct i3c_dev_desc *i3cdev;
+ if (!refdev->info.pid)
+ return NULL;
+
i3c_bus_for_each_i3cdev(&master->bus, i3cdev) {
- if (i3cdev != refdev && i3cdev->info.pid == refdev->info.pid)
+ if (i3cdev != refdev && i3cdev->info.pid &&
+ i3cdev->info.pid == refdev->info.pid)
return i3cdev;
}
@@ -2832,9 +2855,15 @@ i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
boardinfo->pid = ((u64)reg[1] << 32) | reg[2];
- if ((boardinfo->pid & GENMASK_ULL(63, 48)) ||
- I3C_PID_RND_LOWER_32BITS(boardinfo->pid))
- return -EINVAL;
+ /* For SETAASA devices, validate the static address instead of PID */
+ if (boardinfo->static_addr_method & I3C_ADDR_METHOD_SETAASA) {
+ if (!boardinfo->static_addr)
+ return -EINVAL;
+ } else {
+ if ((boardinfo->pid & GENMASK_ULL(63, 48)) ||
+ I3C_PID_RND_LOWER_32BITS(boardinfo->pid))
+ return -EINVAL;
+ }
boardinfo->init_dyn_addr = init_dyn_addr;
boardinfo->fwnode = fwnode_handle_get(fwnode);
@@ -2857,10 +2886,10 @@ static int i3c_master_add_of_dev(struct i3c_master_controller *master,
return ret;
/*
- * The manufacturer ID can't be 0. If reg[1] == 0 that means we're
- * dealing with an I2C device.
+ * I3C device should have either the manufacturer ID specified or the
+ * address discovery method specified. Else treat it as an I2C device.
*/
- if (!reg[1])
+ if (!reg[1] && !fwnode_property_present(fwnode, "mipi-i3c-static-method"))
ret = i3c_master_add_i2c_boardinfo(master, fwnode, reg);
else
ret = i3c_master_add_i3c_boardinfo(master, fwnode, reg);
--
2.43.0
^ permalink raw reply related
* [PATCH v5 04/12] i3c: master: Add support for devices using SETAASA
From: Akhil R @ 2026-06-24 10:20 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
Add support for devices using SETAASA, such as SPD5118 and SPD5108
attached to DDR5 memory modules that do not support ENTDAA. Follow the
guidelines proposed by the MIPI Discovery and Configuration
Specification [1] for discovering such devices.
SETAASA (Set All Addresses to Static Address) differs from standard I3C
address assignment that uses ENTDAA or SETDASA to assign dynamic
addresses. Devices using SETAASA assign their pre-defined static addresses
as their dynamic addresses during DAA, and it is not mandatory for these
devices to implement standard CCC commands like GETPID, GETDCR, or GETBCR.
For such devices, it is generally recommended to issue SETHID (specified
by JEDEC JESD300) as a prerequisite for SETAASA to stop HID bit flipping.
[1] https://www.mipi.org/mipi-disco-for-i3c-download
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i3c/master.c | 83 +++++++++++++++++++++++++++++++++++++-
include/linux/i3c/ccc.h | 1 +
include/linux/i3c/master.h | 15 +++++++
3 files changed, 97 insertions(+), 2 deletions(-)
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 4bba2bad897a..3deae8cdae52 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -5,6 +5,7 @@
* Author: Boris Brezillon <boris.brezillon@bootlin.com>
*/
+#include <dt-bindings/i3c/i3c.h>
#include <linux/acpi.h>
#include <linux/atomic.h>
#include <linux/bitmap.h>
@@ -1102,6 +1103,51 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master,
return ret;
}
+/**
+ * i3c_master_setaasa_locked() - start a SETAASA procedure (Set All Addresses to Static Address)
+ * @master: I3C master object
+ *
+ * Send a SETAASA CCC command to set all attached I3C devices' dynamic addresses to
+ * their static address.
+ *
+ * This function must be called with the bus lock held in write mode.
+ *
+ * First, the SETHID CCC command is sent, followed by the SETAASA CCC.
+ *
+ * Return: 0 in case of success, a positive I3C error code if the error is
+ * one of the official Mx error codes, and a negative error code otherwise.
+ */
+static int i3c_master_setaasa_locked(struct i3c_master_controller *master)
+{
+ struct i3c_ccc_cmd_dest dest;
+ struct i3c_ccc_cmd cmd;
+ int ret;
+
+ /*
+ * Send SETHID CCC command. Though it is a standard CCC command specified
+ * in JESD300-5, we are not defining a separate macro to be explicit that
+ * the value falls under the vendor specific range.
+ */
+ i3c_ccc_cmd_dest_init(&dest, I3C_BROADCAST_ADDR, 0);
+ i3c_ccc_cmd_init(&cmd, false, I3C_CCC_VENDOR(0, true), &dest, 1);
+ ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+ i3c_ccc_cmd_dest_cleanup(&dest);
+ if (ret && cmd.err == I3C_ERROR_M2)
+ ret = 0;
+ if (ret)
+ return ret;
+
+ /* Send SETAASA CCC command */
+ i3c_ccc_cmd_dest_init(&dest, I3C_BROADCAST_ADDR, 0);
+ i3c_ccc_cmd_init(&cmd, false, I3C_CCC_SETAASA, &dest, 1);
+ ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+ i3c_ccc_cmd_dest_cleanup(&dest);
+ if (ret && cmd.err == I3C_ERROR_M2)
+ ret = 0;
+
+ return ret;
+}
+
/**
* i3c_master_entdaa_locked() - start a DAA (Dynamic Address Assignment)
* procedure
@@ -1878,6 +1924,22 @@ static int i3c_master_early_i3c_dev_add(struct i3c_master_controller *master,
if (ret)
goto err_free_dev;
+ /*
+ * For devices using SETAASA instead of ENTDAA, the address is statically
+ * assigned. Update the dynamic address to the provided static address.
+ * Reattach the I3C device after updating the dynamic address with the same
+ * static address. It is not mandatory for such devices to implement CCC
+ * commands like GETPID, GETDCR etc. Hence, we can return after reattaching.
+ */
+ if (i3cdev->boardinfo->static_addr_method & I3C_ADDR_METHOD_SETAASA) {
+ i3cdev->info.dyn_addr = i3cdev->boardinfo->static_addr;
+ ret = i3c_master_reattach_i3c_dev_locked(i3cdev, 0);
+ if (ret)
+ goto err_rstdaa;
+
+ return 0;
+ }
+
ret = i3c_master_setdasa_locked(master, i3cdev->info.static_addr,
i3cdev->boardinfo->init_dyn_addr);
if (ret)
@@ -2232,6 +2294,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
if (ret)
goto err_bus_cleanup;
+ if (master->addr_method & I3C_ADDR_METHOD_SETAASA) {
+ ret = i3c_master_setaasa_locked(master);
+ if (ret)
+ goto err_bus_cleanup;
+ }
+
/*
* Reserve init_dyn_addr first, and then try to pre-assign dynamic
* address and retrieve device information if needed.
@@ -2724,7 +2792,7 @@ i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
struct i3c_dev_boardinfo *boardinfo;
struct device *dev = &master->dev;
enum i3c_addr_slot_status addrstatus;
- u32 init_dyn_addr = 0;
+ u32 init_dyn_addr = 0, static_addr_method = 0;
boardinfo = devm_kzalloc(dev, sizeof(*boardinfo), GFP_KERNEL);
if (!boardinfo)
@@ -2742,7 +2810,14 @@ i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
boardinfo->static_addr = reg[0];
- if (!fwnode_property_read_u32(fwnode, "assigned-address", &init_dyn_addr)) {
+ if (!fwnode_property_read_u32(fwnode, "mipi-i3c-static-method", &static_addr_method))
+ boardinfo->static_addr_method = static_addr_method &
+ (I3C_ADDR_METHOD_SETDASA | I3C_ADDR_METHOD_SETAASA);
+
+ if (boardinfo->static_addr_method & I3C_ADDR_METHOD_SETAASA) {
+ /* For SETAASA, static address is taken as the dynamic address. */
+ init_dyn_addr = boardinfo->static_addr;
+ } else if (!fwnode_property_read_u32(fwnode, "assigned-address", &init_dyn_addr)) {
if (init_dyn_addr > I3C_MAX_ADDR)
return -EINVAL;
@@ -2752,6 +2827,9 @@ i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
return -EINVAL;
}
+ /* Update the address methods required for device discovery */
+ master->addr_method |= boardinfo->static_addr_method;
+
boardinfo->pid = ((u64)reg[1] << 32) | reg[2];
if ((boardinfo->pid & GENMASK_ULL(63, 48)) ||
@@ -3386,6 +3464,7 @@ int i3c_master_register(struct i3c_master_controller *master,
master->dev.release = i3c_masterdev_release;
master->ops = ops;
master->secondary = secondary;
+ master->addr_method = I3C_ADDR_METHOD_SETDASA;
INIT_LIST_HEAD(&master->boardinfo.i2c);
INIT_LIST_HEAD(&master->boardinfo.i3c);
diff --git a/include/linux/i3c/ccc.h b/include/linux/i3c/ccc.h
index ad59a4ae60d1..a145d766ab6f 100644
--- a/include/linux/i3c/ccc.h
+++ b/include/linux/i3c/ccc.h
@@ -32,6 +32,7 @@
#define I3C_CCC_DEFSLVS I3C_CCC_ID(0x8, true)
#define I3C_CCC_ENTTM I3C_CCC_ID(0xb, true)
#define I3C_CCC_ENTHDR(x) I3C_CCC_ID(0x20 + (x), true)
+#define I3C_CCC_SETAASA I3C_CCC_ID(0x29, true)
/* Unicast-only commands */
#define I3C_CCC_SETDASA I3C_CCC_ID(0x7, false)
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index a16deb04b2e1..2dc139a217bf 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -174,6 +174,14 @@ struct i3c_device_ibi_info {
* assigned a dynamic address by the master. Will be used during
* bus initialization to assign it a specific dynamic address
* before starting DAA (Dynamic Address Assignment)
+ * @static_addr_method: Bitmap describing which methods of Dynamic Address
+ * Assignment from a Static Address are supported by this I3C Target.
+ * A value of 1 in a bit position indicates that the I3C target
+ * supports that method, and a value of 0 indicates that the I3C
+ * target does not support that method.
+ * Bit 0: SETDASA
+ * Bit 1: SETAASA
+ * All other bits are reserved.
* @pid: I3C Provisioned ID exposed by the device. This is a unique identifier
* that may be used to attach boardinfo to i3c_dev_desc when the device
* does not have a static address
@@ -189,6 +197,7 @@ struct i3c_dev_boardinfo {
struct list_head node;
u8 init_dyn_addr;
u8 static_addr;
+ u8 static_addr_method;
u64 pid;
struct fwnode_handle *fwnode;
};
@@ -517,6 +526,11 @@ struct i3c_master_controller_ops {
* @boardinfo.i2c: list of I2C boardinfo objects
* @boardinfo: board-level information attached to devices connected on the bus
* @bus: I3C bus exposed by this master
+ * @addr_method: Bitmap describing which methods of Address Assignment required
+ * to be run for discovering all the devices on the bus.
+ * Bit 0: SETDASA
+ * Bit 1: SETAASA
+ * All other bits are reserved.
* @wq: freezable workqueue which can be used by master
* drivers if they need to postpone operations that need to take place
* in a thread context. Typical examples are Hot Join processing which
@@ -552,6 +566,7 @@ struct i3c_master_controller {
struct list_head i2c;
} boardinfo;
struct i3c_bus bus;
+ u8 addr_method;
struct workqueue_struct *wq;
struct work_struct hj_work;
struct work_struct reg_work;
--
2.43.0
^ permalink raw reply related
* [PATCH v5 03/12] i3c: master: Support ACPI enumeration of child devices
From: Akhil R @ 2026-06-24 10:20 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
Although the existing subsystem allows host controllers to register
through the ACPI table, it was not possible to describe I3C or I2C
devices when using ACPI. This is because the driver relied on the reg
property to retrieve the PID, static address, etc., whereas ACPI uses
_ADR or serial resources to describe such devices.
Read _ADR and LVR from ACPI resources and extract the data as per the
ACPI specification for an I3C bus. Also read mipi-i3c-static-address as
per the MIPI DISCO specifications [1] to get the static address to be
used.
Enable describing I3C or I2C devices in the ACPI table. This is required
if the device uses a static address or if it needs device-specific
properties.
[1] https://www.mipi.org/mipi-disco-for-i3c-download
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i3c/master.c | 151 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 143 insertions(+), 8 deletions(-)
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index b20f56f7b68e..4bba2bad897a 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -5,6 +5,7 @@
* Author: Boris Brezillon <boris.brezillon@bootlin.com>
*/
+#include <linux/acpi.h>
#include <linux/atomic.h>
#include <linux/bitmap.h>
#include <linux/bug.h>
@@ -2622,6 +2623,55 @@ EXPORT_SYMBOL_GPL(i3c_master_do_daa);
#define OF_I3C_REG1_IS_I2C_DEV BIT(31)
+#ifdef CONFIG_ACPI
+static int i3c_acpi_get_i2c_resource(struct acpi_resource *ares, void *data)
+{
+ struct i2c_dev_boardinfo *boardinfo = data;
+ struct acpi_resource_i2c_serialbus *sb;
+
+ if (boardinfo->base.addr || !i2c_acpi_get_i2c_resource(ares, &sb))
+ return 1;
+
+ boardinfo->base.addr = sb->slave_address;
+ if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+ boardinfo->base.flags |= I2C_CLIENT_TEN;
+
+ boardinfo->lvr = sb->lvr;
+
+ return 1;
+}
+
+static int i3c_acpi_add_i2c_boardinfo(struct i2c_dev_boardinfo *boardinfo,
+ struct fwnode_handle *fwnode)
+{
+ struct acpi_device *adev = to_acpi_device_node(fwnode);
+ LIST_HEAD(resources);
+ int ret;
+
+ boardinfo->base.fwnode = acpi_fwnode_handle(adev);
+ acpi_set_modalias(adev, dev_name(&adev->dev), boardinfo->base.type,
+ sizeof(boardinfo->base.type));
+
+ ret = acpi_dev_get_resources(adev, &resources,
+ i3c_acpi_get_i2c_resource, boardinfo);
+ if (ret < 0)
+ return ret;
+
+ acpi_dev_free_resource_list(&resources);
+
+ if (!boardinfo->base.addr)
+ return -ENODEV;
+
+ return 0;
+}
+#else
+static inline int i3c_acpi_add_i2c_boardinfo(struct i2c_dev_boardinfo *boardinfo,
+ struct fwnode_handle *fwnode)
+{
+ return -ENODEV;
+}
+#endif
+
static int
i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
struct fwnode_handle *fwnode, u32 *reg)
@@ -2638,6 +2688,15 @@ i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
ret = of_i2c_get_board_info(dev, to_of_node(fwnode), &boardinfo->base);
if (ret)
return ret;
+
+ /* LVR is encoded in reg[2] for Device Tree. */
+ boardinfo->lvr = reg[2];
+ } else if (is_acpi_device_node(fwnode)) {
+ ret = i3c_acpi_add_i2c_boardinfo(boardinfo, fwnode);
+ if (ret) {
+ devm_kfree(dev, boardinfo);
+ return ret;
+ }
} else {
return -EINVAL;
}
@@ -2652,9 +2711,6 @@ i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
return -EOPNOTSUPP;
}
- /* LVR is encoded in reg[2]. */
- boardinfo->lvr = reg[2];
-
list_add_tail(&boardinfo->node, &master->boardinfo.i2c);
fwnode_handle_get(fwnode);
@@ -2709,8 +2765,8 @@ i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
return 0;
}
-static int i3c_master_add_dev(struct i3c_master_controller *master,
- struct fwnode_handle *fwnode)
+static int i3c_master_add_of_dev(struct i3c_master_controller *master,
+ struct fwnode_handle *fwnode)
{
u32 reg[3];
int ret;
@@ -2734,6 +2790,74 @@ static int i3c_master_add_dev(struct i3c_master_controller *master,
return ret;
}
+#ifdef CONFIG_ACPI
+static int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
+ struct fwnode_handle *fwnode)
+{
+ struct acpi_device *adev = to_acpi_device_node(fwnode);
+ acpi_bus_address adr;
+ u32 reg[3] = { 0 };
+ int ret;
+
+ /*
+ * If the ACPI table entry has _ADR method, it's an I3C device.
+ * Otherwise it may be an I2C device described by an I2cSerialBus
+ * resource. If no I2cSerialBus resource is found, ignore the entry.
+ */
+ if (!acpi_has_method(adev->handle, "_ADR")) {
+ ret = i3c_master_add_i2c_boardinfo(master, fwnode, reg);
+ if (ret == -ENODEV)
+ return 0;
+
+ return ret;
+ }
+
+ adr = acpi_device_adr(adev);
+
+ /* For I3C devices, _ADR will have the 48 bit PID of the device */
+ reg[1] = upper_32_bits(adr);
+ reg[2] = lower_32_bits(adr);
+
+ fwnode_property_read_u32(fwnode, "mipi-i3c-static-address", ®[0]);
+
+ return i3c_master_add_i3c_boardinfo(master, fwnode, reg);
+}
+
+static u8 i3c_acpi_i2c_get_lvr(struct i2c_client *client)
+{
+ struct acpi_device *adev = to_acpi_device_node(client->dev.fwnode);
+ struct i2c_dev_boardinfo boardinfo = {};
+ LIST_HEAD(resources);
+ int ret;
+ u8 lvr;
+
+ lvr = I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE;
+
+ ret = acpi_dev_get_resources(adev, &resources,
+ i3c_acpi_get_i2c_resource, &boardinfo);
+ if (ret < 0)
+ return lvr;
+
+ if (boardinfo.base.addr)
+ lvr = boardinfo.lvr;
+
+ acpi_dev_free_resource_list(&resources);
+
+ return lvr;
+}
+#else
+static inline int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
+ struct fwnode_handle *fwnode)
+{
+ return -ENODEV;
+}
+
+static inline u8 i3c_acpi_i2c_get_lvr(struct i2c_client *client)
+{
+ return I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE;
+}
+#endif
+
static int fwnode_populate_i3c_bus(struct i3c_master_controller *master)
{
struct device *dev = &master->dev;
@@ -2745,7 +2869,13 @@ static int fwnode_populate_i3c_bus(struct i3c_master_controller *master)
return 0;
fwnode_for_each_available_child_node_scoped(fwnode, child) {
- ret = i3c_master_add_dev(master, child);
+ if (is_of_node(child))
+ ret = i3c_master_add_of_dev(master, child);
+ else if (is_acpi_device_node(child))
+ ret = i3c_master_add_acpi_dev(master, child);
+ else
+ continue;
+
if (ret)
return ret;
}
@@ -2813,8 +2943,13 @@ static u8 i3c_master_i2c_get_lvr(struct i2c_client *client)
u8 lvr = I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE;
u32 reg[3];
- if (!fwnode_property_read_u32_array(client->dev.fwnode, "reg", reg, ARRAY_SIZE(reg)))
- lvr = reg[2];
+ if (is_of_node(client->dev.fwnode)) {
+ if (!fwnode_property_read_u32_array(client->dev.fwnode, "reg",
+ reg, ARRAY_SIZE(reg)))
+ lvr = reg[2];
+ } else if (is_acpi_device_node(client->dev.fwnode)) {
+ lvr = i3c_acpi_i2c_get_lvr(client);
+ }
return lvr;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v5 02/12] i3c: master: Use unified device property interface
From: Akhil R @ 2026-06-24 10:20 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Frank Li, Miquel Raynal, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, Philipp Zabel, Jon Hunter,
Thierry Reding, linux-i3c, devicetree, linux-hwmon, linux-tegra,
linux-kernel, Akhil R
In-Reply-To: <20260624102153.1770072-1-akhilrajeev@nvidia.com>
Replace all OF-specific functions with unified device property functions
as a prerequisite to support both ACPI and device tree.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i3c/master.c | 78 +++++++++++++++++++++-----------------
include/linux/i3c/master.h | 5 ++-
2 files changed, 47 insertions(+), 36 deletions(-)
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index f1be38a640ca..b20f56f7b68e 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -13,10 +13,12 @@
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -491,7 +493,7 @@ static void i3c_bus_cleanup(struct i3c_bus *i3cbus)
mutex_unlock(&i3c_core_lock);
}
-static int i3c_bus_init(struct i3c_bus *i3cbus, struct device_node *np)
+static int i3c_bus_init(struct i3c_bus *i3cbus, struct fwnode_handle *fwnode)
{
int ret, start, end, id = -1;
@@ -501,8 +503,8 @@ static int i3c_bus_init(struct i3c_bus *i3cbus, struct device_node *np)
i3c_bus_init_addrslots(i3cbus);
i3cbus->mode = I3C_BUS_MODE_PURE;
- if (np)
- id = of_alias_get_id(np, "i3c");
+ if (fwnode && is_of_node(fwnode))
+ id = of_alias_get_id(to_of_node(fwnode), "i3c");
mutex_lock(&i3c_core_lock);
if (id >= 0) {
@@ -837,7 +839,7 @@ static void i3c_masterdev_release(struct device *dev)
WARN_ON(!list_empty(&bus->devs.i2c) || !list_empty(&bus->devs.i3c));
i3c_bus_cleanup(bus);
- of_node_put(dev->of_node);
+ fwnode_handle_put(dev->fwnode);
}
static const struct device_type i3c_masterdev_type = {
@@ -1044,7 +1046,7 @@ static void i3c_device_release(struct device *dev)
WARN_ON(i3cdev->desc);
- of_node_put(i3cdev->dev.of_node);
+ fwnode_handle_put(dev->fwnode);
kfree(i3cdev);
}
@@ -1928,7 +1930,8 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
desc->info.pid);
if (desc->boardinfo)
- desc->dev->dev.of_node = desc->boardinfo->of_node;
+ device_set_node(&desc->dev->dev,
+ fwnode_handle_get(desc->boardinfo->fwnode));
ret = device_register(&desc->dev->dev);
if (ret) {
@@ -2620,8 +2623,8 @@ EXPORT_SYMBOL_GPL(i3c_master_do_daa);
#define OF_I3C_REG1_IS_I2C_DEV BIT(31)
static int
-of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
- struct device_node *node, u32 *reg)
+i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
+ struct fwnode_handle *fwnode, u32 *reg)
{
struct i2c_dev_boardinfo *boardinfo;
struct device *dev = &master->dev;
@@ -2631,9 +2634,13 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
if (!boardinfo)
return -ENOMEM;
- ret = of_i2c_get_board_info(dev, node, &boardinfo->base);
- if (ret)
- return ret;
+ if (is_of_node(fwnode)) {
+ ret = of_i2c_get_board_info(dev, to_of_node(fwnode), &boardinfo->base);
+ if (ret)
+ return ret;
+ } else {
+ return -EINVAL;
+ }
/*
* The I3C Specification does not clearly say I2C devices with 10-bit
@@ -2649,14 +2656,14 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
boardinfo->lvr = reg[2];
list_add_tail(&boardinfo->node, &master->boardinfo.i2c);
- of_node_get(node);
+ fwnode_handle_get(fwnode);
return 0;
}
static int
-of_i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
- struct device_node *node, u32 *reg)
+i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
+ struct fwnode_handle *fwnode, u32 *reg)
{
struct i3c_dev_boardinfo *boardinfo;
struct device *dev = &master->dev;
@@ -2679,7 +2686,7 @@ of_i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
boardinfo->static_addr = reg[0];
- if (!of_property_read_u32(node, "assigned-address", &init_dyn_addr)) {
+ if (!fwnode_property_read_u32(fwnode, "assigned-address", &init_dyn_addr)) {
if (init_dyn_addr > I3C_MAX_ADDR)
return -EINVAL;
@@ -2696,14 +2703,14 @@ of_i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
return -EINVAL;
boardinfo->init_dyn_addr = init_dyn_addr;
- boardinfo->of_node = of_node_get(node);
+ boardinfo->fwnode = fwnode_handle_get(fwnode);
list_add_tail(&boardinfo->node, &master->boardinfo.i3c);
return 0;
}
-static int of_i3c_master_add_dev(struct i3c_master_controller *master,
- struct device_node *node)
+static int i3c_master_add_dev(struct i3c_master_controller *master,
+ struct fwnode_handle *fwnode)
{
u32 reg[3];
int ret;
@@ -2711,7 +2718,7 @@ static int of_i3c_master_add_dev(struct i3c_master_controller *master,
if (!master)
return -EINVAL;
- ret = of_property_read_u32_array(node, "reg", reg, ARRAY_SIZE(reg));
+ ret = fwnode_property_read_u32_array(fwnode, "reg", reg, ARRAY_SIZE(reg));
if (ret)
return ret;
@@ -2720,25 +2727,25 @@ static int of_i3c_master_add_dev(struct i3c_master_controller *master,
* dealing with an I2C device.
*/
if (!reg[1])
- ret = of_i3c_master_add_i2c_boardinfo(master, node, reg);
+ ret = i3c_master_add_i2c_boardinfo(master, fwnode, reg);
else
- ret = of_i3c_master_add_i3c_boardinfo(master, node, reg);
+ ret = i3c_master_add_i3c_boardinfo(master, fwnode, reg);
return ret;
}
-static int of_populate_i3c_bus(struct i3c_master_controller *master)
+static int fwnode_populate_i3c_bus(struct i3c_master_controller *master)
{
struct device *dev = &master->dev;
- struct device_node *i3cbus_np = dev->of_node;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
int ret;
u32 val;
- if (!i3cbus_np)
+ if (!fwnode)
return 0;
- for_each_available_child_of_node_scoped(i3cbus_np, node) {
- ret = of_i3c_master_add_dev(master, node);
+ fwnode_for_each_available_child_node_scoped(fwnode, child) {
+ ret = i3c_master_add_dev(master, child);
if (ret)
return ret;
}
@@ -2748,10 +2755,10 @@ static int of_populate_i3c_bus(struct i3c_master_controller *master)
* on the bus are not supporting typical rates, or if the bus topology
* prevents it from using max possible rate.
*/
- if (!of_property_read_u32(i3cbus_np, "i2c-scl-hz", &val))
+ if (!device_property_read_u32(dev, "i2c-scl-hz", &val))
master->bus.scl_rate.i2c = val;
- if (!of_property_read_u32(i3cbus_np, "i3c-scl-hz", &val))
+ if (!device_property_read_u32(dev, "i3c-scl-hz", &val))
master->bus.scl_rate.i3c = val;
return 0;
@@ -2806,7 +2813,7 @@ static u8 i3c_master_i2c_get_lvr(struct i2c_client *client)
u8 lvr = I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE;
u32 reg[3];
- if (!of_property_read_u32_array(client->dev.of_node, "reg", reg, ARRAY_SIZE(reg)))
+ if (!fwnode_property_read_u32_array(client->dev.fwnode, "reg", reg, ARRAY_SIZE(reg)))
lvr = reg[2];
return lvr;
@@ -2925,7 +2932,8 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
struct i2c_dev_desc *i2cdev;
struct i2c_dev_boardinfo *i2cboardinfo;
- int ret, id;
+ struct fwnode_handle *fwnode = dev_fwnode(&master->dev);
+ int ret, id = -1;
adap->dev.parent = master->dev.parent;
adap->owner = master->dev.parent->driver->owner;
@@ -2934,7 +2942,9 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
adap->timeout = HZ;
adap->retries = 3;
- id = of_alias_get_id(master->dev.of_node, "i2c");
+ if (fwnode && is_of_node(fwnode))
+ id = of_alias_get_id(to_of_node(fwnode), "i2c");
+
if (id >= 0) {
adap->nr = id;
ret = i2c_add_numbered_adapter(adap);
@@ -3235,7 +3245,7 @@ int i3c_master_register(struct i3c_master_controller *master,
return ret;
master->dev.parent = parent;
- master->dev.of_node = of_node_get(parent->of_node);
+ device_set_node(&master->dev, fwnode_handle_get(dev_fwnode(parent)));
master->dev.bus = &i3c_bus_type;
master->dev.type = &i3c_masterdev_type;
master->dev.release = i3c_masterdev_release;
@@ -3254,13 +3264,13 @@ int i3c_master_register(struct i3c_master_controller *master,
master->dev.coherent_dma_mask = parent->coherent_dma_mask;
master->dev.dma_parms = parent->dma_parms;
- ret = i3c_bus_init(i3cbus, master->dev.of_node);
+ ret = i3c_bus_init(i3cbus, dev_fwnode(&master->dev));
if (ret)
goto err_put_dev;
dev_set_name(&master->dev, "i3c-%d", i3cbus->id);
- ret = of_populate_i3c_bus(master);
+ ret = fwnode_populate_i3c_bus(master);
if (ret)
goto err_put_dev;
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index 4d2a68793324..a16deb04b2e1 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -177,7 +177,8 @@ struct i3c_device_ibi_info {
* @pid: I3C Provisioned ID exposed by the device. This is a unique identifier
* that may be used to attach boardinfo to i3c_dev_desc when the device
* does not have a static address
- * @of_node: optional DT node in case the device has been described in the DT
+ * @fwnode: Firmware node (DT or ACPI) in case the device has been
+ * described in firmware
*
* This structure is used to attach board-level information to an I3C device.
* Not all I3C devices connected on the bus will have a boardinfo. It's only
@@ -189,7 +190,7 @@ struct i3c_dev_boardinfo {
u8 init_dyn_addr;
u8 static_addr;
u64 pid;
- struct device_node *of_node;
+ struct fwnode_handle *fwnode;
};
/**
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox