From a7df2d4bb2dfcb7bd3519117f1ba66553c9fd721 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> Date: Sun, 18 Oct 2020 05:26:39 +0530 Subject: [PATCH] serdev: Add serdev_device_id 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 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@gmail.com> --- 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 c5f0d936b003a..01b248fdc2643 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 5b08a473cdba4..656353952da2c 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 9f14f9c12ec42..0d9c90a250b02 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) -- GitLab