diff options
Diffstat (limited to 'drivers/media/video/bt819.c')
-rw-r--r-- | drivers/media/video/bt819.c | 493 |
1 files changed, 268 insertions, 225 deletions
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index a07b7b8..df4516d 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -29,16 +29,16 @@ */ #include <linux/module.h> -#include <linux/delay.h> #include <linux/types.h> #include <linux/ioctl.h> -#include <asm/uaccess.h> +#include <linux/delay.h> #include <linux/i2c.h> #include <linux/i2c-id.h> -#include <linux/videodev.h> -#include <linux/video_decoder.h> -#include <media/v4l2-common.h> -#include <media/v4l2-i2c-drv-legacy.h> +#include <linux/videodev2.h> +#include <media/v4l2-device.h> +#include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv.h> +#include <media/bt819.h> MODULE_DESCRIPTION("Brooktree-819 video decoder driver"); MODULE_AUTHOR("Mike Bernson & Dave Perks"); @@ -48,13 +48,15 @@ static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-1)"); + /* ----------------------------------------------------------------------- */ struct bt819 { + struct v4l2_subdev sd; unsigned char reg[32]; - int initialized; - int norm; + v4l2_std_id norm; + int ident; int input; int enable; int bright; @@ -63,6 +65,11 @@ struct bt819 { int sat; }; +static inline struct bt819 *to_bt819(struct v4l2_subdev *sd) +{ + return container_of(sd, struct bt819, sd); +} + struct timing { int hactive; int hdelay; @@ -80,24 +87,23 @@ static struct timing timing_data[] = { /* ----------------------------------------------------------------------- */ -static inline int bt819_write(struct i2c_client *client, u8 reg, u8 value) +static inline int bt819_write(struct bt819 *decoder, u8 reg, u8 value) { - struct bt819 *decoder = i2c_get_clientdata(client); + struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); decoder->reg[reg] = value; return i2c_smbus_write_byte_data(client, reg, value); } -static inline int bt819_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value) +static inline int bt819_setbit(struct bt819 *decoder, u8 reg, u8 bit, u8 value) { - struct bt819 *decoder = i2c_get_clientdata(client); - - return bt819_write(client, reg, + return bt819_write(decoder, reg, (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0)); } -static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned int len) +static int bt819_write_block(struct bt819 *decoder, const u8 *data, unsigned int len) { + struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); int ret = -1; u8 reg; @@ -105,7 +111,6 @@ static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned * the adapter understands raw I2C */ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { /* do raw I2C, not smbus compatible */ - struct bt819 *decoder = i2c_get_clientdata(client); u8 block_data[32]; int block_len; @@ -126,7 +131,8 @@ static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned /* do some slow I2C emulation kind of thing */ while (len >= 2) { reg = *data++; - if ((ret = bt819_write(client, reg, *data++)) < 0) + ret = bt819_write(decoder, reg, *data++); + if (ret < 0) break; len -= 2; } @@ -135,15 +141,15 @@ static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned return ret; } -static inline int bt819_read(struct i2c_client *client, u8 reg) +static inline int bt819_read(struct bt819 *decoder, u8 reg) { + struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); + return i2c_smbus_read_byte_data(client, reg); } -static int bt819_init(struct i2c_client *client) +static int bt819_init(struct v4l2_subdev *sd) { - struct bt819 *decoder = i2c_get_clientdata(client); - static unsigned char init[] = { /*0x1f, 0x00,*/ /* Reset */ 0x01, 0x59, /* 0x01 input format */ @@ -178,7 +184,8 @@ static int bt819_init(struct i2c_client *client) 0x1a, 0x80, /* 0x1a ADC Interface */ }; - struct timing *timing = &timing_data[decoder->norm]; + struct bt819 *decoder = to_bt819(sd); + struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0]; init[0x03 * 2 - 1] = (((timing->vdelay >> 8) & 0x03) << 6) | @@ -192,266 +199,306 @@ static int bt819_init(struct i2c_client *client) init[0x08 * 2 - 1] = timing->hscale >> 8; init[0x09 * 2 - 1] = timing->hscale & 0xff; /* 0x15 in array is address 0x19 */ - init[0x15 * 2 - 1] = (decoder->norm == 0) ? 115 : 93; /* Chroma burst delay */ + init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93; /* Chroma burst delay */ /* reset */ - bt819_write(client, 0x1f, 0x00); + bt819_write(decoder, 0x1f, 0x00); mdelay(1); /* init */ - return bt819_write_block(client, init, sizeof(init)); + return bt819_write_block(decoder, init, sizeof(init)); } /* ----------------------------------------------------------------------- */ -static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) +static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) { - int temp; + struct bt819 *decoder = to_bt819(sd); + int status = bt819_read(decoder, 0x00); + int res = V4L2_IN_ST_NO_SIGNAL; + v4l2_std_id std; - struct bt819 *decoder = i2c_get_clientdata(client); + if ((status & 0x80)) + res = 0; - if (!decoder->initialized) { /* First call to bt819_init could be */ - bt819_init(client); /* without #FRST = 0 */ - decoder->initialized = 1; - } + if ((status & 0x10)) + std = V4L2_STD_PAL; + else + std = V4L2_STD_NTSC; + if (pstd) + *pstd = std; + if (pstatus) + *pstatus = status; - switch (cmd) { - case 0: - /* This is just for testing!!! */ - bt819_init(client); - break; + v4l2_dbg(1, debug, sd, "get status %x\n", status); + return 0; +} - case DECODER_GET_CAPABILITIES: - { - struct video_decoder_capability *cap = arg; +static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + return bt819_status(sd, NULL, std); +} - cap->flags = VIDEO_DECODER_PAL | - VIDEO_DECODER_NTSC | - VIDEO_DECODER_AUTO | - VIDEO_DECODER_CCIR; - cap->inputs = 8; - cap->outputs = 1; - break; +static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + return bt819_status(sd, status, NULL); +} + +static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct bt819 *decoder = to_bt819(sd); + struct timing *timing = NULL; + + v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); + + if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL) + v4l2_err(sd, "no notify found!\n"); + + if (std & V4L2_STD_NTSC) { + v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0); + bt819_setbit(decoder, 0x01, 0, 1); + bt819_setbit(decoder, 0x01, 1, 0); + bt819_setbit(decoder, 0x01, 5, 0); + bt819_write(decoder, 0x18, 0x68); + bt819_write(decoder, 0x19, 0x5d); + /* bt819_setbit(decoder, 0x1a, 5, 1); */ + timing = &timing_data[1]; + } else if (std & V4L2_STD_PAL) { + v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0); + bt819_setbit(decoder, 0x01, 0, 1); + bt819_setbit(decoder, 0x01, 1, 1); + bt819_setbit(decoder, 0x01, 5, 1); + bt819_write(decoder, 0x18, 0x7f); + bt819_write(decoder, 0x19, 0x72); + /* bt819_setbit(decoder, 0x1a, 5, 0); */ + timing = &timing_data[0]; + } else { + v4l2_dbg(1, debug, sd, "unsupported norm %llx\n", + (unsigned long long)std); + return -EINVAL; } + bt819_write(decoder, 0x03, + (((timing->vdelay >> 8) & 0x03) << 6) | + (((timing->vactive >> 8) & 0x03) << 4) | + (((timing->hdelay >> 8) & 0x03) << 2) | + ((timing->hactive >> 8) & 0x03)); + bt819_write(decoder, 0x04, timing->vdelay & 0xff); + bt819_write(decoder, 0x05, timing->vactive & 0xff); + bt819_write(decoder, 0x06, timing->hdelay & 0xff); + bt819_write(decoder, 0x07, timing->hactive & 0xff); + bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff); + bt819_write(decoder, 0x09, timing->hscale & 0xff); + decoder->norm = std; + v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0); + return 0; +} - case DECODER_GET_STATUS: - { - int *iarg = arg; - int status; - int res; +static int bt819_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) +{ + struct bt819 *decoder = to_bt819(sd); - status = bt819_read(client, 0x00); - res = 0; - if ((status & 0x80)) - res |= DECODER_STATUS_GOOD; + v4l2_dbg(1, debug, sd, "set input %x\n", route->input); - switch (decoder->norm) { - case VIDEO_MODE_NTSC: - res |= DECODER_STATUS_NTSC; - break; - case VIDEO_MODE_PAL: - res |= DECODER_STATUS_PAL; - break; - default: - case VIDEO_MODE_AUTO: - if ((status & 0x10)) - res |= DECODER_STATUS_PAL; - else - res |= DECODER_STATUS_NTSC; - break; - } - res |= DECODER_STATUS_COLOR; - *iarg = res; + if (route->input < 0 || route->input > 7) + return -EINVAL; - v4l_dbg(1, debug, client, "get status %x\n", *iarg); - break; + if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL) + v4l2_err(sd, "no notify found!\n"); + + if (decoder->input != route->input) { + v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0); + decoder->input = route->input; + /* select mode */ + if (decoder->input == 0) { + bt819_setbit(decoder, 0x0b, 6, 0); + bt819_setbit(decoder, 0x1a, 1, 1); + } else { + bt819_setbit(decoder, 0x0b, 6, 1); + bt819_setbit(decoder, 0x1a, 1, 0); + } + v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0); } + return 0; +} - case DECODER_SET_NORM: - { - int *iarg = arg; - struct timing *timing = NULL; - - v4l_dbg(1, debug, client, "set norm %x\n", *iarg); - - switch (*iarg) { - case VIDEO_MODE_NTSC: - bt819_setbit(client, 0x01, 0, 1); - bt819_setbit(client, 0x01, 1, 0); - bt819_setbit(client, 0x01, 5, 0); - bt819_write(client, 0x18, 0x68); - bt819_write(client, 0x19, 0x5d); - /* bt819_setbit(client, 0x1a, 5, 1); */ - timing = &timing_data[VIDEO_MODE_NTSC]; - break; - case VIDEO_MODE_PAL: - bt819_setbit(client, 0x01, 0, 1); - bt819_setbit(client, 0x01, 1, 1); - bt819_setbit(client, 0x01, 5, 1); - bt819_write(client, 0x18, 0x7f); - bt819_write(client, 0x19, 0x72); - /* bt819_setbit(client, 0x1a, 5, 0); */ - timing = &timing_data[VIDEO_MODE_PAL]; - break; - case VIDEO_MODE_AUTO: - bt819_setbit(client, 0x01, 0, 0); - bt819_setbit(client, 0x01, 1, 0); - break; - default: - v4l_dbg(1, debug, client, "unsupported norm %x\n", *iarg); - return -EINVAL; - } +static int bt819_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct bt819 *decoder = to_bt819(sd); - if (timing) { - bt819_write(client, 0x03, - (((timing->vdelay >> 8) & 0x03) << 6) | - (((timing->vactive >> 8) & 0x03) << 4) | - (((timing->hdelay >> 8) & 0x03) << 2) | - ((timing->hactive >> 8) & 0x03) ); - bt819_write(client, 0x04, timing->vdelay & 0xff); - bt819_write(client, 0x05, timing->vactive & 0xff); - bt819_write(client, 0x06, timing->hdelay & 0xff); - bt819_write(client, 0x07, timing->hactive & 0xff); - bt819_write(client, 0x08, (timing->hscale >> 8) & 0xff); - bt819_write(client, 0x09, timing->hscale & 0xff); - } + v4l2_dbg(1, debug, sd, "enable output %x\n", enable); - decoder->norm = *iarg; - break; + if (decoder->enable != enable) { + decoder->enable = enable; + bt819_setbit(decoder, 0x16, 7, !enable); } + return 0; +} - case DECODER_SET_INPUT: - { - int *iarg = arg; - - v4l_dbg(1, debug, client, "set input %x\n", *iarg); - - if (*iarg < 0 || *iarg > 7) - return -EINVAL; - - if (decoder->input != *iarg) { - decoder->input = *iarg; - /* select mode */ - if (decoder->input == 0) { - bt819_setbit(client, 0x0b, 6, 0); - bt819_setbit(client, 0x1a, 1, 1); - } else { - bt819_setbit(client, 0x0b, 6, 1); - bt819_setbit(client, 0x1a, 1, 0); - } - } +static int bt819_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 DECODER_SET_OUTPUT: - { - int *iarg = arg; + case V4L2_CID_CONTRAST: + v4l2_ctrl_query_fill(qc, 0, 511, 1, 256); + break; - v4l_dbg(1, debug, client, "set output %x\n", *iarg); + case V4L2_CID_SATURATION: + v4l2_ctrl_query_fill(qc, 0, 511, 1, 256); + break; - /* not much choice of outputs */ - if (*iarg != 0) - return -EINVAL; + case V4L2_CID_HUE: + v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); break; - } - case DECODER_ENABLE_OUTPUT: - { - int *iarg = arg; - int enable = (*iarg != 0); + default: + return -EINVAL; + } + return 0; +} - v4l_dbg(1, debug, client, "enable output %x\n", *iarg); +static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct bt819 *decoder = to_bt819(sd); + int temp; - if (decoder->enable != enable) { - decoder->enable = enable; - bt819_setbit(client, 0x16, 7, !enable); - } + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + if (decoder->bright == ctrl->value) + break; + decoder->bright = ctrl->value; + bt819_write(decoder, 0x0a, decoder->bright); break; - } - case DECODER_SET_PICTURE: - { - struct video_picture *pic = arg; - - v4l_dbg(1, debug, client, - "set picture brightness %d contrast %d colour %d\n", - pic->brightness, pic->contrast, pic->colour); + case V4L2_CID_CONTRAST: + if (decoder->contrast == ctrl->value) + break; + decoder->contrast = ctrl->value; + bt819_write(decoder, 0x0c, decoder->contrast & 0xff); + bt819_setbit(decoder, 0x0b, 2, ((decoder->contrast >> 8) & 0x01)); + break; + case V4L2_CID_SATURATION: + if (decoder->sat == ctrl->value) + break; + decoder->sat = ctrl->value; + bt819_write(decoder, 0x0d, (decoder->sat >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 1, ((decoder->sat >> 15) & 0x01)); + + /* Ratio between U gain and V gain must stay the same as + the ratio between the default U and V gain values. */ + temp = (decoder->sat * 180) / 254; + bt819_write(decoder, 0x0e, (temp >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01); + break; - if (decoder->bright != pic->brightness) { - /* We want -128 to 127 we get 0-65535 */ - decoder->bright = pic->brightness; - bt819_write(client, 0x0a, - (decoder->bright >> 8) - 128); - } + case V4L2_CID_HUE: + if (decoder->hue == ctrl->value) + break; + decoder->hue = ctrl->value; + bt819_write(decoder, 0x0f, decoder->hue); + break; - if (decoder->contrast != pic->contrast) { - /* We want 0 to 511 we get 0-65535 */ - decoder->contrast = pic->contrast; - bt819_write(client, 0x0c, - (decoder->contrast >> 7) & 0xff); - bt819_setbit(client, 0x0b, 2, - ((decoder->contrast >> 15) & 0x01)); - } + default: + return -EINVAL; + } + return 0; +} - if (decoder->sat != pic->colour) { - /* We want 0 to 511 we get 0-65535 */ - decoder->sat = pic->colour; - bt819_write(client, 0x0d, - (decoder->sat >> 7) & 0xff); - bt819_setbit(client, 0x0b, 1, - ((decoder->sat >> 15) & 0x01)); - - temp = (decoder->sat * 201) / 237; - bt819_write(client, 0x0e, (temp >> 7) & 0xff); - bt819_setbit(client, 0x0b, 0, (temp >> 15) & 0x01); - } +static int bt819_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct bt819 *decoder = to_bt819(sd); - if (decoder->hue != pic->hue) { - /* We want -128 to 127 we get 0-65535 */ - decoder->hue = pic->hue; - bt819_write(client, 0x0f, - 128 - (decoder->hue >> 8)); - } + 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 bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct bt819 *decoder = to_bt819(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0); +} + /* ----------------------------------------------------------------------- */ -static unsigned short normal_i2c[] = { 0x8a >> 1, I2C_CLIENT_END }; +static const struct v4l2_subdev_core_ops bt819_core_ops = { + .g_chip_ident = bt819_g_chip_ident, + .g_ctrl = bt819_g_ctrl, + .s_ctrl = bt819_s_ctrl, + .queryctrl = bt819_queryctrl, +}; + +static const struct v4l2_subdev_tuner_ops bt819_tuner_ops = { + .s_std = bt819_s_std, +}; + +static const struct v4l2_subdev_video_ops bt819_video_ops = { + .s_routing = bt819_s_routing, + .s_stream = bt819_s_stream, + .querystd = bt819_querystd, + .g_input_status = bt819_g_input_status, +}; + +static const struct v4l2_subdev_ops bt819_ops = { + .core = &bt819_core_ops, + .tuner = &bt819_tuner_ops, + .video = &bt819_video_ops, +}; -I2C_CLIENT_INSMOD; +/* ----------------------------------------------------------------------- */ static int bt819_probe(struct i2c_client *client, const struct i2c_device_id *id) { int i, ver; struct bt819 *decoder; + struct v4l2_subdev *sd; const char *name; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - ver = bt819_read(client, 0x17); + decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL); + if (decoder == NULL) + return -ENOMEM; + sd = &decoder->sd; + v4l2_i2c_subdev_init(sd, client, &bt819_ops); + + ver = bt819_read(decoder, 0x17); switch (ver & 0xf0) { case 0x70: name = "bt819a"; + decoder->ident = V4L2_IDENT_BT819A; break; case 0x60: name = "bt817a"; + decoder->ident = V4L2_IDENT_BT817A; break; case 0x20: name = "bt815a"; + decoder->ident = V4L2_IDENT_BT815A; break; default: - v4l_dbg(1, debug, client, + v4l2_dbg(1, debug, sd, "unknown chip version 0x%02x\n", ver); return -ENODEV; } @@ -459,28 +506,26 @@ static int bt819_probe(struct i2c_client *client, v4l_info(client, "%s found @ 0x%x (%s)\n", name, client->addr << 1, client->adapter->name); - decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL); - if (decoder == NULL) - return -ENOMEM; - decoder->norm = VIDEO_MODE_NTSC; + decoder->norm = V4L2_STD_NTSC; decoder->input = 0; decoder->enable = 1; - decoder->bright = 32768; - decoder->contrast = 32768; - decoder->hue = 32768; - decoder->sat = 32768; - decoder->initialized = 0; - i2c_set_clientdata(client, decoder); - - i = bt819_init(client); + decoder->bright = 0; + decoder->contrast = 0xd8; /* 100% of original signal */ + decoder->hue = 0; + decoder->sat = 0xfe; /* 100% of original signal */ + + i = bt819_init(sd); if (i < 0) - v4l_dbg(1, debug, client, "init status %d\n", i); + v4l2_dbg(1, debug, sd, "init status %d\n", i); return 0; } static int bt819_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_bt819(sd)); return 0; } @@ -496,8 +541,6 @@ MODULE_DEVICE_TABLE(i2c, bt819_id); static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "bt819", - .driverid = I2C_DRIVERID_BT819, - .command = bt819_command, .probe = bt819_probe, .remove = bt819_remove, .id_table = bt819_id, |