Additionally to the basic DT support, added to the driver in previous patches, this patch implements complete interface configuration from DT. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@xxxxxx> --- .../platform/soc_camera/sh_mobile_ceu_camera.c | 126 ++++++++++++-------- 1 files changed, 78 insertions(+), 48 deletions(-) diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 1fd03f6..78bcf23 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -37,6 +37,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-dev.h> +#include <media/v4l2-of.h> #include <media/soc_camera.h> #include <media/sh_mobile_ceu.h> #include <media/sh_mobile_csi2.h> @@ -784,50 +785,61 @@ static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct soc_camera_link *icl = icd->link; struct sh_mobile_ceu_dev *pcdev = ici->priv; struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - unsigned long value, common_flags = CEU_BUS_FLAGS; + unsigned long value, common_flags; u32 capsr = capture_save_reset(pcdev); unsigned int yuv_lineskip; int ret; - /* - * If the client doesn't implement g_mbus_config, we just use our - * platform data - */ - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); - if (!ret) { - common_flags = soc_mbus_config_compatible(&cfg, - common_flags); - if (!common_flags) - return -EINVAL; - } else if (ret != -ENOIOCTLCMD) { - return ret; - } + if (icl->of_link) { + /* + * OF configuration validity verified in + * sh_mobile_ceu_try_bus_param() + */ + common_flags = icl->of_link->mbus_flags; + } else { + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - /* Make choises, based on platform preferences */ - if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { - if (pcdev->flags & SH_CEU_FLAG_HSYNC_LOW) - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; - else - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; - } + common_flags = CEU_BUS_FLAGS; + /* + * If the client doesn't implement g_mbus_config, we just use + * our platform data + */ + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, + common_flags); + if (!common_flags) + return -EINVAL; + } else if (ret != -ENOIOCTLCMD) { + return ret; + } - if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { - if (pcdev->flags & SH_CEU_FLAG_VSYNC_LOW) - common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; - else - common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; - } + /* Make choises, based on platform preferences */ + if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { + if (pcdev->flags & SH_CEU_FLAG_HSYNC_LOW) + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; + else + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; + } - cfg.flags = common_flags; - ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; + if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { + if (pcdev->flags & SH_CEU_FLAG_VSYNC_LOW) + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; + else + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; + } + + cfg.flags = common_flags; + ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + } if (icd->current_fmt->host_fmt->bits_per_sample > 8) pcdev->is_16bit = 1; @@ -877,7 +889,9 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) value |= 3 << 12; else if (pcdev->is_16bit) value |= 1 << 12; - else if (pcdev->flags & SH_CEU_FLAG_LOWER_8BIT) + else if (pcdev->flags & SH_CEU_FLAG_LOWER_8BIT || + (icl->of_link && + !icl->of_link->parallel.data_shift)) value |= 2 << 12; ceu_write(pcdev, CAMCR, value); @@ -931,21 +945,36 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, unsigned char buswidth) { struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); - unsigned long common_flags = CEU_BUS_FLAGS; - struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - int ret; + struct soc_camera_link *icl = icd->link; - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); - if (!ret) - common_flags = soc_mbus_config_compatible(&cfg, - common_flags); - else if (ret != -ENOIOCTLCMD) - return ret; + if (icl->of_link) { + unsigned int bus_width = icl->of_link->parallel.bus_width, + data_shift = icl->of_link->parallel.data_shift; + /* + * CEU can use either lower (data shift = 0) or upper (data + * shift = 8) data lines out of 16 available + */ + if (icl->of_link->mbus_flags & ~CEU_BUS_FLAGS || + bus_width < buswidth || bus_width > 16 || + (data_shift && (data_shift != 8 || bus_width > 8))) + return -EINVAL; + } else { + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + struct sh_mobile_ceu_dev *pcdev = ici->priv; + struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); + unsigned long common_flags = CEU_BUS_FLAGS; + int ret; - if (!common_flags || buswidth > 16) - return -EINVAL; + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) + common_flags = soc_mbus_config_compatible(&cfg, + common_flags); + else if (ret != -ENOIOCTLCMD) + return ret; + + if (!common_flags || buswidth > 16) + return -EINVAL; + } return 0; } @@ -2335,6 +2364,7 @@ MODULE_DEVICE_TABLE(of, sh_mobile_ceu_of_match); static struct platform_driver sh_mobile_ceu_driver = { .driver = { .name = "sh_mobile_ceu", + .owner = THIS_MODULE, .pm = &sh_mobile_ceu_dev_pm_ops, .of_match_table = sh_mobile_ceu_of_match, }, -- 1.7.2.5 -- 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