From 17910c70ce338d3fe8f0c376ffd42e6566ae4f5f Mon Sep 17 00:00:00 2001 From: Jeongtae Park Date: Mon, 7 May 2018 11:54:52 +0900 Subject: [PATCH] [COMMON] fimc-is2: clean-up csi_probe() and support sub-device ch. mode Change-Id: I92223707a2efc4cde4f3c76bfbc4ad91b2da6489 Signed-off-by: Jeongtae Park --- .../exynos/fimc-is2/fimc-is-device-csi_v4.c | 283 +++++++++++------- 1 file changed, 169 insertions(+), 114 deletions(-) diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-csi_v4.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-csi_v4.c index 7c6980a6e4fe..2b6aab22ee63 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-csi_v4.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-csi_v4.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "fimc-is-debug.h" #include "fimc-is-config.h" @@ -1860,153 +1861,173 @@ static const struct v4l2_subdev_ops subdev_ops = { .pad = &pad_ops }; +#define VC_DMA_START 0 +#define VC_DMA_SIZE 1 +#define CMN_DMA_START 2 +#define CMN_DMA_SIZE 3 +#define NUM_VC_DMA_RES 4 int fimc_is_csi_probe(void *parent, u32 instance) { - int i = 0; + int vc, m; int ret = 0; struct v4l2_subdev *subdev_csi; struct fimc_is_device_csi *csi; struct fimc_is_device_sensor *device = parent; - struct resource *mem_res; - struct platform_device *pdev; struct fimc_is_core *core; - int num_resource; - int cnt_resource = 0; + struct resource *res; + struct platform_device *pdev; + struct device *dev; + struct device_node *dnode, *child; + u32 dma_res[CSI_VIRTUAL_CH_MAX * NUM_VC_DMA_RES]; + char *irq_name; + int elems; + int cnt_of_ch_mode = 0; FIMC_BUG(!device); - subdev_csi = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); - if (!subdev_csi) { - merr("subdev_csi is NULL", device); - ret = -ENOMEM; - goto p_err; - } - device->subdev_csi = subdev_csi; - core = device->private_data; + pdev = device->pdev; + dev = &pdev->dev; + dnode = dev->of_node; - csi = kzalloc(sizeof(struct fimc_is_device_csi), GFP_KERNEL); + csi = devm_kzalloc(dev, sizeof(struct fimc_is_device_csi), GFP_KERNEL); if (!csi) { - merr("csi is NULL", device); + merr("failed to alloc memory for CSI device", device); ret = -ENOMEM; - goto p_err_free1; + goto err_alloc_csi; } - /* Get SFR base register */ - pdev = device->pdev; - - num_resource = of_property_count_elems_of_size(pdev->dev.of_node, "reg", sizeof(u32)) / 3; - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, cnt_resource++); - if (!mem_res) { - probe_err("Failed to get io memory region(%p)", mem_res); - ret = -EBUSY; - goto err_get_resource; + /* CSI */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csi"); + if (!res) { + probe_err("failed to get memory resource for CSI"); + ret = -ENODEV; + goto err_get_csi_res; } - csi->regs_start = mem_res->start; - csi->regs_end = mem_res->end; - csi->base_reg = devm_ioremap_nocache(&pdev->dev, mem_res->start, resource_size(mem_res)); + csi->regs_start = res->start; + csi->regs_end = res->end; + csi->base_reg = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!csi->base_reg) { - probe_err("Failed to remap io region(%p)", csi->base_reg); + probe_err("can't ioremap for CSI"); ret = -ENOMEM; - goto err_get_resource; + goto err_ioremap_csi; + } + + csi->irq = platform_get_irq_byname(pdev, "csi"); + if (csi->irq < 0) { + probe_err("failed to get IRQ resource for CSI: %d", csi->irq); + ret = csi->irq; + goto err_get_csi_irq; } /* PHY */ - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, cnt_resource++); - if (!mem_res) { - probe_err("Failed to get io memory region(%p)", mem_res); - ret = -EBUSY; - goto err_get_resource; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); + if (!res) { + probe_err("failed to get memory resource for PHY"); + ret = -ENODEV; + goto err_get_phy_res; } - csi->phy_reg = devm_ioremap_nocache(&pdev->dev, mem_res->start, resource_size(mem_res)); + csi->phy_reg = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!csi->phy_reg) { - probe_err("Failed to remap phy io region(%p)", csi->phy_reg); + probe_err("can't ioremap for PHY"); ret = -ENOMEM; - goto err_get_resource; + goto err_ioremap_phy; } - csi->num_of_scm = device->pdata->num_of_ch_mode; + csi->phy = devm_phy_get(dev, "csis_dphy"); + if (IS_ERR(csi->phy)) { + probe_err("failed to get PHY device for CSI"); + ret = PTR_ERR(csi->phy); + goto err_get_phy_dev; + } - /* VC DMA */ - i = 0; - while (cnt_resource < num_resource) { - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, cnt_resource++); - if (!mem_res) { - probe_err("Failed to get io memory region(CSIS VCDMA[%d])(%p)", i, mem_res); - ret = -EBUSY; - goto err_get_resource; - } +#if defined(CONFIG_SECURE_CAMERA_USE) && defined(NOT_SEPERATED_SYSREG) + csi->extra_phy = devm_phy_get(dev, "extra_csis_dphy"); + if (IS_ERR(csi->extra_phy)) + csi->extra_phy = NULL; +#endif - csi->vc_reg[i / CSI_VIRTUAL_CH_MAX][i % CSI_VIRTUAL_CH_MAX] - = devm_ioremap_nocache(&pdev->dev, mem_res->start, resource_size(mem_res)); - if (!csi->vc_reg[i / CSI_VIRTUAL_CH_MAX][i % CSI_VIRTUAL_CH_MAX]) { - probe_err("Failed to remap io region(CSIS VCDMA[%d])(%p)", i, csi->vc_reg[i]); - ret = -ENOMEM; - goto err_get_resource; - } + irq_name = __getname(); + if (unlikely(!irq_name)) { + ret = -ENOMEM; + goto err_alloc_irq_name; + } - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, cnt_resource++); - if (!mem_res) { - probe_err("Failed to get io memory region(CSIS VCDMA CMN[%d])(%p)", i, mem_res); - ret = -EBUSY; - goto err_get_resource; + /* sub-device channel mode */ + for_each_child_of_node(dnode, child) { + elems = of_property_count_elems_of_size(child, "reg", + sizeof(u32) * NUM_VC_DMA_RES); + if (elems != CSI_VIRTUAL_CH_MAX) { + probe_err("insufficient VC DMA memory resources(%d)", elems); + ret = -EINVAL; + goto err_get_vc_dma_res; } - csi->cmn_reg[i / CSI_VIRTUAL_CH_MAX][i % CSI_VIRTUAL_CH_MAX] - = devm_ioremap_nocache(&pdev->dev, mem_res->start, resource_size(mem_res)); - if (!csi->cmn_reg[i / CSI_VIRTUAL_CH_MAX][i % CSI_VIRTUAL_CH_MAX]) { - probe_err("Failed to remap io region(CSIS VCDMA CMN[%d])(%p)", i, csi->cmn_reg[i]); - ret = -ENOMEM; - goto err_get_resource; + ret = of_property_read_u32_array(child, "reg", dma_res, + CSI_VIRTUAL_CH_MAX * NUM_VC_DMA_RES); + if (ret) { + probe_err("failed to get VC DMA memory resources"); + goto err_read_vc_dma_res; } - i++; - } - num_resource = of_property_count_elems_of_size(pdev->dev.of_node, "interrupts", sizeof(u32)) / 3; - cnt_resource = 0; + for (vc = 0; vc < CSI_VIRTUAL_CH_MAX; vc++) { + csi->vc_reg[cnt_of_ch_mode][vc] = devm_ioremap_nocache(dev, + dma_res[(vc * NUM_VC_DMA_RES) + VC_DMA_START], + dma_res[(vc * NUM_VC_DMA_RES) + VC_DMA_SIZE]); + if (!csi->vc_reg[cnt_of_ch_mode][vc]) { + probe_err("failed to ioremap VC[%d] DMA memory for mode: %d", + vc, cnt_of_ch_mode); + ret = -ENOMEM; + goto err_ioremap_vc_dma_mem; + } + + csi->cmn_reg[cnt_of_ch_mode][vc] = devm_ioremap_nocache(dev, + dma_res[(vc * NUM_VC_DMA_RES) + CMN_DMA_START], + dma_res[(vc * NUM_VC_DMA_RES) + CMN_DMA_SIZE]); + if (!csi->cmn_reg[cnt_of_ch_mode][vc]) { + probe_err("failed to ioremap CMN[%d] DMA memory for mode: %d", + vc, cnt_of_ch_mode); + ret = -ENOMEM; + goto err_ioremap_cmn_dma_mem; + } - /* Get CORE IRQ SPI number */ - csi->irq = platform_get_irq(pdev, cnt_resource++); - if (csi->irq < 0) { - probe_err("Failed to get csi_irq(%d)", csi->irq); - ret = -EBUSY; - goto err_get_irq; - } - - /* Get DMA IRQ SPI number */ - i = 0; - while (cnt_resource < num_resource) { - csi->vc_irq[i / CSI_VIRTUAL_CH_MAX][i % CSI_VIRTUAL_CH_MAX] - = platform_get_irq(pdev, cnt_resource++); - if (csi->vc_irq[i / CSI_VIRTUAL_CH_MAX][i % CSI_VIRTUAL_CH_MAX] < 0) { - probe_err("Failed to get vc%d DMA irq(%d)", i, - csi->vc_irq[i / CSI_VIRTUAL_CH_MAX][i % CSI_VIRTUAL_CH_MAX]); - ret = -EBUSY; - goto err_get_irq; + snprintf(irq_name, PATH_MAX, "mode%d_VC%d", cnt_of_ch_mode, vc); + csi->vc_irq[cnt_of_ch_mode][vc] = platform_get_irq_byname(pdev, irq_name); + if (csi->vc_irq[cnt_of_ch_mode][vc] < 0) { + probe_err("invalid VC[%d] DMA IRQ for mode: %d", + vc, cnt_of_ch_mode); + ret = -EINVAL; + goto err_get_dma_irq; + + } } - i++; + + cnt_of_ch_mode++; } - csi->phy = devm_phy_get(&pdev->dev, "csis_dphy"); - if (IS_ERR(csi->phy)) - return PTR_ERR(csi->phy); + if ((device->dma_abstract) && (device->num_of_ch_mode > cnt_of_ch_mode)) { + probe_err("too many sensor ch. modes sensor: %d, csi: %d", + device->num_of_ch_mode, cnt_of_ch_mode); + ret = -EINVAL; + goto err_too_many_ch_modes; + } -#if defined(CONFIG_SECURE_CAMERA_USE) && defined(NOT_SEPERATED_SYSREG) - csi->extra_phy = devm_phy_get(&pdev->dev, "extra_csis_dphy"); - if (IS_ERR(csi->extra_phy)) - csi->extra_phy = NULL; -#endif + subdev_csi = devm_kzalloc(dev, sizeof(struct v4l2_subdev), GFP_KERNEL); + if (!subdev_csi) { + merr("subdev_csi is NULL", device); + ret = -ENOMEM; + goto err_alloc_subdev_csi; + } + + device->subdev_csi = subdev_csi; - /* pointer to me from device sensor */ csi->subdev = &device->subdev_csi; + core = device->private_data; + csi->csi_dma = &core->csi_dma; csi->instance = instance; - /* Get common dma */ - csi->csi_dma = &core->csi_dma; - /* default state setting */ clear_bit(CSIS_SET_MULTIBUF_VC1, &csi->state); clear_bit(CSIS_SET_MULTIBUF_VC2, &csi->state); @@ -2014,8 +2035,8 @@ int fimc_is_csi_probe(void *parent, u32 instance) set_bit(CSIS_DMA_ENABLE, &csi->state); /* init dma subdev slots */ - for (i = CSI_VIRTUAL_CH_0; i < CSI_VIRTUAL_CH_MAX; i++) - csi->dma_subdev[i] = NULL; + for (vc = CSI_VIRTUAL_CH_0; vc < CSI_VIRTUAL_CH_MAX; vc++) + csi->dma_subdev[vc] = NULL; csi->workqueue = alloc_workqueue("fimc-csi/[H/U]", WQ_HIGHPRI | WQ_UNBOUND, 0); if (!csi->workqueue) @@ -2033,22 +2054,56 @@ int fimc_is_csi_probe(void *parent, u32 instance) goto err_reg_v4l2_subdev; } - info("[%d][FRT:D] %s(%d)\n", instance, __func__, ret); + info("[%d][CSI:D] %s(%d)\n", instance, __func__, ret); return 0; err_reg_v4l2_subdev: -err_get_irq: - iounmap(csi->base_reg); + devm_kfree(dev, subdev_csi); + device->subdev_csi = NULL; + +err_alloc_subdev_csi: +err_too_many_ch_modes: +err_get_dma_irq: + for (m = 0; m < SCM_MAX; m++) + for (vc = 0; vc < CSI_VIRTUAL_CH_MAX; vc++) + csi->vc_irq[m][vc] = -ENXIO; + +err_ioremap_cmn_dma_mem: +err_ioremap_vc_dma_mem: + for (m = 0; m < SCM_MAX; m++) { + for (vc = 0; vc < CSI_VIRTUAL_CH_MAX; vc++) { + if (csi->vc_reg[m][vc]) + devm_iounmap(dev, csi->vc_reg[m][vc]); + + if (csi->cmn_reg[m][vc]) + devm_iounmap(dev, csi->cmn_reg[m][vc]); + } + } -err_get_resource: - kfree(csi); +err_read_vc_dma_res: +err_get_vc_dma_res: + __putname(irq_name); -p_err_free1: - kfree(subdev_csi); - device->subdev_csi = NULL; +err_alloc_irq_name: +#if defined(CONFIG_SECURE_CAMERA_USE) && defined(NOT_SEPERATED_SYSREG) + devm_phy_put(dev, csi->extra_phy); +#endif + devm_phy_put(dev, csi->phy); -p_err: - err("[%d][FRT:D] %s(%d)\n", instance, __func__, ret); +err_get_phy_dev: + devm_iounmap(dev, csi->phy_reg); + +err_ioremap_phy: +err_get_phy_res: +err_get_csi_irq: + devm_iounmap(dev, csi->base_reg); + +err_ioremap_csi: +err_get_csi_res: + devm_kfree(dev, csi); + +err_alloc_csi: + err("[%d][CSI:D] %s: %d", instance, __func__, ret); return ret; } -- 2.20.1