Signed-off-by: Hans Verkuil <hverk...@xs4all.nl>
---
 drivers/media/video/mt9m111.c |  184 ++++++++++++-----------------------------
 1 files changed, 54 insertions(+), 130 deletions(-)

diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 53fa2a7..2328579 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -16,6 +16,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 #include <media/soc_camera.h>
 
 /*
@@ -165,22 +166,19 @@ enum mt9m111_context {
 
 struct mt9m111 {
        struct v4l2_subdev subdev;
+       struct v4l2_ctrl_handler hdl;
+       struct v4l2_ctrl *gain;
        int model;      /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
                         * from v4l2-chip-ident.h */
        enum mt9m111_context context;
        struct v4l2_rect rect;
        const struct mt9m111_datafmt *fmt;
-       unsigned int gain;
-       unsigned char autoexposure;
        unsigned char datawidth;
        unsigned int powered:1;
-       unsigned int hflip:1;
-       unsigned int vflip:1;
        unsigned int swap_rgb_even_odd:1;
        unsigned int swap_rgb_red_blue:1;
        unsigned int swap_yuv_y_chromas:1;
        unsigned int swap_yuv_cb_cr:1;
-       unsigned int autowhitebalance:1;
 };
 
 static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
@@ -679,43 +677,6 @@ static int mt9m111_s_register(struct v4l2_subdev *sd,
 }
 #endif
 
-static const struct v4l2_queryctrl mt9m111_controls[] = {
-       {
-               .id             = V4L2_CID_VFLIP,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Flip Verticaly",
-               .minimum        = 0,
-               .maximum        = 1,
-               .step           = 1,
-               .default_value  = 0,
-       }, {
-               .id             = V4L2_CID_HFLIP,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Flip Horizontaly",
-               .minimum        = 0,
-               .maximum        = 1,
-               .step           = 1,
-               .default_value  = 0,
-       }, {    /* gain = 1/32*val (=>gain=1 if val==32) */
-               .id             = V4L2_CID_GAIN,
-               .type           = V4L2_CTRL_TYPE_INTEGER,
-               .name           = "Gain",
-               .minimum        = 0,
-               .maximum        = 63 * 2 * 2,
-               .step           = 1,
-               .default_value  = 32,
-               .flags          = V4L2_CTRL_FLAG_SLIDER,
-       }, {
-               .id             = V4L2_CID_EXPOSURE_AUTO,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Auto Exposure",
-               .minimum        = 0,
-               .maximum        = 1,
-               .step           = 1,
-               .default_value  = 1,
-       }
-};
-
 static int mt9m111_resume(struct soc_camera_device *icd);
 static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state);
 
@@ -724,8 +685,6 @@ static struct soc_camera_ops mt9m111_ops = {
        .resume                 = mt9m111_resume,
        .query_bus_param        = mt9m111_query_bus_param,
        .set_bus_param          = mt9m111_set_bus_param,
-       .controls               = mt9m111_controls,
-       .num_controls           = ARRAY_SIZE(mt9m111_controls),
 };
 
 static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask)
@@ -761,13 +720,11 @@ static int mt9m111_get_global_gain(struct i2c_client 
*client)
 
 static int mt9m111_set_global_gain(struct i2c_client *client, int gain)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
        u16 val;
 
        if (gain > 63 * 2 * 2)
                return -EINVAL;
 
-       mt9m111->gain = gain;
        if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
                val = (1 << 10) | (1 << 9) | (gain / 4);
        else if ((gain >= 64) && (gain < 64 * 2))
@@ -780,115 +737,67 @@ static int mt9m111_set_global_gain(struct i2c_client 
*client, int gain)
 
 static int mt9m111_set_autoexposure(struct i2c_client *client, int on)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
        int ret;
 
        if (on)
                ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
        else
                ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
-
-       if (!ret)
-               mt9m111->autoexposure = on;
-
        return ret;
 }
 
 static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
        int ret;
 
        if (on)
                ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
        else
                ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
-
-       if (!ret)
-               mt9m111->autowhitebalance = on;
-
        return ret;
 }
 
-static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int mt9m111_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
+       struct v4l2_subdev *sd =
+               &container_of(ctrl->handler, struct mt9m111, hdl)->subdev;
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
        int data;
 
        switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               if (mt9m111->context == HIGHPOWER)
-                       data = reg_read(READ_MODE_B);
-               else
-                       data = reg_read(READ_MODE_A);
-
-               if (data < 0)
-                       return -EIO;
-               ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS);
-               break;
-       case V4L2_CID_HFLIP:
-               if (mt9m111->context == HIGHPOWER)
-                       data = reg_read(READ_MODE_B);
-               else
-                       data = reg_read(READ_MODE_A);
-
-               if (data < 0)
-                       return -EIO;
-               ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS);
-               break;
        case V4L2_CID_GAIN:
                data = mt9m111_get_global_gain(client);
                if (data < 0)
                        return data;
-               ctrl->value = data;
-               break;
-       case V4L2_CID_EXPOSURE_AUTO:
-               ctrl->value = mt9m111->autoexposure;
-               break;
-       case V4L2_CID_AUTO_WHITE_BALANCE:
-               ctrl->value = mt9m111->autowhitebalance;
-               break;
+               ctrl->cur.val = data;
+               return 0;
        }
-       return 0;
+       return -EINVAL;
 }
 
-static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+       struct v4l2_subdev *sd =
+               &container_of(ctrl->handler, struct mt9m111, hdl)->subdev;
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-       const struct v4l2_queryctrl *qctrl;
-       int ret;
-
-       qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id);
-       if (!qctrl)
-               return -EINVAL;
 
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
-               mt9m111->vflip = ctrl->value;
-               ret = mt9m111_set_flip(client, ctrl->value,
+               return mt9m111_set_flip(client, ctrl->val,
                                        MT9M111_RMB_MIRROR_ROWS);
-               break;
        case V4L2_CID_HFLIP:
-               mt9m111->hflip = ctrl->value;
-               ret = mt9m111_set_flip(client, ctrl->value,
+               return mt9m111_set_flip(client, ctrl->val,
                                        MT9M111_RMB_MIRROR_COLS);
-               break;
        case V4L2_CID_GAIN:
-               ret = mt9m111_set_global_gain(client, ctrl->value);
-               break;
+               return mt9m111_set_global_gain(client, ctrl->val);
+
        case V4L2_CID_EXPOSURE_AUTO:
-               ret =  mt9m111_set_autoexposure(client, ctrl->value);
-               break;
+               return mt9m111_set_autoexposure(client, ctrl->val);
+
        case V4L2_CID_AUTO_WHITE_BALANCE:
-               ret =  mt9m111_set_autowhitebalance(client, ctrl->value);
-               break;
-       default:
-               ret = -EINVAL;
+               return mt9m111_set_autowhitebalance(client, ctrl->val);
        }
-
-       return ret;
+       return -EINVAL;
 }
 
 static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state)
@@ -896,8 +805,7 @@ static int mt9m111_suspend(struct soc_camera_device *icd, 
pm_message_t state)
        struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
        struct mt9m111 *mt9m111 = to_mt9m111(client);
 
-       mt9m111->gain = mt9m111_get_global_gain(client);
-
+       v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(client));
        return 0;
 }
 
@@ -908,11 +816,7 @@ static int mt9m111_restore_state(struct i2c_client *client)
        mt9m111_set_context(client, mt9m111->context);
        mt9m111_set_pixfmt(client, mt9m111->fmt->code);
        mt9m111_setup_rect(client, &mt9m111->rect);
-       mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
-       mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
-       mt9m111_set_global_gain(client, mt9m111->gain);
-       mt9m111_set_autoexposure(client, mt9m111->autoexposure);
-       mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance);
+       v4l2_ctrl_handler_setup(&mt9m111->hdl);
        return 0;
 }
 
@@ -943,8 +847,6 @@ static int mt9m111_init(struct i2c_client *client)
                ret = mt9m111_reset(client);
        if (!ret)
                ret = mt9m111_set_context(client, mt9m111->context);
-       if (!ret)
-               ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure);
        if (ret)
                dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
        return ret;
@@ -969,9 +871,6 @@ static int mt9m111_video_probe(struct soc_camera_device 
*icd,
            to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
                return -ENODEV;
 
-       mt9m111->autoexposure = 1;
-       mt9m111->autowhitebalance = 1;
-
        mt9m111->swap_rgb_even_odd = 1;
        mt9m111->swap_rgb_red_blue = 1;
 
@@ -988,22 +887,24 @@ static int mt9m111_video_probe(struct soc_camera_device 
*icd,
                dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
                break;
        default:
-               ret = -ENODEV;
                dev_err(&client->dev,
                        "No MT9M111/MT9M112/MT9M131 chip detected register read 
%x\n",
                        data);
-               goto ei2c;
+               return -ENODEV;
        }
 
        ret = mt9m111_init(client);
-
-ei2c:
-       return ret;
+       if (ret)
+               return ret;
+       return v4l2_ctrl_handler_setup(&mt9m111->hdl);
 }
 
+static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
+       .g_volatile_ctrl = mt9m111_g_volatile_ctrl,
+       .s_ctrl = mt9m111_s_ctrl,
+};
+
 static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
-       .g_ctrl         = mt9m111_g_ctrl,
-       .s_ctrl         = mt9m111_s_ctrl,
        .g_chip_ident   = mt9m111_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9m111_g_register,
@@ -1067,6 +968,26 @@ static int mt9m111_probe(struct i2c_client *client,
                return -ENOMEM;
 
        v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
+       v4l2_ctrl_handler_init(&mt9m111->hdl, 5);
+       v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+                       V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+       mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+                       V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32);
+       v4l2_ctrl_new_std_menu(&mt9m111->hdl,
+                       &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+                       V4L2_EXPOSURE_AUTO);
+       mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
+       if (mt9m111->hdl.error) {
+               int err = mt9m111->hdl.error;
+
+               kfree(mt9m111);
+               return err;
+       }
+       mt9m111->gain->is_volatile = 1;
 
        /* Second stage probe - when a capture adapter is there */
        icd->ops                = &mt9m111_ops;
@@ -1080,6 +1001,7 @@ static int mt9m111_probe(struct i2c_client *client,
        ret = mt9m111_video_probe(icd, client);
        if (ret) {
                icd->ops = NULL;
+               v4l2_ctrl_handler_free(&mt9m111->hdl);
                kfree(mt9m111);
        }
 
@@ -1091,7 +1013,9 @@ static int mt9m111_remove(struct i2c_client *client)
        struct mt9m111 *mt9m111 = to_mt9m111(client);
        struct soc_camera_device *icd = client->dev.platform_data;
 
+       v4l2_device_unregister_subdev(&mt9m111->subdev);
        icd->ops = NULL;
+       v4l2_ctrl_handler_free(&mt9m111->hdl);
        kfree(mt9m111);
 
        return 0;
-- 
1.7.0.4

--
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