aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/media/imx/imx-media-dev-common.c
blob: 6cd93419b81dd2cbba1eb20507b6910ed13a3a8b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// SPDX-License-Identifier: GPL-2.0
/*
 * V4L2 Media Controller Driver for Freescale common i.MX5/6/7 SOC
 *
 * Copyright (c) 2019 Linaro Ltd
 * Copyright (c) 2016 Mentor Graphics Inc.
 */

#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include "imx-media.h"

static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
	.bound = imx_media_subdev_bound,
	.complete = imx_media_probe_complete,
};

static const struct media_device_ops imx_media_md_ops = {
	.link_notify = imx_media_link_notify,
};

struct imx_media_dev *imx_media_dev_init(struct device *dev)
{
	struct imx_media_dev *imxmd;
	int ret;

	imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
	if (!imxmd)
		return ERR_PTR(-ENOMEM);

	dev_set_drvdata(dev, imxmd);

	strscpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
	imxmd->md.ops = &imx_media_md_ops;
	imxmd->md.dev = dev;

	mutex_init(&imxmd->mutex);

	imxmd->v4l2_dev.mdev = &imxmd->md;
	imxmd->v4l2_dev.notify = imx_media_notify;
	strscpy(imxmd->v4l2_dev.name, "imx-media",
		sizeof(imxmd->v4l2_dev.name));

	media_device_init(&imxmd->md);

	ret = v4l2_device_register(dev, &imxmd->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&imxmd->v4l2_dev,
			 "Failed to register v4l2_device: %d\n", ret);
		goto cleanup;
	}

	dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);

	INIT_LIST_HEAD(&imxmd->vdev_list);

	v4l2_async_notifier_init(&imxmd->notifier);

	return imxmd;

cleanup:
	media_device_cleanup(&imxmd->md);

	return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(imx_media_dev_init);

int imx_media_dev_notifier_register(struct imx_media_dev *imxmd)
{
	int ret;

	/* no subdevs? just bail */
	if (list_empty(&imxmd->notifier.asd_list)) {
		v4l2_err(&imxmd->v4l2_dev, "no subdevs\n");
		return -ENODEV;
	}

	/* prepare the async subdev notifier and register it */
	imxmd->notifier.ops = &imx_media_subdev_ops;
	ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
					   &imxmd->notifier);
	if (ret) {
		v4l2_err(&imxmd->v4l2_dev,
			 "v4l2_async_notifier_register failed with %d\n", ret);
		return ret;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(imx_media_dev_notifier_register);