Commit af8425c5 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] mt9m111: convert to the control framework

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
[g.liakhovetski@gmx.de: simplified pointer arithmetic]
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 2dd7d29c
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/soc_mediabus.h> #include <media/soc_mediabus.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-chip-ident.h> #include <media/v4l2-chip-ident.h>
/* /*
...@@ -178,6 +179,8 @@ enum mt9m111_context { ...@@ -178,6 +179,8 @@ enum mt9m111_context {
struct mt9m111 { struct mt9m111 {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *gain;
int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
* from v4l2-chip-ident.h */ * from v4l2-chip-ident.h */
enum mt9m111_context context; enum mt9m111_context context;
...@@ -186,13 +189,8 @@ struct mt9m111 { ...@@ -186,13 +189,8 @@ struct mt9m111 {
int power_count; int power_count;
const struct mt9m111_datafmt *fmt; const struct mt9m111_datafmt *fmt;
int lastpage; /* PageMap cache value */ int lastpage; /* PageMap cache value */
unsigned int gain;
unsigned char autoexposure;
unsigned char datawidth; unsigned char datawidth;
unsigned int powered:1; unsigned int powered:1;
unsigned int hflip:1;
unsigned int vflip:1;
unsigned int autowhitebalance:1;
}; };
static struct mt9m111 *to_mt9m111(const struct i2c_client *client) static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
...@@ -646,48 +644,6 @@ static int mt9m111_s_register(struct v4l2_subdev *sd, ...@@ -646,48 +644,6 @@ static int mt9m111_s_register(struct v4l2_subdev *sd,
} }
#endif #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 struct soc_camera_ops mt9m111_ops = {
.controls = mt9m111_controls,
.num_controls = ARRAY_SIZE(mt9m111_controls),
};
static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
...@@ -728,7 +684,6 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) ...@@ -728,7 +684,6 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
if (gain > 63 * 2 * 2) if (gain > 63 * 2 * 2)
return -EINVAL; return -EINVAL;
mt9m111->gain = gain;
if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
val = (1 << 10) | (1 << 9) | (gain / 4); val = (1 << 10) | (1 << 9) | (gain / 4);
else if ((gain >= 64) && (gain < 64 * 2)) else if ((gain >= 64) && (gain < 64 * 2))
...@@ -742,118 +697,47 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) ...@@ -742,118 +697,47 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
int ret;
if (on) if (on)
ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
else return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
if (!ret)
mt9m111->autoexposure = on;
return ret;
} }
static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
int ret;
if (on) if (on)
ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
else return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
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)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
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(mt9m111);
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;
}
return 0;
} }
static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
{ {
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); struct mt9m111 *mt9m111 = container_of(ctrl->handler,
const struct v4l2_queryctrl *qctrl; struct mt9m111, hdl);
int ret;
qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id);
if (!qctrl)
return -EINVAL;
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_VFLIP: case V4L2_CID_VFLIP:
mt9m111->vflip = ctrl->value; return mt9m111_set_flip(mt9m111, ctrl->val,
ret = mt9m111_set_flip(mt9m111, ctrl->value,
MT9M111_RMB_MIRROR_ROWS); MT9M111_RMB_MIRROR_ROWS);
break;
case V4L2_CID_HFLIP: case V4L2_CID_HFLIP:
mt9m111->hflip = ctrl->value; return mt9m111_set_flip(mt9m111, ctrl->val,
ret = mt9m111_set_flip(mt9m111, ctrl->value,
MT9M111_RMB_MIRROR_COLS); MT9M111_RMB_MIRROR_COLS);
break;
case V4L2_CID_GAIN: case V4L2_CID_GAIN:
ret = mt9m111_set_global_gain(mt9m111, ctrl->value); return mt9m111_set_global_gain(mt9m111, ctrl->val);
break;
case V4L2_CID_EXPOSURE_AUTO: case V4L2_CID_EXPOSURE_AUTO:
ret = mt9m111_set_autoexposure(mt9m111, ctrl->value); return mt9m111_set_autoexposure(mt9m111, ctrl->val);
break;
case V4L2_CID_AUTO_WHITE_BALANCE: case V4L2_CID_AUTO_WHITE_BALANCE:
ret = mt9m111_set_autowhitebalance(mt9m111, ctrl->value); return mt9m111_set_autowhitebalance(mt9m111, ctrl->val);
break;
default:
ret = -EINVAL;
} }
return ret; return -EINVAL;
} }
static int mt9m111_suspend(struct mt9m111 *mt9m111) static int mt9m111_suspend(struct mt9m111 *mt9m111)
{ {
mt9m111->gain = mt9m111_get_global_gain(mt9m111); v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111));
return 0; return 0;
} }
...@@ -863,11 +747,7 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111) ...@@ -863,11 +747,7 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111)
mt9m111_set_context(mt9m111, mt9m111->context); mt9m111_set_context(mt9m111, mt9m111->context);
mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
mt9m111_setup_rect(mt9m111, &mt9m111->rect); mt9m111_setup_rect(mt9m111, &mt9m111->rect);
mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); v4l2_ctrl_handler_setup(&mt9m111->hdl);
mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
mt9m111_set_global_gain(mt9m111, mt9m111->gain);
mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure);
mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance);
} }
static int mt9m111_resume(struct mt9m111 *mt9m111) static int mt9m111_resume(struct mt9m111 *mt9m111)
...@@ -895,8 +775,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111) ...@@ -895,8 +775,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
ret = mt9m111_reset(mt9m111); ret = mt9m111_reset(mt9m111);
if (!ret) if (!ret)
ret = mt9m111_set_context(mt9m111, mt9m111->context); ret = mt9m111_set_context(mt9m111, mt9m111->context);
if (!ret)
ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure);
if (ret) if (ret)
dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
return ret; return ret;
...@@ -919,9 +797,6 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, ...@@ -919,9 +797,6 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
mt9m111->lastpage = -1; mt9m111->lastpage = -1;
mt9m111->autoexposure = 1;
mt9m111->autowhitebalance = 1;
data = reg_read(CHIP_VERSION); data = reg_read(CHIP_VERSION);
switch (data) { switch (data) {
...@@ -935,17 +810,16 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, ...@@ -935,17 +810,16 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
break; break;
default: default:
ret = -ENODEV;
dev_err(&client->dev, dev_err(&client->dev,
"No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
data); data);
goto ei2c; return -ENODEV;
} }
ret = mt9m111_init(mt9m111); ret = mt9m111_init(mt9m111);
if (ret)
ei2c:
return ret; return ret;
return v4l2_ctrl_handler_setup(&mt9m111->hdl);
} }
static int mt9m111_s_power(struct v4l2_subdev *sd, int on) static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
...@@ -982,9 +856,11 @@ static int mt9m111_s_power(struct v4l2_subdev *sd, int on) ...@@ -982,9 +856,11 @@ static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
return ret; return ret;
} }
static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
.g_ctrl = mt9m111_g_ctrl,
.s_ctrl = mt9m111_s_ctrl, .s_ctrl = mt9m111_s_ctrl,
};
static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
.g_chip_ident = mt9m111_g_chip_ident, .g_chip_ident = mt9m111_g_chip_ident,
.s_power = mt9m111_s_power, .s_power = mt9m111_s_power,
#ifdef CONFIG_VIDEO_ADV_DEBUG #ifdef CONFIG_VIDEO_ADV_DEBUG
...@@ -1066,10 +942,27 @@ static int mt9m111_probe(struct i2c_client *client, ...@@ -1066,10 +942,27 @@ static int mt9m111_probe(struct i2c_client *client,
return -ENOMEM; return -ENOMEM;
v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); 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;
/* Second stage probe - when a capture adapter is there */ kfree(mt9m111);
icd->ops = &mt9m111_ops; return err;
}
/* Second stage probe - when a capture adapter is there */
mt9m111->rect.left = MT9M111_MIN_DARK_COLS; mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
mt9m111->rect.width = MT9M111_MAX_WIDTH; mt9m111->rect.width = MT9M111_MAX_WIDTH;
...@@ -1078,7 +971,7 @@ static int mt9m111_probe(struct i2c_client *client, ...@@ -1078,7 +971,7 @@ static int mt9m111_probe(struct i2c_client *client,
ret = mt9m111_video_probe(icd, client); ret = mt9m111_video_probe(icd, client);
if (ret) { if (ret) {
icd->ops = NULL; v4l2_ctrl_handler_free(&mt9m111->hdl);
kfree(mt9m111); kfree(mt9m111);
} }
...@@ -1088,9 +981,9 @@ static int mt9m111_probe(struct i2c_client *client, ...@@ -1088,9 +981,9 @@ static int mt9m111_probe(struct i2c_client *client,
static int mt9m111_remove(struct i2c_client *client) static int mt9m111_remove(struct i2c_client *client)
{ {
struct mt9m111 *mt9m111 = to_mt9m111(client); struct mt9m111 *mt9m111 = to_mt9m111(client);
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL; v4l2_device_unregister_subdev(&mt9m111->subdev);
v4l2_ctrl_handler_free(&mt9m111->hdl);
kfree(mt9m111); kfree(mt9m111);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment