diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2012-12-26 10:44:11 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-06-21 15:34:17 -0400 |
commit | e09da11da49c6fd625be52d8b60bbbbe225a9db6 (patch) | |
tree | 80442f04ef06f338578c43e7eea26bca759c9104 | |
parent | 9aea470b399d797e88be08985c489855759c6c60 (diff) |
[media] soc-camera: add V4L2-async support
Add support for asynchronous subdevice probing, using the v4l2-async API.
The legacy synchronous mode is still supported too, which allows to
gradually update drivers and platforms. The selected approach adds a
notifier for each struct soc_camera_device instance, i.e. for each video
device node, even when there are multiple such instances registered with a
single soc-camera host simultaneously.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/platform/soc_camera/soc_camera.c | 527 | ||||
-rw-r--r-- | include/media/soc_camera.h | 23 |
2 files changed, 464 insertions, 86 deletions
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index fe3930e882e1..2e47b5127d4b 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c | |||
@@ -21,22 +21,23 @@ | |||
21 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/mutex.h> | ||
25 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/mutex.h> | ||
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/regulator/consumer.h> | 28 | #include <linux/regulator/consumer.h> |
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
29 | #include <linux/pm_runtime.h> | ||
30 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
31 | 31 | ||
32 | #include <media/soc_camera.h> | 32 | #include <media/soc_camera.h> |
33 | #include <media/soc_mediabus.h> | ||
34 | #include <media/v4l2-async.h> | ||
33 | #include <media/v4l2-clk.h> | 35 | #include <media/v4l2-clk.h> |
34 | #include <media/v4l2-common.h> | 36 | #include <media/v4l2-common.h> |
35 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
36 | #include <media/v4l2-dev.h> | 38 | #include <media/v4l2-dev.h> |
37 | #include <media/videobuf-core.h> | 39 | #include <media/videobuf-core.h> |
38 | #include <media/videobuf2-core.h> | 40 | #include <media/videobuf2-core.h> |
39 | #include <media/soc_mediabus.h> | ||
40 | 41 | ||
41 | /* Default to VGA resolution */ | 42 | /* Default to VGA resolution */ |
42 | #define DEFAULT_WIDTH 640 | 43 | #define DEFAULT_WIDTH 640 |
@@ -47,23 +48,39 @@ | |||
47 | (icd)->vb_vidq.streaming : \ | 48 | (icd)->vb_vidq.streaming : \ |
48 | vb2_is_streaming(&(icd)->vb2_vidq)) | 49 | vb2_is_streaming(&(icd)->vb2_vidq)) |
49 | 50 | ||
51 | #define MAP_MAX_NUM 32 | ||
52 | static DECLARE_BITMAP(device_map, MAP_MAX_NUM); | ||
50 | static LIST_HEAD(hosts); | 53 | static LIST_HEAD(hosts); |
51 | static LIST_HEAD(devices); | 54 | static LIST_HEAD(devices); |
52 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ | 55 | /* |
56 | * Protects lists and bitmaps of hosts and devices. | ||
57 | * Lock nesting: Ok to take ->host_lock under list_lock. | ||
58 | */ | ||
59 | static DEFINE_MUTEX(list_lock); | ||
60 | |||
61 | struct soc_camera_async_client { | ||
62 | struct v4l2_async_subdev *sensor; | ||
63 | struct v4l2_async_notifier notifier; | ||
64 | struct platform_device *pdev; | ||
65 | struct list_head list; /* needed for clean up */ | ||
66 | }; | ||
67 | |||
68 | static int soc_camera_video_start(struct soc_camera_device *icd); | ||
69 | static int video_dev_create(struct soc_camera_device *icd); | ||
53 | 70 | ||
54 | int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd, | 71 | int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd, |
55 | struct v4l2_clk *clk) | 72 | struct v4l2_clk *clk) |
56 | { | 73 | { |
57 | int ret = clk ? v4l2_clk_enable(clk) : 0; | 74 | int ret = clk ? v4l2_clk_enable(clk) : 0; |
58 | if (ret < 0) { | 75 | if (ret < 0) { |
59 | dev_err(dev, "Cannot enable clock\n"); | 76 | dev_err(dev, "Cannot enable clock: %d\n", ret); |
60 | return ret; | 77 | return ret; |
61 | } | 78 | } |
62 | ret = regulator_bulk_enable(ssdd->num_regulators, | 79 | ret = regulator_bulk_enable(ssdd->num_regulators, |
63 | ssdd->regulators); | 80 | ssdd->regulators); |
64 | if (ret < 0) { | 81 | if (ret < 0) { |
65 | dev_err(dev, "Cannot enable regulators\n"); | 82 | dev_err(dev, "Cannot enable regulators\n"); |
66 | goto eregenable;; | 83 | goto eregenable; |
67 | } | 84 | } |
68 | 85 | ||
69 | if (ssdd->power) { | 86 | if (ssdd->power) { |
@@ -117,6 +134,14 @@ int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd | |||
117 | } | 134 | } |
118 | EXPORT_SYMBOL(soc_camera_power_off); | 135 | EXPORT_SYMBOL(soc_camera_power_off); |
119 | 136 | ||
137 | int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd) | ||
138 | { | ||
139 | |||
140 | return devm_regulator_bulk_get(dev, ssdd->num_regulators, | ||
141 | ssdd->regulators); | ||
142 | } | ||
143 | EXPORT_SYMBOL(soc_camera_power_init); | ||
144 | |||
120 | static int __soc_camera_power_on(struct soc_camera_device *icd) | 145 | static int __soc_camera_power_on(struct soc_camera_device *icd) |
121 | { | 146 | { |
122 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 147 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
@@ -532,7 +557,9 @@ static int soc_camera_add_device(struct soc_camera_device *icd) | |||
532 | return -EBUSY; | 557 | return -EBUSY; |
533 | 558 | ||
534 | if (!icd->clk) { | 559 | if (!icd->clk) { |
560 | mutex_lock(&ici->clk_lock); | ||
535 | ret = ici->ops->clock_start(ici); | 561 | ret = ici->ops->clock_start(ici); |
562 | mutex_unlock(&ici->clk_lock); | ||
536 | if (ret < 0) | 563 | if (ret < 0) |
537 | return ret; | 564 | return ret; |
538 | } | 565 | } |
@@ -548,8 +575,11 @@ static int soc_camera_add_device(struct soc_camera_device *icd) | |||
548 | return 0; | 575 | return 0; |
549 | 576 | ||
550 | eadd: | 577 | eadd: |
551 | if (!icd->clk) | 578 | if (!icd->clk) { |
579 | mutex_lock(&ici->clk_lock); | ||
552 | ici->ops->clock_stop(ici); | 580 | ici->ops->clock_stop(ici); |
581 | mutex_unlock(&ici->clk_lock); | ||
582 | } | ||
553 | return ret; | 583 | return ret; |
554 | } | 584 | } |
555 | 585 | ||
@@ -562,8 +592,11 @@ static void soc_camera_remove_device(struct soc_camera_device *icd) | |||
562 | 592 | ||
563 | if (ici->ops->remove) | 593 | if (ici->ops->remove) |
564 | ici->ops->remove(icd); | 594 | ici->ops->remove(icd); |
565 | if (!icd->clk) | 595 | if (!icd->clk) { |
596 | mutex_lock(&ici->clk_lock); | ||
566 | ici->ops->clock_stop(ici); | 597 | ici->ops->clock_stop(ici); |
598 | mutex_unlock(&ici->clk_lock); | ||
599 | } | ||
567 | ici->icd = NULL; | 600 | ici->icd = NULL; |
568 | } | 601 | } |
569 | 602 | ||
@@ -672,8 +705,8 @@ static int soc_camera_open(struct file *file) | |||
672 | return 0; | 705 | return 0; |
673 | 706 | ||
674 | /* | 707 | /* |
675 | * First four errors are entered with the .host_lock held | 708 | * All errors are entered with the .host_lock held, first four also |
676 | * and use_count == 1 | 709 | * with use_count == 1 |
677 | */ | 710 | */ |
678 | einitvb: | 711 | einitvb: |
679 | esfmt: | 712 | esfmt: |
@@ -1098,7 +1131,8 @@ static int soc_camera_s_parm(struct file *file, void *fh, | |||
1098 | return -ENOIOCTLCMD; | 1131 | return -ENOIOCTLCMD; |
1099 | } | 1132 | } |
1100 | 1133 | ||
1101 | static int soc_camera_probe(struct soc_camera_device *icd); | 1134 | static int soc_camera_probe(struct soc_camera_host *ici, |
1135 | struct soc_camera_device *icd); | ||
1102 | 1136 | ||
1103 | /* So far this function cannot fail */ | 1137 | /* So far this function cannot fail */ |
1104 | static void scan_add_host(struct soc_camera_host *ici) | 1138 | static void scan_add_host(struct soc_camera_host *ici) |
@@ -1107,12 +1141,20 @@ static void scan_add_host(struct soc_camera_host *ici) | |||
1107 | 1141 | ||
1108 | mutex_lock(&list_lock); | 1142 | mutex_lock(&list_lock); |
1109 | 1143 | ||
1110 | list_for_each_entry(icd, &devices, list) { | 1144 | list_for_each_entry(icd, &devices, list) |
1111 | if (icd->iface == ici->nr) { | 1145 | if (icd->iface == ici->nr) { |
1146 | struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); | ||
1147 | struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc; | ||
1148 | |||
1149 | /* The camera could have been already on, try to reset */ | ||
1150 | if (ssdd->reset) | ||
1151 | ssdd->reset(icd->pdev); | ||
1152 | |||
1112 | icd->parent = ici->v4l2_dev.dev; | 1153 | icd->parent = ici->v4l2_dev.dev; |
1113 | soc_camera_probe(icd); | 1154 | |
1155 | /* Ignore errors */ | ||
1156 | soc_camera_probe(ici, icd); | ||
1114 | } | 1157 | } |
1115 | } | ||
1116 | 1158 | ||
1117 | mutex_unlock(&list_lock); | 1159 | mutex_unlock(&list_lock); |
1118 | } | 1160 | } |
@@ -1125,6 +1167,7 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk) | |||
1125 | { | 1167 | { |
1126 | struct soc_camera_device *icd = clk->priv; | 1168 | struct soc_camera_device *icd = clk->priv; |
1127 | struct soc_camera_host *ici; | 1169 | struct soc_camera_host *ici; |
1170 | int ret; | ||
1128 | 1171 | ||
1129 | if (!icd || !icd->parent) | 1172 | if (!icd || !icd->parent) |
1130 | return -ENODEV; | 1173 | return -ENODEV; |
@@ -1138,7 +1181,10 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk) | |||
1138 | * If a different client is currently being probed, the host will tell | 1181 | * If a different client is currently being probed, the host will tell |
1139 | * you to go | 1182 | * you to go |
1140 | */ | 1183 | */ |
1141 | return ici->ops->clock_start(ici); | 1184 | mutex_lock(&ici->clk_lock); |
1185 | ret = ici->ops->clock_start(ici); | ||
1186 | mutex_unlock(&ici->clk_lock); | ||
1187 | return ret; | ||
1142 | } | 1188 | } |
1143 | 1189 | ||
1144 | static void soc_camera_clk_disable(struct v4l2_clk *clk) | 1190 | static void soc_camera_clk_disable(struct v4l2_clk *clk) |
@@ -1151,7 +1197,9 @@ static void soc_camera_clk_disable(struct v4l2_clk *clk) | |||
1151 | 1197 | ||
1152 | ici = to_soc_camera_host(icd->parent); | 1198 | ici = to_soc_camera_host(icd->parent); |
1153 | 1199 | ||
1200 | mutex_lock(&ici->clk_lock); | ||
1154 | ici->ops->clock_stop(ici); | 1201 | ici->ops->clock_stop(ici); |
1202 | mutex_unlock(&ici->clk_lock); | ||
1155 | 1203 | ||
1156 | module_put(ici->ops->owner); | 1204 | module_put(ici->ops->owner); |
1157 | } | 1205 | } |
@@ -1168,18 +1216,117 @@ static const struct v4l2_clk_ops soc_camera_clk_ops = { | |||
1168 | .disable = soc_camera_clk_disable, | 1216 | .disable = soc_camera_clk_disable, |
1169 | }; | 1217 | }; |
1170 | 1218 | ||
1219 | static int soc_camera_dyn_pdev(struct soc_camera_desc *sdesc, | ||
1220 | struct soc_camera_async_client *sasc) | ||
1221 | { | ||
1222 | struct platform_device *pdev; | ||
1223 | int ret, i; | ||
1224 | |||
1225 | mutex_lock(&list_lock); | ||
1226 | i = find_first_zero_bit(device_map, MAP_MAX_NUM); | ||
1227 | if (i < MAP_MAX_NUM) | ||
1228 | set_bit(i, device_map); | ||
1229 | mutex_unlock(&list_lock); | ||
1230 | if (i >= MAP_MAX_NUM) | ||
1231 | return -ENOMEM; | ||
1232 | |||
1233 | pdev = platform_device_alloc("soc-camera-pdrv", i); | ||
1234 | if (!pdev) | ||
1235 | return -ENOMEM; | ||
1236 | |||
1237 | ret = platform_device_add_data(pdev, sdesc, sizeof(*sdesc)); | ||
1238 | if (ret < 0) { | ||
1239 | platform_device_put(pdev); | ||
1240 | return ret; | ||
1241 | } | ||
1242 | |||
1243 | sasc->pdev = pdev; | ||
1244 | |||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | static struct soc_camera_device *soc_camera_add_pdev(struct soc_camera_async_client *sasc) | ||
1249 | { | ||
1250 | struct platform_device *pdev = sasc->pdev; | ||
1251 | int ret; | ||
1252 | |||
1253 | ret = platform_device_add(pdev); | ||
1254 | if (ret < 0 || !pdev->dev.driver) | ||
1255 | return NULL; | ||
1256 | |||
1257 | return platform_get_drvdata(pdev); | ||
1258 | } | ||
1259 | |||
1260 | /* Locking: called with .host_lock held */ | ||
1261 | static int soc_camera_probe_finish(struct soc_camera_device *icd) | ||
1262 | { | ||
1263 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1264 | struct v4l2_mbus_framefmt mf; | ||
1265 | int ret; | ||
1266 | |||
1267 | sd->grp_id = soc_camera_grp_id(icd); | ||
1268 | v4l2_set_subdev_hostdata(sd, icd); | ||
1269 | |||
1270 | ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL); | ||
1271 | if (ret < 0) | ||
1272 | return ret; | ||
1273 | |||
1274 | ret = soc_camera_add_device(icd); | ||
1275 | if (ret < 0) { | ||
1276 | dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret); | ||
1277 | return ret; | ||
1278 | } | ||
1279 | |||
1280 | /* At this point client .probe() should have run already */ | ||
1281 | ret = soc_camera_init_user_formats(icd); | ||
1282 | if (ret < 0) | ||
1283 | goto eusrfmt; | ||
1284 | |||
1285 | icd->field = V4L2_FIELD_ANY; | ||
1286 | |||
1287 | ret = soc_camera_video_start(icd); | ||
1288 | if (ret < 0) | ||
1289 | goto evidstart; | ||
1290 | |||
1291 | /* Try to improve our guess of a reasonable window format */ | ||
1292 | if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { | ||
1293 | icd->user_width = mf.width; | ||
1294 | icd->user_height = mf.height; | ||
1295 | icd->colorspace = mf.colorspace; | ||
1296 | icd->field = mf.field; | ||
1297 | } | ||
1298 | soc_camera_remove_device(icd); | ||
1299 | |||
1300 | return 0; | ||
1301 | |||
1302 | evidstart: | ||
1303 | soc_camera_free_user_formats(icd); | ||
1304 | eusrfmt: | ||
1305 | soc_camera_remove_device(icd); | ||
1306 | |||
1307 | return ret; | ||
1308 | } | ||
1309 | |||
1171 | #ifdef CONFIG_I2C_BOARDINFO | 1310 | #ifdef CONFIG_I2C_BOARDINFO |
1172 | static int soc_camera_init_i2c(struct soc_camera_device *icd, | 1311 | static int soc_camera_i2c_init(struct soc_camera_device *icd, |
1173 | struct soc_camera_desc *sdesc) | 1312 | struct soc_camera_desc *sdesc) |
1174 | { | 1313 | { |
1175 | struct i2c_client *client; | 1314 | struct i2c_client *client; |
1176 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 1315 | struct soc_camera_host *ici; |
1177 | struct soc_camera_host_desc *shd = &sdesc->host_desc; | 1316 | struct soc_camera_host_desc *shd = &sdesc->host_desc; |
1178 | struct i2c_adapter *adap = i2c_get_adapter(shd->i2c_adapter_id); | 1317 | struct i2c_adapter *adap; |
1179 | struct v4l2_subdev *subdev; | 1318 | struct v4l2_subdev *subdev; |
1180 | char clk_name[V4L2_SUBDEV_NAME_SIZE]; | 1319 | char clk_name[V4L2_SUBDEV_NAME_SIZE]; |
1181 | int ret; | 1320 | int ret; |
1182 | 1321 | ||
1322 | /* First find out how we link the main client */ | ||
1323 | if (icd->sasc) { | ||
1324 | /* Async non-OF probing handled by the subdevice list */ | ||
1325 | return -EPROBE_DEFER; | ||
1326 | } | ||
1327 | |||
1328 | ici = to_soc_camera_host(icd->parent); | ||
1329 | adap = i2c_get_adapter(shd->i2c_adapter_id); | ||
1183 | if (!adap) { | 1330 | if (!adap) { |
1184 | dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n", | 1331 | dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n", |
1185 | shd->i2c_adapter_id); | 1332 | shd->i2c_adapter_id); |
@@ -1212,42 +1359,202 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, | |||
1212 | return 0; | 1359 | return 0; |
1213 | ei2cnd: | 1360 | ei2cnd: |
1214 | v4l2_clk_unregister(icd->clk); | 1361 | v4l2_clk_unregister(icd->clk); |
1215 | icd->clk = NULL; | ||
1216 | eclkreg: | 1362 | eclkreg: |
1363 | icd->clk = NULL; | ||
1217 | i2c_put_adapter(adap); | 1364 | i2c_put_adapter(adap); |
1218 | return ret; | 1365 | return ret; |
1219 | } | 1366 | } |
1220 | 1367 | ||
1221 | static void soc_camera_free_i2c(struct soc_camera_device *icd) | 1368 | static void soc_camera_i2c_free(struct soc_camera_device *icd) |
1222 | { | 1369 | { |
1223 | struct i2c_client *client = | 1370 | struct i2c_client *client = |
1224 | to_i2c_client(to_soc_camera_control(icd)); | 1371 | to_i2c_client(to_soc_camera_control(icd)); |
1225 | struct i2c_adapter *adap = client->adapter; | 1372 | struct i2c_adapter *adap; |
1226 | 1373 | ||
1227 | icd->control = NULL; | 1374 | icd->control = NULL; |
1375 | if (icd->sasc) | ||
1376 | return; | ||
1377 | |||
1378 | adap = client->adapter; | ||
1228 | v4l2_device_unregister_subdev(i2c_get_clientdata(client)); | 1379 | v4l2_device_unregister_subdev(i2c_get_clientdata(client)); |
1229 | i2c_unregister_device(client); | 1380 | i2c_unregister_device(client); |
1230 | i2c_put_adapter(adap); | 1381 | i2c_put_adapter(adap); |
1231 | v4l2_clk_unregister(icd->clk); | 1382 | v4l2_clk_unregister(icd->clk); |
1232 | icd->clk = NULL; | 1383 | icd->clk = NULL; |
1233 | } | 1384 | } |
1385 | |||
1386 | /* | ||
1387 | * V4L2 asynchronous notifier callbacks. They are all called under a v4l2-async | ||
1388 | * internal global mutex, therefore cannot race against other asynchronous | ||
1389 | * events. Until notifier->complete() (soc_camera_async_complete()) is called, | ||
1390 | * the video device node is not registered and no V4L fops can occur. Unloading | ||
1391 | * of the host driver also calls a v4l2-async function, so also there we're | ||
1392 | * protected. | ||
1393 | */ | ||
1394 | static int soc_camera_async_bound(struct v4l2_async_notifier *notifier, | ||
1395 | struct v4l2_subdev *sd, | ||
1396 | struct v4l2_async_subdev *asd) | ||
1397 | { | ||
1398 | struct soc_camera_async_client *sasc = container_of(notifier, | ||
1399 | struct soc_camera_async_client, notifier); | ||
1400 | struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev); | ||
1401 | |||
1402 | if (asd == sasc->sensor && !WARN_ON(icd->control)) { | ||
1403 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1404 | |||
1405 | /* | ||
1406 | * Only now we get subdevice-specific information like | ||
1407 | * regulators, flags, callbacks, etc. | ||
1408 | */ | ||
1409 | if (client) { | ||
1410 | struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); | ||
1411 | struct soc_camera_subdev_desc *ssdd = | ||
1412 | soc_camera_i2c_to_desc(client); | ||
1413 | if (ssdd) { | ||
1414 | memcpy(&sdesc->subdev_desc, ssdd, | ||
1415 | sizeof(sdesc->subdev_desc)); | ||
1416 | if (ssdd->reset) | ||
1417 | ssdd->reset(icd->pdev); | ||
1418 | } | ||
1419 | |||
1420 | icd->control = &client->dev; | ||
1421 | } | ||
1422 | } | ||
1423 | |||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | static void soc_camera_async_unbind(struct v4l2_async_notifier *notifier, | ||
1428 | struct v4l2_subdev *sd, | ||
1429 | struct v4l2_async_subdev *asd) | ||
1430 | { | ||
1431 | struct soc_camera_async_client *sasc = container_of(notifier, | ||
1432 | struct soc_camera_async_client, notifier); | ||
1433 | struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev); | ||
1434 | |||
1435 | if (icd->clk) { | ||
1436 | v4l2_clk_unregister(icd->clk); | ||
1437 | icd->clk = NULL; | ||
1438 | } | ||
1439 | } | ||
1440 | |||
1441 | static int soc_camera_async_complete(struct v4l2_async_notifier *notifier) | ||
1442 | { | ||
1443 | struct soc_camera_async_client *sasc = container_of(notifier, | ||
1444 | struct soc_camera_async_client, notifier); | ||
1445 | struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev); | ||
1446 | |||
1447 | if (to_soc_camera_control(icd)) { | ||
1448 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1449 | int ret; | ||
1450 | |||
1451 | mutex_lock(&list_lock); | ||
1452 | ret = soc_camera_probe(ici, icd); | ||
1453 | mutex_unlock(&list_lock); | ||
1454 | if (ret < 0) | ||
1455 | return ret; | ||
1456 | } | ||
1457 | |||
1458 | return 0; | ||
1459 | } | ||
1460 | |||
1461 | static int scan_async_group(struct soc_camera_host *ici, | ||
1462 | struct v4l2_async_subdev **asd, int size) | ||
1463 | { | ||
1464 | struct soc_camera_async_subdev *sasd; | ||
1465 | struct soc_camera_async_client *sasc; | ||
1466 | struct soc_camera_device *icd; | ||
1467 | struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,}; | ||
1468 | char clk_name[V4L2_SUBDEV_NAME_SIZE]; | ||
1469 | int ret, i; | ||
1470 | |||
1471 | /* First look for a sensor */ | ||
1472 | for (i = 0; i < size; i++) { | ||
1473 | sasd = container_of(asd[i], struct soc_camera_async_subdev, asd); | ||
1474 | if (sasd->role == SOCAM_SUBDEV_DATA_SOURCE) | ||
1475 | break; | ||
1476 | } | ||
1477 | |||
1478 | if (i == size || asd[i]->bus_type != V4L2_ASYNC_BUS_I2C) { | ||
1479 | /* All useless */ | ||
1480 | dev_err(ici->v4l2_dev.dev, "No I2C data source found!\n"); | ||
1481 | return -ENODEV; | ||
1482 | } | ||
1483 | |||
1484 | /* Or shall this be managed by the soc-camera device? */ | ||
1485 | sasc = devm_kzalloc(ici->v4l2_dev.dev, sizeof(*sasc), GFP_KERNEL); | ||
1486 | if (!sasc) | ||
1487 | return -ENOMEM; | ||
1488 | |||
1489 | /* HACK: just need a != NULL */ | ||
1490 | sdesc.host_desc.board_info = ERR_PTR(-ENODATA); | ||
1491 | |||
1492 | ret = soc_camera_dyn_pdev(&sdesc, sasc); | ||
1493 | if (ret < 0) | ||
1494 | return ret; | ||
1495 | |||
1496 | sasc->sensor = &sasd->asd; | ||
1497 | |||
1498 | icd = soc_camera_add_pdev(sasc); | ||
1499 | if (!icd) { | ||
1500 | platform_device_put(sasc->pdev); | ||
1501 | return -ENOMEM; | ||
1502 | } | ||
1503 | |||
1504 | sasc->notifier.subdev = asd; | ||
1505 | sasc->notifier.num_subdevs = size; | ||
1506 | sasc->notifier.bound = soc_camera_async_bound; | ||
1507 | sasc->notifier.unbind = soc_camera_async_unbind; | ||
1508 | sasc->notifier.complete = soc_camera_async_complete; | ||
1509 | |||
1510 | icd->sasc = sasc; | ||
1511 | icd->parent = ici->v4l2_dev.dev; | ||
1512 | |||
1513 | snprintf(clk_name, sizeof(clk_name), "%d-%04x", | ||
1514 | sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address); | ||
1515 | |||
1516 | icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); | ||
1517 | if (IS_ERR(icd->clk)) { | ||
1518 | ret = PTR_ERR(icd->clk); | ||
1519 | goto eclkreg; | ||
1520 | } | ||
1521 | |||
1522 | ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier); | ||
1523 | if (!ret) | ||
1524 | return 0; | ||
1525 | |||
1526 | v4l2_clk_unregister(icd->clk); | ||
1527 | eclkreg: | ||
1528 | icd->clk = NULL; | ||
1529 | platform_device_unregister(sasc->pdev); | ||
1530 | dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret); | ||
1531 | |||
1532 | return ret; | ||
1533 | } | ||
1534 | |||
1535 | static void scan_async_host(struct soc_camera_host *ici) | ||
1536 | { | ||
1537 | struct v4l2_async_subdev **asd; | ||
1538 | int j; | ||
1539 | |||
1540 | for (j = 0, asd = ici->asd; ici->asd_sizes[j]; j++) { | ||
1541 | scan_async_group(ici, asd, ici->asd_sizes[j]); | ||
1542 | asd += ici->asd_sizes[j]; | ||
1543 | } | ||
1544 | } | ||
1234 | #else | 1545 | #else |
1235 | #define soc_camera_init_i2c(icd, sdesc) (-ENODEV) | 1546 | #define soc_camera_i2c_init(icd, sdesc) (-ENODEV) |
1236 | #define soc_camera_free_i2c(icd) do {} while (0) | 1547 | #define soc_camera_i2c_free(icd) do {} while (0) |
1548 | #define scan_async_host(ici) do {} while (0) | ||
1237 | #endif | 1549 | #endif |
1238 | 1550 | ||
1239 | static int soc_camera_video_start(struct soc_camera_device *icd); | ||
1240 | static int video_dev_create(struct soc_camera_device *icd); | ||
1241 | /* Called during host-driver probe */ | 1551 | /* Called during host-driver probe */ |
1242 | static int soc_camera_probe(struct soc_camera_device *icd) | 1552 | static int soc_camera_probe(struct soc_camera_host *ici, |
1553 | struct soc_camera_device *icd) | ||
1243 | { | 1554 | { |
1244 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1245 | struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); | 1555 | struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); |
1246 | struct soc_camera_host_desc *shd = &sdesc->host_desc; | 1556 | struct soc_camera_host_desc *shd = &sdesc->host_desc; |
1247 | struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc; | ||
1248 | struct device *control = NULL; | 1557 | struct device *control = NULL; |
1249 | struct v4l2_subdev *sd; | ||
1250 | struct v4l2_mbus_framefmt mf; | ||
1251 | int ret; | 1558 | int ret; |
1252 | 1559 | ||
1253 | dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); | 1560 | dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); |
@@ -1263,10 +1570,6 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1263 | if (ret < 0) | 1570 | if (ret < 0) |
1264 | return ret; | 1571 | return ret; |
1265 | 1572 | ||
1266 | /* The camera could have been already on, try to reset */ | ||
1267 | if (ssdd->reset) | ||
1268 | ssdd->reset(icd->pdev); | ||
1269 | |||
1270 | /* Must have icd->vdev before registering the device */ | 1573 | /* Must have icd->vdev before registering the device */ |
1271 | ret = video_dev_create(icd); | 1574 | ret = video_dev_create(icd); |
1272 | if (ret < 0) | 1575 | if (ret < 0) |
@@ -1277,18 +1580,19 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1277 | * itself is protected against concurrent open() calls, but we also have | 1580 | * itself is protected against concurrent open() calls, but we also have |
1278 | * to protect our data also during client probing. | 1581 | * to protect our data also during client probing. |
1279 | */ | 1582 | */ |
1280 | mutex_lock(&ici->host_lock); | ||
1281 | 1583 | ||
1282 | /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */ | 1584 | /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */ |
1283 | if (shd->board_info) { | 1585 | if (shd->board_info) { |
1284 | ret = soc_camera_init_i2c(icd, sdesc); | 1586 | ret = soc_camera_i2c_init(icd, sdesc); |
1285 | if (ret < 0) | 1587 | if (ret < 0 && ret != -EPROBE_DEFER) |
1286 | goto eadd; | 1588 | goto eadd; |
1287 | } else if (!shd->add_device || !shd->del_device) { | 1589 | } else if (!shd->add_device || !shd->del_device) { |
1288 | ret = -EINVAL; | 1590 | ret = -EINVAL; |
1289 | goto eadd; | 1591 | goto eadd; |
1290 | } else { | 1592 | } else { |
1593 | mutex_lock(&ici->clk_lock); | ||
1291 | ret = ici->ops->clock_start(ici); | 1594 | ret = ici->ops->clock_start(ici); |
1595 | mutex_unlock(&ici->clk_lock); | ||
1292 | if (ret < 0) | 1596 | if (ret < 0) |
1293 | goto eadd; | 1597 | goto eadd; |
1294 | 1598 | ||
@@ -1312,57 +1616,33 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1312 | } | 1616 | } |
1313 | } | 1617 | } |
1314 | 1618 | ||
1315 | sd = soc_camera_to_subdev(icd); | 1619 | mutex_lock(&ici->host_lock); |
1316 | sd->grp_id = soc_camera_grp_id(icd); | 1620 | ret = soc_camera_probe_finish(icd); |
1317 | v4l2_set_subdev_hostdata(sd, icd); | ||
1318 | |||
1319 | ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL); | ||
1320 | if (ret < 0) | ||
1321 | goto ectrl; | ||
1322 | |||
1323 | /* At this point client .probe() should have run already */ | ||
1324 | ret = soc_camera_init_user_formats(icd); | ||
1325 | if (ret < 0) | ||
1326 | goto eiufmt; | ||
1327 | |||
1328 | icd->field = V4L2_FIELD_ANY; | ||
1329 | |||
1330 | ret = soc_camera_video_start(icd); | ||
1331 | if (ret < 0) | ||
1332 | goto evidstart; | ||
1333 | |||
1334 | /* Try to improve our guess of a reasonable window format */ | ||
1335 | if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { | ||
1336 | icd->user_width = mf.width; | ||
1337 | icd->user_height = mf.height; | ||
1338 | icd->colorspace = mf.colorspace; | ||
1339 | icd->field = mf.field; | ||
1340 | } | ||
1341 | |||
1342 | if (!shd->board_info) | ||
1343 | ici->ops->clock_stop(ici); | ||
1344 | |||
1345 | mutex_unlock(&ici->host_lock); | 1621 | mutex_unlock(&ici->host_lock); |
1622 | if (ret < 0) | ||
1623 | goto efinish; | ||
1346 | 1624 | ||
1347 | return 0; | 1625 | return 0; |
1348 | 1626 | ||
1349 | evidstart: | 1627 | efinish: |
1350 | soc_camera_free_user_formats(icd); | ||
1351 | eiufmt: | ||
1352 | ectrl: | ||
1353 | if (shd->board_info) { | 1628 | if (shd->board_info) { |
1354 | soc_camera_free_i2c(icd); | 1629 | soc_camera_i2c_free(icd); |
1355 | } else { | 1630 | } else { |
1356 | shd->del_device(icd); | 1631 | shd->del_device(icd); |
1357 | module_put(control->driver->owner); | 1632 | module_put(control->driver->owner); |
1358 | enodrv: | 1633 | enodrv: |
1359 | eadddev: | 1634 | eadddev: |
1635 | mutex_lock(&ici->clk_lock); | ||
1360 | ici->ops->clock_stop(ici); | 1636 | ici->ops->clock_stop(ici); |
1637 | mutex_unlock(&ici->clk_lock); | ||
1361 | } | 1638 | } |
1362 | eadd: | 1639 | eadd: |
1363 | video_device_release(icd->vdev); | 1640 | video_device_release(icd->vdev); |
1364 | icd->vdev = NULL; | 1641 | icd->vdev = NULL; |
1365 | mutex_unlock(&ici->host_lock); | 1642 | if (icd->vdev) { |
1643 | video_device_release(icd->vdev); | ||
1644 | icd->vdev = NULL; | ||
1645 | } | ||
1366 | evdc: | 1646 | evdc: |
1367 | v4l2_ctrl_handler_free(&icd->ctrl_handler); | 1647 | v4l2_ctrl_handler_free(&icd->ctrl_handler); |
1368 | return ret; | 1648 | return ret; |
@@ -1370,15 +1650,15 @@ evdc: | |||
1370 | 1650 | ||
1371 | /* | 1651 | /* |
1372 | * This is called on device_unregister, which only means we have to disconnect | 1652 | * This is called on device_unregister, which only means we have to disconnect |
1373 | * from the host, but not remove ourselves from the device list | 1653 | * from the host, but not remove ourselves from the device list. With |
1654 | * asynchronous client probing this can also be called without | ||
1655 | * soc_camera_probe_finish() having run. Careful with clean up. | ||
1374 | */ | 1656 | */ |
1375 | static int soc_camera_remove(struct soc_camera_device *icd) | 1657 | static int soc_camera_remove(struct soc_camera_device *icd) |
1376 | { | 1658 | { |
1377 | struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); | 1659 | struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); |
1378 | struct video_device *vdev = icd->vdev; | 1660 | struct video_device *vdev = icd->vdev; |
1379 | 1661 | ||
1380 | BUG_ON(!icd->parent); | ||
1381 | |||
1382 | v4l2_ctrl_handler_free(&icd->ctrl_handler); | 1662 | v4l2_ctrl_handler_free(&icd->ctrl_handler); |
1383 | if (vdev) { | 1663 | if (vdev) { |
1384 | video_unregister_device(vdev); | 1664 | video_unregister_device(vdev); |
@@ -1386,15 +1666,27 @@ static int soc_camera_remove(struct soc_camera_device *icd) | |||
1386 | } | 1666 | } |
1387 | 1667 | ||
1388 | if (sdesc->host_desc.board_info) { | 1668 | if (sdesc->host_desc.board_info) { |
1389 | soc_camera_free_i2c(icd); | 1669 | soc_camera_i2c_free(icd); |
1390 | } else { | 1670 | } else { |
1391 | struct device_driver *drv = to_soc_camera_control(icd)->driver; | 1671 | struct device *dev = to_soc_camera_control(icd); |
1672 | struct device_driver *drv = dev ? dev->driver : NULL; | ||
1392 | if (drv) { | 1673 | if (drv) { |
1393 | sdesc->host_desc.del_device(icd); | 1674 | sdesc->host_desc.del_device(icd); |
1394 | module_put(drv->owner); | 1675 | module_put(drv->owner); |
1395 | } | 1676 | } |
1396 | } | 1677 | } |
1397 | soc_camera_free_user_formats(icd); | 1678 | |
1679 | if (icd->num_user_formats) | ||
1680 | soc_camera_free_user_formats(icd); | ||
1681 | |||
1682 | if (icd->clk) { | ||
1683 | /* For the synchronous case */ | ||
1684 | v4l2_clk_unregister(icd->clk); | ||
1685 | icd->clk = NULL; | ||
1686 | } | ||
1687 | |||
1688 | if (icd->sasc) | ||
1689 | platform_device_unregister(icd->sasc->pdev); | ||
1398 | 1690 | ||
1399 | return 0; | 1691 | return 0; |
1400 | } | 1692 | } |
@@ -1505,7 +1797,18 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
1505 | mutex_unlock(&list_lock); | 1797 | mutex_unlock(&list_lock); |
1506 | 1798 | ||
1507 | mutex_init(&ici->host_lock); | 1799 | mutex_init(&ici->host_lock); |
1508 | scan_add_host(ici); | 1800 | mutex_init(&ici->clk_lock); |
1801 | |||
1802 | if (ici->asd_sizes) | ||
1803 | /* | ||
1804 | * No OF, host with a list of subdevices. Don't try to mix | ||
1805 | * modes by initialising some groups statically and some | ||
1806 | * dynamically! | ||
1807 | */ | ||
1808 | scan_async_host(ici); | ||
1809 | else | ||
1810 | /* Legacy: static platform devices from board data */ | ||
1811 | scan_add_host(ici); | ||
1509 | 1812 | ||
1510 | return 0; | 1813 | return 0; |
1511 | 1814 | ||
@@ -1518,13 +1821,30 @@ EXPORT_SYMBOL(soc_camera_host_register); | |||
1518 | /* Unregister all clients! */ | 1821 | /* Unregister all clients! */ |
1519 | void soc_camera_host_unregister(struct soc_camera_host *ici) | 1822 | void soc_camera_host_unregister(struct soc_camera_host *ici) |
1520 | { | 1823 | { |
1521 | struct soc_camera_device *icd; | 1824 | struct soc_camera_device *icd, *tmp; |
1825 | struct soc_camera_async_client *sasc; | ||
1826 | LIST_HEAD(notifiers); | ||
1522 | 1827 | ||
1523 | mutex_lock(&list_lock); | 1828 | mutex_lock(&list_lock); |
1524 | |||
1525 | list_del(&ici->list); | 1829 | list_del(&ici->list); |
1526 | list_for_each_entry(icd, &devices, list) | 1830 | list_for_each_entry(icd, &devices, list) |
1527 | if (icd->iface == ici->nr && to_soc_camera_control(icd)) | 1831 | if (icd->iface == ici->nr && icd->sasc) { |
1832 | /* as long as we hold the device, sasc won't be freed */ | ||
1833 | get_device(icd->pdev); | ||
1834 | list_add(&icd->sasc->list, ¬ifiers); | ||
1835 | } | ||
1836 | mutex_unlock(&list_lock); | ||
1837 | |||
1838 | list_for_each_entry(sasc, ¬ifiers, list) { | ||
1839 | /* Must call unlocked to avoid AB-BA dead-lock */ | ||
1840 | v4l2_async_notifier_unregister(&sasc->notifier); | ||
1841 | put_device(&sasc->pdev->dev); | ||
1842 | } | ||
1843 | |||
1844 | mutex_lock(&list_lock); | ||
1845 | |||
1846 | list_for_each_entry_safe(icd, tmp, &devices, list) | ||
1847 | if (icd->iface == ici->nr) | ||
1528 | soc_camera_remove(icd); | 1848 | soc_camera_remove(icd); |
1529 | 1849 | ||
1530 | mutex_unlock(&list_lock); | 1850 | mutex_unlock(&list_lock); |
@@ -1539,6 +1859,7 @@ static int soc_camera_device_register(struct soc_camera_device *icd) | |||
1539 | struct soc_camera_device *ix; | 1859 | struct soc_camera_device *ix; |
1540 | int num = -1, i; | 1860 | int num = -1, i; |
1541 | 1861 | ||
1862 | mutex_lock(&list_lock); | ||
1542 | for (i = 0; i < 256 && num < 0; i++) { | 1863 | for (i = 0; i < 256 && num < 0; i++) { |
1543 | num = i; | 1864 | num = i; |
1544 | /* Check if this index is available on this interface */ | 1865 | /* Check if this index is available on this interface */ |
@@ -1550,18 +1871,34 @@ static int soc_camera_device_register(struct soc_camera_device *icd) | |||
1550 | } | 1871 | } |
1551 | } | 1872 | } |
1552 | 1873 | ||
1553 | if (num < 0) | 1874 | if (num < 0) { |
1554 | /* | 1875 | /* |
1555 | * ok, we have 256 cameras on this host... | 1876 | * ok, we have 256 cameras on this host... |
1556 | * man, stay reasonable... | 1877 | * man, stay reasonable... |
1557 | */ | 1878 | */ |
1879 | mutex_unlock(&list_lock); | ||
1558 | return -ENOMEM; | 1880 | return -ENOMEM; |
1881 | } | ||
1559 | 1882 | ||
1560 | icd->devnum = num; | 1883 | icd->devnum = num; |
1561 | icd->use_count = 0; | 1884 | icd->use_count = 0; |
1562 | icd->host_priv = NULL; | 1885 | icd->host_priv = NULL; |
1563 | 1886 | ||
1887 | /* | ||
1888 | * Dynamically allocated devices set the bit earlier, but it doesn't hurt setting | ||
1889 | * it again | ||
1890 | */ | ||
1891 | i = to_platform_device(icd->pdev)->id; | ||
1892 | if (i < 0) | ||
1893 | /* One static (legacy) soc-camera platform device */ | ||
1894 | i = 0; | ||
1895 | if (i >= MAP_MAX_NUM) { | ||
1896 | mutex_unlock(&list_lock); | ||
1897 | return -EBUSY; | ||
1898 | } | ||
1899 | set_bit(i, device_map); | ||
1564 | list_add_tail(&icd->list, &devices); | 1900 | list_add_tail(&icd->list, &devices); |
1901 | mutex_unlock(&list_lock); | ||
1565 | 1902 | ||
1566 | return 0; | 1903 | return 0; |
1567 | } | 1904 | } |
@@ -1655,6 +1992,12 @@ static int soc_camera_pdrv_probe(struct platform_device *pdev) | |||
1655 | if (!icd) | 1992 | if (!icd) |
1656 | return -ENOMEM; | 1993 | return -ENOMEM; |
1657 | 1994 | ||
1995 | /* | ||
1996 | * In the asynchronous case ssdd->num_regulators == 0 yet, so, the below | ||
1997 | * regulator allocation is a dummy. They will be really requested later | ||
1998 | * in soc_camera_async_bind(). Also note, that in that case regulators | ||
1999 | * are attached to the I2C device and not to the camera platform device. | ||
2000 | */ | ||
1658 | ret = devm_regulator_bulk_get(&pdev->dev, ssdd->num_regulators, | 2001 | ret = devm_regulator_bulk_get(&pdev->dev, ssdd->num_regulators, |
1659 | ssdd->regulators); | 2002 | ssdd->regulators); |
1660 | if (ret < 0) | 2003 | if (ret < 0) |
@@ -1679,11 +2022,25 @@ static int soc_camera_pdrv_probe(struct platform_device *pdev) | |||
1679 | static int soc_camera_pdrv_remove(struct platform_device *pdev) | 2022 | static int soc_camera_pdrv_remove(struct platform_device *pdev) |
1680 | { | 2023 | { |
1681 | struct soc_camera_device *icd = platform_get_drvdata(pdev); | 2024 | struct soc_camera_device *icd = platform_get_drvdata(pdev); |
2025 | int i; | ||
1682 | 2026 | ||
1683 | if (!icd) | 2027 | if (!icd) |
1684 | return -EINVAL; | 2028 | return -EINVAL; |
1685 | 2029 | ||
1686 | list_del(&icd->list); | 2030 | i = pdev->id; |
2031 | if (i < 0) | ||
2032 | i = 0; | ||
2033 | |||
2034 | /* | ||
2035 | * In synchronous mode with static platform devices this is called in a | ||
2036 | * loop from drivers/base/dd.c::driver_detach(), no parallel execution, | ||
2037 | * no need to lock. In asynchronous case the caller - | ||
2038 | * soc_camera_host_unregister() - already holds the lock | ||
2039 | */ | ||
2040 | if (test_bit(i, device_map)) { | ||
2041 | clear_bit(i, device_map); | ||
2042 | list_del(&icd->list); | ||
2043 | } | ||
1687 | 2044 | ||
1688 | return 0; | 2045 | return 0; |
1689 | } | 2046 | } |
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index f582323fafb7..906ed98c6e95 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h | |||
@@ -19,11 +19,13 @@ | |||
19 | #include <linux/videodev2.h> | 19 | #include <linux/videodev2.h> |
20 | #include <media/videobuf-core.h> | 20 | #include <media/videobuf-core.h> |
21 | #include <media/videobuf2-core.h> | 21 | #include <media/videobuf2-core.h> |
22 | #include <media/v4l2-async.h> | ||
22 | #include <media/v4l2-ctrls.h> | 23 | #include <media/v4l2-ctrls.h> |
23 | #include <media/v4l2-device.h> | 24 | #include <media/v4l2-device.h> |
24 | 25 | ||
25 | struct file; | 26 | struct file; |
26 | struct soc_camera_desc; | 27 | struct soc_camera_desc; |
28 | struct soc_camera_async_client; | ||
27 | 29 | ||
28 | struct soc_camera_device { | 30 | struct soc_camera_device { |
29 | struct list_head list; /* list of all registered devices */ | 31 | struct list_head list; /* list of all registered devices */ |
@@ -50,6 +52,9 @@ struct soc_camera_device { | |||
50 | int use_count; | 52 | int use_count; |
51 | struct file *streamer; /* stream owner */ | 53 | struct file *streamer; /* stream owner */ |
52 | struct v4l2_clk *clk; | 54 | struct v4l2_clk *clk; |
55 | /* Asynchronous subdevice management */ | ||
56 | struct soc_camera_async_client *sasc; | ||
57 | /* video buffer queue */ | ||
53 | union { | 58 | union { |
54 | struct videobuf_queue vb_vidq; | 59 | struct videobuf_queue vb_vidq; |
55 | struct vb2_queue vb2_vidq; | 60 | struct vb2_queue vb2_vidq; |
@@ -59,16 +64,30 @@ struct soc_camera_device { | |||
59 | /* Host supports programmable stride */ | 64 | /* Host supports programmable stride */ |
60 | #define SOCAM_HOST_CAP_STRIDE (1 << 0) | 65 | #define SOCAM_HOST_CAP_STRIDE (1 << 0) |
61 | 66 | ||
67 | enum soc_camera_subdev_role { | ||
68 | SOCAM_SUBDEV_DATA_SOURCE = 1, | ||
69 | SOCAM_SUBDEV_DATA_SINK, | ||
70 | SOCAM_SUBDEV_DATA_PROCESSOR, | ||
71 | }; | ||
72 | |||
73 | struct soc_camera_async_subdev { | ||
74 | struct v4l2_async_subdev asd; | ||
75 | enum soc_camera_subdev_role role; | ||
76 | }; | ||
77 | |||
62 | struct soc_camera_host { | 78 | struct soc_camera_host { |
63 | struct v4l2_device v4l2_dev; | 79 | struct v4l2_device v4l2_dev; |
64 | struct list_head list; | 80 | struct list_head list; |
65 | struct mutex host_lock; /* Protect pipeline modifications */ | 81 | struct mutex host_lock; /* Main synchronisation lock */ |
82 | struct mutex clk_lock; /* Protect pipeline modifications */ | ||
66 | unsigned char nr; /* Host number */ | 83 | unsigned char nr; /* Host number */ |
67 | u32 capabilities; | 84 | u32 capabilities; |
68 | struct soc_camera_device *icd; /* Currently attached client */ | 85 | struct soc_camera_device *icd; /* Currently attached client */ |
69 | void *priv; | 86 | void *priv; |
70 | const char *drv_name; | 87 | const char *drv_name; |
71 | struct soc_camera_host_ops *ops; | 88 | struct soc_camera_host_ops *ops; |
89 | struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */ | ||
90 | int *asd_sizes; /* 0-terminated array of asd group sizes */ | ||
72 | }; | 91 | }; |
73 | 92 | ||
74 | struct soc_camera_host_ops { | 93 | struct soc_camera_host_ops { |
@@ -161,6 +180,7 @@ struct soc_camera_host_desc { | |||
161 | }; | 180 | }; |
162 | 181 | ||
163 | /* | 182 | /* |
183 | * Platform data for "soc-camera-pdrv" | ||
164 | * This MUST be kept binary-identical to struct soc_camera_link below, until | 184 | * This MUST be kept binary-identical to struct soc_camera_link below, until |
165 | * it is completely replaced by this one, after which we can split it into its | 185 | * it is completely replaced by this one, after which we can split it into its |
166 | * two components. | 186 | * two components. |
@@ -326,6 +346,7 @@ static inline void soc_camera_limit_side(int *start, int *length, | |||
326 | unsigned long soc_camera_apply_board_flags(struct soc_camera_subdev_desc *ssdd, | 346 | unsigned long soc_camera_apply_board_flags(struct soc_camera_subdev_desc *ssdd, |
327 | const struct v4l2_mbus_config *cfg); | 347 | const struct v4l2_mbus_config *cfg); |
328 | 348 | ||
349 | int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd); | ||
329 | int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd, | 350 | int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd, |
330 | struct v4l2_clk *clk); | 351 | struct v4l2_clk *clk); |
331 | int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd, | 352 | int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd, |