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
[] = {
69 .name
= "Raw Capture 0",
74 .name
= "Raw Capture 1",
79 /* TODO: change this to vimc-input when it is implemented */
80 .name
= "RGB/YUV Input",
90 .name
= "RGB/YUV Capture",
96 static const struct vimc_ent_link ent_links
[] = {
97 /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */
98 VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED
| MEDIA_LNK_FL_IMMUTABLE
),
99 /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */
100 VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED
| MEDIA_LNK_FL_IMMUTABLE
),
101 /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */
102 VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED
| MEDIA_LNK_FL_IMMUTABLE
),
103 /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */
104 VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED
| MEDIA_LNK_FL_IMMUTABLE
),
105 /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */
106 VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED
),
107 /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */
108 VIMC_ENT_LINK(3, 1, 7, 0, 0),
109 /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */
110 VIMC_ENT_LINK(6, 0, 7, 0, 0),
111 /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */
112 VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED
| MEDIA_LNK_FL_IMMUTABLE
),
115 static struct vimc_pipeline_config pipe_cfg
= {
117 .num_ents
= ARRAY_SIZE(ent_config
),
119 .num_links
= ARRAY_SIZE(ent_links
)
122 /* -------------------------------------------------------------------------- */
124 static void vimc_rm_links(struct vimc_device
*vimc
)
128 for (i
= 0; i
< vimc
->pipe_cfg
->num_ents
; i
++)
129 media_entity_remove_links(vimc
->ent_devs
[i
]->ent
);
132 static int vimc_create_links(struct vimc_device
*vimc
)
137 /* Initialize the links between entities */
138 for (i
= 0; i
< vimc
->pipe_cfg
->num_links
; i
++) {
139 const struct vimc_ent_link
*link
= &vimc
->pipe_cfg
->links
[i
];
141 struct vimc_ent_device
*ved_src
=
142 vimc
->ent_devs
[link
->src_ent
];
143 struct vimc_ent_device
*ved_sink
=
144 vimc
->ent_devs
[link
->sink_ent
];
146 ret
= media_create_pad_link(ved_src
->ent
, link
->src_pad
,
147 ved_sink
->ent
, link
->sink_pad
,
160 static int vimc_add_subdevs(struct vimc_device
*vimc
)
164 for (i
= 0; i
< vimc
->pipe_cfg
->num_ents
; i
++) {
165 dev_dbg(&vimc
->pdev
.dev
, "new entity for %s\n",
166 vimc
->pipe_cfg
->ents
[i
].name
);
167 vimc
->ent_devs
[i
] = vimc
->pipe_cfg
->ents
[i
].add(vimc
,
168 vimc
->pipe_cfg
->ents
[i
].name
);
169 if (!vimc
->ent_devs
[i
]) {
170 dev_err(&vimc
->pdev
.dev
, "add new entity for %s\n",
171 vimc
->pipe_cfg
->ents
[i
].name
);
178 static void vimc_rm_subdevs(struct vimc_device
*vimc
)
182 for (i
= 0; i
< vimc
->pipe_cfg
->num_ents
; i
++)
183 if (vimc
->ent_devs
[i
])
184 vimc
->pipe_cfg
->ents
[i
].rm(vimc
, vimc
->ent_devs
[i
]);
187 static int vimc_register_devices(struct vimc_device
*vimc
)
191 /* Register the v4l2 struct */
192 ret
= v4l2_device_register(vimc
->mdev
.dev
, &vimc
->v4l2_dev
);
194 dev_err(vimc
->mdev
.dev
,
195 "v4l2 device register failed (err=%d)\n", ret
);
199 /* allocate ent_devs */
200 vimc
->ent_devs
= kcalloc(vimc
->pipe_cfg
->num_ents
,
201 sizeof(*vimc
->ent_devs
), GFP_KERNEL
);
202 if (!vimc
->ent_devs
) {
204 goto err_v4l2_unregister
;
207 /* Invoke entity config hooks to initialize and register subdevs */
208 ret
= vimc_add_subdevs(vimc
);
210 /* remove sundevs that got added */
213 /* Initialize links */
214 ret
= vimc_create_links(vimc
);
218 /* Register the media device */
219 ret
= media_device_register(&vimc
->mdev
);
221 dev_err(vimc
->mdev
.dev
,
222 "media device register failed (err=%d)\n", ret
);
226 /* Expose all subdev's nodes*/
227 ret
= v4l2_device_register_subdev_nodes(&vimc
->v4l2_dev
);
229 dev_err(vimc
->mdev
.dev
,
230 "vimc subdev nodes registration failed (err=%d)\n",
232 goto err_mdev_unregister
;
238 media_device_unregister(&vimc
->mdev
);
239 media_device_cleanup(&vimc
->mdev
);
241 vimc_rm_subdevs(vimc
);
242 kfree(vimc
->ent_devs
);
244 v4l2_device_unregister(&vimc
->v4l2_dev
);
249 static void vimc_unregister(struct vimc_device
*vimc
)
251 media_device_unregister(&vimc
->mdev
);
252 media_device_cleanup(&vimc
->mdev
);
253 v4l2_device_unregister(&vimc
->v4l2_dev
);
254 kfree(vimc
->ent_devs
);
257 static int vimc_probe(struct platform_device
*pdev
)
259 struct vimc_device
*vimc
= container_of(pdev
, struct vimc_device
, pdev
);
262 dev_dbg(&pdev
->dev
, "probe");
264 memset(&vimc
->mdev
, 0, sizeof(vimc
->mdev
));
266 /* Link the media device within the v4l2_device */
267 vimc
->v4l2_dev
.mdev
= &vimc
->mdev
;
269 /* Initialize media device */
270 strscpy(vimc
->mdev
.model
, VIMC_MDEV_MODEL_NAME
,
271 sizeof(vimc
->mdev
.model
));
272 snprintf(vimc
->mdev
.bus_info
, sizeof(vimc
->mdev
.bus_info
),
273 "platform:%s", VIMC_PDEV_NAME
);
274 vimc
->mdev
.dev
= &pdev
->dev
;
275 media_device_init(&vimc
->mdev
);
277 ret
= vimc_register_devices(vimc
);
279 media_device_cleanup(&vimc
->mdev
);
286 static int vimc_remove(struct platform_device
*pdev
)
288 struct vimc_device
*vimc
= container_of(pdev
, struct vimc_device
, pdev
);
290 dev_dbg(&pdev
->dev
, "remove");
292 vimc_rm_subdevs(vimc
);
293 vimc_unregister(vimc
);
298 static void vimc_dev_release(struct device
*dev
)
302 static struct vimc_device vimc_dev
= {
303 .pipe_cfg
= &pipe_cfg
,
305 .name
= VIMC_PDEV_NAME
,
306 .dev
.release
= vimc_dev_release
,
310 static struct platform_driver vimc_pdrv
= {
312 .remove
= vimc_remove
,
314 .name
= VIMC_PDEV_NAME
,
318 static int __init
vimc_init(void)
322 ret
= platform_device_register(&vimc_dev
.pdev
);
324 dev_err(&vimc_dev
.pdev
.dev
,
325 "platform device registration failed (err=%d)\n", ret
);
329 ret
= platform_driver_register(&vimc_pdrv
);
331 dev_err(&vimc_dev
.pdev
.dev
,
332 "platform driver registration failed (err=%d)\n", ret
);
333 platform_driver_unregister(&vimc_pdrv
);
340 static void __exit
vimc_exit(void)
342 platform_driver_unregister(&vimc_pdrv
);
344 platform_device_unregister(&vimc_dev
.pdev
);
347 module_init(vimc_init
);
348 module_exit(vimc_exit
);
350 MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)");
351 MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>");
352 MODULE_LICENSE("GPL");