diff options
Diffstat (limited to 'drivers/tty/serdev/core.c')
| -rw-r--r-- | drivers/tty/serdev/core.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 1c4829a56351..ae1aaa0075d1 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -116,6 +116,12 @@ void serdev_device_close(struct serdev_device *serdev) } EXPORT_SYMBOL_GPL(serdev_device_close); +void serdev_device_write_wakeup(struct serdev_device *serdev) +{ + complete(&serdev->write_comp); +} +EXPORT_SYMBOL_GPL(serdev_device_write_wakeup); + int serdev_device_write_buf(struct serdev_device *serdev, const unsigned char *buf, size_t count) { @@ -128,6 +134,36 @@ int serdev_device_write_buf(struct serdev_device *serdev, } EXPORT_SYMBOL_GPL(serdev_device_write_buf); +int serdev_device_write(struct serdev_device *serdev, + const unsigned char *buf, size_t count, + unsigned long timeout) +{ + struct serdev_controller *ctrl = serdev->ctrl; + int ret; + + if (!ctrl || !ctrl->ops->write_buf || + (timeout && !serdev->ops->write_wakeup)) + return -EINVAL; + + mutex_lock(&serdev->write_lock); + do { + reinit_completion(&serdev->write_comp); + + ret = ctrl->ops->write_buf(ctrl, buf, count); + if (ret < 0) + break; + + buf += ret; + count -= ret; + + } while (count && + (timeout = wait_for_completion_timeout(&serdev->write_comp, + timeout))); + mutex_unlock(&serdev->write_lock); + return ret < 0 ? ret : (count ? -ETIMEDOUT : 0); +} +EXPORT_SYMBOL_GPL(serdev_device_write); + void serdev_device_write_flush(struct serdev_device *serdev) { struct serdev_controller *ctrl = serdev->ctrl; @@ -226,11 +262,13 @@ static ssize_t modalias_show(struct device *dev, { return of_device_modalias(dev, buf, PAGE_SIZE); } +DEVICE_ATTR_RO(modalias); -static struct device_attribute serdev_device_attrs[] = { - __ATTR_RO(modalias), - __ATTR_NULL +static struct attribute *serdev_device_attrs[] = { + &dev_attr_modalias.attr, + NULL, }; +ATTRIBUTE_GROUPS(serdev_device); static struct bus_type serdev_bus_type = { .name = "serial", @@ -238,7 +276,7 @@ static struct bus_type serdev_bus_type = { .probe = serdev_drv_probe, .remove = serdev_drv_remove, .uevent = serdev_uevent, - .dev_attrs = serdev_device_attrs, + .dev_groups = serdev_device_groups, }; /** @@ -262,6 +300,8 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *ctrl) serdev->dev.parent = &ctrl->dev; serdev->dev.bus = &serdev_bus_type; serdev->dev.type = &serdev_device_type; + init_completion(&serdev->write_comp); + mutex_init(&serdev->write_lock); return serdev; } EXPORT_SYMBOL_GPL(serdev_device_alloc); |