// 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 #include #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); strlcpy(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; strlcpy(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);