From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Add support to match serdev devices with serdev drivers based on the serdev
ID table defined in serdev_device_driver::id_table.
The matching function, serdev_driver_match_device() uses the serdev device
name to match against the entries in serdev_device_driver::id_table.
If there is no serdev id_table for the driver, then serdev_device_match()
will fallback to ACPI and DT based matching.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/tty/serdev/core.c | 23 ++++++++++++++++++++++-
include/linux/mod_devicetable.h | 7 +++++++
include/linux/serdev.h | 4 ++++
scripts/mod/devicetable-offsets.c | 3 +++
4 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index b33e708cb245..2b5582cd5063 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -85,12 +85,33 @@ static const struct device_type serdev_ctrl_type = {
.release = serdev_ctrl_release,
};
+static int serdev_driver_match_device(struct device *dev, const struct device_driver *drv)
+{
+ const struct serdev_device_driver *serdev_drv = to_serdev_device_driver(drv);
+ struct serdev_device *serdev = to_serdev_device(dev);
+ const struct serdev_device_id *id;
+
+ if (!serdev_drv->id_table)
+ return 0;
+
+ for (id = serdev_drv->id_table; id->name[0]; id++) {
+ if (!strcmp(dev_name(dev), id->name)) {
+ serdev->id = id;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static int serdev_device_match(struct device *dev, const struct device_driver *drv)
{
if (!is_serdev_device(dev))
return 0;
- /* TODO: platform matching */
+ if (serdev_driver_match_device(dev, drv))
+ return 1;
+
if (acpi_driver_match_device(dev, drv))
return 1;
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 6077972e8b45..70c54c4bedba 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -976,4 +976,11 @@ struct coreboot_device_id {
kernel_ulong_t driver_data;
};
+#define SERDEV_NAME_SIZE 32
+
+struct serdev_device_id {
+ const char name[SERDEV_NAME_SIZE];
+ kernel_ulong_t driver_data;
+};
+
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index ecde0ad3e248..aca92e0ee6e7 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -39,6 +39,7 @@ struct serdev_device_ops {
* @ops: Device operations.
* @write_comp Completion used by serdev_device_write() internally
* @write_lock Lock to serialize access when writing data
+ * @id: serdev device ID entry
*/
struct serdev_device {
struct device dev;
@@ -47,6 +48,7 @@ struct serdev_device {
const struct serdev_device_ops *ops;
struct completion write_comp;
struct mutex write_lock;
+ const struct serdev_device_id *id;
};
#define to_serdev_device(d) container_of_const(d, struct serdev_device, dev)
@@ -55,11 +57,13 @@ struct serdev_device {
* struct serdev_device_driver - serdev slave device driver
* @driver: serdev device drivers should initialize name field of this
* structure.
+ * @id_table: serdev device ID table
* @probe: binds this driver to a serdev device.
* @remove: unbinds this driver from the serdev device.
*/
struct serdev_device_driver {
struct device_driver driver;
+ const struct serdev_device_id *id_table;
int (*probe)(struct serdev_device *);
void (*remove)(struct serdev_device *);
};
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index d3d00e85edf7..c1bfa8eddc4d 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -280,5 +280,8 @@ int main(void)
DEVID(coreboot_device_id);
DEVID_FIELD(coreboot_device_id, tag);
+ DEVID(serdev_device_id);
+ DEVID_FIELD(serdev_device_id, name);
+
return 0;
}
--
2.48.1
On Tue, 25 Nov 2025 15:45:06 +0100, Manivannan Sadhasivam via B4 Relay
<devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org> said:
> From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
>
> Add support to match serdev devices with serdev drivers based on the serdev
> ID table defined in serdev_device_driver::id_table.
>
> The matching function, serdev_driver_match_device() uses the serdev device
> name to match against the entries in serdev_device_driver::id_table.
>
> If there is no serdev id_table for the driver, then serdev_device_match()
> will fallback to ACPI and DT based matching.
>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> ---
> drivers/tty/serdev/core.c | 23 ++++++++++++++++++++++-
> include/linux/mod_devicetable.h | 7 +++++++
> include/linux/serdev.h | 4 ++++
> scripts/mod/devicetable-offsets.c | 3 +++
> 4 files changed, 36 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
> index b33e708cb245..2b5582cd5063 100644
> --- a/drivers/tty/serdev/core.c
> +++ b/drivers/tty/serdev/core.c
> @@ -85,12 +85,33 @@ static const struct device_type serdev_ctrl_type = {
> .release = serdev_ctrl_release,
> };
>
> +static int serdev_driver_match_device(struct device *dev, const struct device_driver *drv)
> +{
> + const struct serdev_device_driver *serdev_drv = to_serdev_device_driver(drv);
> + struct serdev_device *serdev = to_serdev_device(dev);
> + const struct serdev_device_id *id;
> +
> + if (!serdev_drv->id_table)
> + return 0;
> +
> + for (id = serdev_drv->id_table; id->name[0]; id++) {
> + if (!strcmp(dev_name(dev), id->name)) {
> + serdev->id = id;
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> +
I don't know if Rob agrees with me but I would very much prefer to see
software-node-based approach instead of an ID table matching.
Could you in the pwrseq driver, create a software node for the serdev device
you allocate, set its "compatible" to "qcom,wcn7850-bt" and match against it
here?
This has several benefits: if you ever need to pass more properties to the
serdev devices, you already have a medium for that and you can also leave
serdev_device_add() alone. You're comparing the entire name here - what if
someone sets device's ID to some value and the name will be "WCN7850.2"?
You could also drop the serdev_id field from struct serdev_device. For matching
you could even reuse the of_device_id from the device driver.
Which also makes me think that maybe we should finally think about a generic,
fwnode-based device driver matching in the driver model...
Bartosz
> static int serdev_device_match(struct device *dev, const struct device_driver *drv)
> {
> if (!is_serdev_device(dev))
> return 0;
>
> - /* TODO: platform matching */
> + if (serdev_driver_match_device(dev, drv))
> + return 1;
> +
> if (acpi_driver_match_device(dev, drv))
> return 1;
>
> diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
> index 6077972e8b45..70c54c4bedba 100644
> --- a/include/linux/mod_devicetable.h
> +++ b/include/linux/mod_devicetable.h
> @@ -976,4 +976,11 @@ struct coreboot_device_id {
> kernel_ulong_t driver_data;
> };
>
> +#define SERDEV_NAME_SIZE 32
> +
> +struct serdev_device_id {
> + const char name[SERDEV_NAME_SIZE];
> + kernel_ulong_t driver_data;
> +};
> +
> #endif /* LINUX_MOD_DEVICETABLE_H */
> diff --git a/include/linux/serdev.h b/include/linux/serdev.h
> index ecde0ad3e248..aca92e0ee6e7 100644
> --- a/include/linux/serdev.h
> +++ b/include/linux/serdev.h
> @@ -39,6 +39,7 @@ struct serdev_device_ops {
> * @ops: Device operations.
> * @write_comp Completion used by serdev_device_write() internally
> * @write_lock Lock to serialize access when writing data
> + * @id: serdev device ID entry
> */
> struct serdev_device {
> struct device dev;
> @@ -47,6 +48,7 @@ struct serdev_device {
> const struct serdev_device_ops *ops;
> struct completion write_comp;
> struct mutex write_lock;
> + const struct serdev_device_id *id;
> };
>
> #define to_serdev_device(d) container_of_const(d, struct serdev_device, dev)
> @@ -55,11 +57,13 @@ struct serdev_device {
> * struct serdev_device_driver - serdev slave device driver
> * @driver: serdev device drivers should initialize name field of this
> * structure.
> + * @id_table: serdev device ID table
> * @probe: binds this driver to a serdev device.
> * @remove: unbinds this driver from the serdev device.
> */
> struct serdev_device_driver {
> struct device_driver driver;
> + const struct serdev_device_id *id_table;
> int (*probe)(struct serdev_device *);
> void (*remove)(struct serdev_device *);
> };
> diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
> index d3d00e85edf7..c1bfa8eddc4d 100644
> --- a/scripts/mod/devicetable-offsets.c
> +++ b/scripts/mod/devicetable-offsets.c
> @@ -280,5 +280,8 @@ int main(void)
> DEVID(coreboot_device_id);
> DEVID_FIELD(coreboot_device_id, tag);
>
> + DEVID(serdev_device_id);
> + DEVID_FIELD(serdev_device_id, name);
> +
> return 0;
> }
>
> --
> 2.48.1
>
>
>
On Thu, Nov 27, 2025 at 06:32:04AM -0800, Bartosz Golaszewski wrote:
> On Tue, 25 Nov 2025 15:45:06 +0100, Manivannan Sadhasivam via B4 Relay
> <devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org> said:
> > From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> >
> > Add support to match serdev devices with serdev drivers based on the serdev
> > ID table defined in serdev_device_driver::id_table.
> >
> > The matching function, serdev_driver_match_device() uses the serdev device
> > name to match against the entries in serdev_device_driver::id_table.
> >
> > If there is no serdev id_table for the driver, then serdev_device_match()
> > will fallback to ACPI and DT based matching.
> >
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> > ---
> > drivers/tty/serdev/core.c | 23 ++++++++++++++++++++++-
> > include/linux/mod_devicetable.h | 7 +++++++
> > include/linux/serdev.h | 4 ++++
> > scripts/mod/devicetable-offsets.c | 3 +++
> > 4 files changed, 36 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
> > index b33e708cb245..2b5582cd5063 100644
> > --- a/drivers/tty/serdev/core.c
> > +++ b/drivers/tty/serdev/core.c
> > @@ -85,12 +85,33 @@ static const struct device_type serdev_ctrl_type = {
> > .release = serdev_ctrl_release,
> > };
> >
> > +static int serdev_driver_match_device(struct device *dev, const struct device_driver *drv)
> > +{
> > + const struct serdev_device_driver *serdev_drv = to_serdev_device_driver(drv);
> > + struct serdev_device *serdev = to_serdev_device(dev);
> > + const struct serdev_device_id *id;
> > +
> > + if (!serdev_drv->id_table)
> > + return 0;
> > +
> > + for (id = serdev_drv->id_table; id->name[0]; id++) {
> > + if (!strcmp(dev_name(dev), id->name)) {
> > + serdev->id = id;
> > + return 1;
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
>
> I don't know if Rob agrees with me but I would very much prefer to see
> software-node-based approach instead of an ID table matching.
>
> Could you in the pwrseq driver, create a software node for the serdev device
> you allocate, set its "compatible" to "qcom,wcn7850-bt" and match against it
> here?
>
> This has several benefits: if you ever need to pass more properties to the
> serdev devices, you already have a medium for that and you can also leave
> serdev_device_add() alone. You're comparing the entire name here - what if
> someone sets device's ID to some value and the name will be "WCN7850.2"?
>
> You could also drop the serdev_id field from struct serdev_device. For matching
> you could even reuse the of_device_id from the device driver.
>
I tried this approach and I really liked it since it gets rid of the yet-another
id_table for serdev (which I didn't like it btw). But there is one concern
though. We need a generic 'device_get_match_data' implementation for swnode.
While trying to implement it, I stumbled upon this patch [1] which does the same
for other usecase, but there was a disagreement on whether swnode should be used
for driver matching or not. For my usecase, I find it very useful and
reasonable, but Dmitry Torokhov believes otherwise.
Maybe I'll include this patch in the next version, CC Dmitry and see where it
goes.
> Which also makes me think that maybe we should finally think about a generic,
> fwnode-based device driver matching in the driver model...
>
Yes, that would be useful too and will allow me to get rid of the custom
matching logic in serdev core.
- Mani
[1] https://lore.kernel.org/all/20240427203650.582989-1-sui.jingfeng@linux.dev
--
மணிவண்ணன் சதாசிவம்
On Tue, Dec 30, 2025 at 8:56 AM Manivannan Sadhasivam <mani@kernel.org> wrote:
>
> On Thu, Nov 27, 2025 at 06:32:04AM -0800, Bartosz Golaszewski wrote:
> > On Tue, 25 Nov 2025 15:45:06 +0100, Manivannan Sadhasivam via B4 Relay
> > <devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org> said:
> > > From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> > >
> > > Add support to match serdev devices with serdev drivers based on the serdev
> > > ID table defined in serdev_device_driver::id_table.
> > >
> > > The matching function, serdev_driver_match_device() uses the serdev device
> > > name to match against the entries in serdev_device_driver::id_table.
> > >
> > > If there is no serdev id_table for the driver, then serdev_device_match()
> > > will fallback to ACPI and DT based matching.
> > >
> > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> > > ---
> > > drivers/tty/serdev/core.c | 23 ++++++++++++++++++++++-
> > > include/linux/mod_devicetable.h | 7 +++++++
> > > include/linux/serdev.h | 4 ++++
> > > scripts/mod/devicetable-offsets.c | 3 +++
> > > 4 files changed, 36 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
> > > index b33e708cb245..2b5582cd5063 100644
> > > --- a/drivers/tty/serdev/core.c
> > > +++ b/drivers/tty/serdev/core.c
> > > @@ -85,12 +85,33 @@ static const struct device_type serdev_ctrl_type = {
> > > .release = serdev_ctrl_release,
> > > };
> > >
> > > +static int serdev_driver_match_device(struct device *dev, const struct device_driver *drv)
> > > +{
> > > + const struct serdev_device_driver *serdev_drv = to_serdev_device_driver(drv);
> > > + struct serdev_device *serdev = to_serdev_device(dev);
> > > + const struct serdev_device_id *id;
> > > +
> > > + if (!serdev_drv->id_table)
> > > + return 0;
> > > +
> > > + for (id = serdev_drv->id_table; id->name[0]; id++) {
> > > + if (!strcmp(dev_name(dev), id->name)) {
> > > + serdev->id = id;
> > > + return 1;
> > > + }
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> >
> > I don't know if Rob agrees with me but I would very much prefer to see
> > software-node-based approach instead of an ID table matching.
> >
> > Could you in the pwrseq driver, create a software node for the serdev device
> > you allocate, set its "compatible" to "qcom,wcn7850-bt" and match against it
> > here?
> >
> > This has several benefits: if you ever need to pass more properties to the
> > serdev devices, you already have a medium for that and you can also leave
> > serdev_device_add() alone. You're comparing the entire name here - what if
> > someone sets device's ID to some value and the name will be "WCN7850.2"?
> >
> > You could also drop the serdev_id field from struct serdev_device. For matching
> > you could even reuse the of_device_id from the device driver.
> >
>
> I tried this approach and I really liked it since it gets rid of the yet-another
> id_table for serdev (which I didn't like it btw). But there is one concern
> though. We need a generic 'device_get_match_data' implementation for swnode.
> While trying to implement it, I stumbled upon this patch [1] which does the same
> for other usecase, but there was a disagreement on whether swnode should be used
> for driver matching or not. For my usecase, I find it very useful and
> reasonable, but Dmitry Torokhov believes otherwise.
>
> Maybe I'll include this patch in the next version, CC Dmitry and see where it
> goes.
Thanks for bringing this to my attention. I think that historically
software nodes were meant to always be "secondary" but now we have all
kinds of auxiliary devices that use software nodes as their "primary"
nodes so maybe we can re-discuss this.
Bart
© 2016 - 2026 Red Hat, Inc.