| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| From: Alistair Delva <adelva@google.com> |
| Date: Fri, 13 Dec 2019 13:56:42 -0800 |
| Subject: ANDROID: serdev: add platform device support |
| |
| Enables devices on a platform bus, such as serial8250 on the ISA bus, to |
| be enumerated by the serdev subsystem. This enables further layering by |
| e.g. the gnss subsystem. |
| |
| With this in change, these devices can now register with the serdev core |
| and show up as serdev tty ports (serialX) and child devices (serialX-Y). |
| |
| serial8250: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a U6_16550A |
| serial serial0: tty port ttyS0 registered |
| serial8250: ttyS1 at I/O 0x2f8 (irq = 3, base_baud = 115200) is a U6_16550A |
| serial serial1: tty port ttyS1 registered |
| serial8250: ttyS2 at I/O 0x3e8 (irq = 4, base_baud = 115200) is a U6_16550A |
| serial serial2: tty port ttyS2 registered |
| serial8250: ttyS3 at I/O 0x2e8 (irq = 3, base_baud = 115200) is a U6_16550A |
| serial serial3: tty port ttyS3 registered |
| |
| The modalias shows up like this: |
| |
| # cat /sys/bus/serial/devices/serial0-0/modalias |
| platform:serial8250 |
| |
| Bug: 146517987 |
| Change-Id: I3711c9d9ecd66fad638a45a8745e97569ae01791 |
| Signed-off-by: Alistair Delva <adelva@google.com> |
| --- |
| drivers/tty/serdev/core.c | 71 +++++++++++++++++++++++++++++++++------ |
| 1 file changed, 61 insertions(+), 10 deletions(-) |
| |
| diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c |
| index a9719858c950..37c6defcd6c1 100644 |
| --- a/drivers/tty/serdev/core.c |
| +++ b/drivers/tty/serdev/core.c |
| @@ -31,7 +31,18 @@ static ssize_t modalias_show(struct device *dev, |
| 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; |
| + |
| + if (dev->parent->parent->bus == &platform_bus_type) { |
| + struct platform_device *pdev = |
| + to_platform_device(dev->parent->parent); |
| + |
| + len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); |
| + } |
| + |
| + return len; |
| } |
| static DEVICE_ATTR_RO(modalias); |
| |
| @@ -45,13 +56,18 @@ static int serdev_device_uevent(struct device *dev, struct kobj_uevent_env *env) |
| { |
| int rc; |
| |
| - /* TODO: platform modalias */ |
| - |
| 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; |
| + |
| + if (dev->parent->parent->bus == &platform_bus_type) |
| + rc = dev->parent->parent->bus->uevent(dev, env); |
| + |
| + return rc; |
| } |
| |
| static void serdev_device_release(struct device *dev) |
| @@ -87,11 +103,17 @@ static int serdev_device_match(struct device *dev, struct 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 (dev->parent->parent->bus == &platform_bus_type && |
| + dev->parent->parent->bus->match(dev, drv)) |
| + return 1; |
| + |
| + return 0; |
| } |
| |
| /** |
| @@ -630,6 +652,33 @@ static inline int acpi_serdev_register_devices(struct serdev_controller *ctrl) |
| } |
| #endif /* CONFIG_ACPI */ |
| |
| +static int platform_serdev_register_devices(struct serdev_controller *ctrl) |
| +{ |
| + struct serdev_device *serdev; |
| + int err; |
| + |
| + if (ctrl->dev.parent->bus != &platform_bus_type) |
| + return -ENODEV; |
| + |
| + serdev = serdev_device_alloc(ctrl); |
| + if (!serdev) { |
| + dev_err(&ctrl->dev, "failed to allocate serdev device for %s\n", |
| + dev_name(ctrl->dev.parent)); |
| + return -ENOMEM; |
| + } |
| + |
| + pm_runtime_no_callbacks(&serdev->dev); |
| + |
| + err = serdev_device_add(serdev); |
| + if (err) { |
| + dev_err(&serdev->dev, |
| + "failure adding device. status %d\n", err); |
| + serdev_device_put(serdev); |
| + } |
| + |
| + return err; |
| +} |
| + |
| /** |
| * serdev_controller_add() - Add an serdev controller |
| * @ctrl: controller to be registered. |
| @@ -639,7 +688,7 @@ static inline int acpi_serdev_register_devices(struct serdev_controller *ctrl) |
| */ |
| int serdev_controller_add(struct serdev_controller *ctrl) |
| { |
| - int ret_of, ret_acpi, ret; |
| + int ret_of, ret_acpi, ret_platform, ret; |
| |
| /* Can't register until after driver model init */ |
| if (WARN_ON(!is_registered)) |
| @@ -653,9 +702,11 @@ int serdev_controller_add(struct serdev_controller *ctrl) |
| |
| ret_of = of_serdev_register_devices(ctrl); |
| ret_acpi = acpi_serdev_register_devices(ctrl); |
| - if (ret_of && ret_acpi) { |
| - dev_dbg(&ctrl->dev, "no devices registered: of:%d acpi:%d\n", |
| - ret_of, ret_acpi); |
| + ret_platform = platform_serdev_register_devices(ctrl); |
| + if (ret_of && ret_acpi && ret_platform) { |
| + dev_dbg(&ctrl->dev, "no devices registered: of:%d acpi:%d " |
| + "platform:%d\n", |
| + ret_of, ret_acpi, ret_platform); |
| ret = -ENODEV; |
| goto err_rpm_disable; |
| } |