summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/mt9v032.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/mt9v032.c')
-rw-r--r--drivers/media/i2c/mt9v032.c115
1 files changed, 92 insertions, 23 deletions
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index bd3f979a4d49..977f4006edbd 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -17,6 +17,8 @@
#include <linux/i2c.h>
#include <linux/log2.h>
#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
@@ -26,6 +28,7 @@
#include <media/mt9v032.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
#include <media/v4l2-subdev.h>
/* The first four rows are black rows. The active area spans 753x481 pixels. */
@@ -371,12 +374,12 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
*/
static struct v4l2_mbus_framefmt *
-__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(fh, pad);
+ return v4l2_subdev_get_try_format(&mt9v032->subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v032->format;
default:
@@ -385,12 +388,12 @@ __mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
}
static struct v4l2_rect *
-__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(fh, pad);
+ return v4l2_subdev_get_try_crop(&mt9v032->subdev, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v032->crop;
default:
@@ -448,7 +451,7 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
}
static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -459,7 +462,7 @@ static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= 3 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
@@ -474,12 +477,12 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
}
static int mt9v032_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
- format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ format->format = *__mt9v032_get_pad_format(mt9v032, cfg, format->pad,
format->which);
return 0;
}
@@ -509,7 +512,7 @@ static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output)
}
static int mt9v032_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -520,7 +523,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
unsigned int hratio;
unsigned int vratio;
- __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad,
+ __crop = __mt9v032_get_pad_crop(mt9v032, cfg, format->pad,
format->which);
/* Clamp the width and height to avoid dividing by zero. */
@@ -536,7 +539,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
hratio = mt9v032_calc_ratio(__crop->width, width);
vratio = mt9v032_calc_ratio(__crop->height, height);
- __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ __format = __mt9v032_get_pad_format(mt9v032, cfg, format->pad,
format->which);
__format->width = __crop->width / hratio;
__format->height = __crop->height / vratio;
@@ -553,7 +556,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
}
static int mt9v032_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -561,12 +564,12 @@ static int mt9v032_get_selection(struct v4l2_subdev *subdev,
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- sel->r = *__mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which);
+ sel->r = *__mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
return 0;
}
static int mt9v032_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -598,13 +601,13 @@ static int mt9v032_set_selection(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int,
rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which);
+ __crop = __mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9v032_get_pad_format(mt9v032, fh, sel->pad,
+ __format = __mt9v032_get_pad_format(mt9v032, cfg, sel->pad,
sel->which);
__format->width = rect.width;
__format->height = rect.height;
@@ -810,13 +813,13 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_try_crop(fh, 0);
+ crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
crop->left = MT9V032_COLUMN_START_DEF;
crop->top = MT9V032_ROW_START_DEF;
crop->width = MT9V032_WINDOW_WIDTH_DEF;
crop->height = MT9V032_WINDOW_HEIGHT_DEF;
- format = v4l2_subdev_get_try_format(fh, 0);
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
if (mt9v032->model->color)
format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
@@ -876,10 +879,58 @@ static const struct regmap_config mt9v032_regmap_config = {
* Driver initialization and probing
*/
+static struct mt9v032_platform_data *
+mt9v032_get_pdata(struct i2c_client *client)
+{
+ struct mt9v032_platform_data *pdata;
+ struct v4l2_of_endpoint endpoint;
+ struct device_node *np;
+ struct property *prop;
+
+ if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
+ return client->dev.platform_data;
+
+ np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
+ if (!np)
+ return NULL;
+
+ if (v4l2_of_parse_endpoint(np, &endpoint) < 0)
+ goto done;
+
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ goto done;
+
+ prop = of_find_property(np, "link-frequencies", NULL);
+ if (prop) {
+ u64 *link_freqs;
+ size_t size = prop->length / sizeof(*link_freqs);
+
+ link_freqs = devm_kcalloc(&client->dev, size,
+ sizeof(*link_freqs), GFP_KERNEL);
+ if (!link_freqs)
+ goto done;
+
+ if (of_property_read_u64_array(np, "link-frequencies",
+ link_freqs, size) < 0)
+ goto done;
+
+ pdata->link_freqs = link_freqs;
+ pdata->link_def_freq = link_freqs[0];
+ }
+
+ pdata->clk_pol = !!(endpoint.bus.parallel.flags &
+ V4L2_MBUS_PCLK_SAMPLE_RISING);
+
+done:
+ of_node_put(np);
+ return pdata;
+}
+
static int mt9v032_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
- struct mt9v032_platform_data *pdata = client->dev.platform_data;
+ struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client);
struct mt9v032 *mt9v032;
unsigned int i;
int ret;
@@ -961,9 +1012,12 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->subdev.ctrl_handler = &mt9v032->ctrls;
- if (mt9v032->ctrls.error)
- printk(KERN_INFO "%s: control initialization error %d\n",
- __func__, mt9v032->ctrls.error);
+ if (mt9v032->ctrls.error) {
+ dev_err(&client->dev, "control initialization error %d\n",
+ mt9v032->ctrls.error);
+ ret = mt9v032->ctrls.error;
+ goto err;
+ }
mt9v032->crop.left = MT9V032_COLUMN_START_DEF;
mt9v032->crop.top = MT9V032_ROW_START_DEF;
@@ -1016,7 +1070,6 @@ static int mt9v032_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(subdev);
v4l2_ctrl_handler_free(&mt9v032->ctrls);
- v4l2_device_unregister_subdev(subdev);
media_entity_cleanup(&subdev->entity);
return 0;
@@ -1035,9 +1088,25 @@ static const struct i2c_device_id mt9v032_id[] = {
};
MODULE_DEVICE_TABLE(i2c, mt9v032_id);
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id mt9v032_of_match[] = {
+ { .compatible = "aptina,mt9v022" },
+ { .compatible = "aptina,mt9v022m" },
+ { .compatible = "aptina,mt9v024" },
+ { .compatible = "aptina,mt9v024m" },
+ { .compatible = "aptina,mt9v032" },
+ { .compatible = "aptina,mt9v032m" },
+ { .compatible = "aptina,mt9v034" },
+ { .compatible = "aptina,mt9v034m" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt9v032_of_match);
+#endif
+
static struct i2c_driver mt9v032_driver = {
.driver = {
.name = "mt9v032",
+ .of_match_table = of_match_ptr(mt9v032_of_match),
},
.probe = mt9v032_probe,
.remove = mt9v032_remove,