Commit 4bbc6d52 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[media] soc-camera: Push probe-time power management to drivers



Several client drivers access the hardware at probe time, for instance
to read the probe chip ID. Such chips need to be powered up when being
probed.

soc-camera handles this by powering chips up in the soc-camera probe
implementation. However, this will break with non soc-camera hosts that
don't perform the same operations.

Fix the problem by pushing the power up/down from the soc-camera core
down to individual drivers on a needs basis.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 4ec10bac
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -310,26 +310,33 @@ static struct v4l2_subdev_ops imx074_subdev_ops = {

static int imx074_video_probe(struct i2c_client *client)
{
	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
	int ret;
	u16 id;

	ret = imx074_s_power(subdev, 1);
	if (ret < 0)
		return ret;

	/* Read sensor Model ID */
	ret = reg_read(client, 0);
	if (ret < 0)
		return ret;
		goto done;

	id = ret << 8;

	ret = reg_read(client, 1);
	if (ret < 0)
		return ret;
		goto done;

	id |= ret;

	dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);

	if (id != 0x74)
		return -ENODEV;
	if (id != 0x74) {
		ret = -ENODEV;
		goto done;
	}

	/* PLL Setting EXTCLK=24MHz, 22.5times */
	reg_write(client, PLL_MULTIPLIER, 0x2D);
@@ -411,7 +418,11 @@ static int imx074_video_probe(struct i2c_client *client)

	reg_write(client, GROUPED_PARAMETER_HOLD, 0x00);	/* off */

	return 0;
	ret = 0;

done:
	imx074_s_power(subdev, 0);
	return ret;
}

static int imx074_probe(struct i2c_client *client,
+14 −3
Original line number Diff line number Diff line
@@ -490,6 +490,10 @@ static int mt9m001_video_probe(struct soc_camera_link *icl,
	unsigned long flags;
	int ret;

	ret = mt9m001_s_power(&mt9m001->subdev, 1);
	if (ret < 0)
		return ret;

	/* Enable the chip */
	data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
	dev_dbg(&client->dev, "write: %d\n", data);
@@ -511,7 +515,8 @@ static int mt9m001_video_probe(struct soc_camera_link *icl,
	default:
		dev_err(&client->dev,
			"No MT9M001 chip detected, register read %x\n", data);
		return -ENODEV;
		ret = -ENODEV;
		goto done;
	}

	mt9m001->num_fmts = 0;
@@ -540,11 +545,17 @@ static int mt9m001_video_probe(struct soc_camera_link *icl,
		 data == 0x8431 ? "C12STM" : "C12ST");

	ret = mt9m001_init(client);
	if (ret < 0)
	if (ret < 0) {
		dev_err(&client->dev, "Failed to initialise the camera\n");
		goto done;
	}

	/* mt9m001_init() has reset the chip, returning registers to defaults */
	return v4l2_ctrl_handler_setup(&mt9m001->hdl);
	ret = v4l2_ctrl_handler_setup(&mt9m001->hdl);

done:
	mt9m001_s_power(&mt9m001->subdev, 0);
	return ret;
}

static void mt9m001_video_remove(struct soc_camera_link *icl)
+45 −35
Original line number Diff line number Diff line
@@ -796,41 +796,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
	return ret;
}

/*
 * Interface active, can use i2c. If it fails, it can indeed mean, that
 * this wasn't our capture interface, so, we wait for the right one
 */
static int mt9m111_video_probe(struct i2c_client *client)
{
	struct mt9m111 *mt9m111 = to_mt9m111(client);
	s32 data;
	int ret;

	data = reg_read(CHIP_VERSION);

	switch (data) {
	case 0x143a: /* MT9M111 or MT9M131 */
		mt9m111->model = V4L2_IDENT_MT9M111;
		dev_info(&client->dev,
			"Detected a MT9M111/MT9M131 chip ID %x\n", data);
		break;
	case 0x148c: /* MT9M112 */
		mt9m111->model = V4L2_IDENT_MT9M112;
		dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
		break;
	default:
		dev_err(&client->dev,
			"No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
			data);
		return -ENODEV;
	}

	ret = mt9m111_init(mt9m111);
	if (ret)
		return ret;
	return v4l2_ctrl_handler_setup(&mt9m111->hdl);
}

static int mt9m111_power_on(struct mt9m111 *mt9m111)
{
	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
@@ -941,6 +906,51 @@ static struct v4l2_subdev_ops mt9m111_subdev_ops = {
	.video	= &mt9m111_subdev_video_ops,
};

/*
 * Interface active, can use i2c. If it fails, it can indeed mean, that
 * this wasn't our capture interface, so, we wait for the right one
 */
static int mt9m111_video_probe(struct i2c_client *client)
{
	struct mt9m111 *mt9m111 = to_mt9m111(client);
	s32 data;
	int ret;

	ret = mt9m111_s_power(&mt9m111->subdev, 1);
	if (ret < 0)
		return ret;

	data = reg_read(CHIP_VERSION);

	switch (data) {
	case 0x143a: /* MT9M111 or MT9M131 */
		mt9m111->model = V4L2_IDENT_MT9M111;
		dev_info(&client->dev,
			"Detected a MT9M111/MT9M131 chip ID %x\n", data);
		break;
	case 0x148c: /* MT9M112 */
		mt9m111->model = V4L2_IDENT_MT9M112;
		dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
		break;
	default:
		dev_err(&client->dev,
			"No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
			data);
		ret = -ENODEV;
		goto done;
	}

	ret = mt9m111_init(mt9m111);
	if (ret)
		goto done;

	ret = v4l2_ctrl_handler_setup(&mt9m111->hdl);

done:
	mt9m111_s_power(&mt9m111->subdev, 0);
	return ret;
}

static int mt9m111_probe(struct i2c_client *client,
			 const struct i2c_device_id *did)
{
+15 −22
Original line number Diff line number Diff line
@@ -161,14 +161,6 @@ static int mt9t031_idle(struct i2c_client *client)
	return ret >= 0 ? 0 : -EIO;
}

static int mt9t031_disable(struct i2c_client *client)
{
	/* Disable the chip */
	reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);

	return 0;
}

static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -643,9 +635,15 @@ static int mt9t031_video_probe(struct i2c_client *client)
	s32 data;
	int ret;

	/* Enable the chip */
	data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
	dev_dbg(&client->dev, "write: %d\n", data);
	ret = mt9t031_s_power(&mt9t031->subdev, 1);
	if (ret < 0)
		return ret;

	ret = mt9t031_idle(client);
	if (ret < 0) {
		dev_err(&client->dev, "Failed to initialise the camera\n");
		goto done;
	}

	/* Read out the chip version register */
	data = reg_read(client, MT9T031_CHIP_VERSION);
@@ -657,16 +655,16 @@ static int mt9t031_video_probe(struct i2c_client *client)
	default:
		dev_err(&client->dev,
			"No MT9T031 chip detected, register read %x\n", data);
		return -ENODEV;
		ret = -ENODEV;
		goto done;
	}

	dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);

	ret = mt9t031_idle(client);
	if (ret < 0)
		dev_err(&client->dev, "Failed to initialise the camera\n");
	else
		v4l2_ctrl_handler_setup(&mt9t031->hdl);
	ret = v4l2_ctrl_handler_setup(&mt9t031->hdl);

done:
	mt9t031_s_power(&mt9t031->subdev, 0);

	return ret;
}
@@ -817,12 +815,7 @@ static int mt9t031_probe(struct i2c_client *client,
	mt9t031->xskip = 1;
	mt9t031->yskip = 1;

	mt9t031_idle(client);

	ret = mt9t031_video_probe(client);

	mt9t031_disable(client);

	if (ret) {
		v4l2_ctrl_handler_free(&mt9t031->hdl);
		kfree(mt9t031);
+10 −2
Original line number Diff line number Diff line
@@ -1041,6 +1041,11 @@ static int mt9t112_camera_probe(struct i2c_client *client)
	struct mt9t112_priv *priv = to_mt9t112(client);
	const char          *devname;
	int                  chipid;
	int		     ret;

	ret = mt9t112_s_power(&priv->subdev, 1);
	if (ret < 0)
		return ret;

	/*
	 * check and show chip ID
@@ -1058,12 +1063,15 @@ static int mt9t112_camera_probe(struct i2c_client *client)
		break;
	default:
		dev_err(&client->dev, "Product ID error %04x\n", chipid);
		return -ENODEV;
		ret = -ENODEV;
		goto done;
	}

	dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid);

	return 0;
done:
	mt9t112_s_power(&priv->subdev, 0);
	return ret;
}

static int mt9t112_probe(struct i2c_client *client,
Loading