diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/upd64083.c | 166 |
1 files changed, 97 insertions, 69 deletions
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 9521ce004dc..58412cb9c01 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -26,7 +26,7 @@ #include <linux/kernel.h> #include <linux/i2c.h> #include <linux/videodev2.h> -#include <media/v4l2-common.h> +#include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-i2c-drv.h> #include <media/upd64083.h> @@ -51,11 +51,17 @@ enum { }; struct upd64083_state { + struct v4l2_subdev sd; u8 mode; u8 ext_y_adc; u8 regs[TOT_REGS]; }; +static inline struct upd64083_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct upd64083_state, sd); +} + /* Initial values when used in combination with the NEC upd64031a ghost reduction chip. */ static u8 upd64083_init[] = { @@ -68,34 +74,24 @@ static u8 upd64083_init[] = { /* ------------------------------------------------------------------------ */ -static void upd64083_log_status(struct i2c_client *client) -{ - u8 buf[7]; - - i2c_master_recv(client, buf, 7); - v4l_info(client, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x " - "SA04=%02x SA05=%02x SA06=%02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); -} - -/* ------------------------------------------------------------------------ */ - -static void upd64083_write(struct i2c_client *client, u8 reg, u8 val) +static void upd64083_write(struct v4l2_subdev *sd, u8 reg, u8 val) { + struct i2c_client *client = v4l2_get_subdevdata(sd); u8 buf[2]; buf[0] = reg; buf[1] = val; - v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val); + v4l2_dbg(1, debug, sd, "write reg: %02x val: %02x\n", reg, val); if (i2c_master_send(client, buf, 2) != 2) - v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val); + v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val); } /* ------------------------------------------------------------------------ */ #ifdef CONFIG_VIDEO_ADV_DEBUG -static u8 upd64083_read(struct i2c_client *client, u8 reg) +static u8 upd64083_read(struct v4l2_subdev *sd, u8 reg) { + struct i2c_client *client = v4l2_get_subdevdata(sd); u8 buf[7]; if (reg >= sizeof(buf)) @@ -107,67 +103,94 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg) /* ------------------------------------------------------------------------ */ -static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg) +static int upd64083_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) { - struct upd64083_state *state = i2c_get_clientdata(client); - struct v4l2_routing *route = arg; - - switch (cmd) { - case VIDIOC_INT_G_VIDEO_ROUTING: - route->input = (state->mode >> 6) | (state->ext_y_adc >> 3); - route->output = 0; - break; - - case VIDIOC_INT_S_VIDEO_ROUTING: - { - u8 r00, r02; - - if (route->input > 7 || (route->input & 6) == 6) - return -EINVAL; - state->mode = (route->input & 3) << 6; - state->ext_y_adc = (route->input & UPD64083_EXT_Y_ADC) << 3; - r00 = (state->regs[R00] & ~(3 << 6)) | state->mode; - r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc; - upd64083_write(client, R00, r00); - upd64083_write(client, R02, r02); - break; - } - - case VIDIOC_LOG_STATUS: - upd64083_log_status(client); - break; + struct upd64083_state *state = to_state(sd); + u8 r00, r02; + + if (route->input > 7 || (route->input & 6) == 6) + return -EINVAL; + state->mode = (route->input & 3) << 6; + state->ext_y_adc = (route->input & UPD64083_EXT_Y_ADC) << 3; + r00 = (state->regs[R00] & ~(3 << 6)) | state->mode; + r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc; + upd64083_write(sd, R00, r00); + upd64083_write(sd, R02, r02); + return 0; +} #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - { - struct v4l2_register *reg = arg; +static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + reg->val = upd64083_read(sd, reg->reg & 0xff); + return 0; +} - if (!v4l2_chip_match_i2c_client(client, +static int upd64083_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (cmd == VIDIOC_DBG_G_REGISTER) { - reg->val = upd64083_read(client, reg->reg & 0xff); - break; - } - upd64083_write(client, reg->reg & 0xff, reg->val & 0xff); - break; - } + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + upd64083_write(sd, reg->reg & 0xff, reg->val & 0xff); + return 0; +} #endif - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, - V4L2_IDENT_UPD64083, 0); +static int upd64083_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64083, 0); +} - default: - break; - } +static int upd64083_log_status(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 buf[7]; + i2c_master_recv(client, buf, 7); + v4l2_info(sd, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x " + "SA04=%02x SA05=%02x SA06=%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); return 0; } +static int upd64083_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 upd64083_core_ops = { + .log_status = upd64083_log_status, + .g_chip_ident = upd64083_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = upd64083_g_register, + .s_register = upd64083_s_register, +#endif +}; + +static const struct v4l2_subdev_video_ops upd64083_video_ops = { + .s_routing = upd64083_s_routing, +}; + +static const struct v4l2_subdev_ops upd64083_ops = { + .core = &upd64083_core_ops, + .video = &upd64083_video_ops, +}; + /* ------------------------------------------------------------------------ */ /* i2c implementation */ @@ -176,6 +199,7 @@ static int upd64083_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct upd64083_state *state; + struct v4l2_subdev *sd; int i; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -187,19 +211,23 @@ static int upd64083_probe(struct i2c_client *client, state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; - i2c_set_clientdata(client, state); + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &upd64083_ops); /* Initially assume that a ghost reduction chip is present */ state->mode = 0; /* YCS mode */ state->ext_y_adc = (1 << 5); memcpy(state->regs, upd64083_init, TOT_REGS); for (i = 0; i < TOT_REGS; i++) - upd64083_write(client, i, state->regs[i]); + upd64083_write(sd, i, state->regs[i]); return 0; } static int upd64083_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_state(sd)); return 0; } |