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