Commit 9aea470b authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab

[media] soc-camera: switch I2C subdevice drivers to use v4l2-clk

Instead of centrally enabling and disabling subdevice master clocks in
soc-camera core, let subdevice drivers do that themselves, using the
V4L2 clock API and soc-camera convenience wrappers.
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent e9e31049
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
/* IMX074 registers */ /* IMX074 registers */
...@@ -76,6 +77,7 @@ struct imx074_datafmt { ...@@ -76,6 +77,7 @@ struct imx074_datafmt {
struct imx074 { struct imx074 {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
const struct imx074_datafmt *fmt; const struct imx074_datafmt *fmt;
struct v4l2_clk *clk;
}; };
static const struct imx074_datafmt imx074_colour_fmts[] = { static const struct imx074_datafmt imx074_colour_fmts[] = {
...@@ -254,8 +256,9 @@ static int imx074_s_power(struct v4l2_subdev *sd, int on) ...@@ -254,8 +256,9 @@ static int imx074_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct imx074 *priv = to_imx074(client);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
} }
static int imx074_g_mbus_config(struct v4l2_subdev *sd, static int imx074_g_mbus_config(struct v4l2_subdev *sd,
...@@ -412,6 +415,7 @@ static int imx074_probe(struct i2c_client *client, ...@@ -412,6 +415,7 @@ static int imx074_probe(struct i2c_client *client,
struct imx074 *priv; struct imx074 *priv;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
if (!ssdd) { if (!ssdd) {
dev_err(&client->dev, "IMX074: missing platform data!\n"); dev_err(&client->dev, "IMX074: missing platform data!\n");
...@@ -432,13 +436,23 @@ static int imx074_probe(struct i2c_client *client, ...@@ -432,13 +436,23 @@ static int imx074_probe(struct i2c_client *client,
priv->fmt = &imx074_colour_fmts[0]; priv->fmt = &imx074_colour_fmts[0];
return imx074_video_probe(client); priv->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
ret = imx074_video_probe(client);
if (ret < 0)
v4l2_clk_put(priv->clk);
return ret;
} }
static int imx074_remove(struct i2c_client *client) static int imx074_remove(struct i2c_client *client)
{ {
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct imx074 *priv = to_imx074(client);
v4l2_clk_put(priv->clk);
if (ssdd->free_bus) if (ssdd->free_bus)
ssdd->free_bus(ssdd); ssdd->free_bus(ssdd);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/soc_mediabus.h> #include <media/soc_mediabus.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
...@@ -93,6 +94,7 @@ struct mt9m001 { ...@@ -93,6 +94,7 @@ struct mt9m001 {
struct v4l2_ctrl *exposure; struct v4l2_ctrl *exposure;
}; };
struct v4l2_rect rect; /* Sensor window */ struct v4l2_rect rect; /* Sensor window */
struct v4l2_clk *clk;
const struct mt9m001_datafmt *fmt; const struct mt9m001_datafmt *fmt;
const struct mt9m001_datafmt *fmts; const struct mt9m001_datafmt *fmts;
int num_fmts; int num_fmts;
...@@ -355,8 +357,9 @@ static int mt9m001_s_power(struct v4l2_subdev *sd, int on) ...@@ -355,8 +357,9 @@ static int mt9m001_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct mt9m001 *mt9m001 = to_mt9m001(client);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, mt9m001->clk, on);
} }
static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
...@@ -681,9 +684,18 @@ static int mt9m001_probe(struct i2c_client *client, ...@@ -681,9 +684,18 @@ static int mt9m001_probe(struct i2c_client *client,
mt9m001->rect.width = MT9M001_MAX_WIDTH; mt9m001->rect.width = MT9M001_MAX_WIDTH;
mt9m001->rect.height = MT9M001_MAX_HEIGHT; mt9m001->rect.height = MT9M001_MAX_HEIGHT;
mt9m001->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(mt9m001->clk)) {
ret = PTR_ERR(mt9m001->clk);
goto eclkget;
}
ret = mt9m001_video_probe(ssdd, client); ret = mt9m001_video_probe(ssdd, client);
if (ret) if (ret) {
v4l2_clk_put(mt9m001->clk);
eclkget:
v4l2_ctrl_handler_free(&mt9m001->hdl); v4l2_ctrl_handler_free(&mt9m001->hdl);
}
return ret; return ret;
} }
...@@ -693,6 +705,7 @@ static int mt9m001_remove(struct i2c_client *client) ...@@ -693,6 +705,7 @@ static int mt9m001_remove(struct i2c_client *client)
struct mt9m001 *mt9m001 = to_mt9m001(client); struct mt9m001 *mt9m001 = to_mt9m001(client);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
v4l2_clk_put(mt9m001->clk);
v4l2_device_unregister_subdev(&mt9m001->subdev); v4l2_device_unregister_subdev(&mt9m001->subdev);
v4l2_ctrl_handler_free(&mt9m001->hdl); v4l2_ctrl_handler_free(&mt9m001->hdl);
mt9m001_video_remove(ssdd); mt9m001_video_remove(ssdd);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
...@@ -206,6 +207,7 @@ struct mt9m111 { ...@@ -206,6 +207,7 @@ struct mt9m111 {
struct v4l2_ctrl *gain; struct v4l2_ctrl *gain;
struct mt9m111_context *ctx; struct mt9m111_context *ctx;
struct v4l2_rect rect; /* cropping rectangle */ struct v4l2_rect rect; /* cropping rectangle */
struct v4l2_clk *clk;
int width; /* output */ int width; /* output */
int height; /* sizes */ int height; /* sizes */
struct mutex power_lock; /* lock to protect power_count */ struct mutex power_lock; /* lock to protect power_count */
...@@ -775,14 +777,14 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) ...@@ -775,14 +777,14 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111)
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret; int ret;
ret = soc_camera_power_on(&client->dev, ssdd); ret = soc_camera_power_on(&client->dev, ssdd, mt9m111->clk);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = mt9m111_resume(mt9m111); ret = mt9m111_resume(mt9m111);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
soc_camera_power_off(&client->dev, ssdd); soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
} }
return ret; return ret;
...@@ -794,7 +796,7 @@ static void mt9m111_power_off(struct mt9m111 *mt9m111) ...@@ -794,7 +796,7 @@ static void mt9m111_power_off(struct mt9m111 *mt9m111)
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
mt9m111_suspend(mt9m111); mt9m111_suspend(mt9m111);
soc_camera_power_off(&client->dev, ssdd); soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
} }
static int mt9m111_s_power(struct v4l2_subdev *sd, int on) static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
...@@ -973,9 +975,18 @@ static int mt9m111_probe(struct i2c_client *client, ...@@ -973,9 +975,18 @@ static int mt9m111_probe(struct i2c_client *client,
mt9m111->lastpage = -1; mt9m111->lastpage = -1;
mutex_init(&mt9m111->power_lock); mutex_init(&mt9m111->power_lock);
mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(mt9m111->clk)) {
ret = PTR_ERR(mt9m111->clk);
goto eclkget;
}
ret = mt9m111_video_probe(client); ret = mt9m111_video_probe(client);
if (ret) if (ret) {
v4l2_clk_put(mt9m111->clk);
eclkget:
v4l2_ctrl_handler_free(&mt9m111->hdl); v4l2_ctrl_handler_free(&mt9m111->hdl);
}
return ret; return ret;
} }
...@@ -984,6 +995,7 @@ static int mt9m111_remove(struct i2c_client *client) ...@@ -984,6 +995,7 @@ static int mt9m111_remove(struct i2c_client *client)
{ {
struct mt9m111 *mt9m111 = to_mt9m111(client); struct mt9m111 *mt9m111 = to_mt9m111(client);
v4l2_clk_put(mt9m111->clk);
v4l2_device_unregister_subdev(&mt9m111->subdev); v4l2_device_unregister_subdev(&mt9m111->subdev);
v4l2_ctrl_handler_free(&mt9m111->hdl); v4l2_ctrl_handler_free(&mt9m111->hdl);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
...@@ -75,6 +76,7 @@ struct mt9t031 { ...@@ -75,6 +76,7 @@ struct mt9t031 {
struct v4l2_ctrl *exposure; struct v4l2_ctrl *exposure;
}; };
struct v4l2_rect rect; /* Sensor window */ struct v4l2_rect rect; /* Sensor window */
struct v4l2_clk *clk;
u16 xskip; u16 xskip;
u16 yskip; u16 yskip;
unsigned int total_h; unsigned int total_h;
...@@ -585,16 +587,17 @@ static int mt9t031_s_power(struct v4l2_subdev *sd, int on) ...@@ -585,16 +587,17 @@ static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct video_device *vdev = soc_camera_i2c_to_vdev(client); struct video_device *vdev = soc_camera_i2c_to_vdev(client);
struct mt9t031 *mt9t031 = to_mt9t031(client);
int ret; int ret;
if (on) { if (on) {
ret = soc_camera_power_on(&client->dev, ssdd); ret = soc_camera_power_on(&client->dev, ssdd, mt9t031->clk);
if (ret < 0) if (ret < 0)
return ret; return ret;
vdev->dev.type = &mt9t031_dev_type; vdev->dev.type = &mt9t031_dev_type;
} else { } else {
vdev->dev.type = NULL; vdev->dev.type = NULL;
soc_camera_power_off(&client->dev, ssdd); soc_camera_power_off(&client->dev, ssdd, mt9t031->clk);
} }
return 0; return 0;
...@@ -785,9 +788,18 @@ static int mt9t031_probe(struct i2c_client *client, ...@@ -785,9 +788,18 @@ static int mt9t031_probe(struct i2c_client *client,
mt9t031->xskip = 1; mt9t031->xskip = 1;
mt9t031->yskip = 1; mt9t031->yskip = 1;
mt9t031->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(mt9t031->clk)) {
ret = PTR_ERR(mt9t031->clk);
goto eclkget;
}
ret = mt9t031_video_probe(client); ret = mt9t031_video_probe(client);
if (ret) if (ret) {
v4l2_clk_put(mt9t031->clk);
eclkget:
v4l2_ctrl_handler_free(&mt9t031->hdl); v4l2_ctrl_handler_free(&mt9t031->hdl);
}
return ret; return ret;
} }
...@@ -796,6 +808,7 @@ static int mt9t031_remove(struct i2c_client *client) ...@@ -796,6 +808,7 @@ static int mt9t031_remove(struct i2c_client *client)
{ {
struct mt9t031 *mt9t031 = to_mt9t031(client); struct mt9t031 *mt9t031 = to_mt9t031(client);
v4l2_clk_put(mt9t031->clk);
v4l2_device_unregister_subdev(&mt9t031->subdev); v4l2_device_unregister_subdev(&mt9t031->subdev);
v4l2_ctrl_handler_free(&mt9t031->hdl); v4l2_ctrl_handler_free(&mt9t031->hdl);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <media/mt9t112.h> #include <media/mt9t112.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
/* you can check PLL/clock info */ /* you can check PLL/clock info */
...@@ -89,6 +90,7 @@ struct mt9t112_priv { ...@@ -89,6 +90,7 @@ struct mt9t112_priv {
struct mt9t112_camera_info *info; struct mt9t112_camera_info *info;
struct i2c_client *client; struct i2c_client *client;
struct v4l2_rect frame; struct v4l2_rect frame;
struct v4l2_clk *clk;
const struct mt9t112_format *format; const struct mt9t112_format *format;
int num_formats; int num_formats;
u32 flags; u32 flags;
...@@ -768,8 +770,9 @@ static int mt9t112_s_power(struct v4l2_subdev *sd, int on) ...@@ -768,8 +770,9 @@ static int mt9t112_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct mt9t112_priv *priv = to_mt9t112(client);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
} }
static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
...@@ -1092,16 +1095,29 @@ static int mt9t112_probe(struct i2c_client *client, ...@@ -1092,16 +1095,29 @@ static int mt9t112_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
priv->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
ret = mt9t112_camera_probe(client); ret = mt9t112_camera_probe(client);
if (ret)
return ret;
/* Cannot fail: using the default supported pixel code */ /* Cannot fail: using the default supported pixel code */
mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8); if (!ret)
mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
else
v4l2_clk_put(priv->clk);
return ret; return ret;
} }
static int mt9t112_remove(struct i2c_client *client)
{
struct mt9t112_priv *priv = to_mt9t112(client);
v4l2_clk_put(priv->clk);
return 0;
}
static const struct i2c_device_id mt9t112_id[] = { static const struct i2c_device_id mt9t112_id[] = {
{ "mt9t112", 0 }, { "mt9t112", 0 },
{ } { }
...@@ -1113,6 +1129,7 @@ static struct i2c_driver mt9t112_i2c_driver = { ...@@ -1113,6 +1129,7 @@ static struct i2c_driver mt9t112_i2c_driver = {
.name = "mt9t112", .name = "mt9t112",
}, },
.probe = mt9t112_probe, .probe = mt9t112_probe,
.remove = mt9t112_remove,
.id_table = mt9t112_id, .id_table = mt9t112_id,
}; };
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/soc_mediabus.h> #include <media/soc_mediabus.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
/* /*
...@@ -153,6 +154,7 @@ struct mt9v022 { ...@@ -153,6 +154,7 @@ struct mt9v022 {
struct v4l2_ctrl *hblank; struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank; struct v4l2_ctrl *vblank;
struct v4l2_rect rect; /* Sensor window */ struct v4l2_rect rect; /* Sensor window */
struct v4l2_clk *clk;
const struct mt9v022_datafmt *fmt; const struct mt9v022_datafmt *fmt;
const struct mt9v022_datafmt *fmts; const struct mt9v022_datafmt *fmts;
const struct mt9v02x_register *reg; const struct mt9v02x_register *reg;
...@@ -498,8 +500,9 @@ static int mt9v022_s_power(struct v4l2_subdev *sd, int on) ...@@ -498,8 +500,9 @@ static int mt9v022_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct mt9v022 *mt9v022 = to_mt9v022(client);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, mt9v022->clk, on);
} }
static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
...@@ -936,9 +939,18 @@ static int mt9v022_probe(struct i2c_client *client, ...@@ -936,9 +939,18 @@ static int mt9v022_probe(struct i2c_client *client,
mt9v022->rect.width = MT9V022_MAX_WIDTH; mt9v022->rect.width = MT9V022_MAX_WIDTH;
mt9v022->rect.height = MT9V022_MAX_HEIGHT; mt9v022->rect.height = MT9V022_MAX_HEIGHT;
mt9v022->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(mt9v022->clk)) {
ret = PTR_ERR(mt9v022->clk);
goto eclkget;
}
ret = mt9v022_video_probe(client); ret = mt9v022_video_probe(client);
if (ret) if (ret) {
v4l2_clk_put(mt9v022->clk);
eclkget:
v4l2_ctrl_handler_free(&mt9v022->hdl); v4l2_ctrl_handler_free(&mt9v022->hdl);
}
return ret; return ret;
} }
...@@ -948,6 +960,7 @@ static int mt9v022_remove(struct i2c_client *client) ...@@ -948,6 +960,7 @@ static int mt9v022_remove(struct i2c_client *client)
struct mt9v022 *mt9v022 = to_mt9v022(client); struct mt9v022 *mt9v022 = to_mt9v022(client);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
v4l2_clk_put(mt9v022->clk);
v4l2_device_unregister_subdev(&mt9v022->subdev); v4l2_device_unregister_subdev(&mt9v022->subdev);
if (ssdd->free_bus) if (ssdd->free_bus)
ssdd->free_bus(ssdd); ssdd->free_bus(ssdd);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
...@@ -302,6 +303,7 @@ struct ov2640_priv { ...@@ -302,6 +303,7 @@ struct ov2640_priv {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl; struct v4l2_ctrl_handler hdl;
enum v4l2_mbus_pixelcode cfmt_code; enum v4l2_mbus_pixelcode cfmt_code;
struct v4l2_clk *clk;
const struct ov2640_win_size *win; const struct ov2640_win_size *win;
}; };
...@@ -758,8 +760,9 @@ static int ov2640_s_power(struct v4l2_subdev *sd, int on) ...@@ -758,8 +760,9 @@ static int ov2640_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct ov2640_priv *priv = to_ov2640(client);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
} }
/* Select the nearest higher resolution for capture */ /* Select the nearest higher resolution for capture */
...@@ -1097,11 +1100,20 @@ static int ov2640_probe(struct i2c_client *client, ...@@ -1097,11 +1100,20 @@ static int ov2640_probe(struct i2c_client *client,
if (priv->hdl.error) if (priv->hdl.error)
return priv->hdl.error; return priv->hdl.error;
priv->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
goto eclkget;
}
ret = ov2640_video_probe(client); ret = ov2640_video_probe(client);
if (ret) if (ret) {
v4l2_clk_put(priv->clk);
eclkget:
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
else } else {
dev_info(&adapter->dev, "OV2640 Probed\n"); dev_info(&adapter->dev, "OV2640 Probed\n");
}
return ret; return ret;
} }
...@@ -1110,6 +1122,7 @@ static int ov2640_remove(struct i2c_client *client) ...@@ -1110,6 +1122,7 @@ static int ov2640_remove(struct i2c_client *client)
{ {
struct ov2640_priv *priv = to_ov2640(client); struct ov2640_priv *priv = to_ov2640(client);
v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev); v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
return 0; return 0;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/v4l2-mediabus.h> #include <linux/v4l2-mediabus.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
/* OV5642 registers */ /* OV5642 registers */
...@@ -609,6 +610,7 @@ struct ov5642 { ...@@ -609,6 +610,7 @@ struct ov5642 {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
const struct ov5642_datafmt *fmt; const struct ov5642_datafmt *fmt;
struct v4l2_rect crop_rect; struct v4l2_rect crop_rect;
struct v4l2_clk *clk;
/* blanking information */ /* blanking information */
int total_width; int total_width;
...@@ -917,12 +919,13 @@ static int ov5642_s_power(struct v4l2_subdev *sd, int on) ...@@ -917,12 +919,13 @@ static int ov5642_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct ov5642 *priv = to_ov5642(client);
int ret; int ret;
if (!on) if (!on)
return soc_camera_power_off(&client->dev, ssdd); return soc_camera_power_off(&client->dev, ssdd, priv->clk);
ret = soc_camera_power_on(&client->dev, ssdd); ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1002,6 +1005,7 @@ static int ov5642_probe(struct i2c_client *client, ...@@ -1002,6 +1005,7 @@ static int ov5642_probe(struct i2c_client *client,
{ {
struct ov5642 *priv; struct ov5642 *priv;
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
if (!ssdd) { if (!ssdd) {
dev_err(&client->dev, "OV5642: missing platform data!\n"); dev_err(&client->dev, "OV5642: missing platform data!\n");
...@@ -1023,13 +1027,23 @@ static int ov5642_probe(struct i2c_client *client, ...@@ -1023,13 +1027,23 @@ static int ov5642_probe(struct i2c_client *client,
priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH; priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
priv->total_height = BLANKING_MIN_HEIGHT; priv->total_height = BLANKING_MIN_HEIGHT;
return ov5642_video_probe(client); priv->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
ret = ov5642_video_probe(client);
if (ret < 0)
v4l2_clk_put(priv->clk);
return ret;
} }
static int ov5642_remove(struct i2c_client *client) static int ov5642_remove(struct i2c_client *client)
{ {
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct ov5642 *priv = to_ov5642(client);
v4l2_clk_put(priv->clk);
if (ssdd->free_bus) if (ssdd->free_bus)
ssdd->free_bus(ssdd); ssdd->free_bus(ssdd);
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
/* Register definitions */ /* Register definitions */
...@@ -195,6 +196,7 @@ struct ov6650 { ...@@ -195,6 +196,7 @@ struct ov6650 {
struct v4l2_ctrl *blue; struct v4l2_ctrl *blue;
struct v4l2_ctrl *red; struct v4l2_ctrl *red;
}; };
struct v4l2_clk *clk;
bool half_scale; /* scale down output by 2 */ bool half_scale; /* scale down output by 2 */
struct v4l2_rect rect; /* sensor cropping window */ struct v4l2_rect rect; /* sensor cropping window */
unsigned long pclk_limit; /* from host */ unsigned long pclk_limit; /* from host */
...@@ -425,8 +427,9 @@ static int ov6650_s_power(struct v4l2_subdev *sd, int on) ...@@ -425,8 +427,9 @@ static int ov6650_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct ov6650 *priv = to_ov6650(client);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
} }
static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
...@@ -1013,9 +1016,18 @@ static int ov6650_probe(struct i2c_client *client, ...@@ -1013,9 +1016,18 @@ static int ov6650_probe(struct i2c_client *client,
priv->code = V4L2_MBUS_FMT_YUYV8_2X8; priv->code = V4L2_MBUS_FMT_YUYV8_2X8;
priv->colorspace = V4L2_COLORSPACE_JPEG; priv->colorspace = V4L2_COLORSPACE_JPEG;
priv->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
goto eclkget;
}
ret = ov6650_video_probe(client); ret = ov6650_video_probe(client);
if (ret) if (ret) {
v4l2_clk_put(priv->clk);
eclkget:
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
}
return ret; return ret;
} }
...@@ -1024,6 +1036,7 @@ static int ov6650_remove(struct i2c_client *client) ...@@ -1024,6 +1036,7 @@ static int ov6650_remove(struct i2c_client *client)
{ {
struct ov6650 *priv = to_ov6650(client); struct ov6650 *priv = to_ov6650(client);
v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev); v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
return 0; return 0;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <media/ov772x.h> #include <media/ov772x.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
...@@ -395,6 +396,7 @@ struct ov772x_win_size { ...@@ -395,6 +396,7 @@ struct ov772x_win_size {
struct ov772x_priv { struct ov772x_priv {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl; struct v4l2_ctrl_handler hdl;
struct v4l2_clk *clk;
struct ov772x_camera_info *info; struct ov772x_camera_info *info;
const struct ov772x_color_format *cfmt; const struct ov772x_color_format *cfmt;
const struct ov772x_win_size *win; const struct ov772x_win_size *win;
...@@ -655,8 +657,9 @@ static int ov772x_s_power(struct v4l2_subdev *sd, int on) ...@@ -655,8 +657,9 @@ static int ov772x_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct ov772x_priv *priv = to_ov772x(sd);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
} }
static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
...@@ -1072,13 +1075,22 @@ static int ov772x_probe(struct i2c_client *client, ...@@ -1072,13 +1075,22 @@ static int ov772x_probe(struct i2c_client *client,
if (priv->hdl.error) if (priv->hdl.error)
return priv->hdl.error; return priv->hdl.error;
priv->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
goto eclkget;
}
ret = ov772x_video_probe(priv); ret = ov772x_video_probe(priv);
if (ret < 0) { if (ret < 0) {
v4l2_clk_put(priv->clk);
eclkget:
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
} else { } else {
priv->cfmt = &ov772x_cfmts[0]; priv->cfmt = &ov772x_cfmts[0];
priv->win = &ov772x_win_sizes[0]; priv->win = &ov772x_win_sizes[0];
} }
return ret; return ret;
} }
...@@ -1086,6 +1098,7 @@ static int ov772x_remove(struct i2c_client *client) ...@@ -1086,6 +1098,7 @@ static int ov772x_remove(struct i2c_client *client)
{ {
struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client)); struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev); v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
return 0; return 0;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
...@@ -324,8 +325,9 @@ static int ov9640_s_power(struct v4l2_subdev *sd, int on) ...@@ -324,8 +325,9 @@ static int ov9640_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct ov9640_priv *priv = to_ov9640_sensor(sd);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
} }
/* select nearest higher resolution for capture */ /* select nearest higher resolution for capture */
...@@ -700,10 +702,18 @@ static int ov9640_probe(struct i2c_client *client, ...@@ -700,10 +702,18 @@ static int ov9640_probe(struct i2c_client *client,
if (priv->hdl.error) if (priv->hdl.error)
return priv->hdl.error; return priv->hdl.error;
ret = ov9640_video_probe(client); priv->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
goto eclkget;
}
if (ret) ret = ov9640_video_probe(client);
if (ret) {
v4l2_clk_put(priv->clk);
eclkget:
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
}
return ret; return ret;
} }
...@@ -713,6 +723,7 @@ static int ov9640_remove(struct i2c_client *client) ...@@ -713,6 +723,7 @@ static int ov9640_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client); struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov9640_priv *priv = to_ov9640_sensor(sd); struct ov9640_priv *priv = to_ov9640_sensor(sd);
v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev); v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
return 0; return 0;
......
...@@ -199,6 +199,7 @@ struct ov9640_reg { ...@@ -199,6 +199,7 @@ struct ov9640_reg {
struct ov9640_priv { struct ov9640_priv {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl; struct v4l2_ctrl_handler hdl;
struct v4l2_clk *clk;
int model; int model;
int revision; int revision;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/v4l2-mediabus.h> #include <linux/v4l2-mediabus.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
#define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev)
...@@ -195,6 +196,7 @@ struct ov9740_reg { ...@@ -195,6 +196,7 @@ struct ov9740_reg {
struct ov9740_priv { struct ov9740_priv {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl; struct v4l2_ctrl_handler hdl;
struct v4l2_clk *clk;
u16 model; u16 model;
u8 revision; u8 revision;
...@@ -778,7 +780,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on) ...@@ -778,7 +780,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on)
int ret; int ret;
if (on) { if (on) {
ret = soc_camera_power_on(&client->dev, ssdd); ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -792,7 +794,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on) ...@@ -792,7 +794,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on)
priv->current_enable = true; priv->current_enable = true;
} }
soc_camera_power_off(&client->dev, ssdd); soc_camera_power_off(&client->dev, ssdd, priv->clk);
} }
return 0; return 0;
...@@ -958,9 +960,18 @@ static int ov9740_probe(struct i2c_client *client, ...@@ -958,9 +960,18 @@ static int ov9740_probe(struct i2c_client *client,
if (priv->hdl.error) if (priv->hdl.error)
return priv->hdl.error; return priv->hdl.error;
priv->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
goto eclkget;
}
ret = ov9740_video_probe(client); ret = ov9740_video_probe(client);
if (ret < 0) if (ret < 0) {
v4l2_clk_put(priv->clk);
eclkget:
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
}
return ret; return ret;
} }
...@@ -969,6 +980,7 @@ static int ov9740_remove(struct i2c_client *client) ...@@ -969,6 +980,7 @@ static int ov9740_remove(struct i2c_client *client)
{ {
struct ov9740_priv *priv = i2c_get_clientdata(client); struct ov9740_priv *priv = i2c_get_clientdata(client);
v4l2_clk_put(priv->clk);
v4l2_device_unregister_subdev(&priv->subdev); v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl); v4l2_ctrl_handler_free(&priv->hdl);
return 0; return 0;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <media/rj54n1cb0c.h> #include <media/rj54n1cb0c.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
...@@ -150,6 +151,7 @@ struct rj54n1_clock_div { ...@@ -150,6 +151,7 @@ struct rj54n1_clock_div {
struct rj54n1 { struct rj54n1 {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl; struct v4l2_ctrl_handler hdl;
struct v4l2_clk *clk;
struct rj54n1_clock_div clk_div; struct rj54n1_clock_div clk_div;
const struct rj54n1_datafmt *fmt; const struct rj54n1_datafmt *fmt;
struct v4l2_rect rect; /* Sensor window */ struct v4l2_rect rect; /* Sensor window */
...@@ -1158,8 +1160,9 @@ static int rj54n1_s_power(struct v4l2_subdev *sd, int on) ...@@ -1158,8 +1160,9 @@ static int rj54n1_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct rj54n1 *rj54n1 = to_rj54n1(client);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, rj54n1->clk, on);
} }
static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl) static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
...@@ -1355,9 +1358,18 @@ static int rj54n1_probe(struct i2c_client *client, ...@@ -1355,9 +1358,18 @@ static int rj54n1_probe(struct i2c_client *client,
rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
(clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
rj54n1->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(rj54n1->clk)) {
ret = PTR_ERR(rj54n1->clk);
goto eclkget;
}
ret = rj54n1_video_probe(client, rj54n1_priv); ret = rj54n1_video_probe(client, rj54n1_priv);
if (ret < 0) if (ret < 0) {
v4l2_clk_put(rj54n1->clk);
eclkget:
v4l2_ctrl_handler_free(&rj54n1->hdl); v4l2_ctrl_handler_free(&rj54n1->hdl);
}
return ret; return ret;
} }
...@@ -1367,6 +1379,7 @@ static int rj54n1_remove(struct i2c_client *client) ...@@ -1367,6 +1379,7 @@ static int rj54n1_remove(struct i2c_client *client)
struct rj54n1 *rj54n1 = to_rj54n1(client); struct rj54n1 *rj54n1 = to_rj54n1(client);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
v4l2_clk_put(rj54n1->clk);
v4l2_device_unregister_subdev(&rj54n1->subdev); v4l2_device_unregister_subdev(&rj54n1->subdev);
if (ssdd->free_bus) if (ssdd->free_bus)
ssdd->free_bus(ssdd); ssdd->free_bus(ssdd);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/tw9910.h> #include <media/tw9910.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
#define GET_ID(val) ((val & 0xF8) >> 3) #define GET_ID(val) ((val & 0xF8) >> 3)
...@@ -227,6 +228,7 @@ struct tw9910_scale_ctrl { ...@@ -227,6 +228,7 @@ struct tw9910_scale_ctrl {
struct tw9910_priv { struct tw9910_priv {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
struct v4l2_clk *clk;
struct tw9910_video_info *info; struct tw9910_video_info *info;
const struct tw9910_scale_ctrl *scale; const struct tw9910_scale_ctrl *scale;
v4l2_std_id norm; v4l2_std_id norm;
...@@ -558,8 +560,9 @@ static int tw9910_s_power(struct v4l2_subdev *sd, int on) ...@@ -558,8 +560,9 @@ static int tw9910_s_power(struct v4l2_subdev *sd, int on)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct tw9910_priv *priv = to_tw9910(client);
return soc_camera_set_power(&client->dev, ssdd, on); return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
} }
static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
...@@ -899,6 +902,7 @@ static int tw9910_probe(struct i2c_client *client, ...@@ -899,6 +902,7 @@ static int tw9910_probe(struct i2c_client *client,
struct i2c_adapter *adapter = struct i2c_adapter *adapter =
to_i2c_adapter(client->dev.parent); to_i2c_adapter(client->dev.parent);
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
if (!ssdd || !ssdd->drv_priv) { if (!ssdd || !ssdd->drv_priv) {
dev_err(&client->dev, "TW9910: missing platform data!\n"); dev_err(&client->dev, "TW9910: missing platform data!\n");
...@@ -922,7 +926,22 @@ static int tw9910_probe(struct i2c_client *client, ...@@ -922,7 +926,22 @@ static int tw9910_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
return tw9910_video_probe(client); priv->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
ret = tw9910_video_probe(client);
if (ret < 0)
v4l2_clk_put(priv->clk);
return ret;
}
static int tw9910_remove(struct i2c_client *client)
{
struct tw9910_priv *priv = to_tw9910(client);
v4l2_clk_put(priv->clk);
return 0;
} }
static const struct i2c_device_id tw9910_id[] = { static const struct i2c_device_id tw9910_id[] = {
...@@ -936,6 +955,7 @@ static struct i2c_driver tw9910_i2c_driver = { ...@@ -936,6 +955,7 @@ static struct i2c_driver tw9910_i2c_driver = {
.name = "tw9910", .name = "tw9910",
}, },
.probe = tw9910_probe, .probe = tw9910_probe,
.remove = tw9910_remove,
.id_table = tw9910_id, .id_table = tw9910_id,
}; };
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <media/soc_camera.h> #include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/v4l2-dev.h> #include <media/v4l2-dev.h>
...@@ -50,13 +51,19 @@ static LIST_HEAD(hosts); ...@@ -50,13 +51,19 @@ static LIST_HEAD(hosts);
static LIST_HEAD(devices); static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd) int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
struct v4l2_clk *clk)
{ {
int ret = regulator_bulk_enable(ssdd->num_regulators, int ret = clk ? v4l2_clk_enable(clk) : 0;
if (ret < 0) {
dev_err(dev, "Cannot enable clock\n");
return ret;
}
ret = regulator_bulk_enable(ssdd->num_regulators,
ssdd->regulators); ssdd->regulators);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Cannot enable regulators\n"); dev_err(dev, "Cannot enable regulators\n");
return ret; goto eregenable;;
} }
if (ssdd->power) { if (ssdd->power) {
...@@ -64,16 +71,25 @@ int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd) ...@@ -64,16 +71,25 @@ int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd)
if (ret < 0) { if (ret < 0) {
dev_err(dev, dev_err(dev,
"Platform failed to power-on the camera.\n"); "Platform failed to power-on the camera.\n");
regulator_bulk_disable(ssdd->num_regulators, goto epwron;
ssdd->regulators);
} }
} }
return 0;
epwron:
regulator_bulk_disable(ssdd->num_regulators,
ssdd->regulators);
eregenable:
if (clk)
v4l2_clk_disable(clk);
return ret; return ret;
} }
EXPORT_SYMBOL(soc_camera_power_on); EXPORT_SYMBOL(soc_camera_power_on);
int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd) int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd,
struct v4l2_clk *clk)
{ {
int ret = 0; int ret = 0;
int err; int err;
...@@ -94,6 +110,9 @@ int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd ...@@ -94,6 +110,9 @@ int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd
ret = ret ? : err; ret = ret ? : err;
} }
if (clk)
v4l2_clk_disable(clk);
return ret; return ret;
} }
EXPORT_SYMBOL(soc_camera_power_off); EXPORT_SYMBOL(soc_camera_power_off);
...@@ -512,9 +531,11 @@ static int soc_camera_add_device(struct soc_camera_device *icd) ...@@ -512,9 +531,11 @@ static int soc_camera_add_device(struct soc_camera_device *icd)
if (ici->icd) if (ici->icd)
return -EBUSY; return -EBUSY;
ret = ici->ops->clock_start(ici); if (!icd->clk) {
if (ret < 0) ret = ici->ops->clock_start(ici);
return ret; if (ret < 0)
return ret;
}
if (ici->ops->add) { if (ici->ops->add) {
ret = ici->ops->add(icd); ret = ici->ops->add(icd);
...@@ -527,7 +548,8 @@ static int soc_camera_add_device(struct soc_camera_device *icd) ...@@ -527,7 +548,8 @@ static int soc_camera_add_device(struct soc_camera_device *icd)
return 0; return 0;
eadd: eadd:
ici->ops->clock_stop(ici); if (!icd->clk)
ici->ops->clock_stop(ici);
return ret; return ret;
} }
...@@ -540,7 +562,8 @@ static void soc_camera_remove_device(struct soc_camera_device *icd) ...@@ -540,7 +562,8 @@ static void soc_camera_remove_device(struct soc_camera_device *icd)
if (ici->ops->remove) if (ici->ops->remove)
ici->ops->remove(icd); ici->ops->remove(icd);
ici->ops->clock_stop(ici); if (!icd->clk)
ici->ops->clock_stop(ici);
ici->icd = NULL; ici->icd = NULL;
} }
...@@ -1094,6 +1117,57 @@ static void scan_add_host(struct soc_camera_host *ici) ...@@ -1094,6 +1117,57 @@ static void scan_add_host(struct soc_camera_host *ici)
mutex_unlock(&list_lock); mutex_unlock(&list_lock);
} }
/*
* It is invalid to call v4l2_clk_enable() after a successful probing
* asynchronously outside of V4L2 operations, i.e. with .host_lock not held.
*/
static int soc_camera_clk_enable(struct v4l2_clk *clk)
{
struct soc_camera_device *icd = clk->priv;
struct soc_camera_host *ici;
if (!icd || !icd->parent)
return -ENODEV;
ici = to_soc_camera_host(icd->parent);
if (!try_module_get(ici->ops->owner))
return -ENODEV;
/*
* If a different client is currently being probed, the host will tell
* you to go
*/
return ici->ops->clock_start(ici);
}
static void soc_camera_clk_disable(struct v4l2_clk *clk)
{
struct soc_camera_device *icd = clk->priv;
struct soc_camera_host *ici;
if (!icd || !icd->parent)
return;
ici = to_soc_camera_host(icd->parent);
ici->ops->clock_stop(ici);
module_put(ici->ops->owner);
}
/*
* Eventually, it would be more logical to make the respective host the clock
* owner, but then we would have to copy this struct for each ici. Besides, it
* would introduce the circular dependency problem, unless we port all client
* drivers to release the clock, when not in use.
*/
static const struct v4l2_clk_ops soc_camera_clk_ops = {
.owner = THIS_MODULE,
.enable = soc_camera_clk_enable,
.disable = soc_camera_clk_disable,
};
#ifdef CONFIG_I2C_BOARDINFO #ifdef CONFIG_I2C_BOARDINFO
static int soc_camera_init_i2c(struct soc_camera_device *icd, static int soc_camera_init_i2c(struct soc_camera_device *icd,
struct soc_camera_desc *sdesc) struct soc_camera_desc *sdesc)
...@@ -1103,19 +1177,32 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, ...@@ -1103,19 +1177,32 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
struct soc_camera_host_desc *shd = &sdesc->host_desc; struct soc_camera_host_desc *shd = &sdesc->host_desc;
struct i2c_adapter *adap = i2c_get_adapter(shd->i2c_adapter_id); struct i2c_adapter *adap = i2c_get_adapter(shd->i2c_adapter_id);
struct v4l2_subdev *subdev; struct v4l2_subdev *subdev;
char clk_name[V4L2_SUBDEV_NAME_SIZE];
int ret;
if (!adap) { if (!adap) {
dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n", dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
shd->i2c_adapter_id); shd->i2c_adapter_id);
goto ei2cga; return -ENODEV;
} }
shd->board_info->platform_data = &sdesc->subdev_desc; shd->board_info->platform_data = &sdesc->subdev_desc;
snprintf(clk_name, sizeof(clk_name), "%d-%04x",
shd->i2c_adapter_id, shd->board_info->addr);
icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
if (IS_ERR(icd->clk)) {
ret = PTR_ERR(icd->clk);
goto eclkreg;
}
subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
shd->board_info, NULL); shd->board_info, NULL);
if (!subdev) if (!subdev) {
ret = -ENODEV;
goto ei2cnd; goto ei2cnd;
}
client = v4l2_get_subdevdata(subdev); client = v4l2_get_subdevdata(subdev);
...@@ -1124,9 +1211,11 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, ...@@ -1124,9 +1211,11 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
return 0; return 0;
ei2cnd: ei2cnd:
v4l2_clk_unregister(icd->clk);
icd->clk = NULL;
eclkreg:
i2c_put_adapter(adap); i2c_put_adapter(adap);
ei2cga: return ret;
return -ENODEV;
} }
static void soc_camera_free_i2c(struct soc_camera_device *icd) static void soc_camera_free_i2c(struct soc_camera_device *icd)
...@@ -1139,6 +1228,8 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd) ...@@ -1139,6 +1228,8 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd)
v4l2_device_unregister_subdev(i2c_get_clientdata(client)); v4l2_device_unregister_subdev(i2c_get_clientdata(client));
i2c_unregister_device(client); i2c_unregister_device(client);
i2c_put_adapter(adap); i2c_put_adapter(adap);
v4l2_clk_unregister(icd->clk);
icd->clk = NULL;
} }
#else #else
#define soc_camera_init_i2c(icd, sdesc) (-ENODEV) #define soc_camera_init_i2c(icd, sdesc) (-ENODEV)
...@@ -1176,26 +1267,31 @@ static int soc_camera_probe(struct soc_camera_device *icd) ...@@ -1176,26 +1267,31 @@ static int soc_camera_probe(struct soc_camera_device *icd)
if (ssdd->reset) if (ssdd->reset)
ssdd->reset(icd->pdev); ssdd->reset(icd->pdev);
mutex_lock(&ici->host_lock);
ret = ici->ops->clock_start(ici);
mutex_unlock(&ici->host_lock);
if (ret < 0)
goto eadd;
/* Must have icd->vdev before registering the device */ /* Must have icd->vdev before registering the device */
ret = video_dev_create(icd); ret = video_dev_create(icd);
if (ret < 0) if (ret < 0)
goto evdc; goto evdc;
/*
* ..._video_start() will create a device node, video_register_device()
* itself is protected against concurrent open() calls, but we also have
* to protect our data also during client probing.
*/
mutex_lock(&ici->host_lock);
/* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */ /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
if (shd->board_info) { if (shd->board_info) {
ret = soc_camera_init_i2c(icd, sdesc); ret = soc_camera_init_i2c(icd, sdesc);
if (ret < 0) if (ret < 0)
goto eadddev; goto eadd;
} else if (!shd->add_device || !shd->del_device) { } else if (!shd->add_device || !shd->del_device) {
ret = -EINVAL; ret = -EINVAL;
goto eadddev; goto eadd;
} else { } else {
ret = ici->ops->clock_start(ici);
if (ret < 0)
goto eadd;
if (shd->module_name) if (shd->module_name)
ret = request_module(shd->module_name); ret = request_module(shd->module_name);
...@@ -1231,13 +1327,6 @@ static int soc_camera_probe(struct soc_camera_device *icd) ...@@ -1231,13 +1327,6 @@ static int soc_camera_probe(struct soc_camera_device *icd)
icd->field = V4L2_FIELD_ANY; icd->field = V4L2_FIELD_ANY;
/*
* ..._video_start() will create a device node, video_register_device()
* itself is protected against concurrent open() calls, but we also have
* to protect our data.
*/
mutex_lock(&ici->host_lock);
ret = soc_camera_video_start(icd); ret = soc_camera_video_start(icd);
if (ret < 0) if (ret < 0)
goto evidstart; goto evidstart;
...@@ -1250,14 +1339,14 @@ static int soc_camera_probe(struct soc_camera_device *icd) ...@@ -1250,14 +1339,14 @@ static int soc_camera_probe(struct soc_camera_device *icd)
icd->field = mf.field; icd->field = mf.field;
} }
ici->ops->clock_stop(ici); if (!shd->board_info)
ici->ops->clock_stop(ici);
mutex_unlock(&ici->host_lock); mutex_unlock(&ici->host_lock);
return 0; return 0;
evidstart: evidstart:
mutex_unlock(&ici->host_lock);
soc_camera_free_user_formats(icd); soc_camera_free_user_formats(icd);
eiufmt: eiufmt:
ectrl: ectrl:
...@@ -1266,16 +1355,15 @@ static int soc_camera_probe(struct soc_camera_device *icd) ...@@ -1266,16 +1355,15 @@ static int soc_camera_probe(struct soc_camera_device *icd)
} else { } else {
shd->del_device(icd); shd->del_device(icd);
module_put(control->driver->owner); module_put(control->driver->owner);
}
enodrv: enodrv:
eadddev: eadddev:
ici->ops->clock_stop(ici);
}
eadd:
video_device_release(icd->vdev); video_device_release(icd->vdev);
icd->vdev = NULL; icd->vdev = NULL;
evdc:
mutex_lock(&ici->host_lock);
ici->ops->clock_stop(ici);
mutex_unlock(&ici->host_lock); mutex_unlock(&ici->host_lock);
eadd: evdc:
v4l2_ctrl_handler_free(&icd->ctrl_handler); v4l2_ctrl_handler_free(&icd->ctrl_handler);
return ret; return ret;
} }
......
...@@ -54,7 +54,7 @@ static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on) ...@@ -54,7 +54,7 @@ static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on)
{ {
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, on); return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, NULL, on);
} }
static struct v4l2_subdev_core_ops platform_subdev_core_ops = { static struct v4l2_subdev_core_ops platform_subdev_core_ops = {
......
...@@ -49,6 +49,7 @@ struct soc_camera_device { ...@@ -49,6 +49,7 @@ struct soc_camera_device {
/* soc_camera.c private count. Only accessed with .host_lock held */ /* soc_camera.c private count. Only accessed with .host_lock held */
int use_count; int use_count;
struct file *streamer; /* stream owner */ struct file *streamer; /* stream owner */
struct v4l2_clk *clk;
union { union {
struct videobuf_queue vb_vidq; struct videobuf_queue vb_vidq;
struct vb2_queue vb2_vidq; struct vb2_queue vb2_vidq;
...@@ -325,14 +326,16 @@ static inline void soc_camera_limit_side(int *start, int *length, ...@@ -325,14 +326,16 @@ static inline void soc_camera_limit_side(int *start, int *length,
unsigned long soc_camera_apply_board_flags(struct soc_camera_subdev_desc *ssdd, unsigned long soc_camera_apply_board_flags(struct soc_camera_subdev_desc *ssdd,
const struct v4l2_mbus_config *cfg); const struct v4l2_mbus_config *cfg);
int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd); int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd); struct v4l2_clk *clk);
int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd,
struct v4l2_clk *clk);
static inline int soc_camera_set_power(struct device *dev, static inline int soc_camera_set_power(struct device *dev,
struct soc_camera_subdev_desc *ssdd, bool on) struct soc_camera_subdev_desc *ssdd, struct v4l2_clk *clk, bool on)
{ {
return on ? soc_camera_power_on(dev, ssdd) return on ? soc_camera_power_on(dev, ssdd, clk)
: soc_camera_power_off(dev, ssdd); : soc_camera_power_off(dev, ssdd, clk);
} }
/* This is only temporary here - until v4l2-subdev begins to link to video_device */ /* This is only temporary here - until v4l2-subdev begins to link to video_device */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment