Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Helen Fornazier and committed by
Mauro Carvalho Chehab
4a29b709 535d296f

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