[media] mt9v032: Provide link frequency control
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Thu, 26 Jul 2012 11:02:50 +0000 (08:02 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 13 Sep 2012 19:29:07 +0000 (16:29 -0300)
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/i2c/mt9v032.c
include/media/mt9v032.h

index 2203a6f..bf591b8 100644 (file)
@@ -29,6 +29,8 @@
 #define MT9V032_PIXEL_ARRAY_HEIGHT                     492
 #define MT9V032_PIXEL_ARRAY_WIDTH                      782
 
+#define MT9V032_SYSCLK_FREQ_DEF                                26600000
+
 #define MT9V032_CHIP_VERSION                           0x00
 #define                MT9V032_CHIP_ID_REV1                    0x1311
 #define                MT9V032_CHIP_ID_REV3                    0x1313
@@ -122,13 +124,18 @@ struct mt9v032 {
        struct v4l2_mbus_framefmt format;
        struct v4l2_rect crop;
 
-       struct v4l2_ctrl *pixel_rate;
        struct v4l2_ctrl_handler ctrls;
+       struct {
+               struct v4l2_ctrl *link_freq;
+               struct v4l2_ctrl *pixel_rate;
+       };
 
        struct mutex power_lock;
        int power_count;
 
        struct mt9v032_platform_data *pdata;
+
+       u32 sysclk;
        u16 chip_control;
        u16 aec_agc;
 };
@@ -196,7 +203,7 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
        int ret;
 
        if (mt9v032->pdata->set_clock) {
-               mt9v032->pdata->set_clock(&mt9v032->subdev, EXT_CLK);
+               mt9v032->pdata->set_clock(&mt9v032->subdev, mt9v032->sysclk);
                udelay(1);
        }
 
@@ -374,7 +381,8 @@ static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032,
        struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
        int ret;
 
-       ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate, EXT_CLK / hratio);
+       ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate,
+                                    mt9v032->sysclk / hratio);
        if (ret < 0)
                dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret);
 }
@@ -487,6 +495,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
        struct mt9v032 *mt9v032 =
                        container_of(ctrl->handler, struct mt9v032, ctrls);
        struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+       u32 freq;
        u16 data;
 
        switch (ctrl->id) {
@@ -505,6 +514,16 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
                return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
                                     ctrl->val);
 
+       case V4L2_CID_PIXEL_RATE:
+       case V4L2_CID_LINK_FREQ:
+               if (mt9v032->link_freq == NULL)
+                       break;
+
+               freq = mt9v032->pdata->link_freqs[mt9v032->link_freq->val];
+               mt9v032->pixel_rate->val64 = freq;
+               mt9v032->sysclk = freq;
+               break;
+
        case V4L2_CID_TEST_PATTERN:
                switch (ctrl->val) {
                case 0:
@@ -683,6 +702,7 @@ static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
 static int mt9v032_probe(struct i2c_client *client,
                const struct i2c_device_id *did)
 {
+       struct mt9v032_platform_data *pdata = client->dev.platform_data;
        struct mt9v032 *mt9v032;
        unsigned int i;
        int ret;
@@ -699,9 +719,9 @@ static int mt9v032_probe(struct i2c_client *client,
                return -ENOMEM;
 
        mutex_init(&mt9v032->power_lock);
-       mt9v032->pdata = client->dev.platform_data;
+       mt9v032->pdata = pdata;
 
-       v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 5);
+       v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 6);
 
        v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
                          V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
@@ -715,10 +735,27 @@ static int mt9v032_probe(struct i2c_client *client,
                          V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
                          MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1,
                          MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
+
        mt9v032->pixel_rate =
                v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
                                  V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
 
+       if (pdata && pdata->link_freqs) {
+               unsigned int def = 0;
+
+               for (i = 0; pdata->link_freqs[i]; ++i) {
+                       if (pdata->link_freqs[i] == pdata->link_def_freq)
+                               def = i;
+               }
+
+               mt9v032->link_freq =
+                       v4l2_ctrl_new_int_menu(&mt9v032->ctrls,
+                                              &mt9v032_ctrl_ops,
+                                              V4L2_CID_LINK_FREQ, i - 1, def,
+                                              pdata->link_freqs);
+               v4l2_ctrl_cluster(2, &mt9v032->link_freq);
+       }
+
        for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i)
                v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL);
 
@@ -740,6 +777,7 @@ static int mt9v032_probe(struct i2c_client *client,
        mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
 
        mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
+       mt9v032->sysclk = MT9V032_SYSCLK_FREQ_DEF;
 
        v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops);
        mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops;
index 5e27f9b..78fd39e 100644 (file)
@@ -7,6 +7,9 @@ struct mt9v032_platform_data {
        unsigned int clk_pol:1;
 
        void (*set_clock)(struct v4l2_subdev *subdev, unsigned int rate);
+
+       const s64 *link_freqs;
+       s64 link_def_freq;
 };
 
 #endif