root/drivers/media/platform/vimc/vimc-core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vimc_create_links
  2. vimc_comp_bind
  3. vimc_comp_unbind
  4. vimc_comp_compare
  5. vimc_add_subdevs
  6. vimc_rm_subdevs
  7. vimc_probe
  8. vimc_remove
  9. vimc_dev_release
  10. vimc_init
  11. vimc_exit

   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/component.h>
   9 #include <linux/init.h>
  10 #include <linux/module.h>
  11 #include <linux/platform_device.h>
  12 #include <media/media-device.h>
  13 #include <media/v4l2-device.h>
  14 
  15 #include "vimc-common.h"
  16 
  17 #define VIMC_MDEV_MODEL_NAME "VIMC MDEV"
  18 
  19 #define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \
  20         .src_ent = src,                                         \
  21         .src_pad = srcpad,                                      \
  22         .sink_ent = sink,                                       \
  23         .sink_pad = sinkpad,                                    \
  24         .flags = link_flags,                                    \
  25 }
  26 
  27 struct vimc_device {
  28         /* The platform device */
  29         struct platform_device pdev;
  30 
  31         /* The pipeline configuration */
  32         const struct vimc_pipeline_config *pipe_cfg;
  33 
  34         /* The Associated media_device parent */
  35         struct media_device mdev;
  36 
  37         /* Internal v4l2 parent device*/
  38         struct v4l2_device v4l2_dev;
  39 
  40         /* Subdevices */
  41         struct platform_device **subdevs;
  42 };
  43 
  44 /* Structure which describes individual configuration for each entity */
  45 struct vimc_ent_config {
  46         const char *name;
  47         const char *drv;
  48 };
  49 
  50 /* Structure which describes links between entities */
  51 struct vimc_ent_link {
  52         unsigned int src_ent;
  53         u16 src_pad;
  54         unsigned int sink_ent;
  55         u16 sink_pad;
  56         u32 flags;
  57 };
  58 
  59 /* Structure which describes the whole topology */
  60 struct vimc_pipeline_config {
  61         const struct vimc_ent_config *ents;
  62         size_t num_ents;
  63         const struct vimc_ent_link *links;
  64         size_t num_links;
  65 };
  66 
  67 /* --------------------------------------------------------------------------
  68  * Topology Configuration
  69  */
  70 
  71 static const struct vimc_ent_config ent_config[] = {
  72         {
  73                 .name = "Sensor A",
  74                 .drv = "vimc-sensor",
  75         },
  76         {
  77                 .name = "Sensor B",
  78                 .drv = "vimc-sensor",
  79         },
  80         {
  81                 .name = "Debayer A",
  82                 .drv = "vimc-debayer",
  83         },
  84         {
  85                 .name = "Debayer B",
  86                 .drv = "vimc-debayer",
  87         },
  88         {
  89                 .name = "Raw Capture 0",
  90                 .drv = "vimc-capture",
  91         },
  92         {
  93                 .name = "Raw Capture 1",
  94                 .drv = "vimc-capture",
  95         },
  96         {
  97                 .name = "RGB/YUV Input",
  98                 /* TODO: change this to vimc-input when it is implemented */
  99                 .drv = "vimc-sensor",
 100         },
 101         {
 102                 .name = "Scaler",
 103                 .drv = "vimc-scaler",
 104         },
 105         {
 106                 .name = "RGB/YUV Capture",
 107                 .drv = "vimc-capture",
 108         },
 109 };
 110 
 111 static const struct vimc_ent_link ent_links[] = {
 112         /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */
 113         VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
 114         /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */
 115         VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
 116         /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */
 117         VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
 118         /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */
 119         VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
 120         /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */
 121         VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED),
 122         /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */
 123         VIMC_ENT_LINK(3, 1, 7, 0, 0),
 124         /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */
 125         VIMC_ENT_LINK(6, 0, 7, 0, 0),
 126         /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */
 127         VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
 128 };
 129 
 130 static const struct vimc_pipeline_config pipe_cfg = {
 131         .ents           = ent_config,
 132         .num_ents       = ARRAY_SIZE(ent_config),
 133         .links          = ent_links,
 134         .num_links      = ARRAY_SIZE(ent_links)
 135 };
 136 
 137 /* -------------------------------------------------------------------------- */
 138 
 139 static int vimc_create_links(struct vimc_device *vimc)
 140 {
 141         unsigned int i;
 142         int ret;
 143 
 144         /* Initialize the links between entities */
 145         for (i = 0; i < vimc->pipe_cfg->num_links; i++) {
 146                 const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i];
 147                 /*
 148                  * TODO: Check another way of retrieving ved struct without
 149                  * relying on platform_get_drvdata
 150                  */
 151                 struct vimc_ent_device *ved_src =
 152                         platform_get_drvdata(vimc->subdevs[link->src_ent]);
 153                 struct vimc_ent_device *ved_sink =
 154                         platform_get_drvdata(vimc->subdevs[link->sink_ent]);
 155 
 156                 ret = media_create_pad_link(ved_src->ent, link->src_pad,
 157                                             ved_sink->ent, link->sink_pad,
 158                                             link->flags);
 159                 if (ret)
 160                         return ret;
 161         }
 162 
 163         return 0;
 164 }
 165 
 166 static int vimc_comp_bind(struct device *master)
 167 {
 168         struct vimc_device *vimc = container_of(to_platform_device(master),
 169                                                 struct vimc_device, pdev);
 170         int ret;
 171 
 172         dev_dbg(master, "bind");
 173 
 174         /* Register the v4l2 struct */
 175         ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev);
 176         if (ret) {
 177                 dev_err(vimc->mdev.dev,
 178                         "v4l2 device register failed (err=%d)\n", ret);
 179                 return ret;
 180         }
 181 
 182         /* Bind subdevices */
 183         ret = component_bind_all(master, &vimc->v4l2_dev);
 184         if (ret)
 185                 goto err_v4l2_unregister;
 186 
 187         /* Initialize links */
 188         ret = vimc_create_links(vimc);
 189         if (ret)
 190                 goto err_comp_unbind_all;
 191 
 192         /* Register the media device */
 193         ret = media_device_register(&vimc->mdev);
 194         if (ret) {
 195                 dev_err(vimc->mdev.dev,
 196                         "media device register failed (err=%d)\n", ret);
 197                 goto err_comp_unbind_all;
 198         }
 199 
 200         /* Expose all subdev's nodes*/
 201         ret = v4l2_device_register_subdev_nodes(&vimc->v4l2_dev);
 202         if (ret) {
 203                 dev_err(vimc->mdev.dev,
 204                         "vimc subdev nodes registration failed (err=%d)\n",
 205                         ret);
 206                 goto err_mdev_unregister;
 207         }
 208 
 209         return 0;
 210 
 211 err_mdev_unregister:
 212         media_device_unregister(&vimc->mdev);
 213         media_device_cleanup(&vimc->mdev);
 214 err_comp_unbind_all:
 215         component_unbind_all(master, NULL);
 216 err_v4l2_unregister:
 217         v4l2_device_unregister(&vimc->v4l2_dev);
 218 
 219         return ret;
 220 }
 221 
 222 static void vimc_comp_unbind(struct device *master)
 223 {
 224         struct vimc_device *vimc = container_of(to_platform_device(master),
 225                                                 struct vimc_device, pdev);
 226 
 227         dev_dbg(master, "unbind");
 228 
 229         media_device_unregister(&vimc->mdev);
 230         media_device_cleanup(&vimc->mdev);
 231         component_unbind_all(master, NULL);
 232         v4l2_device_unregister(&vimc->v4l2_dev);
 233 }
 234 
 235 static int vimc_comp_compare(struct device *comp, void *data)
 236 {
 237         return comp == data;
 238 }
 239 
 240 static struct component_match *vimc_add_subdevs(struct vimc_device *vimc)
 241 {
 242         struct component_match *match = NULL;
 243         struct vimc_platform_data pdata;
 244         int i;
 245 
 246         for (i = 0; i < vimc->pipe_cfg->num_ents; i++) {
 247                 dev_dbg(&vimc->pdev.dev, "new pdev for %s\n",
 248                         vimc->pipe_cfg->ents[i].drv);
 249 
 250                 strscpy(pdata.entity_name, vimc->pipe_cfg->ents[i].name,
 251                         sizeof(pdata.entity_name));
 252 
 253                 vimc->subdevs[i] = platform_device_register_data(&vimc->pdev.dev,
 254                                                 vimc->pipe_cfg->ents[i].drv,
 255                                                 PLATFORM_DEVID_AUTO,
 256                                                 &pdata,
 257                                                 sizeof(pdata));
 258                 if (IS_ERR(vimc->subdevs[i])) {
 259                         match = ERR_CAST(vimc->subdevs[i]);
 260                         while (--i >= 0)
 261                                 platform_device_unregister(vimc->subdevs[i]);
 262 
 263                         return match;
 264                 }
 265 
 266                 component_match_add(&vimc->pdev.dev, &match, vimc_comp_compare,
 267                                     &vimc->subdevs[i]->dev);
 268         }
 269 
 270         return match;
 271 }
 272 
 273 static void vimc_rm_subdevs(struct vimc_device *vimc)
 274 {
 275         unsigned int i;
 276 
 277         for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
 278                 platform_device_unregister(vimc->subdevs[i]);
 279 }
 280 
 281 static const struct component_master_ops vimc_comp_ops = {
 282         .bind = vimc_comp_bind,
 283         .unbind = vimc_comp_unbind,
 284 };
 285 
 286 static int vimc_probe(struct platform_device *pdev)
 287 {
 288         struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev);
 289         struct component_match *match = NULL;
 290         int ret;
 291 
 292         dev_dbg(&pdev->dev, "probe");
 293 
 294         memset(&vimc->mdev, 0, sizeof(vimc->mdev));
 295 
 296         /* Create platform_device for each entity in the topology*/
 297         vimc->subdevs = devm_kcalloc(&vimc->pdev.dev, vimc->pipe_cfg->num_ents,
 298                                      sizeof(*vimc->subdevs), GFP_KERNEL);
 299         if (!vimc->subdevs)
 300                 return -ENOMEM;
 301 
 302         match = vimc_add_subdevs(vimc);
 303         if (IS_ERR(match))
 304                 return PTR_ERR(match);
 305 
 306         /* Link the media device within the v4l2_device */
 307         vimc->v4l2_dev.mdev = &vimc->mdev;
 308 
 309         /* Initialize media device */
 310         strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME,
 311                 sizeof(vimc->mdev.model));
 312         snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info),
 313                  "platform:%s", VIMC_PDEV_NAME);
 314         vimc->mdev.dev = &pdev->dev;
 315         media_device_init(&vimc->mdev);
 316 
 317         /* Add self to the component system */
 318         ret = component_master_add_with_match(&pdev->dev, &vimc_comp_ops,
 319                                               match);
 320         if (ret) {
 321                 media_device_cleanup(&vimc->mdev);
 322                 vimc_rm_subdevs(vimc);
 323                 return ret;
 324         }
 325 
 326         return 0;
 327 }
 328 
 329 static int vimc_remove(struct platform_device *pdev)
 330 {
 331         struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev);
 332 
 333         dev_dbg(&pdev->dev, "remove");
 334 
 335         component_master_del(&pdev->dev, &vimc_comp_ops);
 336         vimc_rm_subdevs(vimc);
 337 
 338         return 0;
 339 }
 340 
 341 static void vimc_dev_release(struct device *dev)
 342 {
 343 }
 344 
 345 static struct vimc_device vimc_dev = {
 346         .pipe_cfg = &pipe_cfg,
 347         .pdev = {
 348                 .name = VIMC_PDEV_NAME,
 349                 .dev.release = vimc_dev_release,
 350         }
 351 };
 352 
 353 static struct platform_driver vimc_pdrv = {
 354         .probe          = vimc_probe,
 355         .remove         = vimc_remove,
 356         .driver         = {
 357                 .name   = VIMC_PDEV_NAME,
 358         },
 359 };
 360 
 361 static int __init vimc_init(void)
 362 {
 363         int ret;
 364 
 365         ret = platform_device_register(&vimc_dev.pdev);
 366         if (ret) {
 367                 dev_err(&vimc_dev.pdev.dev,
 368                         "platform device registration failed (err=%d)\n", ret);
 369                 return ret;
 370         }
 371 
 372         ret = platform_driver_register(&vimc_pdrv);
 373         if (ret) {
 374                 dev_err(&vimc_dev.pdev.dev,
 375                         "platform driver registration failed (err=%d)\n", ret);
 376                 platform_driver_unregister(&vimc_pdrv);
 377                 return ret;
 378         }
 379 
 380         return 0;
 381 }
 382 
 383 static void __exit vimc_exit(void)
 384 {
 385         platform_driver_unregister(&vimc_pdrv);
 386 
 387         platform_device_unregister(&vimc_dev.pdev);
 388 }
 389 
 390 module_init(vimc_init);
 391 module_exit(vimc_exit);
 392 
 393 MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)");
 394 MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>");
 395 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */