Loading drivers/media/video/bt819.c +252 −225 Original line number Diff line number Diff line Loading @@ -29,15 +29,14 @@ */ #include <linux/module.h> #include <linux/delay.h> #include <linux/types.h> #include <linux/ioctl.h> #include <asm/uaccess.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 <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-i2c-drv-legacy.h> MODULE_DESCRIPTION("Brooktree-819 video decoder driver"); Loading @@ -48,13 +47,18 @@ static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-1)"); static unsigned short normal_i2c[] = { 0x8a >> 1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ struct bt819 { struct v4l2_subdev sd; unsigned char reg[32]; int initialized; v4l2_std_id norm; int ident; int input; int enable; int bright; Loading @@ -63,6 +67,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; Loading @@ -80,24 +89,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; Loading @@ -105,7 +113,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; Loading @@ -126,7 +133,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; } Loading @@ -135,15 +143,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 */ Loading Loading @@ -178,6 +186,7 @@ static int bt819_init(struct i2c_client *client) 0x1a, 0x80, /* 0x1a ADC Interface */ }; struct bt819 *decoder = to_bt819(sd); struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0]; init[0x03 * 2 - 1] = Loading @@ -194,41 +203,22 @@ static int bt819_init(struct i2c_client *client) /* 0x15 in array is address 0x19 */ 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 = i2c_get_clientdata(client); if (!decoder->initialized) { /* First call to bt819_init could be */ bt819_init(client); /* without #FRST = 0 */ decoder->initialized = 1; } switch (cmd) { case VIDIOC_INT_INIT: /* This is just for testing!!! */ bt819_init(client); break; case VIDIOC_QUERYSTD: case VIDIOC_INT_G_INPUT_STATUS: { int *iarg = arg; v4l2_std_id *istd = arg; int status; struct bt819 *decoder = to_bt819(sd); int status = bt819_read(decoder, 0x00); int res = V4L2_IN_ST_NO_SIGNAL; v4l2_std_id std; status = bt819_read(client, 0x00); if ((status & 0x80)) res = 0; Loading @@ -236,66 +226,72 @@ static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) std = V4L2_STD_PAL; else std = V4L2_STD_NTSC; if (cmd == VIDIOC_QUERYSTD) *istd = std; else *iarg = res; if (pstd) *pstd = std; if (pstatus) *pstatus = status; v4l_dbg(1, debug, client, "get status %x\n", *iarg); break; v4l2_dbg(1, debug, sd, "get status %x\n", status); return 0; } static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) { return bt819_status(sd, NULL, std); } case VIDIOC_S_STD: static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status) { v4l2_std_id *iarg = arg; 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; v4l_dbg(1, debug, client, "set norm %llx\n", *iarg); v4l2_dbg(1, debug, sd, "set norm %llx\n", std); if (*iarg & V4L2_STD_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); */ if (std & V4L2_STD_NTSC) { 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 (*iarg & V4L2_STD_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); */ } else if (std & V4L2_STD_PAL) { 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 { v4l_dbg(1, debug, client, "unsupported norm %llx\n", *iarg); v4l2_dbg(1, debug, sd, "unsupported norm %llx\n", std); return -EINVAL; } /* case VIDEO_MODE_AUTO: bt819_setbit(client, 0x01, 0, 0); bt819_setbit(client, 0x01, 1, 0);*/ bt819_write(client, 0x03, 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(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); decoder->norm = *iarg; break; 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; return 0; } case VIDIOC_INT_S_VIDEO_ROUTING: static int bt819_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) { struct v4l2_routing *route = arg; struct bt819 *decoder = to_bt819(sd); v4l_dbg(1, debug, client, "set input %x\n", route->input); v4l2_dbg(1, debug, sd, "set input %x\n", route->input); if (route->input < 0 || route->input > 7) return -EINVAL; Loading @@ -304,34 +300,31 @@ static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) decoder->input = route->input; /* select mode */ if (decoder->input == 0) { bt819_setbit(client, 0x0b, 6, 0); bt819_setbit(client, 0x1a, 1, 1); bt819_setbit(decoder, 0x0b, 6, 0); bt819_setbit(decoder, 0x1a, 1, 1); } else { bt819_setbit(client, 0x0b, 6, 1); bt819_setbit(client, 0x1a, 1, 0); bt819_setbit(decoder, 0x0b, 6, 1); bt819_setbit(decoder, 0x1a, 1, 0); } } break; return 0; } case VIDIOC_STREAMON: case VIDIOC_STREAMOFF: static int bt819_s_stream(struct v4l2_subdev *sd, int enable) { int enable = cmd == VIDIOC_STREAMON; struct bt819 *decoder = to_bt819(sd); v4l_dbg(1, debug, client, "enable output %x\n", enable); v4l2_dbg(1, debug, sd, "enable output %x\n", enable); if (decoder->enable != enable) { decoder->enable = enable; bt819_setbit(client, 0x16, 7, !enable); bt819_setbit(decoder, 0x16, 7, !enable); } break; return 0; } case VIDIOC_QUERYCTRL: static int bt819_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) { struct v4l2_queryctrl *qc = arg; switch (qc->id) { case V4L2_CID_BRIGHTNESS: v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); Loading @@ -352,62 +345,60 @@ static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) default: return -EINVAL; } break; return 0; } case VIDIOC_S_CTRL: static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct v4l2_control *ctrl = arg; struct bt819 *decoder = to_bt819(sd); int temp; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: if (decoder->bright != ctrl->value) { if (decoder->bright == ctrl->value) break; decoder->bright = ctrl->value; bt819_write(client, 0x0a, decoder->bright); } bt819_write(decoder, 0x0a, decoder->bright); break; case V4L2_CID_CONTRAST: if (decoder->contrast != ctrl->value) { if (decoder->contrast == ctrl->value) break; decoder->contrast = ctrl->value; bt819_write(client, 0x0c, decoder->contrast & 0xff); bt819_setbit(client, 0x0b, 2, ((decoder->contrast >> 8) & 0x01)); } 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) { if (decoder->sat == ctrl->value) break; decoder->sat = ctrl->value; bt819_write(client, 0x0d, (decoder->sat >> 7) & 0xff); bt819_setbit(client, 0x0b, 1, ((decoder->sat >> 15) & 0x01)); 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(client, 0x0e, (temp >> 7) & 0xff); bt819_setbit(client, 0x0b, 0, (temp >> 15) & 0x01); } bt819_write(decoder, 0x0e, (temp >> 7) & 0xff); bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01); break; case V4L2_CID_HUE: if (decoder->hue != ctrl->value) { if (decoder->hue == ctrl->value) break; decoder->hue = ctrl->value; bt819_write(client, 0x0f, decoder->hue); } bt819_write(decoder, 0x0f, decoder->hue); break; default: return -EINVAL; } break; return 0; } case VIDIOC_G_CTRL: static int bt819_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct v4l2_control *ctrl = arg; struct bt819 *decoder = to_bt819(sd); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: Loading @@ -425,46 +416,84 @@ static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) default: return -EINVAL; } break; return 0; } default: return -EINVAL; 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); } return 0; static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) { return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); } /* ----------------------------------------------------------------------- */ 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, }; I2C_CLIENT_INSMOD; 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, }; /* ----------------------------------------------------------------------- */ 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; } Loading @@ -472,9 +501,6 @@ 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 = V4L2_STD_NTSC; decoder->input = 0; decoder->enable = 1; Loading @@ -482,18 +508,19 @@ static int bt819_probe(struct i2c_client *client, decoder->contrast = 0xd8; /* 100% of original signal */ decoder->hue = 0; decoder->sat = 0xfe; /* 100% of original signal */ decoder->initialized = 0; i2c_set_clientdata(client, decoder); i = bt819_init(client); 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; } Loading include/media/v4l2-chip-ident.h +5 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,11 @@ enum { V4L2_IDENT_CX23416 = 416, V4L2_IDENT_CX23418 = 418, /* module bt819: reserved range 810-819 */ V4L2_IDENT_BT815A = 815, V4L2_IDENT_BT817A = 817, V4L2_IDENT_BT819A = 819, /* module bt866: just ident 866 */ V4L2_IDENT_BT866 = 866, Loading Loading
drivers/media/video/bt819.c +252 −225 Original line number Diff line number Diff line Loading @@ -29,15 +29,14 @@ */ #include <linux/module.h> #include <linux/delay.h> #include <linux/types.h> #include <linux/ioctl.h> #include <asm/uaccess.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 <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-i2c-drv-legacy.h> MODULE_DESCRIPTION("Brooktree-819 video decoder driver"); Loading @@ -48,13 +47,18 @@ static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-1)"); static unsigned short normal_i2c[] = { 0x8a >> 1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ struct bt819 { struct v4l2_subdev sd; unsigned char reg[32]; int initialized; v4l2_std_id norm; int ident; int input; int enable; int bright; Loading @@ -63,6 +67,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; Loading @@ -80,24 +89,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; Loading @@ -105,7 +113,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; Loading @@ -126,7 +133,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; } Loading @@ -135,15 +143,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 */ Loading Loading @@ -178,6 +186,7 @@ static int bt819_init(struct i2c_client *client) 0x1a, 0x80, /* 0x1a ADC Interface */ }; struct bt819 *decoder = to_bt819(sd); struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0]; init[0x03 * 2 - 1] = Loading @@ -194,41 +203,22 @@ static int bt819_init(struct i2c_client *client) /* 0x15 in array is address 0x19 */ 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 = i2c_get_clientdata(client); if (!decoder->initialized) { /* First call to bt819_init could be */ bt819_init(client); /* without #FRST = 0 */ decoder->initialized = 1; } switch (cmd) { case VIDIOC_INT_INIT: /* This is just for testing!!! */ bt819_init(client); break; case VIDIOC_QUERYSTD: case VIDIOC_INT_G_INPUT_STATUS: { int *iarg = arg; v4l2_std_id *istd = arg; int status; struct bt819 *decoder = to_bt819(sd); int status = bt819_read(decoder, 0x00); int res = V4L2_IN_ST_NO_SIGNAL; v4l2_std_id std; status = bt819_read(client, 0x00); if ((status & 0x80)) res = 0; Loading @@ -236,66 +226,72 @@ static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) std = V4L2_STD_PAL; else std = V4L2_STD_NTSC; if (cmd == VIDIOC_QUERYSTD) *istd = std; else *iarg = res; if (pstd) *pstd = std; if (pstatus) *pstatus = status; v4l_dbg(1, debug, client, "get status %x\n", *iarg); break; v4l2_dbg(1, debug, sd, "get status %x\n", status); return 0; } static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) { return bt819_status(sd, NULL, std); } case VIDIOC_S_STD: static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status) { v4l2_std_id *iarg = arg; 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; v4l_dbg(1, debug, client, "set norm %llx\n", *iarg); v4l2_dbg(1, debug, sd, "set norm %llx\n", std); if (*iarg & V4L2_STD_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); */ if (std & V4L2_STD_NTSC) { 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 (*iarg & V4L2_STD_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); */ } else if (std & V4L2_STD_PAL) { 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 { v4l_dbg(1, debug, client, "unsupported norm %llx\n", *iarg); v4l2_dbg(1, debug, sd, "unsupported norm %llx\n", std); return -EINVAL; } /* case VIDEO_MODE_AUTO: bt819_setbit(client, 0x01, 0, 0); bt819_setbit(client, 0x01, 1, 0);*/ bt819_write(client, 0x03, 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(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); decoder->norm = *iarg; break; 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; return 0; } case VIDIOC_INT_S_VIDEO_ROUTING: static int bt819_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) { struct v4l2_routing *route = arg; struct bt819 *decoder = to_bt819(sd); v4l_dbg(1, debug, client, "set input %x\n", route->input); v4l2_dbg(1, debug, sd, "set input %x\n", route->input); if (route->input < 0 || route->input > 7) return -EINVAL; Loading @@ -304,34 +300,31 @@ static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) decoder->input = route->input; /* select mode */ if (decoder->input == 0) { bt819_setbit(client, 0x0b, 6, 0); bt819_setbit(client, 0x1a, 1, 1); bt819_setbit(decoder, 0x0b, 6, 0); bt819_setbit(decoder, 0x1a, 1, 1); } else { bt819_setbit(client, 0x0b, 6, 1); bt819_setbit(client, 0x1a, 1, 0); bt819_setbit(decoder, 0x0b, 6, 1); bt819_setbit(decoder, 0x1a, 1, 0); } } break; return 0; } case VIDIOC_STREAMON: case VIDIOC_STREAMOFF: static int bt819_s_stream(struct v4l2_subdev *sd, int enable) { int enable = cmd == VIDIOC_STREAMON; struct bt819 *decoder = to_bt819(sd); v4l_dbg(1, debug, client, "enable output %x\n", enable); v4l2_dbg(1, debug, sd, "enable output %x\n", enable); if (decoder->enable != enable) { decoder->enable = enable; bt819_setbit(client, 0x16, 7, !enable); bt819_setbit(decoder, 0x16, 7, !enable); } break; return 0; } case VIDIOC_QUERYCTRL: static int bt819_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) { struct v4l2_queryctrl *qc = arg; switch (qc->id) { case V4L2_CID_BRIGHTNESS: v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); Loading @@ -352,62 +345,60 @@ static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) default: return -EINVAL; } break; return 0; } case VIDIOC_S_CTRL: static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct v4l2_control *ctrl = arg; struct bt819 *decoder = to_bt819(sd); int temp; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: if (decoder->bright != ctrl->value) { if (decoder->bright == ctrl->value) break; decoder->bright = ctrl->value; bt819_write(client, 0x0a, decoder->bright); } bt819_write(decoder, 0x0a, decoder->bright); break; case V4L2_CID_CONTRAST: if (decoder->contrast != ctrl->value) { if (decoder->contrast == ctrl->value) break; decoder->contrast = ctrl->value; bt819_write(client, 0x0c, decoder->contrast & 0xff); bt819_setbit(client, 0x0b, 2, ((decoder->contrast >> 8) & 0x01)); } 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) { if (decoder->sat == ctrl->value) break; decoder->sat = ctrl->value; bt819_write(client, 0x0d, (decoder->sat >> 7) & 0xff); bt819_setbit(client, 0x0b, 1, ((decoder->sat >> 15) & 0x01)); 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(client, 0x0e, (temp >> 7) & 0xff); bt819_setbit(client, 0x0b, 0, (temp >> 15) & 0x01); } bt819_write(decoder, 0x0e, (temp >> 7) & 0xff); bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01); break; case V4L2_CID_HUE: if (decoder->hue != ctrl->value) { if (decoder->hue == ctrl->value) break; decoder->hue = ctrl->value; bt819_write(client, 0x0f, decoder->hue); } bt819_write(decoder, 0x0f, decoder->hue); break; default: return -EINVAL; } break; return 0; } case VIDIOC_G_CTRL: static int bt819_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct v4l2_control *ctrl = arg; struct bt819 *decoder = to_bt819(sd); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: Loading @@ -425,46 +416,84 @@ static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) default: return -EINVAL; } break; return 0; } default: return -EINVAL; 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); } return 0; static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg) { return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); } /* ----------------------------------------------------------------------- */ 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, }; I2C_CLIENT_INSMOD; 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, }; /* ----------------------------------------------------------------------- */ 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; } Loading @@ -472,9 +501,6 @@ 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 = V4L2_STD_NTSC; decoder->input = 0; decoder->enable = 1; Loading @@ -482,18 +508,19 @@ static int bt819_probe(struct i2c_client *client, decoder->contrast = 0xd8; /* 100% of original signal */ decoder->hue = 0; decoder->sat = 0xfe; /* 100% of original signal */ decoder->initialized = 0; i2c_set_clientdata(client, decoder); i = bt819_init(client); 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; } Loading
include/media/v4l2-chip-ident.h +5 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,11 @@ enum { V4L2_IDENT_CX23416 = 416, V4L2_IDENT_CX23418 = 418, /* module bt819: reserved range 810-819 */ V4L2_IDENT_BT815A = 815, V4L2_IDENT_BT817A = 817, V4L2_IDENT_BT819A = 819, /* module bt866: just ident 866 */ V4L2_IDENT_BT866 = 866, Loading