[RFC PATCH 1/5] serdev: Add serdev_device_id
From: Vaishnav M A
Date: Mon Oct 26 2020 - 13:57:57 EST
Currently,a serdev device driver can only be used with devices that are
nodes of a device tree, or are part of the ACPI table.id_table will be
used for devices that are not part of the device tree nor the ACPI table
(example: device on greybus gbphy created uart).
corresponding modalias field is introduced to name the driver to be
used with the device, required for device(s) that are neither described
by device tree nor ACPI table.serdev_device_uevent is also extended
for modalias devices.
Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@xxxxxxxxx>
Signed-off-by: Vaishnav M A <vaishnav@xxxxxxxxxxxxxxx>
---
drivers/tty/serdev/core.c | 41 ++++++++++++++++++++++++++++-----
include/linux/mod_devicetable.h | 10 ++++++++
include/linux/serdev.h | 3 +++
3 files changed, 48 insertions(+), 6 deletions(-)
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index c5f0d936b003..01b248fdc264 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -27,12 +27,17 @@ static ssize_t modalias_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int len;
+ struct serdev_device *serdev = to_serdev_device(dev);
len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1);
if (len != -ENODEV)
return len;
- return of_device_modalias(dev, buf, PAGE_SIZE);
+ len = of_device_modalias(dev, buf, PAGE_SIZE);
+ if (len != -ENODEV)
+ return len;
+
+ return sprintf(buf, "%s%s\n", SERDEV_MODULE_PREFIX, serdev->modalias);
}
static DEVICE_ATTR_RO(modalias);
@@ -45,14 +50,18 @@ ATTRIBUTE_GROUPS(serdev_device);
static int serdev_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
int rc;
-
- /* TODO: platform modalias */
+ struct serdev_device *serdev = to_serdev_device(dev);
rc = acpi_device_uevent_modalias(dev, env);
if (rc != -ENODEV)
return rc;
- return of_device_uevent_modalias(dev, env);
+ rc = of_device_uevent_modalias(dev, env);
+ if (rc != -ENODEV)
+ return rc;
+
+ return add_uevent_var(env, "MODALIAS=%s%s", SERDEV_MODULE_PREFIX,
+ serdev->modalias);
}
static void serdev_device_release(struct device *dev)
@@ -83,16 +92,36 @@ static const struct device_type serdev_ctrl_type = {
.release = serdev_ctrl_release,
};
+static int serdev_match_id(const struct serdev_device_id *id,
+ const struct serdev_device *sdev)
+{
+ while (id->name[0]) {
+ if (!strcmp(sdev->modalias, id->name))
+ return 1;
+ id++;
+ }
+
+ return 0;
+}
+
static int serdev_device_match(struct device *dev, struct device_driver *drv)
{
+ const struct serdev_device *sdev = to_serdev_device(dev);
+ const struct serdev_device_driver *sdrv = to_serdev_device_driver(drv);
+
if (!is_serdev_device(dev))
return 0;
- /* TODO: platform matching */
if (acpi_driver_match_device(dev, drv))
return 1;
- return of_driver_match_device(dev, drv);
+ if (of_driver_match_device(dev, drv))
+ return 1;
+
+ if (sdrv->id_table)
+ return serdev_match_id(sdrv->id_table, sdev);
+
+ return strcmp(sdev->modalias, drv->name) == 0;
}
/**
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 5b08a473cdba..656353952da2 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -486,6 +486,16 @@ struct i3c_device_id {
const void *data;
};
+/* serdev */
+
+#define SERDEV_NAME_SIZE 32
+#define SERDEV_MODULE_PREFIX "serdev:"
+
+struct serdev_device_id {
+ char name[SERDEV_NAME_SIZE];
+ kernel_ulong_t driver_data;
+};
+
/* spi */
#define SPI_NAME_SIZE 32
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index 9f14f9c12ec4..0d9c90a250b0 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -7,6 +7,7 @@
#include <linux/types.h>
#include <linux/device.h>
+#include <linux/mod_devicetable.h>
#include <linux/termios.h>
#include <linux/delay.h>
@@ -45,6 +46,7 @@ struct serdev_device {
const struct serdev_device_ops *ops;
struct completion write_comp;
struct mutex write_lock;
+ char modalias[SERDEV_NAME_SIZE];
};
static inline struct serdev_device *to_serdev_device(struct device *d)
@@ -63,6 +65,7 @@ struct serdev_device_driver {
struct device_driver driver;
int (*probe)(struct serdev_device *);
void (*remove)(struct serdev_device *);
+ const struct serdev_device_id *id_table;
};
static inline struct serdev_device_driver *to_serdev_device_driver(struct device_driver *d)
--
2.25.1