Signed-off-by: Sylwester Nawrocki <s.nawrocki@xxxxxxxxxxx> Signed-off-by: Karol Lewandowski <k.lewandowsk@xxxxxxxxxxx> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> --- .../bindings/camera/soc/samsung-fimc.txt | 66 ++++ drivers/media/video/s5p-fimc/fimc-capture.c | 2 +- drivers/media/video/s5p-fimc/fimc-core.c | 410 +++++++++++--------- drivers/media/video/s5p-fimc/fimc-core.h | 2 - drivers/media/video/s5p-fimc/fimc-mdevice.c | 8 +- 5 files changed, 291 insertions(+), 197 deletions(-) create mode 100644 Documentation/devicetree/bindings/camera/soc/samsung-fimc.txt diff --git a/Documentation/devicetree/bindings/camera/soc/samsung-fimc.txt b/Documentation/devicetree/bindings/camera/soc/samsung-fimc.txt new file mode 100644 index 0000000..1ec48e9 --- /dev/null +++ b/Documentation/devicetree/bindings/camera/soc/samsung-fimc.txt @@ -0,0 +1,66 @@ +Samsung S5P/EXYNOS SoC Camera Subsystem (FIMC) +---------------------------------------------- + +The Exynos Camera subsystem uses a dedicated device node associated with +top level device driver that manages common properties of the whole subsystem, +like common camera port pins or clocks for external image sensors. This +aggregate node references related platform sub-devices - FIMC, FIMC-LITE, +MIPI-CSIS [1], and it also contains nodes describing image sensors wired to +the host SoC's video port and using I2C or SPI as the control bus. + + +Common 'camera' node +-------------------- + +Required properties: + +- compatible : must be "samsung,fimc" +- fimc-controllers : an array of phandles to 'fimc' device nodes, + size of this array must be at least 1; + +Optional properties: + +- csi-rx-controllers : an array of phandles to 'csis' device nodes, + it is required for sensors with MIPI-CSI2 bus; + +'fimc' device node +------------------ + +Required properties: + +- compatible : should be one of: + "samsung,s5pv210-fimc" + "samsung,exynos4210-fimc"; + "samsung,exynos4412-fimc"; +- reg : physical base address and size of the device memory mapped + registers; +- interrupts : FIMC interrupt to the CPU should be described here; +- cell-index : FIMC IP instance index, the number of available instances + depends on the SoC revision. For S5PV210 valid values are: + 0...2, for Exynos4x1x: 0...3. + +Example: + + fimc0: fimc@11800000 { + compatible = "samsung,exynos4210-fimc"; + reg = <0x11800000 0x1000>; + interrupts = <0 85 0>; + cell-index = <0>; + }; + + csis0: csis@11880000 { + compatible = "samsung,exynos4210-csis"; + reg = <0x11880000 0x1000>; + interrupts = <0 78 0>; + cell-index = <0>; + }; + + camera { + compatible = "samsung,fimc"; + #address-cells = <1>; + #size-cells = <1>; + fimc-controllers = <&fimc0>; + csi-rx-controllers = <&csis0>; + }; + +[1] Documentation/devicetree/bindings/video/samsung-mipi-csis.txt diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 0549451..7585b2f 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -1684,7 +1684,7 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc) v4l2_subdev_init(sd, &fimc_subdev_ops); sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id); + snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id); fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index fedcd56..30c6365 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -21,6 +21,8 @@ #include <linux/pm_runtime.h> #include <linux/list.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/clk.h> #include <media/v4l2-ioctl.h> @@ -188,6 +190,198 @@ static struct fimc_fmt fimc_formats[] = { }, }; +/* Image pixel limits, similar across several FIMC HW revisions. */ +static struct fimc_pix_limit s5p_pix_limit[4] = { + [0] = { + .scaler_en_w = 3264, + .scaler_dis_w = 8192, + .in_rot_en_h = 1920, + .in_rot_dis_w = 8192, + .out_rot_en_w = 1920, + .out_rot_dis_w = 4224, + }, + [1] = { + .scaler_en_w = 4224, + .scaler_dis_w = 8192, + .in_rot_en_h = 1920, + .in_rot_dis_w = 8192, + .out_rot_en_w = 1920, + .out_rot_dis_w = 4224, + }, + [2] = { + .scaler_en_w = 1920, + .scaler_dis_w = 8192, + .in_rot_en_h = 1280, + .in_rot_dis_w = 8192, + .out_rot_en_w = 1280, + .out_rot_dis_w = 1920, + }, + [3] = { + .scaler_en_w = 1920, + .scaler_dis_w = 8192, + .in_rot_en_h = 1366, + .in_rot_dis_w = 8192, + .out_rot_en_w = 1366, + .out_rot_dis_w = 1920, + }, +}; + +static struct fimc_variant fimc0_variant_s5p = { + .has_inp_rot = 1, + .has_out_rot = 1, + .has_cam_if = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 8, + .min_vsize_align = 16, + .out_buf_count = 4, + .pix_limit = &s5p_pix_limit[0], +}; + +static struct fimc_variant fimc2_variant_s5p = { + .has_cam_if = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 8, + .min_vsize_align = 16, + .out_buf_count = 4, + .pix_limit = &s5p_pix_limit[1], +}; + +static struct fimc_variant fimc0_variant_s5pv210 = { + .pix_hoff = 1, + .has_inp_rot = 1, + .has_out_rot = 1, + .has_cam_if = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 8, + .min_vsize_align = 16, + .out_buf_count = 4, + .pix_limit = &s5p_pix_limit[1], +}; + +static struct fimc_variant fimc1_variant_s5pv210 = { + .pix_hoff = 1, + .has_inp_rot = 1, + .has_out_rot = 1, + .has_cam_if = 1, + .has_mainscaler_ext = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 1, + .min_vsize_align = 1, + .out_buf_count = 4, + .pix_limit = &s5p_pix_limit[2], +}; + +static struct fimc_variant fimc2_variant_s5pv210 = { + .has_cam_if = 1, + .pix_hoff = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 8, + .min_vsize_align = 16, + .out_buf_count = 4, + .pix_limit = &s5p_pix_limit[2], +}; + +static struct fimc_variant fimc0_variant_exynos4 = { + .pix_hoff = 1, + .has_inp_rot = 1, + .has_out_rot = 1, + .has_cam_if = 1, + .has_cistatus2 = 1, + .has_mainscaler_ext = 1, + .has_alpha = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 2, + .min_vsize_align = 1, + .out_buf_count = 32, + .pix_limit = &s5p_pix_limit[1], +}; + +static struct fimc_variant fimc3_variant_exynos4 = { + .pix_hoff = 1, + .has_cam_if = 1, + .has_cistatus2 = 1, + .has_mainscaler_ext = 1, + .has_alpha = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 2, + .min_vsize_align = 1, + .out_buf_count = 32, + .pix_limit = &s5p_pix_limit[3], +}; + +/* S5PC100 */ +static struct fimc_drvdata fimc_drvdata_s5p = { + .variant = { + [0] = &fimc0_variant_s5p, + [1] = &fimc0_variant_s5p, + [2] = &fimc2_variant_s5p, + }, + .num_entities = 3, + .lclk_frequency = 133000000UL, +}; + +/* S5PV210, S5PC110 */ +static struct fimc_drvdata fimc_drvdata_s5pv210 = { + .variant = { + [0] = &fimc0_variant_s5pv210, + [1] = &fimc1_variant_s5pv210, + [2] = &fimc2_variant_s5pv210, + }, + .num_entities = 3, + .lclk_frequency = 166000000UL, +}; + +/* EXYNOS4210, S5PV310, S5PC210 */ +static struct fimc_drvdata fimc_drvdata_exynos4 = { + .variant = { + [0] = &fimc0_variant_exynos4, + [1] = &fimc0_variant_exynos4, + [2] = &fimc0_variant_exynos4, + [3] = &fimc3_variant_exynos4, + }, + .num_entities = 4, + .lclk_frequency = 166000000UL, +}; + +static struct platform_device_id fimc_driver_ids[] = { + { + .name = "s5p-fimc", + .driver_data = (unsigned long)&fimc_drvdata_s5p, + }, { + .name = "s5pv210-fimc", + .driver_data = (unsigned long)&fimc_drvdata_s5pv210, + }, { + .name = "exynos4-fimc", + .driver_data = (unsigned long)&fimc_drvdata_exynos4, + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, fimc_driver_ids); + +#ifdef CONFIG_OF +static const struct of_device_id fimc_of_match[] __devinitconst = { + { + .compatible = "samsung,s5pv210-fimc", + .data = &fimc_drvdata_s5pv210, + }, { + .compatible = "samsung,exynos4210-fimc", + .data = &fimc_drvdata_exynos4, + }, { + .compatible = "samsung,exynos4412-fimc", + .data = &fimc_drvdata_exynos4, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, fimc_of_match); +#endif + struct fimc_fmt *fimc_get_format(unsigned int index) { if (index >= ARRAY_SIZE(fimc_formats)) @@ -865,29 +1059,39 @@ static int fimc_m2m_resume(struct fimc_dev *fimc) static int fimc_probe(struct platform_device *pdev) { - struct fimc_drvdata *drv_data = fimc_get_drvdata(pdev); - struct s5p_platform_fimc *pdata; + struct fimc_drvdata *drv_data = NULL; + + const struct of_device_id *of_id; struct fimc_dev *fimc; struct resource *res; int ret = 0; - if (pdev->id >= drv_data->num_entities) { - dev_err(&pdev->dev, "Invalid platform device id: %d\n", - pdev->id); - return -EINVAL; - } - fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL); if (!fimc) return -ENOMEM; - fimc->id = pdev->id; + if (pdev->dev.of_node) { + u32 id = 0; + of_id = of_match_node(fimc_of_match, pdev->dev.of_node); + if (of_id) + drv_data = of_id->data; + + of_property_read_u32(pdev->dev.of_node, "cell-index", &id); + fimc->id = id; + + } else { + drv_data = fimc_get_drvdata(pdev); + fimc->id = pdev->id; + } + + if (drv_data == NULL || fimc->id >= drv_data->num_entities) { + dev_err(&pdev->dev, "Invalid driver data or device index (%d)\n", + fimc->id); + return -EINVAL; + } fimc->variant = drv_data->variant[fimc->id]; fimc->pdev = pdev; - pdata = pdev->dev.platform_data; - fimc->pdata = pdata; - init_waitqueue_head(&fimc->irq_queue); spin_lock_init(&fimc->slock); mutex_init(&fimc->lock); @@ -1036,181 +1240,6 @@ static int __devexit fimc_remove(struct platform_device *pdev) return 0; } -/* Image pixel limits, similar across several FIMC HW revisions. */ -static struct fimc_pix_limit s5p_pix_limit[4] = { - [0] = { - .scaler_en_w = 3264, - .scaler_dis_w = 8192, - .in_rot_en_h = 1920, - .in_rot_dis_w = 8192, - .out_rot_en_w = 1920, - .out_rot_dis_w = 4224, - }, - [1] = { - .scaler_en_w = 4224, - .scaler_dis_w = 8192, - .in_rot_en_h = 1920, - .in_rot_dis_w = 8192, - .out_rot_en_w = 1920, - .out_rot_dis_w = 4224, - }, - [2] = { - .scaler_en_w = 1920, - .scaler_dis_w = 8192, - .in_rot_en_h = 1280, - .in_rot_dis_w = 8192, - .out_rot_en_w = 1280, - .out_rot_dis_w = 1920, - }, - [3] = { - .scaler_en_w = 1920, - .scaler_dis_w = 8192, - .in_rot_en_h = 1366, - .in_rot_dis_w = 8192, - .out_rot_en_w = 1366, - .out_rot_dis_w = 1920, - }, -}; - -static struct fimc_variant fimc0_variant_s5p = { - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[0], -}; - -static struct fimc_variant fimc2_variant_s5p = { - .has_cam_if = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[1], -}; - -static struct fimc_variant fimc0_variant_s5pv210 = { - .pix_hoff = 1, - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[1], -}; - -static struct fimc_variant fimc1_variant_s5pv210 = { - .pix_hoff = 1, - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 1, - .min_vsize_align = 1, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[2], -}; - -static struct fimc_variant fimc2_variant_s5pv210 = { - .has_cam_if = 1, - .pix_hoff = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[2], -}; - -static struct fimc_variant fimc0_variant_exynos4 = { - .pix_hoff = 1, - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .has_cistatus2 = 1, - .has_mainscaler_ext = 1, - .has_alpha = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 2, - .min_vsize_align = 1, - .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[1], -}; - -static struct fimc_variant fimc3_variant_exynos4 = { - .pix_hoff = 1, - .has_cam_if = 1, - .has_cistatus2 = 1, - .has_mainscaler_ext = 1, - .has_alpha = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 2, - .min_vsize_align = 1, - .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[3], -}; - -/* S5PC100 */ -static struct fimc_drvdata fimc_drvdata_s5p = { - .variant = { - [0] = &fimc0_variant_s5p, - [1] = &fimc0_variant_s5p, - [2] = &fimc2_variant_s5p, - }, - .num_entities = 3, - .lclk_frequency = 133000000UL, -}; - -/* S5PV210, S5PC110 */ -static struct fimc_drvdata fimc_drvdata_s5pv210 = { - .variant = { - [0] = &fimc0_variant_s5pv210, - [1] = &fimc1_variant_s5pv210, - [2] = &fimc2_variant_s5pv210, - }, - .num_entities = 3, - .lclk_frequency = 166000000UL, -}; - -/* EXYNOS4210, S5PV310, S5PC210 */ -static struct fimc_drvdata fimc_drvdata_exynos4 = { - .variant = { - [0] = &fimc0_variant_exynos4, - [1] = &fimc0_variant_exynos4, - [2] = &fimc0_variant_exynos4, - [3] = &fimc3_variant_exynos4, - }, - .num_entities = 4, - .lclk_frequency = 166000000UL, -}; - -static struct platform_device_id fimc_driver_ids[] = { - { - .name = "s5p-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5p, - }, { - .name = "s5pv210-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5pv210, - }, { - .name = "exynos4-fimc", - .driver_data = (unsigned long)&fimc_drvdata_exynos4, - }, - {}, -}; -MODULE_DEVICE_TABLE(platform, fimc_driver_ids); - static const struct dev_pm_ops fimc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume) SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) @@ -1221,9 +1250,10 @@ static struct platform_driver fimc_driver = { .remove = __devexit_p(fimc_remove), .id_table = fimc_driver_ids, .driver = { - .name = FIMC_MODULE_NAME, - .owner = THIS_MODULE, - .pm = &fimc_pm_ops, + .of_match_table = of_match_ptr(fimc_of_match), + .name = FIMC_MODULE_NAME, + .owner = THIS_MODULE, + .pm = &fimc_pm_ops, } }; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 95b27ae..a1df84d 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -414,7 +414,6 @@ struct fimc_ctx; * @slock: the spinlock protecting this data structure * @lock: the mutex protecting this data structure * @pdev: pointer to the FIMC platform device - * @pdata: pointer to the device platform data * @variant: the IP variant information * @id: FIMC device index (0..FIMC_MAX_DEVS) * @clock: clocks required for FIMC operation @@ -431,7 +430,6 @@ struct fimc_dev { spinlock_t slock; struct mutex lock; struct platform_device *pdev; - struct s5p_platform_fimc *pdata; struct fimc_variant *variant; u16 id; struct clk *clock[MAX_FIMC_CLOCKS]; diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index 2d780e5..3ffc4f5e 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -335,15 +335,15 @@ static int fimc_register_callback(struct device *dev, void *p) struct fimc_dev *fimc = dev_get_drvdata(dev); struct v4l2_subdev *sd = &fimc->vid_cap.subdev; struct fimc_md *fmd = p; - int ret = 0; + int ret; - if (!fimc || !fimc->pdev) + if (fimc == NULL) return 0; - if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS) + if (fimc->id >= FIMC_MAX_DEVS) return 0; - fmd->fimc[fimc->pdev->id] = fimc; + fmd->fimc[fimc->id] = fimc; sd->grp_id = FIMC_GROUP_ID; ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); -- 1.7.10 -- 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