X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fvpx3220.c;h=476a204dcf9051866655a8475ac459cc9137577f;hb=7e5eaadcbd8894b25f715aa03cb632d0df63269c;hp=8dcee8b60e21a2cfc458808b1bbf13376d814a7b;hpb=2b48716d1d2f2edb1e7cbc5ecf1cb2cb39373e33;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 8dcee8b..476a204 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -1,4 +1,4 @@ -/* +/* * vpx3220a, vpx3216b & vpx3214c video decoder driver version 0.0.1 * * Copyright (C) 2001 Laurent Pinchart @@ -22,42 +22,35 @@ #include #include #include -#include - -#include - -#include #include - #include -#include - -#define I2C_NAME(x) (x)->name - -#include -#include +#include +#include +#include +#include -#define I2C_VPX3220 0x86 -#define VPX3220_DEBUG KERN_DEBUG "vpx3220: " +MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); +MODULE_AUTHOR("Laurent Pinchart"); +MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) +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]; - int norm; + v4l2_std_id norm; + int ident; int input; int enable; int bright; @@ -66,35 +59,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; @@ -108,66 +104,61 @@ vpx3220_fp_status (struct i2c_client *client) 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) { - dprintk(1, VPX3220_DEBUG "%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) { - dprintk(1, VPX3220_DEBUG "%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) { - dprintk(1, VPX3220_DEBUG "%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) { - dprintk(1, VPX3220_DEBUG "%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++; - if ((ret = - vpx3220_write(client, reg, *data++)) < 0) + ret = vpx3220_write(sd, reg, *data++); + if (ret < 0) break; len -= 2; } @@ -175,17 +166,15 @@ vpx3220_write_block (struct i2c_client *client, return ret; } -static int -vpx3220_write_fp_block (struct i2c_client *client, - const u16 *data, - unsigned int len) +static int vpx3220_write_fp_block(struct v4l2_subdev *sd, + const u16 *data, unsigned int len) { u8 reg; int ret = 0; while (len > 1) { reg = *data++; - ret |= vpx3220_fp_write(client, reg, *data++); + ret |= vpx3220_fp_write(sd, reg, *data++); len -= 2; } @@ -287,466 +276,359 @@ static const unsigned short init_fp[] = { 0x4b, 0x298, /* PLL gain */ }; -static void -vpx3220_dump_i2c (struct i2c_client *client) -{ - int len = sizeof(init_common); - const unsigned char *data = init_common; - while (len > 1) { - dprintk(1, - KERN_DEBUG "vpx3216b i2c reg 0x%02x data 0x%02x\n", - *data, vpx3220_read(client, *data)); - data += 2; - len -= 2; - } +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_command (struct i2c_client *client, - unsigned int cmd, - void *arg) +static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) { - struct vpx3220 *decoder = i2c_get_clientdata(client); + int res = V4L2_IN_ST_NO_SIGNAL, status; + v4l2_std_id std = 0; - switch (cmd) { - case 0: - { - vpx3220_write_block(client, init_common, - sizeof(init_common)); - vpx3220_write_fp_block(client, init_fp, - sizeof(init_fp) >> 1); - switch (decoder->norm) { - - case VIDEO_MODE_NTSC: - vpx3220_write_fp_block(client, init_ntsc, - sizeof(init_ntsc) >> 1); - break; + v4l2_dbg(1, debug, sd, "VIDIOC_QUERYSTD/VIDIOC_INT_G_INPUT_STATUS\n"); - case VIDEO_MODE_PAL: - vpx3220_write_fp_block(client, init_pal, - sizeof(init_pal) >> 1); - break; - case VIDEO_MODE_SECAM: - vpx3220_write_fp_block(client, init_secam, - sizeof(init_secam) >> 1); - break; - default: - vpx3220_write_fp_block(client, init_pal, - sizeof(init_pal) >> 1); - break; - } - } - break; + status = vpx3220_fp_read(sd, 0x0f3); - case DECODER_DUMP: - { - vpx3220_dump_i2c(client); - } - break; - - case DECODER_GET_CAPABILITIES: - { - struct video_decoder_capability *cap = arg; + v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status); - dprintk(1, KERN_DEBUG "%s: DECODER_GET_CAPABILITIES\n", - I2C_NAME(client)); + if (status < 0) + return status; - cap->flags = VIDEO_DECODER_PAL | - VIDEO_DECODER_NTSC | - VIDEO_DECODER_SECAM | - VIDEO_DECODER_AUTO | - VIDEO_DECODER_CCIR; - cap->inputs = 3; - cap->outputs = 1; - } - break; + if ((status & 0x20) == 0) { + res = 0; - case DECODER_GET_STATUS: - { - int res = 0, status; - - dprintk(1, KERN_INFO "%s: DECODER_GET_STATUS\n", - I2C_NAME(client)); - - status = vpx3220_fp_read(client, 0x0f3); - - dprintk(1, KERN_INFO "%s: status: 0x%04x\n", I2C_NAME(client), - status); - - if (status < 0) - return status; - - if ((status & 0x20) == 0) { - res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR; + switch (status & 0x18) { + case 0x00: + case 0x10: + case 0x14: + case 0x18: + std = V4L2_STD_PAL; + break; - switch (status & 0x18) { + case 0x08: + std = V4L2_STD_SECAM; + break; - case 0x00: - case 0x10: - case 0x14: - case 0x18: - res |= DECODER_STATUS_PAL; - break; + case 0x04: + case 0x0c: + case 0x1c: + std = V4L2_STD_NTSC; + break; + } + } + if (pstd) + *pstd = std; + if (pstatus) + *pstatus = status; + return 0; +} - case 0x08: - res |= DECODER_STATUS_SECAM; - break; +static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + return vpx3220_status(sd, NULL, std); +} - case 0x04: - case 0x0c: - case 0x1c: - res |= DECODER_STATUS_NTSC; - break; - } - } +static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + return vpx3220_status(sd, status, NULL); +} - *(int *) arg = res; +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; } - break; - case DECODER_SET_NORM: - { - int *iarg = arg, data; - 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); - - dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n", - I2C_NAME(client), *iarg); - switch (*iarg) { - - case VIDEO_MODE_NTSC: - vpx3220_write_fp_block(client, init_ntsc, - sizeof(init_ntsc) >> 1); - dprintk(1, KERN_INFO "%s: norm switched to NTSC\n", - I2C_NAME(client)); - break; - - case VIDEO_MODE_PAL: - vpx3220_write_fp_block(client, init_pal, - sizeof(init_pal) >> 1); - dprintk(1, KERN_INFO "%s: norm switched to PAL\n", - I2C_NAME(client)); - break; + decoder->norm = std; - case VIDEO_MODE_SECAM: - vpx3220_write_fp_block(client, init_secam, - sizeof(init_secam) >> 1); - dprintk(1, KERN_INFO "%s: norm switched to SECAM\n", - I2C_NAME(client)); - break; + /* And here we set the backed up video input again */ + vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010); + udelay(10); + return 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); - dprintk(1, KERN_INFO "%s: norm switched to Auto\n", - I2C_NAME(client)); - break; +static int vpx3220_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) +{ + int data; - default: - return -EINVAL; + /* RJ: route->input = 0: ST8 (PCTV) input + route->input = 1: COMPOSITE input + route->input = 2: SVHS input */ - } - decoder->norm = *iarg; + const int input[3][2] = { + {0x0c, 0}, + {0x0d, 0}, + {0x0e, 1} + }; - /* And here we set the backed up video input again */ - vpx3220_fp_write(client, 0xf2, temp_input | 0x0010); - udelay(10); - } - break; + if (route->input < 0 || route->input > 2) + return -EINVAL; - case DECODER_SET_INPUT: - { - int *iarg = arg, data; + v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[route->input]); - /* RJ: *iarg = 0: ST8 (PCTV) input - *iarg = 1: COMPOSITE input - *iarg = 2: SVHS input */ + vpx3220_write(sd, 0x33, input[route->input][0]); - const int input[3][2] = { - {0x0c, 0}, - {0x0d, 0}, - {0x0e, 1} - }; + 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); - if (*iarg < 0 || *iarg > 2) - return -EINVAL; + udelay(10); + return 0; +} - dprintk(1, KERN_INFO "%s: input switched to %s\n", - I2C_NAME(client), inputs[*iarg]); +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(client, 0x33, input[*iarg][0]); + vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00)); + return 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[*iarg][1] << 5) | 0x0010); +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; - udelay(10); - } + case V4L2_CID_CONTRAST: + v4l2_ctrl_query_fill(qc, 0, 63, 1, 32); break; - case DECODER_SET_OUTPUT: - { - int *iarg = arg; + case V4L2_CID_SATURATION: + v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048); + break; - /* not much choice of outputs */ - if (*iarg != 0) { - return -EINVAL; - } - } + case V4L2_CID_HUE: + v4l2_ctrl_query_fill(qc, -512, 511, 1, 0); break; - case DECODER_ENABLE_OUTPUT: - { - int *iarg = arg; + default: + return -EINVAL; + } + return 0; +} - dprintk(1, KERN_DEBUG "%s: DECODER_ENABLE_OUTPUT %d\n", - I2C_NAME(client), *iarg); +static int vpx3220_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct vpx3220 *decoder = to_vpx3220(sd); - vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00)); - } + 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; +} - case DECODER_SET_PICTURE: - { - struct video_picture *pic = arg; +static int vpx3220_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct vpx3220 *decoder = to_vpx3220(sd); - if (decoder->bright != pic->brightness) { - /* We want -128 to 128 we get 0-65535 */ - decoder->bright = pic->brightness; - vpx3220_write(client, 0xe6, - (decoder->bright - 32768) >> 8); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + if (decoder->bright != ctrl->value) { + decoder->bright = ctrl->value; + vpx3220_write(sd, 0xe6, decoder->bright); } - if (decoder->contrast != pic->contrast) { - /* We want 0 to 64 we get 0-65535 */ + break; + case V4L2_CID_CONTRAST: + if (decoder->contrast != ctrl->value) { /* Bit 7 and 8 is for noise shaping */ - decoder->contrast = pic->contrast; - vpx3220_write(client, 0xe7, - (decoder->contrast >> 10) + 192); + decoder->contrast = ctrl->value; + vpx3220_write(sd, 0xe7, decoder->contrast + 192); } - if (decoder->sat != pic->colour) { - /* We want 0 to 4096 we get 0-65535 */ - decoder->sat = pic->colour; - vpx3220_fp_write(client, 0xa0, - decoder->sat >> 4); + break; + case V4L2_CID_SATURATION: + if (decoder->sat != ctrl->value) { + decoder->sat = ctrl->value; + vpx3220_fp_write(sd, 0xa0, decoder->sat); } - if (decoder->hue != pic->hue) { - /* We want -512 to 512 we get 0-65535 */ - decoder->hue = pic->hue; - vpx3220_fp_write(client, 0x1c, - ((decoder->hue - 32768) >> 6) & 0xFFF); + 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_init_client (struct i2c_client *client) +static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { - 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); + struct vpx3220 *decoder = to_vpx3220(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); - return 0; + return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0); } -/* ----------------------------------------------------------------------- - * Client managment code - */ +static int vpx3220_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_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4, - I2C_CLIENT_END -}; +/* ----------------------------------------------------------------------- */ -static unsigned short ignore = I2C_CLIENT_END; - -static struct i2c_client_address_data addr_data = { - .normal_i2c = normal_i2c, - .probe = &ignore, - .ignore = &ignore, +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 struct i2c_driver vpx3220_i2c_driver; - -static int -vpx3220_detach_client (struct i2c_client *client) -{ - struct vpx3220 *decoder = i2c_get_clientdata(client); - int err; +static const struct v4l2_subdev_tuner_ops vpx3220_tuner_ops = { + .s_std = vpx3220_s_std, +}; - err = i2c_detach_client(client); - if (err) { - return err; - } +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, +}; - kfree(decoder); - kfree(client); +static const struct v4l2_subdev_ops vpx3220_ops = { + .core = &vpx3220_core_ops, + .tuner = &vpx3220_tuner_ops, + .video = &vpx3220_video_ops, +}; - return 0; -} +/* ----------------------------------------------------------------------- + * Client management code + */ -static int -vpx3220_detect_client (struct i2c_adapter *adapter, - int address, - int kind) +static int vpx3220_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - int err; - struct i2c_client *client; struct vpx3220 *decoder; - - dprintk(1, VPX3220_DEBUG "%s\n", __func__); + struct v4l2_subdev *sd; + const char *name = NULL; + u8 ver; + u16 pn; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality - (adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) - return 0; + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) { + decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL); + if (decoder == NULL) return -ENOMEM; - } - - memset(client, 0, sizeof(struct i2c_client)); - - client->addr = address; - client->adapter = adapter; - client->driver = &vpx3220_i2c_driver; - - /* Check for manufacture ID and part number */ - if (kind < 0) { - u8 id; - u16 pn; - - id = vpx3220_read(client, 0x00); - if (id != 0xec) { - dprintk(1, - KERN_INFO - "vpx3220_attach: Wrong manufacturer ID (0x%02x)\n", - id); - kfree(client); - return 0; - } + sd = &decoder->sd; + v4l2_i2c_subdev_init(sd, client, &vpx3220_ops); + decoder->norm = V4L2_STD_PAL; + decoder->input = 0; + decoder->enable = 1; + decoder->bright = 32768; + decoder->contrast = 32768; + decoder->hue = 32768; + decoder->sat = 32768; - pn = (vpx3220_read(client, 0x02) << 8) + - vpx3220_read(client, 0x01); + 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: - strlcpy(I2C_NAME(client), "vpx3220a", - sizeof(I2C_NAME(client))); + name = "vpx3220a"; break; case 0x4260: - strlcpy(I2C_NAME(client), "vpx3216b", - sizeof(I2C_NAME(client))); + name = "vpx3216b"; + decoder->ident = V4L2_IDENT_VPX3216B; break; case 0x4280: - strlcpy(I2C_NAME(client), "vpx3214c", - sizeof(I2C_NAME(client))); + name = "vpx3214c"; + decoder->ident = V4L2_IDENT_VPX3214C; break; - default: - dprintk(1, - KERN_INFO - "%s: Wrong part number (0x%04x)\n", - __func__, pn); - kfree(client); - return 0; } - } else { - strlcpy(I2C_NAME(client), "forced vpx32xx", - sizeof(I2C_NAME(client))); - } - - decoder = kmalloc(sizeof(struct vpx3220), GFP_KERNEL); - if (decoder == NULL) { - kfree(client); - return -ENOMEM; - } - memset(decoder, 0, sizeof(struct vpx3220)); - decoder->norm = VIDEO_MODE_PAL; - decoder->input = 0; - decoder->enable = 1; - decoder->bright = 32768; - decoder->contrast = 32768; - decoder->hue = 32768; - decoder->sat = 32768; - i2c_set_clientdata(client, decoder); - - err = i2c_attach_client(client); - if (err) { - kfree(client); - kfree(decoder); - return err; } - - dprintk(1, KERN_INFO "%s: vpx32xx client found at address 0x%02x\n", - I2C_NAME(client), client->addr << 1); - - vpx3220_init_client(client); - + if (name) + v4l2_info(sd, "%s found @ 0x%x (%s)\n", name, + client->addr << 1, client->adapter->name); + else + v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n", + ver, pn, client->addr << 1, client->adapter->name); + + 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_attach_adapter (struct i2c_adapter *adapter) +static int vpx3220_remove(struct i2c_client *client) { - int ret; + struct v4l2_subdev *sd = i2c_get_clientdata(client); - ret = i2c_probe(adapter, &addr_data, &vpx3220_detect_client); - dprintk(1, VPX3220_DEBUG "%s: i2c_probe returned %d\n", - __func__, ret); - return ret; + v4l2_device_unregister_subdev(sd); + kfree(to_vpx3220(sd)); + return 0; } -/* ----------------------------------------------------------------------- - * Driver initialization and cleanup code - */ - -static struct i2c_driver vpx3220_i2c_driver = { - .driver = { - .name = "vpx3220", - }, - - .id = I2C_DRIVERID_VPX3220, +static const struct i2c_device_id vpx3220_id[] = { + { "vpx3220a", 0 }, + { "vpx3216b", 0 }, + { "vpx3214c", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, vpx3220_id); - .attach_adapter = vpx3220_attach_adapter, - .detach_client = vpx3220_detach_client, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "vpx3220", + .driverid = I2C_DRIVERID_VPX3220, .command = vpx3220_command, + .probe = vpx3220_probe, + .remove = vpx3220_remove, + .id_table = vpx3220_id, }; - -static int __init -vpx3220_init (void) -{ - return i2c_add_driver(&vpx3220_i2c_driver); -} - -static void __exit -vpx3220_cleanup (void) -{ - i2c_del_driver(&vpx3220_i2c_driver); -} - -module_init(vpx3220_init); -module_exit(vpx3220_cleanup); - -MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video encoder driver"); -MODULE_AUTHOR("Laurent Pinchart"); -MODULE_LICENSE("GPL");