diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2010-12-12 11:19:16 (GMT) |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-21 23:31:49 (GMT) |
commit | ceed52d67e1cf7866fa96514525c615554a0e44e (patch) | |
tree | 4e3324dbb011f531c393cd1a172009970f8120e7 /drivers/media/video/adv7343.c | |
parent | a75b9be1c2fb52dee765d35f29031dd788d522eb (diff) | |
download | linux-fsl-qoriq-ceed52d67e1cf7866fa96514525c615554a0e44e.tar.xz |
[media] adv7343: use control framework
Also fixed a memory leak in the probe function if an error occurred.
The gain control range was also fixed (a proper range from -64 to 64).
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/adv7343.c')
-rw-r--r-- | drivers/media/video/adv7343.c | 167 |
1 files changed, 61 insertions, 106 deletions
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c index 41b2930..021fab2 100644 --- a/drivers/media/video/adv7343.c +++ b/drivers/media/video/adv7343.c @@ -29,6 +29,7 @@ #include <media/adv7343.h> #include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-ctrls.h> #include "adv7343_regs.h" @@ -41,15 +42,13 @@ MODULE_PARM_DESC(debug, "Debug level 0-1"); struct adv7343_state { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; u8 reg00; u8 reg01; u8 reg02; u8 reg35; u8 reg80; u8 reg82; - int bright; - int hue; - int gain; u32 output; v4l2_std_id std; }; @@ -59,6 +58,11 @@ static inline struct adv7343_state *to_state(struct v4l2_subdev *sd) return container_of(sd, struct adv7343_state, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd; +} + static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -268,111 +272,22 @@ static int adv7343_log_status(struct v4l2_subdev *sd) return 0; } -static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN, - ADV7343_BRIGHTNESS_MAX, 1, - ADV7343_BRIGHTNESS_DEF); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN, - ADV7343_HUE_MAX, 1 , - ADV7343_HUE_DEF); - case V4L2_CID_GAIN: - return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN, - ADV7343_GAIN_MAX, 1, - ADV7343_GAIN_DEF); - default: - break; - } - - return 0; -} - -static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct adv7343_state *state = to_state(sd); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value < ADV7343_BRIGHTNESS_MIN || - ctrl->value > ADV7343_BRIGHTNESS_MAX) { - v4l2_dbg(1, debug, sd, - "invalid brightness settings %d\n", - ctrl->value); - return -ERANGE; - } - - state->bright = ctrl->value; - err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, - state->bright); - break; - - case V4L2_CID_HUE: - if (ctrl->value < ADV7343_HUE_MIN || - ctrl->value > ADV7343_HUE_MAX) { - v4l2_dbg(1, debug, sd, "invalid hue settings %d\n", - ctrl->value); - return -ERANGE; - } - - state->hue = ctrl->value; - err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue); - break; - - case V4L2_CID_GAIN: - if (ctrl->value < ADV7343_GAIN_MIN || - ctrl->value > ADV7343_GAIN_MAX) { - v4l2_dbg(1, debug, sd, "invalid gain settings %d\n", - ctrl->value); - return -ERANGE; - } - - if ((ctrl->value > POSITIVE_GAIN_MAX) && - (ctrl->value < NEGATIVE_GAIN_MIN)) { - v4l2_dbg(1, debug, sd, - "gain settings not within the specified range\n"); - return -ERANGE; - } - - state->gain = ctrl->value; - err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain); - break; - - default: - return -EINVAL; - } - - if (err < 0) - v4l2_err(sd, "Failed to set the encoder controls\n"); - - return err; -} - -static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl) { - struct adv7343_state *state = to_state(sd); + struct v4l2_subdev *sd = to_sd(ctrl); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - ctrl->value = state->bright; - break; + return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, + ctrl->val); case V4L2_CID_HUE: - ctrl->value = state->hue; - break; + return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val); case V4L2_CID_GAIN: - ctrl->value = state->gain; - break; - - default: - return -EINVAL; + return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val); } - - return 0; + return -EINVAL; } static int adv7343_g_chip_ident(struct v4l2_subdev *sd, @@ -383,12 +298,20 @@ static int adv7343_g_chip_ident(struct v4l2_subdev *sd, return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0); } +static const struct v4l2_ctrl_ops adv7343_ctrl_ops = { + .s_ctrl = adv7343_s_ctrl, +}; + static const struct v4l2_subdev_core_ops adv7343_core_ops = { - .log_status = adv7343_log_status, - .g_chip_ident = adv7343_g_chip_ident, - .g_ctrl = adv7343_g_ctrl, - .s_ctrl = adv7343_s_ctrl, - .queryctrl = adv7343_queryctrl, + .log_status = adv7343_log_status, + .g_chip_ident = adv7343_g_chip_ident, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, }; static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) @@ -468,6 +391,7 @@ static int adv7343_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adv7343_state *state; + int err; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; @@ -490,15 +414,46 @@ static int adv7343_probe(struct i2c_client *client, state->std = V4L2_STD_NTSC; v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops); - return adv7343_initialize(&state->sd); + + v4l2_ctrl_handler_init(&state->hdl, 2); + v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, + V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN, + ADV7343_BRIGHTNESS_MAX, 1, + ADV7343_BRIGHTNESS_DEF); + v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, + V4L2_CID_HUE, ADV7343_HUE_MIN, + ADV7343_HUE_MAX, 1, + ADV7343_HUE_DEF); + v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, + V4L2_CID_GAIN, ADV7343_GAIN_MIN, + ADV7343_GAIN_MAX, 1, + ADV7343_GAIN_DEF); + state->sd.ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + v4l2_ctrl_handler_setup(&state->hdl); + + err = adv7343_initialize(&state->sd); + if (err) { + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + } + return err; } static int adv7343_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct adv7343_state *state = to_state(sd); v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); return 0; } |