This allows the driver loading via platform data which makes the driver not device tree dependent. Signed-off-by: Luis Oliveira <luis.oliveira@xxxxxxxxxxxx> --- Changelog v3-v4 - not present on v3, allows configuration using pdata MAINTAINERS | 1 + drivers/media/platform/dwc/dw-csi-plat.c | 105 +++++++++++++++++++++---------- include/media/dwc/dw-csi-data.h | 26 ++++++++ 3 files changed, 100 insertions(+), 32 deletions(-) create mode 100644 include/media/dwc/dw-csi-data.h diff --git a/MAINTAINERS b/MAINTAINERS index 6ffe4fd..2df1f7c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15193,6 +15193,7 @@ L: linux-media@xxxxxxxxxxxxxxx T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/platform/dwc +F: include/media/dwc/dw-csi-data.h F: Documentation/devicetree/bindings/media/snps,dw-csi.txt SYNOPSYS DESIGNWARE DMAC DRIVER diff --git a/drivers/media/platform/dwc/dw-csi-plat.c b/drivers/media/platform/dwc/dw-csi-plat.c index 9828d55..c7117c6 100644 --- a/drivers/media/platform/dwc/dw-csi-plat.c +++ b/drivers/media/platform/dwc/dw-csi-plat.c @@ -8,6 +8,7 @@ * Author: Luis Oliveira <luis.oliveira@xxxxxxxxxxxx> */ +#include <media/dwc/dw-csi-data.h> #include <media/dwc/dw-dphy-data.h> #include "dw-csi-plat.h" @@ -312,12 +313,16 @@ static const struct of_device_id dw_mipi_csi_of_match[]; static int dw_csi_probe(struct platform_device *pdev) { const struct of_device_id *of_id = NULL; + struct dw_csih_pdata *pdata; struct device *dev = &pdev->dev; struct resource *res = NULL; struct dw_csi *csi; struct v4l2_subdev *sd; int ret; + if (!IS_ENABLED(CONFIG_OF)) + pdata = pdev->dev.platform_data; + dev_vdbg(dev, "Probing started\n"); /* Resource allocation */ @@ -329,18 +334,29 @@ static int dw_csi_probe(struct platform_device *pdev) spin_lock_init(&csi->slock); csi->dev = dev; - of_id = of_match_node(dw_mipi_csi_of_match, dev->of_node); - if (!of_id) - return -EINVAL; + if (dev->of_node) { + of_id = of_match_node(dw_mipi_csi_of_match, dev->of_node); + if (!of_id) + return -EINVAL; - ret = dw_mipi_csi_parse_dt(pdev, csi); - if (ret < 0) - return ret; + ret = dw_mipi_csi_parse_dt(pdev, csi); + if (ret < 0) + return ret; - csi->phy = devm_of_phy_get(dev, dev->of_node, NULL); - if (IS_ERR(csi->phy)) { - dev_err(dev, "No DPHY available\n"); - return PTR_ERR(csi->phy); + csi->phy = devm_of_phy_get(dev, dev->of_node, NULL); + if (IS_ERR(csi->phy)) { + dev_err(dev, "No DPHY available\n"); + return PTR_ERR(csi->phy); + } + } else { + csi->phy = devm_phy_get(dev, phys[pdata->id].name); + if (IS_ERR(csi->phy)) { + dev_err(dev, "No '%s' DPHY available\n", + phys[pdata->id].name); + return PTR_ERR(csi->phy); + } + dev_vdbg(dev, "got D-PHY %s with id %d\n", phys[pdata->id].name, + csi->phy->id); } /* Registers mapping */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -370,7 +386,10 @@ static int dw_csi_probe(struct platform_device *pdev) dw_mipi_csi_irq1, IRQF_SHARED, dev_name(dev), csi); if (ret) { - dev_err(dev, "irq csi %s failed\n", of_id->name); + if (dev->of_node) + dev_err(dev, "irq csi %s failed\n", of_id->name); + else + dev_err(dev, "irq csi %d failed\n", pdata->id); goto end; } @@ -379,25 +398,44 @@ static int dw_csi_probe(struct platform_device *pdev) v4l2_subdev_init(sd, &dw_mipi_csi_subdev_ops); csi->sd.owner = THIS_MODULE; - snprintf(sd->name, sizeof(sd->name), "%s.%d", - "dw-csi", csi->index); + if (dev->of_node) { + snprintf(sd->name, sizeof(sd->name), "%s.%d", + "dw-csi", csi->index); - csi->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + csi->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + } else { + strlcpy(sd->name, dev_name(dev), sizeof(sd->name)); + strlcpy(csi->v4l2_dev.name, dev_name(dev), + sizeof(csi->v4l2_dev.name)); + } csi->fmt = &dw_mipi_csi_formats[0]; csi->format.code = dw_mipi_csi_formats[0].mbus_code; sd->entity.function = MEDIA_ENT_F_IO_V4L; - csi->pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - csi->pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&csi->sd.entity, - CSI_PADS_NUM, csi->pads); - dev_vdbg(dev, "v4l2.name: %s\n", csi->v4l2_dev.name); + if (dev->of_node) { + csi->pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + csi->pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - if (ret < 0) { - dev_err(dev, "media entity init failed\n"); - goto end; + ret = media_entity_pads_init(&csi->sd.entity, + CSI_PADS_NUM, csi->pads); + if (ret < 0) { + dev_err(dev, "media entity init failed\n"); + goto end; + } + } else { + csi->hw.num_lanes = pdata->lanes; + csi->hw.pclk = pdata->pclk; + csi->hw.fps = pdata->fps; + csi->hw.dphy_freq = pdata->hs_freq; + + ret = v4l2_device_register(NULL, &csi->v4l2_dev); + if (ret) { + dev_err(dev, "failed to register v4l2 device\n"); + goto end; + } } + dev_vdbg(dev, "v4l2.name: %s\n", csi->v4l2_dev.name); v4l2_set_subdevdata(&csi->sd, pdev); platform_set_drvdata(pdev, &csi->sd); @@ -405,6 +443,7 @@ static int dw_csi_probe(struct platform_device *pdev) if (csi->rst) reset_control_deassert(csi->rst); + #if IS_ENABLED(CONFIG_DWC_MIPI_TC_DPHY_GEN3) dw_csi_create_capabilities_sysfs(pdev); #endif @@ -418,11 +457,12 @@ static int dw_csi_probe(struct platform_device *pdev) phy_init(csi->phy); return 0; - end: +#if IS_ENABLED(CONFIG_OF) media_entity_cleanup(&csi->sd.entity); + return ret; +#endif v4l2_device_unregister(csi->vdev.v4l2_dev); - return ret; } @@ -436,35 +476,36 @@ static int dw_csi_remove(struct platform_device *pdev) struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct dw_csi *mipi_csi = sd_to_mipi_csi_dev(sd); - dev_dbg(&pdev->dev, "Removing MIPI CSI-2 module\n"); + dev_dbg(&pdev->dev, "Removing DW MIPI CSI-2 Host module\n"); if (mipi_csi->rst) reset_control_assert(mipi_csi->rst); +#if IS_ENABLED(CONFIG_OF) media_entity_cleanup(&mipi_csi->sd.entity); - +#else + v4l2_device_unregister(mipi_csi->vdev.v4l2_dev); +#endif return 0; } -/** - * @short of_device_id structure - */ +#if IS_ENABLED(CONFIG_OF) static const struct of_device_id dw_mipi_csi_of_match[] = { { .compatible = "snps,dw-csi" }, {}, }; MODULE_DEVICE_TABLE(of, dw_mipi_csi_of_match); +#endif -/** - * @short Platform driver structure - */ static struct platform_driver dw_mipi_csi_driver = { .remove = dw_csi_remove, .probe = dw_csi_probe, .driver = { .name = "dw-csi", .owner = THIS_MODULE, +#if IS_ENABLED(CONFIG_OF) .of_match_table = of_match_ptr(dw_mipi_csi_of_match), +#endif }, }; diff --git a/include/media/dwc/dw-csi-data.h b/include/media/dwc/dw-csi-data.h new file mode 100644 index 0000000..87942ab --- /dev/null +++ b/include/media/dwc/dw-csi-data.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates. + * + * Synopsys DesignWare MIPI CSI-2 platform data + * + * Author: Luis Oliveira <Luis.Oliveira@xxxxxxxxxxxx> + */ + +#include <linux/kernel.h> +#include <media/dwc/dw-mipi-csi-pltfrm.h> + +struct dw_csih_pdata { + u8 eotp_enabled; + u32 hs_freq; + u32 lanes; + u32 pclk; + u32 fps; + u32 bpp; + u8 id; +}; + +static const struct pdata_names csis[] = { + { .name = "dw-csi.0", }, + { .name = "dw-csi.1", }, +}; -- 2.7.4