V4L/DVB (10728): adv7175: convert to v4l2-subdev.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 154dff0..318c305 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -30,15 +30,26 @@
 #include <asm/uaccess.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
-#include <linux/videodev.h>
-#include <linux/video_encoder.h>
-#include <media/v4l2-common.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
+#define   I2C_ADV7175        0xd4
+#define   I2C_ADV7176        0x54
+
+static unsigned short normal_i2c[] = {
+	I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
+	I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1,
+	I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -46,34 +57,38 @@
 /* ----------------------------------------------------------------------- */
 
 struct adv7175 {
+	struct v4l2_subdev sd;
 	v4l2_std_id norm;
 	int input;
-	int bright;
-	int contrast;
-	int hue;
-	int sat;
 };
 
-#define   I2C_ADV7175        0xd4
-#define   I2C_ADV7176        0x54
+static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7175, sd);
+}
 
 static char *inputs[] = { "pass_through", "play_back", "color_bar" };
 
 /* ----------------------------------------------------------------------- */
 
-static inline int adv7175_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
 	return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int adv7175_read(struct i2c_client *client, u8 reg)
+static inline int adv7175_read(struct v4l2_subdev *sd, u8 reg)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
 	return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int adv7175_write_block(struct i2c_client *client,
+static int adv7175_write_block(struct v4l2_subdev *sd,
 		     const u8 *data, unsigned int len)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	int ret = -1;
 	u8 reg;
 
@@ -101,7 +116,7 @@
 		/* do some slow I2C emulation kind of thing */
 		while (len >= 2) {
 			reg = *data++;
-			ret = adv7175_write(client, reg, *data++);
+			ret = adv7175_write(sd, reg, *data++);
 			if (ret < 0)
 				break;
 			len -= 2;
@@ -111,18 +126,18 @@
 	return ret;
 }
 
-static void set_subcarrier_freq(struct i2c_client *client, int pass_through)
+static void set_subcarrier_freq(struct v4l2_subdev *sd, int pass_through)
 {
 	/* for some reason pass_through NTSC needs
 	 * a different sub-carrier freq to remain stable. */
 	if (pass_through)
-		adv7175_write(client, 0x02, 0x00);
+		adv7175_write(sd, 0x02, 0x00);
 	else
-		adv7175_write(client, 0x02, 0x55);
+		adv7175_write(sd, 0x02, 0x55);
 
-	adv7175_write(client, 0x03, 0x55);
-	adv7175_write(client, 0x04, 0x55);
-	adv7175_write(client, 0x05, 0x25);
+	adv7175_write(sd, 0x03, 0x55);
+	adv7175_write(sd, 0x04, 0x55);
+	adv7175_write(sd, 0x05, 0x25);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -182,144 +197,148 @@
 	0x06, 0x1a,		/* subc. phase */
 };
 
-static int adv7175_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int adv7175_init(struct v4l2_subdev *sd, u32 val)
 {
-	struct adv7175 *encoder = i2c_get_clientdata(client);
+	/* This is just for testing!!! */
+	adv7175_write_block(sd, init_common, sizeof(init_common));
+	adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+	adv7175_write(sd, 0x07, TR0MODE);
+	return 0;
+}
 
-	switch (cmd) {
-	case VIDIOC_INT_INIT:
-		/* This is just for testing!!! */
-		adv7175_write_block(client, init_common,
-				    sizeof(init_common));
-		adv7175_write(client, 0x07, TR0MODE | TR0RST);
-		adv7175_write(client, 0x07, TR0MODE);
-		break;
+static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7175 *encoder = to_adv7175(sd);
 
-	case VIDIOC_INT_S_STD_OUTPUT:
-	{
-		v4l2_std_id iarg = *(v4l2_std_id *) arg;
-
-		if (iarg & V4L2_STD_NTSC) {
-			adv7175_write_block(client, init_ntsc,
-					    sizeof(init_ntsc));
-			if (encoder->input == 0)
-				adv7175_write(client, 0x0d, 0x4f);	// Enable genlock
-			adv7175_write(client, 0x07, TR0MODE | TR0RST);
-			adv7175_write(client, 0x07, TR0MODE);
-		} else if (iarg & V4L2_STD_PAL) {
-			adv7175_write_block(client, init_pal,
-					    sizeof(init_pal));
-			if (encoder->input == 0)
-				adv7175_write(client, 0x0d, 0x4f);	// Enable genlock
-			adv7175_write(client, 0x07, TR0MODE | TR0RST);
-			adv7175_write(client, 0x07, TR0MODE);
-		} else if (iarg & V4L2_STD_SECAM) {
-			/* This is an attempt to convert
-			 * SECAM->PAL (typically it does not work
-			 * due to genlock: when decoder is in SECAM
-			 * and encoder in in PAL the subcarrier can
-			 * not be syncronized with horizontal
-			 * quency) */
-			adv7175_write_block(client, init_pal,
-					    sizeof(init_pal));
-			if (encoder->input == 0)
-				adv7175_write(client, 0x0d, 0x49);	// Disable genlock
-			adv7175_write(client, 0x07, TR0MODE | TR0RST);
-			adv7175_write(client, 0x07, TR0MODE);
-		} else {
-			v4l_dbg(1, debug, client, "illegal norm: %llx\n", iarg);
-			return -EINVAL;
-		}
-		v4l_dbg(1, debug, client, "switched to %llx\n", iarg);
-		encoder->norm = iarg;
-		break;
-	}
-
-	case VIDIOC_INT_S_VIDEO_ROUTING:
-	{
-		struct v4l2_routing *route = arg;
-
-		/* RJ: *iarg = 0: input is from SAA7110
-		 *iarg = 1: input is from ZR36060
-		 *iarg = 2: color bar */
-
-		switch (route->input) {
-		case 0:
-			adv7175_write(client, 0x01, 0x00);
-
-			if (encoder->norm & V4L2_STD_NTSC)
-				set_subcarrier_freq(client, 1);
-
-			adv7175_write(client, 0x0c, TR1CAPT);	/* TR1 */
-			if (encoder->norm & V4L2_STD_SECAM)
-				adv7175_write(client, 0x0d, 0x49);	// Disable genlock
-			else
-				adv7175_write(client, 0x0d, 0x4f);	// Enable genlock
-			adv7175_write(client, 0x07, TR0MODE | TR0RST);
-			adv7175_write(client, 0x07, TR0MODE);
-			//udelay(10);
-			break;
-
-		case 1:
-			adv7175_write(client, 0x01, 0x00);
-
-			if (encoder->norm & V4L2_STD_NTSC)
-				set_subcarrier_freq(client, 0);
-
-			adv7175_write(client, 0x0c, TR1PLAY);	/* TR1 */
-			adv7175_write(client, 0x0d, 0x49);
-			adv7175_write(client, 0x07, TR0MODE | TR0RST);
-			adv7175_write(client, 0x07, TR0MODE);
-			/* udelay(10); */
-			break;
-
-		case 2:
-			adv7175_write(client, 0x01, 0x80);
-
-			if (encoder->norm & V4L2_STD_NTSC)
-				set_subcarrier_freq(client, 0);
-
-			adv7175_write(client, 0x0d, 0x49);
-			adv7175_write(client, 0x07, TR0MODE | TR0RST);
-			adv7175_write(client, 0x07, TR0MODE);
-			/* udelay(10); */
-			break;
-
-		default:
-			v4l_dbg(1, debug, client, "illegal input: %d\n", route->input);
-			return -EINVAL;
-		}
-		v4l_dbg(1, debug, client, "switched to %s\n", inputs[route->input]);
-		encoder->input = route->input;
-		break;
-	}
-
-	default:
+	if (std & V4L2_STD_NTSC) {
+		adv7175_write_block(sd, init_ntsc, sizeof(init_ntsc));
+		if (encoder->input == 0)
+			adv7175_write(sd, 0x0d, 0x4f);	/* Enable genlock */
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+	} else if (std & V4L2_STD_PAL) {
+		adv7175_write_block(sd, init_pal, sizeof(init_pal));
+		if (encoder->input == 0)
+			adv7175_write(sd, 0x0d, 0x4f);	/* Enable genlock */
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+	} else if (std & V4L2_STD_SECAM) {
+		/* This is an attempt to convert
+		 * SECAM->PAL (typically it does not work
+		 * due to genlock: when decoder is in SECAM
+		 * and encoder in in PAL the subcarrier can
+		 * not be syncronized with horizontal
+		 * quency) */
+		adv7175_write_block(sd, init_pal, sizeof(init_pal));
+		if (encoder->input == 0)
+			adv7175_write(sd, 0x0d, 0x49);	/* Disable genlock */
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+	} else {
+		v4l2_dbg(1, debug, sd, "illegal norm: %llx\n", std);
 		return -EINVAL;
 	}
-
+	v4l2_dbg(1, debug, sd, "switched to %llx\n", std);
+	encoder->norm = std;
 	return 0;
 }
 
+static int adv7175_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+	struct adv7175 *encoder = to_adv7175(sd);
+
+	/* RJ: route->input = 0: input is from decoder
+	   route->input = 1: input is from ZR36060
+	   route->input = 2: color bar */
+
+	switch (route->input) {
+	case 0:
+		adv7175_write(sd, 0x01, 0x00);
+
+		if (encoder->norm & V4L2_STD_NTSC)
+			set_subcarrier_freq(sd, 1);
+
+		adv7175_write(sd, 0x0c, TR1CAPT);	/* TR1 */
+		if (encoder->norm & V4L2_STD_SECAM)
+			adv7175_write(sd, 0x0d, 0x49);	/* Disable genlock */
+		else
+			adv7175_write(sd, 0x0d, 0x4f);	/* Enable genlock */
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+		/*udelay(10);*/
+		break;
+
+	case 1:
+		adv7175_write(sd, 0x01, 0x00);
+
+		if (encoder->norm & V4L2_STD_NTSC)
+			set_subcarrier_freq(sd, 0);
+
+		adv7175_write(sd, 0x0c, TR1PLAY);	/* TR1 */
+		adv7175_write(sd, 0x0d, 0x49);
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+		/* udelay(10); */
+		break;
+
+	case 2:
+		adv7175_write(sd, 0x01, 0x80);
+
+		if (encoder->norm & V4L2_STD_NTSC)
+			set_subcarrier_freq(sd, 0);
+
+		adv7175_write(sd, 0x0d, 0x49);
+		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		adv7175_write(sd, 0x07, TR0MODE);
+		/* udelay(10); */
+		break;
+
+	default:
+		v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
+		return -EINVAL;
+	}
+	v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
+	encoder->input = route->input;
+	return 0;
+}
+
+static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0);
+}
+
+static int adv7175_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+	return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
 /* ----------------------------------------------------------------------- */
 
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-static unsigned short normal_i2c[] = {
-	I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
-	I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1,
-	I2C_CLIENT_END
+static const struct v4l2_subdev_core_ops adv7175_core_ops = {
+	.g_chip_ident = adv7175_g_chip_ident,
+	.init = adv7175_init,
 };
 
-I2C_CLIENT_INSMOD;
+static const struct v4l2_subdev_video_ops adv7175_video_ops = {
+	.s_std_output = adv7175_s_std_output,
+	.s_routing = adv7175_s_routing,
+};
+
+static const struct v4l2_subdev_ops adv7175_ops = {
+	.core = &adv7175_core_ops,
+	.video = &adv7175_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
 
 static int adv7175_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
 	int i;
 	struct adv7175 *encoder;
+	struct v4l2_subdev *sd;
 
 	/* Check if the adapter supports the needed features */
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -331,25 +350,29 @@
 	encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
 	if (encoder == NULL)
 		return -ENOMEM;
+	sd = &encoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &adv7175_ops);
 	encoder->norm = V4L2_STD_NTSC;
 	encoder->input = 0;
-	i2c_set_clientdata(client, encoder);
 
-	i = adv7175_write_block(client, init_common, sizeof(init_common));
+	i = adv7175_write_block(sd, init_common, sizeof(init_common));
 	if (i >= 0) {
-		i = adv7175_write(client, 0x07, TR0MODE | TR0RST);
-		i = adv7175_write(client, 0x07, TR0MODE);
-		i = adv7175_read(client, 0x12);
-		v4l_dbg(1, debug, client, "revision %d\n", i & 1);
+		i = adv7175_write(sd, 0x07, TR0MODE | TR0RST);
+		i = adv7175_write(sd, 0x07, TR0MODE);
+		i = adv7175_read(sd, 0x12);
+		v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
 	}
 	if (i < 0)
-		v4l_dbg(1, debug, client, "init error 0x%x\n", i);
+		v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
 	return 0;
 }
 
 static int adv7175_remove(struct i2c_client *client)
 {
-	kfree(i2c_get_clientdata(client));
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_adv7175(sd));
 	return 0;
 }