]> err.no Git - linux-2.6/blobdiff - drivers/media/video/mt9v022.c
Merge branch 'for-2.6.26' of master.kernel.org:/pub/scm/linux/kernel/git/jwboyer...
[linux-2.6] / drivers / media / video / mt9v022.c
index 468333946d574dfdfd9dea4416b5457b90e97d30..d1391ac550963b14ebeb2e52e9470c5215501bfd 100644 (file)
@@ -59,18 +59,25 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"\n");
 /* Progressive scan, master, defaults */
 #define MT9V022_CHIP_CONTROL_DEFAULT   0x188
 
-static const struct soc_camera_data_format mt9v022_formats[] = {
+static const struct soc_camera_data_format mt9v022_colour_formats[] = {
+       /* Order important: first natively supported,
+        * second supported with a GPIO extender */
        {
-               .name           = "RGB Bayer (sRGB)",
-               .depth          = 8,
-               .fourcc         = V4L2_PIX_FMT_SBGGR8,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-       }, {
-               .name           = "RGB Bayer (sRGB)",
+               .name           = "Bayer (sRGB) 10 bit",
                .depth          = 10,
                .fourcc         = V4L2_PIX_FMT_SBGGR16,
                .colorspace     = V4L2_COLORSPACE_SRGB,
        }, {
+               .name           = "Bayer (sRGB) 8 bit",
+               .depth          = 8,
+               .fourcc         = V4L2_PIX_FMT_SBGGR8,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+       }
+};
+
+static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
+       /* Order important - see above */
+       {
                .name           = "Monochrome 10 bit",
                .depth          = 10,
                .fourcc         = V4L2_PIX_FMT_Y16,
@@ -234,19 +241,89 @@ static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
 #endif
 }
 
-static int mt9v022_set_capture_format(struct soc_camera_device *icd,
-               __u32 pixfmt, struct v4l2_rect *rect, unsigned int flags)
+static int bus_switch_possible(struct mt9v022 *mt9v022)
+{
+#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+       return gpio_is_valid(mt9v022->switch_gpio);
+#else
+       return 0;
+#endif
+}
+
+static int mt9v022_set_bus_param(struct soc_camera_device *icd,
+                                unsigned long flags)
 {
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       unsigned int width_flag = flags & (IS_DATAWIDTH_10 | IS_DATAWIDTH_9 |
-                                          IS_DATAWIDTH_8);
-       u16 pixclk = 0;
+       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 ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
+           (mt9v022->datawidth != 9  && (width_flag == SOCAM_DATAWIDTH_9)) ||
+           (mt9v022->datawidth != 8  && (width_flag == SOCAM_DATAWIDTH_8))) {
+               /* Well, we actually only can do 10 or 8 bits... */
+               if (width_flag == SOCAM_DATAWIDTH_9)
+                       return -EINVAL;
+
+               ret = bus_switch_act(mt9v022,
+                                    width_flag == SOCAM_DATAWIDTH_8);
+               if (ret < 0)
+                       return ret;
+
+               mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
+       }
+
+       if (flags & SOCAM_PCLK_SAMPLE_RISING)
+               pixclk |= 0x10;
+
+       if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
+               pixclk |= 0x1;
+
+       if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
+               pixclk |= 0x2;
+
+       ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
+       if (ret < 0)
+               return ret;
+
+       if (!(flags & SOCAM_MASTER))
+               mt9v022->chip_control &= ~0x8;
+
+       ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(&icd->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 mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       unsigned int width_flag = SOCAM_DATAWIDTH_10;
+
+       if (bus_switch_possible(mt9v022))
+               width_flag |= SOCAM_DATAWIDTH_8;
+
+       return 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_MASTER | SOCAM_SLAVE |
+               width_flag;
+}
+
+static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
+               __u32 pixfmt, struct v4l2_rect *rect)
+{
+       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       int ret;
+
        /* The caller provides a supported format, as verified per call to
         * icd->try_fmt_cap(), datawidth is from our supported format list */
        switch (pixfmt) {
@@ -301,44 +378,6 @@ static int mt9v022_set_capture_format(struct soc_camera_device *icd,
 
        dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height);
 
-       if ((mt9v022->datawidth != 10 && (width_flag == IS_DATAWIDTH_10)) ||
-           (mt9v022->datawidth != 9  && (width_flag == IS_DATAWIDTH_9)) ||
-           (mt9v022->datawidth != 8  && (width_flag == IS_DATAWIDTH_8))) {
-               /* Well, we actually only can do 10 or 8 bits... */
-               if (width_flag == IS_DATAWIDTH_9)
-                       return -EINVAL;
-
-               ret = bus_switch_act(mt9v022,
-                                    width_flag == IS_DATAWIDTH_8);
-               if (ret < 0)
-                       return ret;
-
-               mt9v022->datawidth = width_flag == IS_DATAWIDTH_8 ? 8 : 10;
-       }
-
-       if (flags & IS_PCLK_SAMPLE_RISING)
-               pixclk |= 0x10;
-
-       if (!(flags & IS_HSYNC_ACTIVE_HIGH))
-               pixclk |= 0x1;
-
-       if (!(flags & IS_VSYNC_ACTIVE_HIGH))
-               pixclk |= 0x2;
-
-       ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
-       if (ret < 0)
-               return ret;
-
-       if (!(flags & IS_MASTER))
-               mt9v022->chip_control &= ~0x8;
-
-       ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
-       if (ret < 0)
-               return ret;
-
-       dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
-               pixclk, mt9v022->chip_control);
-
        return 0;
 }
 
@@ -413,13 +452,7 @@ static int mt9v022_set_register(struct soc_camera_device *icd,
 }
 #endif
 
-static unsigned int mt9v022_get_datawidth(struct soc_camera_device *icd)
-{
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       return mt9v022->datawidth;
-}
-
-const struct v4l2_queryctrl mt9v022_controls[] = {
+static const struct v4l2_queryctrl mt9v022_controls[] = {
        {
                .id             = V4L2_CID_VFLIP,
                .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -473,22 +506,23 @@ const struct v4l2_queryctrl mt9v022_controls[] = {
        }
 };
 
-static int mt9v022_get_control(struct soc_camera_device *icd,
-                              struct v4l2_control *ctrl);
-static int mt9v022_set_control(struct soc_camera_device *icd,
-                              struct v4l2_control *ctrl);
+static int mt9v022_video_probe(struct soc_camera_device *);
+static void mt9v022_video_remove(struct soc_camera_device *);
+static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *);
+static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *);
 
 static struct soc_camera_ops mt9v022_ops = {
        .owner                  = THIS_MODULE,
+       .probe                  = mt9v022_video_probe,
+       .remove                 = mt9v022_video_remove,
        .init                   = mt9v022_init,
        .release                = mt9v022_release,
        .start_capture          = mt9v022_start_capture,
        .stop_capture           = mt9v022_stop_capture,
-       .set_capture_format     = mt9v022_set_capture_format,
+       .set_fmt_cap            = mt9v022_set_fmt_cap,
        .try_fmt_cap            = mt9v022_try_fmt_cap,
-       .formats                = mt9v022_formats,
-       .num_formats            = ARRAY_SIZE(mt9v022_formats),
-       .get_datawidth          = mt9v022_get_datawidth,
+       .set_bus_param          = mt9v022_set_bus_param,
+       .query_bus_param        = mt9v022_query_bus_param,
        .controls               = mt9v022_controls,
        .num_controls           = ARRAY_SIZE(mt9v022_controls),
        .get_control            = mt9v022_get_control,
@@ -671,9 +705,19 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
                            !strcmp("color", sensor_type))) {
                ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+               icd->formats = mt9v022_colour_formats;
+               if (mt9v022->client->dev.platform_data)
+                       icd->num_formats = ARRAY_SIZE(mt9v022_colour_formats);
+               else
+                       icd->num_formats = 1;
        } else {
                ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+               icd->formats = mt9v022_monochrome_formats;
+               if (mt9v022->client->dev.platform_data)
+                       icd->num_formats = ARRAY_SIZE(mt9v022_monochrome_formats);
+               else
+                       icd->num_formats = 1;
        }
 
        if (ret >= 0)
@@ -701,7 +745,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
        soc_camera_video_stop(&mt9v022->icd);
 }
 
-static int mt9v022_probe(struct i2c_client *client)
+static int mt9v022_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
 {
        struct mt9v022 *mt9v022;
        struct soc_camera_device *icd;
@@ -729,8 +774,6 @@ static int mt9v022_probe(struct i2c_client *client)
        i2c_set_clientdata(client, mt9v022);
 
        icd = &mt9v022->icd;
-       icd->probe      = mt9v022_video_probe;
-       icd->remove     = mt9v022_video_remove;
        icd->ops        = &mt9v022_ops;
        icd->control    = &client->dev;
        icd->x_min      = 1;
@@ -776,12 +819,19 @@ static int mt9v022_remove(struct i2c_client *client)
        return 0;
 }
 
+static const struct i2c_device_id mt9v022_id[] = {
+       { "mt9v022", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v022_id);
+
 static struct i2c_driver mt9v022_i2c_driver = {
        .driver = {
                .name = "mt9v022",
        },
        .probe          = mt9v022_probe,
        .remove         = mt9v022_remove,
+       .id_table       = mt9v022_id,
 };
 
 static int __init mt9v022_mod_init(void)