Skip to content

Commit

Permalink
[media] soc-camera: Push probe-time power management to drivers
Browse files Browse the repository at this point in the history
Several client drivers access the hardware at probe time, for instance
to read the probe chip ID. Such chips need to be powered up when being
probed.

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

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

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Laurent Pinchart authored and Mauro Carvalho Chehab committed Aug 15, 2012
1 parent 4ec10ba commit 4bbc6d5
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 123 deletions.
21 changes: 16 additions & 5 deletions drivers/media/i2c/soc_camera/imx074.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
17 changes: 14 additions & 3 deletions drivers/media/i2c/soc_camera/mt9m001.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
80 changes: 45 additions & 35 deletions drivers/media/i2c/soc_camera/mt9m111.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down
37 changes: 15 additions & 22 deletions drivers/media/i2c/soc_camera/mt9t031.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 10 additions & 2 deletions drivers/media/i2c/soc_camera/mt9t112.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions drivers/media/i2c/soc_camera/mt9v022.c
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,10 @@ static int mt9v022_video_probe(struct i2c_client *client)
int ret;
unsigned long flags;

ret = mt9v022_s_power(&mt9v022->subdev, 1);
if (ret < 0)
return ret;

/* Read out the chip version register */
data = reg_read(client, MT9V022_CHIP_VERSION);

Expand Down Expand Up @@ -648,6 +652,7 @@ static int mt9v022_video_probe(struct i2c_client *client)
dev_err(&client->dev, "Failed to initialise the camera\n");

ei2c:
mt9v022_s_power(&mt9v022->subdev, 0);
return ret;
}

Expand Down
11 changes: 8 additions & 3 deletions drivers/media/i2c/soc_camera/ov2640.c
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,10 @@ static int ov2640_video_probe(struct i2c_client *client)
const char *devname;
int ret;

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

/*
* check and show product ID and manufacturer ID
*/
Expand All @@ -973,16 +977,17 @@ static int ov2640_video_probe(struct i2c_client *client)
dev_err(&client->dev,
"Product ID error %x:%x\n", pid, ver);
ret = -ENODEV;
goto err;
goto done;
}

dev_info(&client->dev,
"%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
devname, pid, ver, midh, midl);

return v4l2_ctrl_handler_setup(&priv->hdl);
ret = v4l2_ctrl_handler_setup(&priv->hdl);

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

Expand Down
21 changes: 16 additions & 5 deletions drivers/media/i2c/soc_camera/ov5642.c
Original file line number Diff line number Diff line change
Expand Up @@ -980,29 +980,40 @@ static struct v4l2_subdev_ops ov5642_subdev_ops = {

static int ov5642_video_probe(struct i2c_client *client)
{
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
int ret;
u8 id_high, id_low;
u16 id;

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

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

id = id_high << 8;

ret = reg_read(client, REG_CHIP_ID_LOW, &id_low);
if (ret < 0)
return ret;
goto done;

id |= id_low;

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

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

return 0;
ret = 0;

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

static int ov5642_probe(struct i2c_client *client,
Expand Down
Loading

0 comments on commit 4bbc6d5

Please sign in to comment.