blob: e170682dae788bd9da311d31364f8d42b53a98de [file] [log] [blame]
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -03001/*
2 * V4L2 asynchronous subdevice registration API
3 *
4 * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/device.h>
12#include <linux/err.h>
13#include <linux/i2c.h>
14#include <linux/list.h>
Tomasz Figa758d90e2017-06-19 00:53:43 -030015#include <linux/mm.h>
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030016#include <linux/module.h>
17#include <linux/mutex.h>
Sakari Ailusecdf0cf2016-08-16 06:54:59 -030018#include <linux/of.h>
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030019#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <linux/types.h>
22
23#include <media/v4l2-async.h>
24#include <media/v4l2-device.h>
Sakari Ailus9ca46532017-08-17 11:28:21 -040025#include <media/v4l2-fwnode.h>
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030026#include <media/v4l2-subdev.h>
27
Sakari Ailusddddc182017-09-01 08:27:32 -040028static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
29 struct v4l2_subdev *subdev,
30 struct v4l2_async_subdev *asd)
31{
32 if (!n->ops || !n->ops->bound)
33 return 0;
34
35 return n->ops->bound(n, subdev, asd);
36}
37
38static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
39 struct v4l2_subdev *subdev,
40 struct v4l2_async_subdev *asd)
41{
42 if (!n->ops || !n->ops->unbind)
43 return;
44
45 n->ops->unbind(n, subdev, asd);
46}
47
48static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
49{
50 if (!n->ops || !n->ops->complete)
51 return 0;
52
53 return n->ops->complete(n);
54}
55
Sakari Ailus86217652015-06-11 12:18:01 -070056static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030057{
Guennadi Liakhovetskife05e142013-06-24 05:13:51 -030058#if IS_ENABLED(CONFIG_I2C)
Sakari Ailus86217652015-06-11 12:18:01 -070059 struct i2c_client *client = i2c_verify_client(sd->dev);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030060 return client &&
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030061 asd->match.i2c.adapter_id == client->adapter->nr &&
62 asd->match.i2c.address == client->addr;
Guennadi Liakhovetskife05e142013-06-24 05:13:51 -030063#else
64 return false;
65#endif
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030066}
67
Sakari Ailus86217652015-06-11 12:18:01 -070068static bool match_devname(struct v4l2_subdev *sd,
69 struct v4l2_async_subdev *asd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030070{
Sakari Ailus86217652015-06-11 12:18:01 -070071 return !strcmp(asd->match.device_name.name, dev_name(sd->dev));
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030072}
73
Sakari Ailusecdf0cf2016-08-16 06:54:59 -030074static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
75{
Rob Herring12f92862017-07-20 18:06:22 -040076 return sd->fwnode == asd->match.fwnode.fwnode;
Sakari Ailusecdf0cf2016-08-16 06:54:59 -030077}
78
Sakari Ailus86217652015-06-11 12:18:01 -070079static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
80{
81 if (!asd->match.custom.match)
82 /* Match always */
83 return true;
84
85 return asd->match.custom.match(sd->dev, asd);
Sylwester Nawrockie7359f82013-07-19 12:21:29 -030086}
87
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030088static LIST_HEAD(subdev_list);
89static LIST_HEAD(notifier_list);
90static DEFINE_MUTEX(list_lock);
91
Sakari Ailusc8114d92017-09-04 12:44:39 -040092static struct v4l2_async_subdev *v4l2_async_find_match(
93 struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030094{
Sakari Ailus86217652015-06-11 12:18:01 -070095 bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030096 struct v4l2_async_subdev *asd;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030097
98 list_for_each_entry(asd, &notifier->waiting, list) {
99 /* bus_type has been verified valid before */
Sylwester Nawrockicfca7642013-07-19 12:14:46 -0300100 switch (asd->match_type) {
101 case V4L2_ASYNC_MATCH_CUSTOM:
Sakari Ailus86217652015-06-11 12:18:01 -0700102 match = match_custom;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300103 break;
Sylwester Nawrockicfca7642013-07-19 12:14:46 -0300104 case V4L2_ASYNC_MATCH_DEVNAME:
105 match = match_devname;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300106 break;
Sylwester Nawrockicfca7642013-07-19 12:14:46 -0300107 case V4L2_ASYNC_MATCH_I2C:
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300108 match = match_i2c;
109 break;
Sakari Ailusecdf0cf2016-08-16 06:54:59 -0300110 case V4L2_ASYNC_MATCH_FWNODE:
111 match = match_fwnode;
112 break;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300113 default:
114 /* Cannot happen, unless someone breaks us */
115 WARN_ON(true);
116 return NULL;
117 }
118
119 /* match cannot be NULL here */
Sakari Ailus86217652015-06-11 12:18:01 -0700120 if (match(sd, asd))
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300121 return asd;
122 }
123
124 return NULL;
125}
126
Sakari Ailusc8114d92017-09-04 12:44:39 -0400127static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
128 struct v4l2_subdev *sd,
129 struct v4l2_async_subdev *asd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300130{
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300131 int ret;
132
Sakari Ailusddddc182017-09-01 08:27:32 -0400133 ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
134 if (ret < 0)
135 return ret;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300136
137 ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
138 if (ret < 0) {
Sakari Ailusddddc182017-09-01 08:27:32 -0400139 v4l2_async_notifier_call_unbind(notifier, sd, asd);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300140 return ret;
141 }
142
Tuukka Toivonen47b037a2017-01-27 08:32:56 -0200143 /* Remove from the waiting list */
144 list_del(&asd->list);
145 sd->asd = asd;
146 sd->notifier = notifier;
147
148 /* Move from the global subdevice list to notifier's done */
149 list_move(&sd->async_list, &notifier->done);
150
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300151 return 0;
152}
153
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300154static void v4l2_async_cleanup(struct v4l2_subdev *sd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300155{
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300156 v4l2_device_unregister_subdev(sd);
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300157 /* Subdevice driver will reprobe and put the subdev back onto the list */
158 list_del_init(&sd->async_list);
159 sd->asd = NULL;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300160}
161
Sakari Ailusfb45f432017-10-02 06:24:54 -0400162static void v4l2_async_notifier_unbind_all_subdevs(
163 struct v4l2_async_notifier *notifier)
164{
165 struct v4l2_subdev *sd, *tmp;
166
167 list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
Sakari Ailusddddc182017-09-01 08:27:32 -0400168 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400169 v4l2_async_cleanup(sd);
170
171 list_move(&sd->async_list, &subdev_list);
172 }
173}
174
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300175int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
176 struct v4l2_async_notifier *notifier)
177{
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300178 struct v4l2_subdev *sd, *tmp;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300179 struct v4l2_async_subdev *asd;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400180 int ret;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300181 int i;
182
Niklas Söderlundfbf1e942017-06-13 11:30:35 -0300183 if (!v4l2_dev || !notifier->num_subdevs ||
184 notifier->num_subdevs > V4L2_MAX_SUBDEVS)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300185 return -EINVAL;
186
187 notifier->v4l2_dev = v4l2_dev;
188 INIT_LIST_HEAD(&notifier->waiting);
189 INIT_LIST_HEAD(&notifier->done);
190
191 for (i = 0; i < notifier->num_subdevs; i++) {
Sylwester Nawrockie8419d02013-07-19 12:31:10 -0300192 asd = notifier->subdevs[i];
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300193
Sylwester Nawrockicfca7642013-07-19 12:14:46 -0300194 switch (asd->match_type) {
195 case V4L2_ASYNC_MATCH_CUSTOM:
196 case V4L2_ASYNC_MATCH_DEVNAME:
197 case V4L2_ASYNC_MATCH_I2C:
Sakari Ailusecdf0cf2016-08-16 06:54:59 -0300198 case V4L2_ASYNC_MATCH_FWNODE:
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300199 break;
200 default:
201 dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
Sylwester Nawrockicfca7642013-07-19 12:14:46 -0300202 "Invalid match type %u on %p\n",
203 asd->match_type, asd);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300204 return -EINVAL;
205 }
206 list_add_tail(&asd->list, &notifier->waiting);
207 }
208
209 mutex_lock(&list_lock);
210
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300211 list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300212 int ret;
213
Sakari Ailusc8114d92017-09-04 12:44:39 -0400214 asd = v4l2_async_find_match(notifier, sd);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300215 if (!asd)
216 continue;
217
Sakari Ailusc8114d92017-09-04 12:44:39 -0400218 ret = v4l2_async_match_notify(notifier, sd, asd);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300219 if (ret < 0) {
220 mutex_unlock(&list_lock);
221 return ret;
222 }
223 }
224
Sakari Ailusddddc182017-09-01 08:27:32 -0400225 if (list_empty(&notifier->waiting)) {
226 ret = v4l2_async_notifier_call_complete(notifier);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400227 if (ret)
228 goto err_complete;
229 }
230
Tuukka Toivonen47b037a2017-01-27 08:32:56 -0200231 /* Keep also completed notifiers on the list */
232 list_add(&notifier->list, &notifier_list);
233
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300234 mutex_unlock(&list_lock);
235
236 return 0;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400237
238err_complete:
239 v4l2_async_notifier_unbind_all_subdevs(notifier);
240
241 mutex_unlock(&list_lock);
242
243 return ret;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300244}
245EXPORT_SYMBOL(v4l2_async_notifier_register);
246
247void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
248{
Laurent Pinchart8e3fbfe2013-07-03 07:49:06 -0300249 if (!notifier->v4l2_dev)
250 return;
251
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300252 mutex_lock(&list_lock);
253
254 list_del(&notifier->list);
255
Sakari Ailusfb45f432017-10-02 06:24:54 -0400256 v4l2_async_notifier_unbind_all_subdevs(notifier);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300257
258 mutex_unlock(&list_lock);
259
Laurent Pinchart8e3fbfe2013-07-03 07:49:06 -0300260 notifier->v4l2_dev = NULL;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300261}
262EXPORT_SYMBOL(v4l2_async_notifier_unregister);
263
Sakari Ailus9ca46532017-08-17 11:28:21 -0400264void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
265{
266 unsigned int i;
267
268 if (!notifier->max_subdevs)
269 return;
270
271 for (i = 0; i < notifier->num_subdevs; i++) {
272 struct v4l2_async_subdev *asd = notifier->subdevs[i];
273
274 switch (asd->match_type) {
275 case V4L2_ASYNC_MATCH_FWNODE:
276 fwnode_handle_put(asd->match.fwnode.fwnode);
277 break;
278 default:
279 WARN_ON_ONCE(true);
280 break;
281 }
282
283 kfree(asd);
284 }
285
286 notifier->max_subdevs = 0;
287 notifier->num_subdevs = 0;
288
289 kvfree(notifier->subdevs);
290 notifier->subdevs = NULL;
291}
292EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
293
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300294int v4l2_async_register_subdev(struct v4l2_subdev *sd)
295{
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300296 struct v4l2_async_notifier *notifier;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400297 int ret;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300298
Sakari Ailus86217652015-06-11 12:18:01 -0700299 /*
300 * No reference taken. The reference is held by the device
301 * (struct v4l2_subdev.dev), and async sub-device does not
302 * exist independently of the device at any point of time.
303 */
Sakari Ailus859969b2016-08-26 20:17:25 -0300304 if (!sd->fwnode && sd->dev)
305 sd->fwnode = dev_fwnode(sd->dev);
Sakari Ailus86217652015-06-11 12:18:01 -0700306
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300307 mutex_lock(&list_lock);
308
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300309 INIT_LIST_HEAD(&sd->async_list);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300310
311 list_for_each_entry(notifier, &notifier_list, list) {
Sakari Ailusc8114d92017-09-04 12:44:39 -0400312 struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
313 sd);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400314 int ret;
315
316 if (!asd)
317 continue;
318
Sakari Ailusc8114d92017-09-04 12:44:39 -0400319 ret = v4l2_async_match_notify(notifier, sd, asd);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400320 if (ret)
321 goto err_unlock;
322
Sakari Ailusddddc182017-09-01 08:27:32 -0400323 if (!list_empty(&notifier->waiting))
Sakari Ailusfb45f432017-10-02 06:24:54 -0400324 goto out_unlock;
325
Sakari Ailusddddc182017-09-01 08:27:32 -0400326 ret = v4l2_async_notifier_call_complete(notifier);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400327 if (ret)
328 goto err_cleanup;
329
330 goto out_unlock;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300331 }
332
333 /* None matched, wait for hot-plugging */
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300334 list_add(&sd->async_list, &subdev_list);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300335
Sakari Ailusfb45f432017-10-02 06:24:54 -0400336out_unlock:
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300337 mutex_unlock(&list_lock);
338
339 return 0;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400340
341err_cleanup:
Sakari Ailusddddc182017-09-01 08:27:32 -0400342 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400343 v4l2_async_cleanup(sd);
344
345err_unlock:
346 mutex_unlock(&list_lock);
347
348 return ret;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300349}
350EXPORT_SYMBOL(v4l2_async_register_subdev);
351
352void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
353{
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300354 mutex_lock(&list_lock);
355
Sakari Ailus7fc4fdb2017-10-03 02:26:32 -0400356 if (sd->asd) {
357 struct v4l2_async_notifier *notifier = sd->notifier;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300358
Sakari Ailus7fc4fdb2017-10-03 02:26:32 -0400359 list_add(&sd->asd->list, &notifier->waiting);
360
Sakari Ailusddddc182017-09-01 08:27:32 -0400361 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
Sakari Ailus7fc4fdb2017-10-03 02:26:32 -0400362 }
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300363
Niklas Söderlund633d1852017-10-02 16:16:52 -0400364 v4l2_async_cleanup(sd);
365
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300366 mutex_unlock(&list_lock);
367}
368EXPORT_SYMBOL(v4l2_async_unregister_subdev);