The patch number 10726 was added via Hans Verkuil <[email protected]>
to http://linuxtv.org/hg/v4l-dvb master development tree.
Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel
If anyone has any objections, please let us know by sending a message to:
Linux Media Mailing List <[email protected]>
------
From: Hans Verkuil <[email protected]>
vpx3220: convert to v4l2_subdev.
Priority: normal
Signed-off-by: Hans Verkuil <[email protected]>
---
linux/drivers/media/video/vpx3220.c | 611 +++++++++++++-------------
linux/include/media/v4l2-chip-ident.h | 5
2 files changed, 324 insertions(+), 292 deletions(-)
diff -r b0e701960f26 -r 72a015cc3c73 linux/drivers/media/video/vpx3220.c
--- a/linux/drivers/media/video/vpx3220.c Thu Feb 19 17:24:47 2009 +0100
+++ b/linux/drivers/media/video/vpx3220.c Thu Feb 19 18:36:53 2009 +0100
@@ -24,11 +24,10 @@
#include <linux/types.h>
#include <asm/uaccess.h>
#include <linux/i2c.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>
-#include <linux/videodev.h>
-#include <linux/videodev2.h>
-#include <linux/video_decoder.h>
#include "compat.h"
MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
@@ -39,14 +38,20 @@ module_param(debug, int, 0);
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
+static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
#define VPX_TIMEOUT_COUNT 10
/* ----------------------------------------------------------------------- */
struct vpx3220 {
+ struct v4l2_subdev sd;
unsigned char reg[255];
v4l2_std_id norm;
+ int ident;
int input;
int enable;
int bright;
@@ -55,30 +60,38 @@ struct vpx3220 {
int sat;
};
+static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct vpx3220, sd);
+}
+
static char *inputs[] = { "internal", "composite", "svideo" };
/* ----------------------------------------------------------------------- */
-static inline int vpx3220_write(struct i2c_client *client, u8 reg, u8 value)
-{
+static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct vpx3220 *decoder = i2c_get_clientdata(client);
decoder->reg[reg] = value;
return i2c_smbus_write_byte_data(client, reg, value);
}
-static inline int vpx3220_read(struct i2c_client *client, u8 reg)
-{
+static inline int vpx3220_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 vpx3220_fp_status(struct i2c_client *client)
+static int vpx3220_fp_status(struct v4l2_subdev *sd)
{
unsigned char status;
unsigned int i;
for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
- status = vpx3220_read(client, 0x29);
+ status = vpx3220_read(sd, 0x29);
if (!(status & 4))
return 0;
@@ -92,57 +105,60 @@ static int vpx3220_fp_status(struct i2c_
return -1;
}
-static int vpx3220_fp_write(struct i2c_client *client, u8 fpaddr, u16 data)
-{
+static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
/* Write the 16-bit address to the FPWR register */
if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
- v4l_dbg(1, debug, client, "%s: failed\n", __func__);
+ v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
return -1;
}
- if (vpx3220_fp_status(client) < 0)
+ if (vpx3220_fp_status(sd) < 0)
return -1;
/* Write the 16-bit data to the FPDAT register */
if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
- v4l_dbg(1, debug, client, "%s: failed\n", __func__);
+ v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
return -1;
}
return 0;
}
-static u16 vpx3220_fp_read(struct i2c_client *client, u16 fpaddr)
-{
+static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
s16 data;
/* Write the 16-bit address to the FPRD register */
if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
- v4l_dbg(1, debug, client, "%s: failed\n", __func__);
+ v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
return -1;
}
- if (vpx3220_fp_status(client) < 0)
+ if (vpx3220_fp_status(sd) < 0)
return -1;
/* Read the 16-bit data from the FPDAT register */
data = i2c_smbus_read_word_data(client, 0x28);
if (data == -1) {
- v4l_dbg(1, debug, client, "%s: failed\n", __func__);
+ v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
return -1;
}
return swab16(data);
}
-static int vpx3220_write_block(struct i2c_client *client, const u8 *data,
unsigned int len)
+static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data,
unsigned int len)
{
u8 reg;
int ret = -1;
while (len >= 2) {
reg = *data++;
- ret = vpx3220_write(client, reg, *data++);
+ ret = vpx3220_write(sd, reg, *data++);
if (ret < 0)
break;
len -= 2;
@@ -151,7 +167,7 @@ static int vpx3220_write_block(struct i2
return ret;
}
-static int vpx3220_write_fp_block(struct i2c_client *client,
+static int vpx3220_write_fp_block(struct v4l2_subdev *sd,
const u16 *data, unsigned int len)
{
u8 reg;
@@ -159,7 +175,7 @@ static int vpx3220_write_fp_block(struct
while (len > 1) {
reg = *data++;
- ret |= vpx3220_fp_write(client, reg, *data++);
+ ret |= vpx3220_fp_write(sd, reg, *data++);
len -= 2;
}
@@ -262,294 +278,295 @@ static const unsigned short init_fp[] =
};
#if 0
-static void vpx3220_dump_i2c(struct i2c_client *client)
+static void vpx3220_dump_i2c(struct v4l2_subdev *sd)
{
int len = sizeof(init_common);
const unsigned char *data = init_common;
while (len > 1) {
- v4l_dbg(1, debug, client, "i2c reg 0x%02x data 0x%02x\n",
- *data, vpx3220_read(client, *data));
+ v4l2_dbg(1, debug, sd, "i2c reg 0x%02x data 0x%02x\n",
+ *data, vpx3220_read(sd, *data));
data += 2;
len -= 2;
}
}
#endif
-static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg)
-{
- struct vpx3220 *decoder = i2c_get_clientdata(client);
-
- switch (cmd) {
- case VIDIOC_INT_INIT:
- {
- vpx3220_write_block(client, init_common,
- sizeof(init_common));
- vpx3220_write_fp_block(client, init_fp,
- sizeof(init_fp) >> 1);
- if (decoder->norm & V4L2_STD_NTSC) {
- vpx3220_write_fp_block(client, init_ntsc,
- sizeof(init_ntsc) >> 1);
- } else if (decoder->norm & V4L2_STD_PAL) {
- vpx3220_write_fp_block(client, init_pal,
- sizeof(init_pal) >> 1);
- } else if (decoder->norm & V4L2_STD_SECAM) {
- vpx3220_write_fp_block(client, init_secam,
- sizeof(init_secam) >> 1);
- } else {
- vpx3220_write_fp_block(client, init_pal,
- sizeof(init_pal) >> 1);
+static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
+{
+ struct vpx3220 *decoder = to_vpx3220(sd);
+
+ vpx3220_write_block(sd, init_common, sizeof(init_common));
+ vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
+ if (decoder->norm & V4L2_STD_NTSC)
+ vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
+ else if (decoder->norm & V4L2_STD_PAL)
+ vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+ else if (decoder->norm & V4L2_STD_SECAM)
+ vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
+ else
+ vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+ return 0;
+}
+
+static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id
*pstd)
+{
+ int res = V4L2_IN_ST_NO_SIGNAL, status;
+ v4l2_std_id std = 0;
+
+ v4l2_dbg(1, debug, sd, "VIDIOC_QUERYSTD/VIDIOC_INT_G_INPUT_STATUS\n");
+
+ status = vpx3220_fp_read(sd, 0x0f3);
+
+ v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status);
+
+ if (status < 0)
+ return status;
+
+ if ((status & 0x20) == 0) {
+ res = 0;
+
+ switch (status & 0x18) {
+ case 0x00:
+ case 0x10:
+ case 0x14:
+ case 0x18:
+ std = V4L2_STD_PAL;
+ break;
+
+ case 0x08:
+ std = V4L2_STD_SECAM;
+ break;
+
+ case 0x04:
+ case 0x0c:
+ case 0x1c:
+ std = V4L2_STD_NTSC;
+ break;
}
- break;
- }
-
- case VIDIOC_QUERYSTD:
- case VIDIOC_INT_G_INPUT_STATUS:
- {
- int res = V4L2_IN_ST_NO_SIGNAL, status;
- v4l2_std_id std = 0;
-
- v4l_dbg(1, debug, client,
"VIDIOC_QUERYSTD/VIDIOC_INT_G_INPUT_STATUS\n");
-
- status = vpx3220_fp_read(client, 0x0f3);
-
- v4l_dbg(1, debug, client, "status: 0x%04x\n", status);
-
- if (status < 0)
- return status;
-
- if ((status & 0x20) == 0) {
- res = 0;
-
- switch (status & 0x18) {
- case 0x00:
- case 0x10:
- case 0x14:
- case 0x18:
- std = V4L2_STD_PAL;
- break;
-
- case 0x08:
- std = V4L2_STD_SECAM;
- break;
-
- case 0x04:
- case 0x0c:
- case 0x1c:
- std = V4L2_STD_NTSC;
- break;
- }
- }
-
- if (cmd == VIDIOC_QUERYSTD)
- *(v4l2_std_id *)arg = std;
- else
- *(int *)arg = res;
- break;
- }
-
- case VIDIOC_S_STD:
- {
- v4l2_std_id *iarg = arg;
- int temp_input;
-
- /* Here we back up the input selection because it gets
- overwritten when we fill the registers with the
- choosen video norm */
- temp_input = vpx3220_fp_read(client, 0xf2);
-
- v4l_dbg(1, debug, client, "VIDIOC_S_STD %llx\n", *iarg);
- if (*iarg & V4L2_STD_NTSC) {
- vpx3220_write_fp_block(client, init_ntsc,
- sizeof(init_ntsc) >> 1);
- v4l_dbg(1, debug, client, "norm switched to NTSC\n");
- } else if (*iarg & V4L2_STD_PAL) {
- vpx3220_write_fp_block(client, init_pal,
- sizeof(init_pal) >> 1);
- v4l_dbg(1, debug, client, "norm switched to PAL\n");
- } else if (*iarg & V4L2_STD_SECAM) {
- vpx3220_write_fp_block(client, init_secam,
- sizeof(init_secam) >> 1);
- v4l_dbg(1, debug, client, "norm switched to SECAM\n");
- } else {
- return -EINVAL;
- }
-
-#if 0
- case VIDEO_MODE_AUTO:
- /* FIXME This is only preliminary support */
- data = vpx3220_fp_read(client, 0xf2) & 0x20;
- vpx3220_fp_write(client, 0xf2, 0x00c0 | data);
- v4l_dbg(1, debug, client, "norm switched to AUTO\n");
- break;
-#endif
- decoder->norm = *iarg;
-
- /* And here we set the backed up video input again */
- vpx3220_fp_write(client, 0xf2, temp_input | 0x0010);
- udelay(10);
- break;
- }
-
- case VIDIOC_INT_S_VIDEO_ROUTING:
- {
- struct v4l2_routing *route = arg;
- int data;
-
- /* RJ: *iarg = 0: ST8 (PCTV) input
- *iarg = 1: COMPOSITE input
- *iarg = 2: SVHS input */
-
- const int input[3][2] = {
- {0x0c, 0},
- {0x0d, 0},
- {0x0e, 1}
- };
-
- if (route->input < 0 || route->input > 2)
- return -EINVAL;
-
- v4l_dbg(1, debug, client, "input switched to %s\n",
inputs[route->input]);
-
- vpx3220_write(client, 0x33, input[route->input][0]);
-
- data = vpx3220_fp_read(client, 0xf2) & ~(0x0020);
- if (data < 0)
- return data;
- /* 0x0010 is required to latch the setting */
- vpx3220_fp_write(client, 0xf2,
- data | (input[route->input][1] << 5) | 0x0010);
-
- udelay(10);
- break;
- }
-
- case VIDIOC_STREAMON:
- case VIDIOC_STREAMOFF:
- {
- int on = cmd == VIDIOC_STREAMON;
- v4l_dbg(1, debug, client, "VIDIOC_STREAM%s\n", on ? "ON" :
"OFF");
-
- vpx3220_write(client, 0xf2, (on ? 0x1b : 0x00));
- break;
- }
-
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
-
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
- break;
-
- case V4L2_CID_CONTRAST:
- v4l2_ctrl_query_fill(qc, 0, 63, 1, 32);
- break;
-
- case V4L2_CID_SATURATION:
- v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048);
- break;
-
- case V4L2_CID_HUE:
- v4l2_ctrl_query_fill(qc, -512, 511, 1, 0);
- break;
-
- default:
- return -EINVAL;
- }
- break;
- }
-
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = decoder->bright;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = decoder->contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = decoder->sat;
- break;
- case V4L2_CID_HUE:
- ctrl->value = decoder->hue;
- break;
- default:
- return -EINVAL;
- }
- break;
- }
-
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- if (decoder->bright != ctrl->value) {
- decoder->bright = ctrl->value;
- vpx3220_write(client, 0xe6, decoder->bright);
- }
- break;
- case V4L2_CID_CONTRAST:
- if (decoder->contrast != ctrl->value) {
- /* Bit 7 and 8 is for noise shaping */
- decoder->contrast = ctrl->value;
- vpx3220_write(client, 0xe7,
- decoder->contrast + 192);
- }
- break;
- case V4L2_CID_SATURATION:
- if (decoder->sat != ctrl->value) {
- decoder->sat = ctrl->value;
- vpx3220_fp_write(client, 0xa0, decoder->sat);
- }
- break;
- case V4L2_CID_HUE:
- if (decoder->hue != ctrl->value) {
- decoder->hue = ctrl->value;
- vpx3220_fp_write(client, 0x1c, decoder->hue);
- }
- break;
- default:
- return -EINVAL;
- }
- break;
- }
+ }
+ if (pstd)
+ *pstd = std;
+ if (pstatus)
+ *pstatus = status;
+ return 0;
+}
+
+static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ return vpx3220_status(sd, NULL, std);
+}
+
+static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+ return vpx3220_status(sd, status, NULL);
+}
+
+static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct vpx3220 *decoder = to_vpx3220(sd);
+ int temp_input;
+
+ /* Here we back up the input selection because it gets
+ overwritten when we fill the registers with the
+ choosen video norm */
+ temp_input = vpx3220_fp_read(sd, 0xf2);
+
+ v4l2_dbg(1, debug, sd, "VIDIOC_S_STD %llx\n", std);
+ if (std & V4L2_STD_NTSC) {
+ vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
+ v4l2_dbg(1, debug, sd, "norm switched to NTSC\n");
+ } else if (std & V4L2_STD_PAL) {
+ vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+ v4l2_dbg(1, debug, sd, "norm switched to PAL\n");
+ } else if (std & V4L2_STD_SECAM) {
+ vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
+ v4l2_dbg(1, debug, sd, "norm switched to SECAM\n");
+ } else {
+ return -EINVAL;
+ }
+
+ decoder->norm = std;
+
+ /* And here we set the backed up video input again */
+ vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010);
+ udelay(10);
+ return 0;
+}
+
+static int vpx3220_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing
*route)
+{
+ int data;
+
+ /* RJ: route->input = 0: ST8 (PCTV) input
+ route->input = 1: COMPOSITE input
+ route->input = 2: SVHS input */
+
+ const int input[3][2] = {
+ {0x0c, 0},
+ {0x0d, 0},
+ {0x0e, 1}
+ };
+
+ if (route->input < 0 || route->input > 2)
+ return -EINVAL;
+
+ v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[route->input]);
+
+ vpx3220_write(sd, 0x33, input[route->input][0]);
+
+ data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020);
+ if (data < 0)
+ return data;
+ /* 0x0010 is required to latch the setting */
+ vpx3220_fp_write(sd, 0xf2,
+ data | (input[route->input][1] << 5) | 0x0010);
+
+ udelay(10);
+ return 0;
+}
+
+static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ v4l2_dbg(1, debug, sd, "VIDIOC_STREAM%s\n", enable ? "ON" : "OFF");
+
+ vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00));
+ return 0;
+}
+
+static int vpx3220_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ v4l2_ctrl_query_fill(qc, 0, 63, 1, 32);
+ break;
+
+ case V4L2_CID_SATURATION:
+ v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048);
+ break;
+
+ case V4L2_CID_HUE:
+ v4l2_ctrl_query_fill(qc, -512, 511, 1, 0);
+ break;
default:
return -EINVAL;
}
-
- return 0;
-}
-
-static int vpx3220_init_client(struct i2c_client *client)
-{
- vpx3220_write_block(client, init_common, sizeof(init_common));
- vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1);
- /* Default to PAL */
- vpx3220_write_fp_block(client, init_pal, sizeof(init_pal) >> 1);
-
- return 0;
-}
+ return 0;
+}
+
+static int vpx3220_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct vpx3220 *decoder = to_vpx3220(sd);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = decoder->bright;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = decoder->contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = decoder->sat;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = decoder->hue;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vpx3220_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct vpx3220 *decoder = to_vpx3220(sd);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (decoder->bright != ctrl->value) {
+ decoder->bright = ctrl->value;
+ vpx3220_write(sd, 0xe6, decoder->bright);
+ }
+ break;
+ case V4L2_CID_CONTRAST:
+ if (decoder->contrast != ctrl->value) {
+ /* Bit 7 and 8 is for noise shaping */
+ decoder->contrast = ctrl->value;
+ vpx3220_write(sd, 0xe7, decoder->contrast + 192);
+ }
+ break;
+ case V4L2_CID_SATURATION:
+ if (decoder->sat != ctrl->value) {
+ decoder->sat = ctrl->value;
+ vpx3220_fp_write(sd, 0xa0, decoder->sat);
+ }
+ break;
+ case V4L2_CID_HUE:
+ if (decoder->hue != ctrl->value) {
+ decoder->hue = ctrl->value;
+ vpx3220_fp_write(sd, 0x1c, decoder->hue);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct
v4l2_dbg_chip_ident *chip)
+{
+ struct vpx3220 *decoder = to_vpx3220(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
+}
+
+static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
+ .g_chip_ident = vpx3220_g_chip_ident,
+ .init = vpx3220_init,
+ .g_ctrl = vpx3220_g_ctrl,
+ .s_ctrl = vpx3220_s_ctrl,
+ .queryctrl = vpx3220_queryctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops vpx3220_tuner_ops = {
+ .s_std = vpx3220_s_std,
+};
+
+static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
+ .s_routing = vpx3220_s_routing,
+ .s_stream = vpx3220_s_stream,
+ .querystd = vpx3220_querystd,
+ .g_input_status = vpx3220_g_input_status,
+};
+
+static const struct v4l2_subdev_ops vpx3220_ops = {
+ .core = &vpx3220_core_ops,
+ .tuner = &vpx3220_tuner_ops,
+ .video = &vpx3220_video_ops,
+};
/* -----------------------------------------------------------------------
* Client management code
*/
-static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
static int vpx3220_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct vpx3220 *decoder;
+ struct v4l2_subdev *sd;
const char *name = NULL;
u8 ver;
u16 pn;
@@ -562,6 +579,8 @@ static int vpx3220_probe(struct i2c_clie
decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
if (decoder == NULL)
return -ENOMEM;
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &vpx3220_ops);
decoder->norm = V4L2_STD_PAL;
decoder->input = 0;
decoder->enable = 1;
@@ -569,11 +588,11 @@ static int vpx3220_probe(struct i2c_clie
decoder->contrast = 32768;
decoder->hue = 32768;
decoder->sat = 32768;
- i2c_set_clientdata(client, decoder);
ver = i2c_smbus_read_byte_data(client, 0x00);
pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
i2c_smbus_read_byte_data(client, 0x01);
+ decoder->ident = V4L2_IDENT_VPX3220A;
if (ver == 0xec) {
switch (pn) {
case 0x4680:
@@ -581,26 +600,34 @@ static int vpx3220_probe(struct i2c_clie
break;
case 0x4260:
name = "vpx3216b";
+ decoder->ident = V4L2_IDENT_VPX3216B;
break;
case 0x4280:
name = "vpx3214c";
+ decoder->ident = V4L2_IDENT_VPX3214C;
break;
}
}
if (name)
- v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+ v4l2_info(sd, "%s found @ 0x%x (%s)\n", name,
client->addr << 1, client->adapter->name);
else
- v4l_info(client, "chip (%02x:%04x) found @ 0x%x (%s)\n",
+ v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n",
ver, pn, client->addr << 1, client->adapter->name);
- vpx3220_init_client(client);
+ vpx3220_write_block(sd, init_common, sizeof(init_common));
+ vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
+ /* Default to PAL */
+ vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
return 0;
}
static int vpx3220_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_vpx3220(sd));
return 0;
}
diff -r b0e701960f26 -r 72a015cc3c73 linux/include/media/v4l2-chip-ident.h
--- a/linux/include/media/v4l2-chip-ident.h Thu Feb 19 17:24:47 2009 +0100
+++ b/linux/include/media/v4l2-chip-ident.h Thu Feb 19 18:36:53 2009 +0100
@@ -87,6 +87,11 @@ enum {
/* module vp27smpx: just ident 2700 */
V4L2_IDENT_VP27SMPX = 2700,
+
+ /* module vpx3220: reserved range: 3210-3229 */
+ V4L2_IDENT_VPX3214C = 3214,
+ V4L2_IDENT_VPX3216B = 3216,
+ V4L2_IDENT_VPX3220A = 3220,
/* module tvp5150 */
V4L2_IDENT_TVP5150 = 5150,
---
Patch is available at:
http://linuxtv.org/hg/v4l-dvb/rev/72a015cc3c73dbb21bc2cb049b126f6b7d79307f
_______________________________________________
linuxtv-commits mailing list
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits