From 0326f126a4d2f1e2cda2c11725a7f7d7d8273f7f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2009 16:28:22 +0200 Subject: soc-camera: convert to platform device From: Guennadi Liakhovetski Convert soc-camera core and all drivers to platform device API. We already converted platforms to register a platform device for each soc-camera client, now we remove the compatibility code and switch completely to the new scheme. This is a preparatory step for the v4l2-subdev conversion. Signed-off-by: Guennadi Liakhovetski Priority: low --- linux/drivers/media/video/mt9m001.c | 114 +++++++++++++++++------------------- 1 file changed, 54 insertions(+), 60 deletions(-) (limited to 'linux/drivers/media/video/mt9m001.c') diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index e609d68c4..ad308da71 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -69,8 +69,6 @@ static const struct soc_camera_data_format mt9m001_monochrome_formats[] = { }; struct mt9m001 { - struct i2c_client *client; - struct soc_camera_device icd; int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ unsigned char autoexposure; }; @@ -111,11 +109,11 @@ static int reg_clear(struct i2c_client *client, const u8 reg, static int mt9m001_init(struct soc_camera_device *icd) { - struct i2c_client *client = to_i2c_client(icd->control); - struct soc_camera_link *icl = client->dev.platform_data; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct soc_camera_link *icl = to_soc_camera_link(icd); int ret; - dev_dbg(icd->vdev->parent, "%s\n", __func__); + dev_dbg(&icd->dev, "%s\n", __func__); if (icl->power) { ret = icl->power(&client->dev, 1); @@ -147,8 +145,8 @@ static int mt9m001_init(struct soc_camera_device *icd) static int mt9m001_release(struct soc_camera_device *icd) { - struct i2c_client *client = to_i2c_client(icd->control); - struct soc_camera_link *icl = client->dev.platform_data; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct soc_camera_link *icl = to_soc_camera_link(icd); /* Disable the chip */ reg_write(client, MT9M001_OUTPUT_CONTROL, 0); @@ -161,7 +159,7 @@ static int mt9m001_release(struct soc_camera_device *icd) static int mt9m001_start_capture(struct soc_camera_device *icd) { - struct i2c_client *client = to_i2c_client(icd->control); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); /* Switch to master "normal" mode */ if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0) @@ -171,7 +169,7 @@ static int mt9m001_start_capture(struct soc_camera_device *icd) static int mt9m001_stop_capture(struct soc_camera_device *icd) { - struct i2c_client *client = to_i2c_client(icd->control); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); /* Stop sensor readout */ if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0) @@ -182,8 +180,7 @@ static int mt9m001_stop_capture(struct soc_camera_device *icd) static int mt9m001_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; /* Only one width bit may be set */ @@ -205,8 +202,7 @@ static int mt9m001_set_bus_param(struct soc_camera_device *icd, static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); /* MT9M001 has all capture_format parameters fixed */ unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | @@ -223,8 +219,8 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) static int mt9m001_set_crop(struct soc_camera_device *icd, struct v4l2_rect *rect) { - struct i2c_client *client = to_i2c_client(icd->control); - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9m001 *mt9m001 = i2c_get_clientdata(client); int ret; const u16 hblank = 9, vblank = 25; @@ -290,12 +286,13 @@ static int mt9m001_try_fmt(struct soc_camera_device *icd, static int mt9m001_get_chip_id(struct soc_camera_device *icd, struct v4l2_dbg_chip_ident *id) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9m001 *mt9m001 = i2c_get_clientdata(client); if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) return -EINVAL; - if (id->match.addr != mt9m001->client->addr) + if (id->match.addr != client->addr) return -ENODEV; id->ident = mt9m001->model; @@ -308,7 +305,7 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd, static int mt9m001_get_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct i2c_client *client = to_i2c_client(icd->control); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; @@ -328,7 +325,7 @@ static int mt9m001_get_register(struct soc_camera_device *icd, static int mt9m001_set_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct i2c_client *client = to_i2c_client(icd->control); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; @@ -381,15 +378,11 @@ static const struct v4l2_queryctrl mt9m001_controls[] = { } }; -static int mt9m001_video_probe(struct soc_camera_device *); -static void mt9m001_video_remove(struct soc_camera_device *); static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *); static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *); static struct soc_camera_ops mt9m001_ops = { .owner = THIS_MODULE, - .probe = mt9m001_video_probe, - .remove = mt9m001_video_remove, .init = mt9m001_init, .release = mt9m001_release, .start_capture = mt9m001_start_capture, @@ -412,8 +405,8 @@ static struct soc_camera_ops mt9m001_ops = { static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { - struct i2c_client *client = to_i2c_client(icd->control); - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9m001 *mt9m001 = i2c_get_clientdata(client); int data; switch (ctrl->id) { @@ -432,8 +425,8 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { - struct i2c_client *client = to_i2c_client(icd->control); - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9m001 *mt9m001 = i2c_get_clientdata(client); const struct v4l2_queryctrl *qctrl; int data; @@ -525,11 +518,11 @@ static int mt9m001_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 mt9m001_video_probe(struct soc_camera_device *icd) +static int mt9m001_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) { - struct i2c_client *client = to_i2c_client(icd->control); - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = client->dev.platform_data; + struct mt9m001 *mt9m001 = i2c_get_clientdata(client); + struct soc_camera_link *icl = to_soc_camera_link(icd); s32 data; int ret; unsigned long flags; @@ -540,6 +533,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd) to_soc_camera_host(icd->dev.parent)->nr != icd->iface) return -ENODEV; + /* Switch master clock on */ + ret = soc_camera_video_start(icd, &client->dev); + if (ret) + return ret; + /* Enable the chip */ data = reg_write(client, MT9M001_CHIP_ENABLE, 1); dev_dbg(&icd->dev, "write: %d\n", data); @@ -547,6 +545,8 @@ static int mt9m001_video_probe(struct soc_camera_device *icd) /* Read out the chip version register */ data = reg_read(client, MT9M001_CHIP_VERSION); + soc_camera_video_stop(icd); + /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ switch (data) { case 0x8411: @@ -559,10 +559,9 @@ static int mt9m001_video_probe(struct soc_camera_device *icd) icd->formats = mt9m001_monochrome_formats; break; default: - ret = -ENODEV; dev_err(&icd->dev, "No MT9M001 chip detected, register read %x\n", data); - goto ei2c; + return -ENODEV; } icd->num_formats = 0; @@ -588,26 +587,16 @@ static int mt9m001_video_probe(struct soc_camera_device *icd) dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, data == 0x8431 ? "C12STM" : "C12ST"); - /* Now that we know the model, we can start video */ - ret = soc_camera_video_start(icd); - if (ret) - goto eisis; - return 0; - -eisis: -ei2c: - return ret; } static void mt9m001_video_remove(struct soc_camera_device *icd) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct soc_camera_link *icl = to_soc_camera_link(icd); - dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr, + dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr, icd->dev.parent, icd->vdev); - soc_camera_video_stop(icd); if (icl->free_bus) icl->free_bus(icl); } @@ -620,11 +609,17 @@ static int mt9m001_probe(struct i2c_client *client) #endif { struct mt9m001 *mt9m001; - struct soc_camera_device *icd; + struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl = client->dev.platform_data; + struct soc_camera_link *icl; int ret; + if (!icd) { + dev_err(&client->dev, "MT9M001: missing soc-camera data!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "MT9M001 driver needs platform data\n"); return -EINVAL; @@ -640,13 +635,10 @@ static int mt9m001_probe(struct i2c_client *client) if (!mt9m001) return -ENOMEM; - mt9m001->client = client; i2c_set_clientdata(client, mt9m001); /* Second stage probe - when a capture adapter is there */ - icd = &mt9m001->icd; icd->ops = &mt9m001_ops; - icd->control = &client->dev; icd->x_min = 20; icd->y_min = 12; icd->x_current = 20; @@ -656,27 +648,29 @@ static int mt9m001_probe(struct i2c_client *client) icd->height_min = 32; icd->height_max = 1024; icd->y_skip_top = 1; - icd->iface = icl->bus_id; /* Simulated autoexposure. If enabled, we calculate shutter width * ourselves in the driver based on vertical blanking and frame width */ mt9m001->autoexposure = 1; - ret = soc_camera_device_register(icd); - if (ret) - goto eisdr; - - return 0; + ret = mt9m001_video_probe(icd, client); + if (ret) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(mt9m001); + } -eisdr: - kfree(mt9m001); return ret; } static int mt9m001_remove(struct i2c_client *client) { struct mt9m001 *mt9m001 = i2c_get_clientdata(client); + struct soc_camera_device *icd = client->dev.platform_data; - soc_camera_device_unregister(&mt9m001->icd); + icd->ops = NULL; + mt9m001_video_remove(icd); + i2c_set_clientdata(client, NULL); + client->driver = NULL; kfree(mt9m001); return 0; -- cgit v1.2.3 From a9c698e163df3064b2a003395d6115985d8a4f78 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2009 16:43:33 +0200 Subject: soc-camera: (partially) convert to v4l2-(sub)dev API From: Guennadi Liakhovetski Convert the soc-camera framework to use the v4l2-(sub)dev API. Start using v4l2-subdev operations. Only a part of the interface between the soc_camera core, soc_camera host drivers on one side and soc_camera device drivers on the other side is replaced so far. The rest of the interface will be replaced in incremental steps, and will require extensions and, possibly, modifications to the v4l2-subdev code. Signed-off-by: Guennadi Liakhovetski Priority: low --- linux/drivers/media/video/mt9m001.c | 157 ++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 89 deletions(-) (limited to 'linux/drivers/media/video/mt9m001.c') diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index ad308da71..45d8fad25 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -13,13 +13,13 @@ #include #include -#include +#include #include #include /* mt9m001 i2c address 0x5d - * The platform has to define i2c_board_info - * and call i2c_register_board_info() */ + * The platform has to define ctruct i2c_board_info objects and link to them + * from struct soc_camera_link */ /* mt9m001 selected register addresses */ #define MT9M001_CHIP_VERSION 0x00 @@ -69,10 +69,16 @@ static const struct soc_camera_data_format mt9m001_monochrome_formats[] = { }; struct mt9m001 { + struct v4l2_subdev subdev; int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ unsigned char autoexposure; }; +static struct mt9m001 *to_mt9m001(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct mt9m001, subdev); +} + static int reg_read(struct i2c_client *client, const u8 reg) { s32 data = i2c_smbus_read_word_data(client, reg); @@ -110,32 +116,18 @@ static int reg_clear(struct i2c_client *client, const u8 reg, static int mt9m001_init(struct soc_camera_device *icd) { struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct soc_camera_link *icl = to_soc_camera_link(icd); int ret; dev_dbg(&icd->dev, "%s\n", __func__); - 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; - } - } - - /* The camera could have been already on, we reset it additionally */ - if (icl->reset) - ret = icl->reset(&client->dev); - else - ret = -ENODEV; + /* + * We don't know, whether platform provides reset, + * issue a soft reset too + */ + ret = reg_write(client, MT9M001_RESET, 1); + if (!ret) + ret = reg_write(client, MT9M001_RESET, 0); - if (ret < 0) { - /* Either no platform reset, or platform reset failed */ - ret = reg_write(client, MT9M001_RESET, 1); - if (!ret) - ret = reg_write(client, MT9M001_RESET, 0); - } /* Disable chip, synchronous option update */ if (!ret) ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); @@ -146,33 +138,19 @@ static int mt9m001_init(struct soc_camera_device *icd) static int mt9m001_release(struct soc_camera_device *icd) { struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct soc_camera_link *icl = to_soc_camera_link(icd); /* Disable the chip */ reg_write(client, MT9M001_OUTPUT_CONTROL, 0); - if (icl->power) - icl->power(&client->dev, 0); - return 0; } -static int mt9m001_start_capture(struct soc_camera_device *icd) +static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct i2c_client *client = sd->priv; - /* Switch to master "normal" mode */ - if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0) - return -EIO; - return 0; -} - -static int mt9m001_stop_capture(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - - /* Stop sensor readout */ - if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0) + /* Switch to master "normal" mode or stop sensor readout */ + if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0) return -EIO; return 0; } @@ -220,7 +198,7 @@ static int mt9m001_set_crop(struct soc_camera_device *icd, struct v4l2_rect *rect) { struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9m001 *mt9m001 = i2c_get_clientdata(client); + struct mt9m001 *mt9m001 = to_mt9m001(client); int ret; const u16 hblank = 9, vblank = 25; @@ -257,9 +235,10 @@ static int mt9m001_set_crop(struct soc_camera_device *icd, return ret; } -static int mt9m001_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) +static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) { + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; struct v4l2_rect rect = { .left = icd->x_current, .top = icd->y_current, @@ -271,9 +250,10 @@ static int mt9m001_set_fmt(struct soc_camera_device *icd, return mt9m001_set_crop(icd, &rect); } -static int mt9m001_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) +static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) { + struct i2c_client *client = sd->priv; + struct soc_camera_device *icd = client->dev.platform_data; struct v4l2_pix_format *pix = &f->fmt.pix; v4l_bound_align_image(&pix->width, 48, 1280, 1, @@ -283,11 +263,11 @@ static int mt9m001_try_fmt(struct soc_camera_device *icd, return 0; } -static int mt9m001_get_chip_id(struct soc_camera_device *icd, - struct v4l2_dbg_chip_ident *id) +static int mt9m001_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9m001 *mt9m001 = i2c_get_clientdata(client); + struct i2c_client *client = sd->priv; + struct mt9m001 *mt9m001 = to_mt9m001(client); if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) return -EINVAL; @@ -302,10 +282,10 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd, } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9m001_get_register(struct soc_camera_device *icd, - struct v4l2_dbg_register *reg) +static int mt9m001_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct i2c_client *client = sd->priv; if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; @@ -322,10 +302,10 @@ static int mt9m001_get_register(struct soc_camera_device *icd, return 0; } -static int mt9m001_set_register(struct soc_camera_device *icd, - struct v4l2_dbg_register *reg) +static int mt9m001_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct i2c_client *client = sd->priv; if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; @@ -378,35 +358,20 @@ static const struct v4l2_queryctrl mt9m001_controls[] = { } }; -static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *); -static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *); - static struct soc_camera_ops mt9m001_ops = { - .owner = THIS_MODULE, .init = mt9m001_init, .release = mt9m001_release, - .start_capture = mt9m001_start_capture, - .stop_capture = mt9m001_stop_capture, .set_crop = mt9m001_set_crop, - .set_fmt = mt9m001_set_fmt, - .try_fmt = mt9m001_try_fmt, .set_bus_param = mt9m001_set_bus_param, .query_bus_param = mt9m001_query_bus_param, .controls = mt9m001_controls, .num_controls = ARRAY_SIZE(mt9m001_controls), - .get_control = mt9m001_get_control, - .set_control = mt9m001_set_control, - .get_chip_id = mt9m001_get_chip_id, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .get_register = mt9m001_get_register, - .set_register = mt9m001_set_register, -#endif }; -static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) +static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9m001 *mt9m001 = i2c_get_clientdata(client); + struct i2c_client *client = sd->priv; + struct mt9m001 *mt9m001 = to_mt9m001(client); int data; switch (ctrl->id) { @@ -423,10 +388,11 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro return 0; } -static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) +static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9m001 *mt9m001 = i2c_get_clientdata(client); + struct i2c_client *client = sd->priv; + struct mt9m001 *mt9m001 = to_mt9m001(client); + struct soc_camera_device *icd = client->dev.platform_data; const struct v4l2_queryctrl *qctrl; int data; @@ -521,10 +487,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro static int mt9m001_video_probe(struct soc_camera_device *icd, struct i2c_client *client) { - struct mt9m001 *mt9m001 = i2c_get_clientdata(client); + struct mt9m001 *mt9m001 = to_mt9m001(client); struct soc_camera_link *icl = to_soc_camera_link(icd); s32 data; - int ret; unsigned long flags; /* We must have a parent by now. And it cannot be a wrong one. @@ -533,11 +498,6 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, to_soc_camera_host(icd->dev.parent)->nr != icd->iface) return -ENODEV; - /* Switch master clock on */ - ret = soc_camera_video_start(icd, &client->dev); - if (ret) - return ret; - /* Enable the chip */ data = reg_write(client, MT9M001_CHIP_ENABLE, 1); dev_dbg(&icd->dev, "write: %d\n", data); @@ -545,8 +505,6 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, /* Read out the chip version register */ data = reg_read(client, MT9M001_CHIP_VERSION); - soc_camera_video_stop(icd); - /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ switch (data) { case 0x8411: @@ -601,6 +559,27 @@ static void mt9m001_video_remove(struct soc_camera_device *icd) icl->free_bus(icl); } +static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { + .g_ctrl = mt9m001_g_ctrl, + .s_ctrl = mt9m001_s_ctrl, + .g_chip_ident = mt9m001_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9m001_g_register, + .s_register = mt9m001_s_register, +#endif +}; + +static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { + .s_stream = mt9m001_s_stream, + .s_fmt = mt9m001_s_fmt, + .try_fmt = mt9m001_try_fmt, +}; + +static struct v4l2_subdev_ops mt9m001_subdev_ops = { + .core = &mt9m001_subdev_core_ops, + .video = &mt9m001_subdev_video_ops, +}; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) static int mt9m001_probe(struct i2c_client *client, const struct i2c_device_id *did) @@ -635,7 +614,7 @@ static int mt9m001_probe(struct i2c_client *client) if (!mt9m001) return -ENOMEM; - i2c_set_clientdata(client, mt9m001); + v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); /* Second stage probe - when a capture adapter is there */ icd->ops = &mt9m001_ops; @@ -664,7 +643,7 @@ static int mt9m001_probe(struct i2c_client *client) static int mt9m001_remove(struct i2c_client *client) { - struct mt9m001 *mt9m001 = i2c_get_clientdata(client); + struct mt9m001 *mt9m001 = to_mt9m001(client); struct soc_camera_device *icd = client->dev.platform_data; icd->ops = NULL; -- cgit v1.2.3 From 67b6fcc4c0404e94f16820566585bb0ff9891b89 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2009 16:46:17 +0200 Subject: soc-camera: use struct v4l2_rect in struct soc_camera_device From: Guennadi Liakhovetski Switch to using struct v4l2_rect in struct soc_camera_device for uniformity and simplicity. Signed-off-by: Guennadi Liakhovetski Priority: low --- linux/drivers/media/video/mt9m001.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'linux/drivers/media/video/mt9m001.c') diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index 45d8fad25..7a9435f9b 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -240,8 +240,8 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) struct i2c_client *client = sd->priv; struct soc_camera_device *icd = client->dev.platform_data; struct v4l2_rect rect = { - .left = icd->x_current, - .top = icd->y_current, + .left = icd->rect_current.left, + .top = icd->rect_current.top, .width = f->fmt.pix.width, .height = f->fmt.pix.height, }; @@ -467,11 +467,13 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) case V4L2_CID_EXPOSURE_AUTO: if (ctrl->value) { const u16 vblank = 25; - if (reg_write(client, MT9M001_SHUTTER_WIDTH, icd->height + + if (reg_write(client, MT9M001_SHUTTER_WIDTH, + icd->rect_current.height + icd->y_skip_top + vblank) < 0) return -EIO; qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); - icd->exposure = (524 + (icd->height + icd->y_skip_top + vblank - 1) * + icd->exposure = (524 + (icd->rect_current.height + + icd->y_skip_top + vblank - 1) * (qctrl->maximum - qctrl->minimum)) / 1048 + qctrl->minimum; mt9m001->autoexposure = 1; @@ -617,16 +619,16 @@ static int mt9m001_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); /* Second stage probe - when a capture adapter is there */ - icd->ops = &mt9m001_ops; - icd->x_min = 20; - icd->y_min = 12; - icd->x_current = 20; - icd->y_current = 12; - icd->width_min = 48; - icd->width_max = 1280; - icd->height_min = 32; - icd->height_max = 1024; - icd->y_skip_top = 1; + icd->ops = &mt9m001_ops; + icd->rect_max.left = 20; + icd->rect_max.top = 12; + icd->rect_max.width = 1280; + icd->rect_max.height = 1024; + icd->rect_current.left = 20; + icd->rect_current.top = 12; + icd->width_min = 48; + icd->height_min = 32; + icd->y_skip_top = 1; /* Simulated autoexposure. If enabled, we calculate shutter width * ourselves in the driver based on vertical blanking and frame width */ mt9m001->autoexposure = 1; -- cgit v1.2.3 From a94ff67f3f3091badb6034566504ad58206989ef Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2009 16:46:54 +0200 Subject: soc-camera: switch to s_crop v4l2-subdev video operation From: Guennadi Liakhovetski Remove set_crop soc-camera device method and switch to s_crop from v4l2-subdev video operations. Also extend non-i2c drivers to also hold a pointer to their v4l2-subdev instance in control device driver-data, i.e., in dev_get_drvdata((struct device *)to_soc_camera_control(icd)) Signed-off-by: Guennadi Liakhovetski Priority: low --- drivers/media/video/mt9m001.c | 23 +++--- drivers/media/video/mt9m111.c | 9 +- drivers/media/video/mt9t031.c | 9 +- drivers/media/video/mt9v022.c | 23 +++--- drivers/media/video/mx1_camera.c | 8 ++- drivers/media/video/mx3_camera.c | 7 +- drivers/media/video/ov772x.c | 19 ----- drivers/media/video/pxa_camera.c | 7 +- drivers/media/video/sh_mobile_ceu_camera.c | 110 ++++++++++++++------------- drivers/media/video/soc_camera.c | 4 +- drivers/media/video/soc_camera_platform.c | 28 ++++---- drivers/media/video/tw9910.c | 31 ++++---- include/media/soc_camera.h | 3 +- 13 files changed, 142 insertions(+), 139 deletions(-) --- linux/drivers/media/video/mt9m001.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'linux/drivers/media/video/mt9m001.c') diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index 7a9435f9b..b74ef6cea 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -194,11 +194,12 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) return soc_camera_apply_sensor_flags(icl, flags); } -static int mt9m001_set_crop(struct soc_camera_device *icd, - struct v4l2_rect *rect) +static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct v4l2_rect *rect = &a->c; + struct i2c_client *client = sd->priv; struct mt9m001 *mt9m001 = to_mt9m001(client); + struct soc_camera_device *icd = client->dev.platform_data; int ret; const u16 hblank = 9, vblank = 25; @@ -239,15 +240,17 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) { struct i2c_client *client = sd->priv; struct soc_camera_device *icd = client->dev.platform_data; - struct v4l2_rect rect = { - .left = icd->rect_current.left, - .top = icd->rect_current.top, - .width = f->fmt.pix.width, - .height = f->fmt.pix.height, + struct v4l2_crop a = { + .c = { + .left = icd->rect_current.left, + .top = icd->rect_current.top, + .width = f->fmt.pix.width, + .height = f->fmt.pix.height, + }, }; /* No support for scaling so far, just crop. TODO: use skipping */ - return mt9m001_set_crop(icd, &rect); + return mt9m001_s_crop(sd, &a); } static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) @@ -361,7 +364,6 @@ static const struct v4l2_queryctrl mt9m001_controls[] = { static struct soc_camera_ops mt9m001_ops = { .init = mt9m001_init, .release = mt9m001_release, - .set_crop = mt9m001_set_crop, .set_bus_param = mt9m001_set_bus_param, .query_bus_param = mt9m001_query_bus_param, .controls = mt9m001_controls, @@ -575,6 +577,7 @@ static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .s_stream = mt9m001_s_stream, .s_fmt = mt9m001_s_fmt, .try_fmt = mt9m001_try_fmt, + .s_crop = mt9m001_s_crop, }; static struct v4l2_subdev_ops mt9m001_subdev_ops = { -- cgit v1.2.3 From 3a76b0c22111746bd099bc5c9279dbedc734e3ac Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2009 16:47:00 +0200 Subject: soc-camera: Use I2C device for dev_{dbg,info,...} output in all clients From: Guennadi Liakhovetski Signed-off-by: Guennadi Liakhovetski Priority: low --- drivers/media/video/mt9m001.c | 20 +++++++++++--------- drivers/media/video/mt9m111.c | 11 +++++------ drivers/media/video/mt9t031.c | 16 ++++++++-------- drivers/media/video/mt9v022.c | 16 ++++++++-------- drivers/media/video/ov772x.c | 6 +++--- drivers/media/video/tw9910.c | 6 +++--- 6 files changed, 38 insertions(+), 37 deletions(-) --- linux/drivers/media/video/mt9m001.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'linux/drivers/media/video/mt9m001.c') diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index b74ef6cea..d4ebab8c2 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -118,7 +118,7 @@ static int mt9m001_init(struct soc_camera_device *icd) struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); int ret; - dev_dbg(&icd->dev, "%s\n", __func__); + dev_dbg(&client->dev, "%s\n", __func__); /* * We don't know, whether platform provides reset, @@ -421,7 +421,7 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 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); + dev_dbg(&client->dev, "Setting gain %d\n", data); data = reg_write(client, MT9M001_GLOBAL_GAIN, data); if (data < 0) return -EIO; @@ -439,7 +439,7 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) else data = ((gain - 64) * 7 + 28) / 56 + 96; - dev_dbg(&icd->dev, "Setting gain from %d to %d\n", + dev_dbg(&client->dev, "Setting gain from %d to %d\n", reg_read(client, MT9M001_GLOBAL_GAIN), data); data = reg_write(client, MT9M001_GLOBAL_GAIN, data); if (data < 0) @@ -458,8 +458,10 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 + range / 2) / range + 1; - dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n", - reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); + dev_dbg(&client->dev, + "Setting shutter width from %d to %lu\n", + reg_read(client, MT9M001_SHUTTER_WIDTH), + shutter); if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) return -EIO; icd->exposure = ctrl->value; @@ -504,7 +506,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, /* Enable the chip */ data = reg_write(client, MT9M001_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, MT9M001_CHIP_VERSION); @@ -521,7 +523,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, icd->formats = mt9m001_monochrome_formats; break; default: - dev_err(&icd->dev, + dev_err(&client->dev, "No MT9M001 chip detected, register read %x\n", data); return -ENODEV; } @@ -546,7 +548,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, if (flags & SOCAM_DATAWIDTH_8) icd->num_formats++; - dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, + dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, data == 0x8431 ? "C12STM" : "C12ST"); return 0; @@ -557,7 +559,7 @@ static void mt9m001_video_remove(struct soc_camera_device *icd) struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); struct soc_camera_link *icl = to_soc_camera_link(icd); - dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr, + dev_dbg(&client->dev, "Video %x removed: %p, %p\n", client->addr, icd->dev.parent, icd->vdev); if (icl->free_bus) icl->free_bus(icl); -- cgit v1.2.3 From 30e8a71f69f2769f966054f168e9e4ced8a1d091 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2009 16:50:46 +0200 Subject: soc-camera: V4L2 API compliant scaling (S_FMT) and cropping (S_CROP) From: Guennadi Liakhovetski The initial soc-camera scaling and cropping implementation turned out to be incompliant with the V4L2 API, e.g., it expected the user to specify cropping in output window pixels, instead of input window pixels. This patch converts the soc-camera core and all drivers to comply with the standard. Signed-off-by: Guennadi Liakhovetski Priority: low --- linux/drivers/media/video/mt9m001.c | 142 +++++++++++++++++++++++++++++------- 1 file changed, 114 insertions(+), 28 deletions(-) (limited to 'linux/drivers/media/video/mt9m001.c') diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index d4ebab8c2..3fcf57118 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -39,6 +39,13 @@ #define MT9M001_GLOBAL_GAIN 0x35 #define MT9M001_CHIP_ENABLE 0xF1 +#define MT9M001_MAX_WIDTH 1280 +#define MT9M001_MAX_HEIGHT 1024 +#define MT9M001_MIN_WIDTH 48 +#define MT9M001_MIN_HEIGHT 32 +#define MT9M001_COLUMN_SKIP 20 +#define MT9M001_ROW_SKIP 12 + static const struct soc_camera_data_format mt9m001_colour_formats[] = { /* Order important: first natively supported, * second supported with a GPIO extender */ @@ -70,6 +77,8 @@ static const struct soc_camera_data_format mt9m001_monochrome_formats[] = { struct mt9m001 { struct v4l2_subdev subdev; + struct v4l2_rect rect; /* Sensor window */ + __u32 fourcc; int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ unsigned char autoexposure; }; @@ -196,13 +205,31 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { - struct v4l2_rect *rect = &a->c; struct i2c_client *client = sd->priv; struct mt9m001 *mt9m001 = to_mt9m001(client); + struct v4l2_rect rect = a->c; struct soc_camera_device *icd = client->dev.platform_data; int ret; const u16 hblank = 9, vblank = 25; + if (mt9m001->fourcc == V4L2_PIX_FMT_SBGGR8 || + mt9m001->fourcc == V4L2_PIX_FMT_SBGGR16) + /* + * Bayer format - even number of rows for simplicity, + * but let the user play with the top row. + */ + rect.height = ALIGN(rect.height, 2); + + /* Datasheet requirement: see register description */ + rect.width = ALIGN(rect.width, 2); + rect.left = ALIGN(rect.left, 2); + + soc_camera_limit_side(&rect.left, &rect.width, + MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH); + + soc_camera_limit_side(&rect.top, &rect.height, + MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); + /* Blanking and start values - default... */ ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); if (!ret) @@ -211,46 +238,98 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) /* The caller provides a supported format, as verified per * call to icd->try_fmt() */ if (!ret) - ret = reg_write(client, MT9M001_COLUMN_START, rect->left); + ret = reg_write(client, MT9M001_COLUMN_START, rect.left); if (!ret) - ret = reg_write(client, MT9M001_ROW_START, rect->top); + ret = reg_write(client, MT9M001_ROW_START, rect.top); if (!ret) - ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect->width - 1); + ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1); if (!ret) ret = reg_write(client, MT9M001_WINDOW_HEIGHT, - rect->height + icd->y_skip_top - 1); + rect.height + icd->y_skip_top - 1); if (!ret && mt9m001->autoexposure) { ret = reg_write(client, MT9M001_SHUTTER_WIDTH, - rect->height + icd->y_skip_top + vblank); + rect.height + icd->y_skip_top + vblank); if (!ret) { const struct v4l2_queryctrl *qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); - icd->exposure = (524 + (rect->height + icd->y_skip_top + + icd->exposure = (524 + (rect.height + icd->y_skip_top + vblank - 1) * (qctrl->maximum - qctrl->minimum)) / 1048 + qctrl->minimum; } } + if (!ret) + mt9m001->rect = rect; + return ret; } +static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = sd->priv; + struct mt9m001 *mt9m001 = to_mt9m001(client); + + a->c = mt9m001->rect; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = MT9M001_COLUMN_SKIP; + a->bounds.top = MT9M001_ROW_SKIP; + a->bounds.width = MT9M001_MAX_WIDTH; + a->bounds.height = MT9M001_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 mt9m001_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct mt9m001 *mt9m001 = to_mt9m001(client); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = mt9m001->rect.width; + pix->height = mt9m001->rect.height; + pix->pixelformat = mt9m001->fourcc; + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_SRGB; + + return 0; +} + static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) { struct i2c_client *client = sd->priv; - struct soc_camera_device *icd = client->dev.platform_data; + struct mt9m001 *mt9m001 = to_mt9m001(client); + struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_crop a = { .c = { - .left = icd->rect_current.left, - .top = icd->rect_current.top, - .width = f->fmt.pix.width, - .height = f->fmt.pix.height, + .left = mt9m001->rect.left, + .top = mt9m001->rect.top, + .width = pix->width, + .height = pix->height, }, }; + int ret; /* No support for scaling so far, just crop. TODO: use skipping */ - return mt9m001_s_crop(sd, &a); + ret = mt9m001_s_crop(sd, &a); + if (!ret) { + pix->width = mt9m001->rect.width; + pix->height = mt9m001->rect.height; + mt9m001->fourcc = pix->pixelformat; + } + + return ret; } static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) @@ -259,9 +338,14 @@ static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) struct soc_camera_device *icd = client->dev.platform_data; struct v4l2_pix_format *pix = &f->fmt.pix; - v4l_bound_align_image(&pix->width, 48, 1280, 1, - &pix->height, 32 + icd->y_skip_top, - 1024 + icd->y_skip_top, 0, 0); + v4l_bound_align_image(&pix->width, MT9M001_MIN_WIDTH, + MT9M001_MAX_WIDTH, 1, + &pix->height, MT9M001_MIN_HEIGHT + icd->y_skip_top, + MT9M001_MAX_HEIGHT + icd->y_skip_top, 0, 0); + + if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || + pix->pixelformat == V4L2_PIX_FMT_SBGGR16) + pix->height = ALIGN(pix->height - 1, 2); return 0; } @@ -472,11 +556,11 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (ctrl->value) { const u16 vblank = 25; if (reg_write(client, MT9M001_SHUTTER_WIDTH, - icd->rect_current.height + + mt9m001->rect.height + icd->y_skip_top + vblank) < 0) return -EIO; qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); - icd->exposure = (524 + (icd->rect_current.height + + icd->exposure = (524 + (mt9m001->rect.height + icd->y_skip_top + vblank - 1) * (qctrl->maximum - qctrl->minimum)) / 1048 + qctrl->minimum; @@ -548,6 +632,8 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, if (flags & SOCAM_DATAWIDTH_8) icd->num_formats++; + mt9m001->fourcc = icd->formats->fourcc; + dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, data == 0x8431 ? "C12STM" : "C12ST"); @@ -556,10 +642,9 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, static void mt9m001_video_remove(struct soc_camera_device *icd) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); struct soc_camera_link *icl = to_soc_camera_link(icd); - dev_dbg(&client->dev, "Video %x removed: %p, %p\n", client->addr, + dev_dbg(&icd->dev, "Video removed: %p, %p\n", icd->dev.parent, icd->vdev); if (icl->free_bus) icl->free_bus(icl); @@ -578,8 +663,11 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .s_stream = mt9m001_s_stream, .s_fmt = mt9m001_s_fmt, + .g_fmt = mt9m001_g_fmt, .try_fmt = mt9m001_try_fmt, .s_crop = mt9m001_s_crop, + .g_crop = mt9m001_g_crop, + .cropcap = mt9m001_cropcap, }; static struct v4l2_subdev_ops mt9m001_subdev_ops = { @@ -625,15 +713,13 @@ static int mt9m001_probe(struct i2c_client *client) /* Second stage probe - when a capture adapter is there */ icd->ops = &mt9m001_ops; - icd->rect_max.left = 20; - icd->rect_max.top = 12; - icd->rect_max.width = 1280; - icd->rect_max.height = 1024; - icd->rect_current.left = 20; - icd->rect_current.top = 12; - icd->width_min = 48; - icd->height_min = 32; icd->y_skip_top = 1; + + mt9m001->rect.left = MT9M001_COLUMN_SKIP; + mt9m001->rect.top = MT9M001_ROW_SKIP; + mt9m001->rect.width = MT9M001_MAX_WIDTH; + mt9m001->rect.height = MT9M001_MAX_HEIGHT; + /* Simulated autoexposure. If enabled, we calculate shutter width * ourselves in the driver based on vertical blanking and frame width */ mt9m001->autoexposure = 1; -- cgit v1.2.3 From 243028968448b7efc378c94fb7b5f285ab01fbba Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2009 16:53:23 +0200 Subject: soc-camera: remove .init() and .release() methods from struct soc_camera_ops From: Guennadi Liakhovetski Remove unneeded soc-camera operations, this also makes the soc-camera API to v4l2 subdevices thinner. Signed-off-by: Guennadi Liakhovetski Priority: low --- drivers/media/video/mt9m001.c | 22 ++++++-------------- drivers/media/video/mt9m111.c | 40 +++++++------------------------------ drivers/media/video/mt9t031.c | 23 +++++---------------- drivers/media/video/mt9v022.c | 8 ++++-- drivers/media/video/soc_camera.c | 11 ---------- include/media/soc_camera.h | 4 --- 6 files changed, 26 insertions(+), 82 deletions(-) --- linux/drivers/media/video/mt9m001.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'linux/drivers/media/video/mt9m001.c') diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index 3fcf57118..9da7789e6 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -122,9 +122,8 @@ static int reg_clear(struct i2c_client *client, const u8 reg, return reg_write(client, reg, ret & ~data); } -static int mt9m001_init(struct soc_camera_device *icd) +static int mt9m001_init(struct i2c_client *client) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); int ret; dev_dbg(&client->dev, "%s\n", __func__); @@ -144,16 +143,6 @@ static int mt9m001_init(struct soc_camera_device *icd) return ret; } -static int mt9m001_release(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - - /* Disable the chip */ - reg_write(client, MT9M001_OUTPUT_CONTROL, 0); - - return 0; -} - static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) { struct i2c_client *client = sd->priv; @@ -446,8 +435,6 @@ static const struct v4l2_queryctrl mt9m001_controls[] = { }; static struct soc_camera_ops mt9m001_ops = { - .init = mt9m001_init, - .release = mt9m001_release, .set_bus_param = mt9m001_set_bus_param, .query_bus_param = mt9m001_query_bus_param, .controls = mt9m001_controls, @@ -581,6 +568,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, struct soc_camera_link *icl = to_soc_camera_link(icd); s32 data; unsigned long flags; + int ret; /* We must have a parent by now. And it cannot be a wrong one. * So this entire test is completely redundant. */ @@ -637,7 +625,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, data == 0x8431 ? "C12STM" : "C12ST"); - return 0; + ret = mt9m001_init(client); + if (ret < 0) + dev_err(&client->dev, "Failed to initialise the camera\n"); + + return ret; } static void mt9m001_video_remove(struct soc_camera_device *icd) -- cgit v1.2.3 From 0ac616e3dc8591b81ebfcb8a4d10b936c82fdeab Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2009 16:53:23 +0200 Subject: soc-camera: remove .gain and .exposure struct soc_camera_device members From: Guennadi Liakhovetski This makes the soc-camera interface for V4L2 subdevices thinner yet. Handle gain and exposure internally in each driver just like all other controls. Signed-off-by: Guennadi Liakhovetski Priority: low --- drivers/media/video/mt9m001.c | 43 ++++++++++++++++++++++++------------- drivers/media/video/mt9m111.c | 20 ++++++++++++++--- drivers/media/video/mt9t031.c | 37 +++++++++++++++++++++----------- drivers/media/video/mt9v022.c | 43 ++++++++++++++++++++++++++++--------- drivers/media/video/soc_camera.c | 19 ---------------- include/media/soc_camera.h | 2 - 6 files changed, 100 insertions(+), 64 deletions(-) --- linux/drivers/media/video/mt9m001.c | 43 ++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'linux/drivers/media/video/mt9m001.c') diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index 9da7789e6..93052047c 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -80,6 +80,8 @@ struct mt9m001 { struct v4l2_rect rect; /* Sensor window */ __u32 fourcc; int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ + unsigned int gain; + unsigned int exposure; unsigned char autoexposure; }; @@ -129,8 +131,8 @@ static int mt9m001_init(struct i2c_client *client) dev_dbg(&client->dev, "%s\n", __func__); /* - * We don't know, whether platform provides reset, - * issue a soft reset too + * We don't know, whether platform provides reset, issue a soft reset + * too. This returns all registers to their default values. */ ret = reg_write(client, MT9M001_RESET, 1); if (!ret) @@ -200,6 +202,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) struct soc_camera_device *icd = client->dev.platform_data; int ret; const u16 hblank = 9, vblank = 25; + unsigned int total_h; if (mt9m001->fourcc == V4L2_PIX_FMT_SBGGR8 || mt9m001->fourcc == V4L2_PIX_FMT_SBGGR16) @@ -219,6 +222,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) soc_camera_limit_side(&rect.top, &rect.height, MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); + total_h = rect.height + icd->y_skip_top + vblank; + /* Blanking and start values - default... */ ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); if (!ret) @@ -236,15 +241,13 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ret = reg_write(client, MT9M001_WINDOW_HEIGHT, rect.height + icd->y_skip_top - 1); if (!ret && mt9m001->autoexposure) { - ret = reg_write(client, MT9M001_SHUTTER_WIDTH, - rect.height + icd->y_skip_top + vblank); + ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); if (!ret) { const struct v4l2_queryctrl *qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); - icd->exposure = (524 + (rect.height + icd->y_skip_top + - vblank - 1) * - (qctrl->maximum - qctrl->minimum)) / + mt9m001->exposure = (524 + (total_h - 1) * + (qctrl->maximum - qctrl->minimum)) / 1048 + qctrl->minimum; } } @@ -457,6 +460,12 @@ static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) case V4L2_CID_EXPOSURE_AUTO: ctrl->value = mt9m001->autoexposure; break; + case V4L2_CID_GAIN: + ctrl->value = mt9m001->gain; + break; + case V4L2_CID_EXPOSURE: + ctrl->value = mt9m001->exposure; + break; } return 0; } @@ -518,7 +527,7 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) } /* Success */ - icd->gain = ctrl->value; + mt9m001->gain = ctrl->value; break; case V4L2_CID_EXPOSURE: /* mt9m001 has maximum == default */ @@ -535,21 +544,21 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) shutter); if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) return -EIO; - icd->exposure = ctrl->value; + mt9m001->exposure = ctrl->value; mt9m001->autoexposure = 0; } break; case V4L2_CID_EXPOSURE_AUTO: if (ctrl->value) { const u16 vblank = 25; + unsigned int total_h = mt9m001->rect.height + + icd->y_skip_top + vblank; if (reg_write(client, MT9M001_SHUTTER_WIDTH, - mt9m001->rect.height + - icd->y_skip_top + vblank) < 0) + total_h) < 0) return -EIO; qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); - icd->exposure = (524 + (mt9m001->rect.height + - icd->y_skip_top + vblank - 1) * - (qctrl->maximum - qctrl->minimum)) / + mt9m001->exposure = (524 + (total_h - 1) * + (qctrl->maximum - qctrl->minimum)) / 1048 + qctrl->minimum; mt9m001->autoexposure = 1; } else @@ -629,6 +638,10 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, if (ret < 0) dev_err(&client->dev, "Failed to initialise the camera\n"); + /* mt9m001_init() has reset the chip, returning registers to defaults */ + mt9m001->gain = 64; + mt9m001->exposure = 255; + return ret; } @@ -705,7 +718,7 @@ static int mt9m001_probe(struct i2c_client *client) /* Second stage probe - when a capture adapter is there */ icd->ops = &mt9m001_ops; - icd->y_skip_top = 1; + icd->y_skip_top = 0; mt9m001->rect.left = MT9M001_COLUMN_SKIP; mt9m001->rect.top = MT9M001_ROW_SKIP; -- cgit v1.2.3