From patchwork Thu Jun 25 13:58:13 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: m-karicheri2@ti.com X-Patchwork-Id: 1268 Return-path: Envelope-to: mchehab@infradead.org Delivery-date: Thu, 25 Jun 2009 13:58:25 +0000 Received: from bombadil.infradead.org [18.85.46.34] by caramujo.chehab.org with IMAP (fetchmail-6.3.6) for (single-drop); Thu, 25 Jun 2009 11:48:16 -0300 (BRT) Received: from vger.kernel.org ([209.132.176.167]) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1MJpT6-0006X0-AI; Thu, 25 Jun 2009 13:58:25 +0000 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751718AbZFYN6T (ORCPT + 1 other); Thu, 25 Jun 2009 09:58:19 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752023AbZFYN6T (ORCPT ); Thu, 25 Jun 2009 09:58:19 -0400 Received: from arroyo.ext.ti.com ([192.94.94.40]:38523 "EHLO arroyo.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751718AbZFYN6R (ORCPT ); Thu, 25 Jun 2009 09:58:17 -0400 Received: from dlep33.itg.ti.com ([157.170.170.112]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id n5PDwFQO027497 for ; Thu, 25 Jun 2009 08:58:20 -0500 Received: from legion.dal.design.ti.com (localhost [127.0.0.1]) by dlep33.itg.ti.com (8.13.7/8.13.7) with ESMTP id n5PDwERj004765; Thu, 25 Jun 2009 08:58:14 -0500 (CDT) Received: from gt516km11.gt.design.ti.com (gt516km11.gt.design.ti.com [158.218.100.179]) by legion.dal.design.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id n5PDwE920846; Thu, 25 Jun 2009 08:58:14 -0500 (CDT) Received: from gt516km11.gt.design.ti.com (localhost.localdomain [127.0.0.1]) by gt516km11.gt.design.ti.com (8.13.1/8.13.1) with ESMTP id n5PDwD79023569; Thu, 25 Jun 2009 09:58:13 -0400 Received: (from a0868495@localhost) by gt516km11.gt.design.ti.com (8.13.1/8.13.1/Submit) id n5PDwDs7023566; Thu, 25 Jun 2009 09:58:13 -0400 From: m-karicheri2@ti.com To: linux-media@vger.kernel.org Cc: davinci-linux-open-source@linux.davincidsp.com, Muralidharan Karicheri Subject: [PATCH] V4L: mt9t031 - migration to sub device frame work Date: Thu, 25 Jun 2009 09:58:13 -0400 Message-Id: <1245938293-23534-1-git-send-email-m-karicheri2@ti.com> X-Mailer: git-send-email 1.6.0.4 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Muralidharan Karicheri Re-sending making some minor updates in the patch header This patch migrates mt9t031 driver from SOC Camera interface to sub device interface. This is sent to get a feedback about the changes done since I am not sure if some of the functionality that is removed works okay with SOC Camera bridge driver or not. Following functions are to be discussed and added as needed:- 1) query bus parameters 2) set bus parameters 3) set crop I have tested this with vpfe capture driver and I could capture 640x480@17fps and 2048x1536@12fps resolution frames from the sensor. Reviewed-by: Hans Verkuil Reviewed-by: Guennadi Liakhovetski Signed-off-by: Murali Karicheri --- drivers/media/video/mt9t031.c | 596 ++++++++++++++++++++--------------------- 1 files changed, 293 insertions(+), 303 deletions(-) diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index f72aeb7..0f32ff2 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -13,9 +13,9 @@ #include #include +#include #include #include -#include /* mt9t031 i2c address 0x5d * The platform has to define i2c_board_info @@ -52,33 +52,108 @@ #define MT9T031_VERTICAL_BLANK 25 #define MT9T031_COLUMN_SKIP 32 #define MT9T031_ROW_SKIP 20 +#define MT9T031_DEFAULT_WIDTH 640 +#define MT9T031_DEFAULT_HEIGHT 480 #define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \ SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \ SOCAM_MASTER | SOCAM_DATAWIDTH_10) -static const struct soc_camera_data_format mt9t031_colour_formats[] = { + +/* Debug functions */ +static int debug; +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +static const struct v4l2_fmtdesc mt9t031_formats[] = { + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "Bayer (sRGB) 10 bit", + .pixelformat = V4L2_PIX_FMT_SGRBG10, + }, +}; +static const unsigned int mt9t031_num_formats = ARRAY_SIZE(mt9t031_formats); + +static const struct v4l2_queryctrl mt9t031_controls[] = { { - .name = "Bayer (sRGB) 10 bit", - .depth = 10, - .fourcc = V4L2_PIX_FMT_SGRBG10, - .colorspace = V4L2_COLORSPACE_SRGB, + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 64, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 1, + .maximum = 255, + .step = 1, + .default_value = 255, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, } }; +static const unsigned int mt9t031_num_controls = ARRAY_SIZE(mt9t031_controls); struct mt9t031 { - struct i2c_client *client; - struct soc_camera_device icd; + struct v4l2_subdev sd; int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ unsigned char autoexposure; u16 xskip; u16 yskip; + u32 width; + u32 height; + unsigned short x_min; /* Camera capabilities */ + unsigned short y_min; + unsigned short x_current; /* Current window location */ + unsigned short y_current; + unsigned short width_min; + unsigned short width_max; + unsigned short height_min; + unsigned short height_max; + unsigned short y_skip_top; /* Lines to skip at the top */ + unsigned short gain; + unsigned short exposure; }; +static inline struct mt9t031 *to_mt9t031(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mt9t031, sd); +} + static int reg_read(struct i2c_client *client, const u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); + s32 data; + + data = i2c_smbus_read_word_data(client, reg); return data < 0 ? data : swab16(data); } @@ -110,8 +185,9 @@ static int reg_clear(struct i2c_client *client, const u8 reg, return reg_write(client, reg, ret & ~data); } -static int set_shutter(struct i2c_client *client, const u32 data) +static int set_shutter(struct v4l2_subdev *sd, const u32 data) { + struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16); @@ -122,9 +198,10 @@ static int set_shutter(struct i2c_client *client, const u32 data) return ret; } -static int get_shutter(struct i2c_client *client, u32 *data) +static int get_shutter(struct v4l2_subdev *sd, u32 *data) { int ret; + struct i2c_client *client = v4l2_get_subdevdata(sd); ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER); *data = ret << 16; @@ -136,20 +213,10 @@ static int get_shutter(struct i2c_client *client, u32 *data) return ret < 0 ? ret : 0; } -static int mt9t031_init(struct soc_camera_device *icd) +static int mt9t031_init(struct v4l2_subdev *sd, u32 val) { - struct i2c_client *client = to_i2c_client(icd->control); - struct soc_camera_link *icl = client->dev.platform_data; int ret; - - if (icl->power) { - ret = icl->power(&client->dev, 1); - if (ret < 0) { - dev_err(icd->vdev->parent, - "Platform failed to power-on the camera.\n"); - return ret; - } - } + struct i2c_client *client = v4l2_get_subdevdata(sd); /* Disable chip output, synchronous option update */ ret = reg_write(client, MT9T031_RESET, 1); @@ -158,99 +225,67 @@ static int mt9t031_init(struct soc_camera_device *icd) if (ret >= 0) ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); - if (ret < 0 && icl->power) - icl->power(&client->dev, 0); - return ret >= 0 ? 0 : -EIO; } -static int mt9t031_release(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(icd->control); - struct soc_camera_link *icl = client->dev.platform_data; - - /* Disable the chip */ - reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); - - if (icl->power) - icl->power(&client->dev, 0); - - return 0; -} - -static int mt9t031_start_capture(struct soc_camera_device *icd) +static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) { - struct i2c_client *client = to_i2c_client(icd->control); + struct i2c_client *client = v4l2_get_subdevdata(sd); /* Switch to master "normal" mode */ - if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0) - return -EIO; - return 0; -} - -static int mt9t031_stop_capture(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(icd->control); - - /* Stop sensor readout */ - if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0) - return -EIO; + if (enable) { + if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0) + return -EIO; + } else { + /* Switch to master "" mode */ + if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0) + return -EIO; + } return 0; } -static int mt9t031_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) +/* Round up minima and round down maxima */ +static void recalculate_limits(struct mt9t031 *mt9t031, + u16 xskip, u16 yskip) { - struct i2c_client *client = to_i2c_client(icd->control); - - /* The caller should have queried our parameters, check anyway */ - if (flags & ~MT9T031_BUS_PARAM) - return -EINVAL; - - if (flags & SOCAM_PCLK_SAMPLE_FALLING) - reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); - else - reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); - - return 0; + mt9t031->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip; + mt9t031->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip; + mt9t031->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip; + mt9t031->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip; + mt9t031->width_max = MT9T031_MAX_WIDTH / xskip; + mt9t031->height_max = MT9T031_MAX_HEIGHT / yskip; } -static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) +const struct v4l2_queryctrl *mt9t031_find_qctrl(u32 id) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - struct soc_camera_link *icl = mt9t031->client->dev.platform_data; + int i; - return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); -} - -/* Round up minima and round down maxima */ -static void recalculate_limits(struct soc_camera_device *icd, - u16 xskip, u16 yskip) -{ - icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip; - icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip; - icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip; - icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip; - icd->width_max = MT9T031_MAX_WIDTH / xskip; - icd->height_max = MT9T031_MAX_HEIGHT / yskip; + for (i = 0; i < mt9t031_num_controls; i++) { + if (mt9t031_controls[i].id == id) + return &mt9t031_controls[i]; + } + return NULL; } -static int mt9t031_set_params(struct soc_camera_device *icd, +static int mt9t031_set_params(struct v4l2_subdev *sd, struct v4l2_rect *rect, u16 xskip, u16 yskip) { - struct i2c_client *client = to_i2c_client(icd->control); - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); + struct mt9t031 *mt9t031 = to_mt9t031(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; u16 xbin, ybin, width, height, left, top; const u16 hblank = MT9T031_HORIZONTAL_BLANK, vblank = MT9T031_VERTICAL_BLANK; /* Make sure we don't exceed sensor limits */ - if (rect->left + rect->width > icd->width_max) - rect->left = (icd->width_max - rect->width) / 2 + icd->x_min; + if (rect->left + rect->width > mt9t031->width_max) + rect->left = + (mt9t031->width_max - rect->width) / 2 + mt9t031->x_min; - if (rect->top + rect->height > icd->height_max) - rect->top = (icd->height_max - rect->height) / 2 + icd->y_min; + if (rect->top + rect->height > mt9t031->height_max) + rect->top = + (mt9t031->height_max - rect->height) / 2 + mt9t031->y_min; width = rect->width * xskip; height = rect->height * yskip; @@ -260,8 +295,9 @@ static int mt9t031_set_params(struct soc_camera_device *icd, xbin = min(xskip, (u16)3); ybin = min(yskip, (u16)3); - dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n", - xskip, width, rect->width, yskip, height, rect->height); + v4l2_dbg(1, debug, sd, "xskip %u, width %u/%u, yskip %u," + "height %u/%u\n", xskip, width, rect->width, yskip, + height, rect->height); /* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */ switch (xbin) { @@ -299,7 +335,7 @@ static int mt9t031_set_params(struct soc_camera_device *icd, ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, ((ybin - 1) << 4) | (yskip - 1)); } - dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top); + v4l2_dbg(1, debug, sd, "new physical left %u, top %u\n", left, top); /* The caller provides a supported format, as guaranteed by * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */ @@ -311,46 +347,41 @@ static int mt9t031_set_params(struct soc_camera_device *icd, ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1); if (ret >= 0) ret = reg_write(client, MT9T031_WINDOW_HEIGHT, - height + icd->y_skip_top - 1); + height + mt9t031->y_skip_top - 1); if (ret >= 0 && mt9t031->autoexposure) { - ret = set_shutter(client, height + icd->y_skip_top + vblank); + ret = set_shutter(sd, height + mt9t031->y_skip_top + vblank); if (ret >= 0) { const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; const struct v4l2_queryctrl *qctrl = - soc_camera_find_qctrl(icd->ops, - V4L2_CID_EXPOSURE); - icd->exposure = (shutter_max / 2 + (height + - icd->y_skip_top + vblank - 1) * + mt9t031_find_qctrl(V4L2_CID_EXPOSURE); + mt9t031->exposure = (shutter_max / 2 + (height + + mt9t031->y_skip_top + vblank - 1) * (qctrl->maximum - qctrl->minimum)) / shutter_max + qctrl->minimum; } } /* Re-enable register update, commit all changes */ - if (ret >= 0) + if (ret >= 0) { ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); - + /* update the values */ + mt9t031->width = rect->width, + mt9t031->height = rect->height, + mt9t031->x_current = rect->left; + mt9t031->y_current = rect->top; + } return ret < 0 ? ret : 0; } -static int mt9t031_set_crop(struct soc_camera_device *icd, - struct v4l2_rect *rect) -{ - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - - /* CROP - no change in scaling, or in limits */ - return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip); -} - -static int mt9t031_set_fmt(struct soc_camera_device *icd, +static int mt9t031_set_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); + struct mt9t031 *mt9t031 = to_mt9t031(sd); int ret; u16 xskip, yskip; struct v4l2_rect rect = { - .left = icd->x_current, - .top = icd->y_current, + .left = mt9t031->x_current, + .top = mt9t031->y_current, .width = f->fmt.pix.width, .height = f->fmt.pix.height, }; @@ -369,18 +400,17 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd, if (rect.height * yskip <= MT9T031_MAX_HEIGHT) break; - recalculate_limits(icd, xskip, yskip); + recalculate_limits(mt9t031, xskip, yskip); - ret = mt9t031_set_params(icd, &rect, xskip, yskip); + ret = mt9t031_set_params(sd, &rect, xskip, yskip); if (!ret) { mt9t031->xskip = xskip; mt9t031->yskip = yskip; } - return ret; } -static int mt9t031_try_fmt(struct soc_camera_device *icd, +static int mt9t031_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) { struct v4l2_pix_format *pix = &f->fmt.pix; @@ -396,19 +426,19 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd, pix->width &= ~0x01; /* has to be even */ pix->height &= ~0x01; /* has to be even */ - return 0; } -static int mt9t031_get_chip_id(struct soc_camera_device *icd, +static int mt9t031_get_chip_id(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); + struct mt9t031 *mt9t031 = to_mt9t031(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd);; if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) return -EINVAL; - if (id->match.addr != mt9t031->client->addr) + if (id->match.addr != client->addr) return -ENODEV; id->ident = mt9t031->model; @@ -418,10 +448,11 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd, } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9t031_get_register(struct soc_camera_device *icd, +static int mt9t031_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { - struct i2c_client *client = to_i2c_client(icd->control); + struct i2c_client *client = v4l2_get_subdevdata(sd);; + struct mt9t031 *mt9t031 = to_mt9t031(sd); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; @@ -437,10 +468,11 @@ static int mt9t031_get_register(struct soc_camera_device *icd, return 0; } -static int mt9t031_set_register(struct soc_camera_device *icd, +static int mt9t031_set_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { - struct i2c_client *client = to_i2c_client(icd->control); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(sd); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; @@ -455,85 +487,53 @@ static int mt9t031_set_register(struct soc_camera_device *icd, } #endif -static const struct v4l2_queryctrl mt9t031_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; -static int mt9t031_video_probe(struct soc_camera_device *); -static void mt9t031_video_remove(struct soc_camera_device *); -static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *); -static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *); - -static struct soc_camera_ops mt9t031_ops = { - .owner = THIS_MODULE, - .probe = mt9t031_video_probe, - .remove = mt9t031_video_remove, - .init = mt9t031_init, - .release = mt9t031_release, - .start_capture = mt9t031_start_capture, - .stop_capture = mt9t031_stop_capture, - .set_crop = mt9t031_set_crop, - .set_fmt = mt9t031_set_fmt, - .try_fmt = mt9t031_try_fmt, - .set_bus_param = mt9t031_set_bus_param, - .query_bus_param = mt9t031_query_bus_param, - .controls = mt9t031_controls, - .num_controls = ARRAY_SIZE(mt9t031_controls), - .get_control = mt9t031_get_control, - .set_control = mt9t031_set_control, - .get_chip_id = mt9t031_get_chip_id, +static int mt9t031_get_control(struct v4l2_subdev *, struct v4l2_control *); +static int mt9t031_set_control(struct v4l2_subdev *, struct v4l2_control *); +static int mt9t031_queryctrl(struct v4l2_subdev *, struct v4l2_queryctrl *); + +static const struct v4l2_subdev_core_ops mt9t031_core_ops = { + .g_chip_ident = mt9t031_get_chip_id, + .init = mt9t031_init, + .queryctrl = mt9t031_queryctrl, + .g_ctrl = mt9t031_get_control, + .s_ctrl = mt9t031_set_control, #ifdef CONFIG_VIDEO_ADV_DEBUG - .get_register = mt9t031_get_register, - .set_register = mt9t031_set_register, + .get_register = mt9t031_get_register, + .set_register = mt9t031_set_register, #endif }; -static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) +static const struct v4l2_subdev_video_ops mt9t031_video_ops = { + .s_fmt = mt9t031_set_fmt, + .try_fmt = mt9t031_try_fmt, + .s_stream = mt9t031_s_stream, +}; + +static const struct v4l2_subdev_ops mt9t031_ops = { + .core = &mt9t031_core_ops, + .video = &mt9t031_video_ops, +}; + +static int mt9t031_queryctrl(struct v4l2_subdev *sd, + struct v4l2_queryctrl *qctrl) { - struct i2c_client *client = to_i2c_client(icd->control); - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); + const struct v4l2_queryctrl *temp_qctrl; + + temp_qctrl = mt9t031_find_qctrl(qctrl->id); + if (!temp_qctrl) { + v4l2_err(sd, "control id %d not supported", qctrl->id); + return -EINVAL; + } + memcpy(qctrl, temp_qctrl, sizeof(*qctrl)); + return 0; +} + +static int mt9t031_get_control(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(sd); int data; switch (ctrl->id) { @@ -556,17 +556,22 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro return 0; } -static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) +static int mt9t031_set_control(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) { - struct i2c_client *client = to_i2c_client(icd->control); - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - const struct v4l2_queryctrl *qctrl; + struct mt9t031 *mt9t031 = to_mt9t031(sd); + const struct v4l2_queryctrl *qctrl = NULL; int data; + struct i2c_client *client = v4l2_get_subdevdata(sd); - qctrl = soc_camera_find_qctrl(&mt9t031_ops, ctrl->id); + if (NULL == ctrl) + return -EINVAL; - if (!qctrl) + qctrl = mt9t031_find_qctrl(ctrl->id); + if (!qctrl) { + v4l2_err(sd, "control id %d not supported", ctrl->id); return -EINVAL; + } switch (ctrl->id) { case V4L2_CID_VFLIP: @@ -594,7 +599,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro unsigned long range = qctrl->default_value - qctrl->minimum; data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; - dev_dbg(&icd->dev, "Setting gain %d\n", data); + v4l2_dbg(1, debug, sd, "Setting gain %d\n", data); data = reg_write(client, MT9T031_GLOBAL_GAIN, data); if (data < 0) return -EIO; @@ -606,40 +611,51 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * 1015 + range / 2) / range + 9; - if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ + if (gain <= 32) + /* calculated gain 9..32 -> 9..32 */ data = gain; - else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */ + else if (gain <= 64) + /* calculated gain 33..64 -> 0x51..0x60 */ data = ((gain - 32) * 16 + 16) / 32 + 80; else - /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */ + /* + * calculated gain 65..1024 -> (1..120) << 8 + + * 0x60 + */ data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; - dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n", - reg_read(client, MT9T031_GLOBAL_GAIN), data); + v4l2_dbg(1, debug, sd, "Setting gain from 0x%x to" + "0x%x\n", + reg_read(client, MT9T031_GLOBAL_GAIN), data); + data = reg_write(client, MT9T031_GLOBAL_GAIN, data); if (data < 0) return -EIO; } /* Success */ - icd->gain = ctrl->value; + mt9t031->gain = ctrl->value; break; case V4L2_CID_EXPOSURE: /* mt9t031 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) + if (ctrl->value > qctrl->maximum || + ctrl->value < qctrl->minimum) return -EINVAL; else { - const unsigned long range = qctrl->maximum - qctrl->minimum; - const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 + - range / 2) / range + 1; + const unsigned long range = + qctrl->maximum - qctrl->minimum; + const u32 shutter = + ((ctrl->value - qctrl->minimum) * 1048 + + range / 2) / range + 1; u32 old; - get_shutter(client, &old); - dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n", + get_shutter(sd, &old); + v4l2_dbg(1, debug, sd, + "Setting shutter width from %u to %u\n", old, shutter); - if (set_shutter(client, shutter) < 0) + if (set_shutter(sd, shutter) < 0) return -EIO; - icd->exposure = ctrl->value; + mt9t031->exposure = ctrl->value; mt9t031->autoexposure = 0; } break; @@ -647,13 +663,15 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro if (ctrl->value) { const u16 vblank = MT9T031_VERTICAL_BLANK; const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; - if (set_shutter(client, icd->height + - icd->y_skip_top + vblank) < 0) + if (set_shutter(sd, mt9t031->height + + mt9t031->y_skip_top + vblank) < 0) return -EIO; - qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); - icd->exposure = (shutter_max / 2 + (icd->height + - icd->y_skip_top + vblank - 1) * - (qctrl->maximum - qctrl->minimum)) / + + qctrl = mt9t031_find_qctrl(V4L2_CID_EXPOSURE); + mt9t031->exposure = + (shutter_max / 2 + (mt9t031->height + + mt9t031->y_skip_top + vblank - 1) * + (qctrl->maximum - qctrl->minimum)) / shutter_max + qctrl->minimum; mt9t031->autoexposure = 1; } else @@ -665,130 +683,102 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro /* 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 mt9t031_video_probe(struct soc_camera_device *icd) +static int mt9t031_detect(struct i2c_client *client, int *model) { - struct i2c_client *client = to_i2c_client(icd->control); - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); s32 data; - int ret; - - /* We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; /* Enable the chip */ data = reg_write(client, MT9T031_CHIP_ENABLE, 1); - dev_dbg(&icd->dev, "write: %d\n", data); + dev_dbg(&client->dev, "write: %d\n", data); /* Read out the chip version register */ data = reg_read(client, MT9T031_CHIP_VERSION); switch (data) { case 0x1621: - mt9t031->model = V4L2_IDENT_MT9T031; - icd->formats = mt9t031_colour_formats; - icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats); + *model = V4L2_IDENT_MT9T031; break; default: - ret = -ENODEV; - dev_err(&icd->dev, + dev_err(&client->dev, "No MT9T031 chip detected, register read %x\n", data); - goto ei2c; + return -ENODEV; } - dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data); - - /* Now that we know the model, we can start video */ - ret = soc_camera_video_start(icd); - if (ret) - goto evstart; - + dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); return 0; - -evstart: -ei2c: - return ret; -} - -static void mt9t031_video_remove(struct soc_camera_device *icd) -{ - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - - dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr, - icd->dev.parent, icd->vdev); - soc_camera_video_stop(icd); } static int mt9t031_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9t031 *mt9t031; - struct soc_camera_device *icd; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl = client->dev.platform_data; + struct v4l2_subdev *sd; + int pclk_pol; int ret; - if (!icl) { - dev_err(&client->dev, "MT9T031 driver needs platform data\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_warn(&adapter->dev, + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&client->dev, "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); return -EIO; } + if (!client->dev.platform_data) { + dev_err(&client->dev, "No platform data!!\n"); + return -ENODEV; + } + + pclk_pol = (int)client->dev.platform_data; + mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL); if (!mt9t031) return -ENOMEM; - mt9t031->client = client; - i2c_set_clientdata(client, mt9t031); - - /* Second stage probe - when a capture adapter is there */ - icd = &mt9t031->icd; - icd->ops = &mt9t031_ops; - icd->control = &client->dev; - icd->x_min = MT9T031_COLUMN_SKIP; - icd->y_min = MT9T031_ROW_SKIP; - icd->x_current = icd->x_min; - icd->y_current = icd->y_min; - icd->width_min = MT9T031_MIN_WIDTH; - icd->width_max = MT9T031_MAX_WIDTH; - icd->height_min = MT9T031_MIN_HEIGHT; - icd->height_max = MT9T031_MAX_HEIGHT; - icd->y_skip_top = 0; - icd->iface = icl->bus_id; - /* Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width */ + ret = mt9t031_detect(client, &mt9t031->model); + if (ret) + goto clean; + + mt9t031->x_min = MT9T031_COLUMN_SKIP; + mt9t031->y_min = MT9T031_ROW_SKIP; + mt9t031->width = MT9T031_DEFAULT_WIDTH; + mt9t031->height = MT9T031_DEFAULT_WIDTH; + mt9t031->x_current = mt9t031->x_min; + mt9t031->y_current = mt9t031->y_min; + mt9t031->width_min = MT9T031_MIN_WIDTH; + mt9t031->width_max = MT9T031_MAX_WIDTH; + mt9t031->height_min = MT9T031_MIN_HEIGHT; + mt9t031->height_max = MT9T031_MAX_HEIGHT; + mt9t031->y_skip_top = 0; mt9t031->autoexposure = 1; - mt9t031->xskip = 1; mt9t031->yskip = 1; - ret = soc_camera_device_register(icd); - if (ret) - goto eisdr; + /* Register with V4L2 layer as slave device */ + sd = &mt9t031->sd; + v4l2_i2c_subdev_init(sd, client, &mt9t031_ops); + if (!pclk_pol) + reg_clear(v4l2_get_subdevdata(sd), + MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); + else + reg_set(v4l2_get_subdevdata(sd), + MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); + v4l2_info(sd, "%s decoder driver registered !!\n", sd->name); return 0; -eisdr: - i2c_set_clientdata(client, NULL); +clean: kfree(mt9t031); return ret; } static int mt9t031_remove(struct i2c_client *client) { - struct mt9t031 *mt9t031 = i2c_get_clientdata(client); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct mt9t031 *mt9t031 = to_mt9t031(sd); - soc_camera_device_unregister(&mt9t031->icd); - i2c_set_clientdata(client, NULL); - kfree(mt9t031); + v4l2_device_unregister_subdev(sd); + kfree(mt9t031); return 0; }