[media] V4L: sh_mobile_ceu_camera: convert to the new mbus-config subdev operations
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Wed, 27 Jul 2011 21:17:56 +0000 (18:17 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 3 Nov 2011 20:27:51 +0000 (18:27 -0200)
Switch from soc-camera specific .{query,set}_bus_param() to V4L2
subdevice .[gs]_mbus_config() operations.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/sh_mobile_ceu_camera.c

index d1359f4..59101c0 100644 (file)
@@ -144,30 +144,6 @@ static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb)
        return container_of(vb, struct sh_mobile_ceu_buffer, vb);
 }
 
-static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev)
-{
-       unsigned long flags;
-
-       flags = SOCAM_MASTER |
-               SOCAM_PCLK_SAMPLE_RISING |
-               SOCAM_HSYNC_ACTIVE_HIGH |
-               SOCAM_HSYNC_ACTIVE_LOW |
-               SOCAM_VSYNC_ACTIVE_HIGH |
-               SOCAM_VSYNC_ACTIVE_LOW |
-               SOCAM_DATA_ACTIVE_HIGH;
-
-       if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS)
-               flags |= SOCAM_DATAWIDTH_8;
-
-       if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS)
-               flags |= SOCAM_DATAWIDTH_16;
-
-       if (flags & SOCAM_DATAWIDTH_MASK)
-               return flags;
-
-       return 0;
-}
-
 static void ceu_write(struct sh_mobile_ceu_dev *priv,
                      unsigned long reg_offs, u32 data)
 {
@@ -737,66 +713,90 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr)
                ceu_write(pcdev, CAPSR, capsr);
 }
 
+/* Find the bus subdevice driver, e.g., CSI2 */
+static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev,
+                                          struct soc_camera_device *icd)
+{
+       if (!pcdev->csi2_pdev)
+               return soc_camera_to_subdev(icd);
+
+       return find_csi2(pcdev);
+}
+
+#define CEU_BUS_FLAGS (V4L2_MBUS_MASTER |      \
+               V4L2_MBUS_PCLK_SAMPLE_RISING |  \
+               V4L2_MBUS_HSYNC_ACTIVE_HIGH |   \
+               V4L2_MBUS_HSYNC_ACTIVE_LOW |    \
+               V4L2_MBUS_VSYNC_ACTIVE_HIGH |   \
+               V4L2_MBUS_VSYNC_ACTIVE_LOW |    \
+               V4L2_MBUS_DATA_ACTIVE_HIGH)
+
 /* Capture is not running, no interrupts, no locking needed */
 static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
                                       __u32 pixfmt)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
-       int ret;
-       unsigned long camera_flags, common_flags, value;
-       int yuv_lineskip;
+       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;
        u32 capsr = capture_save_reset(pcdev);
+       unsigned int yuv_lineskip;
+       int ret;
 
-       camera_flags = icd->ops->query_bus_param(icd);
-       common_flags = soc_camera_bus_param_compatible(camera_flags,
-                                                      make_bus_param(pcdev));
-       if (!common_flags)
-               return -EINVAL;
+       /*
+        * 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;
+       }
 
        /* Make choises, based on platform preferences */
-       if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
-           (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+       if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
+           (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
                if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW)
-                       common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+                       common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
                else
-                       common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+                       common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
        }
 
-       if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
-           (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+       if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
+           (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
                if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW)
-                       common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+                       common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
                else
-                       common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+                       common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
        }
 
-       ret = icd->ops->set_bus_param(icd, common_flags);
-       if (ret < 0)
+       cfg.flags = common_flags;
+       ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+       if (ret < 0 && ret != -ENOIOCTLCMD)
                return ret;
 
-       switch (common_flags & SOCAM_DATAWIDTH_MASK) {
-       case SOCAM_DATAWIDTH_8:
-               pcdev->is_16bit = 0;
-               break;
-       case SOCAM_DATAWIDTH_16:
+       if (icd->current_fmt->host_fmt->bits_per_sample > 8)
                pcdev->is_16bit = 1;
-               break;
-       default:
-               return -EINVAL;
-       }
+       else
+               pcdev->is_16bit = 0;
 
        ceu_write(pcdev, CRCNTR, 0);
        ceu_write(pcdev, CRCMPR, 0);
 
        value = 0x00000010; /* data fetch by default */
-       yuv_lineskip = 0;
+       yuv_lineskip = 0x10;
 
        switch (icd->current_fmt->host_fmt->fourcc) {
        case V4L2_PIX_FMT_NV12:
        case V4L2_PIX_FMT_NV21:
-               yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */
+               /* convert 4:2:2 -> 4:2:0 */
+               yuv_lineskip = 0; /* skip for NV12/21, no skip for NV16/61 */
                /* fall-through */
        case V4L2_PIX_FMT_NV16:
        case V4L2_PIX_FMT_NV61:
@@ -822,8 +822,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
            icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61)
                value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */
 
-       value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
-       value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
+       value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
+       value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
        value |= pcdev->is_16bit ? 1 << 12 : 0;
 
        /* CSI2 mode */
@@ -866,9 +866,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
         * using 7 we swap the data bytes to match the incoming order:
         * D0, D1, D2, D3, D4, D5, D6, D7
         */
-       value = 0x00000017;
-       if (yuv_lineskip)
-               value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */
+       value = 0x00000007 | yuv_lineskip;
 
        ceu_write(pcdev, CDOCR, value);
        ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
@@ -889,13 +887,19 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
-       unsigned long camera_flags, common_flags;
+       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;
 
-       camera_flags = icd->ops->query_bus_param(icd);
-       common_flags = soc_camera_bus_param_compatible(camera_flags,
-                                                      make_bus_param(pcdev));
-       if (!common_flags || buswidth > 16 ||
-           (buswidth > 8 && !(common_flags & SOCAM_DATAWIDTH_16)))
+       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;
@@ -905,26 +909,26 @@ static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = {
        {
                .fourcc                 = V4L2_PIX_FMT_NV12,
                .name                   = "NV12",
-               .bits_per_sample        = 12,
-               .packing                = SOC_MBUS_PACKING_NONE,
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_1_5X8,
                .order                  = SOC_MBUS_ORDER_LE,
        }, {
                .fourcc                 = V4L2_PIX_FMT_NV21,
                .name                   = "NV21",
-               .bits_per_sample        = 12,
-               .packing                = SOC_MBUS_PACKING_NONE,
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_1_5X8,
                .order                  = SOC_MBUS_ORDER_LE,
        }, {
                .fourcc                 = V4L2_PIX_FMT_NV16,
                .name                   = "NV16",
-               .bits_per_sample        = 16,
-               .packing                = SOC_MBUS_PACKING_NONE,
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        }, {
                .fourcc                 = V4L2_PIX_FMT_NV61,
                .name                   = "NV61",
-               .bits_per_sample        = 16,
-               .packing                = SOC_MBUS_PACKING_NONE,
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
 };
@@ -933,6 +937,8 @@ static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = {
 static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt)
 {
        return  fmt->packing == SOC_MBUS_PACKING_NONE ||
+               (fmt->bits_per_sample == 8 &&
+                fmt->packing == SOC_MBUS_PACKING_1_5X8) ||
                (fmt->bits_per_sample == 8 &&
                 fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
                (fmt->bits_per_sample > 8 &&
@@ -966,6 +972,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
        }
 
        if (!pcdev->pdata->csi2) {
+               /* Are there any restrictions in the CSI-2 case? */
                ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
                if (ret < 0)
                        return 0;
@@ -1626,8 +1633,6 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
        bool image_mode;
        enum v4l2_field field;
 
-       dev_geo(dev, "S_FMT(pix=0x%x, %ux%u)\n", pixfmt, pix->width, pix->height);
-
        switch (pix->field) {
        default:
                pix->field = V4L2_FIELD_NONE;
@@ -1665,6 +1670,9 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
                image_mode = false;
        }
 
+       dev_info(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code,
+               pix->width, pix->height);
+
        dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);
 
        /* 5. - 9. */