aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/i2c/soc_camera/mt9m111.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/soc_camera/mt9m111.c')
-rw-r--r--drivers/media/i2c/soc_camera/mt9m111.c108
1 files changed, 50 insertions, 58 deletions
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c
index 62fd94af599..ccf59406a17 100644
--- a/drivers/media/i2c/soc_camera/mt9m111.c
+++ b/drivers/media/i2c/soc_camera/mt9m111.c
@@ -17,14 +17,15 @@
#include <linux/module.h>
#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
/*
* MT9M111, MT9M112 and MT9M131:
* i2c address is 0x48 or 0x5d (depending on SADDR pin)
- * The platform has to define i2c_board_info and call i2c_register_board_info()
+ * The platform has to define struct i2c_board_info objects and link to them
+ * from struct soc_camera_host_desc
*/
/*
@@ -204,12 +205,11 @@ struct mt9m111 {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *gain;
- int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
- * from v4l2-chip-ident.h */
struct mt9m111_context *ctx;
struct v4l2_rect rect; /* cropping rectangle */
- int width; /* output */
- int height; /* sizes */
+ struct v4l2_clk *clk;
+ unsigned int width; /* output */
+ unsigned int height; /* sizes */
struct mutex power_lock; /* lock to protect power_count */
int power_count;
const struct mt9m111_datafmt *fmt;
@@ -599,24 +599,6 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
return ret;
}
-static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = mt9m111->model;
- id->revision = 0;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9m111_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -624,10 +606,8 @@ static int mt9m111_g_register(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
int val;
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ if (reg->reg > 0x2ff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
val = mt9m111_reg_read(client, reg->reg);
reg->size = 2;
@@ -640,16 +620,13 @@ static int mt9m111_g_register(struct v4l2_subdev *sd,
}
static int mt9m111_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ if (reg->reg > 0x2ff)
return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
return -EIO;
@@ -700,11 +677,11 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
return reg_write(GLOBAL_GAIN, val);
}
-static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on)
+static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int val)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- if (on)
+ if (val == V4L2_EXPOSURE_AUTO)
return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
}
@@ -784,8 +761,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
int ret;
- /* Default HIGHPOWER context */
- mt9m111->ctx = &context_b;
ret = mt9m111_enable(mt9m111);
if (!ret)
ret = mt9m111_reset(mt9m111);
@@ -799,17 +774,17 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
static int mt9m111_power_on(struct mt9m111 *mt9m111)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- ret = soc_camera_power_on(&client->dev, icl);
+ ret = soc_camera_power_on(&client->dev, ssdd, mt9m111->clk);
if (ret < 0)
return ret;
ret = mt9m111_resume(mt9m111);
if (ret < 0) {
dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
- soc_camera_power_off(&client->dev, icl);
+ soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
}
return ret;
@@ -818,10 +793,10 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111)
static void mt9m111_power_off(struct mt9m111 *mt9m111)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
mt9m111_suspend(mt9m111);
- soc_camera_power_off(&client->dev, icl);
+ soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
}
static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
@@ -857,7 +832,6 @@ static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
};
static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
- .g_chip_ident = mt9m111_g_chip_ident,
.s_power = mt9m111_s_power,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9m111_g_register,
@@ -879,13 +853,13 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -924,12 +898,10 @@ static int mt9m111_video_probe(struct i2c_client *client)
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:
@@ -956,10 +928,10 @@ static int mt9m111_probe(struct i2c_client *client,
{
struct mt9m111 *mt9m111;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "mt9m111: driver needs platform data\n");
return -EINVAL;
}
@@ -970,10 +942,17 @@ static int mt9m111_probe(struct i2c_client *client,
return -EIO;
}
- mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL);
+ mt9m111 = devm_kzalloc(&client->dev, sizeof(struct mt9m111), GFP_KERNEL);
if (!mt9m111)
return -ENOMEM;
+ mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
+ if (IS_ERR(mt9m111->clk))
+ return -EPROBE_DEFER;
+
+ /* Default HIGHPOWER context */
+ mt9m111->ctx = &context_b;
+
v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
v4l2_ctrl_handler_init(&mt9m111->hdl, 5);
v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
@@ -989,10 +968,8 @@ static int mt9m111_probe(struct i2c_client *client,
V4L2_EXPOSURE_AUTO);
mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
if (mt9m111->hdl.error) {
- int err = mt9m111->hdl.error;
-
- kfree(mt9m111);
- return err;
+ ret = mt9m111->hdl.error;
+ goto out_clkput;
}
/* Second stage probe - when a capture adapter is there */
@@ -1004,11 +981,25 @@ static int mt9m111_probe(struct i2c_client *client,
mt9m111->lastpage = -1;
mutex_init(&mt9m111->power_lock);
+ ret = soc_camera_power_init(&client->dev, ssdd);
+ if (ret < 0)
+ goto out_hdlfree;
+
ret = mt9m111_video_probe(client);
- if (ret) {
- v4l2_ctrl_handler_free(&mt9m111->hdl);
- kfree(mt9m111);
- }
+ if (ret < 0)
+ goto out_hdlfree;
+
+ mt9m111->subdev.dev = &client->dev;
+ ret = v4l2_async_register_subdev(&mt9m111->subdev);
+ if (ret < 0)
+ goto out_hdlfree;
+
+ return 0;
+
+out_hdlfree:
+ v4l2_ctrl_handler_free(&mt9m111->hdl);
+out_clkput:
+ v4l2_clk_put(mt9m111->clk);
return ret;
}
@@ -1017,9 +1008,10 @@ static int mt9m111_remove(struct i2c_client *client)
{
struct mt9m111 *mt9m111 = to_mt9m111(client);
+ v4l2_async_unregister_subdev(&mt9m111->subdev);
+ v4l2_clk_put(mt9m111->clk);
v4l2_device_unregister_subdev(&mt9m111->subdev);
v4l2_ctrl_handler_free(&mt9m111->hdl);
- kfree(mt9m111);
return 0;
}