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.liakhovet...@gmx.de>
---
 .../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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to