From 2a2d1cf46500ab7599d0b45ee837f3936763ccac Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Aug 2012 17:15:52 -0300 Subject: [media] move soc_camera i2c drivers into its own dir Move all soc_camera i2c drivers into drivers/media/i2c/soc_camera/. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/mt9v022.c | 879 +++++++++++++++++++++++++++++++++ 1 file changed, 879 insertions(+) create mode 100644 drivers/media/i2c/soc_camera/mt9v022.c (limited to 'drivers/media/i2c/soc_camera/mt9v022.c') diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c new file mode 100644 index 000000000000..72479247522a --- /dev/null +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -0,0 +1,879 @@ +/* + * Driver for MT9V022 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c + * The platform has to define struct i2c_board_info objects and link to them + * from struct soc_camera_link + */ + +static char *sensor_type; +module_param(sensor_type, charp, S_IRUGO); +MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); + +/* mt9v022 selected register addresses */ +#define MT9V022_CHIP_VERSION 0x00 +#define MT9V022_COLUMN_START 0x01 +#define MT9V022_ROW_START 0x02 +#define MT9V022_WINDOW_HEIGHT 0x03 +#define MT9V022_WINDOW_WIDTH 0x04 +#define MT9V022_HORIZONTAL_BLANKING 0x05 +#define MT9V022_VERTICAL_BLANKING 0x06 +#define MT9V022_CHIP_CONTROL 0x07 +#define MT9V022_SHUTTER_WIDTH1 0x08 +#define MT9V022_SHUTTER_WIDTH2 0x09 +#define MT9V022_SHUTTER_WIDTH_CTRL 0x0a +#define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b +#define MT9V022_RESET 0x0c +#define MT9V022_READ_MODE 0x0d +#define MT9V022_MONITOR_MODE 0x0e +#define MT9V022_PIXEL_OPERATION_MODE 0x0f +#define MT9V022_LED_OUT_CONTROL 0x1b +#define MT9V022_ADC_MODE_CONTROL 0x1c +#define MT9V022_ANALOG_GAIN 0x35 +#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 +#define MT9V022_PIXCLK_FV_LV 0x74 +#define MT9V022_DIGITAL_TEST_PATTERN 0x7f +#define MT9V022_AEC_AGC_ENABLE 0xAF +#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD + +/* Progressive scan, master, defaults */ +#define MT9V022_CHIP_CONTROL_DEFAULT 0x188 + +#define MT9V022_MAX_WIDTH 752 +#define MT9V022_MAX_HEIGHT 480 +#define MT9V022_MIN_WIDTH 48 +#define MT9V022_MIN_HEIGHT 32 +#define MT9V022_COLUMN_SKIP 1 +#define MT9V022_ROW_SKIP 4 + +/* MT9V022 has only one fixed colorspace per pixelcode */ +struct mt9v022_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct mt9v022_datafmt *mt9v022_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct mt9v022_datafmt mt9v022_colour_fmts[] = { + /* + * Order important: first natively supported, + * second supported with a GPIO extender + */ + {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, +}; + +static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { + /* Order important - see above */ + {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, +}; + +struct mt9v022 { + struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct { + /* exposure/auto-exposure cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; + struct { + /* gain/auto-gain cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; + struct v4l2_rect rect; /* Sensor window */ + const struct mt9v022_datafmt *fmt; + const struct mt9v022_datafmt *fmts; + int num_fmts; + int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ + u16 chip_control; + unsigned short y_skip_top; /* Lines to skip at the top */ +}; + +static struct mt9v022 *to_mt9v022(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct mt9v022, subdev); +} + +static int reg_read(struct i2c_client *client, const u8 reg) +{ + return i2c_smbus_read_word_swapped(client, reg); +} + +static int reg_write(struct i2c_client *client, const u8 reg, + const u16 data) +{ + return i2c_smbus_write_word_swapped(client, reg, data); +} + +static int reg_set(struct i2c_client *client, const u8 reg, + const u16 data) +{ + int ret; + + ret = reg_read(client, reg); + if (ret < 0) + return ret; + return reg_write(client, reg, ret | data); +} + +static int reg_clear(struct i2c_client *client, const u8 reg, + const u16 data) +{ + int ret; + + ret = reg_read(client, reg); + if (ret < 0) + return ret; + return reg_write(client, reg, ret & ~data); +} + +static int mt9v022_init(struct i2c_client *client) +{ + struct mt9v022 *mt9v022 = to_mt9v022(client); + int ret; + + /* + * Almost the default mode: master, parallel, simultaneous, and an + * undocumented bit 0x200, which is present in table 7, but not in 8, + * plus snapshot mode to disable scan for now + */ + mt9v022->chip_control |= 0x10; + ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); + if (!ret) + ret = reg_write(client, MT9V022_READ_MODE, 0x300); + + /* All defaults */ + if (!ret) + /* AEC, AGC on */ + ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); + if (!ret) + ret = reg_write(client, MT9V022_ANALOG_GAIN, 16); + if (!ret) + ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480); + if (!ret) + ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); + if (!ret) + /* default - auto */ + ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); + if (!ret) + ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); + if (!ret) + return v4l2_ctrl_handler_setup(&mt9v022->hdl); + + return ret; +} + +static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + if (enable) + /* Switch to master "normal" mode */ + mt9v022->chip_control &= ~0x10; + else + /* Switch to snapshot mode */ + mt9v022->chip_control |= 0x10; + + if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) + return -EIO; + return 0; +} + +static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + struct v4l2_rect rect = a->c; + int ret; + + /* Bayer format - even size lengths */ + if (mt9v022->fmts == mt9v022_colour_fmts) { + rect.width = ALIGN(rect.width, 2); + rect.height = ALIGN(rect.height, 2); + /* Let the user play with the starting pixel */ + } + + soc_camera_limit_side(&rect.left, &rect.width, + MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH); + + soc_camera_limit_side(&rect.top, &rect.height, + MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT); + + /* Like in example app. Contradicts the datasheet though */ + ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); + if (ret >= 0) { + if (ret & 1) /* Autoexposure */ + ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, + rect.height + mt9v022->y_skip_top + 43); + else + ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, + rect.height + mt9v022->y_skip_top + 43); + } + /* Setup frame format: defaults apart from width and height */ + if (!ret) + ret = reg_write(client, MT9V022_COLUMN_START, rect.left); + if (!ret) + ret = reg_write(client, MT9V022_ROW_START, rect.top); + if (!ret) + /* + * Default 94, Phytec driver says: + * "width + horizontal blank >= 660" + */ + ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, + rect.width > 660 - 43 ? 43 : + 660 - rect.width); + if (!ret) + ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); + if (!ret) + ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); + if (!ret) + ret = reg_write(client, MT9V022_WINDOW_HEIGHT, + rect.height + mt9v022->y_skip_top); + + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height); + + mt9v022->rect = rect; + + return 0; +} + +static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + a->c = mt9v022->rect; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = MT9V022_COLUMN_SKIP; + a->bounds.top = MT9V022_ROW_SKIP; + a->bounds.width = MT9V022_MAX_WIDTH; + a->bounds.height = MT9V022_MAX_HEIGHT; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int mt9v022_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + mf->width = mt9v022->rect.width; + mf->height = mt9v022->rect.height; + mf->code = mt9v022->fmt->code; + mf->colorspace = mt9v022->fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9v022_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + struct v4l2_crop a = { + .c = { + .left = mt9v022->rect.left, + .top = mt9v022->rect.top, + .width = mf->width, + .height = mf->height, + }, + }; + int ret; + + /* + * The caller provides a supported format, as verified per call to + * .try_mbus_fmt(), datawidth is from our supported format list + */ + switch (mf->code) { + case V4L2_MBUS_FMT_Y8_1X8: + case V4L2_MBUS_FMT_Y10_1X10: + if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) + return -EINVAL; + break; + case V4L2_MBUS_FMT_SBGGR8_1X8: + case V4L2_MBUS_FMT_SBGGR10_1X10: + if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) + return -EINVAL; + break; + default: + return -EINVAL; + } + + /* No support for scaling on this camera, just crop. */ + ret = mt9v022_s_crop(sd, &a); + if (!ret) { + mf->width = mt9v022->rect.width; + mf->height = mt9v022->rect.height; + mt9v022->fmt = mt9v022_find_datafmt(mf->code, + mt9v022->fmts, mt9v022->num_fmts); + mf->colorspace = mt9v022->fmt->colorspace; + } + + return ret; +} + +static int mt9v022_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + const struct mt9v022_datafmt *fmt; + int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + mf->code == V4L2_MBUS_FMT_SBGGR10_1X10; + + v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH, + MT9V022_MAX_WIDTH, align, + &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top, + MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0); + + fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts, + mt9v022->num_fmts); + if (!fmt) { + fmt = mt9v022->fmt; + mf->code = fmt->code; + } + + mf->colorspace = fmt->colorspace; + + return 0; +} + +static int mt9v022_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = mt9v022->model; + id->revision = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9v022_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + reg->size = 2; + reg->val = reg_read(client, reg->reg); + + if (reg->val > 0xffff) + return -EIO; + + return 0; +} + +static int mt9v022_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + if (reg_write(client, reg->reg, reg->val) < 0) + return -EIO; + + return 0; +} +#endif + +static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9v022 *mt9v022 = container_of(ctrl->handler, + struct mt9v022, hdl); + struct v4l2_subdev *sd = &mt9v022->subdev; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_ctrl *gain = mt9v022->gain; + struct v4l2_ctrl *exp = mt9v022->exposure; + unsigned long range; + int data; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + data = reg_read(client, MT9V022_ANALOG_GAIN); + if (data < 0) + return -EIO; + + range = gain->maximum - gain->minimum; + gain->val = ((data - 16) * range + 24) / 48 + gain->minimum; + return 0; + case V4L2_CID_EXPOSURE_AUTO: + data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); + if (data < 0) + return -EIO; + + range = exp->maximum - exp->minimum; + exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; + return 0; + } + return -EINVAL; +} + +static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9v022 *mt9v022 = container_of(ctrl->handler, + struct mt9v022, hdl); + struct v4l2_subdev *sd = &mt9v022->subdev; + struct i2c_client *client = v4l2_get_subdevdata(sd); + int data; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (ctrl->val) + data = reg_set(client, MT9V022_READ_MODE, 0x10); + else + data = reg_clear(client, MT9V022_READ_MODE, 0x10); + if (data < 0) + return -EIO; + return 0; + case V4L2_CID_HFLIP: + if (ctrl->val) + data = reg_set(client, MT9V022_READ_MODE, 0x20); + else + data = reg_clear(client, MT9V022_READ_MODE, 0x20); + if (data < 0) + return -EIO; + return 0; + case V4L2_CID_AUTOGAIN: + if (ctrl->val) { + if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) + return -EIO; + } else { + struct v4l2_ctrl *gain = mt9v022->gain; + /* mt9v022 has minimum == default */ + unsigned long range = gain->maximum - gain->minimum; + /* Valid values 16 to 64, 32 to 64 must be even. */ + unsigned long gain_val = ((gain->val - gain->minimum) * + 48 + range / 2) / range + 16; + + if (gain_val >= 32) + gain_val &= ~1; + + /* + * The user wants to set gain manually, hope, she + * knows, what she's doing... Switch AGC off. + */ + if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) + return -EIO; + + dev_dbg(&client->dev, "Setting gain from %d to %lu\n", + reg_read(client, MT9V022_ANALOG_GAIN), gain_val); + if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0) + return -EIO; + } + return 0; + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_AUTO) { + data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); + } else { + struct v4l2_ctrl *exp = mt9v022->exposure; + unsigned long range = exp->maximum - exp->minimum; + unsigned long shutter = ((exp->val - exp->minimum) * + 479 + range / 2) / range + 1; + + /* + * The user wants to set shutter width manually, hope, + * she knows, what she's doing... Switch AEC off. + */ + data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); + if (data < 0) + return -EIO; + dev_dbg(&client->dev, "Shutter width from %d to %lu\n", + reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), + shutter); + if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, + shutter) < 0) + return -EIO; + } + return 0; + } + return -EINVAL; +} + +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ +static int mt9v022_video_probe(struct i2c_client *client) +{ + struct mt9v022 *mt9v022 = to_mt9v022(client); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + s32 data; + int ret; + unsigned long flags; + + /* Read out the chip version register */ + data = reg_read(client, MT9V022_CHIP_VERSION); + + /* must be 0x1311 or 0x1313 */ + if (data != 0x1311 && data != 0x1313) { + ret = -ENODEV; + dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n", + data); + goto ei2c; + } + + /* Soft reset */ + ret = reg_write(client, MT9V022_RESET, 1); + if (ret < 0) + goto ei2c; + /* 15 clock cycles */ + udelay(200); + if (reg_read(client, MT9V022_RESET)) { + dev_err(&client->dev, "Resetting MT9V022 failed!\n"); + if (ret > 0) + ret = -EIO; + goto ei2c; + } + + /* Set monochrome or colour sensor type */ + if (sensor_type && (!strcmp("colour", sensor_type) || + !strcmp("color", sensor_type))) { + ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); + mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; + mt9v022->fmts = mt9v022_colour_fmts; + } else { + ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); + mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; + mt9v022->fmts = mt9v022_monochrome_fmts; + } + + if (ret < 0) + goto ei2c; + + mt9v022->num_fmts = 0; + + /* + * This is a 10bit sensor, so by default we only allow 10bit. + * The platform may support different bus widths due to + * different routing of the data lines. + */ + if (icl->query_bus_param) + flags = icl->query_bus_param(icl); + else + flags = SOCAM_DATAWIDTH_10; + + if (flags & SOCAM_DATAWIDTH_10) + mt9v022->num_fmts++; + else + mt9v022->fmts++; + + if (flags & SOCAM_DATAWIDTH_8) + mt9v022->num_fmts++; + + mt9v022->fmt = &mt9v022->fmts[0]; + + dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", + data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? + "monochrome" : "colour"); + + ret = mt9v022_init(client); + if (ret < 0) + dev_err(&client->dev, "Failed to initialise the camera\n"); + +ei2c: + return ret; +} + +static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + *lines = mt9v022->y_skip_top; + + return 0; +} + +static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = { + .g_volatile_ctrl = mt9v022_g_volatile_ctrl, + .s_ctrl = mt9v022_s_ctrl, +}; + +static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { + .g_chip_ident = mt9v022_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9v022_g_register, + .s_register = mt9v022_s_register, +#endif +}; + +static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + if (index >= mt9v022->num_fmts) + return -EINVAL; + + *code = mt9v022->fmts[index].code; + return 0; +} + +static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | + V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + +static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + struct mt9v022 *mt9v022 = to_mt9v022(client); + unsigned long flags = soc_camera_apply_board_flags(icl, cfg); + unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample; + int ret; + u16 pixclk = 0; + + if (icl->set_bus_param) { + ret = icl->set_bus_param(icl, 1 << (bps - 1)); + if (ret) + return ret; + } else if (bps != 10) { + /* + * Without board specific bus width settings we only support the + * sensors native bus width + */ + return -EINVAL; + } + + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + pixclk |= 0x10; + + if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)) + pixclk |= 0x1; + + if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)) + pixclk |= 0x2; + + ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); + if (ret < 0) + return ret; + + if (!(flags & V4L2_MBUS_MASTER)) + mt9v022->chip_control &= ~0x8; + + ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", + pixclk, mt9v022->chip_control); + + return 0; +} + +static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { + .s_stream = mt9v022_s_stream, + .s_mbus_fmt = mt9v022_s_fmt, + .g_mbus_fmt = mt9v022_g_fmt, + .try_mbus_fmt = mt9v022_try_fmt, + .s_crop = mt9v022_s_crop, + .g_crop = mt9v022_g_crop, + .cropcap = mt9v022_cropcap, + .enum_mbus_fmt = mt9v022_enum_fmt, + .g_mbus_config = mt9v022_g_mbus_config, + .s_mbus_config = mt9v022_s_mbus_config, +}; + +static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { + .g_skip_top_lines = mt9v022_g_skip_top_lines, +}; + +static struct v4l2_subdev_ops mt9v022_subdev_ops = { + .core = &mt9v022_subdev_core_ops, + .video = &mt9v022_subdev_video_ops, + .sensor = &mt9v022_subdev_sensor_ops, +}; + +static int mt9v022_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9v022 *mt9v022; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; + + if (!icl) { + dev_err(&client->dev, "MT9V022 driver needs platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL); + if (!mt9v022) + return -ENOMEM; + + v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); + v4l2_ctrl_handler_init(&mt9v022->hdl, 6); + v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 64); + + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ + mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl, + &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 255, 1, 255); + + mt9v022->subdev.ctrl_handler = &mt9v022->hdl; + if (mt9v022->hdl.error) { + int err = mt9v022->hdl.error; + + kfree(mt9v022); + return err; + } + v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure, + V4L2_EXPOSURE_MANUAL, true); + v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true); + + mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; + + /* + * MT9V022 _really_ corrupts the first read out line. + * TODO: verify on i.MX31 + */ + mt9v022->y_skip_top = 1; + mt9v022->rect.left = MT9V022_COLUMN_SKIP; + mt9v022->rect.top = MT9V022_ROW_SKIP; + mt9v022->rect.width = MT9V022_MAX_WIDTH; + mt9v022->rect.height = MT9V022_MAX_HEIGHT; + + ret = mt9v022_video_probe(client); + if (ret) { + v4l2_ctrl_handler_free(&mt9v022->hdl); + kfree(mt9v022); + } + + return ret; +} + +static int mt9v022_remove(struct i2c_client *client) +{ + struct mt9v022 *mt9v022 = to_mt9v022(client); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + v4l2_device_unregister_subdev(&mt9v022->subdev); + if (icl->free_bus) + icl->free_bus(icl); + v4l2_ctrl_handler_free(&mt9v022->hdl); + kfree(mt9v022); + + return 0; +} +static const struct i2c_device_id mt9v022_id[] = { + { "mt9v022", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9v022_id); + +static struct i2c_driver mt9v022_i2c_driver = { + .driver = { + .name = "mt9v022", + }, + .probe = mt9v022_probe, + .remove = mt9v022_remove, + .id_table = mt9v022_id, +}; + +module_i2c_driver(mt9v022_i2c_driver); + +MODULE_DESCRIPTION("Micron MT9V022 Camera driver"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4ec10bacd6bf08de39ebdba9e75060452cc313e0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 20 Jul 2012 10:19:50 -0300 Subject: [media] soc-camera: Add and use soc_camera_power_[on|off]() helper functions Instead of forcing all soc-camera drivers to go through the mid-layer to handle power management, create soc_camera_power_[on|off]() functions that can be called from the subdev .s_power() operation to manage regulators and platform-specific power handling. This allows non soc-camera hosts to use soc-camera-aware clients. Signed-off-by: Laurent Pinchart [g.liakhovetski@gmx.de: fix compile breakage] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/imx074.c | 9 +++ drivers/media/i2c/soc_camera/mt9m001.c | 9 +++ drivers/media/i2c/soc_camera/mt9m111.c | 52 +++++++++++----- drivers/media/i2c/soc_camera/mt9t031.c | 11 +++- drivers/media/i2c/soc_camera/mt9t112.c | 9 +++ drivers/media/i2c/soc_camera/mt9v022.c | 9 +++ drivers/media/i2c/soc_camera/ov2640.c | 9 +++ drivers/media/i2c/soc_camera/ov5642.c | 10 +++- drivers/media/i2c/soc_camera/ov6650.c | 9 +++ drivers/media/i2c/soc_camera/ov772x.c | 9 +++ drivers/media/i2c/soc_camera/ov9640.c | 10 +++- drivers/media/i2c/soc_camera/ov9740.c | 24 +++++--- drivers/media/i2c/soc_camera/rj54n1cb0c.c | 9 +++ drivers/media/i2c/soc_camera/tw9910.c | 9 +++ drivers/media/platform/soc_camera.c | 89 +++++++++++++++------------- drivers/media/platform/soc_camera_platform.c | 11 +++- include/media/soc_camera.h | 10 ++++ 17 files changed, 229 insertions(+), 69 deletions(-) (limited to 'drivers/media/i2c/soc_camera/mt9v022.c') diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c index 351e9bafe8fe..ade19873ed83 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/media/i2c/soc_camera/imx074.c @@ -268,6 +268,14 @@ static int imx074_g_chip_ident(struct v4l2_subdev *sd, return 0; } +static int imx074_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + static int imx074_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { @@ -292,6 +300,7 @@ static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { .g_chip_ident = imx074_g_chip_ident, + .s_power = imx074_s_power, }; static struct v4l2_subdev_ops imx074_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index 00583f5fd26b..cd71230c51a9 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -377,6 +377,14 @@ static int mt9m001_s_register(struct v4l2_subdev *sd, } #endif +static int mt9m001_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { struct mt9m001 *mt9m001 = container_of(ctrl->handler, @@ -566,6 +574,7 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { .g_register = mt9m001_g_register, .s_register = mt9m001_s_register, #endif + .s_power = mt9m001_s_power, }; static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 863d722dda06..e555f7739691 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -831,10 +831,37 @@ static int mt9m111_video_probe(struct i2c_client *client) return v4l2_ctrl_handler_setup(&mt9m111->hdl); } +static int mt9m111_power_on(struct mt9m111 *mt9m111) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + int ret; + + ret = soc_camera_power_on(&client->dev, icl); + if (ret < 0) + return ret; + + ret = mt9m111_resume(mt9m111); + if (ret < 0) { + dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); + soc_camera_power_off(&client->dev, icl); + } + + return ret; +} + +static void mt9m111_power_off(struct mt9m111 *mt9m111) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + mt9m111_suspend(mt9m111); + soc_camera_power_off(&client->dev, icl); +} + static int mt9m111_s_power(struct v4l2_subdev *sd, int on) { struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&mt9m111->power_lock); @@ -844,23 +871,18 @@ static int mt9m111_s_power(struct v4l2_subdev *sd, int on) * update the power state. */ if (mt9m111->power_count == !on) { - if (on) { - ret = mt9m111_resume(mt9m111); - if (ret) { - dev_err(&client->dev, - "Failed to resume the sensor: %d\n", ret); - goto out; - } - } else { - mt9m111_suspend(mt9m111); - } + if (on) + ret = mt9m111_power_on(mt9m111); + else + mt9m111_power_off(mt9m111); } - /* Update the power count. */ - mt9m111->power_count += on ? 1 : -1; - WARN_ON(mt9m111->power_count < 0); + if (!ret) { + /* Update the power count. */ + mt9m111->power_count += on ? 1 : -1; + WARN_ON(mt9m111->power_count < 0); + } -out: mutex_unlock(&mt9m111->power_lock); return ret; } diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 1415074138a5..9666e202e395 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -616,12 +616,19 @@ static struct device_type mt9t031_dev_type = { static int mt9t031_s_power(struct v4l2_subdev *sd, int on) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct video_device *vdev = soc_camera_i2c_to_vdev(client); + int ret; - if (on) + if (on) { + ret = soc_camera_power_on(&client->dev, icl); + if (ret < 0) + return ret; vdev->dev.type = &mt9t031_dev_type; - else + } else { vdev->dev.type = NULL; + soc_camera_power_off(&client->dev, icl); + } return 0; } diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index e1ae46a7ee96..624ceec44e18 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -776,12 +776,21 @@ static int mt9t112_s_register(struct v4l2_subdev *sd, } #endif +static int mt9t112_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { .g_chip_ident = mt9t112_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9t112_g_register, .s_register = mt9t112_s_register, #endif + .s_power = mt9t112_s_power, }; diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 72479247522a..5f09cb702bf7 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -445,6 +445,14 @@ static int mt9v022_s_register(struct v4l2_subdev *sd, } #endif +static int mt9v022_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { struct mt9v022 *mt9v022 = container_of(ctrl->handler, @@ -664,6 +672,7 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { .g_register = mt9v022_g_register, .s_register = mt9v022_s_register, #endif + .s_power = mt9v022_s_power, }; static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 7c44d1fe3c87..16ed091c702d 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -742,6 +742,14 @@ static int ov2640_s_register(struct v4l2_subdev *sd, } #endif +static int ov2640_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + /* Select the nearest higher resolution for capture */ static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height) { @@ -988,6 +996,7 @@ static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { .g_register = ov2640_g_register, .s_register = ov2640_s_register, #endif + .s_power = ov2640_s_power, }; static int ov2640_g_mbus_config(struct v4l2_subdev *sd, diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index 0bc93313d37a..61824c6911d5 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c @@ -933,13 +933,17 @@ static int ov5642_g_mbus_config(struct v4l2_subdev *sd, static int ov5642_s_power(struct v4l2_subdev *sd, int on) { - struct i2c_client *client; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; if (!on) - return 0; + return soc_camera_power_off(&client->dev, icl); + + ret = soc_camera_power_on(&client->dev, icl); + if (ret < 0) + return ret; - client = v4l2_get_subdevdata(sd); ret = ov5642_write_array(client, ov5642_default_regs_init); if (!ret) ret = ov5642_set_resolution(sd); diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index 3e028b1970dd..12d57a5dd810 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -432,6 +432,14 @@ static int ov6650_set_register(struct v4l2_subdev *sd, } #endif +static int ov6650_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -866,6 +874,7 @@ static struct v4l2_subdev_core_ops ov6650_core_ops = { .g_register = ov6650_get_register, .s_register = ov6650_set_register, #endif + .s_power = ov6650_s_power, }; /* Request bus settings on camera side */ diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 6d79b89b8603..a022662da98a 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -683,6 +683,14 @@ static int ov772x_s_register(struct v4l2_subdev *sd, } #endif +static int ov772x_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) { __u32 diff; @@ -996,6 +1004,7 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { .g_register = ov772x_g_register, .s_register = ov772x_s_register, #endif + .s_power = ov772x_s_power, }; static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index, diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index 9ed4ba4236c4..53156ef1ec0c 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -333,6 +333,14 @@ static int ov9640_set_register(struct v4l2_subdev *sd, } #endif +static int ov9640_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + /* select nearest higher resolution for capture */ static void ov9640_res_roundup(u32 *width, u32 *height) { @@ -632,7 +640,7 @@ static struct v4l2_subdev_core_ops ov9640_core_ops = { .g_register = ov9640_get_register, .s_register = ov9640_set_register, #endif - + .s_power = ov9640_s_power, }; /* Request bus settings on camera side */ diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 3eb07c22516e..10c0ba9f5bcd 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -786,17 +786,27 @@ static int ov9740_g_chip_ident(struct v4l2_subdev *sd, static int ov9740_s_power(struct v4l2_subdev *sd, int on) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct ov9740_priv *priv = to_ov9740(sd); - - if (!priv->current_enable) - return 0; + int ret; if (on) { - ov9740_s_fmt(sd, &priv->current_mf); - ov9740_s_stream(sd, priv->current_enable); + ret = soc_camera_power_on(&client->dev, icl); + if (ret < 0) + return ret; + + if (priv->current_enable) { + ov9740_s_fmt(sd, &priv->current_mf); + ov9740_s_stream(sd, 1); + } } else { - ov9740_s_stream(sd, 0); - priv->current_enable = true; + if (priv->current_enable) { + ov9740_s_stream(sd, 0); + priv->current_enable = true; + } + + soc_camera_power_off(&client->dev, icl); } return 0; diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index f6419b22c258..ca1cee7c66cb 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -1180,6 +1180,14 @@ static int rj54n1_s_register(struct v4l2_subdev *sd, } #endif +static int rj54n1_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl) { struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl); @@ -1230,6 +1238,7 @@ static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { .g_register = rj54n1_g_register, .s_register = rj54n1_s_register, #endif + .s_power = rj54n1_s_power, }; static int rj54n1_g_mbus_config(struct v4l2_subdev *sd, diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index 9f53eacb66e3..f28365051878 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -566,6 +566,14 @@ static int tw9910_s_register(struct v4l2_subdev *sd, } #endif +static int tw9910_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + + return soc_camera_set_power(&client->dev, icl, on); +} + static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -814,6 +822,7 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { .g_register = tw9910_g_register, .s_register = tw9910_s_register, #endif + .s_power = tw9910_s_power, }; static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index, diff --git a/drivers/media/platform/soc_camera.c b/drivers/media/platform/soc_camera.c index 3feb43b4f281..8e1548e16f54 100644 --- a/drivers/media/platform/soc_camera.c +++ b/drivers/media/platform/soc_camera.c @@ -50,72 +50,77 @@ static LIST_HEAD(hosts); static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ -static int soc_camera_power_on(struct soc_camera_device *icd, - struct soc_camera_link *icl) +int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl) { - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); int ret = regulator_bulk_enable(icl->num_regulators, icl->regulators); if (ret < 0) { - dev_err(icd->pdev, "Cannot enable regulators\n"); + dev_err(dev, "Cannot enable regulators\n"); return ret; } if (icl->power) { - ret = icl->power(icd->control, 1); + ret = icl->power(dev, 1); if (ret < 0) { - dev_err(icd->pdev, + dev_err(dev, "Platform failed to power-on the camera.\n"); - goto elinkpwr; + regulator_bulk_disable(icl->num_regulators, + icl->regulators); } } - ret = v4l2_subdev_call(sd, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) - goto esdpwr; - - return 0; - -esdpwr: - if (icl->power) - icl->power(icd->control, 0); -elinkpwr: - regulator_bulk_disable(icl->num_regulators, - icl->regulators); return ret; } +EXPORT_SYMBOL(soc_camera_power_on); -static int soc_camera_power_off(struct soc_camera_device *icd, - struct soc_camera_link *icl) +int soc_camera_power_off(struct device *dev, struct soc_camera_link *icl) { - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); int ret = 0; int err; - err = v4l2_subdev_call(sd, core, s_power, 0); - if (err < 0 && err != -ENOIOCTLCMD && err != -ENODEV) { - dev_err(icd->pdev, "Subdev failed to power-off the camera.\n"); - ret = err; - } - if (icl->power) { - err = icl->power(icd->control, 0); + err = icl->power(dev, 0); if (err < 0) { - dev_err(icd->pdev, + dev_err(dev, "Platform failed to power-off the camera.\n"); - ret = ret ? : err; + ret = err; } } err = regulator_bulk_disable(icl->num_regulators, icl->regulators); if (err < 0) { - dev_err(icd->pdev, "Cannot disable regulators\n"); + dev_err(dev, "Cannot disable regulators\n"); ret = ret ? : err; } return ret; } +EXPORT_SYMBOL(soc_camera_power_off); + +static int __soc_camera_power_on(struct soc_camera_device *icd) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + int ret; + + ret = v4l2_subdev_call(sd, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + + return 0; +} + +static int __soc_camera_power_off(struct soc_camera_device *icd) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + int ret; + + ret = v4l2_subdev_call(sd, core, s_power, 0); + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + + return 0; +} const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( struct soc_camera_device *icd, unsigned int fourcc) @@ -551,7 +556,7 @@ static int soc_camera_open(struct file *file) goto eiciadd; } - ret = soc_camera_power_on(icd, icl); + ret = __soc_camera_power_on(icd); if (ret < 0) goto epower; @@ -594,7 +599,7 @@ einitvb: esfmt: pm_runtime_disable(&icd->vdev->dev); eresume: - soc_camera_power_off(icd, icl); + __soc_camera_power_off(icd); epower: ici->ops->remove(icd); eiciadd: @@ -614,8 +619,6 @@ static int soc_camera_close(struct file *file) mutex_lock(&icd->video_lock); icd->use_count--; if (!icd->use_count) { - struct soc_camera_link *icl = to_soc_camera_link(icd); - pm_runtime_suspend(&icd->vdev->dev); pm_runtime_disable(&icd->vdev->dev); @@ -623,7 +626,7 @@ static int soc_camera_close(struct file *file) vb2_queue_release(&icd->vb2_vidq); ici->ops->remove(icd); - soc_camera_power_off(icd, icl); + __soc_camera_power_off(icd); } if (icd->streamer == file) @@ -1088,8 +1091,14 @@ static int soc_camera_probe(struct soc_camera_device *icd) * subdevice has not been initialised yet. We'll have to call it once * again after initialisation, even though it shouldn't be needed, we * don't do any IO here. + * + * The device pointer passed to soc_camera_power_on(), and ultimately to + * the platform callback, should be the subdev physical device. However, + * we have no way to retrieve a pointer to that device here. This isn't + * a real issue, as no platform currently uses the device pointer, and + * this soc_camera_power_on() call will be removed in the next commit. */ - ret = soc_camera_power_on(icd, icl); + ret = soc_camera_power_on(icd->pdev, icl); if (ret < 0) goto epower; @@ -1162,7 +1171,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) ici->ops->remove(icd); - soc_camera_power_off(icd, icl); + __soc_camera_power_off(icd); mutex_unlock(&icd->video_lock); @@ -1184,7 +1193,7 @@ eadddev: video_device_release(icd->vdev); icd->vdev = NULL; evdc: - soc_camera_power_off(icd, icl); + __soc_camera_power_off(icd); epower: ici->ops->remove(icd); eadd: diff --git a/drivers/media/platform/soc_camera_platform.c b/drivers/media/platform/soc_camera_platform.c index f59ccade07c8..7cf7fd16481f 100644 --- a/drivers/media/platform/soc_camera_platform.c +++ b/drivers/media/platform/soc_camera_platform.c @@ -50,7 +50,16 @@ static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, return 0; } -static struct v4l2_subdev_core_ops platform_subdev_core_ops; +static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on) +{ + struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); + + return soc_camera_set_power(p->icd->control, p->icd->link, on); +} + +static struct v4l2_subdev_core_ops platform_subdev_core_ops = { + .s_power = soc_camera_platform_s_power, +}; static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index d865dcf9879f..982bfc948414 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -254,6 +254,16 @@ unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, const struct v4l2_mbus_config *cfg); +int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl); +int soc_camera_power_off(struct device *dev, struct soc_camera_link *icl); + +static inline int soc_camera_set_power(struct device *dev, + struct soc_camera_link *icl, bool on) +{ + return on ? soc_camera_power_on(dev, icl) + : soc_camera_power_off(dev, icl); +} + /* This is only temporary here - until v4l2-subdev begins to link to video_device */ #include static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client) -- cgit v1.2.3 From 4bbc6d52e61a8a9c19fcc859c4acab89cb8cd4e5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 18 Jul 2012 10:54:04 -0300 Subject: [media] soc-camera: Push probe-time power management to drivers Several client drivers access the hardware at probe time, for instance to read the probe chip ID. Such chips need to be powered up when being probed. soc-camera handles this by powering chips up in the soc-camera probe implementation. However, this will break with non soc-camera hosts that don't perform the same operations. Fix the problem by pushing the power up/down from the soc-camera core down to individual drivers on a needs basis. Signed-off-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/imx074.c | 21 ++++++-- drivers/media/i2c/soc_camera/mt9m001.c | 17 +++++-- drivers/media/i2c/soc_camera/mt9m111.c | 80 +++++++++++++++++-------------- drivers/media/i2c/soc_camera/mt9t031.c | 37 ++++++-------- drivers/media/i2c/soc_camera/mt9t112.c | 12 ++++- drivers/media/i2c/soc_camera/mt9v022.c | 5 ++ drivers/media/i2c/soc_camera/ov2640.c | 11 +++-- drivers/media/i2c/soc_camera/ov5642.c | 21 ++++++-- drivers/media/i2c/soc_camera/ov6650.c | 19 +++++--- drivers/media/i2c/soc_camera/ov772x.c | 14 +++++- drivers/media/i2c/soc_camera/ov9640.c | 17 +++++-- drivers/media/i2c/soc_camera/ov9740.c | 23 +++++---- drivers/media/i2c/soc_camera/rj54n1cb0c.c | 18 +++++-- drivers/media/i2c/soc_camera/tw9910.c | 12 ++++- drivers/media/platform/soc_camera.c | 20 -------- 15 files changed, 204 insertions(+), 123 deletions(-) (limited to 'drivers/media/i2c/soc_camera/mt9v022.c') diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c index ade19873ed83..f8534eec9de9 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/media/i2c/soc_camera/imx074.c @@ -310,26 +310,33 @@ static struct v4l2_subdev_ops imx074_subdev_ops = { static int imx074_video_probe(struct i2c_client *client) { + struct v4l2_subdev *subdev = i2c_get_clientdata(client); int ret; u16 id; + ret = imx074_s_power(subdev, 1); + if (ret < 0) + return ret; + /* Read sensor Model ID */ ret = reg_read(client, 0); if (ret < 0) - return ret; + goto done; id = ret << 8; ret = reg_read(client, 1); if (ret < 0) - return ret; + goto done; id |= ret; dev_info(&client->dev, "Chip ID 0x%04x detected\n", id); - if (id != 0x74) - return -ENODEV; + if (id != 0x74) { + ret = -ENODEV; + goto done; + } /* PLL Setting EXTCLK=24MHz, 22.5times */ reg_write(client, PLL_MULTIPLIER, 0x2D); @@ -411,7 +418,11 @@ static int imx074_video_probe(struct i2c_client *client) reg_write(client, GROUPED_PARAMETER_HOLD, 0x00); /* off */ - return 0; + ret = 0; + +done: + imx074_s_power(subdev, 0); + return ret; } static int imx074_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index cd71230c51a9..d85be41ffa1d 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -490,6 +490,10 @@ static int mt9m001_video_probe(struct soc_camera_link *icl, unsigned long flags; int ret; + ret = mt9m001_s_power(&mt9m001->subdev, 1); + if (ret < 0) + return ret; + /* Enable the chip */ data = reg_write(client, MT9M001_CHIP_ENABLE, 1); dev_dbg(&client->dev, "write: %d\n", data); @@ -511,7 +515,8 @@ static int mt9m001_video_probe(struct soc_camera_link *icl, default: dev_err(&client->dev, "No MT9M001 chip detected, register read %x\n", data); - return -ENODEV; + ret = -ENODEV; + goto done; } mt9m001->num_fmts = 0; @@ -540,11 +545,17 @@ static int mt9m001_video_probe(struct soc_camera_link *icl, data == 0x8431 ? "C12STM" : "C12ST"); ret = mt9m001_init(client); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "Failed to initialise the camera\n"); + goto done; + } /* mt9m001_init() has reset the chip, returning registers to defaults */ - return v4l2_ctrl_handler_setup(&mt9m001->hdl); + ret = v4l2_ctrl_handler_setup(&mt9m001->hdl); + +done: + mt9m001_s_power(&mt9m001->subdev, 0); + return ret; } static void mt9m001_video_remove(struct soc_camera_link *icl) diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index e555f7739691..938c5c390eec 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -796,41 +796,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111) return ret; } -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int mt9m111_video_probe(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - s32 data; - int ret; - - data = reg_read(CHIP_VERSION); - - switch (data) { - case 0x143a: /* MT9M111 or MT9M131 */ - mt9m111->model = V4L2_IDENT_MT9M111; - dev_info(&client->dev, - "Detected a MT9M111/MT9M131 chip ID %x\n", data); - break; - case 0x148c: /* MT9M112 */ - mt9m111->model = V4L2_IDENT_MT9M112; - dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); - break; - default: - dev_err(&client->dev, - "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", - data); - return -ENODEV; - } - - ret = mt9m111_init(mt9m111); - if (ret) - return ret; - return v4l2_ctrl_handler_setup(&mt9m111->hdl); -} - static int mt9m111_power_on(struct mt9m111 *mt9m111) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); @@ -941,6 +906,51 @@ static struct v4l2_subdev_ops mt9m111_subdev_ops = { .video = &mt9m111_subdev_video_ops, }; +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ +static int mt9m111_video_probe(struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + s32 data; + int ret; + + ret = mt9m111_s_power(&mt9m111->subdev, 1); + if (ret < 0) + return ret; + + data = reg_read(CHIP_VERSION); + + switch (data) { + case 0x143a: /* MT9M111 or MT9M131 */ + mt9m111->model = V4L2_IDENT_MT9M111; + dev_info(&client->dev, + "Detected a MT9M111/MT9M131 chip ID %x\n", data); + break; + case 0x148c: /* MT9M112 */ + mt9m111->model = V4L2_IDENT_MT9M112; + dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); + break; + default: + dev_err(&client->dev, + "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", + data); + ret = -ENODEV; + goto done; + } + + ret = mt9m111_init(mt9m111); + if (ret) + goto done; + + ret = v4l2_ctrl_handler_setup(&mt9m111->hdl); + +done: + mt9m111_s_power(&mt9m111->subdev, 0); + return ret; +} + static int mt9m111_probe(struct i2c_client *client, const struct i2c_device_id *did) { diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 9666e202e395..d74607adc585 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -161,14 +161,6 @@ static int mt9t031_idle(struct i2c_client *client) return ret >= 0 ? 0 : -EIO; } -static int mt9t031_disable(struct i2c_client *client) -{ - /* Disable the chip */ - reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); - - return 0; -} - static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -643,9 +635,15 @@ static int mt9t031_video_probe(struct i2c_client *client) s32 data; int ret; - /* Enable the chip */ - data = reg_write(client, MT9T031_CHIP_ENABLE, 1); - dev_dbg(&client->dev, "write: %d\n", data); + ret = mt9t031_s_power(&mt9t031->subdev, 1); + if (ret < 0) + return ret; + + ret = mt9t031_idle(client); + if (ret < 0) { + dev_err(&client->dev, "Failed to initialise the camera\n"); + goto done; + } /* Read out the chip version register */ data = reg_read(client, MT9T031_CHIP_VERSION); @@ -657,16 +655,16 @@ static int mt9t031_video_probe(struct i2c_client *client) default: dev_err(&client->dev, "No MT9T031 chip detected, register read %x\n", data); - return -ENODEV; + ret = -ENODEV; + goto done; } dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); - ret = mt9t031_idle(client); - if (ret < 0) - dev_err(&client->dev, "Failed to initialise the camera\n"); - else - v4l2_ctrl_handler_setup(&mt9t031->hdl); + ret = v4l2_ctrl_handler_setup(&mt9t031->hdl); + +done: + mt9t031_s_power(&mt9t031->subdev, 0); return ret; } @@ -817,12 +815,7 @@ static int mt9t031_probe(struct i2c_client *client, mt9t031->xskip = 1; mt9t031->yskip = 1; - mt9t031_idle(client); - ret = mt9t031_video_probe(client); - - mt9t031_disable(client); - if (ret) { v4l2_ctrl_handler_free(&mt9t031->hdl); kfree(mt9t031); diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 624ceec44e18..9ba428ede516 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -1041,6 +1041,11 @@ static int mt9t112_camera_probe(struct i2c_client *client) struct mt9t112_priv *priv = to_mt9t112(client); const char *devname; int chipid; + int ret; + + ret = mt9t112_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; /* * check and show chip ID @@ -1058,12 +1063,15 @@ static int mt9t112_camera_probe(struct i2c_client *client) break; default: dev_err(&client->dev, "Product ID error %04x\n", chipid); - return -ENODEV; + ret = -ENODEV; + goto done; } dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); - return 0; +done: + mt9t112_s_power(&priv->subdev, 0); + return ret; } static int mt9t112_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 5f09cb702bf7..2edea8489092 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -578,6 +578,10 @@ static int mt9v022_video_probe(struct i2c_client *client) int ret; unsigned long flags; + ret = mt9v022_s_power(&mt9v022->subdev, 1); + if (ret < 0) + return ret; + /* Read out the chip version register */ data = reg_read(client, MT9V022_CHIP_VERSION); @@ -648,6 +652,7 @@ static int mt9v022_video_probe(struct i2c_client *client) dev_err(&client->dev, "Failed to initialise the camera\n"); ei2c: + mt9v022_s_power(&mt9v022->subdev, 0); return ret; } diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 16ed091c702d..78ac5744cb5d 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -955,6 +955,10 @@ static int ov2640_video_probe(struct i2c_client *client) const char *devname; int ret; + ret = ov2640_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + /* * check and show product ID and manufacturer ID */ @@ -973,16 +977,17 @@ static int ov2640_video_probe(struct i2c_client *client) dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); ret = -ENODEV; - goto err; + goto done; } dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", devname, pid, ver, midh, midl); - return v4l2_ctrl_handler_setup(&priv->hdl); + ret = v4l2_ctrl_handler_setup(&priv->hdl); -err: +done: + ov2640_s_power(&priv->subdev, 0); return ret; } diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index 61824c6911d5..d886c0b9ce44 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c @@ -980,29 +980,40 @@ static struct v4l2_subdev_ops ov5642_subdev_ops = { static int ov5642_video_probe(struct i2c_client *client) { + struct v4l2_subdev *subdev = i2c_get_clientdata(client); int ret; u8 id_high, id_low; u16 id; + ret = ov5642_s_power(subdev, 1); + if (ret < 0) + return ret; + /* Read sensor Model ID */ ret = reg_read(client, REG_CHIP_ID_HIGH, &id_high); if (ret < 0) - return ret; + goto done; id = id_high << 8; ret = reg_read(client, REG_CHIP_ID_LOW, &id_low); if (ret < 0) - return ret; + goto done; id |= id_low; dev_info(&client->dev, "Chip ID 0x%04x detected\n", id); - if (id != 0x5642) - return -ENODEV; + if (id != 0x5642) { + ret = -ENODEV; + goto done; + } - return 0; + ret = 0; + +done: + ov5642_s_power(subdev, 0); + return ret; } static int ov5642_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index 12d57a5dd810..65b031f333b7 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -829,8 +829,13 @@ static int ov6650_prog_dflt(struct i2c_client *client) static int ov6650_video_probe(struct i2c_client *client) { + struct ov6650 *priv = to_ov6650(client); u8 pidh, pidl, midh, midl; - int ret = 0; + int ret; + + ret = ov6650_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; /* * check and show product ID and manufacturer ID @@ -844,12 +849,13 @@ static int ov6650_video_probe(struct i2c_client *client) ret = ov6650_reg_read(client, REG_MIDL, &midl); if (ret) - return ret; + goto done; if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) { dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n", pidh, pidl); - return -ENODEV; + ret = -ENODEV; + goto done; } dev_info(&client->dev, @@ -859,7 +865,11 @@ static int ov6650_video_probe(struct i2c_client *client) ret = ov6650_reset(client); if (!ret) ret = ov6650_prog_dflt(client); + if (!ret) + ret = v4l2_ctrl_handler_setup(&priv->hdl); +done: + ov6650_s_power(&priv->subdev, 0); return ret; } @@ -1019,9 +1029,6 @@ static int ov6650_probe(struct i2c_client *client, priv->colorspace = V4L2_COLORSPACE_JPEG; ret = ov6650_video_probe(client); - if (!ret) - ret = v4l2_ctrl_handler_setup(&priv->hdl); - if (ret) { v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index a022662da98a..641f6f43d7ee 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -962,6 +962,11 @@ static int ov772x_video_probe(struct i2c_client *client) struct ov772x_priv *priv = to_ov772x(client); u8 pid, ver; const char *devname; + int ret; + + ret = ov772x_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; /* * check and show product ID and manufacturer ID @@ -981,7 +986,8 @@ static int ov772x_video_probe(struct i2c_client *client) default: dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); - return -ENODEV; + ret = -ENODEV; + goto done; } dev_info(&client->dev, @@ -991,7 +997,11 @@ static int ov772x_video_probe(struct i2c_client *client) ver, i2c_smbus_read_byte_data(client, MIDH), i2c_smbus_read_byte_data(client, MIDL)); - return v4l2_ctrl_handler_setup(&priv->hdl); + ret = v4l2_ctrl_handler_setup(&priv->hdl); + +done: + ov772x_s_power(&priv->subdev, 0); + return ret; } static const struct v4l2_ctrl_ops ov772x_ctrl_ops = { diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index 53156ef1ec0c..b323684eaf77 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -592,7 +592,11 @@ static int ov9640_video_probe(struct i2c_client *client) struct ov9640_priv *priv = to_ov9640_sensor(sd); u8 pid, ver, midh, midl; const char *devname; - int ret = 0; + int ret; + + ret = ov9640_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; /* * check and show product ID and manufacturer ID @@ -606,7 +610,7 @@ static int ov9640_video_probe(struct i2c_client *client) if (!ret) ret = ov9640_reg_read(client, OV9640_MIDL, &midl); if (ret) - return ret; + goto done; switch (VERSION(pid, ver)) { case OV9640_V2: @@ -621,13 +625,18 @@ static int ov9640_video_probe(struct i2c_client *client) break; default: dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); - return -ENODEV; + ret = -ENODEV; + goto done; } dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", devname, pid, ver, midh, midl); - return v4l2_ctrl_handler_setup(&priv->hdl); + ret = v4l2_ctrl_handler_setup(&priv->hdl); + +done: + ov9640_s_power(&priv->subdev, 0); + return ret; } static const struct v4l2_ctrl_ops ov9640_ctrl_ops = { diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 10c0ba9f5bcd..7a55889e397b 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -853,34 +853,38 @@ static int ov9740_video_probe(struct i2c_client *client) u8 modelhi, modello; int ret; + ret = ov9740_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + /* * check and show product ID and manufacturer ID */ ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi); if (ret < 0) - goto err; + goto done; ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello); if (ret < 0) - goto err; + goto done; priv->model = (modelhi << 8) | modello; ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision); if (ret < 0) - goto err; + goto done; ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid); if (ret < 0) - goto err; + goto done; ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver); if (ret < 0) - goto err; + goto done; if (priv->model != 0x9740) { ret = -ENODEV; - goto err; + goto done; } priv->ident = V4L2_IDENT_OV9740; @@ -889,7 +893,10 @@ static int ov9740_video_probe(struct i2c_client *client) "Manufacturer 0x%02x, SMIA Version 0x%02x\n", priv->model, priv->revision, priv->manid, priv->smiaver); -err: + ret = v4l2_ctrl_handler_setup(&priv->hdl); + +done: + ov9740_s_power(&priv->subdev, 0); return ret; } @@ -973,8 +980,6 @@ static int ov9740_probe(struct i2c_client *client, } ret = ov9740_video_probe(client); - if (!ret) - ret = v4l2_ctrl_handler_setup(&priv->hdl); if (ret < 0) { v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index ca1cee7c66cb..32226c9024f9 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -1296,9 +1296,14 @@ static struct v4l2_subdev_ops rj54n1_subdev_ops = { static int rj54n1_video_probe(struct i2c_client *client, struct rj54n1_pdata *priv) { + struct rj54n1 *rj54n1 = to_rj54n1(client); int data1, data2; int ret; + ret = rj54n1_s_power(&rj54n1->subdev, 1); + if (ret < 0) + return ret; + /* Read out the chip version register */ data1 = reg_read(client, RJ54N1_DEV_CODE); data2 = reg_read(client, RJ54N1_DEV_CODE2); @@ -1307,18 +1312,21 @@ static int rj54n1_video_probe(struct i2c_client *client, ret = -ENODEV; dev_info(&client->dev, "No RJ54N1CB0C found, read 0x%x:0x%x\n", data1, data2); - goto ei2c; + goto done; } /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */ ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7); if (ret < 0) - goto ei2c; + goto done; dev_info(&client->dev, "Detected a RJ54N1CB0C chip ID 0x%x:0x%x\n", data1, data2); -ei2c: + ret = v4l2_ctrl_handler_setup(&rj54n1->hdl); + +done: + rj54n1_s_power(&rj54n1->subdev, 0); return ret; } @@ -1382,9 +1390,9 @@ static int rj54n1_probe(struct i2c_client *client, if (ret < 0) { v4l2_ctrl_handler_free(&rj54n1->hdl); kfree(rj54n1); - return ret; } - return v4l2_ctrl_handler_setup(&rj54n1->hdl); + + return ret; } static int rj54n1_remove(struct i2c_client *client) diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index f28365051878..140716e71a15 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -780,6 +780,7 @@ static int tw9910_video_probe(struct i2c_client *client) { struct tw9910_priv *priv = to_tw9910(client); s32 id; + int ret; /* * tw9910 only use 8 or 16 bit bus width @@ -790,6 +791,10 @@ static int tw9910_video_probe(struct i2c_client *client) return -ENODEV; } + ret = tw9910_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + /* * check and show Product ID * So far only revisions 0 and 1 have been seen @@ -803,7 +808,8 @@ static int tw9910_video_probe(struct i2c_client *client) dev_err(&client->dev, "Product ID error %x:%x\n", id, priv->revision); - return -ENODEV; + ret = -ENODEV; + goto done; } dev_info(&client->dev, @@ -811,7 +817,9 @@ static int tw9910_video_probe(struct i2c_client *client) priv->norm = V4L2_STD_NTSC; - return 0; +done: + tw9910_s_power(&priv->subdev, 0); + return ret; } static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { diff --git a/drivers/media/platform/soc_camera.c b/drivers/media/platform/soc_camera.c index 8e1548e16f54..f94055505d70 100644 --- a/drivers/media/platform/soc_camera.c +++ b/drivers/media/platform/soc_camera.c @@ -1086,22 +1086,6 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (ret < 0) goto eadd; - /* - * This will not yet call v4l2_subdev_core_ops::s_power(1), because the - * subdevice has not been initialised yet. We'll have to call it once - * again after initialisation, even though it shouldn't be needed, we - * don't do any IO here. - * - * The device pointer passed to soc_camera_power_on(), and ultimately to - * the platform callback, should be the subdev physical device. However, - * we have no way to retrieve a pointer to that device here. This isn't - * a real issue, as no platform currently uses the device pointer, and - * this soc_camera_power_on() call will be removed in the next commit. - */ - ret = soc_camera_power_on(icd->pdev, icl); - if (ret < 0) - goto epower; - /* Must have icd->vdev before registering the device */ ret = video_dev_create(icd); if (ret < 0) @@ -1171,8 +1155,6 @@ static int soc_camera_probe(struct soc_camera_device *icd) ici->ops->remove(icd); - __soc_camera_power_off(icd); - mutex_unlock(&icd->video_lock); return 0; @@ -1193,8 +1175,6 @@ eadddev: video_device_release(icd->vdev); icd->vdev = NULL; evdc: - __soc_camera_power_off(icd); -epower: ici->ops->remove(icd); eadd: regulator_bulk_free(icl->num_regulators, icl->regulators); -- cgit v1.2.3 From c078ac18f3f94f643ab477949d0cd93667904e06 Mon Sep 17 00:00:00 2001 From: Alex Gershgorin Date: Thu, 2 Aug 2012 12:32:41 -0300 Subject: [media] mt9v022: Add support for mt9v024 Driver for mt9v022 camera sensor is fully compatible for mt9v024 camera sensor with the exception of several registers which have been changed addresses. mt9v024 also has improved and additional features, but they are currently not in use. Signed-off-by: Alex Gershgorin Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/Kconfig | 2 +- drivers/media/i2c/soc_camera/mt9v022.c | 36 +++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) (limited to 'drivers/media/i2c/soc_camera/mt9v022.c') diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 73fe21d1b2df..6dff2b7ad520 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -34,7 +34,7 @@ config SOC_CAMERA_MT9T112 This driver supports MT9T112 cameras from Aptina. config SOC_CAMERA_MT9V022 - tristate "mt9v022 support" + tristate "mt9v022 and mt9v024 support" depends on SOC_CAMERA && I2C select GPIO_PCA953X if MT9V022_PCA9536_SWITCH help diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 2edea8489092..350d0d854447 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -57,6 +57,10 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); #define MT9V022_AEC_AGC_ENABLE 0xAF #define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD +/* mt9v024 partial list register addresses changes with respect to mt9v022 */ +#define MT9V024_PIXCLK_FV_LV 0x72 +#define MT9V024_MAX_TOTAL_SHUTTER_WIDTH 0xAD + /* Progressive scan, master, defaults */ #define MT9V022_CHIP_CONTROL_DEFAULT 0x188 @@ -67,6 +71,8 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); #define MT9V022_COLUMN_SKIP 1 #define MT9V022_ROW_SKIP 4 +#define is_mt9v024(id) (id == 0x1324) + /* MT9V022 has only one fixed colorspace per pixelcode */ struct mt9v022_datafmt { enum v4l2_mbus_pixelcode code; @@ -101,6 +107,22 @@ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, }; +/* only registers with different addresses on different mt9v02x sensors */ +struct mt9v02x_register { + u8 max_total_shutter_width; + u8 pixclk_fv_lv; +}; + +static const struct mt9v02x_register mt9v022_register = { + .max_total_shutter_width = MT9V022_MAX_TOTAL_SHUTTER_WIDTH, + .pixclk_fv_lv = MT9V022_PIXCLK_FV_LV, +}; + +static const struct mt9v02x_register mt9v024_register = { + .max_total_shutter_width = MT9V024_MAX_TOTAL_SHUTTER_WIDTH, + .pixclk_fv_lv = MT9V024_PIXCLK_FV_LV, +}; + struct mt9v022 { struct v4l2_subdev subdev; struct v4l2_ctrl_handler hdl; @@ -117,6 +139,7 @@ struct mt9v022 { struct v4l2_rect rect; /* Sensor window */ const struct mt9v022_datafmt *fmt; const struct mt9v022_datafmt *fmts; + const struct mt9v02x_register *reg; int num_fmts; int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ u16 chip_control; @@ -185,7 +208,7 @@ static int mt9v022_init(struct i2c_client *client) if (!ret) ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480); if (!ret) - ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); + ret = reg_write(client, mt9v022->reg->max_total_shutter_width, 480); if (!ret) /* default - auto */ ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); @@ -238,7 +261,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); if (ret >= 0) { if (ret & 1) /* Autoexposure */ - ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, + ret = reg_write(client, mt9v022->reg->max_total_shutter_width, rect.height + mt9v022->y_skip_top + 43); else ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, @@ -585,14 +608,17 @@ static int mt9v022_video_probe(struct i2c_client *client) /* Read out the chip version register */ data = reg_read(client, MT9V022_CHIP_VERSION); - /* must be 0x1311 or 0x1313 */ - if (data != 0x1311 && data != 0x1313) { + /* must be 0x1311, 0x1313 or 0x1324 */ + if (data != 0x1311 && data != 0x1313 && data != 0x1324) { ret = -ENODEV; dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n", data); goto ei2c; } + mt9v022->reg = is_mt9v024(data) ? &mt9v024_register : + &mt9v022_register; + /* Soft reset */ ret = reg_write(client, MT9V022_RESET, 1); if (ret < 0) @@ -742,7 +768,7 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)) pixclk |= 0x2; - ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); + ret = reg_write(client, mt9v022->reg->pixclk_fv_lv, pixclk); if (ret < 0) return ret; -- cgit v1.2.3 From 4f996594ceaf6c3f9bc42b40c40b0f7f87b79c86 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Sep 2012 05:10:48 -0300 Subject: [media] v4l2: make vidioc_s_crop const Write-only ioctls should have a const argument in the ioctl op. Do this conversion for vidioc_s_crop. Adding const for write-only ioctls was decided during the 2012 Media Workshop. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/mt9m001.c | 2 +- drivers/media/i2c/soc_camera/mt9m111.c | 2 +- drivers/media/i2c/soc_camera/mt9t031.c | 2 +- drivers/media/i2c/soc_camera/mt9t112.c | 4 +-- drivers/media/i2c/soc_camera/mt9v022.c | 2 +- drivers/media/i2c/soc_camera/ov5642.c | 20 +++++++------- drivers/media/i2c/soc_camera/ov6650.c | 32 +++++++++++----------- drivers/media/i2c/soc_camera/rj54n1cb0c.c | 4 +-- drivers/media/i2c/tvp5150.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 10 +++---- drivers/media/pci/cx18/cx18-ioctl.c | 2 +- drivers/media/pci/cx25821/cx25821-video.c | 2 +- drivers/media/pci/cx25821/cx25821-video.h | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 32 +++++++++++----------- drivers/media/pci/zoran/zoran_driver.c | 2 +- drivers/media/platform/davinci/vpbe_display.c | 2 +- drivers/media/platform/davinci/vpfe_capture.c | 2 +- drivers/media/platform/omap/omap_vout.c | 2 +- drivers/media/platform/s5p-fimc/fimc-m2m.c | 2 +- drivers/media/platform/s5p-g2d/g2d.c | 2 +- drivers/media/platform/sh_vou.c | 2 +- .../platform/soc_camera/sh_mobile_ceu_camera.c | 4 +-- drivers/media/platform/soc_camera/soc_camera.c | 6 ++-- drivers/media/platform/vino.c | 2 +- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 2 +- drivers/staging/media/go7007/go7007-v4l2.c | 2 +- include/media/soc_camera.h | 4 +-- include/media/v4l2-ioctl.h | 2 +- include/media/v4l2-subdev.h | 2 +- 30 files changed, 79 insertions(+), 79 deletions(-) (limited to 'drivers/media/i2c/soc_camera/mt9v022.c') diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index d85be41ffa1d..19f8a07764f9 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -171,7 +171,7 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int mt9m001_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 938c5c390eec..62fd94af599b 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -383,7 +383,7 @@ static int mt9m111_reset(struct mt9m111 *mt9m111) return ret; } -static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int mt9m111_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) { struct v4l2_rect rect = a->c; struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index d74607adc585..40800b10a080 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -294,7 +294,7 @@ static int mt9t031_set_params(struct i2c_client *client, return ret < 0 ? ret : 0; } -static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int mt9t031_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) { struct v4l2_rect rect = a->c; struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 9ba428ede516..de7cd836b0a2 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -907,11 +907,11 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) return 0; } -static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int mt9t112_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); - struct v4l2_rect *rect = &a->c; + const struct v4l2_rect *rect = &a->c; return mt9t112_set_params(priv, rect, priv->format->code); } diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 350d0d854447..13057b966ee9 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -237,7 +237,7 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index d886c0b9ce44..8577e0cfb7fe 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c @@ -865,24 +865,24 @@ static int ov5642_g_chip_ident(struct v4l2_subdev *sd, return 0; } -static int ov5642_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int ov5642_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5642 *priv = to_ov5642(client); - struct v4l2_rect *rect = &a->c; + struct v4l2_rect rect = a->c; int ret; - v4l_bound_align_image(&rect->width, 48, OV5642_MAX_WIDTH, 1, - &rect->height, 32, OV5642_MAX_HEIGHT, 1, 0); + v4l_bound_align_image(&rect.width, 48, OV5642_MAX_WIDTH, 1, + &rect.height, 32, OV5642_MAX_HEIGHT, 1, 0); - priv->crop_rect.width = rect->width; - priv->crop_rect.height = rect->height; - priv->total_width = rect->width + BLANKING_EXTRA_WIDTH; - priv->total_height = max_t(int, rect->height + + priv->crop_rect.width = rect.width; + priv->crop_rect.height = rect.height; + priv->total_width = rect.width + BLANKING_EXTRA_WIDTH; + priv->total_height = max_t(int, rect.height + BLANKING_EXTRA_HEIGHT, BLANKING_MIN_HEIGHT); - priv->crop_rect.width = rect->width; - priv->crop_rect.height = rect->height; + priv->crop_rect.width = rect.width; + priv->crop_rect.height = rect.height; ret = ov5642_write_array(client, ov5642_default_regs_init); if (!ret) diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index 65b031f333b7..e87feb0881e3 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -451,42 +451,42 @@ static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) return 0; } -static int ov6650_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int ov6650_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); - struct v4l2_rect *rect = &a->c; + struct v4l2_rect rect = a->c; int ret; if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - rect->left = ALIGN(rect->left, 2); - rect->width = ALIGN(rect->width, 2); - rect->top = ALIGN(rect->top, 2); - rect->height = ALIGN(rect->height, 2); - soc_camera_limit_side(&rect->left, &rect->width, + rect.left = ALIGN(rect.left, 2); + rect.width = ALIGN(rect.width, 2); + rect.top = ALIGN(rect.top, 2); + rect.height = ALIGN(rect.height, 2); + soc_camera_limit_side(&rect.left, &rect.width, DEF_HSTRT << 1, 2, W_CIF); - soc_camera_limit_side(&rect->top, &rect->height, + soc_camera_limit_side(&rect.top, &rect.height, DEF_VSTRT << 1, 2, H_CIF); - ret = ov6650_reg_write(client, REG_HSTRT, rect->left >> 1); + ret = ov6650_reg_write(client, REG_HSTRT, rect.left >> 1); if (!ret) { - priv->rect.left = rect->left; + priv->rect.left = rect.left; ret = ov6650_reg_write(client, REG_HSTOP, - (rect->left + rect->width) >> 1); + (rect.left + rect.width) >> 1); } if (!ret) { - priv->rect.width = rect->width; - ret = ov6650_reg_write(client, REG_VSTRT, rect->top >> 1); + priv->rect.width = rect.width; + ret = ov6650_reg_write(client, REG_VSTRT, rect.top >> 1); } if (!ret) { - priv->rect.top = rect->top; + priv->rect.top = rect.top; ret = ov6650_reg_write(client, REG_VSTOP, - (rect->top + rect->height) >> 1); + (rect.top + rect.height) >> 1); } if (!ret) - priv->rect.height = rect->height; + priv->rect.height = rect.height; return ret; } diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index 32226c9024f9..02f0400051d9 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -536,11 +536,11 @@ static int rj54n1_commit(struct i2c_client *client) static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h, s32 *out_w, s32 *out_h); -static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int rj54n1_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct rj54n1 *rj54n1 = to_rj54n1(client); - struct v4l2_rect *rect = &a->c; + const struct v4l2_rect *rect = &a->c; int dummy = 0, output_w, output_h, input_w = rect->width, input_h = rect->height; int ret; diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index a751b6c146fd..b5b1792479d0 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -865,7 +865,7 @@ static int tvp5150_mbus_fmt(struct v4l2_subdev *sd, return 0; } -static int tvp5150_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) { struct v4l2_rect rect = a->c; struct tvp5150 *decoder = to_tvp5150(sd); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 31b282667463..16f5ca23698c 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2986,7 +2986,7 @@ static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) return 0; } -static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +static int bttv_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -3028,17 +3028,17 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) } /* Min. scaled size 48 x 32. */ - c.rect.left = clamp(crop->c.left, b_left, b_right - 48); + c.rect.left = clamp_t(s32, crop->c.left, b_left, b_right - 48); c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); - c.rect.width = clamp(crop->c.width, + c.rect.width = clamp_t(s32, crop->c.width, 48, b_right - c.rect.left); - c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); + c.rect.top = clamp_t(s32, crop->c.top, b_top, b_bottom - 32); /* Top and height must be a multiple of two. */ c.rect.top = (c.rect.top + 1) & ~1; - c.rect.height = clamp(crop->c.height, + c.rect.height = clamp_t(s32, crop->c.height, 32, b_bottom - c.rect.top); c.rect.height = (c.rect.height + 1) & ~1; diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index ff315446d4ad..bb5073f72c42 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -527,7 +527,7 @@ static int cx18_cropcap(struct file *file, void *fh, return 0; } -static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) +static int cx18_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index b38d4379cc36..0a80245165d0 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1610,7 +1610,7 @@ int cx25821_vidioc_cropcap(struct file *file, void *priv, return 0; } -int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) +int cx25821_vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; struct cx25821_fh *fh = priv; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 9652a5e35ba2..c265e35b37c3 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -177,7 +177,7 @@ extern int cx25821_set_control(struct cx25821_dev *dev, extern int cx25821_vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap); extern int cx25821_vidioc_s_crop(struct file *file, void *priv, - struct v4l2_crop *crop); + const struct v4l2_crop *crop); extern int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop); diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index d5cbb6177754..ed6dcc7e61bc 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -874,7 +874,7 @@ static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropca return 0; } -static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) +static int ivtv_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 135bfd8c28ad..22f8758d047f 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1953,11 +1953,12 @@ static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) return 0; } -static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) { struct saa7134_fh *fh = f; struct saa7134_dev *dev = fh->dev; struct v4l2_rect *b = &dev->crop_bounds; + struct v4l2_rect *c = &dev->crop_current; if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) @@ -1972,21 +1973,20 @@ static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop) if (res_locked(fh->dev, RESOURCE_VIDEO)) return -EBUSY; - if (crop->c.top < b->top) - crop->c.top = b->top; - if (crop->c.top > b->top + b->height) - crop->c.top = b->top + b->height; - if (crop->c.height > b->top - crop->c.top + b->height) - crop->c.height = b->top - crop->c.top + b->height; - - if (crop->c.left < b->left) - crop->c.left = b->left; - if (crop->c.left > b->left + b->width) - crop->c.left = b->left + b->width; - if (crop->c.width > b->left - crop->c.left + b->width) - crop->c.width = b->left - crop->c.left + b->width; - - dev->crop_current = crop->c; + *c = crop->c; + if (c->top < b->top) + c->top = b->top; + if (c->top > b->top + b->height) + c->top = b->top + b->height; + if (c->height > b->top - c->top + b->height) + c->height = b->top - c->top + b->height; + + if (c->left < b->left) + c->left = b->left; + if (c->left > b->left + b->width) + c->left = b->left + b->width; + if (c->width > b->left - c->left + b->width) + c->width = b->left - c->left + b->width; return 0; } diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 9ecd7d711f27..53f12c7466b0 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -2598,7 +2598,7 @@ gcrop_unlock_and_return: return res; } -static int zoran_s_crop(struct file *file, void *__fh, struct v4l2_crop *crop) +static int zoran_s_crop(struct file *file, void *__fh, const struct v4l2_crop *crop) { struct zoran_fh *fh = __fh; struct zoran *zr = fh->zr; diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 9a05c817462c..e712d6734ac8 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -629,7 +629,7 @@ static int vpbe_display_querycap(struct file *file, void *priv, } static int vpbe_display_s_crop(struct file *file, void *priv, - struct v4l2_crop *crop) + const struct v4l2_crop *crop) { struct vpbe_fh *fh = file->private_data; struct vpbe_layer *layer = fh->layer; diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index f99198cebd35..48052cbffc2b 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1666,7 +1666,7 @@ static int vpfe_g_crop(struct file *file, void *priv, } static int vpfe_s_crop(struct file *file, void *priv, - struct v4l2_crop *crop) + const struct v4l2_crop *crop) { struct vpfe_device *vpfe_dev = video_drvdata(file); int ret = 0; diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 92845f835607..36c3be85649d 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -1291,7 +1291,7 @@ static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) return 0; } -static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) +static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) { int ret = -EINVAL; struct omap_vout_device *vout = fh; diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index ab4c15acdc4c..c67e53bfa43a 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -551,7 +551,7 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) return 0; } -static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) +static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr) { struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_dev *fimc = ctx->fimc_dev; diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 30195ef5a803..69c9f22ee52a 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -526,7 +526,7 @@ static int vidioc_try_crop(struct file *file, void *prv, struct v4l2_crop *cr) return 0; } -static int vidioc_s_crop(struct file *file, void *prv, struct v4l2_crop *cr) +static int vidioc_s_crop(struct file *file, void *prv, const struct v4l2_crop *cr) { struct g2d_ctx *ctx = prv; struct g2d_frame *f; diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 9f62fd89ab57..00cd52c61fe0 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -933,7 +933,7 @@ static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a) } /* Assume a dull encoder, do all the work ourselves. */ -static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a) +static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) { struct video_device *vdev = video_devdata(file); struct sh_vou_device *vou_dev = video_get_drvdata(vdev); diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 0baaf94db7e0..0a24253dcda2 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1263,7 +1263,7 @@ static void update_subrect(struct sh_mobile_ceu_cam *cam) * 3. if (2) failed, try to request the maximum image */ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, - struct v4l2_crop *cam_crop) + const struct v4l2_crop *cam_crop) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c; @@ -1517,7 +1517,7 @@ static int client_scale(struct soc_camera_device *icd, * scaling and cropping algorithms and for the meaning of referenced here steps. */ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) + const struct v4l2_crop *a) { struct v4l2_rect *rect = &a->c; struct device *dev = icd->parent; diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 10b57f8e7ec8..f6b1c1f87761 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -888,11 +888,11 @@ static int soc_camera_g_crop(struct file *file, void *fh, * retrieve it. */ static int soc_camera_s_crop(struct file *file, void *fh, - struct v4l2_crop *a) + const struct v4l2_crop *a) { struct soc_camera_device *icd = file->private_data; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct v4l2_rect *rect = &a->c; + const struct v4l2_rect *rect = &a->c; struct v4l2_crop current_crop; int ret; @@ -1289,7 +1289,7 @@ static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a) return v4l2_subdev_call(sd, video, g_crop, a); } -static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a) +static int default_s_crop(struct soc_camera_device *icd, const struct v4l2_crop *a) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); return v4l2_subdev_call(sd, video, s_crop, a); diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c index aae1720b2f2d..790d96cffeea 100644 --- a/drivers/media/platform/vino.c +++ b/drivers/media/platform/vino.c @@ -3284,7 +3284,7 @@ static int vino_g_crop(struct file *file, void *__fh, } static int vino_s_crop(struct file *file, void *__fh, - struct v4l2_crop *c) + const struct v4l2_crop *c) { struct vino_channel_settings *vcs = video_drvdata(file); unsigned long flags; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 7a445b0e725e..db249cad3cd9 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -760,7 +760,7 @@ static int pvr2_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) return 0; } -static int pvr2_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) +static int pvr2_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index f1dff3d09957..980371b02749 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1372,7 +1372,7 @@ static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) /* FIXME: vidioc_s_crop is not really implemented!!! */ -static int vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) +static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) { if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 435e7b8ad1c3..6442edc2a151 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -85,14 +85,14 @@ struct soc_camera_host_ops { void (*put_formats)(struct soc_camera_device *); int (*cropcap)(struct soc_camera_device *, struct v4l2_cropcap *); int (*get_crop)(struct soc_camera_device *, struct v4l2_crop *); - int (*set_crop)(struct soc_camera_device *, struct v4l2_crop *); + int (*set_crop)(struct soc_camera_device *, const struct v4l2_crop *); int (*get_selection)(struct soc_camera_device *, struct v4l2_selection *); int (*set_selection)(struct soc_camera_device *, struct v4l2_selection *); /* * The difference to .set_crop() is, that .set_livecrop is not allowed * to change the output sizes */ - int (*set_livecrop)(struct soc_camera_device *, struct v4l2_crop *); + int (*set_livecrop)(struct soc_camera_device *, const struct v4l2_crop *); int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *); int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *); void (*init_videobuf)(struct videobuf_queue *, diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index fbeb00e2c109..e48b571ca37d 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -186,7 +186,7 @@ struct v4l2_ioctl_ops { int (*vidioc_g_crop) (struct file *file, void *fh, struct v4l2_crop *a); int (*vidioc_s_crop) (struct file *file, void *fh, - struct v4l2_crop *a); + const struct v4l2_crop *a); int (*vidioc_g_selection) (struct file *file, void *fh, struct v4l2_selection *s); int (*vidioc_s_selection) (struct file *file, void *fh, diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index e698f2cead4e..2ecd7377153b 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -286,7 +286,7 @@ struct v4l2_subdev_video_ops { int (*s_stream)(struct v4l2_subdev *sd, int enable); int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc); int (*g_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop); - int (*s_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop); + int (*s_crop)(struct v4l2_subdev *sd, const struct v4l2_crop *crop); int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); int (*g_frame_interval)(struct v4l2_subdev *sd, -- cgit v1.2.3