diff options
author | Helen Fornazier <helen.koike@collabora.com> | 2017-06-19 13:00:18 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2017-06-23 08:12:07 -0400 |
commit | 4a29b70907496aa9da79112ec31cf9cf2b972c3f (patch) | |
tree | 9be42df7b467e369899f96e2e4d2e25869bf42f8 | |
parent | 535d296f4841ffbd7f773ff2a559daa6e117f315 (diff) |
[media] vimc: Subdevices as modules
Change the core structure for adding subdevices in the topology.
Instead of calling the specific create function for each subdevice,
inject a child platform_device with the driver's name.
Each type of node in the topology (sensor, capture, debayer, scaler)
will register a platform_driver with the corresponding name through the
component subsystem.
Implementing a new subdevice type doesn't require vimc-core to be altered.
This facilitates future implementation of dynamic entities, where
hotpluging an entity in the topology is just a matter of
registering/unregistering a platform_device in the system.
It also facilitates other implementations of different nodes without
touching the core code and remove the need of a header file for each
type of node.
Signed-off-by: Helen Koike <helen.koike@collabora.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
-rw-r--r-- | drivers/media/platform/vimc/Makefile | 7 | ||||
-rw-r--r-- | drivers/media/platform/vimc/vimc-capture.c | 99 | ||||
-rw-r--r-- | drivers/media/platform/vimc/vimc-capture.h | 28 | ||||
-rw-r--r-- | drivers/media/platform/vimc/vimc-common.c | 38 | ||||
-rw-r--r-- | drivers/media/platform/vimc/vimc-common.h | 29 | ||||
-rw-r--r-- | drivers/media/platform/vimc/vimc-core.c | 405 | ||||
-rw-r--r-- | drivers/media/platform/vimc/vimc-sensor.c | 93 | ||||
-rw-r--r-- | drivers/media/platform/vimc/vimc-sensor.h | 28 |
8 files changed, 339 insertions, 388 deletions
diff --git a/drivers/media/platform/vimc/Makefile b/drivers/media/platform/vimc/Makefile index 6b6ddf45e3bf..0e5d5ce37a18 100644 --- a/drivers/media/platform/vimc/Makefile +++ b/drivers/media/platform/vimc/Makefile | |||
@@ -1,3 +1,6 @@ | |||
1 | vimc-objs := vimc-core.o vimc-capture.o vimc-common.o vimc-sensor.o | 1 | vimc-objs := vimc-core.o |
2 | vimc_capture-objs := vimc-capture.o | ||
3 | vimc_common-objs := vimc-common.o | ||
4 | vimc_sensor-objs := vimc-sensor.o | ||
2 | 5 | ||
3 | obj-$(CONFIG_VIDEO_VIMC) += vimc.o | 6 | obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc_sensor.o |
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index 359f59efb44e..14cb32e21130 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c | |||
@@ -15,15 +15,21 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/component.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
18 | #include <media/v4l2-ioctl.h> | 21 | #include <media/v4l2-ioctl.h> |
19 | #include <media/videobuf2-core.h> | 22 | #include <media/videobuf2-core.h> |
20 | #include <media/videobuf2-vmalloc.h> | 23 | #include <media/videobuf2-vmalloc.h> |
21 | 24 | ||
22 | #include "vimc-capture.h" | 25 | #include "vimc-common.h" |
26 | |||
27 | #define VIMC_CAP_DRV_NAME "vimc-capture" | ||
23 | 28 | ||
24 | struct vimc_cap_device { | 29 | struct vimc_cap_device { |
25 | struct vimc_ent_device ved; | 30 | struct vimc_ent_device ved; |
26 | struct video_device vdev; | 31 | struct video_device vdev; |
32 | struct device *dev; | ||
27 | struct v4l2_pix_format format; | 33 | struct v4l2_pix_format format; |
28 | struct vb2_queue queue; | 34 | struct vb2_queue queue; |
29 | struct list_head buf_list; | 35 | struct list_head buf_list; |
@@ -131,7 +137,7 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, | |||
131 | 137 | ||
132 | vimc_cap_try_fmt_vid_cap(file, priv, f); | 138 | vimc_cap_try_fmt_vid_cap(file, priv, f); |
133 | 139 | ||
134 | dev_dbg(vcap->vdev.v4l2_dev->dev, "%s: format update: " | 140 | dev_dbg(vcap->dev, "%s: format update: " |
135 | "old:%dx%d (0x%x, %d, %d, %d, %d) " | 141 | "old:%dx%d (0x%x, %d, %d, %d, %d) " |
136 | "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, | 142 | "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, |
137 | /* old */ | 143 | /* old */ |
@@ -309,8 +315,7 @@ static int vimc_cap_buffer_prepare(struct vb2_buffer *vb) | |||
309 | unsigned long size = vcap->format.sizeimage; | 315 | unsigned long size = vcap->format.sizeimage; |
310 | 316 | ||
311 | if (vb2_plane_size(vb, 0) < size) { | 317 | if (vb2_plane_size(vb, 0) < size) { |
312 | dev_err(vcap->vdev.v4l2_dev->dev, | 318 | dev_err(vcap->dev, "%s: buffer too small (%lu < %lu)\n", |
313 | "%s: buffer too small (%lu < %lu)\n", | ||
314 | vcap->vdev.name, vb2_plane_size(vb, 0), size); | 319 | vcap->vdev.name, vb2_plane_size(vb, 0), size); |
315 | return -EINVAL; | 320 | return -EINVAL; |
316 | } | 321 | } |
@@ -335,8 +340,10 @@ static const struct media_entity_operations vimc_cap_mops = { | |||
335 | .link_validate = vimc_link_validate, | 340 | .link_validate = vimc_link_validate, |
336 | }; | 341 | }; |
337 | 342 | ||
338 | static void vimc_cap_destroy(struct vimc_ent_device *ved) | 343 | static void vimc_cap_comp_unbind(struct device *comp, struct device *master, |
344 | void *master_data) | ||
339 | { | 345 | { |
346 | struct vimc_ent_device *ved = dev_get_drvdata(comp); | ||
340 | struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, | 347 | struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, |
341 | ved); | 348 | ved); |
342 | 349 | ||
@@ -385,42 +392,35 @@ static void vimc_cap_process_frame(struct vimc_ent_device *ved, | |||
385 | vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); | 392 | vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); |
386 | } | 393 | } |
387 | 394 | ||
388 | struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | 395 | static int vimc_cap_comp_bind(struct device *comp, struct device *master, |
389 | const char *const name, | 396 | void *master_data) |
390 | u16 num_pads, | ||
391 | const unsigned long *pads_flag) | ||
392 | { | 397 | { |
398 | struct v4l2_device *v4l2_dev = master_data; | ||
399 | struct vimc_platform_data *pdata = comp->platform_data; | ||
393 | const struct vimc_pix_map *vpix; | 400 | const struct vimc_pix_map *vpix; |
394 | struct vimc_cap_device *vcap; | 401 | struct vimc_cap_device *vcap; |
395 | struct video_device *vdev; | 402 | struct video_device *vdev; |
396 | struct vb2_queue *q; | 403 | struct vb2_queue *q; |
397 | int ret; | 404 | int ret; |
398 | 405 | ||
399 | /* | ||
400 | * Check entity configuration params | ||
401 | * NOTE: we only support a single sink pad | ||
402 | */ | ||
403 | if (!name || num_pads != 1 || !pads_flag || | ||
404 | !(pads_flag[0] & MEDIA_PAD_FL_SINK)) | ||
405 | return ERR_PTR(-EINVAL); | ||
406 | |||
407 | /* Allocate the vimc_cap_device struct */ | 406 | /* Allocate the vimc_cap_device struct */ |
408 | vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); | 407 | vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); |
409 | if (!vcap) | 408 | if (!vcap) |
410 | return ERR_PTR(-ENOMEM); | 409 | return -ENOMEM; |
411 | 410 | ||
412 | /* Allocate the pads */ | 411 | /* Allocate the pads */ |
413 | vcap->ved.pads = vimc_pads_init(num_pads, pads_flag); | 412 | vcap->ved.pads = |
413 | vimc_pads_init(1, (const unsigned long[1]) {MEDIA_PAD_FL_SINK}); | ||
414 | if (IS_ERR(vcap->ved.pads)) { | 414 | if (IS_ERR(vcap->ved.pads)) { |
415 | ret = PTR_ERR(vcap->ved.pads); | 415 | ret = PTR_ERR(vcap->ved.pads); |
416 | goto err_free_vcap; | 416 | goto err_free_vcap; |
417 | } | 417 | } |
418 | 418 | ||
419 | /* Initialize the media entity */ | 419 | /* Initialize the media entity */ |
420 | vcap->vdev.entity.name = name; | 420 | vcap->vdev.entity.name = pdata->entity_name; |
421 | vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; | 421 | vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; |
422 | ret = media_entity_pads_init(&vcap->vdev.entity, | 422 | ret = media_entity_pads_init(&vcap->vdev.entity, |
423 | num_pads, vcap->ved.pads); | 423 | 1, vcap->ved.pads); |
424 | if (ret) | 424 | if (ret) |
425 | goto err_clean_pads; | 425 | goto err_clean_pads; |
426 | 426 | ||
@@ -441,9 +441,8 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | |||
441 | 441 | ||
442 | ret = vb2_queue_init(q); | 442 | ret = vb2_queue_init(q); |
443 | if (ret) { | 443 | if (ret) { |
444 | dev_err(vcap->vdev.v4l2_dev->dev, | 444 | dev_err(comp, "%s: vb2 queue init failed (err=%d)\n", |
445 | "%s: vb2 queue init failed (err=%d)\n", | 445 | pdata->entity_name, ret); |
446 | vcap->vdev.name, ret); | ||
447 | goto err_clean_m_ent; | 446 | goto err_clean_m_ent; |
448 | } | 447 | } |
449 | 448 | ||
@@ -459,10 +458,11 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | |||
459 | vcap->format.height; | 458 | vcap->format.height; |
460 | 459 | ||
461 | /* Fill the vimc_ent_device struct */ | 460 | /* Fill the vimc_ent_device struct */ |
462 | vcap->ved.destroy = vimc_cap_destroy; | ||
463 | vcap->ved.ent = &vcap->vdev.entity; | 461 | vcap->ved.ent = &vcap->vdev.entity; |
464 | vcap->ved.process_frame = vimc_cap_process_frame; | 462 | vcap->ved.process_frame = vimc_cap_process_frame; |
465 | vcap->ved.vdev_get_format = vimc_cap_get_format; | 463 | vcap->ved.vdev_get_format = vimc_cap_get_format; |
464 | dev_set_drvdata(comp, &vcap->ved); | ||
465 | vcap->dev = comp; | ||
466 | 466 | ||
467 | /* Initialize the video_device struct */ | 467 | /* Initialize the video_device struct */ |
468 | vdev = &vcap->vdev; | 468 | vdev = &vcap->vdev; |
@@ -475,19 +475,18 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | |||
475 | vdev->queue = q; | 475 | vdev->queue = q; |
476 | vdev->v4l2_dev = v4l2_dev; | 476 | vdev->v4l2_dev = v4l2_dev; |
477 | vdev->vfl_dir = VFL_DIR_RX; | 477 | vdev->vfl_dir = VFL_DIR_RX; |
478 | strlcpy(vdev->name, name, sizeof(vdev->name)); | 478 | strlcpy(vdev->name, pdata->entity_name, sizeof(vdev->name)); |
479 | video_set_drvdata(vdev, &vcap->ved); | 479 | video_set_drvdata(vdev, &vcap->ved); |
480 | 480 | ||
481 | /* Register the video_device with the v4l2 and the media framework */ | 481 | /* Register the video_device with the v4l2 and the media framework */ |
482 | ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | 482 | ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); |
483 | if (ret) { | 483 | if (ret) { |
484 | dev_err(vcap->vdev.v4l2_dev->dev, | 484 | dev_err(comp, "%s: video register failed (err=%d)\n", |
485 | "%s: video register failed (err=%d)\n", | ||
486 | vcap->vdev.name, ret); | 485 | vcap->vdev.name, ret); |
487 | goto err_release_queue; | 486 | goto err_release_queue; |
488 | } | 487 | } |
489 | 488 | ||
490 | return &vcap->ved; | 489 | return 0; |
491 | 490 | ||
492 | err_release_queue: | 491 | err_release_queue: |
493 | vb2_queue_release(q); | 492 | vb2_queue_release(q); |
@@ -498,5 +497,45 @@ err_clean_pads: | |||
498 | err_free_vcap: | 497 | err_free_vcap: |
499 | kfree(vcap); | 498 | kfree(vcap); |
500 | 499 | ||
501 | return ERR_PTR(ret); | 500 | return ret; |
502 | } | 501 | } |
502 | |||
503 | static const struct component_ops vimc_cap_comp_ops = { | ||
504 | .bind = vimc_cap_comp_bind, | ||
505 | .unbind = vimc_cap_comp_unbind, | ||
506 | }; | ||
507 | |||
508 | static int vimc_cap_probe(struct platform_device *pdev) | ||
509 | { | ||
510 | return component_add(&pdev->dev, &vimc_cap_comp_ops); | ||
511 | } | ||
512 | |||
513 | static int vimc_cap_remove(struct platform_device *pdev) | ||
514 | { | ||
515 | component_del(&pdev->dev, &vimc_cap_comp_ops); | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static struct platform_driver vimc_cap_pdrv = { | ||
521 | .probe = vimc_cap_probe, | ||
522 | .remove = vimc_cap_remove, | ||
523 | .driver = { | ||
524 | .name = VIMC_CAP_DRV_NAME, | ||
525 | }, | ||
526 | }; | ||
527 | |||
528 | static const struct platform_device_id vimc_cap_driver_ids[] = { | ||
529 | { | ||
530 | .name = VIMC_CAP_DRV_NAME, | ||
531 | }, | ||
532 | { } | ||
533 | }; | ||
534 | |||
535 | module_platform_driver(vimc_cap_pdrv); | ||
536 | |||
537 | MODULE_DEVICE_TABLE(platform, vimc_cap_driver_ids); | ||
538 | |||
539 | MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Capture"); | ||
540 | MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>"); | ||
541 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/platform/vimc/vimc-capture.h b/drivers/media/platform/vimc/vimc-capture.h deleted file mode 100644 index 7e5c7073bcc1..000000000000 --- a/drivers/media/platform/vimc/vimc-capture.h +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | /* | ||
2 | * vimc-capture.h Virtual Media Controller Driver | ||
3 | * | ||
4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef _VIMC_CAPTURE_H_ | ||
19 | #define _VIMC_CAPTURE_H_ | ||
20 | |||
21 | #include "vimc-common.h" | ||
22 | |||
23 | struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | ||
24 | const char *const name, | ||
25 | u16 num_pads, | ||
26 | const unsigned long *pads_flag); | ||
27 | |||
28 | #endif | ||
diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index b69805574c67..da7f2b7a2e58 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c | |||
@@ -15,6 +15,9 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | |||
18 | #include "vimc-common.h" | 21 | #include "vimc-common.h" |
19 | 22 | ||
20 | static const struct vimc_pix_map vimc_pix_map_list[] = { | 23 | static const struct vimc_pix_map vimc_pix_map_list[] = { |
@@ -151,6 +154,7 @@ const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) | |||
151 | 154 | ||
152 | return &vimc_pix_map_list[i]; | 155 | return &vimc_pix_map_list[i]; |
153 | } | 156 | } |
157 | EXPORT_SYMBOL_GPL(vimc_pix_map_by_index); | ||
154 | 158 | ||
155 | const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) | 159 | const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) |
156 | { | 160 | { |
@@ -162,6 +166,7 @@ const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) | |||
162 | } | 166 | } |
163 | return NULL; | 167 | return NULL; |
164 | } | 168 | } |
169 | EXPORT_SYMBOL_GPL(vimc_pix_map_by_code); | ||
165 | 170 | ||
166 | const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) | 171 | const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) |
167 | { | 172 | { |
@@ -173,6 +178,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) | |||
173 | } | 178 | } |
174 | return NULL; | 179 | return NULL; |
175 | } | 180 | } |
181 | EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat); | ||
176 | 182 | ||
177 | int vimc_propagate_frame(struct media_pad *src, const void *frame) | 183 | int vimc_propagate_frame(struct media_pad *src, const void *frame) |
178 | { | 184 | { |
@@ -207,6 +213,7 @@ int vimc_propagate_frame(struct media_pad *src, const void *frame) | |||
207 | 213 | ||
208 | return 0; | 214 | return 0; |
209 | } | 215 | } |
216 | EXPORT_SYMBOL_GPL(vimc_propagate_frame); | ||
210 | 217 | ||
211 | /* Helper function to allocate and initialize pads */ | 218 | /* Helper function to allocate and initialize pads */ |
212 | struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) | 219 | struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) |
@@ -227,6 +234,7 @@ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) | |||
227 | 234 | ||
228 | return pads; | 235 | return pads; |
229 | } | 236 | } |
237 | EXPORT_SYMBOL_GPL(vimc_pads_init); | ||
230 | 238 | ||
231 | int vimc_pipeline_s_stream(struct media_entity *ent, int enable) | 239 | int vimc_pipeline_s_stream(struct media_entity *ent, int enable) |
232 | { | 240 | { |
@@ -242,14 +250,8 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable) | |||
242 | /* Start the stream in the subdevice direct connected */ | 250 | /* Start the stream in the subdevice direct connected */ |
243 | pad = media_entity_remote_pad(&ent->pads[i]); | 251 | pad = media_entity_remote_pad(&ent->pads[i]); |
244 | 252 | ||
245 | /* | 253 | if (!is_media_entity_v4l2_subdev(pad->entity)) |
246 | * if this is a raw node from vimc-core, then there is | 254 | return -EINVAL; |
247 | * nothing to activate | ||
248 | * TODO: remove this when there are no more raw nodes in the | ||
249 | * core and return error instead | ||
250 | */ | ||
251 | if (pad->entity->obj_type == MEDIA_ENTITY_TYPE_BASE) | ||
252 | continue; | ||
253 | 255 | ||
254 | sd = media_entity_to_v4l2_subdev(pad->entity); | 256 | sd = media_entity_to_v4l2_subdev(pad->entity); |
255 | ret = v4l2_subdev_call(sd, video, s_stream, enable); | 257 | ret = v4l2_subdev_call(sd, video, s_stream, enable); |
@@ -259,6 +261,7 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable) | |||
259 | 261 | ||
260 | return 0; | 262 | return 0; |
261 | } | 263 | } |
264 | EXPORT_SYMBOL_GPL(vimc_pipeline_s_stream); | ||
262 | 265 | ||
263 | static int vimc_get_mbus_format(struct media_pad *pad, | 266 | static int vimc_get_mbus_format(struct media_pad *pad, |
264 | struct v4l2_subdev_format *fmt) | 267 | struct v4l2_subdev_format *fmt) |
@@ -301,14 +304,6 @@ int vimc_link_validate(struct media_link *link) | |||
301 | struct v4l2_subdev_format source_fmt, sink_fmt; | 304 | struct v4l2_subdev_format source_fmt, sink_fmt; |
302 | int ret; | 305 | int ret; |
303 | 306 | ||
304 | /* | ||
305 | * if it is a raw node from vimc-core, ignore the link for now | ||
306 | * TODO: remove this when there are no more raw nodes in the | ||
307 | * core and return error instead | ||
308 | */ | ||
309 | if (link->source->entity->obj_type == MEDIA_ENTITY_TYPE_BASE) | ||
310 | return 0; | ||
311 | |||
312 | ret = vimc_get_mbus_format(link->source, &source_fmt); | 307 | ret = vimc_get_mbus_format(link->source, &source_fmt); |
313 | if (ret) | 308 | if (ret) |
314 | return ret; | 309 | return ret; |
@@ -378,6 +373,7 @@ int vimc_link_validate(struct media_link *link) | |||
378 | 373 | ||
379 | return 0; | 374 | return 0; |
380 | } | 375 | } |
376 | EXPORT_SYMBOL_GPL(vimc_link_validate); | ||
381 | 377 | ||
382 | static const struct media_entity_operations vimc_ent_sd_mops = { | 378 | static const struct media_entity_operations vimc_ent_sd_mops = { |
383 | .link_validate = vimc_link_validate, | 379 | .link_validate = vimc_link_validate, |
@@ -390,8 +386,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, | |||
390 | u32 function, | 386 | u32 function, |
391 | u16 num_pads, | 387 | u16 num_pads, |
392 | const unsigned long *pads_flag, | 388 | const unsigned long *pads_flag, |
393 | const struct v4l2_subdev_ops *sd_ops, | 389 | const struct v4l2_subdev_ops *sd_ops) |
394 | void (*sd_destroy)(struct vimc_ent_device *)) | ||
395 | { | 390 | { |
396 | int ret; | 391 | int ret; |
397 | 392 | ||
@@ -401,7 +396,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, | |||
401 | return PTR_ERR(ved->pads); | 396 | return PTR_ERR(ved->pads); |
402 | 397 | ||
403 | /* Fill the vimc_ent_device struct */ | 398 | /* Fill the vimc_ent_device struct */ |
404 | ved->destroy = sd_destroy; | ||
405 | ved->ent = &sd->entity; | 399 | ved->ent = &sd->entity; |
406 | 400 | ||
407 | /* Initialize the subdev */ | 401 | /* Initialize the subdev */ |
@@ -437,6 +431,7 @@ err_clean_pads: | |||
437 | vimc_pads_cleanup(ved->pads); | 431 | vimc_pads_cleanup(ved->pads); |
438 | return ret; | 432 | return ret; |
439 | } | 433 | } |
434 | EXPORT_SYMBOL_GPL(vimc_ent_sd_register); | ||
440 | 435 | ||
441 | void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd) | 436 | void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd) |
442 | { | 437 | { |
@@ -444,3 +439,8 @@ void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd) | |||
444 | media_entity_cleanup(ved->ent); | 439 | media_entity_cleanup(ved->ent); |
445 | vimc_pads_cleanup(ved->pads); | 440 | vimc_pads_cleanup(ved->pads); |
446 | } | 441 | } |
442 | EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister); | ||
443 | |||
444 | MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Common"); | ||
445 | MODULE_AUTHOR("Helen Koike <helen.fornazier@gmail.com>"); | ||
446 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h index fb3463c06185..a9c1cfdc0dff 100644 --- a/drivers/media/platform/vimc/vimc-common.h +++ b/drivers/media/platform/vimc/vimc-common.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * vimc-ccommon.h Virtual Media Controller Driver | 2 | * vimc-common.h Virtual Media Controller Driver |
3 | * | 3 | * |
4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | 4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> |
5 | * | 5 | * |
@@ -54,6 +54,21 @@ do { \ | |||
54 | } while (0) | 54 | } while (0) |
55 | 55 | ||
56 | /** | 56 | /** |
57 | * struct vimc_platform_data - platform data to components | ||
58 | * | ||
59 | * @entity_name: The name of the entity to be created | ||
60 | * | ||
61 | * Board setup code will often provide additional information using the device's | ||
62 | * platform_data field to hold additional information. | ||
63 | * When injecting a new platform_device in the component system the core needs | ||
64 | * to provide to the corresponding submodules the name of the entity that should | ||
65 | * be used when registering the subdevice in the Media Controller system. | ||
66 | */ | ||
67 | struct vimc_platform_data { | ||
68 | char entity_name[32]; | ||
69 | }; | ||
70 | |||
71 | /** | ||
57 | * struct vimc_pix_map - maps media bus code with v4l2 pixel format | 72 | * struct vimc_pix_map - maps media bus code with v4l2 pixel format |
58 | * | 73 | * |
59 | * @code: media bus format code defined by MEDIA_BUS_FMT_* macros | 74 | * @code: media bus format code defined by MEDIA_BUS_FMT_* macros |
@@ -74,7 +89,6 @@ struct vimc_pix_map { | |||
74 | * | 89 | * |
75 | * @ent: the pointer to struct media_entity for the node | 90 | * @ent: the pointer to struct media_entity for the node |
76 | * @pads: the list of pads of the node | 91 | * @pads: the list of pads of the node |
77 | * @destroy: callback to destroy the node | ||
78 | * @process_frame: callback send a frame to that node | 92 | * @process_frame: callback send a frame to that node |
79 | * @vdev_get_format: callback that returns the current format a pad, used | 93 | * @vdev_get_format: callback that returns the current format a pad, used |
80 | * only when is_media_entity_v4l2_video_device(ent) returns | 94 | * only when is_media_entity_v4l2_video_device(ent) returns |
@@ -91,7 +105,6 @@ struct vimc_pix_map { | |||
91 | struct vimc_ent_device { | 105 | struct vimc_ent_device { |
92 | struct media_entity *ent; | 106 | struct media_entity *ent; |
93 | struct media_pad *pads; | 107 | struct media_pad *pads; |
94 | void (*destroy)(struct vimc_ent_device *); | ||
95 | void (*process_frame)(struct vimc_ent_device *ved, | 108 | void (*process_frame)(struct vimc_ent_device *ved, |
96 | struct media_pad *sink, const void *frame); | 109 | struct media_pad *sink, const void *frame); |
97 | void (*vdev_get_format)(struct vimc_ent_device *ved, | 110 | void (*vdev_get_format)(struct vimc_ent_device *ved, |
@@ -176,7 +189,6 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); | |||
176 | * @num_pads: number of pads to initialize | 189 | * @num_pads: number of pads to initialize |
177 | * @pads_flag: flags to use in each pad | 190 | * @pads_flag: flags to use in each pad |
178 | * @sd_ops: pointer to &struct v4l2_subdev_ops. | 191 | * @sd_ops: pointer to &struct v4l2_subdev_ops. |
179 | * @sd_destroy: callback to destroy the node | ||
180 | * | 192 | * |
181 | * Helper function initialize and register the struct vimc_ent_device and struct | 193 | * Helper function initialize and register the struct vimc_ent_device and struct |
182 | * v4l2_subdev which represents a subdev node in the topology | 194 | * v4l2_subdev which represents a subdev node in the topology |
@@ -188,14 +200,13 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, | |||
188 | u32 function, | 200 | u32 function, |
189 | u16 num_pads, | 201 | u16 num_pads, |
190 | const unsigned long *pads_flag, | 202 | const unsigned long *pads_flag, |
191 | const struct v4l2_subdev_ops *sd_ops, | 203 | const struct v4l2_subdev_ops *sd_ops); |
192 | void (*sd_destroy)(struct vimc_ent_device *)); | ||
193 | 204 | ||
194 | /** | 205 | /** |
195 | * vimc_ent_sd_register - initialize and register a subdev node | 206 | * vimc_ent_sd_unregister - cleanup and unregister a subdev node |
196 | * | 207 | * |
197 | * @ved: the vimc_ent_device struct to be initialize | 208 | * @ved: the vimc_ent_device struct to be cleaned up |
198 | * @sd: the v4l2_subdev struct to be initialize and registered | 209 | * @sd: the v4l2_subdev struct to be unregistered |
199 | * | 210 | * |
200 | * Helper function cleanup and unregister the struct vimc_ent_device and struct | 211 | * Helper function cleanup and unregister the struct vimc_ent_device and struct |
201 | * v4l2_subdev which represents a subdev node in the topology | 212 | * v4l2_subdev which represents a subdev node in the topology |
diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c index afc79e2f3029..51c0eee61ca6 100644 --- a/drivers/media/platform/vimc/vimc-core.c +++ b/drivers/media/platform/vimc/vimc-core.c | |||
@@ -15,15 +15,14 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/component.h> | ||
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
21 | #include <media/media-device.h> | 22 | #include <media/media-device.h> |
22 | #include <media/v4l2-device.h> | 23 | #include <media/v4l2-device.h> |
23 | 24 | ||
24 | #include "vimc-capture.h" | ||
25 | #include "vimc-common.h" | 25 | #include "vimc-common.h" |
26 | #include "vimc-sensor.h" | ||
27 | 26 | ||
28 | #define VIMC_PDEV_NAME "vimc" | 27 | #define VIMC_PDEV_NAME "vimc" |
29 | #define VIMC_MDEV_MODEL_NAME "VIMC MDEV" | 28 | #define VIMC_MDEV_MODEL_NAME "VIMC MDEV" |
@@ -37,10 +36,10 @@ | |||
37 | } | 36 | } |
38 | 37 | ||
39 | struct vimc_device { | 38 | struct vimc_device { |
40 | /* | 39 | /* The platform device */ |
41 | * The pipeline configuration | 40 | struct platform_device pdev; |
42 | * (filled before calling vimc_device_register) | 41 | |
43 | */ | 42 | /* The pipeline configuration */ |
44 | const struct vimc_pipeline_config *pipe_cfg; | 43 | const struct vimc_pipeline_config *pipe_cfg; |
45 | 44 | ||
46 | /* The Associated media_device parent */ | 45 | /* The Associated media_device parent */ |
@@ -49,43 +48,14 @@ struct vimc_device { | |||
49 | /* Internal v4l2 parent device*/ | 48 | /* Internal v4l2 parent device*/ |
50 | struct v4l2_device v4l2_dev; | 49 | struct v4l2_device v4l2_dev; |
51 | 50 | ||
52 | /* Internal topology */ | 51 | /* Subdevices */ |
53 | struct vimc_ent_device **ved; | 52 | struct platform_device **subdevs; |
54 | }; | ||
55 | |||
56 | /** | ||
57 | * enum vimc_ent_node - Select the functionality of a node in the topology | ||
58 | * @VIMC_ENT_NODE_SENSOR: A node of type SENSOR simulates a camera sensor | ||
59 | * generating internal images in bayer format and | ||
60 | * propagating those images through the pipeline | ||
61 | * @VIMC_ENT_NODE_CAPTURE: A node of type CAPTURE is a v4l2 video_device | ||
62 | * that exposes the received image from the | ||
63 | * pipeline to the user space | ||
64 | * @VIMC_ENT_NODE_INPUT: A node of type INPUT is a v4l2 video_device that | ||
65 | * receives images from the user space and | ||
66 | * propagates them through the pipeline | ||
67 | * @VIMC_ENT_NODE_DEBAYER: A node type DEBAYER expects to receive a frame | ||
68 | * in bayer format converts it to RGB | ||
69 | * @VIMC_ENT_NODE_SCALER: A node of type SCALER scales the received image | ||
70 | * by a given multiplier | ||
71 | * | ||
72 | * This enum is used in the entity configuration struct to allow the definition | ||
73 | * of a custom topology specifying the role of each node on it. | ||
74 | */ | ||
75 | enum vimc_ent_node { | ||
76 | VIMC_ENT_NODE_SENSOR, | ||
77 | VIMC_ENT_NODE_CAPTURE, | ||
78 | VIMC_ENT_NODE_INPUT, | ||
79 | VIMC_ENT_NODE_DEBAYER, | ||
80 | VIMC_ENT_NODE_SCALER, | ||
81 | }; | 53 | }; |
82 | 54 | ||
83 | /* Structure which describes individual configuration for each entity */ | 55 | /* Structure which describes individual configuration for each entity */ |
84 | struct vimc_ent_config { | 56 | struct vimc_ent_config { |
85 | const char *name; | 57 | const char *name; |
86 | size_t pads_qty; | 58 | const char *drv; |
87 | const unsigned long *pads_flag; | ||
88 | enum vimc_ent_node node; | ||
89 | }; | 59 | }; |
90 | 60 | ||
91 | /* Structure which describes links between entities */ | 61 | /* Structure which describes links between entities */ |
@@ -112,60 +82,40 @@ struct vimc_pipeline_config { | |||
112 | static const struct vimc_ent_config ent_config[] = { | 82 | static const struct vimc_ent_config ent_config[] = { |
113 | { | 83 | { |
114 | .name = "Sensor A", | 84 | .name = "Sensor A", |
115 | .pads_qty = 1, | 85 | .drv = "vimc-sensor", |
116 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE}, | ||
117 | .node = VIMC_ENT_NODE_SENSOR, | ||
118 | }, | 86 | }, |
119 | { | 87 | { |
120 | .name = "Sensor B", | 88 | .name = "Sensor B", |
121 | .pads_qty = 1, | 89 | .drv = "vimc-sensor", |
122 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE}, | ||
123 | .node = VIMC_ENT_NODE_SENSOR, | ||
124 | }, | 90 | }, |
125 | { | 91 | { |
126 | .name = "Debayer A", | 92 | .name = "Debayer A", |
127 | .pads_qty = 2, | 93 | .drv = "vimc-debayer", |
128 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK, | ||
129 | MEDIA_PAD_FL_SOURCE}, | ||
130 | .node = VIMC_ENT_NODE_DEBAYER, | ||
131 | }, | 94 | }, |
132 | { | 95 | { |
133 | .name = "Debayer B", | 96 | .name = "Debayer B", |
134 | .pads_qty = 2, | 97 | .drv = "vimc-debayer", |
135 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK, | ||
136 | MEDIA_PAD_FL_SOURCE}, | ||
137 | .node = VIMC_ENT_NODE_DEBAYER, | ||
138 | }, | 98 | }, |
139 | { | 99 | { |
140 | .name = "Raw Capture 0", | 100 | .name = "Raw Capture 0", |
141 | .pads_qty = 1, | 101 | .drv = "vimc-capture", |
142 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK}, | ||
143 | .node = VIMC_ENT_NODE_CAPTURE, | ||
144 | }, | 102 | }, |
145 | { | 103 | { |
146 | .name = "Raw Capture 1", | 104 | .name = "Raw Capture 1", |
147 | .pads_qty = 1, | 105 | .drv = "vimc-capture", |
148 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK}, | ||
149 | .node = VIMC_ENT_NODE_CAPTURE, | ||
150 | }, | 106 | }, |
151 | { | 107 | { |
152 | .name = "RGB/YUV Input", | 108 | .name = "RGB/YUV Input", |
153 | .pads_qty = 1, | 109 | /* TODO: change this to vimc-input when it is implemented */ |
154 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE}, | 110 | .drv = "vimc-sensor", |
155 | .node = VIMC_ENT_NODE_INPUT, | ||
156 | }, | 111 | }, |
157 | { | 112 | { |
158 | .name = "Scaler", | 113 | .name = "Scaler", |
159 | .pads_qty = 2, | 114 | .drv = "vimc-scaler", |
160 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK, | ||
161 | MEDIA_PAD_FL_SOURCE}, | ||
162 | .node = VIMC_ENT_NODE_SCALER, | ||
163 | }, | 115 | }, |
164 | { | 116 | { |
165 | .name = "RGB/YUV Capture", | 117 | .name = "RGB/YUV Capture", |
166 | .pads_qty = 1, | 118 | .drv = "vimc-capture", |
167 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK}, | ||
168 | .node = VIMC_ENT_NODE_CAPTURE, | ||
169 | }, | 119 | }, |
170 | }; | 120 | }; |
171 | 121 | ||
@@ -197,111 +147,40 @@ static const struct vimc_pipeline_config pipe_cfg = { | |||
197 | 147 | ||
198 | /* -------------------------------------------------------------------------- */ | 148 | /* -------------------------------------------------------------------------- */ |
199 | 149 | ||
200 | static void vimc_device_unregister(struct vimc_device *vimc) | 150 | static int vimc_create_links(struct vimc_device *vimc) |
201 | { | 151 | { |
202 | unsigned int i; | 152 | unsigned int i; |
203 | |||
204 | media_device_unregister(&vimc->mdev); | ||
205 | /* Cleanup (only initialized) entities */ | ||
206 | for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { | ||
207 | if (vimc->ved[i] && vimc->ved[i]->destroy) | ||
208 | vimc->ved[i]->destroy(vimc->ved[i]); | ||
209 | |||
210 | vimc->ved[i] = NULL; | ||
211 | } | ||
212 | v4l2_device_unregister(&vimc->v4l2_dev); | ||
213 | media_device_cleanup(&vimc->mdev); | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * TODO: remove this function when all the | ||
218 | * entities specific code are implemented | ||
219 | */ | ||
220 | static void vimc_raw_destroy(struct vimc_ent_device *ved) | ||
221 | { | ||
222 | media_device_unregister_entity(ved->ent); | ||
223 | |||
224 | media_entity_cleanup(ved->ent); | ||
225 | |||
226 | vimc_pads_cleanup(ved->pads); | ||
227 | |||
228 | kfree(ved->ent); | ||
229 | |||
230 | kfree(ved); | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * TODO: remove this function when all the | ||
235 | * entities specific code are implemented | ||
236 | */ | ||
237 | static struct vimc_ent_device *vimc_raw_create(struct v4l2_device *v4l2_dev, | ||
238 | const char *const name, | ||
239 | u16 num_pads, | ||
240 | const unsigned long *pads_flag) | ||
241 | { | ||
242 | struct vimc_ent_device *ved; | ||
243 | int ret; | 153 | int ret; |
244 | 154 | ||
245 | /* Allocate the main ved struct */ | 155 | /* Initialize the links between entities */ |
246 | ved = kzalloc(sizeof(*ved), GFP_KERNEL); | 156 | for (i = 0; i < vimc->pipe_cfg->num_links; i++) { |
247 | if (!ved) | 157 | const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; |
248 | return ERR_PTR(-ENOMEM); | 158 | /* |
249 | 159 | * TODO: Check another way of retrieving ved struct without | |
250 | /* Allocate the media entity */ | 160 | * relying on platform_get_drvdata |
251 | ved->ent = kzalloc(sizeof(*ved->ent), GFP_KERNEL); | 161 | */ |
252 | if (!ved->ent) { | 162 | struct vimc_ent_device *ved_src = |
253 | ret = -ENOMEM; | 163 | platform_get_drvdata(vimc->subdevs[link->src_ent]); |
254 | goto err_free_ved; | 164 | struct vimc_ent_device *ved_sink = |
255 | } | 165 | platform_get_drvdata(vimc->subdevs[link->sink_ent]); |
256 | 166 | ||
257 | /* Allocate the pads */ | 167 | ret = media_create_pad_link(ved_src->ent, link->src_pad, |
258 | ved->pads = vimc_pads_init(num_pads, pads_flag); | 168 | ved_sink->ent, link->sink_pad, |
259 | if (IS_ERR(ved->pads)) { | 169 | link->flags); |
260 | ret = PTR_ERR(ved->pads); | 170 | if (ret) |
261 | goto err_free_ent; | 171 | return ret; |
262 | } | 172 | } |
263 | 173 | ||
264 | /* Initialize the media entity */ | 174 | return 0; |
265 | ved->ent->name = name; | ||
266 | ved->ent->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; | ||
267 | ret = media_entity_pads_init(ved->ent, num_pads, ved->pads); | ||
268 | if (ret) | ||
269 | goto err_cleanup_pads; | ||
270 | |||
271 | /* Register the media entity */ | ||
272 | ret = media_device_register_entity(v4l2_dev->mdev, ved->ent); | ||
273 | if (ret) | ||
274 | goto err_cleanup_entity; | ||
275 | |||
276 | /* Fill out the destroy function and return */ | ||
277 | ved->destroy = vimc_raw_destroy; | ||
278 | return ved; | ||
279 | |||
280 | err_cleanup_entity: | ||
281 | media_entity_cleanup(ved->ent); | ||
282 | err_cleanup_pads: | ||
283 | vimc_pads_cleanup(ved->pads); | ||
284 | err_free_ent: | ||
285 | kfree(ved->ent); | ||
286 | err_free_ved: | ||
287 | kfree(ved); | ||
288 | |||
289 | return ERR_PTR(ret); | ||
290 | } | 175 | } |
291 | 176 | ||
292 | static int vimc_device_register(struct vimc_device *vimc) | 177 | static int vimc_comp_bind(struct device *master) |
293 | { | 178 | { |
294 | unsigned int i; | 179 | struct vimc_device *vimc = container_of(to_platform_device(master), |
180 | struct vimc_device, pdev); | ||
295 | int ret; | 181 | int ret; |
296 | 182 | ||
297 | /* Allocate memory for the vimc_ent_devices pointers */ | 183 | dev_dbg(master, "bind"); |
298 | vimc->ved = devm_kcalloc(vimc->mdev.dev, vimc->pipe_cfg->num_ents, | ||
299 | sizeof(*vimc->ved), GFP_KERNEL); | ||
300 | if (!vimc->ved) | ||
301 | return -ENOMEM; | ||
302 | |||
303 | /* Link the media device within the v4l2_device */ | ||
304 | vimc->v4l2_dev.mdev = &vimc->mdev; | ||
305 | 184 | ||
306 | /* Register the v4l2 struct */ | 185 | /* Register the v4l2 struct */ |
307 | ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev); | 186 | ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev); |
@@ -311,66 +190,22 @@ static int vimc_device_register(struct vimc_device *vimc) | |||
311 | return ret; | 190 | return ret; |
312 | } | 191 | } |
313 | 192 | ||
314 | /* Initialize entities */ | 193 | /* Bind subdevices */ |
315 | for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { | 194 | ret = component_bind_all(master, &vimc->v4l2_dev); |
316 | struct vimc_ent_device *(*create_func)(struct v4l2_device *, | 195 | if (ret) |
317 | const char *const, | 196 | goto err_v4l2_unregister; |
318 | u16, | ||
319 | const unsigned long *); | ||
320 | |||
321 | /* Register the specific node */ | ||
322 | switch (vimc->pipe_cfg->ents[i].node) { | ||
323 | case VIMC_ENT_NODE_SENSOR: | ||
324 | create_func = vimc_sen_create; | ||
325 | break; | ||
326 | |||
327 | case VIMC_ENT_NODE_CAPTURE: | ||
328 | create_func = vimc_cap_create; | ||
329 | break; | ||
330 | |||
331 | /* TODO: Instantiate the specific topology node */ | ||
332 | case VIMC_ENT_NODE_INPUT: | ||
333 | case VIMC_ENT_NODE_DEBAYER: | ||
334 | case VIMC_ENT_NODE_SCALER: | ||
335 | default: | ||
336 | /* | ||
337 | * TODO: remove this when all the entities specific | ||
338 | * code are implemented | ||
339 | */ | ||
340 | create_func = vimc_raw_create; | ||
341 | break; | ||
342 | } | ||
343 | |||
344 | vimc->ved[i] = create_func(&vimc->v4l2_dev, | ||
345 | vimc->pipe_cfg->ents[i].name, | ||
346 | vimc->pipe_cfg->ents[i].pads_qty, | ||
347 | vimc->pipe_cfg->ents[i].pads_flag); | ||
348 | if (IS_ERR(vimc->ved[i])) { | ||
349 | ret = PTR_ERR(vimc->ved[i]); | ||
350 | vimc->ved[i] = NULL; | ||
351 | goto err; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | /* Initialize the links between entities */ | ||
356 | for (i = 0; i < vimc->pipe_cfg->num_links; i++) { | ||
357 | const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; | ||
358 | 197 | ||
359 | ret = media_create_pad_link(vimc->ved[link->src_ent]->ent, | 198 | /* Initialize links */ |
360 | link->src_pad, | 199 | ret = vimc_create_links(vimc); |
361 | vimc->ved[link->sink_ent]->ent, | 200 | if (ret) |
362 | link->sink_pad, | 201 | goto err_comp_unbind_all; |
363 | link->flags); | ||
364 | if (ret) | ||
365 | goto err; | ||
366 | } | ||
367 | 202 | ||
368 | /* Register the media device */ | 203 | /* Register the media device */ |
369 | ret = media_device_register(&vimc->mdev); | 204 | ret = media_device_register(&vimc->mdev); |
370 | if (ret) { | 205 | if (ret) { |
371 | dev_err(vimc->mdev.dev, | 206 | dev_err(vimc->mdev.dev, |
372 | "media device register failed (err=%d)\n", ret); | 207 | "media device register failed (err=%d)\n", ret); |
373 | return ret; | 208 | goto err_comp_unbind_all; |
374 | } | 209 | } |
375 | 210 | ||
376 | /* Expose all subdev's nodes*/ | 211 | /* Expose all subdev's nodes*/ |
@@ -379,32 +214,106 @@ static int vimc_device_register(struct vimc_device *vimc) | |||
379 | dev_err(vimc->mdev.dev, | 214 | dev_err(vimc->mdev.dev, |
380 | "vimc subdev nodes registration failed (err=%d)\n", | 215 | "vimc subdev nodes registration failed (err=%d)\n", |
381 | ret); | 216 | ret); |
382 | goto err; | 217 | goto err_mdev_unregister; |
383 | } | 218 | } |
384 | 219 | ||
385 | return 0; | 220 | return 0; |
386 | 221 | ||
387 | err: | 222 | err_mdev_unregister: |
388 | /* Destroy the so far created topology */ | 223 | media_device_unregister(&vimc->mdev); |
389 | vimc_device_unregister(vimc); | 224 | err_comp_unbind_all: |
225 | component_unbind_all(master, NULL); | ||
226 | err_v4l2_unregister: | ||
227 | v4l2_device_unregister(&vimc->v4l2_dev); | ||
390 | 228 | ||
391 | return ret; | 229 | return ret; |
392 | } | 230 | } |
393 | 231 | ||
232 | static void vimc_comp_unbind(struct device *master) | ||
233 | { | ||
234 | struct vimc_device *vimc = container_of(to_platform_device(master), | ||
235 | struct vimc_device, pdev); | ||
236 | |||
237 | dev_dbg(master, "unbind"); | ||
238 | |||
239 | media_device_unregister(&vimc->mdev); | ||
240 | component_unbind_all(master, NULL); | ||
241 | v4l2_device_unregister(&vimc->v4l2_dev); | ||
242 | } | ||
243 | |||
244 | static int vimc_comp_compare(struct device *comp, void *data) | ||
245 | { | ||
246 | const struct platform_device *pdev = to_platform_device(comp); | ||
247 | const char *name = data; | ||
248 | |||
249 | return !strcmp(pdev->dev.platform_data, name); | ||
250 | } | ||
251 | |||
252 | static struct component_match *vimc_add_subdevs(struct vimc_device *vimc) | ||
253 | { | ||
254 | struct component_match *match = NULL; | ||
255 | struct vimc_platform_data pdata; | ||
256 | int i; | ||
257 | |||
258 | for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { | ||
259 | dev_dbg(&vimc->pdev.dev, "new pdev for %s\n", | ||
260 | vimc->pipe_cfg->ents[i].drv); | ||
261 | |||
262 | strlcpy(pdata.entity_name, vimc->pipe_cfg->ents[i].name, | ||
263 | sizeof(pdata.entity_name)); | ||
264 | |||
265 | vimc->subdevs[i] = platform_device_register_data(&vimc->pdev.dev, | ||
266 | vimc->pipe_cfg->ents[i].drv, | ||
267 | PLATFORM_DEVID_AUTO, | ||
268 | &pdata, | ||
269 | sizeof(pdata)); | ||
270 | if (!vimc->subdevs[i]) { | ||
271 | while (--i >= 0) | ||
272 | platform_device_unregister(vimc->subdevs[i]); | ||
273 | |||
274 | return ERR_PTR(-ENOMEM); | ||
275 | } | ||
276 | |||
277 | component_match_add(&vimc->pdev.dev, &match, vimc_comp_compare, | ||
278 | (void *)vimc->pipe_cfg->ents[i].name); | ||
279 | } | ||
280 | |||
281 | return match; | ||
282 | } | ||
283 | |||
284 | static void vimc_rm_subdevs(struct vimc_device *vimc) | ||
285 | { | ||
286 | unsigned int i; | ||
287 | |||
288 | for (i = 0; i < vimc->pipe_cfg->num_ents; i++) | ||
289 | platform_device_unregister(vimc->subdevs[i]); | ||
290 | } | ||
291 | |||
292 | static const struct component_master_ops vimc_comp_ops = { | ||
293 | .bind = vimc_comp_bind, | ||
294 | .unbind = vimc_comp_unbind, | ||
295 | }; | ||
296 | |||
394 | static int vimc_probe(struct platform_device *pdev) | 297 | static int vimc_probe(struct platform_device *pdev) |
395 | { | 298 | { |
396 | struct vimc_device *vimc; | 299 | struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev); |
300 | struct component_match *match = NULL; | ||
397 | int ret; | 301 | int ret; |
398 | 302 | ||
399 | /* Prepare the vimc topology structure */ | 303 | dev_dbg(&pdev->dev, "probe"); |
400 | 304 | ||
401 | /* Allocate memory for the vimc structure */ | 305 | /* Create platform_device for each entity in the topology*/ |
402 | vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); | 306 | vimc->subdevs = devm_kcalloc(&vimc->pdev.dev, vimc->pipe_cfg->num_ents, |
403 | if (!vimc) | 307 | sizeof(*vimc->subdevs), GFP_KERNEL); |
308 | if (!vimc->subdevs) | ||
404 | return -ENOMEM; | 309 | return -ENOMEM; |
405 | 310 | ||
406 | /* Set the pipeline configuration struct */ | 311 | match = vimc_add_subdevs(vimc); |
407 | vimc->pipe_cfg = &pipe_cfg; | 312 | if (IS_ERR(match)) |
313 | return PTR_ERR(match); | ||
314 | |||
315 | /* Link the media device within the v4l2_device */ | ||
316 | vimc->v4l2_dev.mdev = &vimc->mdev; | ||
408 | 317 | ||
409 | /* Initialize media device */ | 318 | /* Initialize media device */ |
410 | strlcpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, | 319 | strlcpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, |
@@ -412,28 +321,27 @@ static int vimc_probe(struct platform_device *pdev) | |||
412 | vimc->mdev.dev = &pdev->dev; | 321 | vimc->mdev.dev = &pdev->dev; |
413 | media_device_init(&vimc->mdev); | 322 | media_device_init(&vimc->mdev); |
414 | 323 | ||
415 | /* Create vimc topology */ | 324 | /* Add self to the component system */ |
416 | ret = vimc_device_register(vimc); | 325 | ret = component_master_add_with_match(&pdev->dev, &vimc_comp_ops, |
326 | match); | ||
417 | if (ret) { | 327 | if (ret) { |
418 | dev_err(vimc->mdev.dev, | 328 | media_device_cleanup(&vimc->mdev); |
419 | "vimc device registration failed (err=%d)\n", ret); | 329 | vimc_rm_subdevs(vimc); |
420 | kfree(vimc); | 330 | kfree(vimc); |
421 | return ret; | 331 | return ret; |
422 | } | 332 | } |
423 | 333 | ||
424 | /* Link the topology object with the platform device object */ | ||
425 | platform_set_drvdata(pdev, vimc); | ||
426 | |||
427 | return 0; | 334 | return 0; |
428 | } | 335 | } |
429 | 336 | ||
430 | static int vimc_remove(struct platform_device *pdev) | 337 | static int vimc_remove(struct platform_device *pdev) |
431 | { | 338 | { |
432 | struct vimc_device *vimc = platform_get_drvdata(pdev); | 339 | struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev); |
433 | 340 | ||
434 | /* Destroy all the topology */ | 341 | dev_dbg(&pdev->dev, "remove"); |
435 | vimc_device_unregister(vimc); | 342 | |
436 | kfree(vimc); | 343 | component_master_del(&pdev->dev, &vimc_comp_ops); |
344 | vimc_rm_subdevs(vimc); | ||
437 | 345 | ||
438 | return 0; | 346 | return 0; |
439 | } | 347 | } |
@@ -442,9 +350,12 @@ static void vimc_dev_release(struct device *dev) | |||
442 | { | 350 | { |
443 | } | 351 | } |
444 | 352 | ||
445 | static struct platform_device vimc_pdev = { | 353 | static struct vimc_device vimc_dev = { |
446 | .name = VIMC_PDEV_NAME, | 354 | .pipe_cfg = &pipe_cfg, |
447 | .dev.release = vimc_dev_release, | 355 | .pdev = { |
356 | .name = VIMC_PDEV_NAME, | ||
357 | .dev.release = vimc_dev_release, | ||
358 | } | ||
448 | }; | 359 | }; |
449 | 360 | ||
450 | static struct platform_driver vimc_pdrv = { | 361 | static struct platform_driver vimc_pdrv = { |
@@ -459,29 +370,29 @@ static int __init vimc_init(void) | |||
459 | { | 370 | { |
460 | int ret; | 371 | int ret; |
461 | 372 | ||
462 | ret = platform_device_register(&vimc_pdev); | 373 | ret = platform_device_register(&vimc_dev.pdev); |
463 | if (ret) { | 374 | if (ret) { |
464 | dev_err(&vimc_pdev.dev, | 375 | dev_err(&vimc_dev.pdev.dev, |
465 | "platform device registration failed (err=%d)\n", ret); | 376 | "platform device registration failed (err=%d)\n", ret); |
466 | return ret; | 377 | return ret; |
467 | } | 378 | } |
468 | 379 | ||
469 | ret = platform_driver_register(&vimc_pdrv); | 380 | ret = platform_driver_register(&vimc_pdrv); |
470 | if (ret) { | 381 | if (ret) { |
471 | dev_err(&vimc_pdev.dev, | 382 | dev_err(&vimc_dev.pdev.dev, |
472 | "platform driver registration failed (err=%d)\n", ret); | 383 | "platform driver registration failed (err=%d)\n", ret); |
473 | 384 | platform_driver_unregister(&vimc_pdrv); | |
474 | platform_device_unregister(&vimc_pdev); | 385 | return ret; |
475 | } | 386 | } |
476 | 387 | ||
477 | return ret; | 388 | return 0; |
478 | } | 389 | } |
479 | 390 | ||
480 | static void __exit vimc_exit(void) | 391 | static void __exit vimc_exit(void) |
481 | { | 392 | { |
482 | platform_driver_unregister(&vimc_pdrv); | 393 | platform_driver_unregister(&vimc_pdrv); |
483 | 394 | ||
484 | platform_device_unregister(&vimc_pdev); | 395 | platform_device_unregister(&vimc_dev.pdev); |
485 | } | 396 | } |
486 | 397 | ||
487 | module_init(vimc_init); | 398 | module_init(vimc_init); |
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index d4f97050b544..5ea7b0853936 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c | |||
@@ -15,18 +15,24 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/component.h> | ||
18 | #include <linux/freezer.h> | 19 | #include <linux/freezer.h> |
19 | #include <linux/kthread.h> | 20 | #include <linux/kthread.h> |
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
20 | #include <linux/v4l2-mediabus.h> | 23 | #include <linux/v4l2-mediabus.h> |
21 | #include <linux/vmalloc.h> | 24 | #include <linux/vmalloc.h> |
22 | #include <media/v4l2-subdev.h> | 25 | #include <media/v4l2-subdev.h> |
23 | #include <media/v4l2-tpg.h> | 26 | #include <media/v4l2-tpg.h> |
24 | 27 | ||
25 | #include "vimc-sensor.h" | 28 | #include "vimc-common.h" |
29 | |||
30 | #define VIMC_SEN_DRV_NAME "vimc-sensor" | ||
26 | 31 | ||
27 | struct vimc_sen_device { | 32 | struct vimc_sen_device { |
28 | struct vimc_ent_device ved; | 33 | struct vimc_ent_device ved; |
29 | struct v4l2_subdev sd; | 34 | struct v4l2_subdev sd; |
35 | struct device *dev; | ||
30 | struct tpg_data tpg; | 36 | struct tpg_data tpg; |
31 | struct task_struct *kthread_sen; | 37 | struct task_struct *kthread_sen; |
32 | u8 *frame; | 38 | u8 *frame; |
@@ -166,7 +172,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, | |||
166 | /* Set the new format */ | 172 | /* Set the new format */ |
167 | vimc_sen_adjust_fmt(&fmt->format); | 173 | vimc_sen_adjust_fmt(&fmt->format); |
168 | 174 | ||
169 | dev_dbg(vsen->sd.v4l2_dev->mdev->dev, "%s: format update: " | 175 | dev_dbg(vsen->dev, "%s: format update: " |
170 | "old:%dx%d (0x%x, %d, %d, %d, %d) " | 176 | "old:%dx%d (0x%x, %d, %d, %d, %d) " |
171 | "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name, | 177 | "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name, |
172 | /* old */ | 178 | /* old */ |
@@ -252,8 +258,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) | |||
252 | vsen->kthread_sen = kthread_run(vimc_sen_tpg_thread, vsen, | 258 | vsen->kthread_sen = kthread_run(vimc_sen_tpg_thread, vsen, |
253 | "%s-sen", vsen->sd.v4l2_dev->name); | 259 | "%s-sen", vsen->sd.v4l2_dev->name); |
254 | if (IS_ERR(vsen->kthread_sen)) { | 260 | if (IS_ERR(vsen->kthread_sen)) { |
255 | dev_err(vsen->sd.v4l2_dev->dev, | 261 | dev_err(vsen->dev, "%s: kernel_thread() failed\n", |
256 | "%s: kernel_thread() failed\n", vsen->sd.name); | 262 | vsen->sd.name); |
257 | vfree(vsen->frame); | 263 | vfree(vsen->frame); |
258 | vsen->frame = NULL; | 264 | vsen->frame = NULL; |
259 | return PTR_ERR(vsen->kthread_sen); | 265 | return PTR_ERR(vsen->kthread_sen); |
@@ -285,8 +291,10 @@ static const struct v4l2_subdev_ops vimc_sen_ops = { | |||
285 | .video = &vimc_sen_video_ops, | 291 | .video = &vimc_sen_video_ops, |
286 | }; | 292 | }; |
287 | 293 | ||
288 | static void vimc_sen_destroy(struct vimc_ent_device *ved) | 294 | static void vimc_sen_comp_unbind(struct device *comp, struct device *master, |
295 | void *master_data) | ||
289 | { | 296 | { |
297 | struct vimc_ent_device *ved = dev_get_drvdata(comp); | ||
290 | struct vimc_sen_device *vsen = | 298 | struct vimc_sen_device *vsen = |
291 | container_of(ved, struct vimc_sen_device, ved); | 299 | container_of(ved, struct vimc_sen_device, ved); |
292 | 300 | ||
@@ -295,36 +303,31 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved) | |||
295 | kfree(vsen); | 303 | kfree(vsen); |
296 | } | 304 | } |
297 | 305 | ||
298 | struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, | 306 | static int vimc_sen_comp_bind(struct device *comp, struct device *master, |
299 | const char *const name, | 307 | void *master_data) |
300 | u16 num_pads, | ||
301 | const unsigned long *pads_flag) | ||
302 | { | 308 | { |
309 | struct v4l2_device *v4l2_dev = master_data; | ||
310 | struct vimc_platform_data *pdata = comp->platform_data; | ||
303 | struct vimc_sen_device *vsen; | 311 | struct vimc_sen_device *vsen; |
304 | unsigned int i; | ||
305 | int ret; | 312 | int ret; |
306 | 313 | ||
307 | /* NOTE: a sensor node may be created with more then one pad */ | ||
308 | if (!name || !num_pads || !pads_flag) | ||
309 | return ERR_PTR(-EINVAL); | ||
310 | |||
311 | /* check if all pads are sources */ | ||
312 | for (i = 0; i < num_pads; i++) | ||
313 | if (!(pads_flag[i] & MEDIA_PAD_FL_SOURCE)) | ||
314 | return ERR_PTR(-EINVAL); | ||
315 | |||
316 | /* Allocate the vsen struct */ | 314 | /* Allocate the vsen struct */ |
317 | vsen = kzalloc(sizeof(*vsen), GFP_KERNEL); | 315 | vsen = kzalloc(sizeof(*vsen), GFP_KERNEL); |
318 | if (!vsen) | 316 | if (!vsen) |
319 | return ERR_PTR(-ENOMEM); | 317 | return -ENOMEM; |
320 | 318 | ||
321 | /* Initialize ved and sd */ | 319 | /* Initialize ved and sd */ |
322 | ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, name, | 320 | ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, |
323 | MEDIA_ENT_F_CAM_SENSOR, num_pads, pads_flag, | 321 | pdata->entity_name, |
324 | &vimc_sen_ops, vimc_sen_destroy); | 322 | MEDIA_ENT_F_ATV_DECODER, 1, |
323 | (const unsigned long[1]) {MEDIA_PAD_FL_SOURCE}, | ||
324 | &vimc_sen_ops); | ||
325 | if (ret) | 325 | if (ret) |
326 | goto err_free_vsen; | 326 | goto err_free_vsen; |
327 | 327 | ||
328 | dev_set_drvdata(comp, &vsen->ved); | ||
329 | vsen->dev = comp; | ||
330 | |||
328 | /* Initialize the frame format */ | 331 | /* Initialize the frame format */ |
329 | vsen->mbus_format = fmt_default; | 332 | vsen->mbus_format = fmt_default; |
330 | 333 | ||
@@ -335,12 +338,52 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, | |||
335 | if (ret) | 338 | if (ret) |
336 | goto err_unregister_ent_sd; | 339 | goto err_unregister_ent_sd; |
337 | 340 | ||
338 | return &vsen->ved; | 341 | return 0; |
339 | 342 | ||
340 | err_unregister_ent_sd: | 343 | err_unregister_ent_sd: |
341 | vimc_ent_sd_unregister(&vsen->ved, &vsen->sd); | 344 | vimc_ent_sd_unregister(&vsen->ved, &vsen->sd); |
342 | err_free_vsen: | 345 | err_free_vsen: |
343 | kfree(vsen); | 346 | kfree(vsen); |
344 | 347 | ||
345 | return ERR_PTR(ret); | 348 | return ret; |
346 | } | 349 | } |
350 | |||
351 | static const struct component_ops vimc_sen_comp_ops = { | ||
352 | .bind = vimc_sen_comp_bind, | ||
353 | .unbind = vimc_sen_comp_unbind, | ||
354 | }; | ||
355 | |||
356 | static int vimc_sen_probe(struct platform_device *pdev) | ||
357 | { | ||
358 | return component_add(&pdev->dev, &vimc_sen_comp_ops); | ||
359 | } | ||
360 | |||
361 | static int vimc_sen_remove(struct platform_device *pdev) | ||
362 | { | ||
363 | component_del(&pdev->dev, &vimc_sen_comp_ops); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static struct platform_driver vimc_sen_pdrv = { | ||
369 | .probe = vimc_sen_probe, | ||
370 | .remove = vimc_sen_remove, | ||
371 | .driver = { | ||
372 | .name = VIMC_SEN_DRV_NAME, | ||
373 | }, | ||
374 | }; | ||
375 | |||
376 | static const struct platform_device_id vimc_sen_driver_ids[] = { | ||
377 | { | ||
378 | .name = VIMC_SEN_DRV_NAME, | ||
379 | }, | ||
380 | { } | ||
381 | }; | ||
382 | |||
383 | module_platform_driver(vimc_sen_pdrv); | ||
384 | |||
385 | MODULE_DEVICE_TABLE(platform, vimc_sen_driver_ids); | ||
386 | |||
387 | MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Sensor"); | ||
388 | MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>"); | ||
389 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/platform/vimc/vimc-sensor.h b/drivers/media/platform/vimc/vimc-sensor.h deleted file mode 100644 index 580dcec3f79c..000000000000 --- a/drivers/media/platform/vimc/vimc-sensor.h +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | /* | ||
2 | * vimc-sensor.h Virtual Media Controller Driver | ||
3 | * | ||
4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef _VIMC_SENSOR_H_ | ||
19 | #define _VIMC_SENSOR_H_ | ||
20 | |||
21 | #include "vimc-common.h" | ||
22 | |||
23 | struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, | ||
24 | const char *const name, | ||
25 | u16 num_pads, | ||
26 | const unsigned long *pads_flag); | ||
27 | |||
28 | #endif | ||