|
@@ -33,43 +33,10 @@ static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Find an asd by fwnode or device name. This is called during
|
|
|
- * driver load to form the async subdev list and bind them.
|
|
|
- */
|
|
|
-static struct v4l2_async_subdev *
|
|
|
-find_async_subdev(struct imx_media_dev *imxmd,
|
|
|
- struct fwnode_handle *fwnode,
|
|
|
- const char *devname)
|
|
|
-{
|
|
|
- struct imx_media_async_subdev *imxasd;
|
|
|
- struct v4l2_async_subdev *asd;
|
|
|
-
|
|
|
- list_for_each_entry(imxasd, &imxmd->asd_list, list) {
|
|
|
- asd = &imxasd->asd;
|
|
|
- switch (asd->match_type) {
|
|
|
- case V4L2_ASYNC_MATCH_FWNODE:
|
|
|
- if (fwnode && asd->match.fwnode == fwnode)
|
|
|
- return asd;
|
|
|
- break;
|
|
|
- case V4L2_ASYNC_MATCH_DEVNAME:
|
|
|
- if (devname && !strcmp(asd->match.device_name,
|
|
|
- devname))
|
|
|
- return asd;
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*
|
|
|
- * Adds a subdev to the async subdev list. If fwnode is non-NULL, adds
|
|
|
- * the async as a V4L2_ASYNC_MATCH_FWNODE match type, otherwise as
|
|
|
- * a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name of the
|
|
|
- * given platform_device. This is called during driver load when
|
|
|
+ * Adds a subdev to the root notifier's async subdev list. If fwnode is
|
|
|
+ * non-NULL, adds the async as a V4L2_ASYNC_MATCH_FWNODE match type,
|
|
|
+ * otherwise as a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name
|
|
|
+ * of the given platform_device. This is called during driver load when
|
|
|
* forming the async subdev list.
|
|
|
*/
|
|
|
int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
|
|
@@ -80,47 +47,34 @@ int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
|
|
|
struct imx_media_async_subdev *imxasd;
|
|
|
struct v4l2_async_subdev *asd;
|
|
|
const char *devname = NULL;
|
|
|
- int ret = 0;
|
|
|
-
|
|
|
- mutex_lock(&imxmd->mutex);
|
|
|
+ int ret;
|
|
|
|
|
|
- if (pdev)
|
|
|
+ if (fwnode) {
|
|
|
+ asd = v4l2_async_notifier_add_fwnode_subdev(
|
|
|
+ &imxmd->notifier, fwnode, sizeof(*imxasd));
|
|
|
+ } else {
|
|
|
devname = dev_name(&pdev->dev);
|
|
|
-
|
|
|
- /* return -EEXIST if this asd already added */
|
|
|
- if (find_async_subdev(imxmd, fwnode, devname)) {
|
|
|
- dev_dbg(imxmd->md.dev, "%s: already added %s\n",
|
|
|
- __func__, np ? np->name : devname);
|
|
|
- ret = -EEXIST;
|
|
|
- goto out;
|
|
|
+ asd = v4l2_async_notifier_add_devname_subdev(
|
|
|
+ &imxmd->notifier, devname, sizeof(*imxasd));
|
|
|
}
|
|
|
|
|
|
- imxasd = devm_kzalloc(imxmd->md.dev, sizeof(*imxasd), GFP_KERNEL);
|
|
|
- if (!imxasd) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto out;
|
|
|
- }
|
|
|
- asd = &imxasd->asd;
|
|
|
-
|
|
|
- if (fwnode) {
|
|
|
- asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
|
|
|
- asd->match.fwnode = fwnode;
|
|
|
- } else {
|
|
|
- asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
|
|
|
- asd->match.device_name = devname;
|
|
|
- imxasd->pdev = pdev;
|
|
|
+ if (IS_ERR(asd)) {
|
|
|
+ ret = PTR_ERR(asd);
|
|
|
+ if (ret == -EEXIST)
|
|
|
+ dev_dbg(imxmd->md.dev, "%s: already added %s\n",
|
|
|
+ __func__, np ? np->name : devname);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
- list_add_tail(&imxasd->list, &imxmd->asd_list);
|
|
|
+ imxasd = to_imx_media_asd(asd);
|
|
|
|
|
|
- imxmd->notifier.num_subdevs++;
|
|
|
+ if (devname)
|
|
|
+ imxasd->pdev = pdev;
|
|
|
|
|
|
dev_dbg(imxmd->md.dev, "%s: added %s, match type %s\n",
|
|
|
__func__, np ? np->name : devname, np ? "FWNODE" : "DEVNAME");
|
|
|
|
|
|
-out:
|
|
|
- mutex_unlock(&imxmd->mutex);
|
|
|
- return ret;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -483,10 +437,8 @@ static int imx_media_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct device *dev = &pdev->dev;
|
|
|
struct device_node *node = dev->of_node;
|
|
|
- struct imx_media_async_subdev *imxasd;
|
|
|
- struct v4l2_async_subdev **subdevs;
|
|
|
struct imx_media_dev *imxmd;
|
|
|
- int num_subdevs, i, ret;
|
|
|
+ int ret;
|
|
|
|
|
|
imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
|
|
|
if (!imxmd)
|
|
@@ -515,44 +467,31 @@ static int imx_media_probe(struct platform_device *pdev)
|
|
|
|
|
|
dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
|
|
|
|
|
|
- INIT_LIST_HEAD(&imxmd->asd_list);
|
|
|
INIT_LIST_HEAD(&imxmd->vdev_list);
|
|
|
|
|
|
+ v4l2_async_notifier_init(&imxmd->notifier);
|
|
|
+
|
|
|
ret = imx_media_add_of_subdevs(imxmd, node);
|
|
|
if (ret) {
|
|
|
v4l2_err(&imxmd->v4l2_dev,
|
|
|
"add_of_subdevs failed with %d\n", ret);
|
|
|
- goto unreg_dev;
|
|
|
+ goto notifier_cleanup;
|
|
|
}
|
|
|
|
|
|
ret = imx_media_add_internal_subdevs(imxmd);
|
|
|
if (ret) {
|
|
|
v4l2_err(&imxmd->v4l2_dev,
|
|
|
"add_internal_subdevs failed with %d\n", ret);
|
|
|
- goto unreg_dev;
|
|
|
+ goto notifier_cleanup;
|
|
|
}
|
|
|
|
|
|
- num_subdevs = imxmd->notifier.num_subdevs;
|
|
|
-
|
|
|
/* no subdevs? just bail */
|
|
|
- if (num_subdevs == 0) {
|
|
|
+ if (list_empty(&imxmd->notifier.asd_list)) {
|
|
|
ret = -ENODEV;
|
|
|
- goto unreg_dev;
|
|
|
+ goto notifier_cleanup;
|
|
|
}
|
|
|
|
|
|
- subdevs = devm_kcalloc(imxmd->md.dev, num_subdevs, sizeof(*subdevs),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!subdevs) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto unreg_dev;
|
|
|
- }
|
|
|
-
|
|
|
- i = 0;
|
|
|
- list_for_each_entry(imxasd, &imxmd->asd_list, list)
|
|
|
- subdevs[i++] = &imxasd->asd;
|
|
|
-
|
|
|
/* prepare the async subdev notifier and register it */
|
|
|
- imxmd->notifier.subdevs = subdevs;
|
|
|
imxmd->notifier.ops = &imx_media_subdev_ops;
|
|
|
ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
|
|
|
&imxmd->notifier);
|
|
@@ -566,7 +505,8 @@ static int imx_media_probe(struct platform_device *pdev)
|
|
|
|
|
|
del_int:
|
|
|
imx_media_remove_internal_subdevs(imxmd);
|
|
|
-unreg_dev:
|
|
|
+notifier_cleanup:
|
|
|
+ v4l2_async_notifier_cleanup(&imxmd->notifier);
|
|
|
v4l2_device_unregister(&imxmd->v4l2_dev);
|
|
|
cleanup:
|
|
|
media_device_cleanup(&imxmd->md);
|
|
@@ -582,6 +522,7 @@ static int imx_media_remove(struct platform_device *pdev)
|
|
|
|
|
|
v4l2_async_notifier_unregister(&imxmd->notifier);
|
|
|
imx_media_remove_internal_subdevs(imxmd);
|
|
|
+ v4l2_async_notifier_cleanup(&imxmd->notifier);
|
|
|
v4l2_device_unregister(&imxmd->v4l2_dev);
|
|
|
media_device_unregister(&imxmd->md);
|
|
|
media_device_cleanup(&imxmd->md);
|