Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.7 381 lines 9.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * vimc-core.c Virtual Media Controller Driver 4 * 5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> 6 */ 7 8#include <linux/init.h> 9#include <linux/module.h> 10#include <linux/platform_device.h> 11#include <media/media-device.h> 12#include <media/v4l2-device.h> 13 14#include "vimc-common.h" 15 16#define VIMC_MDEV_MODEL_NAME "VIMC MDEV" 17 18#define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ 19 .src_ent = src, \ 20 .src_pad = srcpad, \ 21 .sink_ent = sink, \ 22 .sink_pad = sinkpad, \ 23 .flags = link_flags, \ 24} 25 26/* Structure which describes links between entities */ 27struct vimc_ent_link { 28 unsigned int src_ent; 29 u16 src_pad; 30 unsigned int sink_ent; 31 u16 sink_pad; 32 u32 flags; 33}; 34 35/* Structure which describes the whole topology */ 36struct vimc_pipeline_config { 37 const struct vimc_ent_config *ents; 38 size_t num_ents; 39 const struct vimc_ent_link *links; 40 size_t num_links; 41}; 42 43/* -------------------------------------------------------------------------- 44 * Topology Configuration 45 */ 46 47static struct vimc_ent_config ent_config[] = { 48 { 49 .name = "Sensor A", 50 .add = vimc_sen_add, 51 .release = vimc_sen_release, 52 }, 53 { 54 .name = "Sensor B", 55 .add = vimc_sen_add, 56 .release = vimc_sen_release, 57 }, 58 { 59 .name = "Debayer A", 60 .add = vimc_deb_add, 61 .release = vimc_deb_release, 62 }, 63 { 64 .name = "Debayer B", 65 .add = vimc_deb_add, 66 .release = vimc_deb_release, 67 }, 68 { 69 .name = "Raw Capture 0", 70 .add = vimc_cap_add, 71 .unregister = vimc_cap_unregister, 72 .release = vimc_cap_release, 73 }, 74 { 75 .name = "Raw Capture 1", 76 .add = vimc_cap_add, 77 .unregister = vimc_cap_unregister, 78 .release = vimc_cap_release, 79 }, 80 { 81 /* TODO: change this to vimc-input when it is implemented */ 82 .name = "RGB/YUV Input", 83 .add = vimc_sen_add, 84 .release = vimc_sen_release, 85 }, 86 { 87 .name = "Scaler", 88 .add = vimc_sca_add, 89 .release = vimc_sca_release, 90 }, 91 { 92 .name = "RGB/YUV Capture", 93 .add = vimc_cap_add, 94 .unregister = vimc_cap_unregister, 95 .release = vimc_cap_release, 96 }, 97}; 98 99static const struct vimc_ent_link ent_links[] = { 100 /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */ 101 VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 102 /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */ 103 VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 104 /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */ 105 VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 106 /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */ 107 VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 108 /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */ 109 VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED), 110 /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */ 111 VIMC_ENT_LINK(3, 1, 7, 0, 0), 112 /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */ 113 VIMC_ENT_LINK(6, 0, 7, 0, 0), 114 /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */ 115 VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 116}; 117 118static struct vimc_pipeline_config pipe_cfg = { 119 .ents = ent_config, 120 .num_ents = ARRAY_SIZE(ent_config), 121 .links = ent_links, 122 .num_links = ARRAY_SIZE(ent_links) 123}; 124 125/* -------------------------------------------------------------------------- */ 126 127static void vimc_rm_links(struct vimc_device *vimc) 128{ 129 unsigned int i; 130 131 for (i = 0; i < vimc->pipe_cfg->num_ents; i++) 132 media_entity_remove_links(vimc->ent_devs[i]->ent); 133} 134 135static int vimc_create_links(struct vimc_device *vimc) 136{ 137 unsigned int i; 138 int ret; 139 140 /* Initialize the links between entities */ 141 for (i = 0; i < vimc->pipe_cfg->num_links; i++) { 142 const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; 143 144 struct vimc_ent_device *ved_src = 145 vimc->ent_devs[link->src_ent]; 146 struct vimc_ent_device *ved_sink = 147 vimc->ent_devs[link->sink_ent]; 148 149 ret = media_create_pad_link(ved_src->ent, link->src_pad, 150 ved_sink->ent, link->sink_pad, 151 link->flags); 152 if (ret) 153 goto err_rm_links; 154 } 155 156 return 0; 157 158err_rm_links: 159 vimc_rm_links(vimc); 160 return ret; 161} 162 163static int vimc_add_subdevs(struct vimc_device *vimc) 164{ 165 unsigned int i; 166 167 for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { 168 dev_dbg(vimc->mdev.dev, "new entity for %s\n", 169 vimc->pipe_cfg->ents[i].name); 170 vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].add(vimc, 171 vimc->pipe_cfg->ents[i].name); 172 if (!vimc->ent_devs[i]) { 173 dev_err(vimc->mdev.dev, "add new entity for %s\n", 174 vimc->pipe_cfg->ents[i].name); 175 return -EINVAL; 176 } 177 } 178 return 0; 179} 180 181static void vimc_release_subdevs(struct vimc_device *vimc) 182{ 183 unsigned int i; 184 185 for (i = 0; i < vimc->pipe_cfg->num_ents; i++) 186 if (vimc->ent_devs[i]) 187 vimc->pipe_cfg->ents[i].release(vimc->ent_devs[i]); 188} 189 190static void vimc_unregister_subdevs(struct vimc_device *vimc) 191{ 192 unsigned int i; 193 194 for (i = 0; i < vimc->pipe_cfg->num_ents; i++) 195 if (vimc->ent_devs[i] && vimc->pipe_cfg->ents[i].unregister) 196 vimc->pipe_cfg->ents[i].unregister(vimc->ent_devs[i]); 197} 198 199static void vimc_v4l2_dev_release(struct v4l2_device *v4l2_dev) 200{ 201 struct vimc_device *vimc = 202 container_of(v4l2_dev, struct vimc_device, v4l2_dev); 203 204 vimc_release_subdevs(vimc); 205 media_device_cleanup(&vimc->mdev); 206 kfree(vimc->ent_devs); 207 kfree(vimc); 208} 209 210static int vimc_register_devices(struct vimc_device *vimc) 211{ 212 int ret; 213 214 /* Register the v4l2 struct */ 215 ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev); 216 if (ret) { 217 dev_err(vimc->mdev.dev, 218 "v4l2 device register failed (err=%d)\n", ret); 219 return ret; 220 } 221 /* allocate ent_devs */ 222 vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents, 223 sizeof(*vimc->ent_devs), GFP_KERNEL); 224 if (!vimc->ent_devs) { 225 ret = -ENOMEM; 226 goto err_v4l2_unregister; 227 } 228 229 /* Invoke entity config hooks to initialize and register subdevs */ 230 ret = vimc_add_subdevs(vimc); 231 if (ret) 232 /* remove sundevs that got added */ 233 goto err_rm_subdevs; 234 235 /* Initialize links */ 236 ret = vimc_create_links(vimc); 237 if (ret) 238 goto err_rm_subdevs; 239 240 /* Register the media device */ 241 ret = media_device_register(&vimc->mdev); 242 if (ret) { 243 dev_err(vimc->mdev.dev, 244 "media device register failed (err=%d)\n", ret); 245 goto err_rm_subdevs; 246 } 247 248 /* Expose all subdev's nodes*/ 249 ret = v4l2_device_register_subdev_nodes(&vimc->v4l2_dev); 250 if (ret) { 251 dev_err(vimc->mdev.dev, 252 "vimc subdev nodes registration failed (err=%d)\n", 253 ret); 254 goto err_mdev_unregister; 255 } 256 257 return 0; 258 259err_mdev_unregister: 260 media_device_unregister(&vimc->mdev); 261err_rm_subdevs: 262 vimc_unregister_subdevs(vimc); 263 vimc_release_subdevs(vimc); 264 kfree(vimc->ent_devs); 265err_v4l2_unregister: 266 v4l2_device_unregister(&vimc->v4l2_dev); 267 268 return ret; 269} 270 271static void vimc_unregister(struct vimc_device *vimc) 272{ 273 vimc_unregister_subdevs(vimc); 274 media_device_unregister(&vimc->mdev); 275 v4l2_device_unregister(&vimc->v4l2_dev); 276} 277 278static int vimc_probe(struct platform_device *pdev) 279{ 280 struct vimc_device *vimc; 281 int ret; 282 283 dev_dbg(&pdev->dev, "probe"); 284 285 vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); 286 if (!vimc) 287 return -ENOMEM; 288 289 vimc->pipe_cfg = &pipe_cfg; 290 291 /* Link the media device within the v4l2_device */ 292 vimc->v4l2_dev.mdev = &vimc->mdev; 293 294 /* Initialize media device */ 295 strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, 296 sizeof(vimc->mdev.model)); 297 snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info), 298 "platform:%s", VIMC_PDEV_NAME); 299 vimc->mdev.dev = &pdev->dev; 300 media_device_init(&vimc->mdev); 301 302 ret = vimc_register_devices(vimc); 303 if (ret) { 304 media_device_cleanup(&vimc->mdev); 305 kfree(vimc); 306 return ret; 307 } 308 /* 309 * the release cb is set only after successful registration. 310 * if the registration fails, we release directly from probe 311 */ 312 313 vimc->v4l2_dev.release = vimc_v4l2_dev_release; 314 platform_set_drvdata(pdev, vimc); 315 return 0; 316} 317 318static int vimc_remove(struct platform_device *pdev) 319{ 320 struct vimc_device *vimc = platform_get_drvdata(pdev); 321 322 dev_dbg(&pdev->dev, "remove"); 323 324 vimc_unregister(vimc); 325 v4l2_device_put(&vimc->v4l2_dev); 326 327 return 0; 328} 329 330static void vimc_dev_release(struct device *dev) 331{ 332} 333 334static struct platform_device vimc_pdev = { 335 .name = VIMC_PDEV_NAME, 336 .dev.release = vimc_dev_release, 337}; 338 339static struct platform_driver vimc_pdrv = { 340 .probe = vimc_probe, 341 .remove = vimc_remove, 342 .driver = { 343 .name = VIMC_PDEV_NAME, 344 }, 345}; 346 347static int __init vimc_init(void) 348{ 349 int ret; 350 351 ret = platform_device_register(&vimc_pdev); 352 if (ret) { 353 dev_err(&vimc_pdev.dev, 354 "platform device registration failed (err=%d)\n", ret); 355 return ret; 356 } 357 358 ret = platform_driver_register(&vimc_pdrv); 359 if (ret) { 360 dev_err(&vimc_pdev.dev, 361 "platform driver registration failed (err=%d)\n", ret); 362 platform_driver_unregister(&vimc_pdrv); 363 return ret; 364 } 365 366 return 0; 367} 368 369static void __exit vimc_exit(void) 370{ 371 platform_driver_unregister(&vimc_pdrv); 372 373 platform_device_unregister(&vimc_pdev); 374} 375 376module_init(vimc_init); 377module_exit(vimc_exit); 378 379MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)"); 380MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>"); 381MODULE_LICENSE("GPL");