All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sakari Ailus <sakari.ailus@iki.fi>
To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: linux-media@vger.kernel.org, sakari.ailus@iki.fi,
	Martin Hostettler <martin@neutronstar.dyndns.org>
Subject: Re: [PATCH v4 5/5] v4l: Add driver for Micron MT9M032 camera sensor
Date: Fri, 09 Mar 2012 21:15:28 +0200	[thread overview]
Message-ID: <4F5A56D0.50803@iki.fi> (raw)
In-Reply-To: <1331305285-10781-6-git-send-email-laurent.pinchart@ideasonboard.com>

Hi Laurent,

Thanks for the patch. Just a few minor comments below.

Laurent Pinchart wrote:
...
> +static int mt9m032_setup_pll(struct mt9m032 *sensor)
> +{
> +	static const struct aptina_pll_limits limits = {
> +		.ext_clock_min = 8000000,
> +		.ext_clock_max = 16500000,
> +		.int_clock_min = 2000000,
> +		.int_clock_max = 24000000,
> +		.out_clock_min = 322000000,
> +		.out_clock_max = 693000000,
> +		.pix_clock_max = 99000000,
> +		.n_min = 1,
> +		.n_max = 64,
> +		.m_min = 16,
> +		.m_max = 255,
> +		.p1_min = 1,
> +		.p1_max = 128,
> +	};
> +
> +	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
> +	struct mt9m032_platform_data *pdata = sensor->pdata;
> +	struct aptina_pll pll;
> +	int ret;
> +
> +	pll.ext_clock = pdata->ext_clock;
> +	pll.pix_clock = pdata->pix_clock;
> +
> +	ret = aptina_pll_calculate(&client->dev, &limits, &pll);
> +	if (ret < 0)
> +		return ret;
> +
> +	sensor->pix_clock = pll.pix_clock;

I wouldn't expect aptina_pll_calculate() to change the supplied pixel
clock. I'd consider it a bug if it does that. So you could use the pixel
clock from platform data equally well.

> +	ret = mt9m032_write(client, MT9M032_PLL_CONFIG1,
> +			    (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT)
> +			    | (pll.p1 - 1));
> +	if (!ret)
> +		ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1);
> +	if (!ret)
> +		ret = mt9m032_write(client, MT9P031_PLL_CONTROL,
> +				    MT9P031_PLL_CONTROL_PWRON |
> +				    MT9P031_PLL_CONTROL_USEPLL);
> +	if (!ret)		/* more reserved, Continuous, Master Mode */
> +		ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006);
> +	if (!ret)		/* Set 14-bit mode, select 7 divider */
> +		ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e);
> +
> +	return ret;
> +}

...
> +static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
> +				  struct v4l2_subdev_fh *fh,
> +				  struct v4l2_subdev_format *fmt)
> +{
> +	struct mt9m032 *sensor = to_mt9m032(subdev);
> +	int ret;
> +
> +	mutex_lock(&sensor->lock);
> +
> +	if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> +		ret = -EBUSY;
> +		goto done;
> +	}
> +
> +	/* Scaling is not supported, the format is thus fixed. */
> +	ret = mt9m032_get_pad_format(subdev, fh, fmt);
> +
> +done:
> +	mutex_lock(&sensor->lock);
> +	return ret;
> +}
> +
> +static int mt9m032_get_crop(struct v4l2_subdev *subdev,
> +			    struct v4l2_subdev_fh *fh,
> +			    struct v4l2_subdev_crop *crop)
> +{
> +	struct mt9m032 *sensor = to_mt9m032(subdev);
> +
> +	mutex_lock(&sensor->lock);
> +	crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which);
> +	mutex_unlock(&sensor->lock);
> +
> +	return 0;
> +}

Shouldn't these two be renamed --- you've got "pad" in set/get fmt names
as well.

> +static int mt9m032_set_crop(struct v4l2_subdev *subdev,
> +			    struct v4l2_subdev_fh *fh,
> +			    struct v4l2_subdev_crop *crop)
> +{
> +	struct mt9m032 *sensor = to_mt9m032(subdev);
> +	struct v4l2_mbus_framefmt *format;
> +	struct v4l2_rect *__crop;
> +	struct v4l2_rect rect;
> +	int ret = 0;
> +
> +	mutex_lock(&sensor->lock);
> +
> +	if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> +		ret = -EBUSY;
> +		goto done;
> +	}
> +
> +	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
> +	 * pixels to ensure a GRBG Bayer pattern.
> +	 */
> +	rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN,
> +			  MT9M032_COLUMN_START_MAX);
> +	rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN,
> +			 MT9M032_ROW_START_MAX);
> +	rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN,
> +			   MT9M032_COLUMN_SIZE_MAX);
> +	rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN,
> +			    MT9M032_ROW_SIZE_MAX);
> +
> +	rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
> +	rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
> +
> +	__crop = __mt9m032_get_pad_crop(sensor, fh, crop->which);
> +
> +	if (rect.width != __crop->width || rect.height != __crop->height) {
> +		/* Reset the output image size if the crop rectangle size has
> +		 * been modified.
> +		 */
> +		format = __mt9m032_get_pad_format(sensor, fh, crop->which);
> +		format->width = rect.width;
> +		format->height = rect.height;
> +	}
> +
> +	*__crop = rect;
> +	crop->rect = rect;
> +
> +	if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
> +		ret = mt9m032_update_geom_timing(sensor);
> +
> +done:
> +	mutex_unlock(&sensor->lock);
> +	return ret;
> +}

...

> +static int mt9m032_probe(struct i2c_client *client,
> +			 const struct i2c_device_id *devid)
> +{
> +	struct i2c_adapter *adapter = client->adapter;
> +	struct mt9m032 *sensor;
> +	int chip_version;
> +	int ret;
> +
> +	if (!i2c_check_functionality(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)
> +		return -ENODEV;
> +
> +	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
> +	if (sensor == NULL)
> +		return -ENOMEM;
> +
> +	mutex_init(&sensor->lock);
> +
> +	sensor->pdata = client->dev.platform_data;
> +
> +	v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops);
> +	sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +
> +	chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION);
> +	if (chip_version != MT9M032_CHIP_VERSION_VALUE) {
> +		dev_err(&client->dev, "MT9M032 not detected, wrong version "
> +			"0x%04x\n", chip_version);
> +		ret = -ENODEV;
> +		goto free_sensor;
> +	}
> +
> +	dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n",
> +		 client->addr);
> +
> +	sensor->frame_interval.numerator = 1;
> +	sensor->frame_interval.denominator = 30;
> +
> +	sensor->crop.left = 416;
> +	sensor->crop.top = 360;
> +	sensor->crop.width = 640;
> +	sensor->crop.height = 480;

How was the situation with this? Shouldn't the default be no cropping?

> +	sensor->format.width = sensor->crop.width;
> +	sensor->format.height = sensor->crop.height;
> +	sensor->format.code = V4L2_MBUS_FMT_Y8_1X8;
> +	sensor->format.field = V4L2_FIELD_NONE;
> +	sensor->format.colorspace = V4L2_COLORSPACE_SRGB;
> +
> +	v4l2_ctrl_handler_init(&sensor->ctrls, 4);
> +
> +	v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
> +			  V4L2_CID_GAIN, 0, 127, 1, 64);
> +
> +	sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls,
> +					  &mt9m032_ctrl_ops,
> +					  V4L2_CID_HFLIP, 0, 1, 1, 0);
> +	sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls,
> +					  &mt9m032_ctrl_ops,
> +					  V4L2_CID_VFLIP, 0, 1, 1, 0);
> +
> +	v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
> +			  V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN,
> +			  MT9M032_SHUTTER_WIDTH_MAX, 1,
> +			  MT9M032_SHUTTER_WIDTH_DEF);
> +
> +	if (sensor->ctrls.error) {
> +		ret = sensor->ctrls.error;
> +		dev_err(&client->dev, "control initialization error %d\n", ret);
> +		goto free_ctrl;
> +	}
> +
> +	v4l2_ctrl_cluster(2, &sensor->hflip);
> +
> +	sensor->subdev.ctrl_handler = &sensor->ctrls;
> +	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
> +	ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0);
> +	if (ret < 0)
> +		goto free_ctrl;
> +
> +	ret = mt9m032_write(client, MT9M032_RESET, 1);	/* reset on */
> +	if (ret < 0)
> +		goto free_ctrl;

I think you should do media_entity_cleanup() if this or anything past
this fails.

> +	mt9m032_write(client, MT9M032_RESET, 0);	/* reset off */
> +	if (ret < 0)
> +		goto free_ctrl;
> +
> +	ret = mt9m032_setup_pll(sensor);
> +	if (ret < 0)
> +		goto free_ctrl;
> +	usleep_range(10000, 11000);
> +
> +	v4l2_ctrl_handler_setup(&sensor->ctrls);
> +
> +	/* SIZE */
> +	ret = mt9m032_update_geom_timing(sensor);
> +	if (ret < 0)
> +		goto free_ctrl;
> +
> +	ret = mt9m032_write(client, 0x41, 0x0000);	/* reserved !!! */
> +	if (ret < 0)
> +		goto free_ctrl;
> +	ret = mt9m032_write(client, 0x42, 0x0003);	/* reserved !!! */
> +	if (ret < 0)
> +		goto free_ctrl;
> +	ret = mt9m032_write(client, 0x43, 0x0003);	/* reserved !!! */
> +	if (ret < 0)
> +		goto free_ctrl;
> +	ret = mt9m032_write(client, 0x7f, 0x0000);	/* reserved !!! */
> +	if (ret < 0)
> +		goto free_ctrl;
> +	if (sensor->pdata->invert_pixclock) {
> +		ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL,
> +				    MT9M032_PIX_CLK_CTRL_INV_PIXCLK);
> +		if (ret < 0)
> +			goto free_ctrl;
> +	}
> +
> +	ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */
> +	if (ret < 0)
> +		goto free_ctrl;
> +	msleep(100);
> +	ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */
> +	if (ret < 0)
> +		goto free_ctrl;
> +	msleep(100);
> +	ret = update_formatter2(sensor, false);
> +	if (ret < 0)
> +		goto free_ctrl;
> +
> +	return ret;
> +
> +free_ctrl:
> +	v4l2_ctrl_handler_free(&sensor->ctrls);
> +
> +free_sensor:
> +	mutex_destroy(&sensor->lock);
> +	kfree(sensor);
> +	return ret;
> +}
> +
> +static int mt9m032_remove(struct i2c_client *client)
> +{
> +	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
> +	struct mt9m032 *sensor = to_mt9m032(subdev);
> +
> +	v4l2_device_unregister_subdev(&sensor->subdev);
> +	v4l2_ctrl_handler_free(&sensor->ctrls);
> +	media_entity_cleanup(&sensor->subdev.entity);
> +	mutex_destroy(&sensor->lock);
> +	kfree(sensor);
> +	return 0;
> +}

Kind regards,

-- 
Sakari Ailus
sakari.ailus@iki.fi

  reply	other threads:[~2012-03-09 19:15 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-09 15:01 [PATCH v4 0/5] MT9M032 and MT9P031 sensor patches Laurent Pinchart
2012-03-09 15:01 ` [PATCH v4 1/5] mt9p031: Remove duplicate media/v4l2-subdev.h include Laurent Pinchart
2012-03-09 15:01 ` [PATCH v4 2/5] mt9p031: Remove unused xskip and yskip fields in struct mt9p031 Laurent Pinchart
2012-03-09 15:01 ` [PATCH v4 3/5] v4l: Aptina-style sensor PLL support Laurent Pinchart
2012-03-09 15:01 ` [PATCH v4 4/5] mt9p031: Use generic PLL setup code Laurent Pinchart
2012-03-09 15:01 ` [PATCH v4 5/5] v4l: Add driver for Micron MT9M032 camera sensor Laurent Pinchart
2012-03-09 19:15   ` Sakari Ailus [this message]
2012-03-09 20:20     ` Laurent Pinchart
2012-03-11  1:55       ` Sakari Ailus
2012-03-09 20:21   ` [PATCH v5 1/1] " Laurent Pinchart
2012-03-09 21:30     ` Sylwester Nawrocki
2012-03-10 12:17       ` Laurent Pinchart
2012-03-10 14:13         ` Sylwester Nawrocki
2012-03-11 14:33     ` [PATCH v6] " Laurent Pinchart
2012-03-11 14:42       ` Sakari Ailus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F5A56D0.50803@iki.fi \
    --to=sakari.ailus@iki.fi \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-media@vger.kernel.org \
    --cc=martin@neutronstar.dyndns.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.