All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/21] Control framework conversions
@ 2013-05-31 10:02 Hans Verkuil
  2013-05-31 10:02 ` [PATCH 01/21] saa7706h: convert to the control framework Hans Verkuil
                   ` (20 more replies)
  0 siblings, 21 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media

This continues my ongoing work to convert drivers to the control framework.

These conversions touch upon rarely used drivers. The only one I could
actually test was the saa6752hs conversion. All others are untested because
I do not have the hardware.

Ondrej, I know you have a radio-sf16fmi board. I'd appreciate it if you could
test these patches for me. If you could run v4l2-compliance, then that would
be great.

I don't believe anyone has a working timberdale environment or a tea5764 setup.
If you do, and you are willing to test, then let me know. Otherwise those
changes will go in untested.

Regards,

	Hans


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/21] saa7706h: convert to the control framework.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 02/21] sr030pc30: " Hans Verkuil
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Richard Röjfors

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Richard Röjfors <richard.rojfors@pelagicore.com>
---
 drivers/media/radio/saa7706h.c |   58 +++++++++++++++++++++-------------------
 1 file changed, 30 insertions(+), 28 deletions(-)

diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c
index 06c06cc..1f09844 100644
--- a/drivers/media/radio/saa7706h.c
+++ b/drivers/media/radio/saa7706h.c
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 #define DRIVER_NAME "saa7706h"
 
@@ -127,6 +128,7 @@
 
 struct saa7706h_state {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
 	unsigned muted;
 };
 
@@ -317,34 +319,16 @@ static int saa7706h_mute(struct v4l2_subdev *sd)
 	return err;
 }
 
-static int saa7706h_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+static int saa7706h_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	}
-	return -EINVAL;
-}
-
-static int saa7706h_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct saa7706h_state *state = to_state(sd);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = state->muted;
-		return 0;
-	}
-	return -EINVAL;
-}
+	struct saa7706h_state *state =
+		container_of(ctrl->handler, struct saa7706h_state, hdl);
 
-static int saa7706h_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
-			return saa7706h_mute(sd);
-		return saa7706h_unmute(sd);
+		if (ctrl->val)
+			return saa7706h_mute(&state->sd);
+		return saa7706h_unmute(&state->sd);
 	}
 	return -EINVAL;
 }
@@ -357,11 +341,19 @@ static int saa7706h_g_chip_ident(struct v4l2_subdev *sd,
 	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7706H, 0);
 }
 
+static const struct v4l2_ctrl_ops saa7706h_ctrl_ops = {
+	.s_ctrl = saa7706h_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops saa7706h_core_ops = {
 	.g_chip_ident = saa7706h_g_chip_ident,
-	.queryctrl = saa7706h_queryctrl,
-	.g_ctrl = saa7706h_g_ctrl,
-	.s_ctrl = saa7706h_s_ctrl,
+	.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 const struct v4l2_subdev_ops saa7706h_ops = {
@@ -393,13 +385,20 @@ static int saa7706h_probe(struct i2c_client *client,
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &saa7706h_ops);
 
+	v4l2_ctrl_handler_init(&state->hdl, 4);
+	v4l2_ctrl_new_std(&state->hdl, &saa7706h_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	sd->ctrl_handler = &state->hdl;
+	err = state->hdl.error;
+	if (err)
+		goto err;
+
 	/* check the rom versions */
 	err = saa7706h_get_reg16(sd, SAA7706H_DSP1_ROM_VER);
 	if (err < 0)
 		goto err;
 	if (err != SUPPORTED_DSP1_ROM_VER)
 		v4l2_warn(sd, "Unknown DSP1 ROM code version: 0x%x\n", err);
-
 	state->muted = 1;
 
 	/* startup in a muted state */
@@ -411,6 +410,7 @@ static int saa7706h_probe(struct i2c_client *client,
 
 err:
 	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
 	kfree(to_state(sd));
 
 	printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", err);
@@ -421,9 +421,11 @@ err:
 static int saa7706h_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct saa7706h_state *state = to_state(sd);
 
 	saa7706h_mute(sd);
 	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
 	kfree(to_state(sd));
 	return 0;
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 02/21] sr030pc30: convert to the control framework.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
  2013-05-31 10:02 ` [PATCH 01/21] saa7706h: convert to the control framework Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:38   ` Sylwester Nawrocki
  2013-05-31 10:02 ` [PATCH 03/21] saa6752hs: " Hans Verkuil
                   ` (18 subsequent siblings)
  20 siblings, 1 reply; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Sylwester Nawrocki

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
---
 drivers/media/i2c/sr030pc30.c |  276 +++++++++++++----------------------------
 1 file changed, 88 insertions(+), 188 deletions(-)

diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index 4c5a9ee..ae94326 100644
--- a/drivers/media/i2c/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
@@ -23,6 +23,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-mediabus.h>
+#include <media/v4l2-ctrls.h>
 #include <media/sr030pc30.h>
 
 static int debug;
@@ -142,17 +143,24 @@ module_param(debug, int, 0644);
 
 struct sr030pc30_info {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
 	const struct sr030pc30_platform_data *pdata;
 	const struct sr030pc30_format *curr_fmt;
 	const struct sr030pc30_frmsize *curr_win;
-	unsigned int auto_wb:1;
-	unsigned int auto_exp:1;
 	unsigned int hflip:1;
 	unsigned int vflip:1;
 	unsigned int sleep:1;
-	unsigned int exposure;
-	u8 blue_balance;
-	u8 red_balance;
+	struct {
+		/* auto whitebalance control cluster */
+		struct v4l2_ctrl *awb;
+		struct v4l2_ctrl *red;
+		struct v4l2_ctrl *blue;
+	};
+	struct {
+		/* auto exposure control cluster */
+		struct v4l2_ctrl *autoexp;
+		struct v4l2_ctrl *exp;
+	};
 	u8 i2c_reg_page;
 };
 
@@ -173,52 +181,6 @@ struct i2c_regval {
 	u16 val;
 };
 
-static const struct v4l2_queryctrl sr030pc30_ctrl[] = {
-	{
-		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
-		.type		= V4L2_CTRL_TYPE_BOOLEAN,
-		.name		= "Auto White Balance",
-		.minimum	= 0,
-		.maximum	= 1,
-		.step		= 1,
-		.default_value	= 1,
-	}, {
-		.id		= V4L2_CID_RED_BALANCE,
-		.type		= V4L2_CTRL_TYPE_INTEGER,
-		.name		= "Red Balance",
-		.minimum	= 0,
-		.maximum	= 127,
-		.step		= 1,
-		.default_value	= 64,
-		.flags		= 0,
-	}, {
-		.id		= V4L2_CID_BLUE_BALANCE,
-		.type		= V4L2_CTRL_TYPE_INTEGER,
-		.name		= "Blue Balance",
-		.minimum	= 0,
-		.maximum	= 127,
-		.step		= 1,
-		.default_value	= 64,
-	}, {
-		.id		= V4L2_CID_EXPOSURE_AUTO,
-		.type		= V4L2_CTRL_TYPE_INTEGER,
-		.name		= "Auto Exposure",
-		.minimum	= 0,
-		.maximum	= 1,
-		.step		= 1,
-		.default_value	= 1,
-	}, {
-		.id		= V4L2_CID_EXPOSURE,
-		.type		= V4L2_CTRL_TYPE_INTEGER,
-		.name		= "Exposure",
-		.minimum	= EXPOS_MIN_MS,
-		.maximum	= EXPOS_MAX_MS,
-		.step		= 1,
-		.default_value	= 1,
-	}, {
-	}
-};
-
 /* supported resolutions */
 static const struct sr030pc30_frmsize sr030pc30_sizes[] = {
 	{
@@ -394,48 +356,6 @@ static int sr030pc30_pwr_ctrl(struct v4l2_subdev *sd,
 	return ret;
 }
 
-static inline int sr030pc30_enable_autoexposure(struct v4l2_subdev *sd, int on)
-{
-	struct sr030pc30_info *info = to_sr030pc30(sd);
-	/* auto anti-flicker is also enabled here */
-	int ret = cam_i2c_write(sd, AE_CTL1_REG, on ? 0xDC : 0x0C);
-	if (!ret)
-		info->auto_exp = on;
-	return ret;
-}
-
-static int sr030pc30_set_exposure(struct v4l2_subdev *sd, int value)
-{
-	struct sr030pc30_info *info = to_sr030pc30(sd);
-
-	unsigned long expos = value * info->pdata->clk_rate / (8 * 1000);
-
-	int ret = cam_i2c_write(sd, EXP_TIMEH_REG, expos >> 16 & 0xFF);
-	if (!ret)
-		ret = cam_i2c_write(sd, EXP_TIMEM_REG, expos >> 8 & 0xFF);
-	if (!ret)
-		ret = cam_i2c_write(sd, EXP_TIMEL_REG, expos & 0xFF);
-	if (!ret) { /* Turn off AE */
-		info->exposure = value;
-		ret = sr030pc30_enable_autoexposure(sd, 0);
-	}
-	return ret;
-}
-
-/* Automatic white balance control */
-static int sr030pc30_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
-{
-	struct sr030pc30_info *info = to_sr030pc30(sd);
-
-	int ret = cam_i2c_write(sd, AWB_CTL2_REG, on ? 0x2E : 0x2F);
-	if (!ret)
-		ret = cam_i2c_write(sd, AWB_CTL1_REG, on ? 0xFB : 0x7B);
-	if (!ret)
-		info->auto_wb = on;
-
-	return ret;
-}
-
 static int sr030pc30_set_flip(struct v4l2_subdev *sd)
 {
 	struct sr030pc30_info *info = to_sr030pc30(sd);
@@ -498,107 +418,56 @@ static int sr030pc30_try_frame_size(struct v4l2_mbus_framefmt *mf)
 	return -EINVAL;
 }
 
-static int sr030pc30_queryctrl(struct v4l2_subdev *sd,
-			       struct v4l2_queryctrl *qc)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
-		if (qc->id == sr030pc30_ctrl[i].id) {
-			*qc = sr030pc30_ctrl[i];
-			v4l2_dbg(1, debug, sd, "%s id: %d\n",
-				 __func__, qc->id);
-			return 0;
-		}
-
-	return -EINVAL;
-}
-
-static inline int sr030pc30_set_bluebalance(struct v4l2_subdev *sd, int value)
-{
-	int ret = cam_i2c_write(sd, MWB_BGAIN_REG, value);
-	if (!ret)
-		to_sr030pc30(sd)->blue_balance = value;
-	return ret;
-}
-
-static inline int sr030pc30_set_redbalance(struct v4l2_subdev *sd, int value)
-{
-	int ret = cam_i2c_write(sd, MWB_RGAIN_REG, value);
-	if (!ret)
-		to_sr030pc30(sd)->red_balance = value;
-	return ret;
-}
-
-static int sr030pc30_s_ctrl(struct v4l2_subdev *sd,
-			    struct v4l2_control *ctrl)
+static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	int i, ret = 0;
-
-	for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
-		if (ctrl->id == sr030pc30_ctrl[i].id)
-			break;
-
-	if (i == ARRAY_SIZE(sr030pc30_ctrl))
-		return -EINVAL;
-
-	if (ctrl->value < sr030pc30_ctrl[i].minimum ||
-		ctrl->value > sr030pc30_ctrl[i].maximum)
-			return -ERANGE;
+	struct sr030pc30_info *info =
+		container_of(ctrl->handler, struct sr030pc30_info, hdl);
+	struct v4l2_subdev *sd = &info->sd;
+	int ret = 0;
 
 	v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
-			 __func__, ctrl->id, ctrl->value);
+			 __func__, ctrl->id, ctrl->val);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUTO_WHITE_BALANCE:
-		sr030pc30_enable_autowhitebalance(sd, ctrl->value);
-		break;
-	case V4L2_CID_BLUE_BALANCE:
-		ret = sr030pc30_set_bluebalance(sd, ctrl->value);
-		break;
-	case V4L2_CID_RED_BALANCE:
-		ret = sr030pc30_set_redbalance(sd, ctrl->value);
-		break;
-	case V4L2_CID_EXPOSURE_AUTO:
-		sr030pc30_enable_autoexposure(sd,
-			ctrl->value == V4L2_EXPOSURE_AUTO);
-		break;
-	case V4L2_CID_EXPOSURE:
-		ret = sr030pc30_set_exposure(sd, ctrl->value);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-static int sr030pc30_g_ctrl(struct v4l2_subdev *sd,
-			    struct v4l2_control *ctrl)
-{
-	struct sr030pc30_info *info = to_sr030pc30(sd);
-
-	v4l2_dbg(1, debug, sd, "%s: id: %d\n", __func__, ctrl->id);
+		if (ctrl->is_new) {
+			ret = cam_i2c_write(sd, AWB_CTL2_REG,
+					ctrl->val ? 0x2E : 0x2F);
+			if (!ret)
+				ret = cam_i2c_write(sd, AWB_CTL1_REG,
+						ctrl->val ? 0xFB : 0x7B);
+		}
+		if (!ret && info->blue->is_new)
+			ret = cam_i2c_write(sd, MWB_BGAIN_REG, info->blue->val);
+		if (!ret && info->red->is_new)
+			ret = cam_i2c_write(sd, MWB_RGAIN_REG, info->red->val);
+		return ret;
 
-	switch (ctrl->id) {
-	case V4L2_CID_AUTO_WHITE_BALANCE:
-		ctrl->value = info->auto_wb;
-		break;
-	case V4L2_CID_BLUE_BALANCE:
-		ctrl->value = info->blue_balance;
-		break;
-	case V4L2_CID_RED_BALANCE:
-		ctrl->value = info->red_balance;
-		break;
 	case V4L2_CID_EXPOSURE_AUTO:
-		ctrl->value = info->auto_exp;
-		break;
-	case V4L2_CID_EXPOSURE:
-		ctrl->value = info->exposure;
-		break;
+		/* auto anti-flicker is also enabled here */
+		if (ctrl->is_new)
+			ret = cam_i2c_write(sd, AE_CTL1_REG,
+				ctrl->val == V4L2_EXPOSURE_AUTO ? 0xDC : 0x0C);
+		if (info->exp->is_new) {
+			unsigned long expos = info->exp->val;
+
+			expos = expos * info->pdata->clk_rate / (8 * 1000);
+
+			if (!ret)
+				ret = cam_i2c_write(sd, EXP_TIMEH_REG,
+						expos >> 16 & 0xFF);
+			if (!ret)
+				ret = cam_i2c_write(sd, EXP_TIMEM_REG,
+						expos >> 8 & 0xFF);
+			if (!ret)
+				ret = cam_i2c_write(sd, EXP_TIMEL_REG,
+						expos & 0xFF);
+		}
+		return ret;
 	default:
 		return -EINVAL;
 	}
+
 	return 0;
 }
 
@@ -752,11 +621,19 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
 	return ret;
 }
 
+static const struct v4l2_ctrl_ops sr030pc30_ctrl_ops = {
+	.s_ctrl = sr030pc30_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
 	.s_power	= sr030pc30_s_power,
-	.queryctrl	= sr030pc30_queryctrl,
-	.s_ctrl		= sr030pc30_s_ctrl,
-	.g_ctrl		= sr030pc30_g_ctrl,
+	.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 const struct v4l2_subdev_video_ops sr030pc30_video_ops = {
@@ -807,6 +684,7 @@ static int sr030pc30_probe(struct i2c_client *client,
 {
 	struct sr030pc30_info *info;
 	struct v4l2_subdev *sd;
+	struct v4l2_ctrl_handler *hdl;
 	const struct sr030pc30_platform_data *pdata
 		= client->dev.platform_data;
 	int ret;
@@ -830,10 +708,31 @@ static int sr030pc30_probe(struct i2c_client *client,
 
 	v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops);
 
+	hdl = &info->hdl;
+	v4l2_ctrl_handler_init(hdl, 6);
+	info->awb = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+			V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+	info->red = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+			V4L2_CID_RED_BALANCE, 0, 127, 1, 64);
+	info->blue = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+			V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64);
+	info->autoexp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+			V4L2_CID_EXPOSURE_AUTO, 0, 1, 1, 1);
+	info->exp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+			V4L2_CID_EXPOSURE, EXPOS_MIN_MS, EXPOS_MAX_MS, 1, 30);
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		int err = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		return err;
+	}
+	v4l2_ctrl_auto_cluster(3, &info->awb, 0, false);
+	v4l2_ctrl_auto_cluster(2, &info->autoexp, V4L2_EXPOSURE_MANUAL, false);
+	v4l2_ctrl_handler_setup(hdl);
+
 	info->i2c_reg_page	= -1;
 	info->hflip		= 1;
-	info->auto_exp		= 1;
-	info->exposure		= 30;
 
 	return 0;
 }
@@ -843,6 +742,7 @@ static int sr030pc30_remove(struct i2c_client *client)
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
 	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
 	return 0;
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 03/21] saa6752hs: convert to the control framework.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
  2013-05-31 10:02 ` [PATCH 01/21] saa7706h: convert to the control framework Hans Verkuil
  2013-05-31 10:02 ` [PATCH 02/21] sr030pc30: " Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 04/21] radio-tea5764: add support for struct v4l2_device Hans Verkuil
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/pci/saa7134/saa6752hs.c |  457 +++++++++------------------------
 1 file changed, 122 insertions(+), 335 deletions(-)

diff --git a/drivers/media/pci/saa7134/saa6752hs.c b/drivers/media/pci/saa7134/saa6752hs.c
index f147b05..5813ce8 100644
--- a/drivers/media/pci/saa7134/saa6752hs.c
+++ b/drivers/media/pci/saa7134/saa6752hs.c
@@ -34,6 +34,7 @@
 #include <linux/types.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
 #include <linux/init.h>
@@ -92,6 +93,12 @@ static const struct v4l2_format v4l2_format_table[] =
 
 struct saa6752hs_state {
 	struct v4l2_subdev            sd;
+	struct v4l2_ctrl_handler      hdl;
+	struct { /* video bitrate mode control cluster */
+		struct v4l2_ctrl *video_bitrate_mode;
+		struct v4l2_ctrl *video_bitrate;
+		struct v4l2_ctrl *video_bitrate_peak;
+	};
 	int 			      chip;
 	u32 			      revision;
 	int 			      has_ac3;
@@ -362,316 +369,72 @@ static int saa6752hs_set_bitrate(struct i2c_client *client,
 	return 0;
 }
 
-
-static int get_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
-		struct v4l2_ext_control *ctrl)
+static int saa6752hs_try_ctrl(struct v4l2_ctrl *ctrl)
 {
+	struct saa6752hs_state *h =
+		container_of(ctrl->handler, struct saa6752hs_state, hdl);
+
 	switch (ctrl->id) {
-	case V4L2_CID_MPEG_STREAM_TYPE:
-		ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
-		break;
-	case V4L2_CID_MPEG_STREAM_PID_PMT:
-		ctrl->value = params->ts_pid_pmt;
-		break;
-	case V4L2_CID_MPEG_STREAM_PID_AUDIO:
-		ctrl->value = params->ts_pid_audio;
-		break;
-	case V4L2_CID_MPEG_STREAM_PID_VIDEO:
-		ctrl->value = params->ts_pid_video;
-		break;
-	case V4L2_CID_MPEG_STREAM_PID_PCR:
-		ctrl->value = params->ts_pid_pcr;
-		break;
-	case V4L2_CID_MPEG_AUDIO_ENCODING:
-		ctrl->value = params->au_encoding;
-		break;
-	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-		ctrl->value = params->au_l2_bitrate;
-		break;
-	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-		if (!has_ac3)
-			return -EINVAL;
-		ctrl->value = params->au_ac3_bitrate;
-		break;
-	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-		ctrl->value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
-		break;
-	case V4L2_CID_MPEG_VIDEO_ENCODING:
-		ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
-		break;
-	case V4L2_CID_MPEG_VIDEO_ASPECT:
-		ctrl->value = params->vi_aspect;
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE:
-		ctrl->value = params->vi_bitrate * 1000;
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-		ctrl->value = params->vi_bitrate_peak * 1000;
-		break;
 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-		ctrl->value = params->vi_bitrate_mode;
+		/* peak bitrate shall be >= normal bitrate */
+		if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+		    h->video_bitrate_peak->val < h->video_bitrate->val)
+			h->video_bitrate_peak->val = h->video_bitrate->val;
 		break;
-	default:
-		return -EINVAL;
 	}
 	return 0;
 }
 
-static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
-		struct v4l2_ext_control *ctrl, int set)
+static int saa6752hs_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	int old = 0, new;
+	struct saa6752hs_state *h =
+		container_of(ctrl->handler, struct saa6752hs_state, hdl);
+	struct saa6752hs_mpeg_params *params = &h->params;
 
-	new = ctrl->value;
 	switch (ctrl->id) {
 	case V4L2_CID_MPEG_STREAM_TYPE:
-		old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
-		if (set && new != old)
-			return -ERANGE;
-		new = old;
 		break;
 	case V4L2_CID_MPEG_STREAM_PID_PMT:
-		old = params->ts_pid_pmt;
-		if (set && new > MPEG_PID_MAX)
-			return -ERANGE;
-		if (new > MPEG_PID_MAX)
-			new = MPEG_PID_MAX;
-		params->ts_pid_pmt = new;
+		params->ts_pid_pmt = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_STREAM_PID_AUDIO:
-		old = params->ts_pid_audio;
-		if (set && new > MPEG_PID_MAX)
-			return -ERANGE;
-		if (new > MPEG_PID_MAX)
-			new = MPEG_PID_MAX;
-		params->ts_pid_audio = new;
+		params->ts_pid_audio = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_STREAM_PID_VIDEO:
-		old = params->ts_pid_video;
-		if (set && new > MPEG_PID_MAX)
-			return -ERANGE;
-		if (new > MPEG_PID_MAX)
-			new = MPEG_PID_MAX;
-		params->ts_pid_video = new;
+		params->ts_pid_video = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_STREAM_PID_PCR:
-		old = params->ts_pid_pcr;
-		if (set && new > MPEG_PID_MAX)
-			return -ERANGE;
-		if (new > MPEG_PID_MAX)
-			new = MPEG_PID_MAX;
-		params->ts_pid_pcr = new;
+		params->ts_pid_pcr = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_AUDIO_ENCODING:
-		old = params->au_encoding;
-		if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
-		    (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
-			return -ERANGE;
-		params->au_encoding = new;
+		params->au_encoding = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-		old = params->au_l2_bitrate;
-		if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
-			   new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
-			return -ERANGE;
-		if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
-			new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
-		else
-			new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
-		params->au_l2_bitrate = new;
+		params->au_l2_bitrate = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-		if (!has_ac3)
-			return -EINVAL;
-		old = params->au_ac3_bitrate;
-		if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
-			   new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
-			return -ERANGE;
-		if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
-			new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
-		else
-			new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
-		params->au_ac3_bitrate = new;
+		params->au_ac3_bitrate = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-		old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
-		if (set && new != old)
-			return -ERANGE;
-		new = old;
 		break;
 	case V4L2_CID_MPEG_VIDEO_ENCODING:
-		old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
-		if (set && new != old)
-			return -ERANGE;
-		new = old;
 		break;
 	case V4L2_CID_MPEG_VIDEO_ASPECT:
-		old = params->vi_aspect;
-		if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
-			   new != V4L2_MPEG_VIDEO_ASPECT_4x3)
-			return -ERANGE;
-		if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
-			new = V4L2_MPEG_VIDEO_ASPECT_4x3;
-		params->vi_aspect = new;
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE:
-		old = params->vi_bitrate * 1000;
-		new = 1000 * (new / 1000);
-		if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-			return -ERANGE;
-		if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-			new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
-		params->vi_bitrate = new / 1000;
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-		old = params->vi_bitrate_peak * 1000;
-		new = 1000 * (new / 1000);
-		if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-			return -ERANGE;
-		if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-			new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
-		params->vi_bitrate_peak = new / 1000;
+		params->vi_aspect = ctrl->val;
 		break;
 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-		old = params->vi_bitrate_mode;
-		params->vi_bitrate_mode = new;
+		params->vi_bitrate_mode = ctrl->val;
+		params->vi_bitrate = h->video_bitrate->val / 1000;
+		params->vi_bitrate_peak = h->video_bitrate_peak->val / 1000;
+		v4l2_ctrl_activate(h->video_bitrate_peak,
+				ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
 		break;
 	default:
 		return -EINVAL;
 	}
-	ctrl->value = new;
 	return 0;
 }
 
-
-static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
-{
-	struct saa6752hs_state *h = to_state(sd);
-	struct saa6752hs_mpeg_params *params = &h->params;
-	int err;
-
-	switch (qctrl->id) {
-	case V4L2_CID_MPEG_AUDIO_ENCODING:
-		return v4l2_ctrl_query_fill(qctrl,
-				V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-				h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
-					V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-				1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
-
-	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-		return v4l2_ctrl_query_fill(qctrl,
-				V4L2_MPEG_AUDIO_L2_BITRATE_256K,
-				V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
-				V4L2_MPEG_AUDIO_L2_BITRATE_256K);
-
-	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-		if (!h->has_ac3)
-			return -EINVAL;
-		return v4l2_ctrl_query_fill(qctrl,
-				V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
-				V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1,
-				V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
-
-	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-		return v4l2_ctrl_query_fill(qctrl,
-				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
-				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1,
-				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
-
-	case V4L2_CID_MPEG_VIDEO_ENCODING:
-		return v4l2_ctrl_query_fill(qctrl,
-				V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
-				V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
-				V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
-
-	case V4L2_CID_MPEG_VIDEO_ASPECT:
-		return v4l2_ctrl_query_fill(qctrl,
-				V4L2_MPEG_VIDEO_ASPECT_4x3,
-				V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
-				V4L2_MPEG_VIDEO_ASPECT_4x3);
-
-	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-		err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
-		if (err == 0 &&
-		    params->vi_bitrate_mode ==
-				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
-			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-		return err;
-
-	case V4L2_CID_MPEG_STREAM_TYPE:
-		return v4l2_ctrl_query_fill(qctrl,
-				V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
-				V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1,
-				V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
-
-	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-		return v4l2_ctrl_query_fill(qctrl,
-				V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
-				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
-				V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
-	case V4L2_CID_MPEG_VIDEO_BITRATE:
-		return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
-	case V4L2_CID_MPEG_STREAM_PID_PMT:
-		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
-	case V4L2_CID_MPEG_STREAM_PID_AUDIO:
-		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
-	case V4L2_CID_MPEG_STREAM_PID_VIDEO:
-		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
-	case V4L2_CID_MPEG_STREAM_PID_PCR:
-		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
-
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static int saa6752hs_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qmenu)
-{
-	static const u32 mpeg_audio_encoding[] = {
-		V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-		V4L2_CTRL_MENU_IDS_END
-	};
-	static const u32 mpeg_audio_ac3_encoding[] = {
-		V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-		V4L2_MPEG_AUDIO_ENCODING_AC3,
-		V4L2_CTRL_MENU_IDS_END
-	};
-	static u32 mpeg_audio_l2_bitrate[] = {
-		V4L2_MPEG_AUDIO_L2_BITRATE_256K,
-		V4L2_MPEG_AUDIO_L2_BITRATE_384K,
-		V4L2_CTRL_MENU_IDS_END
-	};
-	static u32 mpeg_audio_ac3_bitrate[] = {
-		V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
-		V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
-		V4L2_CTRL_MENU_IDS_END
-	};
-	struct saa6752hs_state *h = to_state(sd);
-	struct v4l2_queryctrl qctrl;
-	int err;
-
-	qctrl.id = qmenu->id;
-	err = saa6752hs_queryctrl(sd, &qctrl);
-	if (err)
-		return err;
-	switch (qmenu->id) {
-	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-		return v4l2_ctrl_query_menu_valid_items(qmenu,
-				mpeg_audio_l2_bitrate);
-	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-		if (!h->has_ac3)
-			return -EINVAL;
-		return v4l2_ctrl_query_menu_valid_items(qmenu,
-				mpeg_audio_ac3_bitrate);
-	case V4L2_CID_MPEG_AUDIO_ENCODING:
-		return v4l2_ctrl_query_menu_valid_items(qmenu,
-			h->has_ac3 ? mpeg_audio_ac3_encoding :
-				mpeg_audio_encoding);
-	}
-	return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
-}
-
 static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
 {
 	unsigned char buf[9], buf2[4];
@@ -793,58 +556,6 @@ static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
 	return 0;
 }
 
-static int saa6752hs_do_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls, int set)
-{
-	struct saa6752hs_state *h = to_state(sd);
-	struct saa6752hs_mpeg_params params;
-	int i;
-
-	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-		return -EINVAL;
-
-	params = h->params;
-	for (i = 0; i < ctrls->count; i++) {
-		int err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, set);
-
-		if (err) {
-			ctrls->error_idx = i;
-			return err;
-		}
-	}
-	if (set)
-		h->params = params;
-	return 0;
-}
-
-static int saa6752hs_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
-{
-	return saa6752hs_do_ext_ctrls(sd, ctrls, 1);
-}
-
-static int saa6752hs_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
-{
-	return saa6752hs_do_ext_ctrls(sd, ctrls, 0);
-}
-
-static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
-{
-	struct saa6752hs_state *h = to_state(sd);
-	int i;
-
-	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-		return -EINVAL;
-
-	for (i = 0; i < ctrls->count; i++) {
-		int err = get_ctrl(h->has_ac3, &h->params, ctrls->controls + i);
-
-		if (err) {
-			ctrls->error_idx = i;
-			return err;
-		}
-	}
-	return 0;
-}
-
 static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
 {
 	struct saa6752hs_state *h = to_state(sd);
@@ -925,14 +636,21 @@ static int saa6752hs_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_i
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
+	.try_ctrl = saa6752hs_try_ctrl,
+	.s_ctrl = saa6752hs_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
 	.g_chip_ident = saa6752hs_g_chip_ident,
 	.init = saa6752hs_init,
-	.queryctrl = saa6752hs_queryctrl,
-	.querymenu = saa6752hs_querymenu,
-	.g_ext_ctrls = saa6752hs_g_ext_ctrls,
-	.s_ext_ctrls = saa6752hs_s_ext_ctrls,
-	.try_ext_ctrls = saa6752hs_try_ext_ctrls,
+	.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,
 	.s_std = saa6752hs_s_std,
 };
 
@@ -951,6 +669,7 @@ static int saa6752hs_probe(struct i2c_client *client,
 {
 	struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
 	struct v4l2_subdev *sd;
+	struct v4l2_ctrl_handler *hdl;
 	u8 addr = 0x13;
 	u8 data[12];
 
@@ -969,9 +688,84 @@ static int saa6752hs_probe(struct i2c_client *client,
 	if (h->revision == 0x0206) {
 		h->chip = V4L2_IDENT_SAA6752HS_AC3;
 		h->has_ac3 = 1;
-		v4l_info(client, "support AC-3\n");
+		v4l_info(client, "supports AC-3\n");
 	}
 	h->params = param_defaults;
+
+	hdl = &h->hdl;
+	v4l2_ctrl_handler_init(hdl, 14);
+	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_AUDIO_ENCODING,
+		h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
+			V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+		0x0d, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+		V4L2_MPEG_AUDIO_L2_BITRATE_384K,
+		~((1 << V4L2_MPEG_AUDIO_L2_BITRATE_256K) |
+		  (1 << V4L2_MPEG_AUDIO_L2_BITRATE_384K)),
+		V4L2_MPEG_AUDIO_L2_BITRATE_256K);
+
+	if (h->has_ac3)
+		v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+			V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
+			V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
+			~((1 << V4L2_MPEG_AUDIO_AC3_BITRATE_256K) |
+			  (1 << V4L2_MPEG_AUDIO_AC3_BITRATE_384K)),
+			V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
+
+	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+		V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+		~(1 << V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000),
+		V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
+	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_ENCODING,
+		V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+		~(1 << V4L2_MPEG_VIDEO_ENCODING_MPEG_2),
+		V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+
+	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_ASPECT,
+		V4L2_MPEG_VIDEO_ASPECT_16x9, 0x01,
+		V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+	h->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+		1000000, 27000000, 1000, 8000000);
+
+	v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_STREAM_TYPE,
+		V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+		~(1 << V4L2_MPEG_STREAM_TYPE_MPEG2_TS),
+		V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+
+	h->video_bitrate_mode = v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+		V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+	h->video_bitrate = v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_BITRATE, 1000000, 27000000, 1000, 6000000);
+	v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_STREAM_PID_PMT, 0, (1 << 14) - 1, 1, 16);
+	v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_STREAM_PID_AUDIO, 0, (1 << 14) - 1, 1, 260);
+	v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_STREAM_PID_VIDEO, 0, (1 << 14) - 1, 1, 256);
+	v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+		V4L2_CID_MPEG_STREAM_PID_PCR, 0, (1 << 14) - 1, 1, 259);
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		int err = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		kfree(h);
+		return err;
+	}
+	v4l2_ctrl_cluster(3, &h->video_bitrate_mode);
+	v4l2_ctrl_handler_setup(hdl);
 	h->standard = 0; /* Assume 625 input lines */
 	return 0;
 }
@@ -981,6 +775,7 @@ static int saa6752hs_remove(struct i2c_client *client)
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
 	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&to_state(sd)->hdl);
 	kfree(to_state(sd));
 	return 0;
 }
@@ -1002,11 +797,3 @@ static struct i2c_driver saa6752hs_driver = {
 };
 
 module_i2c_driver(saa6752hs_driver);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 04/21] radio-tea5764: add support for struct v4l2_device.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (2 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 03/21] saa6752hs: " Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 05/21] radio-tea5764: embed struct video_device Hans Verkuil
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Fabio Belavenuto

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Fabio Belavenuto <belavenuto@gmail.com>
---
 drivers/media/radio/radio-tea5764.c |   22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 38d563d..f6a5471 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -39,6 +39,7 @@
 #include <linux/i2c.h>			/* I2C				*/
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
 
 #define DRIVER_VERSION	"0.0.2"
 
@@ -138,6 +139,7 @@ static int radio_nr = -1;
 static int use_xtal = RADIO_TEA5764_XTAL;
 
 struct tea5764_device {
+	struct v4l2_device v4l2_dev;
 	struct i2c_client		*i2c_client;
 	struct video_device		*videodev;
 	struct tea5764_regs		regs;
@@ -497,6 +499,7 @@ static int tea5764_i2c_probe(struct i2c_client *client,
 			     const struct i2c_device_id *id)
 {
 	struct tea5764_device *radio;
+	struct v4l2_device *v4l2_dev;
 	struct tea5764_regs *r;
 	int ret;
 
@@ -505,31 +508,37 @@ static int tea5764_i2c_probe(struct i2c_client *client,
 	if (!radio)
 		return -ENOMEM;
 
+	v4l2_dev = &radio->v4l2_dev;
+	ret = v4l2_device_register(&client->dev, v4l2_dev);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "could not register v4l2_device\n");
+		goto errfr;
+	}
 	mutex_init(&radio->mutex);
 	radio->i2c_client = client;
 	ret = tea5764_i2c_read(radio);
 	if (ret)
-		goto errfr;
+		goto errunreg;
 	r = &radio->regs;
 	PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid);
 	if (r->chipid != TEA5764_CHIPID ||
 		(r->manid & 0x0fff) != TEA5764_MANID) {
 		PWARN("This chip is not a TEA5764!");
 		ret = -EINVAL;
-		goto errfr;
+		goto errunreg;
 	}
 
 	radio->videodev = video_device_alloc();
 	if (!(radio->videodev)) {
 		ret = -ENOMEM;
-		goto errfr;
+		goto errunreg;
 	}
-	memcpy(radio->videodev, &tea5764_radio_template,
-		sizeof(tea5764_radio_template));
+	*radio->videodev = tea5764_radio_template;
 
 	i2c_set_clientdata(client, radio);
 	video_set_drvdata(radio->videodev, radio);
 	radio->videodev->lock = &radio->mutex;
+	radio->videodev->v4l2_dev = v4l2_dev;
 
 	/* initialize and power off the chip */
 	tea5764_i2c_read(radio);
@@ -547,6 +556,8 @@ static int tea5764_i2c_probe(struct i2c_client *client,
 	return 0;
 errrel:
 	video_device_release(radio->videodev);
+errunreg:
+	v4l2_device_unregister(v4l2_dev);
 errfr:
 	kfree(radio);
 	return ret;
@@ -560,6 +571,7 @@ static int tea5764_i2c_remove(struct i2c_client *client)
 	if (radio) {
 		tea5764_power_down(radio);
 		video_unregister_device(radio->videodev);
+		v4l2_device_unregister(&radio->v4l2_dev);
 		kfree(radio);
 	}
 	return 0;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 05/21] radio-tea5764: embed struct video_device.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (3 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 04/21] radio-tea5764: add support for struct v4l2_device Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 06/21] radio-tea5764: convert to the control framework Hans Verkuil
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Fabio Belavenuto

From: Hans Verkuil <hans.verkuil@cisco.com>

This simplifies the code as it removes a memory allocation check.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Fabio Belavenuto <belavenuto@gmail.com>
---
 drivers/media/radio/radio-tea5764.c |   27 ++++++++++-----------------
 1 file changed, 10 insertions(+), 17 deletions(-)

diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index f6a5471..4e0bf64 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -141,7 +141,7 @@ static int use_xtal = RADIO_TEA5764_XTAL;
 struct tea5764_device {
 	struct v4l2_device v4l2_dev;
 	struct i2c_client		*i2c_client;
-	struct video_device		*videodev;
+	struct video_device		vdev;
 	struct tea5764_regs		regs;
 	struct mutex			mutex;
 };
@@ -303,7 +303,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 					struct v4l2_capability *v)
 {
 	struct tea5764_device *radio = video_drvdata(file);
-	struct video_device *dev = radio->videodev;
+	struct video_device *dev = &radio->vdev;
 
 	strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
 	strlcpy(v->card, dev->name, sizeof(v->card));
@@ -491,7 +491,7 @@ static struct video_device tea5764_radio_template = {
 	.name		= "TEA5764 FM-Radio",
 	.fops           = &tea5764_fops,
 	.ioctl_ops 	= &tea5764_ioctl_ops,
-	.release	= video_device_release,
+	.release	= video_device_release_empty,
 };
 
 /* I2C probe: check if the device exists and register with v4l if it is */
@@ -528,17 +528,12 @@ static int tea5764_i2c_probe(struct i2c_client *client,
 		goto errunreg;
 	}
 
-	radio->videodev = video_device_alloc();
-	if (!(radio->videodev)) {
-		ret = -ENOMEM;
-		goto errunreg;
-	}
-	*radio->videodev = tea5764_radio_template;
+	radio->vdev = tea5764_radio_template;
 
 	i2c_set_clientdata(client, radio);
-	video_set_drvdata(radio->videodev, radio);
-	radio->videodev->lock = &radio->mutex;
-	radio->videodev->v4l2_dev = v4l2_dev;
+	video_set_drvdata(&radio->vdev, radio);
+	radio->vdev.lock = &radio->mutex;
+	radio->vdev.v4l2_dev = v4l2_dev;
 
 	/* initialize and power off the chip */
 	tea5764_i2c_read(radio);
@@ -546,16 +541,14 @@ static int tea5764_i2c_probe(struct i2c_client *client,
 	tea5764_mute(radio, 1);
 	tea5764_power_down(radio);
 
-	ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+	ret = video_register_device(&radio->vdev, VFL_TYPE_RADIO, radio_nr);
 	if (ret < 0) {
 		PWARN("Could not register video device!");
-		goto errrel;
+		goto errunreg;
 	}
 
 	PINFO("registered.");
 	return 0;
-errrel:
-	video_device_release(radio->videodev);
 errunreg:
 	v4l2_device_unregister(v4l2_dev);
 errfr:
@@ -570,7 +563,7 @@ static int tea5764_i2c_remove(struct i2c_client *client)
 	PDEBUG("remove");
 	if (radio) {
 		tea5764_power_down(radio);
-		video_unregister_device(radio->videodev);
+		video_unregister_device(&radio->vdev);
 		v4l2_device_unregister(&radio->v4l2_dev);
 		kfree(radio);
 	}
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 06/21] radio-tea5764: convert to the control framework.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (4 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 05/21] radio-tea5764: embed struct video_device Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 07/21] radio-tea5764: audio and input ioctls do not apply to radio devices Hans Verkuil
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Fabio Belavenuto

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Fabio Belavenuto <belavenuto@gmail.com>
---
 drivers/media/radio/radio-tea5764.c |   79 ++++++++++++-----------------------
 1 file changed, 26 insertions(+), 53 deletions(-)

diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 4e0bf64..5c47a97 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -40,6 +40,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 
 #define DRIVER_VERSION	"0.0.2"
 
@@ -139,7 +140,8 @@ static int radio_nr = -1;
 static int use_xtal = RADIO_TEA5764_XTAL;
 
 struct tea5764_device {
-	struct v4l2_device v4l2_dev;
+	struct v4l2_device		v4l2_dev;
+	struct v4l2_ctrl_handler	ctrl_handler;
 	struct i2c_client		*i2c_client;
 	struct video_device		vdev;
 	struct tea5764_regs		regs;
@@ -189,18 +191,6 @@ static int tea5764_i2c_write(struct tea5764_device *radio)
 	return 0;
 }
 
-/* V4L2 code related */
-static struct v4l2_queryctrl radio_qctrl[] = {
-	{
-		.id            = V4L2_CID_AUDIO_MUTE,
-		.name          = "Mute",
-		.minimum       = 0,
-		.maximum       = 1,
-		.default_value = 1,
-		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-	}
-};
-
 static void tea5764_power_up(struct tea5764_device *radio)
 {
 	struct tea5764_regs *r = &radio->regs;
@@ -293,11 +283,6 @@ static void tea5764_mute(struct tea5764_device *radio, int on)
 		tea5764_i2c_write(radio);
 }
 
-static int tea5764_is_muted(struct tea5764_device *radio)
-{
-	return radio->regs.tnctrl & TEA5764_TNCTRL_MU;
-}
-
 /* V4L2 vidioc */
 static int vidioc_querycap(struct file *file, void  *priv,
 					struct v4l2_capability *v)
@@ -391,42 +376,14 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 	return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-			    struct v4l2_queryctrl *qc)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-		if (qc->id && qc->id == radio_qctrl[i].id) {
-			memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-			    struct v4l2_control *ctrl)
-{
-	struct tea5764_device *radio = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		tea5764_i2c_read(radio);
-		ctrl->value = tea5764_is_muted(radio) ? 1 : 0;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			    struct v4l2_control *ctrl)
+static int tea5764_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct tea5764_device *radio = video_drvdata(file);
+	struct tea5764_device *radio =
+		container_of(ctrl->handler, struct tea5764_device, ctrl_handler);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		tea5764_mute(radio, ctrl->value);
+		tea5764_mute(radio, ctrl->val);
 		return 0;
 	}
 	return -EINVAL;
@@ -465,6 +422,10 @@ static int vidioc_s_audio(struct file *file, void *priv,
 	return 0;
 }
 
+static const struct v4l2_ctrl_ops tea5764_ctrl_ops = {
+	.s_ctrl = tea5764_s_ctrl,
+};
+
 /* File system interface */
 static const struct v4l2_file_operations tea5764_fops = {
 	.owner		= THIS_MODULE,
@@ -481,9 +442,6 @@ static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
 	.vidioc_s_input     = vidioc_s_input,
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 /* V4L2 interface */
@@ -500,6 +458,7 @@ static int tea5764_i2c_probe(struct i2c_client *client,
 {
 	struct tea5764_device *radio;
 	struct v4l2_device *v4l2_dev;
+	struct v4l2_ctrl_handler *hdl;
 	struct tea5764_regs *r;
 	int ret;
 
@@ -514,6 +473,18 @@ static int tea5764_i2c_probe(struct i2c_client *client,
 		v4l2_err(v4l2_dev, "could not register v4l2_device\n");
 		goto errfr;
 	}
+
+	hdl = &radio->ctrl_handler;
+	v4l2_ctrl_handler_init(hdl, 1);
+	v4l2_ctrl_new_std(hdl, &tea5764_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	v4l2_dev->ctrl_handler = hdl;
+	if (hdl->error) {
+		ret = hdl->error;
+		v4l2_err(v4l2_dev, "Could not register controls\n");
+		goto errunreg;
+	}
+
 	mutex_init(&radio->mutex);
 	radio->i2c_client = client;
 	ret = tea5764_i2c_read(radio);
@@ -550,6 +521,7 @@ static int tea5764_i2c_probe(struct i2c_client *client,
 	PINFO("registered.");
 	return 0;
 errunreg:
+	v4l2_ctrl_handler_free(hdl);
 	v4l2_device_unregister(v4l2_dev);
 errfr:
 	kfree(radio);
@@ -564,6 +536,7 @@ static int tea5764_i2c_remove(struct i2c_client *client)
 	if (radio) {
 		tea5764_power_down(radio);
 		video_unregister_device(&radio->vdev);
+		v4l2_ctrl_handler_free(&radio->ctrl_handler);
 		v4l2_device_unregister(&radio->v4l2_dev);
 		kfree(radio);
 	}
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 07/21] radio-tea5764: audio and input ioctls do not apply to radio devices.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (5 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 06/21] radio-tea5764: convert to the control framework Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 08/21] radio-tea5764: add device_caps support Hans Verkuil
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Fabio Belavenuto

From: Hans Verkuil <hans.verkuil@cisco.com>

Deleted those ioctls from this driver.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Fabio Belavenuto <belavenuto@gmail.com>
---
 drivers/media/radio/radio-tea5764.c |   37 -----------------------------------
 1 file changed, 37 deletions(-)

diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 5c47a97..5a60990 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -389,39 +389,6 @@ static int tea5764_s_ctrl(struct v4l2_ctrl *ctrl)
 	return -EINVAL;
 }
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	if (i != 0)
-		return -EINVAL;
-	return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-			   struct v4l2_audio *a)
-{
-	if (a->index > 1)
-		return -EINVAL;
-
-	strcpy(a->name, "Radio");
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-			   const struct v4l2_audio *a)
-{
-	if (a->index != 0)
-		return -EINVAL;
-
-	return 0;
-}
-
 static const struct v4l2_ctrl_ops tea5764_ctrl_ops = {
 	.s_ctrl = tea5764_s_ctrl,
 };
@@ -436,10 +403,6 @@ static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
 	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
 };
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 08/21] radio-tea5764: add device_caps support.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (6 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 07/21] radio-tea5764: audio and input ioctls do not apply to radio devices Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 09/21] radio-tea5764: add prio and control event support Hans Verkuil
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Fabio Belavenuto

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Fabio Belavenuto <belavenuto@gmail.com>
---
 drivers/media/radio/radio-tea5764.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 5a60990..077d906 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -294,7 +294,8 @@ static int vidioc_querycap(struct file *file, void  *priv,
 	strlcpy(v->card, dev->name, sizeof(v->card));
 	snprintf(v->bus_info, sizeof(v->bus_info),
 		 "I2C:%s", dev_name(&dev->dev));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 09/21] radio-tea5764: add prio and control event support.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (7 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 08/21] radio-tea5764: add device_caps support Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range Hans Verkuil
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Fabio Belavenuto

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Fabio Belavenuto <belavenuto@gmail.com>
---
 drivers/media/radio/radio-tea5764.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 077d906..c22feed 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -41,6 +41,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 
 #define DRIVER_VERSION	"0.0.2"
 
@@ -397,6 +398,9 @@ static const struct v4l2_ctrl_ops tea5764_ctrl_ops = {
 /* File system interface */
 static const struct v4l2_file_operations tea5764_fops = {
 	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
 	.unlocked_ioctl	= video_ioctl2,
 };
 
@@ -406,6 +410,9 @@ static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
 	.vidioc_s_tuner     = vidioc_s_tuner,
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_log_status  = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 /* V4L2 interface */
@@ -469,6 +476,7 @@ static int tea5764_i2c_probe(struct i2c_client *client,
 	video_set_drvdata(&radio->vdev, radio);
 	radio->vdev.lock = &radio->mutex;
 	radio->vdev.v4l2_dev = v4l2_dev;
+	set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
 
 	/* initialize and power off the chip */
 	tea5764_i2c_read(radio);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (8 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 09/21] radio-tea5764: add prio and control event support Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-10-28 11:45   ` [BUG] [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range AND [PATCH 15/21] tef6862: clamp frequency Hans Petter Selasky
  2013-05-31 10:02 ` [PATCH 11/21] radio-timb: add device_caps support, remove input/audio ioctls Hans Verkuil
                   ` (10 subsequent siblings)
  20 siblings, 1 reply; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Fabio Belavenuto

From: Hans Verkuil <hans.verkuil@cisco.com>

Some small cleanups and when setting the frequency it is now clamped
to the valid frequency range instead of returning an error.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Fabio Belavenuto <belavenuto@gmail.com>
---
 drivers/media/radio/radio-tea5764.c |   24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index c22feed..036e2f5 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -60,8 +60,8 @@
 
 /* Frequency limits in MHz -- these are European values.  For Japanese
 devices, that would be 76000 and 91000.  */
-#define FREQ_MIN  87500
-#define FREQ_MAX 108000
+#define FREQ_MIN  87500U
+#define FREQ_MAX 108000U
 #define FREQ_MUL 16
 
 /* TEA5764 registers */
@@ -309,8 +309,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 	if (v->index > 0)
 		return -EINVAL;
 
-	memset(v, 0, sizeof(*v));
-	strcpy(v->name, "FM");
+	strlcpy(v->name, "FM", sizeof(v->name));
 	v->type = V4L2_TUNER_RADIO;
 	tea5764_i2c_read(radio);
 	v->rangelow   = FREQ_MIN * FREQ_MUL;
@@ -343,19 +342,23 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 				const struct v4l2_frequency *f)
 {
 	struct tea5764_device *radio = video_drvdata(file);
+	unsigned freq = f->frequency;
 
 	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
 		return -EINVAL;
-	if (f->frequency == 0) {
+	if (freq == 0) {
 		/* We special case this as a power down control. */
 		tea5764_power_down(radio);
-	}
-	if (f->frequency < (FREQ_MIN * FREQ_MUL))
-		return -EINVAL;
-	if (f->frequency > (FREQ_MAX * FREQ_MUL))
+		/* Yes, that's what is returned in this case. This
+		   whole special case is non-compliant and should really
+		   be replaced with something better, but changing this
+		   might well break code that depends on this behavior.
+		   So we keep it as-is. */
 		return -EINVAL;
+	}
+	clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
 	tea5764_power_up(radio);
-	tea5764_tune(radio, (f->frequency * 125) / 2);
+	tea5764_tune(radio, (freq * 125) / 2);
 	return 0;
 }
 
@@ -368,7 +371,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 	if (f->tuner != 0)
 		return -EINVAL;
 	tea5764_i2c_read(radio);
-	memset(f, 0, sizeof(*f));
 	f->type = V4L2_TUNER_RADIO;
 	if (r->tnctrl & TEA5764_TNCTRL_PUPD0)
 		f->frequency = (tea5764_get_freq(radio) * 2) / 125;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 11/21] radio-timb: add device_caps support, remove input/audio ioctls.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (9 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 12/21] radio-timb: convert to the control framework Hans Verkuil
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Richard Röjfors

From: Hans Verkuil <hans.verkuil@cisco.com>

The audio and input ioctls are not applicable for radio devices,
remove them.

Also set the device_caps field in v4l2_querycap.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Richard Röjfors <richard.rojfors@pelagicore.com>
---
 drivers/media/radio/radio-timb.c |   35 ++---------------------------------
 1 file changed, 2 insertions(+), 33 deletions(-)

diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index bb7b143..cecf7d7 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -44,7 +44,8 @@ static int timbradio_vidioc_querycap(struct file *file, void  *priv,
 	strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver));
 	strlcpy(v->card, "Timberdale Radio", sizeof(v->card));
 	snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -62,34 +63,6 @@ static int timbradio_vidioc_s_tuner(struct file *file, void *priv,
 	return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v);
 }
 
-static int timbradio_vidioc_g_input(struct file *filp, void *priv,
-	unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int timbradio_vidioc_s_input(struct file *filp, void *priv,
-	unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int timbradio_vidioc_g_audio(struct file *file, void *priv,
-	struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int timbradio_vidioc_s_audio(struct file *file, void *priv,
-	const struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
 static int timbradio_vidioc_s_frequency(struct file *file, void *priv,
 	const struct v4l2_frequency *f)
 {
@@ -131,10 +104,6 @@ static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
 	.vidioc_s_tuner		= timbradio_vidioc_s_tuner,
 	.vidioc_g_frequency	= timbradio_vidioc_g_frequency,
 	.vidioc_s_frequency	= timbradio_vidioc_s_frequency,
-	.vidioc_g_input		= timbradio_vidioc_g_input,
-	.vidioc_s_input		= timbradio_vidioc_s_input,
-	.vidioc_g_audio		= timbradio_vidioc_g_audio,
-	.vidioc_s_audio		= timbradio_vidioc_s_audio,
 	.vidioc_queryctrl	= timbradio_vidioc_queryctrl,
 	.vidioc_g_ctrl		= timbradio_vidioc_g_ctrl,
 	.vidioc_s_ctrl		= timbradio_vidioc_s_ctrl
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 12/21] radio-timb: convert to the control framework.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (10 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 11/21] radio-timb: add device_caps support, remove input/audio ioctls Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 13/21] radio-timb: actually load the requested subdevs Hans Verkuil
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Richard Röjfors

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Richard Röjfors <richard.rojfors@pelagicore.com>
---
 drivers/media/radio/radio-timb.c |   24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index cecf7d7..99694dd 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -77,36 +77,12 @@ static int timbradio_vidioc_g_frequency(struct file *file, void *priv,
 	return v4l2_subdev_call(tr->sd_tuner, tuner, g_frequency, f);
 }
 
-static int timbradio_vidioc_queryctrl(struct file *file, void *priv,
-	struct v4l2_queryctrl *qc)
-{
-	struct timbradio *tr = video_drvdata(file);
-	return v4l2_subdev_call(tr->sd_dsp, core, queryctrl, qc);
-}
-
-static int timbradio_vidioc_g_ctrl(struct file *file, void *priv,
-	struct v4l2_control *ctrl)
-{
-	struct timbradio *tr = video_drvdata(file);
-	return v4l2_subdev_call(tr->sd_dsp, core, g_ctrl, ctrl);
-}
-
-static int timbradio_vidioc_s_ctrl(struct file *file, void *priv,
-	struct v4l2_control *ctrl)
-{
-	struct timbradio *tr = video_drvdata(file);
-	return v4l2_subdev_call(tr->sd_dsp, core, s_ctrl, ctrl);
-}
-
 static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
 	.vidioc_querycap	= timbradio_vidioc_querycap,
 	.vidioc_g_tuner		= timbradio_vidioc_g_tuner,
 	.vidioc_s_tuner		= timbradio_vidioc_s_tuner,
 	.vidioc_g_frequency	= timbradio_vidioc_g_frequency,
 	.vidioc_s_frequency	= timbradio_vidioc_s_frequency,
-	.vidioc_queryctrl	= timbradio_vidioc_queryctrl,
-	.vidioc_g_ctrl		= timbradio_vidioc_g_ctrl,
-	.vidioc_s_ctrl		= timbradio_vidioc_s_ctrl
 };
 
 static const struct v4l2_file_operations timbradio_fops = {
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 13/21] radio-timb: actually load the requested subdevs
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (11 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 12/21] radio-timb: convert to the control framework Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 14/21] radio-timb: add control events and prio support Hans Verkuil
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Richard Röjfors

From: Hans Verkuil <hans.verkuil@cisco.com>

For some reason the tuner and dsp subdevs were never actually loaded.
Added the relevant code to do that.

Also remove bogus calls to video_device_release_empty().

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Richard Röjfors <richard.rojfors@pelagicore.com>
---
 drivers/media/radio/radio-timb.c |   13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 99694dd..1931ef7 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -126,6 +126,15 @@ static int timbradio_probe(struct platform_device *pdev)
 
 	tr->video_dev.v4l2_dev = &tr->v4l2_dev;
 
+	tr->sd_tuner = v4l2_i2c_new_subdev_board(&tr->v4l2_dev,
+		i2c_get_adapter(pdata->i2c_adapter), pdata->tuner, NULL);
+	tr->sd_dsp = v4l2_i2c_new_subdev_board(&tr->v4l2_dev,
+		i2c_get_adapter(pdata->i2c_adapter), pdata->dsp, NULL);
+	if (tr->sd_tuner == NULL || tr->sd_dsp == NULL)
+		goto err_video_req;
+
+	tr->v4l2_dev.ctrl_handler = tr->sd_dsp->ctrl_handler;
+
 	err = video_register_device(&tr->video_dev, VFL_TYPE_RADIO, -1);
 	if (err) {
 		dev_err(&pdev->dev, "Error reg video\n");
@@ -138,7 +147,6 @@ static int timbradio_probe(struct platform_device *pdev)
 	return 0;
 
 err_video_req:
-	video_device_release_empty(&tr->video_dev);
 	v4l2_device_unregister(&tr->v4l2_dev);
 err:
 	dev_err(&pdev->dev, "Failed to register: %d\n", err);
@@ -151,10 +159,7 @@ static int timbradio_remove(struct platform_device *pdev)
 	struct timbradio *tr = platform_get_drvdata(pdev);
 
 	video_unregister_device(&tr->video_dev);
-	video_device_release_empty(&tr->video_dev);
-
 	v4l2_device_unregister(&tr->v4l2_dev);
-
 	return 0;
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 14/21] radio-timb: add control events and prio support.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (12 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 13/21] radio-timb: actually load the requested subdevs Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 15/21] tef6862: clamp frequency Hans Verkuil
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Richard Röjfors

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Richard Röjfors <richard.rojfors@pelagicore.com>
---
 drivers/media/radio/radio-timb.c |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 1931ef7..0817964 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -19,6 +19,8 @@
 #include <linux/io.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
@@ -83,10 +85,16 @@ static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
 	.vidioc_s_tuner		= timbradio_vidioc_s_tuner,
 	.vidioc_g_frequency	= timbradio_vidioc_g_frequency,
 	.vidioc_s_frequency	= timbradio_vidioc_s_frequency,
+	.vidioc_log_status      = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static const struct v4l2_file_operations timbradio_fops = {
 	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
 	.unlocked_ioctl	= video_ioctl2,
 };
 
@@ -118,6 +126,7 @@ static int timbradio_probe(struct platform_device *pdev)
 	tr->video_dev.release = video_device_release_empty;
 	tr->video_dev.minor = -1;
 	tr->video_dev.lock = &tr->lock;
+	set_bit(V4L2_FL_USE_FH_PRIO, &tr->video_dev.flags);
 
 	strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
 	err = v4l2_device_register(NULL, &tr->v4l2_dev);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 15/21] tef6862: clamp frequency.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (13 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 14/21] radio-timb: add control events and prio support Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 16/21] timblogiw: fix querycap Hans Verkuil
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Richard Röjfors

From: Hans Verkuil <hans.verkuil@cisco.com>

Clamp the frequency to the valid frequency range as per the V4L2 specification.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Richard Röjfors <richard.rojfors@pelagicore.com>
---
 drivers/media/radio/tef6862.c |   10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index 82c6c94..de2e6db 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -31,8 +31,8 @@
 
 #define FREQ_MUL 16000
 
-#define TEF6862_LO_FREQ (875 * FREQ_MUL / 10)
-#define TEF6862_HI_FREQ (108 * FREQ_MUL)
+#define TEF6862_LO_FREQ (875U * FREQ_MUL / 10)
+#define TEF6862_HI_FREQ (108U * FREQ_MUL)
 
 /* Write mode sub addresses */
 #define WM_SUB_BANDWIDTH	0x0
@@ -105,6 +105,7 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
 {
 	struct tef6862_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	unsigned freq = f->frequency;
 	u16 pll;
 	u8 i2cmsg[3];
 	int err;
@@ -112,7 +113,8 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
 	if (f->tuner != 0)
 		return -EINVAL;
 
-	pll = 1964 + ((f->frequency - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
+	clamp(freq, TEF6862_LO_FREQ, TEF6862_HI_FREQ);
+	pll = 1964 + ((freq - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
 	i2cmsg[0] = (MODE_PRESET << MODE_SHIFT) | WM_SUB_PLLM;
 	i2cmsg[1] = (pll >> 8) & 0xff;
 	i2cmsg[2] = pll & 0xff;
@@ -121,7 +123,7 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
 	if (err != sizeof(i2cmsg))
 		return err < 0 ? err : -EIO;
 
-	state->freq = f->frequency;
+	state->freq = freq;
 	return 0;
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 16/21] timblogiw: fix querycap.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (14 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 15/21] tef6862: clamp frequency Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 17/21] radio-sf16fmi: remove audio/input ioctls Hans Verkuil
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Richard Röjfors

From: Hans Verkuil <hans.verkuil@cisco.com>

Don't set version (the core does that for you), fill in device_caps and
prefix bus_info with "platform:".

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Richard Röjfors <richard.rojfors@pelagicore.com>
---
 drivers/media/platform/timblogiw.c |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c
index 99861c63..b557caf 100644
--- a/drivers/media/platform/timblogiw.c
+++ b/drivers/media/platform/timblogiw.c
@@ -239,13 +239,12 @@ static int timblogiw_querycap(struct file *file, void  *priv,
 	struct video_device *vdev = video_devdata(file);
 
 	dev_dbg(&vdev->dev, "%s: Entry\n",  __func__);
-	memset(cap, 0, sizeof(*cap));
 	strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1);
 	strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1);
-	strlcpy(cap->bus_info, vdev->name, sizeof(cap->bus_info));
-	cap->version = TIMBLOGIW_VERSION_CODE;
-	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", vdev->name);
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
 		V4L2_CAP_READWRITE;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
 	return 0;
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 17/21] radio-sf16fmi: remove audio/input ioctls.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (15 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 16/21] timblogiw: fix querycap Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 18/21] radio-sf16fmi: add device_caps support to querycap Hans Verkuil
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Ondrej Zary

From: Hans Verkuil <hans.verkuil@cisco.com>

The audio and input ioctls do not apply to radio devices. Remove them.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Ondrej Zary <linux@rainbow-software.org>
---
 drivers/media/radio/radio-sf16fmi.c |   30 ------------------------------
 1 file changed, 30 deletions(-)

diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index adfcc61..c1d51ec 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -218,32 +218,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 	return -EINVAL;
 }
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-					const struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
 static const struct v4l2_file_operations fmi_fops = {
 	.owner		= THIS_MODULE,
 	.unlocked_ioctl	= video_ioctl2,
@@ -253,10 +227,6 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
 	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
 	.vidioc_queryctrl   = vidioc_queryctrl,
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 18/21] radio-sf16fmi: add device_caps support to querycap.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (16 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 17/21] radio-sf16fmi: remove audio/input ioctls Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 19/21] radio-sf16fmi: clamp frequency Hans Verkuil
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Ondrej Zary

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Ondrej Zary <linux@rainbow-software.org>
---
 drivers/media/radio/radio-sf16fmi.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index c1d51ec..80beda7 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -121,7 +121,8 @@ static int vidioc_querycap(struct file *file, void  *priv,
 	strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
 	strlcpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card));
 	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 19/21] radio-sf16fmi: clamp frequency.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (17 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 18/21] radio-sf16fmi: add device_caps support to querycap Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 20/21] radio-sf16fmi: convert to the control framework Hans Verkuil
  2013-05-31 10:02 ` [PATCH 21/21] radio-sf16fmi: add control event and prio support Hans Verkuil
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Ondrej Zary

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Ondrej Zary <linux@rainbow-software.org>
---
 drivers/media/radio/radio-sf16fmi.c |   11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 80beda7..9cd0338 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -55,8 +55,8 @@ static struct fmi fmi_card;
 static struct pnp_dev *dev;
 bool pnp_attached;
 
-#define RSF16_MINFREQ (87 * 16000)
-#define RSF16_MAXFREQ (108 * 16000)
+#define RSF16_MINFREQ (87U * 16000)
+#define RSF16_MAXFREQ (108U * 16000)
 
 #define FMI_BIT_TUN_CE		(1 << 0)
 #define FMI_BIT_TUN_CLK		(1 << 1)
@@ -155,15 +155,14 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 					const struct v4l2_frequency *f)
 {
 	struct fmi *fmi = video_drvdata(file);
+	unsigned freq = f->frequency;
 
 	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
 		return -EINVAL;
-	if (f->frequency < RSF16_MINFREQ ||
-			f->frequency > RSF16_MAXFREQ)
-		return -EINVAL;
+	clamp(freq, RSF16_MINFREQ, RSF16_MAXFREQ);
 	/* rounding in steps of 800 to match the freq
 	   that will be used */
-	lm7000_set_freq((f->frequency / 800) * 800, fmi, fmi_set_pins);
+	lm7000_set_freq((freq / 800) * 800, fmi, fmi_set_pins);
 	return 0;
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 20/21] radio-sf16fmi: convert to the control framework.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (18 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 19/21] radio-sf16fmi: clamp frequency Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  2013-05-31 10:02 ` [PATCH 21/21] radio-sf16fmi: add control event and prio support Hans Verkuil
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Ondrej Zary

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Ondrej Zary <linux@rainbow-software.org>
---
 drivers/media/radio/radio-sf16fmi.c |   56 ++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 31 deletions(-)

diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 9cd0338..b058f36 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -27,6 +27,7 @@
 #include <linux/io.h>		/* outb, outb_p			*/
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
 #include "lm7000.h"
 
 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
@@ -44,6 +45,7 @@ module_param(radio_nr, int, 0);
 struct fmi
 {
 	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler hdl;
 	struct video_device vdev;
 	int io;
 	bool mute;
@@ -178,46 +180,26 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 	return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
+static int fmi_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct fmi *fmi = video_drvdata(file);
+	struct fmi *fmi = container_of(ctrl->handler, struct fmi, hdl);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = fmi->mute;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct fmi *fmi = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
+		if (ctrl->val)
 			fmi_mute(fmi);
 		else
 			fmi_unmute(fmi);
-		fmi->mute = ctrl->value;
+		fmi->mute = ctrl->val;
 		return 0;
 	}
 	return -EINVAL;
 }
 
+static const struct v4l2_ctrl_ops fmi_ctrl_ops = {
+	.s_ctrl = fmi_s_ctrl,
+};
+
 static const struct v4l2_file_operations fmi_fops = {
 	.owner		= THIS_MODULE,
 	.unlocked_ioctl	= video_ioctl2,
@@ -229,9 +211,6 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
 	.vidioc_s_tuner     = vidioc_s_tuner,
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 /* ladis: this is my card. does any other types exist? */
@@ -281,6 +260,7 @@ static int __init fmi_init(void)
 {
 	struct fmi *fmi = &fmi_card;
 	struct v4l2_device *v4l2_dev = &fmi->v4l2_dev;
+	struct v4l2_ctrl_handler *hdl = &fmi->hdl;
 	int res, i;
 	int probe_ports[] = { 0, 0x284, 0x384 };
 
@@ -333,6 +313,18 @@ static int __init fmi_init(void)
 		return res;
 	}
 
+	v4l2_ctrl_handler_init(hdl, 1);
+	v4l2_ctrl_new_std(hdl, &fmi_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	v4l2_dev->ctrl_handler = hdl;
+	if (hdl->error) {
+		res = hdl->error;
+		v4l2_err(v4l2_dev, "Could not register controls\n");
+		v4l2_ctrl_handler_free(hdl);
+		v4l2_device_unregister(v4l2_dev);
+		return res;
+	}
+
 	strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
 	fmi->vdev.v4l2_dev = v4l2_dev;
 	fmi->vdev.fops = &fmi_fops;
@@ -346,6 +338,7 @@ static int __init fmi_init(void)
 	fmi_mute(fmi);
 
 	if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+		v4l2_ctrl_handler_free(hdl);
 		v4l2_device_unregister(v4l2_dev);
 		release_region(fmi->io, 2);
 		if (pnp_attached)
@@ -361,6 +354,7 @@ static void __exit fmi_exit(void)
 {
 	struct fmi *fmi = &fmi_card;
 
+	v4l2_ctrl_handler_free(&fmi->hdl);
 	video_unregister_device(&fmi->vdev);
 	v4l2_device_unregister(&fmi->v4l2_dev);
 	release_region(fmi->io, 2);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 21/21] radio-sf16fmi: add control event and prio support.
  2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
                   ` (19 preceding siblings ...)
  2013-05-31 10:02 ` [PATCH 20/21] radio-sf16fmi: convert to the control framework Hans Verkuil
@ 2013-05-31 10:02 ` Hans Verkuil
  20 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-05-31 10:02 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Ondrej Zary

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Ondrej Zary <linux@rainbow-software.org>
---
 drivers/media/radio/radio-sf16fmi.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index b058f36..9e712c8 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -28,6 +28,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 #include "lm7000.h"
 
 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
@@ -202,6 +203,9 @@ static const struct v4l2_ctrl_ops fmi_ctrl_ops = {
 
 static const struct v4l2_file_operations fmi_fops = {
 	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
 	.unlocked_ioctl	= video_ioctl2,
 };
 
@@ -211,6 +215,9 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
 	.vidioc_s_tuner     = vidioc_s_tuner,
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_log_status  = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 /* ladis: this is my card. does any other types exist? */
@@ -330,6 +337,7 @@ static int __init fmi_init(void)
 	fmi->vdev.fops = &fmi_fops;
 	fmi->vdev.ioctl_ops = &fmi_ioctl_ops;
 	fmi->vdev.release = video_device_release_empty;
+	set_bit(V4L2_FL_USE_FH_PRIO, &fmi->vdev.flags);
 	video_set_drvdata(&fmi->vdev, fmi);
 
 	mutex_init(&fmi->lock);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 02/21] sr030pc30: convert to the control framework.
  2013-05-31 10:02 ` [PATCH 02/21] sr030pc30: " Hans Verkuil
@ 2013-05-31 10:38   ` Sylwester Nawrocki
  0 siblings, 0 replies; 25+ messages in thread
From: Sylwester Nawrocki @ 2013-05-31 10:38 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Hans Verkuil

On 05/31/2013 12:02 PM, Hans Verkuil wrote:
> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: Sylwester Nawrocki <sylvester.nawrocki@gmail.com>

Acked-by: Sylwester Nawrocki <s.nawrocki@samsung.com>

> ---
>  drivers/media/i2c/sr030pc30.c |  276 +++++++++++++----------------------------
>  1 file changed, 88 insertions(+), 188 deletions(-)
> 
> diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
> index 4c5a9ee..ae94326 100644
> --- a/drivers/media/i2c/sr030pc30.c
> +++ b/drivers/media/i2c/sr030pc30.c
> @@ -23,6 +23,7 @@
>  #include <media/v4l2-device.h>
>  #include <media/v4l2-subdev.h>
>  #include <media/v4l2-mediabus.h>
> +#include <media/v4l2-ctrls.h>
>  #include <media/sr030pc30.h>
>  
>  static int debug;
> @@ -142,17 +143,24 @@ module_param(debug, int, 0644);
>  
>  struct sr030pc30_info {
>  	struct v4l2_subdev sd;
> +	struct v4l2_ctrl_handler hdl;
>  	const struct sr030pc30_platform_data *pdata;
>  	const struct sr030pc30_format *curr_fmt;
>  	const struct sr030pc30_frmsize *curr_win;
> -	unsigned int auto_wb:1;
> -	unsigned int auto_exp:1;
>  	unsigned int hflip:1;
>  	unsigned int vflip:1;
>  	unsigned int sleep:1;
> -	unsigned int exposure;
> -	u8 blue_balance;
> -	u8 red_balance;
> +	struct {
> +		/* auto whitebalance control cluster */
> +		struct v4l2_ctrl *awb;
> +		struct v4l2_ctrl *red;
> +		struct v4l2_ctrl *blue;
> +	};
> +	struct {
> +		/* auto exposure control cluster */
> +		struct v4l2_ctrl *autoexp;
> +		struct v4l2_ctrl *exp;
> +	};
>  	u8 i2c_reg_page;
>  };
>  
> @@ -173,52 +181,6 @@ struct i2c_regval {
>  	u16 val;
>  };
>  
> -static const struct v4l2_queryctrl sr030pc30_ctrl[] = {
> -	{
> -		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
> -		.type		= V4L2_CTRL_TYPE_BOOLEAN,
> -		.name		= "Auto White Balance",
> -		.minimum	= 0,
> -		.maximum	= 1,
> -		.step		= 1,
> -		.default_value	= 1,
> -	}, {
> -		.id		= V4L2_CID_RED_BALANCE,
> -		.type		= V4L2_CTRL_TYPE_INTEGER,
> -		.name		= "Red Balance",
> -		.minimum	= 0,
> -		.maximum	= 127,
> -		.step		= 1,
> -		.default_value	= 64,
> -		.flags		= 0,
> -	}, {
> -		.id		= V4L2_CID_BLUE_BALANCE,
> -		.type		= V4L2_CTRL_TYPE_INTEGER,
> -		.name		= "Blue Balance",
> -		.minimum	= 0,
> -		.maximum	= 127,
> -		.step		= 1,
> -		.default_value	= 64,
> -	}, {
> -		.id		= V4L2_CID_EXPOSURE_AUTO,
> -		.type		= V4L2_CTRL_TYPE_INTEGER,
> -		.name		= "Auto Exposure",
> -		.minimum	= 0,
> -		.maximum	= 1,
> -		.step		= 1,
> -		.default_value	= 1,
> -	}, {
> -		.id		= V4L2_CID_EXPOSURE,
> -		.type		= V4L2_CTRL_TYPE_INTEGER,
> -		.name		= "Exposure",
> -		.minimum	= EXPOS_MIN_MS,
> -		.maximum	= EXPOS_MAX_MS,
> -		.step		= 1,
> -		.default_value	= 1,
> -	}, {
> -	}
> -};
> -
>  /* supported resolutions */
>  static const struct sr030pc30_frmsize sr030pc30_sizes[] = {
>  	{
> @@ -394,48 +356,6 @@ static int sr030pc30_pwr_ctrl(struct v4l2_subdev *sd,
>  	return ret;
>  }
>  
> -static inline int sr030pc30_enable_autoexposure(struct v4l2_subdev *sd, int on)
> -{
> -	struct sr030pc30_info *info = to_sr030pc30(sd);
> -	/* auto anti-flicker is also enabled here */
> -	int ret = cam_i2c_write(sd, AE_CTL1_REG, on ? 0xDC : 0x0C);
> -	if (!ret)
> -		info->auto_exp = on;
> -	return ret;
> -}
> -
> -static int sr030pc30_set_exposure(struct v4l2_subdev *sd, int value)
> -{
> -	struct sr030pc30_info *info = to_sr030pc30(sd);
> -
> -	unsigned long expos = value * info->pdata->clk_rate / (8 * 1000);
> -
> -	int ret = cam_i2c_write(sd, EXP_TIMEH_REG, expos >> 16 & 0xFF);
> -	if (!ret)
> -		ret = cam_i2c_write(sd, EXP_TIMEM_REG, expos >> 8 & 0xFF);
> -	if (!ret)
> -		ret = cam_i2c_write(sd, EXP_TIMEL_REG, expos & 0xFF);
> -	if (!ret) { /* Turn off AE */
> -		info->exposure = value;
> -		ret = sr030pc30_enable_autoexposure(sd, 0);
> -	}
> -	return ret;
> -}
> -
> -/* Automatic white balance control */
> -static int sr030pc30_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
> -{
> -	struct sr030pc30_info *info = to_sr030pc30(sd);
> -
> -	int ret = cam_i2c_write(sd, AWB_CTL2_REG, on ? 0x2E : 0x2F);
> -	if (!ret)
> -		ret = cam_i2c_write(sd, AWB_CTL1_REG, on ? 0xFB : 0x7B);
> -	if (!ret)
> -		info->auto_wb = on;
> -
> -	return ret;
> -}
> -
>  static int sr030pc30_set_flip(struct v4l2_subdev *sd)
>  {
>  	struct sr030pc30_info *info = to_sr030pc30(sd);
> @@ -498,107 +418,56 @@ static int sr030pc30_try_frame_size(struct v4l2_mbus_framefmt *mf)
>  	return -EINVAL;
>  }
>  
> -static int sr030pc30_queryctrl(struct v4l2_subdev *sd,
> -			       struct v4l2_queryctrl *qc)
> -{
> -	int i;
> -
> -	for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
> -		if (qc->id == sr030pc30_ctrl[i].id) {
> -			*qc = sr030pc30_ctrl[i];
> -			v4l2_dbg(1, debug, sd, "%s id: %d\n",
> -				 __func__, qc->id);
> -			return 0;
> -		}
> -
> -	return -EINVAL;
> -}
> -
> -static inline int sr030pc30_set_bluebalance(struct v4l2_subdev *sd, int value)
> -{
> -	int ret = cam_i2c_write(sd, MWB_BGAIN_REG, value);
> -	if (!ret)
> -		to_sr030pc30(sd)->blue_balance = value;
> -	return ret;
> -}
> -
> -static inline int sr030pc30_set_redbalance(struct v4l2_subdev *sd, int value)
> -{
> -	int ret = cam_i2c_write(sd, MWB_RGAIN_REG, value);
> -	if (!ret)
> -		to_sr030pc30(sd)->red_balance = value;
> -	return ret;
> -}
> -
> -static int sr030pc30_s_ctrl(struct v4l2_subdev *sd,
> -			    struct v4l2_control *ctrl)
> +static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl)
>  {
> -	int i, ret = 0;
> -
> -	for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
> -		if (ctrl->id == sr030pc30_ctrl[i].id)
> -			break;
> -
> -	if (i == ARRAY_SIZE(sr030pc30_ctrl))
> -		return -EINVAL;
> -
> -	if (ctrl->value < sr030pc30_ctrl[i].minimum ||
> -		ctrl->value > sr030pc30_ctrl[i].maximum)
> -			return -ERANGE;
> +	struct sr030pc30_info *info =
> +		container_of(ctrl->handler, struct sr030pc30_info, hdl);
> +	struct v4l2_subdev *sd = &info->sd;
> +	int ret = 0;
>  
>  	v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
> -			 __func__, ctrl->id, ctrl->value);
> +			 __func__, ctrl->id, ctrl->val);
>  
>  	switch (ctrl->id) {
>  	case V4L2_CID_AUTO_WHITE_BALANCE:
> -		sr030pc30_enable_autowhitebalance(sd, ctrl->value);
> -		break;
> -	case V4L2_CID_BLUE_BALANCE:
> -		ret = sr030pc30_set_bluebalance(sd, ctrl->value);
> -		break;
> -	case V4L2_CID_RED_BALANCE:
> -		ret = sr030pc30_set_redbalance(sd, ctrl->value);
> -		break;
> -	case V4L2_CID_EXPOSURE_AUTO:
> -		sr030pc30_enable_autoexposure(sd,
> -			ctrl->value == V4L2_EXPOSURE_AUTO);
> -		break;
> -	case V4L2_CID_EXPOSURE:
> -		ret = sr030pc30_set_exposure(sd, ctrl->value);
> -		break;
> -	default:
> -		return -EINVAL;
> -	}
> -
> -	return ret;
> -}
> -
> -static int sr030pc30_g_ctrl(struct v4l2_subdev *sd,
> -			    struct v4l2_control *ctrl)
> -{
> -	struct sr030pc30_info *info = to_sr030pc30(sd);
> -
> -	v4l2_dbg(1, debug, sd, "%s: id: %d\n", __func__, ctrl->id);
> +		if (ctrl->is_new) {
> +			ret = cam_i2c_write(sd, AWB_CTL2_REG,
> +					ctrl->val ? 0x2E : 0x2F);
> +			if (!ret)
> +				ret = cam_i2c_write(sd, AWB_CTL1_REG,
> +						ctrl->val ? 0xFB : 0x7B);
> +		}
> +		if (!ret && info->blue->is_new)
> +			ret = cam_i2c_write(sd, MWB_BGAIN_REG, info->blue->val);
> +		if (!ret && info->red->is_new)
> +			ret = cam_i2c_write(sd, MWB_RGAIN_REG, info->red->val);
> +		return ret;
>  
> -	switch (ctrl->id) {
> -	case V4L2_CID_AUTO_WHITE_BALANCE:
> -		ctrl->value = info->auto_wb;
> -		break;
> -	case V4L2_CID_BLUE_BALANCE:
> -		ctrl->value = info->blue_balance;
> -		break;
> -	case V4L2_CID_RED_BALANCE:
> -		ctrl->value = info->red_balance;
> -		break;
>  	case V4L2_CID_EXPOSURE_AUTO:
> -		ctrl->value = info->auto_exp;
> -		break;
> -	case V4L2_CID_EXPOSURE:
> -		ctrl->value = info->exposure;
> -		break;
> +		/* auto anti-flicker is also enabled here */
> +		if (ctrl->is_new)
> +			ret = cam_i2c_write(sd, AE_CTL1_REG,
> +				ctrl->val == V4L2_EXPOSURE_AUTO ? 0xDC : 0x0C);
> +		if (info->exp->is_new) {
> +			unsigned long expos = info->exp->val;
> +
> +			expos = expos * info->pdata->clk_rate / (8 * 1000);
> +
> +			if (!ret)
> +				ret = cam_i2c_write(sd, EXP_TIMEH_REG,
> +						expos >> 16 & 0xFF);
> +			if (!ret)
> +				ret = cam_i2c_write(sd, EXP_TIMEM_REG,
> +						expos >> 8 & 0xFF);
> +			if (!ret)
> +				ret = cam_i2c_write(sd, EXP_TIMEL_REG,
> +						expos & 0xFF);
> +		}
> +		return ret;
>  	default:
>  		return -EINVAL;
>  	}
> +
>  	return 0;
>  }
>  
> @@ -752,11 +621,19 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
>  	return ret;
>  }
>  
> +static const struct v4l2_ctrl_ops sr030pc30_ctrl_ops = {
> +	.s_ctrl = sr030pc30_s_ctrl,
> +};
> +
>  static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
>  	.s_power	= sr030pc30_s_power,
> -	.queryctrl	= sr030pc30_queryctrl,
> -	.s_ctrl		= sr030pc30_s_ctrl,
> -	.g_ctrl		= sr030pc30_g_ctrl,
> +	.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 const struct v4l2_subdev_video_ops sr030pc30_video_ops = {
> @@ -807,6 +684,7 @@ static int sr030pc30_probe(struct i2c_client *client,
>  {
>  	struct sr030pc30_info *info;
>  	struct v4l2_subdev *sd;
> +	struct v4l2_ctrl_handler *hdl;
>  	const struct sr030pc30_platform_data *pdata
>  		= client->dev.platform_data;
>  	int ret;
> @@ -830,10 +708,31 @@ static int sr030pc30_probe(struct i2c_client *client,
>  
>  	v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops);
>  
> +	hdl = &info->hdl;
> +	v4l2_ctrl_handler_init(hdl, 6);
> +	info->awb = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
> +			V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
> +	info->red = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
> +			V4L2_CID_RED_BALANCE, 0, 127, 1, 64);
> +	info->blue = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
> +			V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64);
> +	info->autoexp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
> +			V4L2_CID_EXPOSURE_AUTO, 0, 1, 1, 1);
> +	info->exp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
> +			V4L2_CID_EXPOSURE, EXPOS_MIN_MS, EXPOS_MAX_MS, 1, 30);
> +	sd->ctrl_handler = hdl;
> +	if (hdl->error) {
> +		int err = hdl->error;
> +
> +		v4l2_ctrl_handler_free(hdl);
> +		return err;
> +	}
> +	v4l2_ctrl_auto_cluster(3, &info->awb, 0, false);
> +	v4l2_ctrl_auto_cluster(2, &info->autoexp, V4L2_EXPOSURE_MANUAL, false);
> +	v4l2_ctrl_handler_setup(hdl);
> +
>  	info->i2c_reg_page	= -1;
>  	info->hflip		= 1;
> -	info->auto_exp		= 1;
> -	info->exposure		= 30;
>  
>  	return 0;
>  }
> @@ -843,6 +742,7 @@ static int sr030pc30_remove(struct i2c_client *client)
>  	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>  
>  	v4l2_device_unregister_subdev(sd);
> +	v4l2_ctrl_handler_free(sd->ctrl_handler);
>  	return 0;
>  }

--
Thanks & Regards,
Sylwester

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [BUG] [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range AND [PATCH 15/21] tef6862: clamp frequency.
  2013-05-31 10:02 ` [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range Hans Verkuil
@ 2013-10-28 11:45   ` Hans Petter Selasky
  2013-11-04  9:15     ` Hans Verkuil
  0 siblings, 1 reply; 25+ messages in thread
From: Hans Petter Selasky @ 2013-10-28 11:45 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Hans Verkuil, Fabio Belavenuto

On 05/31/13 12:02, Hans Verkuil wrote:
>   		return -EINVAL;
> +	}
> +	clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
>   	tea5764_power_up(radio);
> -	tea5764_tune(radio, (f->frequency * 125) / 2);
> +	tea5764_tune(radio, (freq * 125) / 2);
>   	return 0;

Hi Hans,

Should the part quoted above part perhaps read:

freq = clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);

Or did "#define clamp() change" recently?

http://lxr.free-electrons.com/source/include/linux/kernel.h

> 698 /**
> 699  * clamp - return a value clamped to a given range with strict typechecking
> 700  * @val: current value
> 701  * @min: minimum allowable value
> 702  * @max: maximum allowable value
> 703  *
> 704  * This macro does strict typechecking of min/max to make sure they are of the
> 705  * same type as val.  See the unnecessary pointer comparisons.
> 706  */
> 707 #define clamp(val, min, max) ({                 \
> 708         typeof(val) __val = (val);              \
> 709         typeof(min) __min = (min);              \
> 710         typeof(max) __max = (max);              \
> 711         (void) (&__val == &__min);              \
> 712         (void) (&__val == &__max);              \
> 713         __val = __val < __min ? __min: __val;   \
> 714         __val > __max ? __max: __val; })

Thank you!

Same spotted in:

>> media_tree/drivers/media/radio/radio-tea5764.c: In function 'vidioc_s_frequency':
>> media_tree/drivers/media/radio/radio-tea5764.c:359: warning: statement with no effect
>
>> media_tree/drivers/media/radio/tef6862.c: In function 'tef6862_s_frequency':
>> media_tree/drivers/media/radio/tef6862.c:115: warning: statement with no effect

Keep up the good work!

--HPS

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [BUG] [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range AND [PATCH 15/21] tef6862: clamp frequency.
  2013-10-28 11:45   ` [BUG] [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range AND [PATCH 15/21] tef6862: clamp frequency Hans Petter Selasky
@ 2013-11-04  9:15     ` Hans Verkuil
  0 siblings, 0 replies; 25+ messages in thread
From: Hans Verkuil @ 2013-11-04  9:15 UTC (permalink / raw)
  To: Hans Petter Selasky; +Cc: linux-media, Hans Verkuil, Fabio Belavenuto

Hi Hans,

On 10/28/2013 12:45 PM, Hans Petter Selasky wrote:
> On 05/31/13 12:02, Hans Verkuil wrote:
>>   		return -EINVAL;
>> +	}
>> +	clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
>>   	tea5764_power_up(radio);
>> -	tea5764_tune(radio, (f->frequency * 125) / 2);
>> +	tea5764_tune(radio, (freq * 125) / 2);
>>   	return 0;
> 
> Hi Hans,
> 
> Should the part quoted above part perhaps read:
> 
> freq = clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
> 
> Or did "#define clamp() change" recently?

Nope, that's a bug. Thanks for spotting this!

I'll make a patch for this.

Regards,

	Hans

> 
> http://lxr.free-electrons.com/source/include/linux/kernel.h
> 
>> 698 /**
>> 699  * clamp - return a value clamped to a given range with strict typechecking
>> 700  * @val: current value
>> 701  * @min: minimum allowable value
>> 702  * @max: maximum allowable value
>> 703  *
>> 704  * This macro does strict typechecking of min/max to make sure they are of the
>> 705  * same type as val.  See the unnecessary pointer comparisons.
>> 706  */
>> 707 #define clamp(val, min, max) ({                 \
>> 708         typeof(val) __val = (val);              \
>> 709         typeof(min) __min = (min);              \
>> 710         typeof(max) __max = (max);              \
>> 711         (void) (&__val == &__min);              \
>> 712         (void) (&__val == &__max);              \
>> 713         __val = __val < __min ? __min: __val;   \
>> 714         __val > __max ? __max: __val; })
> 
> Thank you!
> 
> Same spotted in:
> 
>>> media_tree/drivers/media/radio/radio-tea5764.c: In function 'vidioc_s_frequency':
>>> media_tree/drivers/media/radio/radio-tea5764.c:359: warning: statement with no effect
>>
>>> media_tree/drivers/media/radio/tef6862.c: In function 'tef6862_s_frequency':
>>> media_tree/drivers/media/radio/tef6862.c:115: warning: statement with no effect
> 
> Keep up the good work!
> 
> --HPS
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2013-11-04  9:15 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-31 10:02 [PATCH 00/21] Control framework conversions Hans Verkuil
2013-05-31 10:02 ` [PATCH 01/21] saa7706h: convert to the control framework Hans Verkuil
2013-05-31 10:02 ` [PATCH 02/21] sr030pc30: " Hans Verkuil
2013-05-31 10:38   ` Sylwester Nawrocki
2013-05-31 10:02 ` [PATCH 03/21] saa6752hs: " Hans Verkuil
2013-05-31 10:02 ` [PATCH 04/21] radio-tea5764: add support for struct v4l2_device Hans Verkuil
2013-05-31 10:02 ` [PATCH 05/21] radio-tea5764: embed struct video_device Hans Verkuil
2013-05-31 10:02 ` [PATCH 06/21] radio-tea5764: convert to the control framework Hans Verkuil
2013-05-31 10:02 ` [PATCH 07/21] radio-tea5764: audio and input ioctls do not apply to radio devices Hans Verkuil
2013-05-31 10:02 ` [PATCH 08/21] radio-tea5764: add device_caps support Hans Verkuil
2013-05-31 10:02 ` [PATCH 09/21] radio-tea5764: add prio and control event support Hans Verkuil
2013-05-31 10:02 ` [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range Hans Verkuil
2013-10-28 11:45   ` [BUG] [PATCH 10/21] radio-tea5764: some cleanups and clamp frequency when out-of-range AND [PATCH 15/21] tef6862: clamp frequency Hans Petter Selasky
2013-11-04  9:15     ` Hans Verkuil
2013-05-31 10:02 ` [PATCH 11/21] radio-timb: add device_caps support, remove input/audio ioctls Hans Verkuil
2013-05-31 10:02 ` [PATCH 12/21] radio-timb: convert to the control framework Hans Verkuil
2013-05-31 10:02 ` [PATCH 13/21] radio-timb: actually load the requested subdevs Hans Verkuil
2013-05-31 10:02 ` [PATCH 14/21] radio-timb: add control events and prio support Hans Verkuil
2013-05-31 10:02 ` [PATCH 15/21] tef6862: clamp frequency Hans Verkuil
2013-05-31 10:02 ` [PATCH 16/21] timblogiw: fix querycap Hans Verkuil
2013-05-31 10:02 ` [PATCH 17/21] radio-sf16fmi: remove audio/input ioctls Hans Verkuil
2013-05-31 10:02 ` [PATCH 18/21] radio-sf16fmi: add device_caps support to querycap Hans Verkuil
2013-05-31 10:02 ` [PATCH 19/21] radio-sf16fmi: clamp frequency Hans Verkuil
2013-05-31 10:02 ` [PATCH 20/21] radio-sf16fmi: convert to the control framework Hans Verkuil
2013-05-31 10:02 ` [PATCH 21/21] radio-sf16fmi: add control event and prio support Hans Verkuil

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.