Hi Sakari, Thank you for the patch. On Monday 16 March 2015 02:26:09 Sakari Ailus wrote: > Add the ISP device to omap3 DT include file and add support to the driver to > use it. > > Also obtain information on the external entities and the ISP configuration > related to them through the Device Tree in addition to the platform data. > > Signed-off-by: Sakari Ailus <sakari.ailus@xxxxxx> > --- > drivers/media/platform/omap3isp/isp.c | 209 ++++++++++++++++++++++-- > drivers/media/platform/omap3isp/isp.h | 11 ++ > drivers/media/platform/omap3isp/ispcsiphy.c | 7 + > 3 files changed, 215 insertions(+), 12 deletions(-) > > diff --git a/drivers/media/platform/omap3isp/isp.c > b/drivers/media/platform/omap3isp/isp.c index 992e74c..0d6012a 100644 > --- a/drivers/media/platform/omap3isp/isp.c > +++ b/drivers/media/platform/omap3isp/isp.c > @@ -64,6 +64,7 @@ > > #include <media/v4l2-common.h> > #include <media/v4l2-device.h> > +#include <media/v4l2-of.h> > > #include "isp.h" > #include "ispreg.h" > @@ -1991,6 +1992,14 @@ static int isp_register_entities(struct isp_device > *isp) if (ret < 0) > goto done; > > + /* > + * Device Tree --- the external of the sub-devices will be What do you mean by "the external of the sub-devices" ? > + * registered later. Same goes for the sub-device node > + * registration. > + */ > + if (isp->dev->of_node) > + return 0; > + > /* Register external entities */ > for (isp_subdev = pdata ? pdata->subdevs : NULL; > isp_subdev && isp_subdev->board_info; isp_subdev++) { > @@ -2016,8 +2025,10 @@ static int isp_register_entities(struct isp_device > *isp) ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); > > done: > - if (ret < 0) > + if (ret < 0) { > isp_unregister_entities(isp); > + v4l2_async_notifier_unregister(&isp->notifier); > + } > > return ret; > } > @@ -2232,6 +2243,7 @@ static int isp_remove(struct platform_device *pdev) > { > struct isp_device *isp = platform_get_drvdata(pdev); > > + v4l2_async_notifier_unregister(&isp->notifier); > isp_unregister_entities(isp); > isp_cleanup_modules(isp); > isp_xclk_cleanup(isp); > @@ -2243,6 +2255,151 @@ static int isp_remove(struct platform_device *pdev) > return 0; > } > > +enum isp_of_phy { > + ISP_OF_PHY_PARALLEL = 0, > + ISP_OF_PHY_CSIPHY1, > + ISP_OF_PHY_CSIPHY2, > +}; > + > +static int isp_of_parse_node(struct device *dev, struct device_node *node, > + struct isp_async_subdev *isd) > +{ > + struct isp_bus_cfg *buscfg = &isd->bus; > + struct v4l2_of_endpoint vep; > + unsigned int i; > + > + v4l2_of_parse_endpoint(node, &vep); > + > + dev_dbg(dev, "interface %u\n", vep.base.port); The message seems a bit terse to me, I would also print the endpoint node name to give a bit of context. dev_dbg(dev, "parsing endpoint %s, interface %u\n", node->full_name, vep.base.port); > + > + switch (vep.base.port) { > + case ISP_OF_PHY_PARALLEL: > + buscfg->interface = ISP_INTERFACE_PARALLEL; > + buscfg->bus.parallel.data_lane_shift = > + vep.bus.parallel.data_shift; > + buscfg->bus.parallel.clk_pol = > + !!(vep.bus.parallel.flags > + & V4L2_MBUS_PCLK_SAMPLE_FALLING); > + buscfg->bus.parallel.hs_pol = > + !!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW); > + buscfg->bus.parallel.vs_pol = > + !!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW); > + buscfg->bus.parallel.fld_pol = > + !!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); > + buscfg->bus.parallel.data_pol = > + !!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); > + break; > + > + case ISP_OF_PHY_CSIPHY1: > + case ISP_OF_PHY_CSIPHY2: > + /* FIXME: always assume CSI-2 for now. */ > + switch (vep.base.port) { > + case ISP_OF_PHY_CSIPHY1: I'd use an if - else here, but that's up to you. > + buscfg->interface = ISP_INTERFACE_CSI2C_PHY1; > + break; > + case ISP_OF_PHY_CSIPHY2: > + buscfg->interface = ISP_INTERFACE_CSI2A_PHY2; > + break; > + } > + buscfg->bus.csi2.lanecfg.clk.pos = vep.bus.mipi_csi2.clock_lane; > + buscfg->bus.csi2.lanecfg.clk.pol = > + vep.bus.mipi_csi2.lane_polarity[0]; > + dev_dbg(dev, "clock lane polarity %u, pos %u\n", > + buscfg->bus.csi2.lanecfg.clk.pol, > + buscfg->bus.csi2.lanecfg.clk.pos); > + > + for (i = 0; i < ISP_CSIPHY2_NUM_DATA_LANES; i++) { > + buscfg->bus.csi2.lanecfg.data[i].pos = > + vep.bus.mipi_csi2.data_lanes[i]; > + buscfg->bus.csi2.lanecfg.data[i].pol = > + vep.bus.mipi_csi2.lane_polarity[i + 1]; > + dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i, > + buscfg->bus.csi2.lanecfg.data[i].pol, > + buscfg->bus.csi2.lanecfg.data[i].pos); > + } > + > + /* > + * FIXME: now we assume the CRC is always there. > + * Implement a way to obtain this information from the > + * sensor. Frame descriptors, perhaps? > + */ > + buscfg->bus.csi2.crc = 1; > + break; > + > + default: > + dev_warn(dev, "invalid interface %d\n\n", vep.base.port); Double \n ? I would also print the node name to add a bit of context. > + break; > + } > + > + return 0; > +} > + > +static int isp_of_parse_nodes(struct device *dev, > + struct v4l2_async_notifier *notifier) > +{ > + struct device_node *node = NULL; No need to initialize node to NULL. > + struct v4l2_async_subdev **asds; > + > + asds = notifier->subdevs = Could you use a single assignment per line, please ? > + devm_kcalloc(dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), > + GFP_KERNEL); > + if (!asds) > + return -ENOMEM; > + > + while ((node = of_graph_get_next_endpoint(dev->of_node, node)) && > + notifier->num_subdevs < ISP_MAX_SUBDEVS) { > + struct isp_async_subdev *isd; > + > + isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL); > + if (!isd) > + return -ENOMEM; > + > + *asds = &isd->asd; > + > + if (isp_of_parse_node(dev, node, isd)) > + return -EINVAL; > + > + isd->asd.match.of.node = of_graph_get_remote_port_parent(node); An of_node_put() is needed somewhere in the exit/cleanup paths. > + > + if (!isd->asd.match.of.node) { > + dev_warn(dev, "bad remote port parent\n"); > + return -EINVAL; > + } > + isd->asd.match_type = V4L2_ASYNC_MATCH_OF; > + notifier->num_subdevs++; > + } > + > + return notifier->num_subdevs; > +} > + > +static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async, > + struct v4l2_subdev *subdev, > + struct v4l2_async_subdev *asd) > +{ > + struct isp_device *isp = container_of(async, struct isp_device, > + notifier); > + struct isp_async_subdev *isd = > + container_of(asd, struct isp_async_subdev, asd); > + int rval; The coding style in the omap3isp driver mostly uses ret, sorry :-) > + > + rval = isp_link_entity(isp, &subdev->entity, isd->bus.interface); > + if (rval < 0) > + return rval; > + > + isd->sd = subdev; > + isd->sd->host_priv = &isd->bus; > + > + return rval; > +} > + > +static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) > +{ > + struct isp_device *isp = container_of(async, struct isp_device, > + notifier); > + > + return v4l2_device_register_subdev_nodes(&isp->v4l2_dev); > +} > + > /* > * isp_probe - Probe ISP platform device > * @pdev: Pointer to ISP platform device > @@ -2256,7 +2413,6 @@ static int isp_remove(struct platform_device *pdev) > */ > static int isp_probe(struct platform_device *pdev) > { > - struct isp_platform_data *pdata = pdev->dev.platform_data; > struct isp_device *isp; > struct resource *mem; > int ret; > @@ -2268,13 +2424,37 @@ static int isp_probe(struct platform_device *pdev) > return -ENOMEM; > } > > + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { > + ret = of_property_read_u32(pdev->dev.of_node, "ti,phy-type", > + &isp->phy_type); > + if (ret) > + return ret; > + > + isp->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, > + "syscon"); > + if (IS_ERR(isp->syscon)) > + return PTR_ERR(isp->syscon); isp->syscon_offset isn't set anywhere in the DT case, am I missing something ? > + > + ret = isp_of_parse_nodes(&pdev->dev, &isp->notifier); > + if (ret < 0) > + return ret; > + ret = v4l2_async_notifier_register(&isp->v4l2_dev, > + &isp->notifier); > + if (ret) > + return ret; > + } else { > + isp->pdata = pdev->dev.platform_data; > + isp->syscon = syscon_regmap_lookup_by_pdevname("syscon.0"); > + if (IS_ERR(isp->syscon)) > + return PTR_ERR(isp->syscon); > + } > + > isp->autoidle = autoidle; > > mutex_init(&isp->isp_mutex); > spin_lock_init(&isp->stat_lock); > > isp->dev = &pdev->dev; > - isp->pdata = pdata; > isp->ref_count = 0; > > ret = dma_coerce_mask_and_coherent(isp->dev, DMA_BIT_MASK(32)); > @@ -2346,6 +2526,11 @@ static int isp_probe(struct platform_device *pdev) > goto error_isp; > } > > + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) { > + isp->syscon_offset = isp_res_maps[m].syscon_offset; > + isp->phy_type = isp_res_maps[m].phy_type; > + } > + > for (i = 1; i < OMAP3_ISP_IOMEM_CSI2A_REGS1; i++) > isp->mmio_base[i] = > isp->mmio_base[0] + isp_res_maps[m].offset[i]; > @@ -2358,15 +2543,6 @@ static int isp_probe(struct platform_device *pdev) > isp->mmio_hist_base_phys = > mem->start + isp_res_maps[m].offset[OMAP3_ISP_IOMEM_HIST]; > > - isp->syscon = syscon_regmap_lookup_by_pdevname("syscon.0"); > - if (IS_ERR(isp->syscon)) { > - ret = PTR_ERR(isp->syscon); > - goto error_isp; > - } > - > - isp->syscon_offset = isp_res_maps[m].syscon_offset; > - isp->phy_type = isp_res_maps[m].phy_type; > - > /* IOMMU */ > ret = isp_attach_iommu(isp); > if (ret < 0) { > @@ -2394,6 +2570,9 @@ static int isp_probe(struct platform_device *pdev) > if (ret < 0) > goto error_iommu; > > + isp->notifier.bound = isp_subdev_notifier_bound; > + isp->notifier.complete = isp_subdev_notifier_complete; > + > ret = isp_register_entities(isp); > if (ret < 0) > goto error_modules; > @@ -2429,6 +2608,11 @@ static struct platform_device_id omap3isp_id_table[] > = { }; > MODULE_DEVICE_TABLE(platform, omap3isp_id_table); > > +static const struct of_device_id omap3isp_of_table[] = { > + { .compatible = "ti,omap3-isp" }, > + { }, > +}; > + > static struct platform_driver omap3isp_driver = { > .probe = isp_probe, > .remove = isp_remove, > @@ -2436,6 +2620,7 @@ static struct platform_driver omap3isp_driver = { > .driver = { > .name = "omap3isp", > .pm = &omap3isp_pm_ops, > + .of_match_table = omap3isp_of_table, > }, > }; > > diff --git a/drivers/media/platform/omap3isp/isp.h > b/drivers/media/platform/omap3isp/isp.h index dcb7d20..431224e 100644 > --- a/drivers/media/platform/omap3isp/isp.h > +++ b/drivers/media/platform/omap3isp/isp.h > @@ -18,6 +18,7 @@ > #define OMAP3_ISP_CORE_H > > #include <media/omap3isp.h> > +#include <media/v4l2-async.h> > #include <media/v4l2-device.h> > #include <linux/clk-provider.h> > #include <linux/device.h> > @@ -178,6 +179,7 @@ struct isp_xclk { > */ > struct isp_device { > struct v4l2_device v4l2_dev; > + struct v4l2_async_notifier notifier; > struct media_device media_dev; > struct device *dev; > u32 revision; > @@ -224,6 +226,15 @@ struct isp_device { > > unsigned int sbl_resources; > unsigned int subclk_resources; > + > +#define ISP_MAX_SUBDEVS 8 > + struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS]; > +}; > + > +struct isp_async_subdev { > + struct v4l2_subdev *sd; > + struct isp_bus_cfg bus; > + struct v4l2_async_subdev asd; > }; > > #define v4l2_dev_to_isp_device(dev) \ > diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c > b/drivers/media/platform/omap3isp/ispcsiphy.c index d91dde1..495447d 100644 > --- a/drivers/media/platform/omap3isp/ispcsiphy.c > +++ b/drivers/media/platform/omap3isp/ispcsiphy.c > @@ -173,6 +173,13 @@ static int omap3isp_csiphy_config(struct isp_csiphy > *phy) unsigned int i; > u32 reg; > > + if (!buscfg) { > + struct isp_async_subdev *isd = > + container_of(pipe->external->asd, > + struct isp_async_subdev, asd); > + buscfg = &isd->bus; > + } > + > if (buscfg->interface == ISP_INTERFACE_CCP2B_PHY1 > > || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2) > > lanes = &buscfg->bus.ccp2.lanecfg; -- Regards, Laurent Pinchart -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html