1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * vimc-core.c Virtual Media Controller Driver
5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
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>
14 #include "vimc-common.h"
16 #define VIMC_MDEV_MODEL_NAME "VIMC MDEV"
18 #define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \
22 .sink_pad = sinkpad, \
23 .flags = link_flags, \
26 /* Structure which describes links between entities */
27 struct vimc_ent_link
{
30 unsigned int sink_ent
;
35 /* Structure which describes the whole topology */
36 struct vimc_pipeline_config
{
37 const struct vimc_ent_config
*ents
;
39 const struct vimc_ent_link
*links
;
43 /* --------------------------------------------------------------------------
44 * Topology Configuration
47 static struct vimc_ent_config ent_config
[] = {
51 .release
= vimc_sen_release
,
56 .release
= vimc_sen_release
,
61 .release
= vimc_deb_release
,
66 .release
= vimc_deb_release
,
69 .name
= "Raw Capture 0",
71 .unregister
= vimc_cap_unregister
,
72 .release
= vimc_cap_release
,
75 .name
= "Raw Capture 1",
77 .unregister
= vimc_cap_unregister
,
78 .release
= vimc_cap_release
,
81 /* TODO: change this to vimc-input when it is implemented */
82 .name
= "RGB/YUV Input",
84 .release
= vimc_sen_release
,
89 .release
= vimc_sca_release
,
92 .name
= "RGB/YUV Capture",
94 .unregister
= vimc_cap_unregister
,
95 .release
= vimc_cap_release
,
99 static 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
),
118 static struct vimc_pipeline_config pipe_cfg
= {
120 .num_ents
= ARRAY_SIZE(ent_config
),
122 .num_links
= ARRAY_SIZE(ent_links
)
125 /* -------------------------------------------------------------------------- */
127 static void vimc_rm_links(struct vimc_device
*vimc
)
131 for (i
= 0; i
< vimc
->pipe_cfg
->num_ents
; i
++)
132 media_entity_remove_links(vimc
->ent_devs
[i
]->ent
);
135 static int vimc_create_links(struct vimc_device
*vimc
)
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
];
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
];
149 ret
= media_create_pad_link(ved_src
->ent
, link
->src_pad
,
150 ved_sink
->ent
, link
->sink_pad
,
163 static int vimc_add_subdevs(struct vimc_device
*vimc
)
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
);
181 static void vimc_release_subdevs(struct vimc_device
*vimc
)
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
]);
190 static void vimc_unregister_subdevs(struct vimc_device
*vimc
)
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
]);
199 static void vimc_v4l2_dev_release(struct v4l2_device
*v4l2_dev
)
201 struct vimc_device
*vimc
=
202 container_of(v4l2_dev
, struct vimc_device
, v4l2_dev
);
204 vimc_release_subdevs(vimc
);
205 media_device_cleanup(&vimc
->mdev
);
206 kfree(vimc
->ent_devs
);
210 static int vimc_register_devices(struct vimc_device
*vimc
)
214 /* Register the v4l2 struct */
215 ret
= v4l2_device_register(vimc
->mdev
.dev
, &vimc
->v4l2_dev
);
217 dev_err(vimc
->mdev
.dev
,
218 "v4l2 device register failed (err=%d)\n", ret
);
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
) {
226 goto err_v4l2_unregister
;
229 /* Invoke entity config hooks to initialize and register subdevs */
230 ret
= vimc_add_subdevs(vimc
);
232 /* remove sundevs that got added */
235 /* Initialize links */
236 ret
= vimc_create_links(vimc
);
240 /* Register the media device */
241 ret
= media_device_register(&vimc
->mdev
);
243 dev_err(vimc
->mdev
.dev
,
244 "media device register failed (err=%d)\n", ret
);
248 /* Expose all subdev's nodes*/
249 ret
= v4l2_device_register_subdev_nodes(&vimc
->v4l2_dev
);
251 dev_err(vimc
->mdev
.dev
,
252 "vimc subdev nodes registration failed (err=%d)\n",
254 goto err_mdev_unregister
;
260 media_device_unregister(&vimc
->mdev
);
262 vimc_unregister_subdevs(vimc
);
263 vimc_release_subdevs(vimc
);
264 kfree(vimc
->ent_devs
);
266 v4l2_device_unregister(&vimc
->v4l2_dev
);
271 static void vimc_unregister(struct vimc_device
*vimc
)
273 vimc_unregister_subdevs(vimc
);
274 media_device_unregister(&vimc
->mdev
);
275 v4l2_device_unregister(&vimc
->v4l2_dev
);
278 static int vimc_probe(struct platform_device
*pdev
)
280 struct vimc_device
*vimc
;
283 dev_dbg(&pdev
->dev
, "probe");
285 vimc
= kzalloc(sizeof(*vimc
), GFP_KERNEL
);
289 vimc
->pipe_cfg
= &pipe_cfg
;
291 /* Link the media device within the v4l2_device */
292 vimc
->v4l2_dev
.mdev
= &vimc
->mdev
;
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
);
302 ret
= vimc_register_devices(vimc
);
304 media_device_cleanup(&vimc
->mdev
);
309 * the release cb is set only after successful registration.
310 * if the registration fails, we release directly from probe
313 vimc
->v4l2_dev
.release
= vimc_v4l2_dev_release
;
314 platform_set_drvdata(pdev
, vimc
);
318 static int vimc_remove(struct platform_device
*pdev
)
320 struct vimc_device
*vimc
= platform_get_drvdata(pdev
);
322 dev_dbg(&pdev
->dev
, "remove");
324 vimc_unregister(vimc
);
325 v4l2_device_put(&vimc
->v4l2_dev
);
330 static void vimc_dev_release(struct device
*dev
)
334 static struct platform_device vimc_pdev
= {
335 .name
= VIMC_PDEV_NAME
,
336 .dev
.release
= vimc_dev_release
,
339 static struct platform_driver vimc_pdrv
= {
341 .remove
= vimc_remove
,
343 .name
= VIMC_PDEV_NAME
,
347 static int __init
vimc_init(void)
351 ret
= platform_device_register(&vimc_pdev
);
353 dev_err(&vimc_pdev
.dev
,
354 "platform device registration failed (err=%d)\n", ret
);
358 ret
= platform_driver_register(&vimc_pdrv
);
360 dev_err(&vimc_pdev
.dev
,
361 "platform driver registration failed (err=%d)\n", ret
);
362 platform_driver_unregister(&vimc_pdrv
);
369 static void __exit
vimc_exit(void)
371 platform_driver_unregister(&vimc_pdrv
);
373 platform_device_unregister(&vimc_pdev
);
376 module_init(vimc_init
);
377 module_exit(vimc_exit
);
379 MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)");
380 MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>");
381 MODULE_LICENSE("GPL");