1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Media driver for Freescale i.MX5/6 SOC 4 * 5 * Open Firmware parsing. 6 * 7 * Copyright (c) 2016 Mentor Graphics Inc. 8 */ 9 #include <linux/of_platform.h> 10 #include <media/v4l2-ctrls.h> 11 #include <media/v4l2-device.h> 12 #include <media/v4l2-fwnode.h> 13 #include <media/v4l2-subdev.h> 14 #include <media/videobuf2-dma-contig.h> 15 #include <linux/of_graph.h> 16 #include <video/imx-ipu-v3.h> 17 #include "imx-media.h" 18 19 static int imx_media_of_add_csi(struct imx_media_dev *imxmd, 20 struct device_node *csi_np) 21 { 22 struct v4l2_async_subdev *asd; 23 int ret = 0; 24 25 if (!of_device_is_available(csi_np)) { 26 dev_dbg(imxmd->md.dev, "%s: %pOFn not enabled\n", __func__, 27 csi_np); 28 return -ENODEV; 29 } 30 31 /* add CSI fwnode to async notifier */ 32 asd = v4l2_async_nf_add_fwnode(&imxmd->notifier, 33 of_fwnode_handle(csi_np), 34 struct v4l2_async_subdev); 35 if (IS_ERR(asd)) { 36 ret = PTR_ERR(asd); 37 if (ret == -EEXIST) 38 dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n", 39 __func__, csi_np); 40 } 41 42 return ret; 43 } 44 45 int imx_media_add_of_subdevs(struct imx_media_dev *imxmd, 46 struct device_node *np) 47 { 48 struct device_node *csi_np; 49 int i, ret; 50 51 for (i = 0; ; i++) { 52 csi_np = of_parse_phandle(np, "ports", i); 53 if (!csi_np) 54 break; 55 56 ret = imx_media_of_add_csi(imxmd, csi_np); 57 if (ret) { 58 /* unavailable or already added is not an error */ 59 if (ret == -ENODEV || ret == -EEXIST) { 60 of_node_put(csi_np); 61 continue; 62 } 63 64 /* other error, can't continue */ 65 goto err_out; 66 } 67 } 68 69 return 0; 70 71 err_out: 72 of_node_put(csi_np); 73 return ret; 74 } 75 EXPORT_SYMBOL_GPL(imx_media_add_of_subdevs); 76