[media] ov9640: convert to the control framework
[pandora-kernel.git] / drivers / media / video / mt9v022.c
index 51b0fcc..53149a7 100644 (file)
 #include <linux/delay.h>
 #include <linux/log2.h>
 
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/soc_camera.h>
 
 /*
  * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
@@ -199,78 +200,6 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
        return 0;
 }
 
-static int mt9v022_set_bus_param(struct soc_camera_device *icd,
-                                unsigned long flags)
-{
-       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-       struct soc_camera_link *icl = to_soc_camera_link(icd);
-       unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
-       int ret;
-       u16 pixclk = 0;
-
-       /* Only one width bit may be set */
-       if (!is_power_of_2(width_flag))
-               return -EINVAL;
-
-       if (icl->set_bus_param) {
-               ret = icl->set_bus_param(icl, width_flag);
-               if (ret)
-                       return ret;
-       } else {
-               /*
-                * Without board specific bus width settings we only support the
-                * sensors native bus width
-                */
-               if (width_flag != SOCAM_DATAWIDTH_10)
-                       return -EINVAL;
-       }
-
-       flags = soc_camera_apply_sensor_flags(icl, flags);
-
-       if (flags & SOCAM_PCLK_SAMPLE_FALLING)
-               pixclk |= 0x10;
-
-       if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
-               pixclk |= 0x1;
-
-       if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
-               pixclk |= 0x2;
-
-       ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk);
-       if (ret < 0)
-               return ret;
-
-       if (!(flags & SOCAM_MASTER))
-               mt9v022->chip_control &= ~0x8;
-
-       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
-       if (ret < 0)
-               return ret;
-
-       dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
-               pixclk, mt9v022->chip_control);
-
-       return 0;
-}
-
-static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
-{
-       struct soc_camera_link *icl = to_soc_camera_link(icd);
-       unsigned int flags = SOCAM_MASTER | SOCAM_SLAVE |
-               SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
-               SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
-               SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
-               SOCAM_DATA_ACTIVE_HIGH;
-
-       if (icl->query_bus_param)
-               flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK;
-       else
-               flags |= SOCAM_DATAWIDTH_10;
-
-       return soc_camera_apply_sensor_flags(icl, flags);
-}
-
 static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -557,8 +486,6 @@ static const struct v4l2_queryctrl mt9v022_controls[] = {
 };
 
 static struct soc_camera_ops mt9v022_ops = {
-       .set_bus_param          = mt9v022_set_bus_param,
-       .query_bus_param        = mt9v022_query_bus_param,
        .controls               = mt9v022_controls,
        .num_controls           = ARRAY_SIZE(mt9v022_controls),
 };
@@ -848,6 +775,83 @@ static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
        return 0;
 }
 
+static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+       cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
+               V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
+               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;
+       cfg->type = V4L2_MBUS_PARALLEL;
+       cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+       return 0;
+}
+
+static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
+                                const struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+       unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+       /*
+        * Cannot use icd->current_fmt->host_fmt->bits_per_sample, because that
+        * is the number of bits, that the host has to sample, not the number of
+        * bits, that we have to send. See mx3_camera.c for an example of 10-bit
+        * formats being truncated to 8 bits by the host.
+        */
+       unsigned int bps = soc_mbus_get_fmtdesc(icd->current_fmt->code)->bits_per_sample;
+       int ret;
+       u16 pixclk = 0;
+
+       dev_info(icd->pdev, "set %d: %s, %dbps\n", icd->current_fmt->code,
+                icd->current_fmt->host_fmt->name, bps);
+
+       if (icl->set_bus_param) {
+               ret = icl->set_bus_param(icl, 1 << (bps - 1));
+               if (ret)
+                       return ret;
+       } else if (bps != 10) {
+               /*
+                * Without board specific bus width settings we only support the
+                * sensors native bus width
+                */
+               return -EINVAL;
+       }
+
+       if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+               pixclk |= 0x10;
+
+       if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH))
+               pixclk |= 0x1;
+
+       if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH))
+               pixclk |= 0x2;
+
+       ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk);
+       if (ret < 0)
+               return ret;
+
+       if (!(flags & V4L2_MBUS_MASTER))
+               mt9v022->chip_control &= ~0x8;
+
+       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
+               pixclk, mt9v022->chip_control);
+
+       return 0;
+}
+
 static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
        .s_stream       = mt9v022_s_stream,
        .s_mbus_fmt     = mt9v022_s_fmt,
@@ -857,6 +861,8 @@ static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
        .g_crop         = mt9v022_g_crop,
        .cropcap        = mt9v022_cropcap,
        .enum_mbus_fmt  = mt9v022_enum_fmt,
+       .g_mbus_config  = mt9v022_g_mbus_config,
+       .s_mbus_config  = mt9v022_s_mbus_config,
 };
 
 static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {