diff options
-rw-r--r-- | drivers/tty/serdev/core.c | 36 | ||||
-rw-r--r-- | include/linux/serdev.h | 17 |
2 files changed, 46 insertions, 7 deletions
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index f4c6c90add78..6701d1011fce 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c | |||
@@ -116,17 +116,41 @@ void serdev_device_close(struct serdev_device *serdev) | |||
116 | } | 116 | } |
117 | EXPORT_SYMBOL_GPL(serdev_device_close); | 117 | EXPORT_SYMBOL_GPL(serdev_device_close); |
118 | 118 | ||
119 | int serdev_device_write_buf(struct serdev_device *serdev, | 119 | void serdev_device_write_wakeup(struct serdev_device *serdev) |
120 | const unsigned char *buf, size_t count) | 120 | { |
121 | complete(&serdev->write_comp); | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(serdev_device_write_wakeup); | ||
124 | |||
125 | int serdev_device_write(struct serdev_device *serdev, | ||
126 | const unsigned char *buf, size_t count, | ||
127 | unsigned long timeout) | ||
121 | { | 128 | { |
122 | struct serdev_controller *ctrl = serdev->ctrl; | 129 | struct serdev_controller *ctrl = serdev->ctrl; |
130 | int ret; | ||
123 | 131 | ||
124 | if (!ctrl || !ctrl->ops->write_buf) | 132 | if (!ctrl || !ctrl->ops->write_buf || |
133 | (timeout && !serdev->ops->write_wakeup)) | ||
125 | return -EINVAL; | 134 | return -EINVAL; |
126 | 135 | ||
127 | return ctrl->ops->write_buf(ctrl, buf, count); | 136 | mutex_lock(&serdev->write_lock); |
137 | do { | ||
138 | reinit_completion(&serdev->write_comp); | ||
139 | |||
140 | ret = ctrl->ops->write_buf(ctrl, buf, count); | ||
141 | if (ret < 0) | ||
142 | break; | ||
143 | |||
144 | buf += ret; | ||
145 | count -= ret; | ||
146 | |||
147 | } while (count && | ||
148 | (timeout = wait_for_completion_timeout(&serdev->write_comp, | ||
149 | timeout))); | ||
150 | mutex_unlock(&serdev->write_lock); | ||
151 | return ret < 0 ? ret : (count ? -ETIMEDOUT : 0); | ||
128 | } | 152 | } |
129 | EXPORT_SYMBOL_GPL(serdev_device_write_buf); | 153 | EXPORT_SYMBOL_GPL(serdev_device_write); |
130 | 154 | ||
131 | void serdev_device_write_flush(struct serdev_device *serdev) | 155 | void serdev_device_write_flush(struct serdev_device *serdev) |
132 | { | 156 | { |
@@ -232,6 +256,8 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *ctrl) | |||
232 | serdev->dev.parent = &ctrl->dev; | 256 | serdev->dev.parent = &ctrl->dev; |
233 | serdev->dev.bus = &serdev_bus_type; | 257 | serdev->dev.bus = &serdev_bus_type; |
234 | serdev->dev.type = &serdev_device_type; | 258 | serdev->dev.type = &serdev_device_type; |
259 | init_completion(&serdev->write_comp); | ||
260 | mutex_init(&serdev->write_lock); | ||
235 | return serdev; | 261 | return serdev; |
236 | } | 262 | } |
237 | EXPORT_SYMBOL_GPL(serdev_device_alloc); | 263 | EXPORT_SYMBOL_GPL(serdev_device_alloc); |
diff --git a/include/linux/serdev.h b/include/linux/serdev.h index 5176cdc2057f..0beaff886992 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h | |||
@@ -39,12 +39,16 @@ struct serdev_device_ops { | |||
39 | * @nr: Device number on serdev bus. | 39 | * @nr: Device number on serdev bus. |
40 | * @ctrl: serdev controller managing this device. | 40 | * @ctrl: serdev controller managing this device. |
41 | * @ops: Device operations. | 41 | * @ops: Device operations. |
42 | * @write_comp Completion used by serdev_device_write() internally | ||
43 | * @write_lock Lock to serialize access when writing data | ||
42 | */ | 44 | */ |
43 | struct serdev_device { | 45 | struct serdev_device { |
44 | struct device dev; | 46 | struct device dev; |
45 | int nr; | 47 | int nr; |
46 | struct serdev_controller *ctrl; | 48 | struct serdev_controller *ctrl; |
47 | const struct serdev_device_ops *ops; | 49 | const struct serdev_device_ops *ops; |
50 | struct completion write_comp; | ||
51 | struct mutex write_lock; | ||
48 | }; | 52 | }; |
49 | 53 | ||
50 | static inline struct serdev_device *to_serdev_device(struct device *d) | 54 | static inline struct serdev_device *to_serdev_device(struct device *d) |
@@ -186,7 +190,8 @@ int serdev_device_open(struct serdev_device *); | |||
186 | void serdev_device_close(struct serdev_device *); | 190 | void serdev_device_close(struct serdev_device *); |
187 | unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int); | 191 | unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int); |
188 | void serdev_device_set_flow_control(struct serdev_device *, bool); | 192 | void serdev_device_set_flow_control(struct serdev_device *, bool); |
189 | int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t); | 193 | void serdev_device_write_wakeup(struct serdev_device *); |
194 | int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, unsigned long); | ||
190 | void serdev_device_write_flush(struct serdev_device *); | 195 | void serdev_device_write_flush(struct serdev_device *); |
191 | int serdev_device_write_room(struct serdev_device *); | 196 | int serdev_device_write_room(struct serdev_device *); |
192 | 197 | ||
@@ -223,7 +228,8 @@ static inline unsigned int serdev_device_set_baudrate(struct serdev_device *sdev | |||
223 | return 0; | 228 | return 0; |
224 | } | 229 | } |
225 | static inline void serdev_device_set_flow_control(struct serdev_device *sdev, bool enable) {} | 230 | static inline void serdev_device_set_flow_control(struct serdev_device *sdev, bool enable) {} |
226 | static inline int serdev_device_write_buf(struct serdev_device *sdev, const unsigned char *buf, size_t count) | 231 | static inline int serdev_device_write(struct serdev_device *sdev, const unsigned char *buf, |
232 | size_t count, unsigned long timeout) | ||
227 | { | 233 | { |
228 | return -ENODEV; | 234 | return -ENODEV; |
229 | } | 235 | } |
@@ -259,4 +265,11 @@ static inline struct device *serdev_tty_port_register(struct tty_port *port, | |||
259 | static inline void serdev_tty_port_unregister(struct tty_port *port) {} | 265 | static inline void serdev_tty_port_unregister(struct tty_port *port) {} |
260 | #endif /* CONFIG_SERIAL_DEV_CTRL_TTYPORT */ | 266 | #endif /* CONFIG_SERIAL_DEV_CTRL_TTYPORT */ |
261 | 267 | ||
268 | static inline int serdev_device_write_buf(struct serdev_device *serdev, | ||
269 | const unsigned char *data, | ||
270 | size_t count) | ||
271 | { | ||
272 | return serdev_device_write(serdev, data, count, 0); | ||
273 | } | ||
274 | |||
262 | #endif /*_LINUX_SERDEV_H */ | 275 | #endif /*_LINUX_SERDEV_H */ |