All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 01/17] v4l: Introduce integer menu controls
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
@ 2011-12-20 20:27 ` Sakari Ailus
  2012-01-05 15:53   ` Laurent Pinchart
  2011-12-20 20:27 ` [RFC 02/17] v4l: Document " Sakari Ailus
                   ` (16 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:27 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Create a new control type called V4L2_CTRL_TYPE_INTEGER_MENU. Integer menu
controls are just like menu controls but the menu items are 64-bit integers
rather than strings.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/media/video/v4l2-ctrls.c |   60 +++++++++++++++++++++++++++----------
 include/linux/videodev2.h        |    6 +++-
 include/media/v4l2-ctrls.h       |    6 +++-
 3 files changed, 54 insertions(+), 18 deletions(-)

diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 0f415da..083bb79 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -804,7 +804,8 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change
 		ev->u.ctrl.value64 = ctrl->cur.val64;
 	ev->u.ctrl.minimum = ctrl->minimum;
 	ev->u.ctrl.maximum = ctrl->maximum;
-	if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+	if (ctrl->type == V4L2_CTRL_TYPE_MENU
+	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
 		ev->u.ctrl.step = 1;
 	else
 		ev->u.ctrl.step = ctrl->step;
@@ -1035,10 +1036,13 @@ static int validate_new_int(const struct v4l2_ctrl *ctrl, s32 *pval)
 		return 0;
 
 	case V4L2_CTRL_TYPE_MENU:
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
 		if (val < ctrl->minimum || val > ctrl->maximum)
 			return -ERANGE;
-		if (ctrl->qmenu[val][0] == '\0' ||
-		    (ctrl->menu_skip_mask & (1 << val)))
+		if (ctrl->menu_skip_mask & (1 << val))
+			return -EINVAL;
+		if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
+		    ctrl->qmenu[val][0] == '\0')
 			return -EINVAL;
 		return 0;
 
@@ -1295,7 +1299,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
 			u32 id, const char *name, enum v4l2_ctrl_type type,
 			s32 min, s32 max, u32 step, s32 def,
-			u32 flags, const char * const *qmenu, void *priv)
+			u32 flags, const char * const *qmenu,
+			const s64 *qmenu_int, void *priv)
 {
 	struct v4l2_ctrl *ctrl;
 	unsigned sz_extra = 0;
@@ -1308,6 +1313,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	    (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
 	    (type == V4L2_CTRL_TYPE_BITMASK && max == 0) ||
 	    (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
+	    (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL) ||
 	    (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
 		handler_set_err(hdl, -ERANGE);
 		return NULL;
@@ -1318,6 +1324,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	}
 	if ((type == V4L2_CTRL_TYPE_INTEGER ||
 	     type == V4L2_CTRL_TYPE_MENU ||
+	     type == V4L2_CTRL_TYPE_INTEGER_MENU ||
 	     type == V4L2_CTRL_TYPE_BOOLEAN) &&
 	    (def < min || def > max)) {
 		handler_set_err(hdl, -ERANGE);
@@ -1352,7 +1359,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	ctrl->minimum = min;
 	ctrl->maximum = max;
 	ctrl->step = step;
-	ctrl->qmenu = qmenu;
+	if (type == V4L2_CTRL_TYPE_MENU)
+		ctrl->qmenu = qmenu;
+	else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
+		ctrl->qmenu_int = qmenu_int;
 	ctrl->priv = priv;
 	ctrl->cur.val = ctrl->val = ctrl->default_value = def;
 
@@ -1379,6 +1389,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 	struct v4l2_ctrl *ctrl;
 	const char *name = cfg->name;
 	const char * const *qmenu = cfg->qmenu;
+	const s64 *qmenu_int = cfg->qmenu_int;
 	enum v4l2_ctrl_type type = cfg->type;
 	u32 flags = cfg->flags;
 	s32 min = cfg->min;
@@ -1390,18 +1401,24 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 		v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
 								&def, &flags);
 
-	is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU);
+	is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU ||
+		   cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU);
 	if (is_menu)
 		WARN_ON(step);
 	else
 		WARN_ON(cfg->menu_skip_mask);
-	if (is_menu && qmenu == NULL)
+	if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL)
 		qmenu = v4l2_ctrl_get_menu(cfg->id);
+	else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU &&
+		 qmenu_int == NULL) {
+		handler_set_err(hdl, -EINVAL);
+		return NULL;
+	}
 
 	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name,
 			type, min, max,
 			is_menu ? cfg->menu_skip_mask : step,
-			def, flags, qmenu, priv);
+			def, flags, qmenu, qmenu_int, priv);
 	if (ctrl)
 		ctrl->is_private = cfg->is_private;
 	return ctrl;
@@ -1418,12 +1435,13 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
 	u32 flags;
 
 	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-	if (type == V4L2_CTRL_TYPE_MENU) {
+	if (type == V4L2_CTRL_TYPE_MENU
+	    || type == V4L2_CTRL_TYPE_INTEGER_MENU) {
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, type,
-				    min, max, step, def, flags, NULL, NULL);
+			     min, max, step, def, flags, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std);
 
@@ -1445,7 +1463,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, type,
-				    0, max, mask, def, flags, qmenu, NULL);
+			     0, max, mask, def, flags, qmenu, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
 
@@ -1609,6 +1627,9 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
 	case V4L2_CTRL_TYPE_MENU:
 		printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
 		break;
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
+		printk(KERN_CONT "%lld", ctrl->qmenu_int[ctrl->cur.val]);
+		break;
 	case V4L2_CTRL_TYPE_BITMASK:
 		printk(KERN_CONT "0x%08x", ctrl->cur.val);
 		break;
@@ -1745,7 +1766,8 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
 	qc->minimum = ctrl->minimum;
 	qc->maximum = ctrl->maximum;
 	qc->default_value = ctrl->default_value;
-	if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+	if (ctrl->type == V4L2_CTRL_TYPE_MENU
+	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
 		qc->step = 1;
 	else
 		qc->step = ctrl->step;
@@ -1775,16 +1797,22 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
 
 	qm->reserved = 0;
 	/* Sanity checks */
-	if (ctrl->qmenu == NULL ||
+	if ((ctrl->type == V4L2_CTRL_TYPE_MENU && ctrl->qmenu == NULL) ||
+	    (ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU
+	     && ctrl->qmenu_int == NULL) ||
 	    i < ctrl->minimum || i > ctrl->maximum)
 		return -EINVAL;
 	/* Use mask to see if this menu item should be skipped */
 	if (ctrl->menu_skip_mask & (1 << i))
 		return -EINVAL;
 	/* Empty menu items should also be skipped */
-	if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
-		return -EINVAL;
-	strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+	if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
+		if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
+			return -EINVAL;
+		strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+	} else if (ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU) {
+		qm->value = ctrl->qmenu_int[i];
+	}
 	return 0;
 }
 EXPORT_SYMBOL(v4l2_querymenu);
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 4b752d5..9633c69 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1094,6 +1094,7 @@ enum v4l2_ctrl_type {
 	V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
 	V4L2_CTRL_TYPE_STRING        = 7,
 	V4L2_CTRL_TYPE_BITMASK       = 8,
+	V4L2_CTRL_TYPE_INTEGER_MENU = 9,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
@@ -1113,7 +1114,10 @@ struct v4l2_queryctrl {
 struct v4l2_querymenu {
 	__u32		id;
 	__u32		index;
-	__u8		name[32];	/* Whatever */
+	union {
+		__u8	name[32];	/* Whatever */
+		__s64	value;
+	};
 	__u32		reserved;
 };
 
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index eeb3df6..f7819e7 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -129,7 +129,10 @@ struct v4l2_ctrl {
 		u32 step;
 		u32 menu_skip_mask;
 	};
-	const char * const *qmenu;
+	union {
+		const char * const *qmenu;
+		const s64 *qmenu_int;
+	};
 	unsigned long flags;
 	union {
 		s32 val;
@@ -219,6 +222,7 @@ struct v4l2_ctrl_config {
 	u32 flags;
 	u32 menu_skip_mask;
 	const char * const *qmenu;
+	const s64 *qmenu_int;
 	unsigned int is_private:1;
 };
 
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code
@ 2011-12-20 20:27 Sakari Ailus
  2011-12-20 20:27 ` [RFC 01/17] v4l: Introduce integer menu controls Sakari Ailus
                   ` (17 more replies)
  0 siblings, 18 replies; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:27 UTC (permalink / raw)
  To: linux-media
  Cc: Laurent Pinchart, David Cohen, Sylwester Nawrocki, Hans Verkuil,
	Andy Shevchenko, Tomasz Stanislawski, tuukkat76, Kamil Debski,
	Kim HeungJun

Hi everyone,

This patchset contains new versions of a couple of previous patchsets
I've sent to the list recently. There are mostly minor changes to many
existing patches based on the comments I've got so far, so I'm resending
them. The list is here:

- Integer menu controls [2],
- Selection IOCTL for subdevs [3],
- Sensor control changes [5],
- validate_pipeline() V4L2 subdev pad op,
- OMAP 3 ISP driver improvements [4],
- SMIA++ sensor driver and
- rm680/rm696 board code (a.k.a Nokia N9 and N950)

More detailed information can be found in the references. I'm still
sending the set as RFC since it contains many patches which I would like
to get more comments on, especially the changes related to V4L2.

This patchset depends on Aaro Koskinen's N9 patchset [1] to actually
function at least on the N9. That, to my understanding, is on its way to
mainline.


Comments and questions are very, very welcome.


References:

[1] http://www.spinics.net/lists/linux-omap/msg61295.html

[2] http://www.spinics.net/lists/linux-media/msg40796.html

[3] http://www.spinics.net/lists/linux-media/msg41503.html

[4] http://www.spinics.net/lists/linux-media/msg41542.html

[5] http://www.spinics.net/lists/linux-media/msg40861.html


Kind regards,

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [RFC 02/17] v4l: Document integer menu controls
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
  2011-12-20 20:27 ` [RFC 01/17] v4l: Introduce integer menu controls Sakari Ailus
@ 2011-12-20 20:27 ` Sakari Ailus
  2012-01-05 15:55   ` Laurent Pinchart
  2011-12-20 20:27 ` [RFC 03/17] vivi: Add an integer menu test control Sakari Ailus
                   ` (15 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:27 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 Documentation/DocBook/media/v4l/compat.xml         |   10 +++++
 Documentation/DocBook/media/v4l/v4l2.xml           |    7 ++++
 .../DocBook/media/v4l/vidioc-queryctrl.xml         |   39 +++++++++++++++++++-
 3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index b68698f..569efd1 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2379,6 +2379,16 @@ that used it. It was originally scheduled for removal in 2.6.35.
       </orderedlist>
     </section>
 
+    <section>
+      <title>V4L2 in Linux 3.3</title>
+      <orderedlist>
+        <listitem>
+	  <para>Added integer menus, the new type will be
+	  V4L2_CTRL_TYPE_INTEGER_MENU.</para>
+        </listitem>
+      </orderedlist>
+    </section>
+
     <section id="other">
       <title>Relation of V4L2 to other Linux multimedia APIs</title>
 
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index 2ab365c..affe1ba 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -128,6 +128,13 @@ structs, ioctls) must be noted in more detail in the history chapter
 applications. -->
 
       <revision>
+	<revnumber>3.3</revnumber>
+	<date>2011-11-24</date>
+	<authorinitials>sa</authorinitials>
+	<revremark>Added V4L2_CTRL_TYPE_INTEGER_MENU.</revremark>
+      </revision>
+
+      <revision>
 	<revnumber>3.2</revnumber>
 	<date>2011-08-26</date>
 	<authorinitials>hv</authorinitials>
diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
index 0ac0057..02064b0 100644
--- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
@@ -215,11 +215,12 @@ the array to zero.</entry>
 
     <table pgwide="1" frame="none" id="v4l2-querymenu">
       <title>struct <structname>v4l2_querymenu</structname></title>
-      <tgroup cols="3">
+      <tgroup cols="4">
 	&cs-str;
 	<tbody valign="top">
 	  <row>
 	    <entry>__u32</entry>
+	    <entry></entry>
 	    <entry><structfield>id</structfield></entry>
 	    <entry>Identifies the control, set by the application
 from the respective &v4l2-queryctrl;
@@ -227,18 +228,38 @@ from the respective &v4l2-queryctrl;
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
+	    <entry></entry>
 	    <entry><structfield>index</structfield></entry>
 	    <entry>Index of the menu item, starting at zero, set by
 	    the application.</entry>
 	  </row>
 	  <row>
+	    <entry>union</entry>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry></entry>
 	    <entry>__u8</entry>
 	    <entry><structfield>name</structfield>[32]</entry>
 	    <entry>Name of the menu item, a NUL-terminated ASCII
-string. This information is intended for the user.</entry>
+string. This information is intended for the user. This field is valid
+for <constant>V4L2_CTRL_FLAG_MENU</constant> type controls.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>__s64</entry>
+	    <entry><structfield>value</structfield></entry>
+	    <entry>
+              Value of the integer menu item. This field is valid for
+              <constant>V4L2_CTRL_FLAG_INTEGER_MENU</constant> type
+              controls.
+            </entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
+	    <entry></entry>
 	    <entry><structfield>reserved</structfield></entry>
 	    <entry>Reserved for future extensions. Drivers must set
 the array to zero.</entry>
@@ -292,6 +313,20 @@ the menu items can be enumerated with the
 <constant>VIDIOC_QUERYMENU</constant> ioctl.</entry>
 	  </row>
 	  <row>
+	    <entry><constant>V4L2_CTRL_TYPE_INTEGER_MENU</constant></entry>
+	    <entry>&ge; 0</entry>
+	    <entry>1</entry>
+	    <entry>N-1</entry>
+	    <entry>
+              The control has a menu of N choices. The values of the
+              menu items can be enumerated with the
+              <constant>VIDIOC_QUERYMENU</constant> ioctl. This is
+              similar to <constant>V4L2_CTRL_TYPE_MENU</constant>
+              except that instead of strings, the menu items are
+              signed 64-bit integers.
+            </entry>
+	  </row>
+	  <row>
 	    <entry><constant>V4L2_CTRL_TYPE_BITMASK</constant></entry>
 	    <entry>0</entry>
 	    <entry>n/a</entry>
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 03/17] vivi: Add an integer menu test control
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
  2011-12-20 20:27 ` [RFC 01/17] v4l: Introduce integer menu controls Sakari Ailus
  2011-12-20 20:27 ` [RFC 02/17] v4l: Document " Sakari Ailus
@ 2011-12-20 20:27 ` Sakari Ailus
  2012-01-05 15:59   ` Laurent Pinchart
  2011-12-20 20:27 ` [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs Sakari Ailus
                   ` (14 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:27 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Add an integer menu test control for the vivi driver.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/media/video/vivi.c |   21 +++++++++++++++++++++
 1 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 7d754fb..763ec23 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -177,6 +177,7 @@ struct vivi_dev {
 	struct v4l2_ctrl	   *menu;
 	struct v4l2_ctrl	   *string;
 	struct v4l2_ctrl	   *bitmask;
+	struct v4l2_ctrl	   *int_menu;
 
 	spinlock_t                 slock;
 	struct mutex		   mutex;
@@ -503,6 +504,10 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 			dev->boolean->cur.val,
 			dev->menu->qmenu[dev->menu->cur.val],
 			dev->string->cur.string);
+	snprintf(str, sizeof(str), " integer_menu %s, value %lld ",
+			dev->int_menu->qmenu[dev->int_menu->cur.val],
+			dev->int64->cur.val64);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
 	mutex_unlock(&dev->ctrl_handler.lock);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
 	if (dev->button_pressed) {
@@ -1183,6 +1188,22 @@ static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
 	.step = 0,
 };
 
+static const s64 * const vivi_ctrl_int_menu_values[] = {
+	1, 1, 2, 3, 5, 8, 13, 21, 42,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_string = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIDI_CID_CUSTOM_BASE + 7
+	.name = "Integer menu",
+	.type = V4L2_CTRL_TYPE_INTEGER_MENU,
+	.min = 1,
+	.max = 8,
+	.def = 4,
+	.menu_skip_mask = 0x02,
+	.qmenu_int = &vivi_ctrl_int_menu_values,
+};
+
 static const struct v4l2_file_operations vivi_fops = {
 	.owner		= THIS_MODULE,
 	.open           = v4l2_fh_open,
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (2 preceding siblings ...)
  2011-12-20 20:27 ` [RFC 03/17] vivi: Add an integer menu test control Sakari Ailus
@ 2011-12-20 20:27 ` Sakari Ailus
  2012-01-05 16:12   ` Laurent Pinchart
  2011-12-20 20:27 ` [RFC 05/17] v4l: Support s_crop and g_crop through s/g_selection Sakari Ailus
                   ` (13 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:27 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Add support for VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION
IOCTLs. They replace functionality provided by VIDIOC_SUBDEV_S_CROP and
VIDIOC_SUBDEV_G_CROP IOCTLs and also add new functionality (composing).

VIDIOC_SUBDEV_G_CROP and VIDIOC_SUBDEV_S_CROP continue to be supported.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/media/video/v4l2-subdev.c |   26 ++++++++++++++++++++-
 include/linux/v4l2-subdev.h       |   45 +++++++++++++++++++++++++++++++++++++
 include/media/v4l2-subdev.h       |    5 ++++
 3 files changed, 75 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 65ade5f..e8ae098 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -36,13 +36,17 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
 {
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
 	/* Allocate try format and crop in the same memory block */
-	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
+	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop)
+			       + sizeof(*fh->try_compose))
 			      * sd->entity.num_pads, GFP_KERNEL);
 	if (fh->try_fmt == NULL)
 		return -ENOMEM;
 
 	fh->try_crop = (struct v4l2_rect *)
 		(fh->try_fmt + sd->entity.num_pads);
+
+	fh->try_compose = (struct v4l2_rect *)
+		(fh->try_crop + sd->entity.num_pads);
 #endif
 	return 0;
 }
@@ -281,6 +285,26 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 		return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh,
 					fie);
 	}
+
+	case VIDIOC_SUBDEV_G_SELECTION: {
+		struct v4l2_subdev_selection *sel = arg;
+
+		if (sel->pad >= sd->entity.num_pads)
+			return -EINVAL;
+
+		return v4l2_subdev_call(
+			sd, pad, get_selection, subdev_fh, sel);
+	}
+
+	case VIDIOC_SUBDEV_S_SELECTION: {
+		struct v4l2_subdev_selection *sel = arg;
+
+		if (sel->pad >= sd->entity.num_pads)
+			return -EINVAL;
+
+		return v4l2_subdev_call(
+			sd, pad, set_selection, subdev_fh, sel);
+	}
 #endif
 	default:
 		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
index ed29cbb..d53d775 100644
--- a/include/linux/v4l2-subdev.h
+++ b/include/linux/v4l2-subdev.h
@@ -123,6 +123,47 @@ struct v4l2_subdev_frame_interval_enum {
 	__u32 reserved[9];
 };
 
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE			(1 << 0)
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE			(1 << 1)
+#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG		(1 << 2)
+
+/* active cropping area */
+#define V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE			0
+/* default cropping area */
+#define V4L2_SUBDEV_SEL_TGT_CROP_DEFAULT		1
+/* cropping bounds */
+#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS			2
+/* current composing area */
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE		256
+/* default composing area */
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_DEFAULT		257
+/* composing bounds */
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS		258
+
+
+/**
+ * struct v4l2_subdev_selection - selection info
+ *
+ * @which: either V4L2_SUBDEV_FORMAT_ACTIVE or V4L2_SUBDEV_FORMAT_TRY
+ * @pad: pad number, as reported by the media API
+ * @target: selection target, used to choose one of possible rectangles
+ * @flags: constraints flags
+ * @r: coordinates of selection window
+ * @reserved: for future use, rounds structure size to 64 bytes, set to zero
+ *
+ * Hardware may use multiple helper window to process a video stream.
+ * The structure is used to exchange this selection areas between
+ * an application and a driver.
+ */
+struct v4l2_subdev_selection {
+	__u32 which;
+	__u32 pad;
+	__u32 target;
+	__u32 flags;
+	struct v4l2_rect r;
+	__u32 reserved[8];
+};
+
 #define VIDIOC_SUBDEV_G_FMT	_IOWR('V',  4, struct v4l2_subdev_format)
 #define VIDIOC_SUBDEV_S_FMT	_IOWR('V',  5, struct v4l2_subdev_format)
 #define VIDIOC_SUBDEV_G_FRAME_INTERVAL \
@@ -137,5 +178,9 @@ struct v4l2_subdev_frame_interval_enum {
 			_IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)
 #define VIDIOC_SUBDEV_G_CROP	_IOWR('V', 59, struct v4l2_subdev_crop)
 #define VIDIOC_SUBDEV_S_CROP	_IOWR('V', 60, struct v4l2_subdev_crop)
+#define VIDIOC_SUBDEV_G_SELECTION \
+	_IOWR('V', 61, struct v4l2_subdev_selection)
+#define VIDIOC_SUBDEV_S_SELECTION \
+	_IOWR('V', 62, struct v4l2_subdev_selection)
 
 #endif
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index f0f3358..26eeaa4 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -466,6 +466,10 @@ struct v4l2_subdev_pad_ops {
 		       struct v4l2_subdev_crop *crop);
 	int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 		       struct v4l2_subdev_crop *crop);
+	int (*get_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_selection *sel);
+	int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_selection *sel);
 };
 
 struct v4l2_subdev_ops {
@@ -551,6 +555,7 @@ struct v4l2_subdev_fh {
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
 	struct v4l2_mbus_framefmt *try_fmt;
 	struct v4l2_rect *try_crop;
+	struct v4l2_rect *try_compose;
 #endif
 };
 
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 05/17] v4l: Support s_crop and g_crop through s/g_selection
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (3 preceding siblings ...)
  2011-12-20 20:27 ` [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs Sakari Ailus
@ 2011-12-20 20:27 ` Sakari Ailus
  2012-01-05 16:13   ` Laurent Pinchart
  2011-12-20 20:27 ` [RFC 06/17] v4l: Add selections documentation Sakari Ailus
                   ` (12 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:27 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Revert to s_selection if s_crop isn't implemented by a driver. Same for
g_selection / g_crop.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/media/video/v4l2-subdev.c |   37 +++++++++++++++++++++++++++++++++++--
 1 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index e8ae098..f8de551 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -226,6 +226,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
 	case VIDIOC_SUBDEV_G_CROP: {
 		struct v4l2_subdev_crop *crop = arg;
+		struct v4l2_subdev_selection sel;
+		int rval;
 
 		if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
 		    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -234,11 +236,27 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 		if (crop->pad >= sd->entity.num_pads)
 			return -EINVAL;
 
-		return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
+		rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
+		if (rval != -ENOIOCTLCMD)
+			return rval;
+
+		memset(&sel, 0, sizeof(sel));
+		sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		sel.pad = crop->pad;
+		sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE;
+
+		rval = v4l2_subdev_call(
+			sd, pad, get_selection, subdev_fh, &sel);
+
+		crop->rect = sel.r;
+
+		return rval;
 	}
 
 	case VIDIOC_SUBDEV_S_CROP: {
 		struct v4l2_subdev_crop *crop = arg;
+		struct v4l2_subdev_selection sel;
+		int rval;
 
 		if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
 		    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -247,7 +265,22 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 		if (crop->pad >= sd->entity.num_pads)
 			return -EINVAL;
 
-		return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
+		rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
+		if (rval != -ENOIOCTLCMD)
+			return rval;
+
+		memset(&sel, 0, sizeof(sel));
+		sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		sel.pad = crop->pad;
+		sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE;
+		sel.r = crop->rect;
+
+		rval = v4l2_subdev_call(
+			sd, pad, set_selection, subdev_fh, &sel);
+
+		crop->rect = sel.r;
+
+		return rval;
 	}
 
 	case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 06/17] v4l: Add selections documentation.
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (4 preceding siblings ...)
  2011-12-20 20:27 ` [RFC 05/17] v4l: Support s_crop and g_crop through s/g_selection Sakari Ailus
@ 2011-12-20 20:27 ` Sakari Ailus
  2012-01-06 11:43   ` Laurent Pinchart
  2011-12-20 20:27 ` [RFC 07/17] v4l: Add pixelrate to struct v4l2_mbus_framefmt Sakari Ailus
                   ` (11 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:27 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 Documentation/DocBook/media/v4l/dev-subdev.xml     |   95 +++++++--
 Documentation/DocBook/media/v4l/v4l2.xml           |    1 +
 .../media/v4l/vidioc-subdev-g-selection.xml        |  226 ++++++++++++++++++++
 3 files changed, 302 insertions(+), 20 deletions(-)
 create mode 100644 Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml

diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml
index 0916a73..722db60 100644
--- a/Documentation/DocBook/media/v4l/dev-subdev.xml
+++ b/Documentation/DocBook/media/v4l/dev-subdev.xml
@@ -77,7 +77,7 @@
     format, frame width and frame height.</para></note>
 
     <para>Image formats are typically negotiated on video capture and output
-    devices using the <link linkend="crop">cropping and scaling</link> ioctls.
+    devices using the format and <link linkend="selection">selection</link> ioctls.
     The driver is responsible for configuring every block in the video pipeline
     according to the requested format at the pipeline input and/or
     output.</para>
@@ -276,11 +276,11 @@
     </section>
 
     <section>
-      <title>Cropping and scaling</title>
+      <title>Selections: cropping, scaling and composition</title>
 
       <para>Many sub-devices support cropping frames on their input or output
       pads (or possible even on both). Cropping is used to select the area of
-      interest in an image, typically on a video sensor or video decoder. It can
+      interest in an image, typically on an image sensor or a video decoder. It can
       also be used as part of digital zoom implementations to select the area of
       the image that will be scaled up.</para>
 
@@ -288,26 +288,81 @@
       &v4l2-rect; by the coordinates of the top left corner and the rectangle
       size. Both the coordinates and sizes are expressed in pixels.</para>
 
-      <para>The crop rectangle is retrieved and set using the
-      &VIDIOC-SUBDEV-G-CROP; and &VIDIOC-SUBDEV-S-CROP; ioctls. Like for pad
-      formats, drivers store try and active crop rectangles. The format
-      negotiation mechanism applies to crop settings as well.</para>
-
-      <para>On input pads, cropping is applied relatively to the current pad
-      format. The pad format represents the image size as received by the
-      sub-device from the previous block in the pipeline, and the crop rectangle
-      represents the sub-image that will be transmitted further inside the
-      sub-device for processing. The crop rectangle be entirely containted
-      inside the input image size.</para>
-
-      <para>Input crop rectangle are reset to their default value when the input
-      image format is modified. Drivers should use the input image size as the
-      crop rectangle default value, but hardware requirements may prevent this.
-      </para>
+      <para>Scaling operation changes the size of the image by scaling
+      it to new dimensions. Some sub-devices support it. The scaled
+      size (width and height) is represented by &v4l2-rect;. In the
+      case of scaling, top and left will always be zero. Scaling is
+      configured using &sub-subdev-g-selection; and
+      <constant>V4L2_SUBDEV_SEL_COMPOSE_ACTIVE</constant> selection
+      target on the sink pad of the subdev. The scaling is performed
+      related to the width and height of the crop rectangle on the
+      subdev's sink pad.</para>
+
+      <para>As for pad formats, drivers store try and active
+      rectangles for the selection targets of ACTIVE type <xref
+      linkend="v4l2-subdev-selection-targets">.</xref></para>
+
+      <para>On sink pads, cropping is applied relatively to the
+      current pad format. The pad format represents the image size as
+      received by the sub-device from the previous block in the
+      pipeline, and the crop rectangle represents the sub-image that
+      will be transmitted further inside the sub-device for
+      processing.</para>
+
+      <para>On source pads, cropping is similar to sink pads, with the
+      exception that the source size from which the cropping is
+      performed, is the COMPOSE rectangle on the sink pad. In both
+      sink and source pads, the crop rectangle must be entirely
+      containted inside the source image size for the crop
+      operation.</para>
+
+      <para>The drivers should always use the closest possible
+      rectangle the user requests on all selection targets, unless
+      specificly told otherwise<xref
+      linkend="v4l2-subdev-selection-flags">.</xref></para>
+    </section>
+
+    <section>
+      <title>Order of configuration and format propagation</title>
+
+      <para>The order of image processing steps will always be from
+      the sink pad towards the source pad. This is also reflected in
+      the order in which the configuration must be performed by the
+      user. The format is propagated within the subdev along the later
+      processing steps. For example, setting the sink pad format
+      causes all the selection rectangles and the source pad format to
+      be set to sink pad format --- if allowed by the hardware, and if
+      not, then closest possible. The coordinates to a step always
+      refer to the active size of the previous step.</para>
+
+      <orderedlist>
+	<listitem>Sink pad format. The user configures the sink pad
+	format. This format defines the parameters of the image the
+	entity receives through the pad for further processing.</listitem>
 
-      <para>Cropping behaviour on output pads is not defined.</para>
+	<listitem>Sink pad active crop selection. The sink pad crop
+	defines the performed to the sink pad format.</listitem>
 
+	<listitem>Sink pad active compose selection. The sink pad compose
+	rectangle defines the scaling ratio compared to the size of
+	the sink pad crop rectangle.</listitem>
+
+	<listitem>Source pad active crop selection. Crop on the source
+	pad defines crop performed to the image scaled according to
+	the sink pad compose rectangle.</listitem>
+
+	<listitem>Source pad active compose selection. The source pad
+	compose defines the size and location of the compose
+	rectangle.</listitem>
+
+	<listitem>Source pad format. The source pad format defines the
+	output pixel format of the subdev, as well as the other
+	parameters with the exception of the image width and
+	height.</listitem>
+
+      </orderedlist>
     </section>
+
   </section>
 
   &sub-subdev-formats;
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index affe1ba..3ff11a6 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -529,6 +529,7 @@ and discussions on the V4L mailing list.</revremark>
     &sub-subdev-g-crop;
     &sub-subdev-g-fmt;
     &sub-subdev-g-frame-interval;
+    &sub-subdev-g-selection;
     &sub-subscribe-event;
     <!-- End of ioctls. -->
     &sub-mmap;
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
new file mode 100644
index 0000000..5fbcd65
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
@@ -0,0 +1,226 @@
+<refentry id="vidioc-subdev-g-selection">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_G_SELECTION, VIDIOC_SUBDEV_S_SELECTION</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_G_SELECTION</refname>
+    <refname>VIDIOC_SUBDEV_S_SELECTION</refname>
+    <refpurpose>Get or set selection rectangles on a subdev pad</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_subdev_selection *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_SUBDEV_G_SELECTION, VIDIOC_SUBDEV_S_SELECTION</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>The selections are used to configure various image
+    processing functionality performed by the subdevs which affect the
+    image size. This currently includes cropping, scaling and
+    composition.</para>
+
+    <para>The selections replace the crop API &sub-subdev-g-crop;. All
+    the function of the crop API, and more, are supported by the
+    selections API.</para>
+
+    <para>See <xref linkend="subdev">Sub-device interface</xref> for
+    more information on how each selection target affects the image
+    processing pipeline inside the subdevice.</para>
+
+    <section>
+      <title>Types of selection targets</title>
+
+      <para>The are four types of selection targets: active, default,
+      bounds and padding. The ACTIVE targets are the targets which
+      configure the hardware. The DEFAULT target provides the default
+      for the ACTIVE selection. The BOUNDS target will return the
+      maximum width and height of the target. The PADDED target
+      provides the width and height for the padded image, and is
+      directly affected by the ACTIVE target. The PADDED targets may
+      be configurable depending on the hardware.</para>
+    </section>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-selection-targets">
+      <title>V4L2 subdev selection targets</title>
+      <tgroup cols="3">
+        &cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE</constant></entry>
+	    <entry>0</entry>
+	    <entry>Active crop. Defines the cropping
+	    performed by the processing step.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_DEFAULT</constant></entry>
+	    <entry>1</entry>
+	    <entry>Default crop rectangle.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS</constant></entry>
+	    <entry>2</entry>
+	    <entry>Bounds of the crop rectangle.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE</constant></entry>
+	    <entry>256</entry>
+	    <entry>Active compose rectangle. Used to configure scaling
+	    on sink pads and composition on source pads.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_DEFAULT</constant></entry>
+	    <entry>257</entry>
+	    <entry>Default compose rectangle.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
+	    <entry>258</entry>
+	    <entry>Bounds of the compose rectangle.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-selection-flags">
+      <title>V4L2 subdev selection flags</title>
+      <tgroup cols="3">
+        &cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant></entry>
+	    <entry>(1 &lt;&lt; 0)</entry>
+	    <entry>Suggest the driver it should choose greater or
+	    equal rectangle (in size) than was requested.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant></entry>
+	    <entry>(1 &lt;&lt; 1)</entry>
+	    <entry>Suggest the driver it should choose lesser or
+	    equal rectangle (in size) than was requested.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant></entry>
+	    <entry>(1 &lt;&lt; 2)</entry>
+	    <entry>The configuration should not be propagated to any
+	    further processing steps. If this flag is not given, the
+	    configuration is propagated inside the subdevice to all
+	    further processing steps.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-selection">
+      <title>struct <structname>v4l2_subdev_selection</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>which</structfield></entry>
+	    <entry>Active or try selection, from
+	    &v4l2-subdev-format-whence;.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>pad</structfield></entry>
+	    <entry>Pad number as reported by the media framework.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>target</structfield></entry>
+	    <entry>Target selection rectangle. See
+	    <xref linkend="v4l2-subdev-selection-targets">.</xref>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>flags</structfield></entry>
+	    <entry>Flags. See
+	    <xref linkend="v4l2-subdev-selection-flags">.</xref></entry>
+	  </row>
+	  <row>
+	    <entry>&v4l2-rect;</entry>
+	    <entry><structfield>rect</structfield></entry>
+	    <entry>Crop rectangle boundaries, in pixels.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[8]</entry>
+	    <entry>Reserved for future extensions. Applications and drivers must
+	    set the array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
+	<listitem>
+	  <para>The selection rectangle can't be changed because the
+	  pad is currently busy. This can be caused, for instance, by
+	  an active video stream on the pad. The ioctl must not be
+	  retried without performing another action to fix the problem
+	  first. Only returned by
+	  <constant>VIDIOC_SUBDEV_S_SELECTION</constant></para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>The &v4l2-subdev-selection;
+	  <structfield>pad</structfield> references a non-existing
+	  pad, the <structfield>which</structfield> field references a
+	  non-existing format, or the selection target is not
+	  supported on the given subdev pad.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 07/17] v4l: Add pixelrate to struct v4l2_mbus_framefmt
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (5 preceding siblings ...)
  2011-12-20 20:27 ` [RFC 06/17] v4l: Add selections documentation Sakari Ailus
@ 2011-12-20 20:27 ` Sakari Ailus
  2012-01-06 10:26   ` Laurent Pinchart
  2011-12-20 20:28 ` [RFC 08/17] v4l: Image source control class Sakari Ailus
                   ` (10 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:27 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Pixelrate is an essential part of the image data parameters. Add this.
Together, the current parameters also define the frame rate.

Sensors do not have a concept of frame rate; pixelrate is much more
meaningful in this context. Also, it is best to combine the pixelrate with
the other format parameters since there are dependencies between them.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 Documentation/DocBook/media/v4l/subdev-formats.xml |   10 +++++++++-
 include/linux/v4l2-mediabus.h                      |    4 +++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml
index 49c532e..a6a6630 100644
--- a/Documentation/DocBook/media/v4l/subdev-formats.xml
+++ b/Documentation/DocBook/media/v4l/subdev-formats.xml
@@ -35,7 +35,15 @@
 	</row>
 	<row>
 	  <entry>__u32</entry>
-	  <entry><structfield>reserved</structfield>[7]</entry>
+	  <entry><structfield>pixelrate</structfield></entry>
+	  <entry>Pixel rate in kp/s. This clock is the maximum rate at
+	  which pixels are transferred on the bus. The
+	  <structfield>pixelrate</structfield> field is
+	  read-only.</entry>
+	</row>
+	<row>
+	  <entry>__u32</entry>
+	  <entry><structfield>reserved</structfield>[6]</entry>
 	  <entry>Reserved for future extensions. Applications and drivers must
 	  set the array to zero.</entry>
 	</row>
diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
index 5ea7f75..35c6b96 100644
--- a/include/linux/v4l2-mediabus.h
+++ b/include/linux/v4l2-mediabus.h
@@ -101,6 +101,7 @@ enum v4l2_mbus_pixelcode {
  * @code:	data format code (from enum v4l2_mbus_pixelcode)
  * @field:	used interlacing type (from enum v4l2_field)
  * @colorspace:	colorspace of the data (from enum v4l2_colorspace)
+ * @pixel_clock: pixel clock, in kHz
  */
 struct v4l2_mbus_framefmt {
 	__u32			width;
@@ -108,7 +109,8 @@ struct v4l2_mbus_framefmt {
 	__u32			code;
 	__u32			field;
 	__u32			colorspace;
-	__u32			reserved[7];
+	__u32			pixelrate;
+	__u32			reserved[6];
 };
 
 #endif
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 08/17] v4l: Image source control class
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (6 preceding siblings ...)
  2011-12-20 20:27 ` [RFC 07/17] v4l: Add pixelrate to struct v4l2_mbus_framefmt Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2012-01-05 16:23   ` Laurent Pinchart
  2011-12-20 20:28 ` [RFC 09/17] v4l: Add pad op for pipeline validation Sakari Ailus
                   ` (9 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Add image source control class. This control class is intended to contain
low level controls which deal with control of the image capture process ---
the A/D converter in image sensors, for example.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 Documentation/DocBook/media/v4l/controls.xml       |  101 ++++++++++++++++++++
 .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       |    6 +
 drivers/media/video/v4l2-ctrls.c                   |   10 ++
 include/linux/videodev2.h                          |   10 ++
 4 files changed, 127 insertions(+), 0 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 3bc5ee8..69ede83 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -3356,6 +3356,107 @@ interface and may change in the future.</para>
       </table>
 
     </section>
+
+    <section id="image-source-controls">
+      <title>Image Source Control Reference</title>
+
+      <note>
+	<title>Experimental</title>
+
+	<para>This is an <link
+	linkend="experimental">experimental</link> interface and may
+	change in the future.</para>
+      </note>
+
+      <para>
+	The Image Source control class is intended for low-level
+	control of image source devices such as image sensors. The
+	devices feature an analogue to digital converter and a bus
+	transmitter to transmit the image data out of the device.
+      </para>
+
+      <table pgwide="1" frame="none" id="image-source-control-id">
+      <title>Image Source Control IDs</title>
+
+      <tgroup cols="4">
+	<colspec colname="c1" colwidth="1*" />
+	<colspec colname="c2" colwidth="6*" />
+	<colspec colname="c3" colwidth="2*" />
+	<colspec colname="c4" colwidth="6*" />
+	<spanspec namest="c1" nameend="c2" spanname="id" />
+	<spanspec namest="c2" nameend="c4" spanname="descr" />
+	<thead>
+	  <row>
+	    <entry spanname="id" align="left">ID</entry>
+	    <entry align="left">Type</entry>
+	  </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+	  </row>
+	</thead>
+	<tbody valign="top">
+	  <row><entry></entry></row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry>
+	    <entry>class</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">The IMAGE_SOURCE class descriptor.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_VBLANK</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Vertical blanking. The idle
+	    preriod after every frame during which no image data is
+	    produced. The unit of vertical blanking is a line. Every
+	    line has length of the image width plus horizontal
+	    blanking at the pixel clock specified by struct
+	    v4l2_mbus_framefmt <xref linkend="v4l2-mbus-framefmt"
+	    />.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_HBLANK</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Horizontal blanking. The idle
+	    preriod after every line of image data during which no
+	    image data is produced. The unit of horizontal blanking is
+	    pixels.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_LINK_FREQ</constant></entry>
+	    <entry>integer menu</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Image source's data bus frequency.
+	    Together with the media bus pixel code, bus type (clock
+	    cycles per sample), the data bus frequency defines the
+	    pixel clock. <xref linkend="v4l2-mbus-framefmt" /> The
+	    frame rate can be calculated from the pixel clock, image
+	    width and height and horizontal and vertical blanking. The
+	    frame rate control is performed by selecting the desired
+	    horizontal and vertical blanking.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Analogue gain is gain affecting
+	    all colour components in the pixel matrix. The gain
+	    operation is performed in the analogue domain before A/D
+	    conversion.
+	    </entry>
+	  </row>
+	  <row><entry></entry></row>
+	</tbody>
+      </tgroup>
+      </table>
+
+    </section>
+
 </section>
 
   <!--
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index 5122ce8..250c1cf 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -257,6 +257,12 @@ These controls are described in <xref
 These controls are described in <xref
 		linkend="flash-controls" />.</entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_CLASS_IMAGE_SOURCE</constant></entry>
+	    <entry>0x9d0000</entry> <entry>The class containing image
+	    source controls. These controls are described in <xref
+	    linkend="image-source-controls" />.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 083bb79..da1ec52 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -606,6 +606,12 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_FLASH_CHARGE:		return "Charge";
 	case V4L2_CID_FLASH_READY:		return "Ready to strobe";
 
+	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image source controls";
+	case V4L2_CID_IMAGE_SOURCE_VBLANK:	return "Vertical blanking";
+	case V4L2_CID_IMAGE_SOURCE_HBLANK:	return "Horizontal blanking";
+	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:	return "Link frequency";
+	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN: return "Analogue gain";
+
 	default:
 		return NULL;
 	}
@@ -694,6 +700,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
 		*type = V4L2_CTRL_TYPE_MENU;
 		break;
+	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:
+		*type = V4L2_CTRL_TYPE_INTEGER_MENU;
+		break;
 	case V4L2_CID_RDS_TX_PS_NAME:
 	case V4L2_CID_RDS_TX_RADIO_TEXT:
 		*type = V4L2_CTRL_TYPE_STRING;
@@ -703,6 +712,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_MPEG_CLASS:
 	case V4L2_CID_FM_TX_CLASS:
 	case V4L2_CID_FLASH_CLASS:
+	case V4L2_CID_IMAGE_SOURCE_CLASS:
 		*type = V4L2_CTRL_TYPE_CTRL_CLASS;
 		/* You can neither read not write these */
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 9633c69..0f8f904 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1080,6 +1080,7 @@ struct v4l2_ext_controls {
 #define V4L2_CTRL_CLASS_CAMERA 0x009a0000	/* Camera class controls */
 #define V4L2_CTRL_CLASS_FM_TX 0x009b0000	/* FM Modulator control class */
 #define V4L2_CTRL_CLASS_FLASH 0x009c0000	/* Camera flash controls */
+#define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009d0000	/* Image source flash controls */
 
 #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
@@ -1690,6 +1691,15 @@ enum v4l2_flash_strobe_source {
 #define V4L2_CID_FLASH_CHARGE			(V4L2_CID_FLASH_CLASS_BASE + 11)
 #define V4L2_CID_FLASH_READY			(V4L2_CID_FLASH_CLASS_BASE + 12)
 
+/* Image source controls */
+#define V4L2_CID_IMAGE_SOURCE_CLASS_BASE	(V4L2_CTRL_CLASS_IMAGE_SOURCE | 0x900)
+#define V4L2_CID_IMAGE_SOURCE_CLASS		(V4L2_CTRL_CLASS_IMAGE_SOURCE | 1)
+
+#define V4L2_CID_IMAGE_SOURCE_VBLANK		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1)
+#define V4L2_CID_IMAGE_SOURCE_HBLANK		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
+#define V4L2_CID_IMAGE_SOURCE_LINK_FREQ		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
+#define V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN	(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4)
+
 /*
  *	T U N I N G
  */
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 09/17] v4l: Add pad op for pipeline validation
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (7 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 08/17] v4l: Image source control class Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2012-01-06  9:42   ` Laurent Pinchart
  2011-12-20 20:28 ` [RFC 10/17] omap3: add definition for CONTROL_CAMERA_PHY_CTRL Sakari Ailus
                   ` (8 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

smiapp_pad_ops.validate_pipeline is intended to validate the full pipeline
which is implemented by the driver to which the subdev implementing this op
belongs to. The validate_pipeline op must also call validate_pipeline on
any external entity which is linked to its sink pads.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 include/media/v4l2-subdev.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 26eeaa4..a5ebe86 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -470,6 +470,7 @@ struct v4l2_subdev_pad_ops {
 			     struct v4l2_subdev_selection *sel);
 	int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 			     struct v4l2_subdev_selection *sel);
+	int (*validate_pipeline)(struct v4l2_subdev *sd);
 };
 
 struct v4l2_subdev_ops {
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 10/17] omap3: add definition for CONTROL_CAMERA_PHY_CTRL
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (8 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 09/17] v4l: Add pad op for pipeline validation Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2011-12-20 20:28 ` [RFC 11/17] omap3isp: Implement validate_pipeline Sakari Ailus
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

This register is available only in OMAP3630.

The original patch was submitted by Vimarsh Zutshi.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 arch/arm/mach-omap2/control.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index d4ef75d..6a26a0d 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -183,6 +183,7 @@
 #define OMAP3630_CONTROL_FUSE_OPP120_VDD1       (OMAP2_CONTROL_GENERAL + 0x0120)
 #define OMAP3630_CONTROL_FUSE_OPP50_VDD2        (OMAP2_CONTROL_GENERAL + 0x0128)
 #define OMAP3630_CONTROL_FUSE_OPP100_VDD2       (OMAP2_CONTROL_GENERAL + 0x012C)
+#define OMAP3630_CONTROL_CAMERA_PHY_CTRL	(OMAP2_CONTROL_GENERAL + 0x02f0)
 
 /* OMAP44xx control efuse offsets */
 #define OMAP44XX_CONTROL_FUSE_IVA_OPP50		0x22C
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 11/17] omap3isp: Implement validate_pipeline
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (9 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 10/17] omap3: add definition for CONTROL_CAMERA_PHY_CTRL Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2011-12-20 20:28 ` [RFC 12/17] omap3isp: Add lane configuration to platform data Sakari Ailus
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Validate pipeline of any external entity connected to the ISP driver.
The validation of the pipeline for the part that involves links inside the
domain of another driver must be done by that very driver.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/media/video/omap3isp/ispvideo.c |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c
index f229057..0568234 100644
--- a/drivers/media/video/omap3isp/ispvideo.c
+++ b/drivers/media/video/omap3isp/ispvideo.c
@@ -355,6 +355,18 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
 		    fmt_source.format.height != fmt_sink.format.height)
 			return -EPIPE;
 
+		if (subdev->host_priv) {
+			/*
+			 * host_priv != NULL: this is a sensor. Issue
+			 * validate_pipeline. We're at our end of the
+			 * pipeline so we quit now.
+			 */
+			ret = v4l2_subdev_call(subdev, pad, validate_pipeline);
+			if (ret < 0 && ret != -ENOIOCTLCMD)
+				return -EPIPE;
+			break;
+		}
+
 		if (shifter_link) {
 			unsigned int parallel_shift = 0;
 			if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) {
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 12/17] omap3isp: Add lane configuration to platform data
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (10 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 11/17] omap3isp: Implement validate_pipeline Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2012-01-06 10:06   ` Laurent Pinchart
  2011-12-20 20:28 ` [RFC 13/17] omap3isp: Configure CSI-2 phy based on " Sakari Ailus
                   ` (5 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Add lane configuration (order of clock and data lane) to platform data on
both CCP2 and CSI-2.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/media/video/omap3isp/ispcsiphy.h |   15 ++-------------
 include/media/omap3isp.h                 |   15 +++++++++++++++
 2 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/media/video/omap3isp/ispcsiphy.h b/drivers/media/video/omap3isp/ispcsiphy.h
index 9596dc6..e93a661 100644
--- a/drivers/media/video/omap3isp/ispcsiphy.h
+++ b/drivers/media/video/omap3isp/ispcsiphy.h
@@ -27,22 +27,11 @@
 #ifndef OMAP3_ISP_CSI_PHY_H
 #define OMAP3_ISP_CSI_PHY_H
 
+#include <media/omap3isp.h>
+
 struct isp_csi2_device;
 struct regulator;
 
-struct csiphy_lane {
-	u8 pos;
-	u8 pol;
-};
-
-#define ISP_CSIPHY2_NUM_DATA_LANES	2
-#define ISP_CSIPHY1_NUM_DATA_LANES	1
-
-struct isp_csiphy_lanes_cfg {
-	struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
-	struct csiphy_lane clk;
-};
-
 struct isp_csiphy_dphy_cfg {
 	u8 ths_term;
 	u8 ths_settle;
diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
index e917b1d..8fe0bdf 100644
--- a/include/media/omap3isp.h
+++ b/include/media/omap3isp.h
@@ -86,6 +86,19 @@ enum {
 	ISP_CCP2_MODE_CCP2 = 1,
 };
 
+struct csiphy_lane {
+	u8 pos;
+	u8 pol;
+};
+
+#define ISP_CSIPHY2_NUM_DATA_LANES	2
+#define ISP_CSIPHY1_NUM_DATA_LANES	1
+
+struct isp_csiphy_lanes_cfg {
+	struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
+	struct csiphy_lane clk;
+};
+
 /**
  * struct isp_ccp2_platform_data - CCP2 interface platform data
  * @strobe_clk_pol: Strobe/clock polarity
@@ -105,6 +118,7 @@ struct isp_ccp2_platform_data {
 	unsigned int ccp2_mode:1;
 	unsigned int phy_layer:1;
 	unsigned int vpclk_div:2;
+	struct isp_csiphy_lanes_cfg *lanecfg;
 };
 
 /**
@@ -115,6 +129,7 @@ struct isp_ccp2_platform_data {
 struct isp_csi2_platform_data {
 	unsigned crc:1;
 	unsigned vpclk_div:2;
+	struct isp_csiphy_lanes_cfg *lanecfg;
 };
 
 struct isp_subdev_i2c_board_info {
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (11 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 12/17] omap3isp: Add lane configuration to platform data Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2012-01-06 10:01   ` Laurent Pinchart
  2011-12-20 20:28 ` [RFC 14/17] omap3isp: Use pixelrate from sensor media bus frameformat Sakari Ailus
                   ` (4 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Configure CSI-2 phy based on platform data in the ISP driver rather than in
platform code.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/media/video/omap3isp/isp.c       |   38 ++++++++++++--
 drivers/media/video/omap3isp/isp.h       |    3 -
 drivers/media/video/omap3isp/ispcsiphy.c |   83 ++++++++++++++++++++++++++----
 drivers/media/video/omap3isp/ispcsiphy.h |    4 ++
 4 files changed, 111 insertions(+), 17 deletions(-)

diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
index b818cac..6020fd7 100644
--- a/drivers/media/video/omap3isp/isp.c
+++ b/drivers/media/video/omap3isp/isp.c
@@ -737,7 +737,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
 	struct isp_device *isp = pipe->output->isp;
 	struct media_entity *entity;
 	struct media_pad *pad;
-	struct v4l2_subdev *subdev;
+	struct v4l2_subdev *subdev = NULL, *prev_subdev;
 	unsigned long flags;
 	int ret;
 
@@ -759,11 +759,41 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
 			break;
 
 		entity = pad->entity;
+		prev_subdev = subdev;
 		subdev = media_entity_to_v4l2_subdev(entity);
 
-		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
-		if (ret < 0 && ret != -ENOIOCTLCMD)
-			return ret;
+		/* Configure CSI-2 receiver based on sensor format. */
+		if (prev_subdev == &isp->isp_csi2a.subdev
+		    || prev_subdev == &isp->isp_csi2c.subdev) {
+			struct v4l2_subdev_format fmt;
+
+			fmt.pad = pad->index;
+			fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+			ret = v4l2_subdev_call(subdev, pad, get_fmt,
+					       NULL, &fmt);
+			if (ret < 0)
+				return -EPIPE;
+
+			ret = omap3isp_csiphy_config(
+				isp, prev_subdev, subdev,
+				&fmt.format);
+			if (ret < 0)
+				return -EPIPE;
+
+			/* Start CSI-2 after configuration. */
+			ret = v4l2_subdev_call(prev_subdev, video,
+					       s_stream, mode);
+			if (ret < 0 && ret != -ENOIOCTLCMD)
+				return ret;
+		}
+
+		/* Start any other subdev except the CSI-2 receivers. */
+		if (subdev != &isp->isp_csi2a.subdev
+		    && subdev != &isp->isp_csi2c.subdev) {
+			ret = v4l2_subdev_call(subdev, video, s_stream, mode);
+			if (ret < 0 && ret != -ENOIOCTLCMD)
+				return ret;
+		}
 
 		if (subdev == &isp->isp_ccdc.subdev) {
 			v4l2_subdev_call(&isp->isp_aewb.subdev, video,
diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h
index 705946e..c5935ae 100644
--- a/drivers/media/video/omap3isp/isp.h
+++ b/drivers/media/video/omap3isp/isp.h
@@ -126,9 +126,6 @@ struct isp_reg {
 
 struct isp_platform_callback {
 	u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
-	int (*csiphy_config)(struct isp_csiphy *phy,
-			     struct isp_csiphy_dphy_cfg *dphy,
-			     struct isp_csiphy_lanes_cfg *lanes);
 	void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
 };
 
diff --git a/drivers/media/video/omap3isp/ispcsiphy.c b/drivers/media/video/omap3isp/ispcsiphy.c
index 5be37ce..f027ece 100644
--- a/drivers/media/video/omap3isp/ispcsiphy.c
+++ b/drivers/media/video/omap3isp/ispcsiphy.c
@@ -28,6 +28,8 @@
 #include <linux/device.h>
 #include <linux/regulator/consumer.h>
 
+#include "../../../../arch/arm/mach-omap2/control.h"
+
 #include "isp.h"
 #include "ispreg.h"
 #include "ispcsiphy.h"
@@ -138,15 +140,78 @@ static void csiphy_dphy_config(struct isp_csiphy *phy)
 	isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
 }
 
-static int csiphy_config(struct isp_csiphy *phy,
-			 struct isp_csiphy_dphy_cfg *dphy,
-			 struct isp_csiphy_lanes_cfg *lanes)
+/*
+ * TCLK values are OK at their reset values
+ */
+#define TCLK_TERM	0
+#define TCLK_MISS	1
+#define TCLK_SETTLE	14
+
+int omap3isp_csiphy_config(struct isp_device *isp,
+			   struct v4l2_subdev *csi2_subdev,
+			   struct v4l2_subdev *sensor,
+			   struct v4l2_mbus_framefmt *sensor_fmt)
 {
+	struct isp_v4l2_subdevs_group *subdevs = sensor->host_priv;
+	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(csi2_subdev);
+	struct isp_csiphy_dphy_cfg csi2phy;
+	int csi2_ddrclk_khz;
+	struct isp_csiphy_lanes_cfg *lanes;
 	unsigned int used_lanes = 0;
 	unsigned int i;
+	u32 cam_phy_ctrl;
+
+	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1
+	    || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
+		lanes = subdevs->bus.ccp2.lanecfg;
+	else
+		lanes = subdevs->bus.csi2.lanecfg;
+
+	if (!lanes) {
+		dev_err(isp->dev, "no lane configuration\n");
+		return -EINVAL;
+	}
+
+	cam_phy_ctrl = omap_readl(
+		OMAP343X_CTRL_BASE + OMAP3630_CONTROL_CAMERA_PHY_CTRL);
+	/*
+	 * SCM.CONTROL_CAMERA_PHY_CTRL
+	 * - bit[4]    : CSIPHY1 data sent to CSIB
+	 * - bit [3:2] : CSIPHY1 config: 00 d-phy, 01/10 ccp2
+	 * - bit [1:0] : CSIPHY2 config: 00 d-phy, 01/10 ccp2
+	 */
+	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1)
+		cam_phy_ctrl |= 1 << 2;
+	else if (subdevs->interface == ISP_INTERFACE_CSI2C_PHY1)
+		cam_phy_ctrl &= 1 << 2;
+
+	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
+		cam_phy_ctrl |= 1;
+	else if (subdevs->interface == ISP_INTERFACE_CSI2A_PHY2)
+		cam_phy_ctrl &= 1;
+
+	/* FIXME: Do 34xx / 35xx require something here? */
+	if (cpu_is_omap3630())
+		omap_writel(cam_phy_ctrl,
+			    OMAP343X_CTRL_BASE
+			    + OMAP3630_CONTROL_CAMERA_PHY_CTRL);
+
+	csi2_ddrclk_khz = sensor_fmt->pixelrate
+		/ (2 * csi2->phy->num_data_lanes)
+		* omap3isp_video_format_info(sensor_fmt->code)->bpp;
+
+	/*
+	 * THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1.
+	 * THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3.
+	 */
+	csi2phy.ths_term = DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1;
+	csi2phy.ths_settle = DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3;
+	csi2phy.tclk_term = TCLK_TERM;
+	csi2phy.tclk_miss = TCLK_MISS;
+	csi2phy.tclk_settle = TCLK_SETTLE;
 
 	/* Clock and data lanes verification */
-	for (i = 0; i < phy->num_data_lanes; i++) {
+	for (i = 0; i < csi2->phy->num_data_lanes; i++) {
 		if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
 			return -EINVAL;
 
@@ -162,10 +227,10 @@ static int csiphy_config(struct isp_csiphy *phy,
 	if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
 		return -EINVAL;
 
-	mutex_lock(&phy->mutex);
-	phy->dphy = *dphy;
-	phy->lanes = *lanes;
-	mutex_unlock(&phy->mutex);
+	mutex_lock(&csi2->phy->mutex);
+	csi2->phy->dphy = csi2phy;
+	csi2->phy->lanes = *lanes;
+	mutex_unlock(&csi2->phy->mutex);
 
 	return 0;
 }
@@ -225,8 +290,6 @@ int omap3isp_csiphy_init(struct isp_device *isp)
 	struct isp_csiphy *phy1 = &isp->isp_csiphy1;
 	struct isp_csiphy *phy2 = &isp->isp_csiphy2;
 
-	isp->platform_cb.csiphy_config = csiphy_config;
-
 	phy2->isp = isp;
 	phy2->csi2 = &isp->isp_csi2a;
 	phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES;
diff --git a/drivers/media/video/omap3isp/ispcsiphy.h b/drivers/media/video/omap3isp/ispcsiphy.h
index e93a661..9f93222 100644
--- a/drivers/media/video/omap3isp/ispcsiphy.h
+++ b/drivers/media/video/omap3isp/ispcsiphy.h
@@ -56,6 +56,10 @@ struct isp_csiphy {
 	struct isp_csiphy_dphy_cfg dphy;
 };
 
+int omap3isp_csiphy_config(struct isp_device *isp,
+			   struct v4l2_subdev *csi2_subdev,
+			   struct v4l2_subdev *sensor,
+			   struct v4l2_mbus_framefmt *fmt);
 int omap3isp_csiphy_acquire(struct isp_csiphy *phy);
 void omap3isp_csiphy_release(struct isp_csiphy *phy);
 int omap3isp_csiphy_init(struct isp_device *isp);
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 14/17] omap3isp: Use pixelrate from sensor media bus frameformat
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (12 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 13/17] omap3isp: Configure CSI-2 phy based on " Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2012-01-06 10:14   ` Laurent Pinchart
  2011-12-20 20:28 ` [RFC 15/17] omap3isp: Move definitions required by board code under include/media Sakari Ailus
                   ` (3 subsequent siblings)
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

Configure the ISP based on the pixelrate in media bus frame format.
Previously the same was configured from the board code.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/media/video/omap3isp/isp.c |   24 +++++++++++++++++++++---
 drivers/media/video/omap3isp/isp.h |    1 -
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
index 6020fd7..92f9716 100644
--- a/drivers/media/video/omap3isp/isp.c
+++ b/drivers/media/video/omap3isp/isp.c
@@ -749,10 +749,14 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
 
 	entity = &pipe->output->video.entity;
 	while (1) {
-		pad = &entity->pads[0];
-		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+		/*
+		 * Is this an external subdev connected to us? If so,
+		 * we're done.
+		 */
+		if (subdev && subdev->host_priv)
 			break;
 
+		pad = &entity->pads[0];
 		pad = media_entity_remote_source(pad);
 		if (pad == NULL ||
 		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
@@ -762,6 +766,21 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
 		prev_subdev = subdev;
 		subdev = media_entity_to_v4l2_subdev(entity);
 
+		/* Configure CCDC pixel clock */
+		if (subdev->host_priv) {
+			struct v4l2_subdev_format fmt;
+
+			fmt.pad = pad->index;
+			fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+			ret = v4l2_subdev_call(subdev, pad, get_fmt,
+					       NULL, &fmt);
+			if (ret < 0)
+				return -EINVAL;
+
+			isp_set_pixel_clock(isp,
+					    fmt.format.pixelrate * 1000);
+		}
+
 		/* Configure CSI-2 receiver based on sensor format. */
 		if (prev_subdev == &isp->isp_csi2a.subdev
 		    || prev_subdev == &isp->isp_csi2c.subdev) {
@@ -2102,7 +2121,6 @@ static int isp_probe(struct platform_device *pdev)
 
 	isp->autoidle = autoidle;
 	isp->platform_cb.set_xclk = isp_set_xclk;
-	isp->platform_cb.set_pixel_clock = isp_set_pixel_clock;
 
 	mutex_init(&isp->isp_mutex);
 	spin_lock_init(&isp->stat_lock);
diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h
index c5935ae..7d73a39 100644
--- a/drivers/media/video/omap3isp/isp.h
+++ b/drivers/media/video/omap3isp/isp.h
@@ -126,7 +126,6 @@ struct isp_reg {
 
 struct isp_platform_callback {
 	u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
-	void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
 };
 
 /*
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 15/17] omap3isp: Move definitions required by board code under include/media.
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (13 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 14/17] omap3isp: Use pixelrate from sensor media bus frameformat Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2011-12-20 20:28 ` [RFC 16/17] smiapp: Add driver Sakari Ailus
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

From: Sakari Ailus <sakari.ailus@iki.fi>

XCLK definitions are often required by the board code. Move them to public
include file.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/media/video/omap3isp/isp.h |    4 ----
 include/media/omap3isp.h           |    4 ++++
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h
index 7d73a39..dd1b61e 100644
--- a/drivers/media/video/omap3isp/isp.h
+++ b/drivers/media/video/omap3isp/isp.h
@@ -235,10 +235,6 @@ void omap3isp_configure_bridge(struct isp_device *isp,
 			       const struct isp_parallel_platform_data *pdata,
 			       unsigned int shift);
 
-#define ISP_XCLK_NONE			0
-#define ISP_XCLK_A			1
-#define ISP_XCLK_B			2
-
 struct isp_device *omap3isp_get(struct isp_device *isp);
 void omap3isp_put(struct isp_device *isp);
 
diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
index 8fe0bdf..deb3949 100644
--- a/include/media/omap3isp.h
+++ b/include/media/omap3isp.h
@@ -29,6 +29,10 @@
 struct i2c_board_info;
 struct isp_device;
 
+#define ISP_XCLK_NONE			0
+#define ISP_XCLK_A			1
+#define ISP_XCLK_B			2
+
 enum isp_interface_type {
 	ISP_INTERFACE_PARALLEL,
 	ISP_INTERFACE_CSI2A_PHY2,
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 16/17] smiapp: Add driver.
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (14 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 15/17] omap3isp: Move definitions required by board code under include/media Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2012-01-06 17:12   ` Sylwester Nawrocki
  2011-12-20 20:28 ` [RFC 17/17] rm680: Add camera init Sakari Ailus
  2011-12-28  9:47 ` [yavta PATCH 1/1] Support integer menus Sakari Ailus
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

Add driver for SMIA++/SMIA image sensors. The driver exposes the sensor as
three subdevs, pixel array, binner and scaler --- in case the device has a
scaler.

Currently it relies on the board code for external clock handling. There is
no fast way out of this dependency before the ISP drivers (omap3isp) among
others will be able to export that clock through the clock framework
instead.

Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
---
 drivers/media/video/Kconfig           |   13 +
 drivers/media/video/Makefile          |    3 +
 drivers/media/video/smiapp-core.c     | 2595 +++++++++++++++++++++++++++++++++
 drivers/media/video/smiapp-debug.h    |   32 +
 drivers/media/video/smiapp-limits.c   |  132 ++
 drivers/media/video/smiapp-limits.h   |  128 ++
 drivers/media/video/smiapp-pll.c      |  664 +++++++++
 drivers/media/video/smiapp-quirk.c    |  264 ++++
 drivers/media/video/smiapp-quirk.h    |   72 +
 drivers/media/video/smiapp-reg-defs.h |  733 ++++++++++
 drivers/media/video/smiapp-reg.h      |  119 ++
 drivers/media/video/smiapp-regs.c     |  222 +++
 drivers/media/video/smiapp.h          |  250 ++++
 include/media/smiapp-regs.h           |   51 +
 include/media/smiapp.h                |   82 +
 15 files changed, 5360 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/smiapp-core.c
 create mode 100644 drivers/media/video/smiapp-debug.h
 create mode 100644 drivers/media/video/smiapp-limits.c
 create mode 100644 drivers/media/video/smiapp-limits.h
 create mode 100644 drivers/media/video/smiapp-pll.c
 create mode 100644 drivers/media/video/smiapp-quirk.c
 create mode 100644 drivers/media/video/smiapp-quirk.h
 create mode 100644 drivers/media/video/smiapp-reg-defs.h
 create mode 100644 drivers/media/video/smiapp-reg.h
 create mode 100644 drivers/media/video/smiapp-regs.c
 create mode 100644 drivers/media/video/smiapp.h
 create mode 100644 include/media/smiapp-regs.h
 create mode 100644 include/media/smiapp.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4e8a0c4..0aa8f13 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -524,6 +524,19 @@ config VIDEO_S5K6AA
 	  This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
 	  camera sensor with an embedded SoC image signal processor.
 
+config VIDEO_SMIAPP
+	tristate "SMIA++/SMIA sensor support"
+	depends on I2C && VIDEO_V4L2
+	---help---
+	  This is a generic driver for SMIA++/SMIA camera modules.
+
+config VIDEO_SMIAPP_DEBUG
+	bool "Enable debugging for the generic SMIA++/SMIA driver"
+	depends on VIDEO_SMIAPP
+	---help---
+	  Enable debugging output in the generic SMIA++/SMIA driver. If you
+	  are developing the driver you might want to enable this.
+
 comment "Flash devices"
 
 config VIDEO_ADP1653
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ddeaa6c..82a0cea 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -73,6 +73,9 @@ obj-$(CONFIG_VIDEO_SR030PC30)	+= sr030pc30.o
 obj-$(CONFIG_VIDEO_NOON010PC30)	+= noon010pc30.o
 obj-$(CONFIG_VIDEO_M5MOLS)	+= m5mols/
 obj-$(CONFIG_VIDEO_S5K6AA)	+= s5k6aa.o
+smiapp-objs			+= smiapp-core.o smiapp-regs.o smiapp-pll.o \
+				   smiapp-quirk.o smiapp-limits.o
+obj-$(CONFIG_VIDEO_SMIAPP)	+= smiapp.o
 obj-$(CONFIG_VIDEO_ADP1653)	+= adp1653.o
 
 obj-$(CONFIG_SOC_CAMERA_IMX074)		+= imx074.o
diff --git a/drivers/media/video/smiapp-core.c b/drivers/media/video/smiapp-core.c
new file mode 100644
index 0000000..1d15c1d
--- /dev/null
+++ b/drivers/media/video/smiapp-core.c
@@ -0,0 +1,2595 @@
+/*
+ * drivers/media/video/smiapp-core.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010--2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Based on smiapp driver by Vimarsh Zutshi
+ * Based on jt8ev1.c by Vimarsh Zutshi
+ * Based on smia-sensor.c by Tuukka Toivonen <tuukkat76@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "smiapp-debug.h"
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+
+#include "smiapp.h"
+
+#define SMIAPP_ALIGN_DIM(dim, flags)	      \
+	(flags & V4L2_SUBDEV_SEL_FLAG_SIZE_GE \
+	 ? ALIGN(dim, 2)		      \
+	 : dim & ~1)
+
+/*
+ * smiapp_module_idents - supported camera modules
+ */
+static const struct smiapp_module_ident smiapp_module_idents[] = {
+	SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk),
+	SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk),
+	SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"),
+	SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"),
+	SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"),
+	SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk),
+	SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"),
+	SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"),
+	SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk),
+	SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"),
+	SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"),
+};
+
+/*
+ *
+ * Dynamic Capability Identification
+ *
+ */
+
+static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc;
+	int i;
+	int rval;
+	int line_count = 0;
+	int embedded_start = -1, embedded_end = -1;
+	int image_start = 0;
+
+	sensor->sof_rows = 0;
+	sensor->eof_rows = 0;
+
+	rval = smia_i2c_read_reg(client,
+				 SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE,
+				 &fmt_model_type);
+	if (rval)
+		return rval;
+
+	rval = smia_i2c_read_reg(client,
+				 SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE,
+				 &fmt_model_subtype);
+	if (rval)
+		return rval;
+
+	ncol_desc = (fmt_model_subtype
+		     & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK)
+		>> SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT;
+	nrow_desc = (fmt_model_subtype
+		     & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK);
+
+	dev_dbg(&client->dev, "format_model_type %s\n",
+		fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE
+		? "2 byte" :
+		fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE
+		? "4 byte" : "is simply bad");
+
+	for (i = 0; i < ncol_desc + nrow_desc; i++) {
+		u32 desc;
+		u32 pixelcode;
+		u32 pixels;
+		char *which;
+		char *what;
+
+		if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) {
+			rval = smia_i2c_read_reg(
+				client,
+				SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i),
+				&desc);
+			if (rval)
+				return rval;
+
+			pixelcode =
+				(desc
+				 & SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK)
+				>> SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT;
+			pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK;
+		} else if (fmt_model_type
+			   == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) {
+			rval = smia_i2c_read_reg(
+				client,
+				SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i),
+				&desc);
+			if (rval)
+				return rval;
+
+			pixelcode =
+				(desc
+				 & SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK)
+				>> SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT;
+			pixels = desc & SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK;
+		} else {
+			dev_dbg(&client->dev,
+				"invalid frame format model type %d\n",
+				fmt_model_type);
+			return -EINVAL;
+		}
+
+		if (i < ncol_desc)
+			which = "columns";
+		else
+			which = "rows";
+
+		switch (pixelcode) {
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED:
+			what = "embedded";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY:
+			what = "dummy";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK:
+			what = "black";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK:
+			what = "dark";
+			break;
+		case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE:
+			what = "visible";
+			break;
+		default:
+			what = "invalid";
+			dev_dbg(&client->dev, "pixelcode %d\n", pixelcode);
+			break;
+		}
+
+		dev_dbg(&client->dev, "%s pixels: %d %s\n",
+			what, pixels, which);
+
+		if (i < ncol_desc)
+			continue;
+
+		/* Handle row descriptors */
+		if (pixelcode
+		    == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED) {
+			embedded_start = line_count;
+		} else {
+			if (pixelcode
+			    == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE
+			    || pixels
+			    >= sensor->limits[
+				    SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES] / 2) {
+				image_start = line_count;
+			}
+			if (embedded_start != -1 && embedded_end == -1)
+				embedded_end = line_count;
+		}
+		line_count += pixels;
+	}
+
+	if (embedded_start == -1 || embedded_end == -1)
+		embedded_start = embedded_end = 0;
+
+	dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
+		embedded_start, embedded_end);
+	dev_dbg(&client->dev, "image data starts at line %d\n", image_start);
+
+	return 0;
+}
+
+/*
+ *
+ * V4L2 Controls handling
+ *
+ */
+
+static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
+{
+	struct v4l2_ctrl *ctrl = sensor->exposure;
+	int max;
+
+	max = sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].height
+		+ sensor->vblank->val -
+		sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
+
+	ctrl->maximum = max;
+	if (ctrl->default_value > max)
+		ctrl->default_value = max;
+	if (ctrl->val > max)
+		ctrl->val = max;
+	if (ctrl->cur.val > max)
+		ctrl->cur.val = max;
+}
+
+static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct smiapp_sensor *sensor =
+		container_of(ctrl->handler, struct smiapp_subdev, ctrl_handler)
+			->sensor;
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	u32 orient;
+	int exposure;
+	int rval = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN:
+		return smia_i2c_write_reg(
+			client,
+			SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL, ctrl->val);
+
+	case V4L2_CID_EXPOSURE:
+		return smia_i2c_write_reg(
+			client,
+			SMIAPP_REG_U16_COARSE_INTEGRATION_TIME, ctrl->val);
+
+	case V4L2_CID_HFLIP:
+	case V4L2_CID_VFLIP:
+		orient = 0;
+
+		if (sensor->hflip->val)
+			orient |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
+
+		if (sensor->vflip->val)
+			orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+		orient ^= sensor->hvflip_inv_mask;
+		return smia_i2c_write_reg(client,
+					  SMIAPP_REG_U8_IMAGE_ORIENTATION,
+					  orient);
+
+	case V4L2_CID_IMAGE_SOURCE_VBLANK:
+		exposure = sensor->exposure->val;
+
+		__smiapp_update_exposure_limits(sensor);
+
+		if (exposure > sensor->exposure->maximum) {
+			sensor->exposure->val =
+				sensor->exposure->maximum;
+			rval = smiapp_set_ctrl(
+				sensor->exposure);
+		}
+
+		if (rval < 0)
+			return rval;
+
+		return smia_i2c_write_reg(
+			client, SMIAPP_REG_U16_FRAME_LENGTH_LINES,
+			sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].height
+			+ ctrl->val);
+
+	case V4L2_CID_IMAGE_SOURCE_HBLANK:
+		return smia_i2c_write_reg(
+			client, SMIAPP_REG_U16_LINE_LENGTH_PCK,
+			sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].width
+			+ ctrl->val);
+
+	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:
+		return smiapp_pll_update(sensor);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
+	.s_ctrl = smiapp_set_ctrl,
+};
+
+static int smiapp_init_controls(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct v4l2_ctrl_config cfg;
+	int rval;
+
+	rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 6);
+	if (rval)
+		return rval;
+
+	sensor->analog_gain = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN,
+		sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN],
+		sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX],
+		max_t(int,
+		      sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1),
+		sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]);
+
+	sensor->exposure = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_EXPOSURE,
+		sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN],
+		sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN], 1,
+		sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN]);
+
+	sensor->hflip = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_HFLIP, 0, 1, 1, 0);
+	sensor->vflip = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	sensor->vblank = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_IMAGE_SOURCE_VBLANK, 0, 1, 1, 0);
+
+	if (sensor->vblank)
+		sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+	sensor->hblank = v4l2_ctrl_new_std(
+		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_IMAGE_SOURCE_HBLANK, 0, 1, 1, 0);
+
+	if (sensor->hblank)
+		sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+	memset(&cfg, 0, sizeof(cfg));
+
+	cfg.ops = &smiapp_ctrl_ops;
+	cfg.id = V4L2_CID_IMAGE_SOURCE_LINK_FREQ;
+	cfg.type = V4L2_CTRL_TYPE_INTEGER_MENU;
+	while (sensor->platform_data->op_sys_clock[cfg.max])
+		cfg.max++;
+	cfg.max--;
+	cfg.qmenu_int = sensor->platform_data->op_sys_clock;
+
+	sensor->link_freq = v4l2_ctrl_new_custom(
+		&sensor->pixel_array->ctrl_handler, &cfg, NULL);
+
+	if (sensor->pixel_array->ctrl_handler.error) {
+		dev_err(&client->dev, "controls initialization failed (%d)\n",
+			sensor->pixel_array->ctrl_handler.error);
+		return sensor->pixel_array->ctrl_handler.error;
+	}
+
+	v4l2_ctrl_cluster(2, &sensor->hflip);
+
+	sensor->pixel_array->sd.ctrl_handler =
+		&sensor->pixel_array->ctrl_handler;
+
+	rval = v4l2_ctrl_handler_init(
+		&sensor->binner->ctrl_handler, 0);
+	if (rval)
+		return rval;
+
+	sensor->binner->sd.ctrl_handler =
+		&sensor->binner->ctrl_handler;
+
+	if (sensor->scaler) {
+		rval = v4l2_ctrl_handler_init(
+			&sensor->scaler->ctrl_handler, 0);
+		if (rval)
+			return rval;
+
+		sensor->scaler->sd.ctrl_handler =
+			&sensor->scaler->ctrl_handler;
+	}
+
+	return 0;
+}
+
+static void smiapp_free_controls(struct smiapp_sensor *sensor)
+{
+	int i;
+
+	for (i = 0; i < sensor->sds_used; i++)
+		v4l2_ctrl_handler_free(&sensor->sds[i].ctrl_handler);
+}
+
+static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = {
+	{ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, },
+	{ V4L2_MBUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, },
+	{ V4L2_MBUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, },
+	{ V4L2_MBUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, },
+	{ V4L2_MBUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, },
+	{ V4L2_MBUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, },
+};
+
+static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
+			     int n)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int i, val;
+	int rval;
+
+	for (i = 0; i < n; i++) {
+		rval = smia_i2c_read_reg(
+			client, smiapp_reg_limits[limit[i]].addr, &val);
+		if (rval) {
+			dev_dbg(&client->dev, "error reading register %4.4x\n",
+				(u16)smiapp_reg_limits[limit[i]].addr);
+			return rval;
+		}
+		sensor->limits[limit[i]] = val;
+		dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n",
+			smiapp_reg_limits[limit[i]].addr,
+			smiapp_reg_limits[limit[i]].what, val, val);
+	}
+
+	return 0;
+}
+
+static int smiapp_get_all_limits(struct smiapp_sensor *sensor)
+{
+	int rval, i;
+
+	for (i = 0; i < SMIAPP_LIMIT_LAST; i++) {
+		rval = smiapp_get_limits(sensor, &i, 1);
+		if (rval < 0)
+			return rval;
+	}
+
+	if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0)
+		smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16);
+
+	return 0;
+}
+
+static int smiapp_get_limits_binning(struct smiapp_sensor *sensor)
+{
+	static u32 const limits[] = {
+		SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN,
+		SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN,
+		SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN,
+		SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN,
+		SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN,
+	};
+	static u32 const limits_replace[] = {
+		SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES,
+		SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES,
+		SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK,
+		SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK,
+		SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN,
+		SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN,
+	};
+
+	if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY] ==
+	    SMIAPP_BINNING_CAPABILITY_NO) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(limits); i++)
+			sensor->limits[limits[i]] =
+				sensor->limits[limits_replace[i]];
+
+		return 0;
+	}
+
+	return smiapp_get_limits(sensor, limits, ARRAY_SIZE(limits));
+}
+
+static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	unsigned int type, n;
+	int i, rval, pixel_order;
+	const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
+
+	rval = smia_i2c_read_reg(
+		client, SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE, &type);
+	if (rval)
+		return rval;
+
+	dev_dbg(&client->dev, "data_format_model_type %d\n", type);
+
+	rval = smia_i2c_read_reg(client, SMIAPP_REG_U8_PIXEL_ORDER,
+				 &pixel_order);
+	if (rval)
+		return rval;
+
+	if (pixel_order >= ARRAY_SIZE(pixel_order_str)) {
+		dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order);
+		return -EINVAL;
+	}
+
+	dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order,
+		pixel_order_str[pixel_order]);
+
+	switch (type) {
+	case SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL:
+		n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N;
+		break;
+	case SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED:
+		n = SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	sensor->mbus_frame_fmts = 0;
+
+	for (i = 0; i < n; i++) {
+		int fmt, j;
+
+		rval = smia_i2c_read_reg(
+			client,
+			SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(i), &fmt);
+		if (rval)
+			return rval;
+
+		dev_dbg(&client->dev, "bpp %d, compressed %d\n",
+			fmt >> 8, (u8)fmt);
+
+		for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) {
+			const struct smiapp_csi_data_format *f =
+				&smiapp_csi_data_formats[j];
+
+			if (f->pixel_order != pixel_order)
+				continue;
+
+			if (f->width != fmt >> 8 || f->compressed != (u8)fmt)
+				continue;
+
+			dev_dbg(&client->dev, "jolly good! %d\n", j);
+
+			sensor->mbus_frame_fmts |= 1 << j;
+			if (!sensor->csi_format)
+				sensor->csi_format = f;
+		}
+	}
+
+	if (!sensor->csi_format) {
+		dev_err(&client->dev, "no supported mbus code found\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void __smiapp_update_blanking(struct smiapp_sensor *sensor)
+{
+	struct v4l2_ctrl *vblank = sensor->vblank, *hblank = sensor->hblank;
+
+	vblank->minimum =
+		max_t(int,
+		      sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
+		      sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
+		      sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].height);
+	vblank->maximum =
+		sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
+		sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].height;
+
+	vblank->val = clamp_t(int, vblank->val,
+			      vblank->minimum, vblank->maximum);
+	vblank->default_value = vblank->minimum;
+	vblank->val = vblank->val;
+	vblank->cur.val = vblank->val;
+
+	hblank->minimum =
+		max_t(int,
+		      sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
+		      sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].width,
+		      sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
+	hblank->maximum =
+		sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
+		sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].width;
+
+	hblank->val = clamp_t(int, hblank->val,
+			      hblank->minimum, hblank->maximum);
+	hblank->default_value = hblank->minimum;
+	hblank->val = hblank->val;
+	hblank->cur.val = hblank->val;
+
+	__smiapp_update_exposure_limits(sensor);
+}
+
+static void smiapp_update_blanking(struct smiapp_sensor *sensor)
+{
+	v4l2_ctrl_lock(sensor->vblank);
+	__smiapp_update_blanking(sensor);
+	v4l2_ctrl_unlock(sensor->vblank);
+}
+
+static int smiapp_update_mode(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int binning_mode;
+	int rval;
+
+	dev_dbg(&client->dev, "frame size: %dx%d\n",
+		sensor->src->crop[SMIAPP_PAD_SOURCE].width,
+		sensor->src->crop[SMIAPP_PAD_SOURCE].height);
+	dev_dbg(&client->dev, "csi format width: %d\n",
+		sensor->csi_format->width);
+
+	/* Binning has to be set up here; it affects limits */
+	if (sensor->binning_horizontal == 1 &&
+	    sensor->binning_vertical == 1) {
+		binning_mode = 0;
+	} else {
+		u8 binning_type =
+			(sensor->binning_horizontal << 4)
+			| sensor->binning_vertical;
+
+		rval = smia_i2c_write_reg(
+			client, SMIAPP_REG_U8_BINNING_TYPE, binning_type);
+		if (rval < 0)
+			return rval;
+
+		binning_mode = 1;
+	}
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U8_BINNING_MODE, binning_mode);
+	if (rval < 0)
+		return rval;
+
+	/* Get updated limits due to binning */
+	rval = smiapp_get_limits_binning(sensor);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_pll_update(sensor);
+	if (rval < 0)
+		return rval;
+
+	/* Output from pixel array, including blanking */
+	smiapp_update_blanking(sensor);
+
+	dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val);
+	dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val);
+
+	dev_dbg(&client->dev, "real timeperframe\t100/%d\n",
+		sensor->pll.vt_pix_clk_freq_hz /
+		((sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].width
+		  + sensor->hblank->val) *
+		 (sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].height
+		  + sensor->vblank->val) / 100));
+
+	return 0;
+}
+
+/*
+ *
+ * SMIA++ NVM handling
+ *
+ */
+static int smiapp_read_nvm(struct smiapp_sensor *sensor,
+			   unsigned char *nvm)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	u32 i, s, p, np, v;
+	int rval;
+
+	np = sensor->nvm_size / SMIAPP_NVM_PAGE_SIZE;
+	for (p = 0; p < np; p++) {
+		rval = smia_i2c_write_reg(
+			client,
+			SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p);
+		if (rval)
+			goto out;
+
+		rval = smia_i2c_write_reg(client,
+					  SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL,
+					  SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN |
+					  SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN);
+		if (rval)
+			goto out;
+
+		i = 1000;
+		do {
+			rval = smia_i2c_read_reg(client,
+				SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s);
+
+			if (rval)
+				goto out;
+
+			if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
+				break;
+
+			if (--i == 0)
+				goto out;
+
+		} while (1);
+
+		for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) {
+			rval = smia_i2c_read_reg(client,
+				SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i,
+				&v);
+			if (rval)
+				goto out;
+
+			*nvm++ = v;
+		}
+	}
+
+out:
+	rval |= smia_i2c_write_reg(client,
+				   SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0);
+	return rval;
+}
+
+/*
+ *
+ * SMIA++ CCI address control
+ *
+ */
+static int smiapp_change_cci_addr(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+	u32 val;
+
+	client->addr = sensor->platform_data->i2c_addr_dfl;
+
+	rval = smia_i2c_write_reg(client,
+				  SMIAPP_REG_U8_CCI_ADDRESS_CONTROL,
+				  sensor->platform_data->i2c_addr_alt << 1);
+	if (rval) {
+		client->addr = sensor->platform_data->i2c_addr_alt;
+		return rval;
+	}
+
+	client->addr = sensor->platform_data->i2c_addr_alt;
+
+	/* verify addr change went ok */
+	rval = smia_i2c_read_reg(client,
+				 SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val);
+	if (rval)
+		return rval;
+
+	if (val != sensor->platform_data->i2c_addr_alt << 1)
+		return -ENODEV;
+
+	return 0;
+}
+
+/*
+ *
+ * SMIA++ Mode Control
+ *
+ */
+static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct smiapp_flash_strobe_parms *strobe_setup;
+	unsigned int ext_freq = sensor->platform_data->ext_clk;
+	int rval;
+	u32 tmp;
+	u32 strobe_adjustment;
+	u32 strobe_width_high_rs;
+
+	strobe_setup = sensor->platform_data->strobe_setup;
+
+	/*
+	 * How to calculate registers related to strobe length. Please
+	 * do not change, or if you do at least know what you're
+	 * doing. :-)
+	 *
+	 * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25
+	 *
+	 * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl
+	 *	/ EXTCLK freq [Hz]) * flash_strobe_adjustment
+	 *
+	 * tFlash_strobe_width_ctrl E N, [1 - 0xffff]
+	 * flash_strobe_adjustment E N, [1 - 0xff]
+	 *
+	 * The formula above is written as below to keep it on one
+	 * line:
+	 *
+	 * l / 10^6 = w / e * a
+	 *
+	 * Let's mark w * a by x:
+	 *
+	 * x = w * a
+	 *
+	 * Thus, we get:
+	 *
+	 * x = l * e / 10^6
+	 *
+	 * The strobe width must be at least as long as requested,
+	 * thus rounding upwards is needed.
+	 *
+	 * x = (l * e + 10^6 - 1) / 10^6
+	 * -----------------------------
+	 *
+	 * Maximum possible accuracy is wanted at all times. Thus keep
+	 * a as small as possible.
+	 *
+	 * Calculate a, assuming maximum w, with rounding upwards:
+	 *
+	 * a = (x + (2^16 - 1) - 1) / (2^16 - 1)
+	 * -------------------------------------
+	 *
+	 * Thus, we also get w, with that a, with rounding upwards:
+	 *
+	 * w = (x + a - 1) / a
+	 * -------------------
+	 *
+	 * To get limits:
+	 *
+	 * x E [1, (2^16 - 1) * (2^8 - 1)]
+	 *
+	 * Substituting maximum x to the original formula (with rounding),
+	 * the maximum l is thus
+	 *
+	 * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1
+	 *
+	 * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e
+	 * --------------------------------------------------
+	 *
+	 * flash_strobe_length must be clamped between 1 and
+	 * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq.
+	 *
+	 * Then,
+	 *
+	 * flash_strobe_adjustment = ((flash_strobe_length *
+	 *	EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1)
+	 *
+	 * tFlash_strobe_width_ctrl = ((flash_strobe_length *
+	 *	EXTCLK freq + 10^6 - 1) / 10^6 +
+	 *	flash_strobe_adjustment - 1) / flash_strobe_adjustment
+	 */
+	tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) -
+		      1000000 + 1, ext_freq);
+	strobe_setup->strobe_width_high_us =
+		clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp);
+
+	tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq +
+			1000000 - 1), 1000000ULL);
+	strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1);
+	strobe_width_high_rs = (tmp + strobe_adjustment - 1) /
+				strobe_adjustment;
+
+	rval = smia_i2c_write_reg(client,
+				  SMIAPP_REG_U8_FLASH_MODE_RS,
+				  strobe_setup->mode);
+	if (rval < 0)
+		goto out;
+
+	rval = smia_i2c_write_reg(client,
+				  SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT,
+				  strobe_adjustment);
+	if (rval < 0)
+		goto out;
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL,
+		strobe_width_high_rs);
+	if (rval < 0)
+		goto out;
+
+	rval = smia_i2c_write_reg(client,
+				  SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL,
+				  strobe_setup->strobe_delay);
+	if (rval < 0)
+		goto out;
+
+	rval = smia_i2c_write_reg(client,
+				  SMIAPP_REG_U16_FLASH_STROBE_START_POINT,
+				  strobe_setup->stobe_start_point);
+	if (rval < 0)
+		goto out;
+
+	rval = smia_i2c_write_reg(client,
+				  SMIAPP_REG_U8_FLASH_TRIGGER_RS,
+				  strobe_setup->trigger);
+
+out:
+	sensor->platform_data->strobe_setup->trigger = 0;
+
+	return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+static int smiapp_power_on(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int sleep;
+	int rval;
+
+	rval = regulator_enable(sensor->vana);
+	if (rval) {
+		dev_err(&client->dev, "failed to enable vana regulator\n");
+		return rval;
+	}
+	usleep_range(1000, 1000);
+
+	rval = sensor->platform_data->set_xclk(&sensor->src->sd,
+					sensor->platform_data->ext_clk);
+	if (rval < 0) {
+		dev_dbg(&client->dev, "failed to set xclk\n");
+		goto out_xclk_fail;
+	}
+	usleep_range(1000, 1000);
+
+	if (sensor->platform_data->set_xshutdown) {
+		rval = sensor->platform_data->set_xshutdown(
+			&sensor->src->sd, 1);
+		if (rval) {
+			dev_err(&client->dev, "sensor xshutdown failed\n");
+			goto out_xshut_fail;
+		}
+	}
+
+	sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk);
+	usleep_range(sleep, sleep);
+
+	/*
+	 * Failures to respond to the address change command have been noticed.
+	 * Those failures seem to be caused by the sensor requiring a longer
+	 * boot time than advertised. An additional 10ms delay seems to work
+	 * around the issue, but the SMIA++ I2C write retry hack makes the delay
+	 * unnecessary. The failures need to be investigated to find a proper
+	 * fix, and a delay will likely need to be added here if the I2C write
+	 * retry hack is reverted before the root cause of the boot time issue
+	 * is found.
+	 */
+
+	if (sensor->platform_data->i2c_addr_alt) {
+		rval = smiapp_change_cci_addr(sensor);
+		if (rval) {
+			dev_err(&client->dev, "cci address change error\n");
+			goto out_cci_addr_fail;
+		}
+	}
+
+	rval = smia_i2c_write_reg(client, SMIAPP_REG_U8_SOFTWARE_RESET,
+				  SMIAPP_SOFTWARE_RESET);
+	if (rval < 0) {
+		dev_err(&client->dev, "software reset failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	if (sensor->platform_data->i2c_addr_alt) {
+		rval = smiapp_change_cci_addr(sensor);
+		if (rval) {
+			dev_err(&client->dev, "cci address change error\n");
+			goto out_cci_addr_fail;
+		}
+	}
+
+	rval = smia_i2c_write_reg(client,
+				  SMIAPP_REG_U16_COMPRESSION_MODE,
+				  SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR);
+	if (rval) {
+		dev_err(&client->dev, "compression mode set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ,
+		sensor->platform_data->ext_clk / (1000000 / (1 << 8)));
+	if (rval) {
+		dev_err(&client->dev, "extclk frequency set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U8_CSI_LANE_MODE,
+		sensor->platform_data->lanes - 1);
+	if (rval) {
+		dev_err(&client->dev, "csi lane mode set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smia_i2c_write_reg(client, SMIAPP_REG_U8_FAST_STANDBY_CTRL, 1);
+	if (rval) {
+		dev_err(&client->dev, "fast standby set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	/* DPHY control done by sensor based on requested link rate */
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U8_DPHY_CTRL, SMIAPP_DPHY_CTRL_UI);
+	if (rval < 0) {
+		dev_err(&client->dev, "set dphy_ctrl_ui failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	rval = smia_i2c_write_reg(client, SMIAPP_REG_U8_CSI_SIGNALLING_MODE,
+				  SMIAPP_CSI_SIGNALLING_MODE_CSI2);
+	if (rval) {
+		dev_err(&client->dev, "csi signalling mode set failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	/* DPHY control done by sensor based on requested link rate */
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U8_DPHY_CTRL, SMIAPP_DPHY_CTRL_UI);
+	if (rval < 0)
+		return rval;
+
+	rval = smiapp_call_quirk(sensor, post_poweron);
+	if (rval) {
+		dev_err(&client->dev, "post_poweron quirks failed\n");
+		goto out_cci_addr_fail;
+	}
+
+	return 0;
+
+out_cci_addr_fail:
+	if (sensor->platform_data->set_xshutdown)
+		sensor->platform_data->set_xshutdown(&sensor->src->sd, 0);
+out_xshut_fail:
+	sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+out_xclk_fail:
+	regulator_disable(sensor->vana);
+	return rval;
+}
+
+static void smiapp_power_off(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+	/*
+	 * Currently power/clock to lens are enable/disabled separately
+	 * but they are essentially the same signals. So if the sensor is
+	 * powered off while the lens is powered on the sensor does not
+	 * really see a power off and next time the cci address change
+	 * will fail. So do a soft reset explicitly here.
+	 */
+	if (sensor->platform_data->i2c_addr_alt)
+		smia_i2c_write_reg(client,
+				   SMIAPP_REG_U8_SOFTWARE_RESET,
+				   SMIAPP_SOFTWARE_RESET);
+
+	if (sensor->platform_data->set_xshutdown)
+		sensor->platform_data->set_xshutdown(&sensor->src->sd, 0);
+	sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+	usleep_range(5000, 5000);
+	regulator_disable(sensor->vana);
+	sensor->streaming = 0;
+}
+
+static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int ret = 0;
+
+	mutex_lock(&sensor->power_lock);
+
+	/* If the power count is modified from 0 to != 0 or from != 0 to 0,
+	 * update the power state.
+	 */
+	if (sensor->power_count == !on) {
+		if (on) {
+			ret = smiapp_power_on(sensor);
+			if (ret < 0)
+				goto done;
+			ret = smiapp_update_mode(sensor);
+		} else {
+			smiapp_power_off(sensor);
+		}
+		if (ret < 0)
+			goto done;
+	}
+
+	/* Update the power count. */
+	sensor->power_count += on ? 1 : -1;
+	WARN_ON(sensor->power_count < 0);
+
+done:
+	mutex_unlock(&sensor->power_lock);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Video stream management
+ */
+
+static int smiapp_start_streaming(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int vblank, hblank;
+	int rval, i;
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_CSI_DATA_FORMAT,
+		(sensor->csi_format->width << 8) |
+		sensor->csi_format->compressed);
+	if (rval)
+		goto fail_sensor_cfg;
+
+	rval = smiapp_pll_configure(sensor);
+	if (rval)
+		return rval;
+
+	/* Analog crop start coordinates */
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_X_ADDR_START,
+		sensor->pixel_array->crop[SMIAPP_PAD_SOURCE].left);
+	if (rval < 0)
+		return rval;
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_Y_ADDR_START,
+		sensor->pixel_array->crop[SMIAPP_PAD_SOURCE].top);
+	if (rval < 0)
+		return rval;
+
+	/* Analog crop end coordinates */
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_X_ADDR_END,
+		sensor->pixel_array->crop[SMIAPP_PAD_SOURCE].left
+		+ sensor->pixel_array->crop[SMIAPP_PAD_SOURCE].width - 1);
+	if (rval < 0)
+		return rval;
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_Y_ADDR_END,
+		sensor->pixel_array->crop[SMIAPP_PAD_SOURCE].top
+		+ sensor->pixel_array->crop[SMIAPP_PAD_SOURCE].height - 1);
+	if (rval < 0)
+		return rval;
+
+	v4l2_ctrl_lock(sensor->vblank);
+	vblank = sensor->vblank->cur.val;
+	hblank = sensor->hblank->cur.val;
+	v4l2_ctrl_unlock(sensor->vblank);
+
+	/*
+	 * Output from pixel array, including blanking, is set using
+	 * controls below. No need to set here.
+	 */
+
+	/* Digital crop */
+	if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+	    == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+		rval = smia_i2c_write_reg(
+			client, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].left);
+		if (rval < 0)
+			return rval;
+
+		rval = smia_i2c_write_reg(
+			client, SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].top);
+		if (rval < 0)
+			return rval;
+
+		rval = smia_i2c_write_reg(
+			client, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].width);
+		if (rval < 0)
+			return rval;
+
+		rval = smia_i2c_write_reg(
+			client, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT,
+			sensor->scaler->crop[SMIAPP_PAD_SINK].height);
+		if (rval < 0)
+			return rval;
+	}
+
+	/* Scaling */
+	if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+	    != SMIAPP_SCALING_CAPABILITY_NONE) {
+		rval = smia_i2c_write_reg(
+			client, SMIAPP_REG_U16_SCALING_MODE,
+			sensor->scaling_mode);
+		if (rval < 0)
+			return rval;
+
+		if (sensor->scale_m
+		    != sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) {
+			rval = smia_i2c_write_reg(
+				client, SMIAPP_REG_U16_SCALE_M,
+				sensor->scale_m);
+			if (rval < 0)
+				return rval;
+		}
+	}
+
+	/* Output size from sensor */
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_X_OUTPUT_SIZE,
+		sensor->src->crop[SMIAPP_PAD_SOURCE].width);
+	if (rval < 0)
+		return rval;
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_Y_OUTPUT_SIZE,
+		sensor->src->crop[SMIAPP_PAD_SOURCE].height);
+	if (rval < 0)
+		return rval;
+
+	/* Controls set while the power to the sensor is turned off are saved
+	 * but not applied to the hardware. Now that we're about to start
+	 * streaming apply all the current values to the hardware.
+	 */
+	for (i = 0; i < sensor->sds_used; i++) {
+		rval = v4l2_ctrl_handler_setup(&sensor->sds[i].ctrl_handler);
+		if (rval)
+			goto fail_sensor_cfg;
+	}
+
+	if ((sensor->flash_capability &
+	     (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
+	      SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
+	    sensor->platform_data->strobe_setup != NULL &&
+	    sensor->platform_data->strobe_setup->trigger != 0) {
+		rval = smiapp_setup_flash_strobe(sensor);
+		if (rval)
+			goto fail_sensor_cfg;
+	}
+
+	rval = smiapp_call_quirk(sensor, pre_streamon);
+	if (rval) {
+		dev_err(&client->dev, "pre_streamon quirks failed\n");
+		goto fail_sensor_cfg;
+	}
+
+	return smia_i2c_write_reg(client, SMIAPP_REG_U8_MODE_SELECT,
+				  SMIAPP_MODE_SELECT_STREAMING);
+
+fail_sensor_cfg:
+	dev_err(&client->dev, "sensor configuration failed\n");
+	return rval;
+}
+
+static int smiapp_stop_streaming(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	rval = smia_i2c_write_reg(client, SMIAPP_REG_U8_MODE_SELECT,
+		SMIAPP_MODE_SELECT_SOFTWARE_STANDBY);
+	if (rval)
+		return rval;
+
+	rval = smiapp_call_quirk(sensor, post_streamoff);
+	if (rval)
+		dev_err(&client->dev, "post_streamoff quirks failed\n");
+	return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	if (sensor->streaming == enable)
+		return 0;
+
+	if (enable)
+		rval = smiapp_start_streaming(sensor);
+	else
+		rval = smiapp_stop_streaming(sensor);
+
+	if (rval == 0)
+		sensor->streaming = enable;
+
+	return rval;
+}
+
+static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int i, idx = -1;
+
+	for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+		if (sensor->mbus_frame_fmts & (1 << i))
+			idx++;
+
+		if (idx == code->index) {
+			code->code = smiapp_csi_data_formats[i].code;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int smiapp_get_format(struct v4l2_subdev *subdev,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+	} else {
+		struct v4l2_rect *r;
+
+		if (fmt->pad == SMIAPP_PAD_SOURCE)
+			r = &ssd->compose[fmt->pad];
+		else
+			r = &ssd->sink_fmt;
+
+		fmt->format.width = r->width;
+		fmt->format.height = r->height;
+		fmt->format.code = sensor->csi_format->code;
+		fmt->format.pixelrate = ssd->pixelrate[fmt->pad];
+	}
+
+	return 0;
+}
+
+static void smiapp_propagate(struct v4l2_subdev *subdev,
+			     struct v4l2_subdev_fh *fh, int which,
+			     int pad, int target)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comps, *crops;
+	int whence;
+
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		crops = ssd->crop;
+		comps = ssd->compose;
+	} else {
+		crops = fh->try_crop;
+		comps = fh->try_compose;
+	}
+
+#define SMIAPP_PIPE_SINK_COMPOSE	1
+#define SMIAPP_PIPE_SINK_CROP		2
+#define SMIAPP_PIPE_SOURCE_COMPOSE	3
+	if (pad == SMIAPP_PAD_SINK) {
+		if (target == V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE)
+			whence = SMIAPP_PIPE_SINK_COMPOSE;
+		else if (target == V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE)
+			whence = SMIAPP_PIPE_SINK_CROP;
+		else
+			BUG();
+	} else {
+		if (target == V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE)
+			whence = SMIAPP_PIPE_SOURCE_COMPOSE;
+		else if (target == V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE)
+			return;
+		else
+			BUG();
+	}
+
+	switch (whence) {
+	case SMIAPP_PIPE_SINK_CROP:
+		comps[SMIAPP_PAD_SINK].width =
+			crops[SMIAPP_PAD_SINK].width;
+		comps[SMIAPP_PAD_SINK].height =
+			crops[SMIAPP_PAD_SINK].height;
+		if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+			if (ssd == sensor->scaler) {
+				sensor->scale_m =
+					sensor->limits[
+						SMIAPP_LIMIT_SCALER_N_MIN];
+				sensor->scaling_mode =
+					SMIAPP_SCALING_MODE_NONE;
+			} else if (ssd == sensor->binner) {
+				sensor->binning_horizontal = 1;
+				sensor->binning_vertical = 1;
+			}
+		}
+	case SMIAPP_PIPE_SINK_COMPOSE:
+		crops[SMIAPP_PAD_SOURCE] = comps[SMIAPP_PAD_SINK];
+	case SMIAPP_PIPE_SOURCE_COMPOSE:
+		comps[SMIAPP_PAD_SOURCE] = crops[SMIAPP_PAD_SOURCE];
+
+	}
+}
+
+static int smiapp_set_format(struct v4l2_subdev *subdev,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comps, *crops;
+	int i = 0;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		crops = ssd->crop;
+		comps = ssd->compose;
+	} else {
+		crops = fh->try_crop;
+		comps = fh->try_compose;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+		if (sensor->mbus_frame_fmts & (1 << i) &&
+		    smiapp_csi_data_formats[i].code == fmt->format.code) {
+			if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+				sensor->csi_format =
+					&smiapp_csi_data_formats[i];
+			break;
+		}
+	}
+
+	if (i < ARRAY_SIZE(smiapp_csi_data_formats))
+		fmt->format.code = smiapp_csi_data_formats[i].code;
+	else
+		fmt->format.code = sensor->csi_format->code;
+
+	if (fmt->pad == SMIAPP_PAD_SOURCE)
+		return smiapp_get_format(subdev, fh, fmt);
+
+	fmt->format.width &= ~1;
+	fmt->format.height &= ~1;
+
+	if (fmt->format.width < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
+		fmt->format.width =
+			sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
+	if (fmt->format.height
+	    < sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE])
+		fmt->format.height =
+			sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE];
+
+	crops[SMIAPP_PAD_SINK].left = crops[SMIAPP_PAD_SINK].top = 0;
+	crops[SMIAPP_PAD_SINK].width = fmt->format.width;
+	crops[SMIAPP_PAD_SINK].height = fmt->format.height;
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		ssd->sink_fmt = crops[SMIAPP_PAD_SINK];
+	smiapp_propagate(subdev, fh, fmt->which, SMIAPP_PAD_SINK,
+			 V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE);
+
+	return 0;
+}
+
+#define SCALING_GOODNESS		100000
+#define SCALING_GOODNESS_EXTREME	100000000
+static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
+			    int h, int ask_h, u32 flags)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	int val = 0;
+
+	w &= ~1;
+	ask_w &= ~1;
+	h &= ~1;
+	ask_h &= ~1;
+
+	if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_GE) {
+		if (w < ask_w)
+			val -= SCALING_GOODNESS;
+		if (h < ask_h)
+			val -= SCALING_GOODNESS;
+	}
+
+	if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_LE) {
+		if (w > ask_w)
+			val -= SCALING_GOODNESS;
+		if (h > ask_h)
+			val -= SCALING_GOODNESS;
+	}
+
+	val -= abs(w - ask_w);
+	val -= abs(h - ask_h);
+
+	if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
+		val -= SCALING_GOODNESS_EXTREME;
+
+	dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
+		w, ask_h, h, ask_h, val);
+
+	return val;
+}
+
+/* We're only called on source pads. This function sets scaling. */
+static int smiapp_set_compose(struct v4l2_subdev *subdev,
+			      struct v4l2_subdev_fh *fh,
+			      struct v4l2_subdev_selection *sel)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comps, *crops;
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		crops = ssd->crop;
+		comps = ssd->compose;
+	} else {
+		crops = fh->try_crop;
+		comps = fh->try_compose;
+	}
+
+	sel->r.top = 0;
+	sel->r.left = 0;
+
+	if (ssd == sensor->binner) {
+		int i;
+		int binh = 1, binv = 1;
+		int best = scaling_goodness(
+			subdev,
+			crops[SMIAPP_PAD_SINK].width,
+			sel->r.width,
+			crops[SMIAPP_PAD_SINK].height,
+			sel->r.height, sel->flags);
+
+		for (i = 0; i < sensor->nbinning_subtypes; i++) {
+			int this = scaling_goodness(
+				subdev,
+				crops[SMIAPP_PAD_SINK].width
+				/ sensor->binning_subtypes[i].horizontal,
+				sel->r.width,
+				crops[SMIAPP_PAD_SINK].height
+				/ sensor->binning_subtypes[i].vertical,
+				sel->r.height, sel->flags);
+
+			if (this > best) {
+				binh = sensor->binning_subtypes[i].horizontal;
+				binv = sensor->binning_subtypes[i].vertical;
+				best = this;
+
+				if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+					sensor->binning_vertical = binv;
+					sensor->binning_horizontal = binh;
+				}
+			}
+		}
+
+		sel->r.width =
+			(crops[SMIAPP_PAD_SINK].width / binh) & ~1;
+		sel->r.height =
+			(crops[SMIAPP_PAD_SINK].height / binv) & ~1;
+
+	} else {
+		u32 min, max, a, b, max_m;
+		u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+		int mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+		u32 try[4];
+		u32 ntry = 0;
+		int i;
+		int best = INT_MIN;
+
+		sel->r.width = min_t(unsigned int, sel->r.width,
+				     crops[SMIAPP_PAD_SINK].width);
+		sel->r.height = min_t(unsigned int, sel->r.height,
+				      crops[SMIAPP_PAD_SINK].height);
+
+		a = crops[SMIAPP_PAD_SINK].width
+			* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
+			/ sel->r.width;
+		b = crops[SMIAPP_PAD_SINK].height
+			* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
+			/ sel->r.height;
+		max_m = crops[SMIAPP_PAD_SINK].width
+			* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
+			/ sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
+
+		a = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+			max(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+		b = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+			max(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+		max_m = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+			    max(max_m,
+				sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+
+		dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n",
+			a, b, max_m);
+
+		min = min(max_m, min(a, b));
+		max = min(max_m, max(a, b));
+
+		try[ntry] = min;
+		ntry++;
+		if (min != max) {
+			try[ntry] = max;
+			ntry++;
+		}
+		if (max != max_m) {
+			try[ntry] = min + 1;
+			ntry++;
+			if (min != max) {
+				try[ntry] = max + 1;
+				ntry++;
+			}
+		}
+
+		for (i = 0; i < ntry; i++) {
+			int this = scaling_goodness(
+				subdev,
+				crops[SMIAPP_PAD_SINK].width
+				/ try[i]
+				* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+				sel->r.width,
+				crops[SMIAPP_PAD_SINK].height,
+				sel->r.height,
+				sel->flags);
+
+			dev_dbg(&client->dev, "trying factor %d (%d)\n",
+				try[i], i);
+
+			if (this > best) {
+				scale_m = try[i];
+				mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+				best = this;
+			}
+
+			if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+			    == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+				continue;
+
+			this = scaling_goodness(
+				subdev, crops[SMIAPP_PAD_SINK].width
+				/ try[i]
+				* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+				sel->r.width,
+				crops[SMIAPP_PAD_SINK].height
+				/ try[i]
+				* sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+				sel->r.height,
+				sel->flags);
+
+			if (this > best) {
+				scale_m = try[i];
+				mode = SMIAPP_SCALING_MODE_BOTH;
+				best = this;
+			}
+		}
+
+		sel->r.width =
+			(crops[SMIAPP_PAD_SINK].width
+			 / scale_m
+			 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1;
+		if (mode == SMIAPP_SCALING_MODE_BOTH)
+			sel->r.height =
+				(crops[SMIAPP_PAD_SINK].height
+				 / scale_m
+				 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN])
+				& ~1;
+		else
+			sel->r.height = crops[SMIAPP_PAD_SINK].height;
+
+		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+			sensor->scale_m = scale_m;
+			sensor->scaling_mode = mode;
+		}
+	}
+
+	comps[SMIAPP_PAD_SINK] = sel->r;
+	smiapp_propagate(subdev, fh, sel->which, SMIAPP_PAD_SINK,
+			 V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		return smiapp_update_mode(sensor);
+
+	return 0;
+}
+
+static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+
+	/* We only implement crop in three places. */
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE:
+	case V4L2_SUBDEV_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+		if (ssd == sensor->pixel_array
+		    && sel->pad == SMIAPP_PAD_SOURCE)
+			return 0;
+		if (ssd == sensor->src
+		    && sel->pad == SMIAPP_PAD_SOURCE)
+			return 0;
+		if (ssd == sensor->scaler
+		    && sel->pad == SMIAPP_PAD_SINK
+		    && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+		    == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
+			return 0;
+		return -EINVAL;
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE:
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+		if (sel->pad != SMIAPP_PAD_SINK)
+			return -EINVAL;
+		if (ssd == sensor->binner)
+			return 0;
+		if (ssd == sensor->scaler
+		    && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		    != SMIAPP_SCALING_CAPABILITY_NONE)
+			return 0;
+		/* Fall through */
+	default:
+		return -EINVAL;
+	}
+}
+
+static int smiapp_set_crop(struct v4l2_subdev *subdev,
+			   struct v4l2_subdev_fh *fh,
+			   struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *src_size, *crops;
+	struct v4l2_rect _r;
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		crops = ssd->crop;
+		if (sel->pad == SMIAPP_PAD_SINK)
+			src_size = &ssd->sink_fmt;
+		else
+			src_size = &ssd->compose[SMIAPP_PAD_SINK];
+	} else {
+		crops = fh->try_crop;
+		if (sel->pad == SMIAPP_PAD_SINK) {
+			_r.left = _r.top = 0;
+			_r.width = fh->try_fmt[sel->pad].width;
+			_r.height = fh->try_fmt[sel->pad].height;
+			src_size = &_r;
+		} else {
+			src_size = &fh->try_compose[SMIAPP_PAD_SINK];
+		}
+	}
+
+	if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SOURCE)
+		sel->r.left = 0, sel->r.top = 0;
+
+	if (sel->r.width > src_size->width)
+		sel->r.width = src_size->width;
+	if (sel->r.height > src_size->height)
+		sel->r.height = src_size->height;
+
+	if (sel->r.left + sel->r.width > src_size->width)
+		sel->r.left =
+			src_size->width - sel->r.width;
+	if (sel->r.top + sel->r.height > src_size->height)
+		sel->r.top =
+			src_size->height - sel->r.height;
+
+	crops[sel->pad] = sel->r;
+
+	smiapp_propagate(subdev, fh, sel->which, sel->pad,
+			 V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE);
+
+	return 0;
+}
+
+static int smiapp_get_selection(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comps, *crops;
+	int ret;
+
+	ret = __smiapp_sel_supported(subdev, sel);
+	if (ret)
+		return ret;
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		crops = ssd->crop;
+		comps = ssd->compose;
+	} else {
+		crops = fh->try_crop;
+		comps = fh->try_compose;
+	}
+
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE:
+		sel->r = crops[sel->pad];
+		break;
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE:
+		sel->r = comps[sel->pad];
+		break;
+	}
+
+	return 0;
+}
+
+static int smiapp_set_selection(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+	struct v4l2_rect *comps, *crops;
+	int ret;
+
+	ret = __smiapp_sel_supported(subdev, sel);
+	if (ret)
+		return ret;
+
+	sel->r.left = sel->r.left & ~1;
+	sel->r.top = sel->r.top & ~1;
+	sel->r.width = SMIAPP_ALIGN_DIM(sel->r.width, sel->flags);
+	sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		crops = ssd->crop;
+		comps = ssd->compose;
+	} else {
+		crops = fh->try_crop;
+		comps = fh->try_compose;
+	}
+
+	sel->r.left &= ~1;
+	sel->r.top &= ~1;
+	sel->r.width &= ~1;
+	sel->r.height &= ~1;
+
+	sel->r.left = max(0, sel->r.left);
+	sel->r.top = max(0, sel->r.top);
+	sel->r.width = max(0, sel->r.width);
+	sel->r.height = max(0, sel->r.height);
+
+	sel->r.width = max_t(unsigned int,
+			     sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+			     sel->r.width);
+	sel->r.height = max_t(unsigned int,
+			      sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+			      sel->r.height);
+
+	switch (sel->target) {
+	case V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE:
+		return smiapp_set_crop(subdev, fh, sel);
+	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE:
+		return smiapp_set_compose(subdev, fh, sel);
+	}
+
+	BUG();
+}
+
+static int smiapp_validate_pipeline(struct v4l2_subdev *subdev)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct smiapp_subdev *ssds[] = {
+		sensor->scaler, sensor->binner, sensor->pixel_array };
+	int i;
+	struct smiapp_subdev *last = NULL;
+
+	if (sensor->src->crop[SMIAPP_PAD_SOURCE].width
+	    < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
+		return -EPIPE;
+	if (sensor->src->crop[SMIAPP_PAD_SOURCE].height
+	    < sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE])
+		return -EPIPE;
+
+	for (i = 0; i < SMIAPP_SUBDEVS; i++) {
+		struct smiapp_subdev *this = ssds[i];
+
+		if (!this)
+			continue;
+
+		if (!last) {
+			last = this;
+			continue;
+		}
+
+		if (last->sink_fmt.width
+		    != this->compose[SMIAPP_PAD_SOURCE].width)
+			return -EPIPE;
+		if (last->sink_fmt.height
+		    != this->compose[SMIAPP_PAD_SOURCE].height)
+			return -EPIPE;
+
+		last = this;
+	}
+
+	return 0;
+}
+
+static int smiapp_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+	*lines = sensor->sof_rows;
+	return 0;
+}
+
+static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+	*frames = sensor->frame_skip;
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * sysfs attributes
+ */
+
+static ssize_t
+smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
+		      char *buf)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int nbytes;
+
+	if (!sensor->dev_init_done)
+		return -EBUSY;
+
+	if (!sensor->nvm_size) {
+		/* NVM not read yet - read it now */
+		sensor->nvm_size = sensor->platform_data->nvm_size;
+		if (smiapp_set_power(subdev, 1) < 0)
+			return -ENODEV;
+		if (smiapp_read_nvm(sensor, sensor->nvm)) {
+			dev_err(&client->dev, "nvm read failed\n");
+			return -ENODEV;
+		}
+		smiapp_set_power(subdev, 0);
+	}
+	/*
+	 * NVM is still way below a PAGE_SIZE, so we can safely
+	 * assume this for now.
+	 */
+	nbytes = min_t(unsigned int, sensor->nvm_size, PAGE_SIZE);
+	memcpy(buf, sensor->nvm, nbytes);
+
+	return nbytes;
+}
+static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL);
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int smiapp_identify_module(struct v4l2_subdev *subdev)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	int i, rval = 0;
+	struct smiapp_module_info *minfo = &sensor->minfo;
+
+	minfo->name = SMIAPP_NAME;
+
+	/* Module info */
+	rval = smia_i2c_read_reg(client,
+				 SMIAPP_REG_U8_MANUFACTURER_ID,
+				 &minfo->manufacturer_id);
+	if (!rval)
+		rval = smia_i2c_read_reg(client,
+					 SMIAPP_REG_U16_MODEL_ID,
+					 &minfo->model_id);
+	if (!rval)
+		rval |= smia_i2c_read_reg(client,
+					  SMIAPP_REG_U8_REVISION_NUMBER_MAJOR,
+					  &minfo->revision_number_major);
+	if (!rval)
+		rval |= smia_i2c_read_reg(client,
+					  SMIAPP_REG_U8_REVISION_NUMBER_MINOR,
+					  &minfo->revision_number_minor);
+	if (!rval)
+		rval |= smia_i2c_read_reg(client,
+					  SMIAPP_REG_U8_MODULE_DATE_YEAR,
+					  &minfo->module_year);
+	if (!rval)
+		rval |= smia_i2c_read_reg(client,
+					  SMIAPP_REG_U8_MODULE_DATE_MONTH,
+					  &minfo->module_month);
+	if (!rval)
+		rval |= smia_i2c_read_reg(client,
+					  SMIAPP_REG_U8_MODULE_DATE_DAY,
+					  &minfo->module_day);
+
+	/* Sensor info */
+	if (!rval)
+		rval |= smia_i2c_read_reg(client,
+					  SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID,
+					  &minfo->sensor_manufacturer_id);
+	if (!rval)
+		rval |= smia_i2c_read_reg(client,
+					  SMIAPP_REG_U16_SENSOR_MODEL_ID,
+					  &minfo->sensor_model_id);
+	if (!rval)
+		rval = smia_i2c_read_reg(client,
+					 SMIAPP_REG_U8_SENSOR_REVISION_NUMBER,
+					 &minfo->sensor_revision_number);
+	if (!rval)
+		rval = smia_i2c_read_reg(client,
+					 SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION,
+					 &minfo->sensor_firmware_version);
+
+	/* SMIA */
+	if (!rval)
+		rval = smia_i2c_read_reg(client,
+					 SMIAPP_REG_U8_SMIA_VERSION,
+					 &minfo->smia_version);
+	if (!rval)
+		rval = smia_i2c_read_reg(client,
+					 SMIAPP_REG_U8_SMIAPP_VERSION,
+					 &minfo->smiapp_version);
+
+	if (rval) {
+		dev_err(&client->dev, "sensor detection failed\n");
+		return -ENODEV;
+	}
+
+	dev_dbg(&client->dev, "module 0x%2.2x-0x%4.4x\n",
+		minfo->manufacturer_id, minfo->model_id);
+
+	dev_dbg(&client->dev,
+		"module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n",
+		minfo->revision_number_major, minfo->revision_number_minor,
+		minfo->module_year, minfo->module_month, minfo->module_day);
+
+	dev_dbg(&client->dev, "sensor 0x%2.2x-0x%4.4x\n",
+		minfo->sensor_manufacturer_id, minfo->sensor_model_id);
+
+	dev_dbg(&client->dev,
+		"sensor revision 0x%2.2x firmware version 0x%2.2x\n",
+		minfo->sensor_revision_number, minfo->sensor_firmware_version);
+
+	dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n",
+		minfo->smia_version, minfo->smiapp_version);
+
+	if (!minfo->manufacturer_id && !minfo->model_id) {
+		minfo->manufacturer_id = minfo->sensor_manufacturer_id;
+		minfo->model_id = minfo->sensor_model_id;
+		minfo->revision_number_major = minfo->sensor_revision_number;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) {
+		if (smiapp_module_idents[i].manufacturer_id
+		    != minfo->manufacturer_id)
+			continue;
+		if (smiapp_module_idents[i].model_id != minfo->model_id)
+			continue;
+		if (smiapp_module_idents[i].flags
+		    & SMIAPP_MODULE_IDENT_FLAG_REV_LE) {
+			if (smiapp_module_idents[i].revision_number_major
+			    < minfo->revision_number_major)
+				continue;
+		} else {
+			if (smiapp_module_idents[i].revision_number_major
+			    != minfo->revision_number_major)
+				continue;
+		}
+
+		minfo->name = smiapp_module_idents[i].name;
+		minfo->quirk = smiapp_module_idents[i].quirk;
+		break;
+	}
+
+	if (i >= ARRAY_SIZE(smiapp_module_idents))
+		dev_warn(&client->dev, "no quirks for this module\n");
+
+	dev_dbg(&client->dev, "the sensor is called %s, ident %2.2x%4.4x%2.2x\n",
+		minfo->name, minfo->manufacturer_id, minfo->model_id,
+		minfo->revision_number_major);
+
+	strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name));
+
+	return 0;
+}
+
+static const struct v4l2_subdev_ops smiapp_ops;
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
+
+static int smiapp_registered(struct v4l2_subdev *subdev)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct smiapp_subdev *last = NULL;
+	int rval;
+	u32 tmp, i;
+
+	sensor->vana = regulator_get(&client->dev, "VANA");
+	if (IS_ERR(sensor->vana)) {
+		dev_err(&client->dev, "could not get regulator for vana\n");
+		return -ENODEV;
+	}
+
+	rval = smiapp_power_on(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out;
+	}
+
+	rval = smiapp_identify_module(subdev);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_power_off;
+	}
+
+	rval = smiapp_get_all_limits(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_power_off;
+	}
+
+	rval = smiapp_get_mbus_formats(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_power_off;
+	}
+
+	if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
+		int i;
+		int val;
+
+		rval = smia_i2c_read_reg(client,
+					 SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
+		if (rval < 0) {
+			rval = -ENODEV;
+			goto out_power_off;
+		}
+		sensor->nbinning_subtypes = val;
+
+		sensor->nbinning_subtypes = min_t(u8, sensor->nbinning_subtypes,
+						  SMIAPP_BINNING_SUBTYPES);
+
+		for (i = 0; i < sensor->nbinning_subtypes; i++) {
+			rval = smia_i2c_read_reg(
+				client, SMIAPP_REG_U8_BINNING_TYPE_1 + i,
+				&val);
+			if (rval < 0) {
+				rval = -ENODEV;
+				goto out_power_off;
+			}
+			sensor->binning_subtypes[i] =
+				*(struct smiapp_binning_subtype *)&val;
+
+			dev_dbg(&client->dev, "binning %xx%x\n",
+				sensor->binning_subtypes[i].horizontal,
+				sensor->binning_subtypes[i].vertical);
+		}
+	}
+	sensor->binning_horizontal = 1;
+	sensor->binning_vertical = 1;
+
+	/* SMIA++ NVM initialization - it will be read from the sensor
+	 * when it is first requested by userspace.
+	 */
+	if (sensor->minfo.smiapp_version && sensor->platform_data->nvm_size) {
+		sensor->nvm = kzalloc(sensor->platform_data->nvm_size,
+				      GFP_KERNEL);
+		if (sensor->nvm == NULL) {
+			dev_err(&client->dev, "nvm buf allocation failed\n");
+			rval = -ENOMEM;
+			goto out_power_off;
+		}
+
+		if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
+			dev_err(&client->dev, "sysfs nvm entry failed\n");
+			rval = -EBUSY;
+			goto out_nvm_release1;
+		}
+	}
+
+	/*
+	 * Handle Sensor Module orientation on the board.
+	 *
+	 * The application of H-FLIP and V-FLIP on the sensor is modified by
+	 * the sensor orientation on the board.
+	 *
+	 * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
+	 * both H-FLIP and V-FLIP for normal operation which also implies
+	 * that a set/unset operation for user space HFLIP and VFLIP v4l2
+	 * controls will need to be internally inverted.
+	 *
+	 * FIXME: rotation also changes the bayer pattern.
+	 */
+	if (sensor->platform_data->module_board_orient ==
+	    SMIAPP_MODULE_BOARD_ORIENT_180)
+		sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
+					  SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+	rval = smiapp_call_quirk(sensor, limits);
+	if (rval) {
+		dev_err(&client->dev, "limits quirks failed\n");
+		goto out_nvm_release2;
+	}
+
+	/* We consider this as profile 0 sensor if any of these are zero. */
+	if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
+	    !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
+	    !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
+	    !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
+		sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
+	} else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		   != SMIAPP_SCALING_CAPABILITY_NONE) {
+		if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+		    == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+			sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
+		else
+			sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
+		sensor->scaler = &sensor->sds[sensor->sds_used];
+		sensor->sds_used++;
+	} else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+		   == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+		sensor->scaler = &sensor->sds[sensor->sds_used];
+		sensor->sds_used++;
+	}
+	sensor->binner = &sensor->sds[sensor->sds_used];
+	sensor->sds_used++;
+	sensor->pixel_array = &sensor->sds[sensor->sds_used];
+	sensor->sds_used++;
+
+	sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+
+	for (i = 0; i < SMIAPP_SUBDEVS; i++) {
+		struct {
+			struct smiapp_subdev *sds;
+			char *name;
+		} _t[] = {
+			{ sensor->scaler, "scaler", },
+			{ sensor->binner, "binner", },
+			{ sensor->pixel_array, "pixel array", },
+		}, *this = &_t[i];
+		if (!this->sds)
+			continue;
+
+		if (this->sds != sensor->src)
+			v4l2_subdev_init(&this->sds->sd, &smiapp_ops);
+
+		this->sds->sensor = sensor;
+
+		if (this->sds == sensor->pixel_array) {
+			if (this->sds == sensor->src)
+				sensor->sds->sd.entity.num_pads = 1;
+			this->sds->npads = 1;
+		} else {
+			this->sds->npads = 2;
+		}
+
+		snprintf(this->sds->sd.name,
+			 sizeof(this->sds->sd.name), "%s %s",
+			 sensor->minfo.name, this->name);
+
+		this->sds->sink_fmt.width =
+			sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+		this->sds->sink_fmt.height =
+			sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+		this->sds->crop[SMIAPP_PAD_SINK].width =
+			this->sds->sink_fmt.width;
+		this->sds->crop[SMIAPP_PAD_SINK].height =
+			this->sds->sink_fmt.height;
+
+		smiapp_propagate(&this->sds->sd, NULL,
+				 V4L2_SUBDEV_FORMAT_ACTIVE,
+				 SMIAPP_PAD_SINK,
+				 V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE);
+
+		this->sds->pads[1].flags = MEDIA_PAD_FL_SINK;
+		this->sds->pads[0].flags = MEDIA_PAD_FL_SOURCE;
+
+		if (last == NULL) {
+			last = this->sds;
+			continue;
+		}
+
+		this->sds->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+		this->sds->sd.internal_ops = &smiapp_internal_ops;
+		this->sds->sd.owner = NULL;
+		v4l2_set_subdevdata(&this->sds->sd, client);
+
+		rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
+						   &this->sds->sd);
+		if (rval) {
+			dev_err(&client->dev,
+				"v4l2_device_register_subdev failed\n");
+			goto out_nvm_release2;
+		}
+
+		rval = media_entity_init(&this->sds->sd.entity,
+					 this->sds->npads, this->sds->pads, 0);
+		if (rval) {
+			dev_err(&client->dev,
+				"media_entity_init failed\n");
+			goto out_nvm_release2;
+		}
+
+		rval = media_entity_create_link(&this->sds->sd.entity, 0,
+						&last->sd.entity, 1,
+						MEDIA_LNK_FL_ENABLED |
+						MEDIA_LNK_FL_IMMUTABLE);
+		if (rval) {
+			dev_err(&client->dev,
+				"media_entity_create_link failed\n");
+			goto out_nvm_release2;
+		}
+
+		last = this->sds;
+	}
+
+	dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
+
+	sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+
+	/* final steps */
+	smiapp_read_frame_fmt(sensor);
+	rval = smiapp_init_controls(sensor);
+	if (rval < 0)
+		goto out_nvm_release2;
+
+	rval = smiapp_update_mode(sensor);
+	if (rval) {
+		dev_err(&client->dev, "update mode failed\n");
+		goto out_nvm_release2;
+	}
+
+	sensor->streaming = false;
+	sensor->dev_init_done = true;
+
+	/* check flash capability */
+	rval = smia_i2c_read_reg(client,
+				 SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp);
+	sensor->flash_capability = tmp;
+	if (rval)
+		goto out_nvm_release2;
+
+	smiapp_power_off(sensor);
+
+	return 0;
+
+out_nvm_release2:
+	device_remove_file(&client->dev, &dev_attr_nvm);
+
+out_nvm_release1:
+	kfree(sensor->nvm);
+	sensor->nvm = NULL;
+
+out_power_off:
+	smiapp_power_off(sensor);
+
+out:
+	regulator_put(sensor->vana);
+	sensor->vana = NULL;
+	return rval;
+}
+
+static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
+	int i;
+
+	for (i = 0; i < ssd->npads; i++) {
+		struct v4l2_subdev_format fmt;
+		struct v4l2_subdev_selection sel;
+
+		fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		fmt.pad = i;
+		smiapp_get_format(sd, fh, &fmt);
+		fh->try_fmt[i] = fmt.format;
+
+		sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		sel.pad = i;
+		sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE;
+		smiapp_get_selection(sd, fh, &sel);
+		fh->try_crop[i] = sel.r;
+
+		sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+		sel.pad = i;
+		sel.target = V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE;
+		smiapp_get_selection(sd, fh, &sel);
+		fh->try_compose[i] = sel.r;
+	}
+
+	return smiapp_set_power(sd, 1);
+}
+
+static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return smiapp_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_video_ops smiapp_video_ops = {
+	.s_stream = smiapp_set_stream,
+};
+
+static const struct v4l2_subdev_core_ops smiapp_core_ops = {
+	.s_power = smiapp_set_power,
+};
+
+static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
+	.enum_mbus_code = smiapp_enum_mbus_code,
+	.get_fmt = smiapp_get_format,
+	.set_fmt = smiapp_set_format,
+	.get_selection = smiapp_get_selection,
+	.set_selection = smiapp_set_selection,
+	.validate_pipeline = smiapp_validate_pipeline,
+};
+
+static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
+	.g_skip_top_lines = smiapp_get_skip_top_lines,
+	.g_skip_frames = smiapp_get_skip_frames,
+};
+
+static const struct v4l2_subdev_ops smiapp_ops = {
+	.core = &smiapp_core_ops,
+	.video = &smiapp_video_ops,
+	.pad = &smiapp_pad_ops,
+	.sensor = &smiapp_sensor_ops,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = {
+	.registered = smiapp_registered,
+	.open = smiapp_open,
+	.close = smiapp_close,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops = {
+	.open = smiapp_open,
+	.close = smiapp_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * I2C Driver
+ */
+
+#ifdef CONFIG_PM
+
+static int smiapp_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int ss;
+
+	if (sensor->power_count == 0)
+		return 0;
+
+	if (sensor->streaming)
+		smiapp_stop_streaming(sensor);
+
+	ss = sensor->streaming;
+
+	smiapp_power_off(sensor);
+
+	/* save state for resume */
+	sensor->streaming = ss;
+
+	return 0;
+}
+
+static int smiapp_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int rval;
+
+	if (sensor->power_count == 0)
+		return 0;
+
+	rval = smiapp_power_on(sensor);
+	if (rval)
+		return rval;
+
+	if (sensor->streaming)
+		rval = smiapp_start_streaming(sensor);
+
+	return rval;
+}
+
+#else
+
+#define smiapp_suspend	NULL
+#define smiapp_resume	NULL
+
+#endif /* CONFIG_PM */
+
+static int smiapp_probe(struct i2c_client *client,
+			const struct i2c_device_id *devid)
+{
+	struct smiapp_sensor *sensor;
+	int rval;
+
+	if (client->dev.platform_data == NULL)
+		return -ENODEV;
+
+	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+	if (sensor == NULL)
+		return -ENOMEM;
+
+	sensor->platform_data = client->dev.platform_data;
+	mutex_init(&sensor->power_lock);
+	sensor->src = &sensor->sds[sensor->sds_used];
+
+	v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
+	sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
+	sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sensor->src->sensor = sensor;
+
+	sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
+	rval = media_entity_init(&sensor->src->sd.entity, 2,
+				 sensor->src->pads, 0);
+	if (rval < 0)
+		kfree(sensor);
+
+	return rval;
+}
+
+static int __exit smiapp_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	int i;
+
+	if (sensor->power_count) {
+		if (sensor->platform_data->set_xshutdown)
+			sensor->platform_data->set_xshutdown(
+				&sensor->src->sd, 0);
+		sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+		sensor->power_count = 0;
+	}
+
+	if (sensor->nvm) {
+		device_remove_file(&client->dev, &dev_attr_nvm);
+		kfree(sensor->nvm);
+	}
+
+	for (i = 0; i < sensor->sds_used; i++) {
+		media_entity_cleanup(&sensor->sds[i].sd.entity);
+		v4l2_device_unregister_subdev(&sensor->sds[i].sd);
+	}
+	smiapp_free_controls(sensor);
+	if (sensor->vana)
+		regulator_put(sensor->vana);
+
+	kfree(sensor);
+
+	return 0;
+}
+
+static const struct i2c_device_id smiapp_id_table[] = {
+	{ SMIAPP_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, smiapp_id_table);
+
+static const struct dev_pm_ops smiapp_pm_ops = {
+	.suspend	= smiapp_suspend,
+	.resume		= smiapp_resume,
+};
+
+static struct i2c_driver smiapp_i2c_driver = {
+	.driver	= {
+		.name = SMIAPP_NAME,
+		.pm = &smiapp_pm_ops,
+	},
+	.probe	= smiapp_probe,
+	.remove	= __exit_p(smiapp_remove),
+	.id_table = smiapp_id_table,
+};
+
+static int __init smiapp_init(void)
+{
+	int rval;
+
+	rval = i2c_add_driver(&smiapp_i2c_driver);
+	if (rval)
+		printk(KERN_ERR "Failed registering driver" SMIAPP_NAME "\n");
+
+	return rval;
+}
+
+static void __exit smiapp_exit(void)
+{
+	i2c_del_driver(&smiapp_i2c_driver);
+}
+
+module_init(smiapp_init);
+module_exit(smiapp_exit);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
+MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/smiapp-debug.h b/drivers/media/video/smiapp-debug.h
new file mode 100644
index 0000000..0cbad12
--- /dev/null
+++ b/drivers/media/video/smiapp-debug.h
@@ -0,0 +1,32 @@
+/*
+ * drivers/media/video/smiapp-debug.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SMIAPP_DEBUG_H
+#define SMIAPP_DEBUG_H
+
+#ifdef CONFIG_VIDEO_SMIAPP_DEBUG
+#define DEBUG
+#endif
+
+#endif
diff --git a/drivers/media/video/smiapp-limits.c b/drivers/media/video/smiapp-limits.c
new file mode 100644
index 0000000..724f514
--- /dev/null
+++ b/drivers/media/video/smiapp-limits.c
@@ -0,0 +1,132 @@
+/*
+ * drivers/media/video/smiapp-limits.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "smiapp.h"
+
+struct smiapp_reg_limits smiapp_reg_limits[] = {
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY, "analogue_gain_capability" }, /* 0 */
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN, "analogue_gain_code_min" },
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX, "analogue_gain_code_max" },
+	{ SMIAPP_REG_U8_THS_ZERO_MIN, "ths_zero_min" },
+	{ SMIAPP_REG_U8_TCLK_TRAIL_MIN, "tclk_trail_min" },
+	{ SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY, "integration_time_capability" }, /* 5 */
+	{ SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN, "coarse_integration_time_min" },
+	{ SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN, "coarse_integration_time_max_margin" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN, "fine_integration_time_min" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN, "fine_integration_time_max_margin" },
+	{ SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY, "digital_gain_capability" }, /* 10 */
+	{ SMIAPP_REG_U16_DIGITAL_GAIN_MIN, "digital_gain_min" },
+	{ SMIAPP_REG_U16_DIGITAL_GAIN_MAX, "digital_gain_max" },
+	{ SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ, "min_ext_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ, "max_ext_clk_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV, "min_pre_pll_clk_div" }, /* 15 */
+	{ SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV, "max_pre_pll_clk_div" },
+	{ SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ, "min_pll_ip_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ, "max_pll_ip_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_PLL_MULTIPLIER, "min_pll_multiplier" },
+	{ SMIAPP_REG_U16_MAX_PLL_MULTIPLIER, "max_pll_multiplier" }, /* 20 */
+	{ SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ, "min_pll_op_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ, "max_pll_op_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV, "min_vt_sys_clk_div" },
+	{ SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV, "max_vt_sys_clk_div" },
+	{ SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ, "min_vt_sys_clk_freq_hz" }, /* 25 */
+	{ SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ, "max_vt_sys_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ, "min_vt_pix_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ, "max_vt_pix_clk_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV, "min_vt_pix_clk_div" },
+	{ SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV, "max_vt_pix_clk_div" }, /* 30 */
+	{ SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES, "min_frame_length_lines" },
+	{ SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES, "max_frame_length_lines" },
+	{ SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK, "min_line_length_pck" },
+	{ SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK, "max_line_length_pck" },
+	{ SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK, "min_line_blanking_pck" }, /* 35 */
+	{ SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES, "min_frame_blanking_lines" },
+	{ SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE, "min_line_length_pck_step_size" },
+	{ SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV, "min_op_sys_clk_div" },
+	{ SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV, "max_op_sys_clk_div" },
+	{ SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ, "min_op_sys_clk_freq_hz" }, /* 40 */
+	{ SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ, "max_op_sys_clk_freq_hz" },
+	{ SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV, "min_op_pix_clk_div" },
+	{ SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV, "max_op_pix_clk_div" },
+	{ SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ, "min_op_pix_clk_freq_hz" },
+	{ SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ, "max_op_pix_clk_freq_hz" }, /* 45 */
+	{ SMIAPP_REG_U16_X_ADDR_MIN, "x_addr_min" },
+	{ SMIAPP_REG_U16_Y_ADDR_MIN, "y_addr_min" },
+	{ SMIAPP_REG_U16_X_ADDR_MAX, "x_addr_max" },
+	{ SMIAPP_REG_U16_Y_ADDR_MAX, "y_addr_max" },
+	{ SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE, "min_x_output_size" }, /* 50 */
+	{ SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE, "min_y_output_size" },
+	{ SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE, "max_x_output_size" },
+	{ SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE, "max_y_output_size" },
+	{ SMIAPP_REG_U16_MIN_EVEN_INC, "min_even_inc" },
+	{ SMIAPP_REG_U16_MAX_EVEN_INC, "max_even_inc" }, /* 55 */
+	{ SMIAPP_REG_U16_MIN_ODD_INC, "min_odd_inc" },
+	{ SMIAPP_REG_U16_MAX_ODD_INC, "max_odd_inc" },
+	{ SMIAPP_REG_U16_SCALING_CAPABILITY, "scaling_capability" },
+	{ SMIAPP_REG_U16_SCALER_M_MIN, "scaler_m_min" },
+	{ SMIAPP_REG_U16_SCALER_M_MAX, "scaler_m_max" }, /* 60 */
+	{ SMIAPP_REG_U16_SCALER_N_MIN, "scaler_n_min" },
+	{ SMIAPP_REG_U16_SCALER_N_MAX, "scaler_n_max" },
+	{ SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY, "spatial_sampling_capability" },
+	{ SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY, "digital_crop_capability" },
+	{ SMIAPP_REG_U16_COMPRESSION_CAPABILITY, "compression_capability" }, /* 65 */
+	{ SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY, "fifo_support_capability" },
+	{ SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY, "dphy_ctrl_capability" },
+	{ SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY, "csi_lane_mode_capability" },
+	{ SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY, "csi_signalling_mode_capability" },
+	{ SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY, "fast_standby_capability" }, /* 70 */
+	{ SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY, "cci_address_control_capability" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS, "max_per_lane_bitrate_1_lane_mode_mbps" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS, "max_per_lane_bitrate_2_lane_mode_mbps" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS, "max_per_lane_bitrate_3_lane_mode_mbps" },
+	{ SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS, "max_per_lane_bitrate_4_lane_mode_mbps" }, /* 75 */
+	{ SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY, "temp_sensor_capability" },
+	{ SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN, "min_frame_length_lines_bin" },
+	{ SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN, "max_frame_length_lines_bin" },
+	{ SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN, "min_line_length_pck_bin" },
+	{ SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN, "max_line_length_pck_bin" }, /* 80 */
+	{ SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN, "min_line_blanking_pck_bin" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN, "fine_integration_time_min_bin" },
+	{ SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, "fine_integration_time_max_margin_bin" },
+	{ SMIAPP_REG_U8_BINNING_CAPABILITY, "binning_capability" },
+	{ SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY, "binning_weighting_capability" }, /* 85 */
+	{ SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY, "data_transfer_if_capability" },
+	{ SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY, "shading_correction_capability" },
+	{ SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY, "green_imbalance_capability" },
+	{ SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY, "black_level_capability" },
+	{ SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY, "module_specific_correction_capability" }, /* 90 */
+	{ SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY, "defect_correction_capability" },
+	{ SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2, "defect_correction_capability_2" },
+	{ SMIAPP_REG_U8_EDOF_CAPABILITY, "edof_capability" },
+	{ SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY, "colour_feedback_capability" },
+	{ SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY, "estimation_mode_capability" }, /* 95 */
+	{ SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY, "estimation_zone_capability" },
+	{ SMIAPP_REG_U16_CAPABILITY_TRDY_MIN, "capability_trdy_min" },
+	{ SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, "flash_mode_capability" },
+	{ SMIAPP_REG_U8_ACTUATOR_CAPABILITY, "actuator_capability" },
+	{ SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1, "bracketing_lut_capability_1" }, /* 100 */
+	{ SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2, "bracketing_lut_capability_2" },
+	{ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP, "analogue_gain_code_step" },
+	{ 0, NULL },
+};
diff --git a/drivers/media/video/smiapp-limits.h b/drivers/media/video/smiapp-limits.h
new file mode 100644
index 0000000..83e5f4d
--- /dev/null
+++ b/drivers/media/video/smiapp-limits.h
@@ -0,0 +1,128 @@
+/*
+ * drivers/media/video/smiapp-limits.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY			0
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN			1
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX			2
+#define SMIAPP_LIMIT_THS_ZERO_MIN				3
+#define SMIAPP_LIMIT_TCLK_TRAIL_MIN				4
+#define SMIAPP_LIMIT_INTEGRATION_TIME_CAPABILITY		5
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN		6
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN		7
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN			8
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN		9
+#define SMIAPP_LIMIT_DIGITAL_GAIN_CAPABILITY			10
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MIN				11
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MAX				12
+#define SMIAPP_LIMIT_MIN_EXT_CLK_FREQ_HZ			13
+#define SMIAPP_LIMIT_MAX_EXT_CLK_FREQ_HZ			14
+#define SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV			15
+#define SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV			16
+#define SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ				17
+#define SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ				18
+#define SMIAPP_LIMIT_MIN_PLL_MULTIPLIER				19
+#define SMIAPP_LIMIT_MAX_PLL_MULTIPLIER				20
+#define SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ				21
+#define SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ				22
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV				23
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV				24
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ			25
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ			26
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ			27
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ			28
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV				29
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV				30
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES			31
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES			32
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK			33
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK			34
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK			35
+#define SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES			36
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_STEP_SIZE		37
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV				38
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV				39
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ			40
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ			41
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV				42
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV				43
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ			44
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ			45
+#define SMIAPP_LIMIT_X_ADDR_MIN					46
+#define SMIAPP_LIMIT_Y_ADDR_MIN					47
+#define SMIAPP_LIMIT_X_ADDR_MAX					48
+#define SMIAPP_LIMIT_Y_ADDR_MAX					49
+#define SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE				50
+#define SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE				51
+#define SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE				52
+#define SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE				53
+#define SMIAPP_LIMIT_MIN_EVEN_INC				54
+#define SMIAPP_LIMIT_MAX_EVEN_INC				55
+#define SMIAPP_LIMIT_MIN_ODD_INC				56
+#define SMIAPP_LIMIT_MAX_ODD_INC				57
+#define SMIAPP_LIMIT_SCALING_CAPABILITY				58
+#define SMIAPP_LIMIT_SCALER_M_MIN				59
+#define SMIAPP_LIMIT_SCALER_M_MAX				60
+#define SMIAPP_LIMIT_SCALER_N_MIN				61
+#define SMIAPP_LIMIT_SCALER_N_MAX				62
+#define SMIAPP_LIMIT_SPATIAL_SAMPLING_CAPABILITY		63
+#define SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY			64
+#define SMIAPP_LIMIT_COMPRESSION_CAPABILITY			65
+#define SMIAPP_LIMIT_FIFO_SUPPORT_CAPABILITY			66
+#define SMIAPP_LIMIT_DPHY_CTRL_CAPABILITY			67
+#define SMIAPP_LIMIT_CSI_LANE_MODE_CAPABILITY			68
+#define SMIAPP_LIMIT_CSI_SIGNALLING_MODE_CAPABILITY		69
+#define SMIAPP_LIMIT_FAST_STANDBY_CAPABILITY			70
+#define SMIAPP_LIMIT_CCI_ADDRESS_CONTROL_CAPABILITY		71
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS	72
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS	73
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS	74
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS	75
+#define SMIAPP_LIMIT_TEMP_SENSOR_CAPABILITY			76
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN			77
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN			78
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN			79
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN			80
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN			81
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN		82
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN	83
+#define SMIAPP_LIMIT_BINNING_CAPABILITY				84
+#define SMIAPP_LIMIT_BINNING_WEIGHTING_CAPABILITY		85
+#define SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY		86
+#define SMIAPP_LIMIT_SHADING_CORRECTION_CAPABILITY		87
+#define SMIAPP_LIMIT_GREEN_IMBALANCE_CAPABILITY			88
+#define SMIAPP_LIMIT_BLACK_LEVEL_CAPABILITY			89
+#define SMIAPP_LIMIT_MODULE_SPECIFIC_CORRECTION_CAPABILITY	90
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY		91
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY_2		92
+#define SMIAPP_LIMIT_EDOF_CAPABILITY				93
+#define SMIAPP_LIMIT_COLOUR_FEEDBACK_CAPABILITY			94
+#define SMIAPP_LIMIT_ESTIMATION_MODE_CAPABILITY			95
+#define SMIAPP_LIMIT_ESTIMATION_ZONE_CAPABILITY			96
+#define SMIAPP_LIMIT_CAPABILITY_TRDY_MIN			97
+#define SMIAPP_LIMIT_FLASH_MODE_CAPABILITY			98
+#define SMIAPP_LIMIT_ACTUATOR_CAPABILITY			99
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_1		100
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_2		101
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP			102
+#define SMIAPP_LIMIT_LAST					103
diff --git a/drivers/media/video/smiapp-pll.c b/drivers/media/video/smiapp-pll.c
new file mode 100644
index 0000000..64634d0
--- /dev/null
+++ b/drivers/media/video/smiapp-pll.c
@@ -0,0 +1,664 @@
+/*
+ * drivers/media/video/smiapp-pll.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "smiapp-debug.h"
+
+#include "smiapp.h"
+
+#include <linux/gcd.h>
+#include <linux/lcm.h>
+
+struct smiapp_pll_limits {
+	uint32_t min_ext_clk_freq_hz;
+	uint32_t max_ext_clk_freq_hz;
+	uint16_t min_pre_pll_clk_div;
+	uint16_t max_pre_pll_clk_div;
+	uint32_t min_pll_ip_freq_hz;
+	uint32_t max_pll_ip_freq_hz;
+	uint16_t min_pll_multiplier;
+	uint16_t max_pll_multiplier;
+	uint32_t min_pll_op_freq_hz;
+	uint32_t max_pll_op_freq_hz;
+
+	uint16_t min_vt_sys_clk_div;
+	uint16_t max_vt_sys_clk_div;
+	uint16_t min_vt_pix_clk_div;
+	uint16_t max_vt_pix_clk_div;
+
+	uint16_t min_op_sys_clk_div;
+	uint16_t max_op_sys_clk_div;
+	uint32_t min_op_sys_clk_freq_hz;
+	uint32_t max_op_sys_clk_freq_hz;
+	uint16_t min_op_pix_clk_div;
+	uint16_t max_op_pix_clk_div;
+	uint32_t min_op_pix_clk_freq_hz;
+	uint32_t max_op_pix_clk_freq_hz;
+};
+
+#define CLAMP(value, min, max) \
+	((value) < (min) ? (min) : (value) > (max) ? (max) : (value))
+
+#define AVG(a, b) (((a) + (b)) >> 1)
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even(uint32_t a)
+{
+	return max_t(uint32_t, 1, a & ~1);
+}
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even_up(uint32_t a)
+{
+	if (a == 1)
+		return 1;
+	return (a + 1) & ~1;
+}
+
+static inline int is_one_or_even(uint32_t a)
+{
+	if (a == 1)
+		return 1;
+	if (a & 1)
+		return 0;
+
+	return 1;
+}
+
+/* Clamp which returns even or one. */
+static inline uint32_t clamp_to_div2(uint32_t value, uint32_t min, uint32_t max)
+{
+	if (value <= min)
+		return min;
+	else if (value >= max)
+		return max;
+
+	return clk_div_even(value);
+}
+
+/* Division with rounding. */
+static inline uint32_t div_round(uint32_t dividend, uint32_t divisor)
+{
+	return (dividend + (divisor >> 1)) / divisor;
+}
+
+static void bounds_check(struct device *dev, uint32_t val,
+			 uint32_t min, uint32_t max, char *str)
+{
+	if (val >= min && val <= max)
+		return;
+
+	dev_warn(dev, "%s out of bounds: %d (%d--%d)\n",
+		 str, val, min, max);
+}
+
+/*
+ * Return a divisor such that dividend / divisor produces a result in
+ * between result_min and result_max. Try to keep the original if possible.
+ */
+static inline
+uint32_t clamp_div_round(uint32_t dividend, uint32_t divisor,
+			 uint32_t result_min, uint32_t result_max)
+{
+	uint32_t result = div_round(dividend, divisor);
+
+	if (result < result_min)
+		return dividend / result_min;
+	if (result > result_max)
+		return DIV_ROUND_UP(dividend, result_max);
+
+	return divisor;
+}
+
+/*
+ * Return a divisor such that dividend / divisor produces a result in
+ * between result_min and result_max. Try to keep the original if possible.
+ *
+ * Additionally, divisor is required to be even or one.
+ */
+static inline
+uint32_t clamp_div_round2(uint32_t dividend, uint32_t divisor,
+			  uint32_t result_min, uint32_t result_max)
+{
+	uint32_t result;
+
+	divisor = clk_div_even(divisor);
+	result = div_round(dividend, divisor);
+
+	if (result < result_min)
+		return clk_div_even(dividend / result_min);
+	if (result > result_max)
+		return clk_div_even(DIV_ROUND_UP(dividend, result_max) + 1);
+
+	return divisor;
+}
+
+/*
+ * Return a factor of multiplication such that fixed * variable
+ * belongs to range [result_min..result_max]. Change variable if
+ * necessary.
+ */
+static inline uint32_t clamp_mul_round(uint32_t fixed, uint32_t variable,
+				       uint32_t result_min, uint32_t result_max)
+{
+	uint32_t result = fixed * variable;
+
+	if (result < result_min)
+		return DIV_ROUND_UP(result_min, fixed);
+	if (result > result_max)
+		return result_max / fixed;
+
+	return variable;
+}
+
+static void print_pll(struct smiapp_sensor *sensor, struct smiapp_pll *pll)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+	dev_dbg(&client->dev, "pre_pll_clk_div\t%d\n",  pll->pre_pll_clk_div);
+	dev_dbg(&client->dev, "pll_multiplier \t%d\n",  pll->pll_multiplier);
+	if (sensor->minfo.smiapp_profile != SMIAPP_PROFILE_0) {
+		dev_dbg(&client->dev, "op_sys_clk_div \t%d\n",
+			pll->op_sys_clk_div);
+		dev_dbg(&client->dev, "op_pix_clk_div \t%d\n",
+			pll->op_pix_clk_div);
+	}
+	dev_dbg(&client->dev, "vt_sys_clk_div \t%d\n",  pll->vt_sys_clk_div);
+	dev_dbg(&client->dev, "vt_pix_clk_div \t%d\n",  pll->vt_pix_clk_div);
+
+	dev_dbg(&client->dev, "ext_clk_freq_hz \t%d\n",
+		pll->ext_clk_freq_hz);
+	dev_dbg(&client->dev, "pll_ip_clk_freq_hz \t%d\n",
+		pll->pll_ip_clk_freq_hz);
+	dev_dbg(&client->dev, "pll_op_clk_freq_hz \t%d\n",
+		pll->pll_op_clk_freq_hz);
+	if (sensor->minfo.smiapp_profile != SMIAPP_PROFILE_0) {
+		dev_dbg(&client->dev, "op_sys_clk_freq_hz \t%d\n",
+			pll->op_sys_clk_freq_hz);
+		dev_dbg(&client->dev, "op_pix_clk_freq_hz \t%d\n",
+			pll->op_pix_clk_freq_hz);
+	}
+	dev_dbg(&client->dev, "vt_sys_clk_freq_hz \t%d\n",
+		pll->vt_sys_clk_freq_hz);
+	dev_dbg(&client->dev, "vt_pix_clk_freq_hz \t%d\n",
+		pll->vt_pix_clk_freq_hz);
+}
+
+static void smiapp_link_freq_to_pll(struct smiapp_sensor *sensor,
+				    u64 freq, unsigned int *mul,
+				    unsigned int *div)
+{
+	int t;
+
+	t = gcd(freq,
+		sensor->platform_data->ext_clk);
+	*mul = div_u64(freq, t);
+	*div = sensor->platform_data->ext_clk / t;
+}
+
+int smiapp_pll_update(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct smiapp_pll_limits lim = {
+		.min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV],
+		.max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV],
+		.min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ],
+		.max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ],
+		.min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER],
+		.max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER],
+		.min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ],
+		.max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ],
+
+		.min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV],
+		.max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV],
+		.min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV],
+		.max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV],
+		.min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ],
+		.max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ],
+		.min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ],
+		.max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ],
+	};
+	struct smiapp_pll *pll = &sensor->pll;
+	struct smiapp_subdev *last = NULL;
+	const struct smiapp_csi_data_format *format = sensor->csi_format;
+	uint32_t lanes = sensor->platform_data->lanes;
+	uint32_t ext_clk = sensor->platform_data->ext_clk;
+	uint32_t compressed = format->compressed;
+	uint32_t sys_div;
+	uint32_t best_pix_div = INT_MAX >> 1;
+	uint32_t vt_op_binning_div;
+	uint32_t lane_op_clock_ratio;
+	uint32_t mul, div;
+	uint32_t more_mul_min, more_mul_max;
+	uint32_t more_mul_factor;
+	uint32_t i;
+	uint32_t min_vt_div, max_vt_div, vt_div;
+	uint32_t min_sys_div, max_sys_div;
+
+	if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) {
+		/*
+		 * Fill in operational clock divisors limits from the
+		 * video timing ones. On profile 0 sensors the
+		 * requirements regarding them are essentially the
+		 * same as on VT ones.
+		 */
+		lim.min_op_sys_clk_div =
+			sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV];
+		lim.max_op_sys_clk_div =
+			sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV];
+		lim.min_op_pix_clk_div =
+			sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV];
+		lim.max_op_pix_clk_div =
+			sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV];
+		lim.min_op_sys_clk_freq_hz =
+			sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ];
+		lim.max_op_sys_clk_freq_hz =
+			sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ];
+		lim.min_op_pix_clk_freq_hz =
+			sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ];
+		lim.max_op_pix_clk_freq_hz =
+			sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ];
+	}
+
+	if (smiapp_needs_quirk(sensor,
+			       SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE))
+		lane_op_clock_ratio = lanes;
+	else
+		lane_op_clock_ratio = 1;
+	dev_dbg(&client->dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
+
+	dev_dbg(&client->dev, "binning \t\t%dx%d\n", sensor->binning_horizontal,
+		sensor->binning_vertical);
+
+	pll->ext_clk_freq_hz = ext_clk;
+	pll->pll_op_clk_freq_hz = sensor->link_freq->qmenu_int[
+		sensor->link_freq->val] * 1000
+		* (sensor->platform_data->lanes / lane_op_clock_ratio);
+
+	/* Figure out limits for pre-pll divider based on extclk */
+	dev_dbg(&client->dev, "min / max pre_pll_clk_div: %d / %d\n",
+		lim.min_pre_pll_clk_div, lim.max_pre_pll_clk_div);
+	lim.max_pre_pll_clk_div =
+		min_t(uint16_t, lim.max_pre_pll_clk_div,
+		      clk_div_even(pll->ext_clk_freq_hz /
+				   lim.min_pll_ip_freq_hz));
+	lim.min_pre_pll_clk_div =
+		max_t(uint16_t, lim.min_pre_pll_clk_div,
+		      clk_div_even(pll->ext_clk_freq_hz /
+				   lim.max_pll_ip_freq_hz));
+	dev_dbg(&client->dev,
+		"pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
+		lim.min_pre_pll_clk_div, lim.max_pre_pll_clk_div);
+
+	smiapp_link_freq_to_pll(sensor, pll->pll_op_clk_freq_hz, &mul, &div);
+	dev_dbg(&client->dev, "mul %d / div %d\n", mul, div);
+
+	lim.min_pre_pll_clk_div =
+		max_t(uint16_t, lim.min_pre_pll_clk_div,
+		      clk_div_even_up(
+			      DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
+					   lim.max_pll_op_freq_hz)));
+	dev_dbg(&client->dev,
+		"pll_op check: min / max pre_pll_clk_div: %d / %d\n",
+		lim.min_pre_pll_clk_div, lim.max_pre_pll_clk_div);
+
+	if (lim.min_pre_pll_clk_div > lim.max_pre_pll_clk_div) {
+		dev_err(&client->dev, "unable to compute pre_pll divisor\n");
+		return -EINVAL;
+	}
+
+	pll->pre_pll_clk_div = lim.min_pre_pll_clk_div;
+
+	/*
+	 * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
+	 * too high.
+	 */
+	dev_dbg(&client->dev, "pre_pll_clk_div %d\n", pll->pre_pll_clk_div);
+
+	/* Don't go above max pll multiplier. */
+	more_mul_max = lim.max_pll_multiplier / mul;
+	dev_dbg(&client->dev, "more_mul_max: max_pll_multiplier check: %d\n",
+		more_mul_max);
+	/* Don't go above max pll op frequency. */
+	more_mul_max =
+		min_t(int,
+		      more_mul_max,
+		      lim.max_pll_op_freq_hz
+		      / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
+	dev_dbg(&client->dev, "more_mul_max: max_pll_op_freq_hz check: %d\n",
+		more_mul_max);
+	/* Don't go above the division capability of op sys clock divider. */
+	more_mul_max = min(more_mul_max,
+			   lim.max_op_sys_clk_div / div);
+	dev_dbg(&client->dev, "more_mul_max: max_op_sys_clk_div check: %d\n",
+		more_mul_max);
+	/* Ensure we won't go above min_pll_multiplier. */
+	more_mul_max = min(more_mul_max,
+			   DIV_ROUND_UP(lim.max_pll_multiplier, mul));
+	dev_dbg(&client->dev, "more_mul_max: min_pll_multiplier check: %d\n",
+		more_mul_max);
+
+	/* Ensure we won't go below min_pll_op_freq_hz. */
+	more_mul_min = DIV_ROUND_UP(lim.min_pll_op_freq_hz,
+				    pll->ext_clk_freq_hz / pll->pre_pll_clk_div
+				    * mul);
+	dev_dbg(&client->dev, "more_mul_min: min_pll_op_freq_hz check: %d\n",
+		more_mul_min);
+	/* Ensure we won't go below min_pll_multiplier. */
+	more_mul_min = max(more_mul_min,
+			   DIV_ROUND_UP(lim.min_pll_multiplier, mul));
+	dev_dbg(&client->dev, "more_mul_min: min_pll_multiplier check: %d\n",
+		more_mul_min);
+
+	if (more_mul_min > more_mul_max) {
+		dev_warn(&client->dev,
+			 "unable to compute more_mul_min and more_mul_max");
+		return -EINVAL;
+	}
+
+	more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
+	dev_dbg(&client->dev, "more_mul_factor: %d\n", more_mul_factor);
+	more_mul_factor = lcm(more_mul_factor, lim.min_op_sys_clk_div);
+	dev_dbg(&client->dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
+		more_mul_factor);
+	i = ALIGN(more_mul_min, more_mul_factor);
+	if (!is_one_or_even(i))
+		i <<= 1;
+
+	dev_dbg(&client->dev, "final more_mul: %d\n", i);
+	if (i > more_mul_max) {
+		dev_warn(&client->dev, "final more_mul is bad, max %d",
+			 more_mul_max);
+		return -EINVAL;
+	}
+
+	pll->pll_multiplier = mul * i;
+	pll->op_sys_clk_div = div * i / pll->pre_pll_clk_div;
+	dev_dbg(&client->dev, "op_sys_clk_div: %d\n", pll->op_sys_clk_div);
+
+	pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
+		/ pll->pre_pll_clk_div;
+
+	pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
+		* pll->pll_multiplier;
+
+	/* Derive pll_op_clk_freq_hz. */
+	pll->op_sys_clk_freq_hz =
+		pll->pll_op_clk_freq_hz / pll->op_sys_clk_div;
+
+	pll->op_pix_clk_div = compressed;
+	dev_dbg(&client->dev, "op_pix_clk_div: %d\n", pll->op_pix_clk_div);
+
+	pll->op_pix_clk_freq_hz =
+		pll->op_sys_clk_freq_hz / pll->op_pix_clk_div;
+
+	/*
+	 * Some sensors perform analogue binning and some do this
+	 * digitally. The ones doing this digitally can be roughly be
+	 * found out using this formula. The ones doing this digitally
+	 * should run at higher clock rate, so smaller divisor is used
+	 * on video timing side.
+	 */
+	if (sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] >
+	    sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK] /
+	    sensor->binning_horizontal)
+		vt_op_binning_div = sensor->binning_horizontal;
+	else
+		vt_op_binning_div = 1;
+	dev_dbg(&client->dev, "vt_op_binning_div: %d\n", vt_op_binning_div);
+
+	/*
+	 * Profile 2 supports vt_pix_clk_div E [4, 10]
+	 *
+	 * Horizontal binning can be used as a base for difference in
+	 * divisors. One must make sure that horizontal blanking is
+	 * enough to accommodate the CSI-2 sync codes.
+	 *
+	 * Take scaling factor into account as well.
+	 *
+	 * Find absolute limits for the factor of vt divider.
+	 */
+	dev_dbg(&client->dev, "scale_m: %d\n", sensor->scale_m);
+	min_vt_div = DIV_ROUND_UP(pll->op_pix_clk_div * pll->op_sys_clk_div
+				  * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+				  lane_op_clock_ratio * vt_op_binning_div
+				  * sensor->scale_m);
+
+	/* Find smallest and biggest allowed vt divisor. */
+	dev_dbg(&client->dev, "min_vt_div: %d\n", min_vt_div);
+	min_vt_div = max(
+		min_vt_div,
+		DIV_ROUND_UP(
+			pll->pll_op_clk_freq_hz,
+			sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ]));
+	dev_dbg(&client->dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n",
+		min_vt_div);
+	min_vt_div = max(
+		min_vt_div,
+		sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV]
+		* sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV]);
+	dev_dbg(&client->dev, "min_vt_div: min_vt_clk_div: %d\n",
+		min_vt_div);
+
+	max_vt_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV]
+		* sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV];
+	dev_dbg(&client->dev, "max_vt_div: %d\n", max_vt_div);
+	max_vt_div = min(
+		max_vt_div,
+		DIV_ROUND_UP(
+			pll->pll_op_clk_freq_hz,
+			sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ]));
+	dev_dbg(&client->dev, "max_vt_div: %d\n", max_vt_div);
+
+	/*
+	 * Find limits for sys_clk_div. Not all values are possible
+	 * with all values of pix_clk_div.
+	 */
+	min_sys_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV];
+	dev_dbg(&client->dev, "min_sys_div: %d\n", min_sys_div);
+	min_sys_div = max(
+		min_sys_div,
+		DIV_ROUND_UP(
+			min_vt_div,
+			sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV]));
+	dev_dbg(&client->dev, "min_sys_div: max_vt_pix_clk_div: %d\n",
+		min_sys_div);
+	min_sys_div = max(
+		min_sys_div,
+		pll->pll_op_clk_freq_hz
+		/ sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ]);
+	dev_dbg(&client->dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n",
+		min_sys_div);
+	min_sys_div = clk_div_even_up(min_sys_div);
+	dev_dbg(&client->dev, "min_sys_div: one or even: %d\n", min_sys_div);
+
+	max_sys_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV];
+	dev_dbg(&client->dev, "max_sys_div: %d\n", max_sys_div);
+	max_sys_div = min(
+		max_sys_div,
+		DIV_ROUND_UP(
+			max_vt_div,
+			sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV]));
+	dev_dbg(&client->dev, "max_sys_div: min_vt_pix_clk_div: %d\n",
+		max_sys_div);
+	max_sys_div =
+		min(max_sys_div,
+		    DIV_ROUND_UP(
+			    pll->pll_op_clk_freq_hz,
+			    sensor->limits[
+				    SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ]));
+	dev_dbg(&client->dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n",
+		max_sys_div);
+
+	/*
+	 * Find pix_div such that a legal pix_div * sys_div results
+	 * into a value which is not smaller than div, the desired
+	 * divisor.
+	 */
+	for (vt_div = min_vt_div; vt_div <= max_vt_div;
+	     vt_div += 2 - (vt_div & 1)) {
+		for (sys_div = min_sys_div;
+		     sys_div <= max_sys_div;
+		     sys_div += 2 - (sys_div & 1)) {
+			int pix_div = DIV_ROUND_UP(vt_div, sys_div);
+
+			if (pix_div <
+			    sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV]
+			    || pix_div
+			    > sensor->limits[
+				    SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV]) {
+				dev_dbg(&client->dev,
+					"pix_div %d too small or too big (%d--%d)\n",
+					pix_div,
+					sensor->limits[
+						SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV],
+					sensor->limits[
+						SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV]);
+				continue;
+			}
+
+			/* Check if this one is better. */
+			if (pix_div * sys_div
+			    <= ALIGN(min_vt_div, best_pix_div))
+				best_pix_div = pix_div;
+		}
+		if (best_pix_div < INT_MAX >> 1)
+			break;
+	}
+
+	pll->vt_sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
+	pll->vt_pix_clk_div = best_pix_div;
+
+	pll->vt_sys_clk_freq_hz =
+		pll->pll_op_clk_freq_hz / pll->vt_sys_clk_div;
+	pll->vt_pix_clk_freq_hz =
+		pll->vt_sys_clk_freq_hz / pll->vt_pix_clk_div;
+
+	/* Distribute pixel clock information on subdevs. */
+	sensor->pixel_array->pixelrate[SMIAPP_PAD_SOURCE] =
+		pll->op_pix_clk_freq_hz / 1000 * vt_op_binning_div;
+
+	for (i = 0; i < SMIAPP_SUBDEVS; i++) {
+		struct smiapp_subdev *arr[] = {
+			sensor->pixel_array, sensor->binner, sensor->scaler, };
+		struct smiapp_subdev *this = arr[i];
+
+		if (!this)
+			continue;
+
+		if (!last) {
+			last = this;
+			continue;
+		}
+
+		this->pixelrate[SMIAPP_PAD_SINK] =
+			last->pixelrate[SMIAPP_PAD_SOURCE];
+
+		this->pixelrate[SMIAPP_PAD_SOURCE] =
+			this->pixelrate[SMIAPP_PAD_SINK];
+		if (this == sensor->binner)
+			this->pixelrate[SMIAPP_PAD_SOURCE] /=
+				vt_op_binning_div;
+	}
+
+	print_pll(sensor, pll);
+
+	bounds_check(&client->dev, pll->pre_pll_clk_div,
+		     sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV],
+		     sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV],
+		     "pre_pll_clk_div");
+	bounds_check(&client->dev, pll->pll_ip_clk_freq_hz,
+		     lim.min_pll_ip_freq_hz, lim.max_pll_ip_freq_hz,
+		     "pll_ip_clk_freq_hz");
+	bounds_check(&client->dev, pll->pll_multiplier,
+		     lim.min_pll_multiplier, lim.max_pll_multiplier,
+		     "pll_multiplier");
+	bounds_check(&client->dev, pll->pll_op_clk_freq_hz,
+		     lim.min_pll_op_freq_hz, lim.max_pll_op_freq_hz,
+		     "pll_op_clk_freq_hz");
+	bounds_check(&client->dev, pll->op_sys_clk_div,
+		     lim.min_op_sys_clk_div, lim.max_op_sys_clk_div,
+		     "op_sys_clk_div");
+	bounds_check(&client->dev, pll->op_pix_clk_div,
+		     lim.min_op_pix_clk_div, lim.max_op_pix_clk_div,
+		     "op_pix_clk_freq_hz");
+	bounds_check(&client->dev, pll->op_sys_clk_freq_hz,
+		     lim.min_op_sys_clk_freq_hz, lim.max_op_sys_clk_freq_hz,
+		     "op_sys_clk_freq_hz");
+	bounds_check(&client->dev, pll->op_pix_clk_freq_hz,
+		     lim.min_op_pix_clk_freq_hz, lim.max_op_pix_clk_freq_hz,
+		     "op_pix_clk_freq_hz");
+	bounds_check(&client->dev, pll->vt_sys_clk_freq_hz,
+		     sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ],
+		     sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ],
+		     "vt_sys_clk_freq_hz");
+	bounds_check(&client->dev, pll->vt_pix_clk_freq_hz,
+		     sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ],
+		     sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ],
+		     "vt_pix_clk_freq_hz");
+
+	return 0;
+}
+
+int smiapp_pll_configure(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct smiapp_pll *pll = &sensor->pll;
+	int rval;
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt_pix_clk_div);
+	if (rval < 0)
+		return rval;
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt_sys_clk_div);
+	if (rval < 0)
+		return rval;
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_PRE_PLL_CLK_DIV, pll->pre_pll_clk_div);
+	if (rval < 0)
+		return rval;
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_PLL_MULTIPLIER, pll->pll_multiplier);
+	if (rval < 0)
+		return rval;
+
+	/* Lane op clock ratio does not apply here. */
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS,
+		DIV_ROUND_UP(pll->op_sys_clk_freq_hz, 1000000 / 256 / 256));
+	if (rval < 0 ||
+	    sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
+		return rval;
+
+	rval = smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op_pix_clk_div);
+	if (rval < 0)
+		return rval;
+
+	return smia_i2c_write_reg(
+		client, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op_sys_clk_div);
+}
diff --git a/drivers/media/video/smiapp-quirk.c b/drivers/media/video/smiapp-quirk.c
new file mode 100644
index 0000000..afc73ff
--- /dev/null
+++ b/drivers/media/video/smiapp-quirk.c
@@ -0,0 +1,264 @@
+/*
+ * drivers/media/video/smiapp-pll.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "smiapp-debug.h"
+
+#include <linux/delay.h>
+
+#include "smiapp.h"
+
+static int smiapp_write_reg_8(struct smiapp_sensor *sensor, u16 reg, u8 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+	return smia_i2c_write_reg(client, (SMIA_REG_8BIT << 16) | reg, val);
+}
+
+static int smiapp_write_regs_8(struct smiapp_sensor *sensor,
+			       struct smiapp_reg_8 *regs, int len)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	for (; len > 0; len--, regs++) {
+		rval = smiapp_write_reg_8(sensor, regs->reg, regs->val);
+		if (rval < 0) {
+			dev_err(&client->dev,
+				"error %d writing reg 0x%4.4x, val 0x%2.2x",
+				rval, regs->reg, regs->val);
+			return rval;
+		}
+	}
+
+	return 0;
+}
+
+void smiapp_replace_limit(struct smiapp_sensor *sensor,
+			  u32 limit, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+	dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" = %d, 0x%x\n",
+		smiapp_reg_limits[limit].addr,
+		smiapp_reg_limits[limit].what, val, val);
+	sensor->limits[limit] = val;
+}
+
+int smiapp_replace_limit_at(struct smiapp_sensor *sensor,
+			    u32 reg, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int i;
+
+	for (i = 0; smiapp_reg_limits[i].addr; i++) {
+		if ((smiapp_reg_limits[i].addr & 0xffff) != reg)
+			continue;
+
+		smiapp_replace_limit(sensor, i, val);
+
+		return 0;
+	}
+
+	dev_dbg(&client->dev, "quirk: bad register 0x%4.4x\n", reg);
+
+	return -EINVAL;
+}
+
+static int jt8ew9_limits(struct smiapp_sensor *sensor)
+{
+	if (sensor->minfo.revision_number_major < 0x03)
+		sensor->frame_skip = 1;
+
+	/* Below 24 gain doesn't have effect at all, */
+	/* but ~59 is needed for full dynamic range */
+	smiapp_replace_limit(sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN, 59);
+	smiapp_replace_limit(
+		sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX, 6000);
+
+	return 0;
+}
+
+static int jt8ew9_post_poweron(struct smiapp_sensor *sensor)
+{
+	struct smiapp_reg_8 regs[] = {
+		{ 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */
+		{ 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+		{ 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+		{ 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */
+		{ 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+		{ 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+		{ 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+		{ 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+		{ 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */
+		{ 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+		{ 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+		{ 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+		{ 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+		{ 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+		{ 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+		/* Taken from v03. No idea what the rest are. */
+		{ 0x32e0, 0x05 },
+		{ 0x32e1, 0x05 },
+		{ 0x32e2, 0x04 },
+		{ 0x32e5, 0x04 },
+		{ 0x32e6, 0x04 },
+
+	};
+
+	return smiapp_write_regs_8(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_jt8ew9_quirk = {
+	.limits = jt8ew9_limits,
+	.post_poweron = jt8ew9_post_poweron,
+};
+
+static int imx125es_post_poweron(struct smiapp_sensor *sensor)
+{
+	/* Taken from v02. No idea what the other two are. */
+	struct smiapp_reg_8 regs[] = {
+		/*
+		 * 0x3302: clk during frame blanking:
+		 * 0x00 - HS mode, 0x01 - LP11
+		 */
+		{ 0x3302, 0x01 },
+		{ 0x302d, 0x00 },
+		{ 0x3b08, 0x8c },
+	};
+
+	return smiapp_write_regs_8(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_imx125es_quirk = {
+	.post_poweron = imx125es_post_poweron,
+};
+
+static int jt8ev1_limits(struct smiapp_sensor *sensor)
+{
+	smiapp_replace_limit(sensor, SMIAPP_LIMIT_X_ADDR_MAX, 4271);
+	smiapp_replace_limit(sensor,
+			     SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, 184);
+
+	return 0;
+}
+
+static int jt8ev1_post_poweron(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	int rval;
+
+	struct smiapp_reg_8 regs[] = {
+		{ 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */
+		{ 0x30a3, 0xd0 }, /* FLASH STROBE enable */
+		{ 0x3237, 0x00 }, /* For control of pulse timing for ADC */
+		{ 0x3238, 0x43 },
+		{ 0x3301, 0x06 }, /* For analog bias for sensor */
+		{ 0x3302, 0x06 },
+		{ 0x3304, 0x00 },
+		{ 0x3305, 0x88 },
+		{ 0x332a, 0x14 },
+		{ 0x332c, 0x6b },
+		{ 0x3336, 0x01 },
+		{ 0x333f, 0x1f },
+		{ 0x3355, 0x00 },
+		{ 0x3356, 0x20 },
+		{ 0x33bf, 0x20 }, /* Adjust the FBC speed */
+		{ 0x33c9, 0x20 },
+		{ 0x33ce, 0x30 }, /* Adjust the parameter for logic function */
+		{ 0x33cf, 0xec }, /* For Black sun */
+		{ 0x3328, 0x80 }, /* Ugh. No idea what's this. */
+	};
+
+	struct smiapp_reg_8 regs_96[] = {
+		{ 0x30ae, 0x00 }, /* For control of ADC clock */
+		{ 0x30af, 0xd0 },
+		{ 0x30b0, 0x01 },
+	};
+
+	rval = smiapp_write_regs_8(sensor, regs, ARRAY_SIZE(regs));
+	if (rval < 0)
+		return rval;
+
+	switch (sensor->platform_data->ext_clk) {
+	case 9600000:
+		return smiapp_write_regs_8(sensor, regs_96,
+					   ARRAY_SIZE(regs_96));
+	default:
+		dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n",
+			 sensor->platform_data->ext_clk);
+		return 0;
+	}
+}
+
+static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor)
+{
+	return smiapp_write_reg_8(sensor, 0x3328, 0x00);
+}
+
+static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
+{
+	int rval;
+
+	/* Workaround: allows fast standby to work properly */
+	rval = smiapp_write_reg_8(sensor, 0x3205, 0x04);
+	if (rval < 0)
+		return rval;
+
+	/* Wait for 1 ms + one line => 2 ms is likely enough */
+	usleep_range(2000, 2000);
+
+	/* Restore it */
+	rval = smiapp_write_reg_8(sensor, 0x3205, 0x00);
+	if (rval < 0)
+		return rval;
+
+	return smiapp_write_reg_8(sensor, 0x3328, 0x80);
+}
+
+const struct smiapp_quirk smiapp_jt8ev1_quirk = {
+	.limits = jt8ev1_limits,
+	.post_poweron = jt8ev1_post_poweron,
+	.pre_streamon = jt8ev1_pre_streamon,
+	.post_streamoff = jt8ev1_post_streamoff,
+	.flags = SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE,
+};
+
+static int tcm8500md_limits(struct smiapp_sensor *sensor)
+{
+	smiapp_replace_limit(sensor, SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ, 2700000);
+
+	return 0;
+}
+
+const struct smiapp_quirk smiapp_tcm8500md_quirk = {
+	.limits = tcm8500md_limits,
+};
diff --git a/drivers/media/video/smiapp-quirk.h b/drivers/media/video/smiapp-quirk.h
new file mode 100644
index 0000000..b9f56fd
--- /dev/null
+++ b/drivers/media/video/smiapp-quirk.h
@@ -0,0 +1,72 @@
+/*
+ * drivers/media/video/smiapp-quirk.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_QUIRK__
+#define __SMIAPP_QUIRK__
+
+struct smiapp_sensor;
+
+/**
+ * struct smiapp_quirk - quirks for sensors that deviate from SMIA++ standard
+ *
+ * @limits: Replace sensor->limits with values which can't be read from
+ *	    sensor registers. Called the first time the sensor is powered up.
+ * @post_poweron: Called always after the sensor has been fully powered on.
+ * @pre_streamon: Called just before streaming is enabled.
+ * @post_streamon: Called right after stopping streaming.
+ */
+struct smiapp_quirk {
+	int (*limits)(struct smiapp_sensor *sensor);
+	int (*post_poweron)(struct smiapp_sensor *sensor);
+	int (*pre_streamon)(struct smiapp_sensor *sensor);
+	int (*post_streamoff)(struct smiapp_sensor *sensor);
+	unsigned long flags;
+};
+
+/* op pix clock is for all lanes in total normally */
+#define SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE			(1 << 0)
+
+struct smiapp_reg_8 {
+	u16 reg;
+	u8 val;
+};
+
+void smiapp_replace_limit(struct smiapp_sensor *sensor,
+			  u32 limit, u32 val);
+
+#define smiapp_call_quirk(_sensor, _quirk, ...)				\
+	(_sensor->minfo.quirk &&					\
+	 _sensor->minfo.quirk->_quirk ?					\
+	 _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0)
+
+#define smiapp_needs_quirk(_sensor, _quirk)		\
+	(_sensor->minfo.quirk ?				\
+	 _sensor->minfo.quirk->flags & _quirk : 0)
+
+extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
+extern const struct smiapp_quirk smiapp_imx125es_quirk;
+extern const struct smiapp_quirk smiapp_jt8ew9_quirk;
+extern const struct smiapp_quirk smiapp_tcm8500md_quirk;
+
+#endif /* __SMIAPP_QUIRK__ */
diff --git a/drivers/media/video/smiapp-reg-defs.h b/drivers/media/video/smiapp-reg-defs.h
new file mode 100644
index 0000000..e94b9d1
--- /dev/null
+++ b/drivers/media/video/smiapp-reg-defs.h
@@ -0,0 +1,733 @@
+/*
+ * drivers/media/video/smiapp-reg-defs.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#define SMIAPP_REG_U16_MODEL_ID					((SMIA_REG_16BIT << 16) | 0x0000)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR			((SMIA_REG_8BIT << 16) | 0x0002)
+#define SMIAPP_REG_U8_MANUFACTURER_ID				((SMIA_REG_8BIT << 16) | 0x0003)
+#define SMIAPP_REG_U8_SMIA_VERSION				((SMIA_REG_8BIT << 16) | 0x0004)
+#define SMIAPP_REG_U8_FRAME_COUNT				((SMIA_REG_8BIT << 16) | 0x0005)
+#define SMIAPP_REG_U8_PIXEL_ORDER				((SMIA_REG_8BIT << 16) | 0x0006)
+#define SMIAPP_REG_U16_DATA_PEDESTAL				((SMIA_REG_16BIT << 16) | 0x0008)
+#define SMIAPP_REG_U8_PIXEL_DEPTH				((SMIA_REG_8BIT << 16) | 0x000c)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR			((SMIA_REG_8BIT << 16) | 0x0010)
+#define SMIAPP_REG_U8_SMIAPP_VERSION				((SMIA_REG_8BIT << 16) | 0x0011)
+#define SMIAPP_REG_U8_MODULE_DATE_YEAR				((SMIA_REG_8BIT << 16) | 0x0012)
+#define SMIAPP_REG_U8_MODULE_DATE_MONTH				((SMIA_REG_8BIT << 16) | 0x0013)
+#define SMIAPP_REG_U8_MODULE_DATE_DAY				((SMIA_REG_8BIT << 16) | 0x0014)
+#define SMIAPP_REG_U8_MODULE_DATE_PHASE				((SMIA_REG_8BIT << 16) | 0x0015)
+#define SMIAPP_REG_U16_SENSOR_MODEL_ID				((SMIA_REG_16BIT << 16) | 0x0016)
+#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER			((SMIA_REG_8BIT << 16) | 0x0018)
+#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID			((SMIA_REG_8BIT << 16) | 0x0019)
+#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION			((SMIA_REG_8BIT << 16) | 0x001a)
+#define SMIAPP_REG_U32_SERIAL_NUMBER				((SMIA_REG_32BIT << 16) | 0x001c)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE			((SMIA_REG_8BIT << 16) | 0x0040)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE		((SMIA_REG_8BIT << 16) | 0x0041)
+#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n)		((SMIA_REG_16BIT << 16) | (0x0042 + ((n) << 1))) /* 0 <= n <= 14 */
+#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n)		((SMIA_REG_32BIT << 16) | (0x0060 + ((n) << 2))) /* 0 <= n <= 7 */
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY			((SMIA_REG_16BIT << 16) | 0x0080)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN			((SMIA_REG_16BIT << 16) | 0x0084)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX			((SMIA_REG_16BIT << 16) | 0x0086)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP			((SMIA_REG_16BIT << 16) | 0x0088)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE			((SMIA_REG_16BIT << 16) | 0x008a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0				((SMIA_REG_16BIT << 16) | 0x008c)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0				((SMIA_REG_16BIT << 16) | 0x008e)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1				((SMIA_REG_16BIT << 16) | 0x0090)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1				((SMIA_REG_16BIT << 16) | 0x0092)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE			((SMIA_REG_8BIT << 16) | 0x00c0)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE			((SMIA_REG_8BIT << 16) | 0x00c1)
+#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n)		((SMIA_REG_16BIT << 16) | (0x00c2 + ((n) << 1)))
+#define SMIAPP_REG_U8_MODE_SELECT				((SMIA_REG_8BIT << 16) | 0x0100)
+#define SMIAPP_REG_U8_IMAGE_ORIENTATION				((SMIA_REG_8BIT << 16) | 0x0101)
+#define SMIAPP_REG_U8_SOFTWARE_RESET				((SMIA_REG_8BIT << 16) | 0x0103)
+#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD			((SMIA_REG_8BIT << 16) | 0x0104)
+#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES			((SMIA_REG_8BIT << 16) | 0x0105)
+#define SMIAPP_REG_U8_FAST_STANDBY_CTRL				((SMIA_REG_8BIT << 16) | 0x0106)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL			((SMIA_REG_8BIT << 16) | 0x0107)
+#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL			((SMIA_REG_8BIT << 16) | 0x0108)
+#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL			((SMIA_REG_8BIT << 16) | 0x0109)
+#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER			((SMIA_REG_8BIT << 16) | 0x0110)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE			((SMIA_REG_8BIT << 16) | 0x0111)
+#define SMIAPP_REG_U16_CSI_DATA_FORMAT				((SMIA_REG_16BIT << 16) | 0x0112)
+#define SMIAPP_REG_U8_CSI_LANE_MODE				((SMIA_REG_8BIT << 16) | 0x0114)
+#define SMIAPP_REG_U8_CSI2_10_TO_8_DT				((SMIA_REG_8BIT << 16) | 0x0115)
+#define SMIAPP_REG_U8_CSI2_10_TO_7_DT				((SMIA_REG_8BIT << 16) | 0x0116)
+#define SMIAPP_REG_U8_CSI2_10_TO_6_DT				((SMIA_REG_8BIT << 16) | 0x0117)
+#define SMIAPP_REG_U8_CSI2_12_TO_8_DT				((SMIA_REG_8BIT << 16) | 0x0118)
+#define SMIAPP_REG_U8_CSI2_12_TO_7_DT				((SMIA_REG_8BIT << 16) | 0x0119)
+#define SMIAPP_REG_U8_CSI2_12_TO_6_DT				((SMIA_REG_8BIT << 16) | 0x011a)
+#define SMIAPP_REG_U8_CSI2_14_TO_10_DT				((SMIA_REG_8BIT << 16) | 0x011b)
+#define SMIAPP_REG_U8_CSI2_14_TO_8_DT				((SMIA_REG_8BIT << 16) | 0x011c)
+#define SMIAPP_REG_U8_CSI2_16_TO_10_DT				((SMIA_REG_8BIT << 16) | 0x011d)
+#define SMIAPP_REG_U8_CSI2_16_TO_8_DT				((SMIA_REG_8BIT << 16) | 0x011e)
+#define SMIAPP_REG_U8_GAIN_MODE					((SMIA_REG_8BIT << 16) | 0x0120)
+#define SMIAPP_REG_U16_VANA_VOLTAGE				((SMIA_REG_16BIT << 16) | 0x0130)
+#define SMIAPP_REG_U16_VDIG_VOLTAGE				((SMIA_REG_16BIT << 16) | 0x0132)
+#define SMIAPP_REG_U16_VIO_VOLTAGE				((SMIA_REG_16BIT << 16) | 0x0134)
+#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ			((SMIA_REG_16BIT << 16) | 0x0136)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL			((SMIA_REG_8BIT << 16) | 0x0138)
+#define SMIAPP_REG_U8_TEMP_SENSOR_MODE				((SMIA_REG_8BIT << 16) | 0x0139)
+#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT			((SMIA_REG_8BIT << 16) | 0x013a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME			((SMIA_REG_16BIT << 16) | 0x0200)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME			((SMIA_REG_16BIT << 16) | 0x0202)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL		((SMIA_REG_16BIT << 16) | 0x0204)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR		((SMIA_REG_16BIT << 16) | 0x0206)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED			((SMIA_REG_16BIT << 16) | 0x0208)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE			((SMIA_REG_16BIT << 16) | 0x020a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB		((SMIA_REG_16BIT << 16) | 0x020c)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR			((SMIA_REG_16BIT << 16) | 0x020e)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_RED				((SMIA_REG_16BIT << 16) | 0x0210)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE			((SMIA_REG_16BIT << 16) | 0x0212)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB			((SMIA_REG_16BIT << 16) | 0x0214)
+#define SMIAPP_REG_U16_VT_PIX_CLK_DIV				((SMIA_REG_16BIT << 16) | 0x0300)
+#define SMIAPP_REG_U16_VT_SYS_CLK_DIV				((SMIA_REG_16BIT << 16) | 0x0302)
+#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV				((SMIA_REG_16BIT << 16) | 0x0304)
+#define SMIAPP_REG_U16_PLL_MULTIPLIER				((SMIA_REG_16BIT << 16) | 0x0306)
+#define SMIAPP_REG_U16_OP_PIX_CLK_DIV				((SMIA_REG_16BIT << 16) | 0x0308)
+#define SMIAPP_REG_U16_OP_SYS_CLK_DIV				((SMIA_REG_16BIT << 16) | 0x030a)
+#define SMIAPP_REG_U16_FRAME_LENGTH_LINES			((SMIA_REG_16BIT << 16) | 0x0340)
+#define SMIAPP_REG_U16_LINE_LENGTH_PCK				((SMIA_REG_16BIT << 16) | 0x0342)
+#define SMIAPP_REG_U16_X_ADDR_START				((SMIA_REG_16BIT << 16) | 0x0344)
+#define SMIAPP_REG_U16_Y_ADDR_START				((SMIA_REG_16BIT << 16) | 0x0346)
+#define SMIAPP_REG_U16_X_ADDR_END				((SMIA_REG_16BIT << 16) | 0x0348)
+#define SMIAPP_REG_U16_Y_ADDR_END				((SMIA_REG_16BIT << 16) | 0x034a)
+#define SMIAPP_REG_U16_X_OUTPUT_SIZE				((SMIA_REG_16BIT << 16) | 0x034c)
+#define SMIAPP_REG_U16_Y_OUTPUT_SIZE				((SMIA_REG_16BIT << 16) | 0x034e)
+#define SMIAPP_REG_U16_X_EVEN_INC				((SMIA_REG_16BIT << 16) | 0x0380)
+#define SMIAPP_REG_U16_X_ODD_INC				((SMIA_REG_16BIT << 16) | 0x0382)
+#define SMIAPP_REG_U16_Y_EVEN_INC				((SMIA_REG_16BIT << 16) | 0x0384)
+#define SMIAPP_REG_U16_Y_ODD_INC				((SMIA_REG_16BIT << 16) | 0x0386)
+#define SMIAPP_REG_U16_SCALING_MODE				((SMIA_REG_16BIT << 16) | 0x0400)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING				((SMIA_REG_16BIT << 16) | 0x0402)
+#define SMIAPP_REG_U16_SCALE_M					((SMIA_REG_16BIT << 16) | 0x0404)
+#define SMIAPP_REG_U16_SCALE_N					((SMIA_REG_16BIT << 16) | 0x0406)
+#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET			((SMIA_REG_16BIT << 16) | 0x0408)
+#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET			((SMIA_REG_16BIT << 16) | 0x040a)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH			((SMIA_REG_16BIT << 16) | 0x040c)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT		((SMIA_REG_16BIT << 16) | 0x040e)
+#define SMIAPP_REG_U16_COMPRESSION_MODE				((SMIA_REG_16BIT << 16) | 0x0500)
+#define SMIAPP_REG_U16_TEST_PATTERN_MODE			((SMIA_REG_16BIT << 16) | 0x0600)
+#define SMIAPP_REG_U16_TEST_DATA_RED				((SMIA_REG_16BIT << 16) | 0x0602)
+#define SMIAPP_REG_U16_TEST_DATA_GREENR				((SMIA_REG_16BIT << 16) | 0x0604)
+#define SMIAPP_REG_U16_TEST_DATA_BLUE				((SMIA_REG_16BIT << 16) | 0x0606)
+#define SMIAPP_REG_U16_TEST_DATA_GREENB				((SMIA_REG_16BIT << 16) | 0x0608)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH			((SMIA_REG_16BIT << 16) | 0x060a)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION		((SMIA_REG_16BIT << 16) | 0x060c)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH			((SMIA_REG_16BIT << 16) | 0x060e)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION			((SMIA_REG_16BIT << 16) | 0x0610)
+#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS			((SMIA_REG_16BIT << 16) | 0x0700)
+#define SMIAPP_REG_U8_TCLK_POST					((SMIA_REG_8BIT << 16) | 0x0800)
+#define SMIAPP_REG_U8_THS_PREPARE				((SMIA_REG_8BIT << 16) | 0x0801)
+#define SMIAPP_REG_U8_THS_ZERO_MIN				((SMIA_REG_8BIT << 16) | 0x0802)
+#define SMIAPP_REG_U8_THS_TRAIL					((SMIA_REG_8BIT << 16) | 0x0803)
+#define SMIAPP_REG_U8_TCLK_TRAIL_MIN				((SMIA_REG_8BIT << 16) | 0x0804)
+#define SMIAPP_REG_U8_TCLK_PREPARE				((SMIA_REG_8BIT << 16) | 0x0805)
+#define SMIAPP_REG_U8_TCLK_ZERO					((SMIA_REG_8BIT << 16) | 0x0806)
+#define SMIAPP_REG_U8_TLPX					((SMIA_REG_8BIT << 16) | 0x0807)
+#define SMIAPP_REG_U8_DPHY_CTRL					((SMIA_REG_8BIT << 16) | 0x0808)
+#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS		((SMIA_REG_32BIT << 16) | 0x0820)
+#define SMIAPP_REG_U8_BINNING_MODE				((SMIA_REG_8BIT << 16) | 0x0900)
+#define SMIAPP_REG_U8_BINNING_TYPE				((SMIA_REG_8BIT << 16) | 0x0901)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING				((SMIA_REG_8BIT << 16) | 0x0902)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL			((SMIA_REG_8BIT << 16) | 0x0a00)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS			((SMIA_REG_8BIT << 16) | 0x0a01)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT		((SMIA_REG_8BIT << 16) | 0x0a02)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0			((SMIA_REG_8BIT << 16) | 0x0a04)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1			((SMIA_REG_8BIT << 16) | 0x0a05)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2			((SMIA_REG_8BIT << 16) | 0x0a06)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3			((SMIA_REG_8BIT << 16) | 0x0a07)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4			((SMIA_REG_8BIT << 16) | 0x0a08)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5			((SMIA_REG_8BIT << 16) | 0x0a09)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12		((SMIA_REG_8BIT << 16) | 0x0a10)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13		((SMIA_REG_8BIT << 16) | 0x0a11)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14		((SMIA_REG_8BIT << 16) | 0x0a12)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15		((SMIA_REG_8BIT << 16) | 0x0a13)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16		((SMIA_REG_8BIT << 16) | 0x0a14)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17		((SMIA_REG_8BIT << 16) | 0x0a15)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18		((SMIA_REG_8BIT << 16) | 0x0a16)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19		((SMIA_REG_8BIT << 16) | 0x0a17)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20		((SMIA_REG_8BIT << 16) | 0x0a18)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21		((SMIA_REG_8BIT << 16) | 0x0a19)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22		((SMIA_REG_8BIT << 16) | 0x0a1a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23		((SMIA_REG_8BIT << 16) | 0x0a1b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24		((SMIA_REG_8BIT << 16) | 0x0a1c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25		((SMIA_REG_8BIT << 16) | 0x0a1d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26		((SMIA_REG_8BIT << 16) | 0x0a1e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27		((SMIA_REG_8BIT << 16) | 0x0a1f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28		((SMIA_REG_8BIT << 16) | 0x0a20)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29		((SMIA_REG_8BIT << 16) | 0x0a21)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30		((SMIA_REG_8BIT << 16) | 0x0a22)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31		((SMIA_REG_8BIT << 16) | 0x0a23)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32		((SMIA_REG_8BIT << 16) | 0x0a24)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33		((SMIA_REG_8BIT << 16) | 0x0a25)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34		((SMIA_REG_8BIT << 16) | 0x0a26)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35		((SMIA_REG_8BIT << 16) | 0x0a27)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36		((SMIA_REG_8BIT << 16) | 0x0a28)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37		((SMIA_REG_8BIT << 16) | 0x0a29)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38		((SMIA_REG_8BIT << 16) | 0x0a2a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39		((SMIA_REG_8BIT << 16) | 0x0a2b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40		((SMIA_REG_8BIT << 16) | 0x0a2c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41		((SMIA_REG_8BIT << 16) | 0x0a2d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42		((SMIA_REG_8BIT << 16) | 0x0a2e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43		((SMIA_REG_8BIT << 16) | 0x0a2f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44		((SMIA_REG_8BIT << 16) | 0x0a30)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45		((SMIA_REG_8BIT << 16) | 0x0a31)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46		((SMIA_REG_8BIT << 16) | 0x0a32)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47		((SMIA_REG_8BIT << 16) | 0x0a33)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48		((SMIA_REG_8BIT << 16) | 0x0a34)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49		((SMIA_REG_8BIT << 16) | 0x0a35)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50		((SMIA_REG_8BIT << 16) | 0x0a36)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51		((SMIA_REG_8BIT << 16) | 0x0a37)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52		((SMIA_REG_8BIT << 16) | 0x0a38)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53		((SMIA_REG_8BIT << 16) | 0x0a39)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54		((SMIA_REG_8BIT << 16) | 0x0a3a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55		((SMIA_REG_8BIT << 16) | 0x0a3b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56		((SMIA_REG_8BIT << 16) | 0x0a3c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57		((SMIA_REG_8BIT << 16) | 0x0a3d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58		((SMIA_REG_8BIT << 16) | 0x0a3e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59		((SMIA_REG_8BIT << 16) | 0x0a3f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60		((SMIA_REG_8BIT << 16) | 0x0a40)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61		((SMIA_REG_8BIT << 16) | 0x0a41)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62		((SMIA_REG_8BIT << 16) | 0x0a42)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63		((SMIA_REG_8BIT << 16) | 0x0a43)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL			((SMIA_REG_8BIT << 16) | 0x0a44)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS			((SMIA_REG_8BIT << 16) | 0x0a45)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT		((SMIA_REG_8BIT << 16) | 0x0a46)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0			((SMIA_REG_8BIT << 16) | 0x0a48)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1			((SMIA_REG_8BIT << 16) | 0x0a49)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2			((SMIA_REG_8BIT << 16) | 0x0a4a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3			((SMIA_REG_8BIT << 16) | 0x0a4b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4			((SMIA_REG_8BIT << 16) | 0x0a4c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5			((SMIA_REG_8BIT << 16) | 0x0a4d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6			((SMIA_REG_8BIT << 16) | 0x0a4e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7			((SMIA_REG_8BIT << 16) | 0x0a4f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8			((SMIA_REG_8BIT << 16) | 0x0a50)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9			((SMIA_REG_8BIT << 16) | 0x0a51)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10		((SMIA_REG_8BIT << 16) | 0x0a52)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11		((SMIA_REG_8BIT << 16) | 0x0a53)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12		((SMIA_REG_8BIT << 16) | 0x0a54)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13		((SMIA_REG_8BIT << 16) | 0x0a55)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14		((SMIA_REG_8BIT << 16) | 0x0a56)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15		((SMIA_REG_8BIT << 16) | 0x0a57)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16		((SMIA_REG_8BIT << 16) | 0x0a58)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17		((SMIA_REG_8BIT << 16) | 0x0a59)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18		((SMIA_REG_8BIT << 16) | 0x0a5a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19		((SMIA_REG_8BIT << 16) | 0x0a5b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20		((SMIA_REG_8BIT << 16) | 0x0a5c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21		((SMIA_REG_8BIT << 16) | 0x0a5d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22		((SMIA_REG_8BIT << 16) | 0x0a5e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23		((SMIA_REG_8BIT << 16) | 0x0a5f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24		((SMIA_REG_8BIT << 16) | 0x0a60)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25		((SMIA_REG_8BIT << 16) | 0x0a61)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26		((SMIA_REG_8BIT << 16) | 0x0a62)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27		((SMIA_REG_8BIT << 16) | 0x0a63)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28		((SMIA_REG_8BIT << 16) | 0x0a64)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29		((SMIA_REG_8BIT << 16) | 0x0a65)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30		((SMIA_REG_8BIT << 16) | 0x0a66)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31		((SMIA_REG_8BIT << 16) | 0x0a67)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32		((SMIA_REG_8BIT << 16) | 0x0a68)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33		((SMIA_REG_8BIT << 16) | 0x0a69)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34		((SMIA_REG_8BIT << 16) | 0x0a6a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35		((SMIA_REG_8BIT << 16) | 0x0a6b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36		((SMIA_REG_8BIT << 16) | 0x0a6c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37		((SMIA_REG_8BIT << 16) | 0x0a6d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38		((SMIA_REG_8BIT << 16) | 0x0a6e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39		((SMIA_REG_8BIT << 16) | 0x0a6f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40		((SMIA_REG_8BIT << 16) | 0x0a70)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41		((SMIA_REG_8BIT << 16) | 0x0a71)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42		((SMIA_REG_8BIT << 16) | 0x0a72)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43		((SMIA_REG_8BIT << 16) | 0x0a73)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44		((SMIA_REG_8BIT << 16) | 0x0a74)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45		((SMIA_REG_8BIT << 16) | 0x0a75)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46		((SMIA_REG_8BIT << 16) | 0x0a76)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47		((SMIA_REG_8BIT << 16) | 0x0a77)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48		((SMIA_REG_8BIT << 16) | 0x0a78)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49		((SMIA_REG_8BIT << 16) | 0x0a79)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50		((SMIA_REG_8BIT << 16) | 0x0a7a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51		((SMIA_REG_8BIT << 16) | 0x0a7b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52		((SMIA_REG_8BIT << 16) | 0x0a7c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53		((SMIA_REG_8BIT << 16) | 0x0a7d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54		((SMIA_REG_8BIT << 16) | 0x0a7e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55		((SMIA_REG_8BIT << 16) | 0x0a7f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56		((SMIA_REG_8BIT << 16) | 0x0a80)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57		((SMIA_REG_8BIT << 16) | 0x0a81)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58		((SMIA_REG_8BIT << 16) | 0x0a82)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59		((SMIA_REG_8BIT << 16) | 0x0a83)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60		((SMIA_REG_8BIT << 16) | 0x0a84)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61		((SMIA_REG_8BIT << 16) | 0x0a85)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62		((SMIA_REG_8BIT << 16) | 0x0a86)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63		((SMIA_REG_8BIT << 16) | 0x0a87)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE			((SMIA_REG_8BIT << 16) | 0x0b00)
+#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL		((SMIA_REG_8BIT << 16) | 0x0b01)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE		((SMIA_REG_8BIT << 16) | 0x0b02)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT		((SMIA_REG_8BIT << 16) | 0x0b03)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE		((SMIA_REG_8BIT << 16) | 0x0b04)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE		((SMIA_REG_8BIT << 16) | 0x0b05)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE		((SMIA_REG_8BIT << 16) | 0x0b06)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT		((SMIA_REG_8BIT << 16) | 0x0b07)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE		((SMIA_REG_8BIT << 16) | 0x0b08)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT		((SMIA_REG_8BIT << 16) | 0x0b09)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE		((SMIA_REG_8BIT << 16) | 0x0b0a)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT		((SMIA_REG_8BIT << 16) | 0x0b0b)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE		((SMIA_REG_8BIT << 16) | 0x0b0c)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT		((SMIA_REG_8BIT << 16) | 0x0b0d)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE		((SMIA_REG_8BIT << 16) | 0x0b0e)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST		((SMIA_REG_8BIT << 16) | 0x0b0f)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST		((SMIA_REG_8BIT << 16) | 0x0b10)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE	((SMIA_REG_8BIT << 16) | 0x0b11)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST	((SMIA_REG_8BIT << 16) | 0x0b12)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE	((SMIA_REG_8BIT << 16) | 0x0b13)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST	((SMIA_REG_8BIT << 16) | 0x0b14)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE	((SMIA_REG_8BIT << 16) | 0x0b15)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST	((SMIA_REG_8BIT << 16) | 0x0b16)
+#define SMIAPP_REG_U8_EDOF_MODE					((SMIA_REG_8BIT << 16) | 0x0b80)
+#define SMIAPP_REG_U8_SHARPNESS					((SMIA_REG_8BIT << 16) | 0x0b83)
+#define SMIAPP_REG_U8_DENOISING					((SMIA_REG_8BIT << 16) | 0x0b84)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC				((SMIA_REG_8BIT << 16) | 0x0b85)
+#define SMIAPP_REG_U16_DEPTH_OF_FIELD				((SMIA_REG_16BIT << 16) | 0x0b86)
+#define SMIAPP_REG_U16_FOCUS_DISTANCE				((SMIA_REG_16BIT << 16) | 0x0b88)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL			((SMIA_REG_8BIT << 16) | 0x0b8a)
+#define SMIAPP_REG_U16_COLOUR_TEMPERATURE			((SMIA_REG_16BIT << 16) | 0x0b8c)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR			((SMIA_REG_16BIT << 16) | 0x0b8e)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED			((SMIA_REG_16BIT << 16) | 0x0b90)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE			((SMIA_REG_16BIT << 16) | 0x0b92)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB			((SMIA_REG_16BIT << 16) | 0x0b94)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE			((SMIA_REG_8BIT << 16) | 0x0bc0)
+#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING			((SMIA_REG_16BIT << 16) | 0x0bc2)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START			((SMIA_REG_16BIT << 16) | 0x0bc4)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START			((SMIA_REG_16BIT << 16) | 0x0bc6)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH			((SMIA_REG_16BIT << 16) | 0x0bc8)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT			((SMIA_REG_16BIT << 16) | 0x0bca)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1			((SMIA_REG_8BIT << 16) | 0x0c00)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2			((SMIA_REG_8BIT << 16) | 0x0c01)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1		((SMIA_REG_8BIT << 16) | 0x0c02)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2		((SMIA_REG_8BIT << 16) | 0x0c03)
+#define SMIAPP_REG_U16_TRDY_CTRL				((SMIA_REG_16BIT << 16) | 0x0c04)
+#define SMIAPP_REG_U16_TRDOUT_CTRL				((SMIA_REG_16BIT << 16) | 0x0c06)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL		((SMIA_REG_16BIT << 16) | 0x0c08)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL		((SMIA_REG_16BIT << 16) | 0x0c0a)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL			((SMIA_REG_16BIT << 16) | 0x0c0c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL		((SMIA_REG_16BIT << 16) | 0x0c0e)
+#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL			((SMIA_REG_16BIT << 16) | 0x0c10)
+#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT			((SMIA_REG_8BIT << 16) | 0x0c12)
+#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT			((SMIA_REG_16BIT << 16) | 0x0c14)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL		((SMIA_REG_16BIT << 16) | 0x0c16)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL		((SMIA_REG_16BIT << 16) | 0x0c18)
+#define SMIAPP_REG_U8_FLASH_MODE_RS				((SMIA_REG_8BIT << 16) | 0x0c1a)
+#define SMIAPP_REG_U8_FLASH_TRIGGER_RS				((SMIA_REG_8BIT << 16) | 0x0c1b)
+#define SMIAPP_REG_U8_FLASH_STATUS				((SMIA_REG_8BIT << 16) | 0x0c1c)
+#define SMIAPP_REG_U8_SA_STROBE_MODE				((SMIA_REG_8BIT << 16) | 0x0c1d)
+#define SMIAPP_REG_U16_SA_STROBE_START_POINT			((SMIA_REG_16BIT << 16) | 0x0c1e)
+#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL			((SMIA_REG_16BIT << 16) | 0x0c20)
+#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL			((SMIA_REG_16BIT << 16) | 0x0c22)
+#define SMIAPP_REG_U8_SA_STROBE_TRIGGER				((SMIA_REG_8BIT << 16) | 0x0c24)
+#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS			((SMIA_REG_8BIT << 16) | 0x0c25)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL	((SMIA_REG_16BIT << 16) | 0x0c26)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL		((SMIA_REG_16BIT << 16) | 0x0c28)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL		((SMIA_REG_8BIT << 16) | 0x0c2a)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL			((SMIA_REG_8BIT << 16) | 0x0c2b)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL		((SMIA_REG_16BIT << 16) | 0x0c2c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL		((SMIA_REG_16BIT << 16) | 0x0c2e)
+#define SMIAPP_REG_U8_LOW_LEVEL_CTRL				((SMIA_REG_8BIT << 16) | 0x0c80)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT			((SMIA_REG_16BIT << 16) | 0x0c82)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_T3				((SMIA_REG_16BIT << 16) | 0x0c84)
+#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT			((SMIA_REG_8BIT << 16) | 0x0c86)
+#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3			((SMIA_REG_16BIT << 16) | 0x0c88)
+#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT			((SMIA_REG_8BIT << 16) | 0x0c8a)
+#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3			((SMIA_REG_16BIT << 16) | 0x0c8c)
+#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT			((SMIA_REG_8BIT << 16) | 0x0c8e)
+#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL				((SMIA_REG_8BIT << 16) | 0x0d00)
+#define SMIAPP_REG_U8_OPERATION_MODE				((SMIA_REG_8BIT << 16) | 0x0d01)
+#define SMIAPP_REG_U8_ACT_STATE1				((SMIA_REG_8BIT << 16) | 0x0d02)
+#define SMIAPP_REG_U8_ACT_STATE2				((SMIA_REG_8BIT << 16) | 0x0d03)
+#define SMIAPP_REG_U16_FOCUS_CHANGE				((SMIA_REG_16BIT << 16) | 0x0d80)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL			((SMIA_REG_16BIT << 16) | 0x0d82)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1		((SMIA_REG_16BIT << 16) | 0x0d84)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2		((SMIA_REG_16BIT << 16) | 0x0d86)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1			((SMIA_REG_8BIT << 16) | 0x0d88)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2			((SMIA_REG_8BIT << 16) | 0x0d89)
+#define SMIAPP_REG_U8_POSITION					((SMIA_REG_8BIT << 16) | 0x0d8a)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL			((SMIA_REG_8BIT << 16) | 0x0e00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_MODE			((SMIA_REG_8BIT << 16) | 0x0e01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL		((SMIA_REG_8BIT << 16) | 0x0e02)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_START			((SMIA_REG_8BIT << 16) | 0x0e10)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_END			((SMIA_REG_8BIT << 16) | 0x0eff)
+#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY		((SMIA_REG_16BIT << 16) | 0x1000)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN		((SMIA_REG_16BIT << 16) | 0x1004)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN	((SMIA_REG_16BIT << 16) | 0x1006)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN		((SMIA_REG_16BIT << 16) | 0x1008)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN		((SMIA_REG_16BIT << 16) | 0x100a)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY			((SMIA_REG_16BIT << 16) | 0x1080)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN				((SMIA_REG_16BIT << 16) | 0x1084)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX				((SMIA_REG_16BIT << 16) | 0x1086)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE			((SMIA_REG_16BIT << 16) | 0x1088)
+#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1100)
+#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1104)
+#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x1108)
+#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x110a)
+#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x110c)
+#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1110)
+#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER			((SMIA_REG_16BIT << 16) | 0x1114)
+#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER			((SMIA_REG_16BIT << 16) | 0x1116)
+#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1118)
+#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x111c)
+#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x1120)
+#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x1122)
+#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1124)
+#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1128)
+#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x112c)
+#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1130)
+#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x1134)
+#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x1136)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES			((SMIA_REG_16BIT << 16) | 0x1140)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES			((SMIA_REG_16BIT << 16) | 0x1142)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK			((SMIA_REG_16BIT << 16) | 0x1144)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK			((SMIA_REG_16BIT << 16) | 0x1146)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK			((SMIA_REG_16BIT << 16) | 0x1148)
+#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES			((SMIA_REG_16BIT << 16) | 0x114a)
+#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE		((SMIA_REG_8BIT << 16) | 0x114c)
+#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x1160)
+#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x1162)
+#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1164)
+#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1168)
+#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x116c)
+#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV			((SMIA_REG_16BIT << 16) | 0x116e)
+#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1170)
+#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ			(SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | 0x1174)
+#define SMIAPP_REG_U16_X_ADDR_MIN				((SMIA_REG_16BIT << 16) | 0x1180)
+#define SMIAPP_REG_U16_Y_ADDR_MIN				((SMIA_REG_16BIT << 16) | 0x1182)
+#define SMIAPP_REG_U16_X_ADDR_MAX				((SMIA_REG_16BIT << 16) | 0x1184)
+#define SMIAPP_REG_U16_Y_ADDR_MAX				((SMIA_REG_16BIT << 16) | 0x1186)
+#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE			((SMIA_REG_16BIT << 16) | 0x1188)
+#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE			((SMIA_REG_16BIT << 16) | 0x118a)
+#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE			((SMIA_REG_16BIT << 16) | 0x118c)
+#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE			((SMIA_REG_16BIT << 16) | 0x118e)
+#define SMIAPP_REG_U16_MIN_EVEN_INC				((SMIA_REG_16BIT << 16) | 0x11c0)
+#define SMIAPP_REG_U16_MAX_EVEN_INC				((SMIA_REG_16BIT << 16) | 0x11c2)
+#define SMIAPP_REG_U16_MIN_ODD_INC				((SMIA_REG_16BIT << 16) | 0x11c4)
+#define SMIAPP_REG_U16_MAX_ODD_INC				((SMIA_REG_16BIT << 16) | 0x11c6)
+#define SMIAPP_REG_U16_SCALING_CAPABILITY			((SMIA_REG_16BIT << 16) | 0x1200)
+#define SMIAPP_REG_U16_SCALER_M_MIN				((SMIA_REG_16BIT << 16) | 0x1204)
+#define SMIAPP_REG_U16_SCALER_M_MAX				((SMIA_REG_16BIT << 16) | 0x1206)
+#define SMIAPP_REG_U16_SCALER_N_MIN				((SMIA_REG_16BIT << 16) | 0x1208)
+#define SMIAPP_REG_U16_SCALER_N_MAX				((SMIA_REG_16BIT << 16) | 0x120a)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY		((SMIA_REG_16BIT << 16) | 0x120c)
+#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x120e)
+#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY			((SMIA_REG_16BIT << 16) | 0x1300)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED			((SMIA_REG_16BIT << 16) | 0x1400)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED		((SMIA_REG_16BIT << 16) | 0x1402)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED			((SMIA_REG_16BIT << 16) | 0x1404)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN		((SMIA_REG_16BIT << 16) | 0x1406)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN		((SMIA_REG_16BIT << 16) | 0x1408)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN		((SMIA_REG_16BIT << 16) | 0x140a)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE			((SMIA_REG_16BIT << 16) | 0x140c)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE		((SMIA_REG_16BIT << 16) | 0x140e)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE		((SMIA_REG_16BIT << 16) | 0x1410)
+#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS				((SMIA_REG_16BIT << 16) | 0x1500)
+#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x1502)
+#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x1600)
+#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x1601)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY		((SMIA_REG_8BIT << 16) | 0x1602)
+#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x1603)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY		((SMIA_REG_8BIT << 16) | 0x1604)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS	((SMIA_REG_32BIT << 16) | 0x1608)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS	((SMIA_REG_32BIT << 16) | 0x160c)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS	((SMIA_REG_32BIT << 16) | 0x1610)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS	((SMIA_REG_32BIT << 16) | 0x1614)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x1618)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN		((SMIA_REG_16BIT << 16) | 0x1700)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN		((SMIA_REG_16BIT << 16) | 0x1702)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN			((SMIA_REG_16BIT << 16) | 0x1704)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN			((SMIA_REG_16BIT << 16) | 0x1706)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN		((SMIA_REG_16BIT << 16) | 0x1708)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN		((SMIA_REG_16BIT << 16) | 0x170a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN	((SMIA_REG_16BIT << 16) | 0x170c)
+#define SMIAPP_REG_U8_BINNING_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x1710)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY		((SMIA_REG_8BIT << 16) | 0x1711)
+#define SMIAPP_REG_U8_BINNING_SUBTYPES				((SMIA_REG_8BIT << 16) | 0x1712)
+#define SMIAPP_REG_U8_BINNING_TYPE_1				((SMIA_REG_8BIT << 16) | 0x1713)
+#define SMIAPP_REG_U8_BINNING_TYPE_2				((SMIA_REG_8BIT << 16) | 0x1714)
+#define SMIAPP_REG_U8_BINNING_TYPE_3				((SMIA_REG_8BIT << 16) | 0x1715)
+#define SMIAPP_REG_U8_BINNING_TYPE_4				((SMIA_REG_8BIT << 16) | 0x1716)
+#define SMIAPP_REG_U8_BINNING_TYPE_5				((SMIA_REG_8BIT << 16) | 0x1717)
+#define SMIAPP_REG_U8_BINNING_TYPE_6				((SMIA_REG_8BIT << 16) | 0x1718)
+#define SMIAPP_REG_U8_BINNING_TYPE_7				((SMIA_REG_8BIT << 16) | 0x1719)
+#define SMIAPP_REG_U8_BINNING_TYPE_8				((SMIA_REG_8BIT << 16) | 0x171a)
+#define SMIAPP_REG_U8_BINNING_TYPE_9				((SMIA_REG_8BIT << 16) | 0x171b)
+#define SMIAPP_REG_U8_BINNING_TYPE_10				((SMIA_REG_8BIT << 16) | 0x171c)
+#define SMIAPP_REG_U8_BINNING_TYPE_11				((SMIA_REG_8BIT << 16) | 0x171d)
+#define SMIAPP_REG_U8_BINNING_TYPE_12				((SMIA_REG_8BIT << 16) | 0x171e)
+#define SMIAPP_REG_U8_BINNING_TYPE_13				((SMIA_REG_8BIT << 16) | 0x171f)
+#define SMIAPP_REG_U8_BINNING_TYPE_14				((SMIA_REG_8BIT << 16) | 0x1720)
+#define SMIAPP_REG_U8_BINNING_TYPE_15				((SMIA_REG_8BIT << 16) | 0x1721)
+#define SMIAPP_REG_U8_BINNING_TYPE_16				((SMIA_REG_8BIT << 16) | 0x1722)
+#define SMIAPP_REG_U8_BINNING_TYPE_17				((SMIA_REG_8BIT << 16) | 0x1723)
+#define SMIAPP_REG_U8_BINNING_TYPE_18				((SMIA_REG_8BIT << 16) | 0x1724)
+#define SMIAPP_REG_U8_BINNING_TYPE_19				((SMIA_REG_8BIT << 16) | 0x1725)
+#define SMIAPP_REG_U8_BINNING_TYPE_20				((SMIA_REG_8BIT << 16) | 0x1726)
+#define SMIAPP_REG_U8_BINNING_TYPE_21				((SMIA_REG_8BIT << 16) | 0x1727)
+#define SMIAPP_REG_U8_BINNING_TYPE_22				((SMIA_REG_8BIT << 16) | 0x1728)
+#define SMIAPP_REG_U8_BINNING_TYPE_23				((SMIA_REG_8BIT << 16) | 0x1729)
+#define SMIAPP_REG_U8_BINNING_TYPE_24				((SMIA_REG_8BIT << 16) | 0x172a)
+#define SMIAPP_REG_U8_BINNING_TYPE_25				((SMIA_REG_8BIT << 16) | 0x172b)
+#define SMIAPP_REG_U8_BINNING_TYPE_26				((SMIA_REG_8BIT << 16) | 0x172c)
+#define SMIAPP_REG_U8_BINNING_TYPE_27				((SMIA_REG_8BIT << 16) | 0x172d)
+#define SMIAPP_REG_U8_BINNING_TYPE_28				((SMIA_REG_8BIT << 16) | 0x172e)
+#define SMIAPP_REG_U8_BINNING_TYPE_29				((SMIA_REG_8BIT << 16) | 0x172f)
+#define SMIAPP_REG_U8_BINNING_TYPE_30				((SMIA_REG_8BIT << 16) | 0x1730)
+#define SMIAPP_REG_U8_BINNING_TYPE_31				((SMIA_REG_8BIT << 16) | 0x1731)
+#define SMIAPP_REG_U8_BINNING_TYPE_32				((SMIA_REG_8BIT << 16) | 0x1732)
+#define SMIAPP_REG_U8_BINNING_TYPE_33				((SMIA_REG_8BIT << 16) | 0x1733)
+#define SMIAPP_REG_U8_BINNING_TYPE_34				((SMIA_REG_8BIT << 16) | 0x1734)
+#define SMIAPP_REG_U8_BINNING_TYPE_35				((SMIA_REG_8BIT << 16) | 0x1735)
+#define SMIAPP_REG_U8_BINNING_TYPE_36				((SMIA_REG_8BIT << 16) | 0x1736)
+#define SMIAPP_REG_U8_BINNING_TYPE_37				((SMIA_REG_8BIT << 16) | 0x1737)
+#define SMIAPP_REG_U8_BINNING_TYPE_38				((SMIA_REG_8BIT << 16) | 0x1738)
+#define SMIAPP_REG_U8_BINNING_TYPE_39				((SMIA_REG_8BIT << 16) | 0x1739)
+#define SMIAPP_REG_U8_BINNING_TYPE_40				((SMIA_REG_8BIT << 16) | 0x173a)
+#define SMIAPP_REG_U8_BINNING_TYPE_41				((SMIA_REG_8BIT << 16) | 0x173b)
+#define SMIAPP_REG_U8_BINNING_TYPE_42				((SMIA_REG_8BIT << 16) | 0x173c)
+#define SMIAPP_REG_U8_BINNING_TYPE_43				((SMIA_REG_8BIT << 16) | 0x173d)
+#define SMIAPP_REG_U8_BINNING_TYPE_44				((SMIA_REG_8BIT << 16) | 0x173e)
+#define SMIAPP_REG_U8_BINNING_TYPE_45				((SMIA_REG_8BIT << 16) | 0x173f)
+#define SMIAPP_REG_U8_BINNING_TYPE_46				((SMIA_REG_8BIT << 16) | 0x1740)
+#define SMIAPP_REG_U8_BINNING_TYPE_47				((SMIA_REG_8BIT << 16) | 0x1741)
+#define SMIAPP_REG_U8_BINNING_TYPE_48				((SMIA_REG_8BIT << 16) | 0x1742)
+#define SMIAPP_REG_U8_BINNING_TYPE_49				((SMIA_REG_8BIT << 16) | 0x1743)
+#define SMIAPP_REG_U8_BINNING_TYPE_50				((SMIA_REG_8BIT << 16) | 0x1744)
+#define SMIAPP_REG_U8_BINNING_TYPE_51				((SMIA_REG_8BIT << 16) | 0x1745)
+#define SMIAPP_REG_U8_BINNING_TYPE_52				((SMIA_REG_8BIT << 16) | 0x1746)
+#define SMIAPP_REG_U8_BINNING_TYPE_53				((SMIA_REG_8BIT << 16) | 0x1747)
+#define SMIAPP_REG_U8_BINNING_TYPE_54				((SMIA_REG_8BIT << 16) | 0x1748)
+#define SMIAPP_REG_U8_BINNING_TYPE_55				((SMIA_REG_8BIT << 16) | 0x1749)
+#define SMIAPP_REG_U8_BINNING_TYPE_56				((SMIA_REG_8BIT << 16) | 0x174a)
+#define SMIAPP_REG_U8_BINNING_TYPE_57				((SMIA_REG_8BIT << 16) | 0x174b)
+#define SMIAPP_REG_U8_BINNING_TYPE_58				((SMIA_REG_8BIT << 16) | 0x174c)
+#define SMIAPP_REG_U8_BINNING_TYPE_59				((SMIA_REG_8BIT << 16) | 0x174d)
+#define SMIAPP_REG_U8_BINNING_TYPE_60				((SMIA_REG_8BIT << 16) | 0x174e)
+#define SMIAPP_REG_U8_BINNING_TYPE_61				((SMIA_REG_8BIT << 16) | 0x174f)
+#define SMIAPP_REG_U8_BINNING_TYPE_62				((SMIA_REG_8BIT << 16) | 0x1750)
+#define SMIAPP_REG_U8_BINNING_TYPE_63				((SMIA_REG_8BIT << 16) | 0x1751)
+#define SMIAPP_REG_U8_BINNING_TYPE_64				((SMIA_REG_8BIT << 16) | 0x1752)
+#define SMIAPP_REG_U8_BINNING_TYPE_65				((SMIA_REG_8BIT << 16) | 0x1753)
+#define SMIAPP_REG_U8_BINNING_TYPE_66				((SMIA_REG_8BIT << 16) | 0x1754)
+#define SMIAPP_REG_U8_BINNING_TYPE_67				((SMIA_REG_8BIT << 16) | 0x1755)
+#define SMIAPP_REG_U8_BINNING_TYPE_68				((SMIA_REG_8BIT << 16) | 0x1756)
+#define SMIAPP_REG_U8_BINNING_TYPE_69				((SMIA_REG_8BIT << 16) | 0x1757)
+#define SMIAPP_REG_U8_BINNING_TYPE_70				((SMIA_REG_8BIT << 16) | 0x1758)
+#define SMIAPP_REG_U8_BINNING_TYPE_71				((SMIA_REG_8BIT << 16) | 0x1759)
+#define SMIAPP_REG_U8_BINNING_TYPE_72				((SMIA_REG_8BIT << 16) | 0x175a)
+#define SMIAPP_REG_U8_BINNING_TYPE_73				((SMIA_REG_8BIT << 16) | 0x175b)
+#define SMIAPP_REG_U8_BINNING_TYPE_74				((SMIA_REG_8BIT << 16) | 0x175c)
+#define SMIAPP_REG_U8_BINNING_TYPE_75				((SMIA_REG_8BIT << 16) | 0x175d)
+#define SMIAPP_REG_U8_BINNING_TYPE_76				((SMIA_REG_8BIT << 16) | 0x175e)
+#define SMIAPP_REG_U8_BINNING_TYPE_77				((SMIA_REG_8BIT << 16) | 0x175f)
+#define SMIAPP_REG_U8_BINNING_TYPE_78				((SMIA_REG_8BIT << 16) | 0x1760)
+#define SMIAPP_REG_U8_BINNING_TYPE_79				((SMIA_REG_8BIT << 16) | 0x1761)
+#define SMIAPP_REG_U8_BINNING_TYPE_80				((SMIA_REG_8BIT << 16) | 0x1762)
+#define SMIAPP_REG_U8_BINNING_TYPE_81				((SMIA_REG_8BIT << 16) | 0x1763)
+#define SMIAPP_REG_U8_BINNING_TYPE_82				((SMIA_REG_8BIT << 16) | 0x1764)
+#define SMIAPP_REG_U8_BINNING_TYPE_83				((SMIA_REG_8BIT << 16) | 0x1765)
+#define SMIAPP_REG_U8_BINNING_TYPE_84				((SMIA_REG_8BIT << 16) | 0x1766)
+#define SMIAPP_REG_U8_BINNING_TYPE_85				((SMIA_REG_8BIT << 16) | 0x1767)
+#define SMIAPP_REG_U8_BINNING_TYPE_86				((SMIA_REG_8BIT << 16) | 0x1768)
+#define SMIAPP_REG_U8_BINNING_TYPE_87				((SMIA_REG_8BIT << 16) | 0x1769)
+#define SMIAPP_REG_U8_BINNING_TYPE_88				((SMIA_REG_8BIT << 16) | 0x176a)
+#define SMIAPP_REG_U8_BINNING_TYPE_89				((SMIA_REG_8BIT << 16) | 0x176b)
+#define SMIAPP_REG_U8_BINNING_TYPE_90				((SMIA_REG_8BIT << 16) | 0x176c)
+#define SMIAPP_REG_U8_BINNING_TYPE_91				((SMIA_REG_8BIT << 16) | 0x176d)
+#define SMIAPP_REG_U8_BINNING_TYPE_92				((SMIA_REG_8BIT << 16) | 0x176e)
+#define SMIAPP_REG_U8_BINNING_TYPE_93				((SMIA_REG_8BIT << 16) | 0x176f)
+#define SMIAPP_REG_U8_BINNING_TYPE_94				((SMIA_REG_8BIT << 16) | 0x1770)
+#define SMIAPP_REG_U8_BINNING_TYPE_95				((SMIA_REG_8BIT << 16) | 0x1771)
+#define SMIAPP_REG_U8_BINNING_TYPE_96				((SMIA_REG_8BIT << 16) | 0x1772)
+#define SMIAPP_REG_U8_BINNING_TYPE_97				((SMIA_REG_8BIT << 16) | 0x1773)
+#define SMIAPP_REG_U8_BINNING_TYPE_98				((SMIA_REG_8BIT << 16) | 0x1774)
+#define SMIAPP_REG_U8_BINNING_TYPE_99				((SMIA_REG_8BIT << 16) | 0x1775)
+#define SMIAPP_REG_U8_BINNING_TYPE_100				((SMIA_REG_8BIT << 16) | 0x1776)
+#define SMIAPP_REG_U8_BINNING_TYPE_101				((SMIA_REG_8BIT << 16) | 0x1777)
+#define SMIAPP_REG_U8_BINNING_TYPE_102				((SMIA_REG_8BIT << 16) | 0x1778)
+#define SMIAPP_REG_U8_BINNING_TYPE_103				((SMIA_REG_8BIT << 16) | 0x1779)
+#define SMIAPP_REG_U8_BINNING_TYPE_104				((SMIA_REG_8BIT << 16) | 0x177a)
+#define SMIAPP_REG_U8_BINNING_TYPE_105				((SMIA_REG_8BIT << 16) | 0x177b)
+#define SMIAPP_REG_U8_BINNING_TYPE_106				((SMIA_REG_8BIT << 16) | 0x177c)
+#define SMIAPP_REG_U8_BINNING_TYPE_107				((SMIA_REG_8BIT << 16) | 0x177d)
+#define SMIAPP_REG_U8_BINNING_TYPE_108				((SMIA_REG_8BIT << 16) | 0x177e)
+#define SMIAPP_REG_U8_BINNING_TYPE_109				((SMIA_REG_8BIT << 16) | 0x177f)
+#define SMIAPP_REG_U8_BINNING_TYPE_110				((SMIA_REG_8BIT << 16) | 0x1780)
+#define SMIAPP_REG_U8_BINNING_TYPE_111				((SMIA_REG_8BIT << 16) | 0x1781)
+#define SMIAPP_REG_U8_BINNING_TYPE_112				((SMIA_REG_8BIT << 16) | 0x1782)
+#define SMIAPP_REG_U8_BINNING_TYPE_113				((SMIA_REG_8BIT << 16) | 0x1783)
+#define SMIAPP_REG_U8_BINNING_TYPE_114				((SMIA_REG_8BIT << 16) | 0x1784)
+#define SMIAPP_REG_U8_BINNING_TYPE_115				((SMIA_REG_8BIT << 16) | 0x1785)
+#define SMIAPP_REG_U8_BINNING_TYPE_116				((SMIA_REG_8BIT << 16) | 0x1786)
+#define SMIAPP_REG_U8_BINNING_TYPE_117				((SMIA_REG_8BIT << 16) | 0x1787)
+#define SMIAPP_REG_U8_BINNING_TYPE_118				((SMIA_REG_8BIT << 16) | 0x1788)
+#define SMIAPP_REG_U8_BINNING_TYPE_119				((SMIA_REG_8BIT << 16) | 0x1789)
+#define SMIAPP_REG_U8_BINNING_TYPE_120				((SMIA_REG_8BIT << 16) | 0x178a)
+#define SMIAPP_REG_U8_BINNING_TYPE_121				((SMIA_REG_8BIT << 16) | 0x178b)
+#define SMIAPP_REG_U8_BINNING_TYPE_122				((SMIA_REG_8BIT << 16) | 0x178c)
+#define SMIAPP_REG_U8_BINNING_TYPE_123				((SMIA_REG_8BIT << 16) | 0x178d)
+#define SMIAPP_REG_U8_BINNING_TYPE_124				((SMIA_REG_8BIT << 16) | 0x178e)
+#define SMIAPP_REG_U8_BINNING_TYPE_125				((SMIA_REG_8BIT << 16) | 0x178f)
+#define SMIAPP_REG_U8_BINNING_TYPE_126				((SMIA_REG_8BIT << 16) | 0x1790)
+#define SMIAPP_REG_U8_BINNING_TYPE_127				((SMIA_REG_8BIT << 16) | 0x1791)
+#define SMIAPP_REG_U8_BINNING_TYPE_128				((SMIA_REG_8BIT << 16) | 0x1792)
+#define SMIAPP_REG_U8_BINNING_TYPE_129				((SMIA_REG_8BIT << 16) | 0x1793)
+#define SMIAPP_REG_U8_BINNING_TYPE_130				((SMIA_REG_8BIT << 16) | 0x1794)
+#define SMIAPP_REG_U8_BINNING_TYPE_131				((SMIA_REG_8BIT << 16) | 0x1795)
+#define SMIAPP_REG_U8_BINNING_TYPE_132				((SMIA_REG_8BIT << 16) | 0x1796)
+#define SMIAPP_REG_U8_BINNING_TYPE_133				((SMIA_REG_8BIT << 16) | 0x1797)
+#define SMIAPP_REG_U8_BINNING_TYPE_134				((SMIA_REG_8BIT << 16) | 0x1798)
+#define SMIAPP_REG_U8_BINNING_TYPE_135				((SMIA_REG_8BIT << 16) | 0x1799)
+#define SMIAPP_REG_U8_BINNING_TYPE_136				((SMIA_REG_8BIT << 16) | 0x179a)
+#define SMIAPP_REG_U8_BINNING_TYPE_137				((SMIA_REG_8BIT << 16) | 0x179b)
+#define SMIAPP_REG_U8_BINNING_TYPE_138				((SMIA_REG_8BIT << 16) | 0x179c)
+#define SMIAPP_REG_U8_BINNING_TYPE_139				((SMIA_REG_8BIT << 16) | 0x179d)
+#define SMIAPP_REG_U8_BINNING_TYPE_140				((SMIA_REG_8BIT << 16) | 0x179e)
+#define SMIAPP_REG_U8_BINNING_TYPE_141				((SMIA_REG_8BIT << 16) | 0x179f)
+#define SMIAPP_REG_U8_BINNING_TYPE_142				((SMIA_REG_8BIT << 16) | 0x17a0)
+#define SMIAPP_REG_U8_BINNING_TYPE_143				((SMIA_REG_8BIT << 16) | 0x17a1)
+#define SMIAPP_REG_U8_BINNING_TYPE_144				((SMIA_REG_8BIT << 16) | 0x17a2)
+#define SMIAPP_REG_U8_BINNING_TYPE_145				((SMIA_REG_8BIT << 16) | 0x17a3)
+#define SMIAPP_REG_U8_BINNING_TYPE_146				((SMIA_REG_8BIT << 16) | 0x17a4)
+#define SMIAPP_REG_U8_BINNING_TYPE_147				((SMIA_REG_8BIT << 16) | 0x17a5)
+#define SMIAPP_REG_U8_BINNING_TYPE_148				((SMIA_REG_8BIT << 16) | 0x17a6)
+#define SMIAPP_REG_U8_BINNING_TYPE_149				((SMIA_REG_8BIT << 16) | 0x17a7)
+#define SMIAPP_REG_U8_BINNING_TYPE_150				((SMIA_REG_8BIT << 16) | 0x17a8)
+#define SMIAPP_REG_U8_BINNING_TYPE_151				((SMIA_REG_8BIT << 16) | 0x17a9)
+#define SMIAPP_REG_U8_BINNING_TYPE_152				((SMIA_REG_8BIT << 16) | 0x17aa)
+#define SMIAPP_REG_U8_BINNING_TYPE_153				((SMIA_REG_8BIT << 16) | 0x17ab)
+#define SMIAPP_REG_U8_BINNING_TYPE_154				((SMIA_REG_8BIT << 16) | 0x17ac)
+#define SMIAPP_REG_U8_BINNING_TYPE_155				((SMIA_REG_8BIT << 16) | 0x17ad)
+#define SMIAPP_REG_U8_BINNING_TYPE_156				((SMIA_REG_8BIT << 16) | 0x17ae)
+#define SMIAPP_REG_U8_BINNING_TYPE_157				((SMIA_REG_8BIT << 16) | 0x17af)
+#define SMIAPP_REG_U8_BINNING_TYPE_158				((SMIA_REG_8BIT << 16) | 0x17b0)
+#define SMIAPP_REG_U8_BINNING_TYPE_159				((SMIA_REG_8BIT << 16) | 0x17b1)
+#define SMIAPP_REG_U8_BINNING_TYPE_160				((SMIA_REG_8BIT << 16) | 0x17b2)
+#define SMIAPP_REG_U8_BINNING_TYPE_161				((SMIA_REG_8BIT << 16) | 0x17b3)
+#define SMIAPP_REG_U8_BINNING_TYPE_162				((SMIA_REG_8BIT << 16) | 0x17b4)
+#define SMIAPP_REG_U8_BINNING_TYPE_163				((SMIA_REG_8BIT << 16) | 0x17b5)
+#define SMIAPP_REG_U8_BINNING_TYPE_164				((SMIA_REG_8BIT << 16) | 0x17b6)
+#define SMIAPP_REG_U8_BINNING_TYPE_165				((SMIA_REG_8BIT << 16) | 0x17b7)
+#define SMIAPP_REG_U8_BINNING_TYPE_166				((SMIA_REG_8BIT << 16) | 0x17b8)
+#define SMIAPP_REG_U8_BINNING_TYPE_167				((SMIA_REG_8BIT << 16) | 0x17b9)
+#define SMIAPP_REG_U8_BINNING_TYPE_168				((SMIA_REG_8BIT << 16) | 0x17ba)
+#define SMIAPP_REG_U8_BINNING_TYPE_169				((SMIA_REG_8BIT << 16) | 0x17bb)
+#define SMIAPP_REG_U8_BINNING_TYPE_170				((SMIA_REG_8BIT << 16) | 0x17bc)
+#define SMIAPP_REG_U8_BINNING_TYPE_171				((SMIA_REG_8BIT << 16) | 0x17bd)
+#define SMIAPP_REG_U8_BINNING_TYPE_172				((SMIA_REG_8BIT << 16) | 0x17be)
+#define SMIAPP_REG_U8_BINNING_TYPE_173				((SMIA_REG_8BIT << 16) | 0x17bf)
+#define SMIAPP_REG_U8_BINNING_TYPE_174				((SMIA_REG_8BIT << 16) | 0x17c0)
+#define SMIAPP_REG_U8_BINNING_TYPE_175				((SMIA_REG_8BIT << 16) | 0x17c1)
+#define SMIAPP_REG_U8_BINNING_TYPE_176				((SMIA_REG_8BIT << 16) | 0x17c2)
+#define SMIAPP_REG_U8_BINNING_TYPE_177				((SMIA_REG_8BIT << 16) | 0x17c3)
+#define SMIAPP_REG_U8_BINNING_TYPE_178				((SMIA_REG_8BIT << 16) | 0x17c4)
+#define SMIAPP_REG_U8_BINNING_TYPE_179				((SMIA_REG_8BIT << 16) | 0x17c5)
+#define SMIAPP_REG_U8_BINNING_TYPE_180				((SMIA_REG_8BIT << 16) | 0x17c6)
+#define SMIAPP_REG_U8_BINNING_TYPE_181				((SMIA_REG_8BIT << 16) | 0x17c7)
+#define SMIAPP_REG_U8_BINNING_TYPE_182				((SMIA_REG_8BIT << 16) | 0x17c8)
+#define SMIAPP_REG_U8_BINNING_TYPE_183				((SMIA_REG_8BIT << 16) | 0x17c9)
+#define SMIAPP_REG_U8_BINNING_TYPE_184				((SMIA_REG_8BIT << 16) | 0x17ca)
+#define SMIAPP_REG_U8_BINNING_TYPE_185				((SMIA_REG_8BIT << 16) | 0x17cb)
+#define SMIAPP_REG_U8_BINNING_TYPE_186				((SMIA_REG_8BIT << 16) | 0x17cc)
+#define SMIAPP_REG_U8_BINNING_TYPE_187				((SMIA_REG_8BIT << 16) | 0x17cd)
+#define SMIAPP_REG_U8_BINNING_TYPE_188				((SMIA_REG_8BIT << 16) | 0x17ce)
+#define SMIAPP_REG_U8_BINNING_TYPE_189				((SMIA_REG_8BIT << 16) | 0x17cf)
+#define SMIAPP_REG_U8_BINNING_TYPE_190				((SMIA_REG_8BIT << 16) | 0x17d0)
+#define SMIAPP_REG_U8_BINNING_TYPE_191				((SMIA_REG_8BIT << 16) | 0x17d1)
+#define SMIAPP_REG_U8_BINNING_TYPE_192				((SMIA_REG_8BIT << 16) | 0x17d2)
+#define SMIAPP_REG_U8_BINNING_TYPE_193				((SMIA_REG_8BIT << 16) | 0x17d3)
+#define SMIAPP_REG_U8_BINNING_TYPE_194				((SMIA_REG_8BIT << 16) | 0x17d4)
+#define SMIAPP_REG_U8_BINNING_TYPE_195				((SMIA_REG_8BIT << 16) | 0x17d5)
+#define SMIAPP_REG_U8_BINNING_TYPE_196				((SMIA_REG_8BIT << 16) | 0x17d6)
+#define SMIAPP_REG_U8_BINNING_TYPE_197				((SMIA_REG_8BIT << 16) | 0x17d7)
+#define SMIAPP_REG_U8_BINNING_TYPE_198				((SMIA_REG_8BIT << 16) | 0x17d8)
+#define SMIAPP_REG_U8_BINNING_TYPE_199				((SMIA_REG_8BIT << 16) | 0x17d9)
+#define SMIAPP_REG_U8_BINNING_TYPE_200				((SMIA_REG_8BIT << 16) | 0x17da)
+#define SMIAPP_REG_U8_BINNING_TYPE_201				((SMIA_REG_8BIT << 16) | 0x17db)
+#define SMIAPP_REG_U8_BINNING_TYPE_202				((SMIA_REG_8BIT << 16) | 0x17dc)
+#define SMIAPP_REG_U8_BINNING_TYPE_203				((SMIA_REG_8BIT << 16) | 0x17dd)
+#define SMIAPP_REG_U8_BINNING_TYPE_204				((SMIA_REG_8BIT << 16) | 0x17de)
+#define SMIAPP_REG_U8_BINNING_TYPE_205				((SMIA_REG_8BIT << 16) | 0x17df)
+#define SMIAPP_REG_U8_BINNING_TYPE_206				((SMIA_REG_8BIT << 16) | 0x17e0)
+#define SMIAPP_REG_U8_BINNING_TYPE_207				((SMIA_REG_8BIT << 16) | 0x17e1)
+#define SMIAPP_REG_U8_BINNING_TYPE_208				((SMIA_REG_8BIT << 16) | 0x17e2)
+#define SMIAPP_REG_U8_BINNING_TYPE_209				((SMIA_REG_8BIT << 16) | 0x17e3)
+#define SMIAPP_REG_U8_BINNING_TYPE_210				((SMIA_REG_8BIT << 16) | 0x17e4)
+#define SMIAPP_REG_U8_BINNING_TYPE_211				((SMIA_REG_8BIT << 16) | 0x17e5)
+#define SMIAPP_REG_U8_BINNING_TYPE_212				((SMIA_REG_8BIT << 16) | 0x17e6)
+#define SMIAPP_REG_U8_BINNING_TYPE_213				((SMIA_REG_8BIT << 16) | 0x17e7)
+#define SMIAPP_REG_U8_BINNING_TYPE_214				((SMIA_REG_8BIT << 16) | 0x17e8)
+#define SMIAPP_REG_U8_BINNING_TYPE_215				((SMIA_REG_8BIT << 16) | 0x17e9)
+#define SMIAPP_REG_U8_BINNING_TYPE_216				((SMIA_REG_8BIT << 16) | 0x17ea)
+#define SMIAPP_REG_U8_BINNING_TYPE_217				((SMIA_REG_8BIT << 16) | 0x17eb)
+#define SMIAPP_REG_U8_BINNING_TYPE_218				((SMIA_REG_8BIT << 16) | 0x17ec)
+#define SMIAPP_REG_U8_BINNING_TYPE_219				((SMIA_REG_8BIT << 16) | 0x17ed)
+#define SMIAPP_REG_U8_BINNING_TYPE_220				((SMIA_REG_8BIT << 16) | 0x17ee)
+#define SMIAPP_REG_U8_BINNING_TYPE_221				((SMIA_REG_8BIT << 16) | 0x17ef)
+#define SMIAPP_REG_U8_BINNING_TYPE_222				((SMIA_REG_8BIT << 16) | 0x17f0)
+#define SMIAPP_REG_U8_BINNING_TYPE_223				((SMIA_REG_8BIT << 16) | 0x17f1)
+#define SMIAPP_REG_U8_BINNING_TYPE_224				((SMIA_REG_8BIT << 16) | 0x17f2)
+#define SMIAPP_REG_U8_BINNING_TYPE_225				((SMIA_REG_8BIT << 16) | 0x17f3)
+#define SMIAPP_REG_U8_BINNING_TYPE_226				((SMIA_REG_8BIT << 16) | 0x17f4)
+#define SMIAPP_REG_U8_BINNING_TYPE_227				((SMIA_REG_8BIT << 16) | 0x17f5)
+#define SMIAPP_REG_U8_BINNING_TYPE_228				((SMIA_REG_8BIT << 16) | 0x17f6)
+#define SMIAPP_REG_U8_BINNING_TYPE_229				((SMIA_REG_8BIT << 16) | 0x17f7)
+#define SMIAPP_REG_U8_BINNING_TYPE_230				((SMIA_REG_8BIT << 16) | 0x17f8)
+#define SMIAPP_REG_U8_BINNING_TYPE_231				((SMIA_REG_8BIT << 16) | 0x17f9)
+#define SMIAPP_REG_U8_BINNING_TYPE_232				((SMIA_REG_8BIT << 16) | 0x17fa)
+#define SMIAPP_REG_U8_BINNING_TYPE_233				((SMIA_REG_8BIT << 16) | 0x17fb)
+#define SMIAPP_REG_U8_BINNING_TYPE_234				((SMIA_REG_8BIT << 16) | 0x17fc)
+#define SMIAPP_REG_U8_BINNING_TYPE_235				((SMIA_REG_8BIT << 16) | 0x17fd)
+#define SMIAPP_REG_U8_BINNING_TYPE_236				((SMIA_REG_8BIT << 16) | 0x17fe)
+#define SMIAPP_REG_U8_BINNING_TYPE_237				((SMIA_REG_8BIT << 16) | 0x17ff)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY		((SMIA_REG_8BIT << 16) | 0x1800)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY		((SMIA_REG_8BIT << 16) | 0x1900)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY		((SMIA_REG_8BIT << 16) | 0x1901)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x1902)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY	((SMIA_REG_8BIT << 16) | 0x1903)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY		((SMIA_REG_16BIT << 16) | 0x1904)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2		((SMIA_REG_16BIT << 16) | 0x1906)
+#define SMIAPP_REG_U8_EDOF_CAPABILITY				((SMIA_REG_8BIT << 16) | 0x1980)
+#define SMIAPP_REG_U8_ESTIMATION_FRAMES				((SMIA_REG_8BIT << 16) | 0x1981)
+#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ			((SMIA_REG_8BIT << 16) | 0x1982)
+#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ			((SMIA_REG_8BIT << 16) | 0x1983)
+#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ		((SMIA_REG_8BIT << 16) | 0x1984)
+#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ		((SMIA_REG_8BIT << 16) | 0x1985)
+#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ		((SMIA_REG_8BIT << 16) | 0x1986)
+#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY		((SMIA_REG_8BIT << 16) | 0x1987)
+#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM			((SMIA_REG_8BIT << 16) | 0x1988)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY		((SMIA_REG_8BIT << 16) | 0x19c0)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY		((SMIA_REG_8BIT << 16) | 0x19c1)
+#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD			((SMIA_REG_16BIT << 16) | 0x19c2)
+#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE			((SMIA_REG_16BIT << 16) | 0x19c4)
+#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN			((SMIA_REG_16BIT << 16) | 0x1a00)
+#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x1a02)
+#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR		((SMIA_REG_16BIT << 16) | 0x1b02)
+#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY			((SMIA_REG_8BIT << 16) | 0x1b04)
+#define SMIAPP_REG_U16_ACTUATOR_TYPE				((SMIA_REG_16BIT << 16) | 0x1b40)
+#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS				((SMIA_REG_8BIT << 16) | 0x1b42)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS			((SMIA_REG_16BIT << 16) | 0x1b44)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1		((SMIA_REG_8BIT << 16) | 0x1c00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2		((SMIA_REG_8BIT << 16) | 0x1c01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE			((SMIA_REG_8BIT << 16) | 0x1c02)
diff --git a/drivers/media/video/smiapp-reg.h b/drivers/media/video/smiapp-reg.h
new file mode 100644
index 0000000..871f4cc
--- /dev/null
+++ b/drivers/media/video/smiapp-reg.h
@@ -0,0 +1,119 @@
+/*
+ * drivers/media/video/smiapp-reg.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_REG_H_
+#define __SMIAPP_REG_H_
+
+#include "smiapp-reg-defs.h"
+
+/* Bits for above register */
+#define SMIAPP_IMAGE_ORIENTATION_HFLIP		(1 << 0)
+#define SMIAPP_IMAGE_ORIENTATION_VFLIP		(1 << 1)
+
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN		(1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN		(0 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN		(1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR	(1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY	(1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY	(1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA		(1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE		(1 << 3)
+
+#define SMIAPP_SOFTWARE_RESET				(1 << 0)
+
+#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE	(1 << 0)
+#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE	(1 << 1)
+
+#define SMIAPP_DPHY_CTRL_AUTOMATIC			0
+/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */
+#define SMIAPP_DPHY_CTRL_UI				1
+#define SMIAPP_DPHY_CTRL_REGISTER			2
+
+#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR	1
+#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR	2
+
+#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY		0
+#define SMIAPP_MODE_SELECT_STREAMING			1
+
+#define SMIAPP_SCALING_MODE_NONE			0
+#define SMIAPP_SCALING_MODE_HORIZONTAL			1
+#define SMIAPP_SCALING_MODE_BOTH			2
+
+#define SMIAPP_SCALING_CAPABILITY_NONE			0
+#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL		1
+#define SMIAPP_SCALING_CAPABILITY_BOTH			2 /* horizontal/both */
+
+/* digital crop right before scaler */
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE		0
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP	1
+
+#define SMIAPP_BINNING_CAPABILITY_NO			0
+#define SMIAPP_BINNING_CAPABILITY_YES			1
+
+/* Maximum number of binning subtypes */
+#define SMIAPP_BINNING_SUBTYPES				253
+
+#define SMIAPP_PIXEL_ORDER_GRBG				0
+#define SMIAPP_PIXEL_ORDER_RGGB				1
+#define SMIAPP_PIXEL_ORDER_BGGR				2
+#define SMIAPP_PIXEL_ORDER_GBRG				3
+
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL		1
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED		2
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N		8
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N	16
+
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE		0x01
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE		0x02
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK	0x0f
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK	0xf0
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT	4
+
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK	0xf000
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT	12
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK		0x0fff
+
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK	0xf0000000
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT	28
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK		0x0000ffff
+
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED	1
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY	2
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK	3
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK		4
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE	5
+
+/* Scaling N factor */
+#define SMIAPP_SCALE_N					16
+
+/* Image statistics registers */
+/* Registers 0x2000 to 0x2fff are reserved for future
+ * use for statistics features.
+ */
+
+/* Manufacturer Specific Registers: 0x3000 to 0x3fff
+ * The manufacturer specifies these as a black box.
+ */
+
+#endif /* __SMIAPP_REG_H_ */
diff --git a/drivers/media/video/smiapp-regs.c b/drivers/media/video/smiapp-regs.c
new file mode 100644
index 0000000..59882b2
--- /dev/null
+++ b/drivers/media/video/smiapp-regs.c
@@ -0,0 +1,222 @@
+/*
+ * drivers/media/video/smiapp-regs.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "smiapp-debug.h"
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <media/smiapp-regs.h>
+
+#include "smiapp-reg-defs.h"
+
+static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
+					 uint32_t phloat)
+{
+	int32_t exp;
+	uint64_t man;
+
+	if (phloat >= 0x80000000) {
+		dev_err(&client->dev, "this is a negative number\n");
+		return 0;
+	}
+
+	if (phloat == 0x7f800000)
+		return ~0; /* Inf. */
+
+	if ((phloat & 0x7f800000) == 0x7f800000) {
+		dev_err(&client->dev, "NaN or other special number\n");
+		return 0;
+	}
+
+	/* Valid cases begin here */
+	if (phloat == 0)
+		return 0; /* Valid zero */
+
+	if (phloat > 0x4f800000)
+		return ~0; /* larger than 4294967295 */
+
+	/*
+	 * Unbias exponent (note how phloat is now guaranteed to
+	 * have 0 in the high bit)
+	 */
+	exp = ((int32_t)phloat >> 23) - 127;
+
+	/* Extract mantissa, add missing '1' bit and it's in MHz */
+	man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
+
+	if (exp < 0)
+		man >>= -exp;
+	else
+		man <<= exp;
+
+	man >>= 23; /* Remove mantissa bias */
+
+	return man & 0xffffffff;
+}
+
+
+/*
+ * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+int smia_i2c_read_reg(struct i2c_client *client, u32 reg, u32 *val)
+{
+	struct i2c_msg msg[1];
+	unsigned char data[4];
+	unsigned int len = (u8)(reg >> 16);
+	u16 offset = reg;
+	int r;
+
+	if (!client->adapter)
+		return -ENODEV;
+	if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT
+	    && len != SMIA_REG_32BIT)
+		return -EINVAL;
+
+	msg->addr = client->addr;
+	msg->flags = 0;
+	msg->len = 2;
+	msg->buf = data;
+
+	/* high byte goes out first */
+	data[0] = (u8) (offset >> 8);
+	data[1] = (u8) offset;
+	r = i2c_transfer(client->adapter, msg, 1);
+	if (r < 0)
+		goto err;
+
+	msg->len = len;
+	msg->flags = I2C_M_RD;
+	r = i2c_transfer(client->adapter, msg, 1);
+	if (r < 0)
+		goto err;
+
+	*val = 0;
+	/* high byte comes first */
+	switch (len) {
+	case SMIA_REG_32BIT:
+		*val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
+			data[3];
+		break;
+	case SMIA_REG_16BIT:
+		*val = (data[0] << 8) + data[1];
+		break;
+	case SMIA_REG_8BIT:
+		*val = data[0];
+		break;
+	default:
+		BUG();
+	}
+
+	if (reg & SMIA_REG_FLAG_FLOAT)
+		*val = float_to_u32_mul_1000000(client, *val);
+
+	return 0;
+
+err:
+	dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
+
+	return r;
+}
+
+static void smia_i2c_create_msg(struct i2c_client *client, u16 len, u16 reg,
+				u32 val, struct i2c_msg *msg,
+				unsigned char *buf)
+{
+	msg->addr = client->addr;
+	msg->flags = 0; /* Write */
+	msg->len = 2 + len;
+	msg->buf = buf;
+
+	/* high byte goes out first */
+	buf[0] = (u8) (reg >> 8);
+	buf[1] = (u8) (reg & 0xff);
+
+	switch (len) {
+	case SMIA_REG_8BIT:
+		buf[2] = val;
+		break;
+	case SMIA_REG_16BIT:
+		buf[2] = val >> 8;
+		buf[3] = val;
+		break;
+	case SMIA_REG_32BIT:
+		buf[2] = val >> 24;
+		buf[3] = val >> 16;
+		buf[4] = val >> 8;
+		buf[5] = val;
+		break;
+	default:
+		BUG();
+	}
+}
+
+/*
+ * Write to a 8/16-bit register.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+int smia_i2c_write_reg(struct i2c_client *client, u32 reg, u32 val)
+{
+	struct i2c_msg msg[1];
+	unsigned char data[6];
+	unsigned int retries = 5;
+	unsigned int flags = reg >> 24;
+	unsigned int len = (u8)(reg >> 16);
+	u16 offset = reg;
+	int r;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT &&
+	     len != SMIA_REG_32BIT) || flags)
+		return -EINVAL;
+
+	smia_i2c_create_msg(client, len, offset, val, msg, data);
+
+	do {
+		/*
+		 * Due to unknown reason sensor stops responding. This
+		 * loop is a temporaty solution until the root cause
+		 * is found.
+		 */
+		r = i2c_transfer(client->adapter, msg, 1);
+		if (r >= 0)
+			break;
+
+		usleep_range(2000, 2000);
+	} while (retries--);
+
+	if (r < 0)
+		dev_err(&client->dev,
+			"wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
+	else
+		r = 0; /* on success i2c_transfer() return messages trasfered */
+
+	if (retries < 5)
+		dev_err(&client->dev, "sensor i2c stall encountered. "
+			"retries: %d\n", 5 - retries);
+
+	return r;
+}
diff --git a/drivers/media/video/smiapp.h b/drivers/media/video/smiapp.h
new file mode 100644
index 0000000..5c229f2
--- /dev/null
+++ b/drivers/media/video/smiapp.h
@@ -0,0 +1,250 @@
+/*
+ * drivers/media/video/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010-2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_PRIV_H_
+#define __SMIAPP_PRIV_H_
+
+#include <linux/mutex.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <media/smiapp-regs.h>
+#include <media/smiapp.h>
+
+#include "smiapp-reg.h"
+#include "smiapp-quirk.h"
+
+/*
+ * Standard SMIA++ constants
+ */
+#define SMIA_VERSION_1			10
+#define SMIAPP_VERSION_0_8		8 /* Draft 0.8 */
+#define SMIAPP_VERSION_0_9		9 /* Draft 0.9 */
+#define SMIAPP_VERSION_1		10
+
+#define SMIAPP_PROFILE_0		0
+#define SMIAPP_PROFILE_1		1
+#define SMIAPP_PROFILE_2		2
+
+#define SMIAPP_NVM_PAGE_SIZE		64	/* bytes */
+
+#define SMIAPP_RESET_DELAY_CLOCKS	2400
+#define SMIAPP_RESET_DELAY(clk)				\
+	(1000 +	(SMIAPP_RESET_DELAY_CLOCKS * 1000	\
+		 + (clk) / 1000 - 1) / ((clk) / 1000))
+
+#include "smiapp-limits.h"
+
+struct smiapp_quirk;
+
+#define SMIAPP_MODULE_IDENT_FLAG_REV_LE		(1 << 0)
+
+struct smiapp_module_ident {
+	u8 manufacturer_id;
+	u16 model_id;
+	u8 revision_number_major;
+
+	u8 flags;
+
+	char *name;
+	const struct smiapp_quirk *quirk;
+} __packed;
+
+struct smiapp_module_info {
+	u32 manufacturer_id;
+	u32 model_id;
+	u32 revision_number_major;
+	u32 revision_number_minor;
+
+	u32 module_year;
+	u32 module_month;
+	u32 module_day;
+
+	u32 sensor_manufacturer_id;
+	u32 sensor_model_id;
+	u32 sensor_revision_number;
+	u32 sensor_firmware_version;
+
+	u32 smia_version;
+	u32 smiapp_version;
+
+	u32 smiapp_profile;
+
+	char *name;
+	const struct smiapp_quirk *quirk;
+};
+
+#define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk)	\
+	{ .manufacturer_id = manufacturer,				\
+			.model_id = model,				\
+			.revision_number_major = rev,			\
+			.flags = fl,					\
+			.name = _name,					\
+			.quirk = _quirk, }
+
+#define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk)	\
+	{ .manufacturer_id = manufacturer,				\
+			.model_id = model,				\
+			.revision_number_major = rev,			\
+			.flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE,	\
+			.name = _name,					\
+			.quirk = _quirk, }
+
+#define SMIAPP_IDENT_L(manufacturer, model, rev, _name)			\
+	{ .manufacturer_id = manufacturer,				\
+			.model_id = model,				\
+			.revision_number_major = rev,			\
+			.flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE,	\
+			.name = _name, }
+
+#define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk)		\
+	{ .manufacturer_id = manufacturer,				\
+			.model_id = model,				\
+			.revision_number_major = rev,			\
+			.flags = 0,					\
+			.name = _name,					\
+			.quirk = _quirk, }
+
+#define SMIAPP_IDENT(manufacturer, model, rev, _name)			\
+	{ .manufacturer_id = manufacturer,				\
+			.model_id = model,				\
+			.revision_number_major = rev,			\
+			.flags = 0,					\
+			.name = _name, }
+
+struct smiapp_reg_limits {
+	u32 addr;
+	char *what;
+};
+
+extern struct smiapp_reg_limits smiapp_reg_limits[];
+
+struct smiapp_csi_data_format {
+	u32 code;
+	u8 width;
+	u8 compressed;
+	u8 pixel_order;
+};
+
+struct smiapp_pll {
+	uint16_t pre_pll_clk_div;
+	uint16_t pll_multiplier;
+	uint16_t op_sys_clk_div;
+	uint16_t op_pix_clk_div;
+	uint16_t vt_sys_clk_div;
+	uint16_t vt_pix_clk_div;
+
+	uint32_t ext_clk_freq_hz;
+	uint32_t pll_ip_clk_freq_hz;
+	uint32_t pll_op_clk_freq_hz;
+	uint32_t op_sys_clk_freq_hz;
+	uint32_t op_pix_clk_freq_hz;
+	uint32_t vt_sys_clk_freq_hz;
+	uint32_t vt_pix_clk_freq_hz;
+};
+
+#define SMIAPP_SUBDEVS			3
+
+#define SMIAPP_PAD_SOURCE		0
+#define SMIAPP_PAD_SINK			1
+
+struct smiapp_binning_subtype {
+	u8 horizontal:4;
+	u8 vertical:4;
+} __packed;
+
+struct smiapp_subdev {
+	struct v4l2_subdev sd;
+	struct media_pad pads[2];
+	struct v4l2_rect sink_fmt;
+	struct v4l2_rect crop[2];
+	struct v4l2_rect compose[2];
+	unsigned int pixelrate[2];
+	int npads;
+	struct smiapp_sensor *sensor;
+	struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/*
+ * struct smiapp_sensor - Main device structure
+ */
+struct smiapp_sensor {
+	struct smiapp_subdev sds[SMIAPP_SUBDEVS];
+	u32 sds_used;
+	struct smiapp_subdev *src;
+	struct smiapp_subdev *binner;
+	struct smiapp_subdev *scaler;
+	struct smiapp_subdev *pixel_array;
+	struct smiapp_platform_data *platform_data;
+	struct regulator *vana;
+	u32 limits[SMIAPP_LIMIT_LAST];
+	u8 nbinning_subtypes;
+	struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES];
+	u32 mbus_frame_fmts;
+
+	u8 binning_horizontal;
+	u8 binning_vertical;
+
+	u8 scale_m;
+	u8 scaling_mode;
+
+	/* Pixel array controls */
+	struct v4l2_ctrl *analog_gain;
+	struct v4l2_ctrl *exposure;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *hblank;
+	struct v4l2_ctrl *link_freq;
+
+	u8 sof_rows;
+	u8 eof_rows;
+	u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
+	u8 flash_capability;
+	u8 frame_skip;
+
+	struct mutex power_lock;
+	int power_count;
+
+	unsigned int streaming:1;
+	unsigned int dev_init_done:1;
+
+	u8 *nvm;		/* nvm memory buffer */
+	unsigned int nvm_size;	/* bytes */
+
+	struct smiapp_module_info minfo;
+
+	struct smiapp_pll pll;
+	const struct smiapp_csi_data_format *csi_format;
+};
+
+#define to_smiapp_subdev(_sd)				\
+	container_of(_sd, struct smiapp_subdev, sd)
+
+#define to_smiapp_sensor(_sd)	\
+	(to_smiapp_subdev(_sd)->sensor)
+
+int smiapp_pll_update(struct smiapp_sensor *sensor);
+int smiapp_pll_configure(struct smiapp_sensor *sensor);
+
+#endif /* __SMIAPP_PRIV_H_ */
diff --git a/include/media/smiapp-regs.h b/include/media/smiapp-regs.h
new file mode 100644
index 0000000..3109b02
--- /dev/null
+++ b/include/media/smiapp-regs.h
@@ -0,0 +1,51 @@
+/*
+ * include/media/smiapp-regs.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SMIAPP_REGS_H
+#define SMIAPP_REGS_H
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-subdev.h>
+
+struct v4l2_mbus_framefmt;
+struct v4l2_subdev_pad_mbus_code_enum;
+
+/* Use upper 8 bits of the type field for flags */
+#define SMIA_REG_FLAG_FLOAT		(1 << 24)
+
+#define SMIA_REG_8BIT			1
+#define SMIA_REG_16BIT			2
+#define SMIA_REG_32BIT			4
+struct smia_reg {
+	u16 type;
+	u16 reg;			/* 16-bit offset */
+	u32 val;			/* 8/16/32-bit value */
+};
+
+int smia_i2c_read_reg(struct i2c_client *client, u32 reg, u32 *val);
+int smia_i2c_write_reg(struct i2c_client *client, u32 reg, u32 val);
+
+#endif
diff --git a/include/media/smiapp.h b/include/media/smiapp.h
new file mode 100644
index 0000000..b302570
--- /dev/null
+++ b/include/media/smiapp.h
@@ -0,0 +1,82 @@
+/*
+ * include/media/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_H_
+#define __SMIAPP_H_
+
+#include <media/smiapp-regs.h>
+#include <media/v4l2-subdev.h>
+
+#define SMIAPP_NAME		"smiapp"
+
+#define SMIAPP_DFL_I2C_ADDR	(0x20 >> 1) /* Default I2C Address */
+#define SMIAPP_ALT_I2C_ADDR	(0x6e >> 1) /* Alternate I2C Address */
+
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK	0
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE	1
+#define SMIAPP_CSI_SIGNALLING_MODE_CSI2			2
+
+/*
+ * Sometimes due to board layout considerations the camera module can be
+ * mounted rotated. The typical rotation used is 180 degrees which can be
+ * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
+ * FIXME: rotation also changes the bayer pattern.
+ */
+enum smiapp_module_board_orient {
+	SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
+	SMIAPP_MODULE_BOARD_ORIENT_180,
+};
+
+struct smiapp_flash_strobe_parms {
+	u8 mode;
+	u32 strobe_width_high_us;
+	u16 strobe_delay;
+	u16 stobe_start_point;
+	u8 trigger;
+};
+
+struct smiapp_platform_data {
+	/*
+	 * Change the cci address if i2c_addr_alt is set.
+	 * Both default and alternate cci addr need to be present
+	 */
+	unsigned short i2c_addr_dfl;	/* Default i2c addr */
+	unsigned short i2c_addr_alt;	/* Alternate i2c addr */
+
+	unsigned int nvm_size;			/* bytes */
+	unsigned int ext_clk;			/* sensor external clk */
+
+	unsigned int lanes;		/* Number of CSI-2 lanes */
+	u8 csi_signalling_mode;		/* SMIAPP_CSI_SIGNALLING_MODE_* */
+	const s64 *op_sys_clock;
+
+	enum smiapp_module_board_orient module_board_orient;
+
+	struct smiapp_flash_strobe_parms *strobe_setup;
+
+	int (*set_xclk)(struct v4l2_subdev *sd, int hz);
+	int (*set_xshutdown)(struct v4l2_subdev *sd, u8 set);
+};
+
+#endif /* __SMIAPP_H_  */
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [RFC 17/17] rm680: Add camera init
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (15 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 16/17] smiapp: Add driver Sakari Ailus
@ 2011-12-20 20:28 ` Sakari Ailus
  2012-01-06 10:21   ` Laurent Pinchart
  2012-01-06 14:58   ` Sylwester Nawrocki
  2011-12-28  9:47 ` [yavta PATCH 1/1] Support integer menus Sakari Ailus
  17 siblings, 2 replies; 76+ messages in thread
From: Sakari Ailus @ 2011-12-20 20:28 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, dacohen, snjw23

This currently introduces an extra file to the arch/arm/mach-omap2
directory: board-rm680-camera.c. Keeping the device tree in mind, the
context of the file could be represented as static data with one exception:
the external clock to the sensor.

This external clock is provided by the OMAP 3 SoC and required by the
sensor. The issue is that the clock originates from the ISP and not from
PRCM block as the other clocks and thus is not supported by the clock
framework. Otherwise the sensor driver could just clk_get() and clk_enable()
it, just like the regulators and gpios.

Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
---
 arch/arm/mach-omap2/Makefile             |    3 +-
 arch/arm/mach-omap2/board-rm680-camera.c |  408 ++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/board-rm680.c        |   42 +++
 3 files changed, 452 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/board-rm680-camera.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 69ab1c0..1444bc5 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -201,7 +201,8 @@ obj-$(CONFIG_MACH_OMAP3_PANDORA)	+= board-omap3pandora.o
 obj-$(CONFIG_MACH_OMAP_3430SDP)		+= board-3430sdp.o
 obj-$(CONFIG_MACH_NOKIA_N8X0)		+= board-n8x0.o
 obj-$(CONFIG_MACH_NOKIA_RM680)		+= board-rm680.o \
-					   sdram-nokia.o
+					   sdram-nokia.o \
+					   board-rm680-camera.o
 obj-$(CONFIG_MACH_NOKIA_RX51)		+= board-rx51.o \
 					   sdram-nokia.o \
 					   board-rx51-peripherals.o \
diff --git a/arch/arm/mach-omap2/board-rm680-camera.c b/arch/arm/mach-omap2/board-rm680-camera.c
new file mode 100644
index 0000000..4cc1ced
--- /dev/null
+++ b/arch/arm/mach-omap2/board-rm680-camera.c
@@ -0,0 +1,408 @@
+/**
+ * arch/arm/mach-omap2/board-rm680-camera.c
+ *
+ * Copyright (C) 2010--2011 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Based on board-rx71-camera.c by Vimarsh Zutshi
+ * Based on board-rx51-camera.c by Sakari Ailus
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+
+#include <linux/gpio.h>
+#include <plat/omap-pm.h>
+
+#include "../../../drivers/media/video/omap3isp/isp.h"
+
+#include <media/omap3isp.h>
+#include <media/smiapp.h>
+#include <asm/mach-types.h>
+
+#include "../../../drivers/media/video/smiapp.h"
+
+#include "devices.h"
+
+#define SEC_CAMERA_RESET_GPIO	97
+
+#define RM680_PRI_SENSOR	1
+#define RM680_PRI_LENS		2
+#define RM680_SEC_SENSOR	3
+#define MAIN_CAMERA_XCLK	ISP_XCLK_A
+#define SEC_CAMERA_XCLK		ISP_XCLK_B
+
+/*
+ *
+ * HW initialization
+ *
+ *
+ */
+static int __init rm680_sec_camera_init(void)
+{
+	if (gpio_request(SEC_CAMERA_RESET_GPIO, "sec_camera reset") != 0) {
+		printk(KERN_INFO "%s: unable to acquire secondary "
+		       "camera reset gpio\n", __func__);
+		return -ENODEV;
+	}
+
+	/* XSHUTDOWN off, reset  */
+	gpio_direction_output(SEC_CAMERA_RESET_GPIO, 0);
+	gpio_set_value(SEC_CAMERA_RESET_GPIO, 0);
+
+	return 0;
+}
+
+static int __init rm680_camera_hw_init(void)
+{
+	return rm680_sec_camera_init();
+}
+
+/*
+ *
+ * Main Camera Module EXTCLK
+ * Used by the sensor and the actuator driver.
+ *
+ */
+static struct camera_xclk {
+	u32 hz;
+	u32 lock;
+	u8 xclksel;
+} cameras_xclk;
+
+static DEFINE_MUTEX(lock_xclk);
+
+static int rm680_update_xclk(struct v4l2_subdev *subdev, u32 hz, u32 which,
+			     u8 xclksel)
+{
+	struct isp_device *isp = v4l2_dev_to_isp_device(subdev->v4l2_dev);
+	int ret;
+
+	mutex_lock(&lock_xclk);
+
+	if (which == RM680_SEC_SENSOR) {
+		if (cameras_xclk.xclksel == MAIN_CAMERA_XCLK) {
+			ret = -EBUSY;
+			goto done;
+		}
+	} else {
+		if (cameras_xclk.xclksel == SEC_CAMERA_XCLK) {
+			ret = -EBUSY;
+			goto done;
+		}
+	}
+
+	if (hz) {	/* Turn on */
+		cameras_xclk.lock |= which;
+		if (cameras_xclk.hz == 0) {
+			isp->platform_cb.set_xclk(isp, hz, xclksel);
+			cameras_xclk.hz = hz;
+			cameras_xclk.xclksel = xclksel;
+		}
+	} else {	/* Turn off */
+		cameras_xclk.lock &= ~which;
+		if (cameras_xclk.lock == 0) {
+			isp->platform_cb.set_xclk(isp, 0, xclksel);
+			cameras_xclk.hz = 0;
+			cameras_xclk.xclksel = 0;
+		}
+	}
+
+	ret = cameras_xclk.hz;
+
+done:
+	mutex_unlock(&lock_xclk);
+	return ret;
+}
+
+/*
+ *
+ * Main Camera Sensor
+ *
+ */
+
+static struct isp_csiphy_lanes_cfg rm696_main_camera_csi2_lanecfg = {
+	.clk = {
+		.pol = 1,
+		.pos = 2,
+	},
+	.data[0] = {
+		.pol = 1,
+		.pos = 1,
+	},
+	.data[1] = {
+		.pol = 1,
+		.pos = 3,
+	},
+};
+
+static struct isp_csiphy_lanes_cfg rm680_main_camera_csi2_lanecfg = {
+	.clk = {
+		.pol = 1,
+		.pos = 2,
+	},
+	.data[0] = {
+		.pol = 1,
+		.pos = 3,
+	},
+	.data[1] = {
+		.pol = 1,
+		.pos = 1,
+	},
+};
+
+static int rm680_main_camera_set_xclk(struct v4l2_subdev *sd, int hz)
+{
+	return rm680_update_xclk(sd, hz, RM680_PRI_SENSOR, MAIN_CAMERA_XCLK);
+}
+
+static struct smiapp_flash_strobe_parms rm680_main_camera_strobe_setup = {
+	.mode			= 0x0c,
+	.strobe_width_high_us	= 100000,
+	.strobe_delay		= 0,
+	.stobe_start_point	= 0,
+	.trigger		= 0,
+};
+
+static struct smiapp_platform_data rm696_main_camera_platform_data = {
+	.i2c_addr_dfl		= SMIAPP_DFL_I2C_ADDR,
+	.i2c_addr_alt		= SMIAPP_ALT_I2C_ADDR,
+	.nvm_size		= 16 * 64,
+	.ext_clk		= (9.6 * 1000 * 1000),
+	.lanes			= 2,
+	.op_sys_clock		= (s64 []){ 796800 / 2, 840000 / 2,
+					    1996800 / 2, 0 },
+	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CSI2,
+	.strobe_setup		= &rm680_main_camera_strobe_setup,
+	.set_xclk		= rm680_main_camera_set_xclk,
+};
+
+static struct smiapp_platform_data rm680_main_camera_platform_data = {
+	.i2c_addr_dfl		= SMIAPP_DFL_I2C_ADDR,
+	.i2c_addr_alt		= SMIAPP_ALT_I2C_ADDR,
+	.nvm_size		= 16 * 64,
+	.ext_clk		= (9.6 * 1000 * 1000),
+	.lanes			= 2,
+	.op_sys_clock		= (s64 []){ 840000 / 2, 1334400 / 2,
+					    1593600 / 2, 0 },
+	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CSI2,
+	.module_board_orient	= SMIAPP_MODULE_BOARD_ORIENT_180,
+	.strobe_setup		= &rm680_main_camera_strobe_setup,
+	.set_xclk		= rm680_main_camera_set_xclk,
+};
+
+/*
+ *
+ * SECONDARY CAMERA Sensor
+ *
+ */
+
+#define SEC_CAMERA_XCLK		ISP_XCLK_B
+
+static struct isp_csiphy_lanes_cfg rm680_sec_camera_csiphy_lanecfg = {
+	.clk = {
+		.pol = 0,
+		.pos = 1,
+	},
+	.data[0] = {
+		.pol = 0,
+		.pos = 2,
+	},
+};
+
+static int rm680_sec_camera_set_xclk(struct v4l2_subdev *sd, int hz)
+{
+	return rm680_update_xclk(sd, hz, RM680_SEC_SENSOR, SEC_CAMERA_XCLK);
+}
+
+static int rm680_sec_camera_set_xshutdown(struct v4l2_subdev *subdev, u8 set)
+{
+	gpio_set_value(SEC_CAMERA_RESET_GPIO, !!set);
+	return 0;
+}
+
+static struct smiapp_platform_data rm696_sec_camera_platform_data = {
+	.ext_clk		= (10.8 * 1000 * 1000),
+	.lanes			= 1,
+	.op_sys_clock		= (s64 []){ 13770 * 10, 0 },
+	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK,
+	.module_board_orient	= SMIAPP_MODULE_BOARD_ORIENT_180,
+	.set_xclk		= rm680_sec_camera_set_xclk,
+	.set_xshutdown		= rm680_sec_camera_set_xshutdown,
+};
+
+static struct smiapp_platform_data rm680_sec_camera_platform_data = {
+	.ext_clk		= (10.8 * 1000 * 1000),
+	.lanes			= 1,
+	.op_sys_clock		= (s64 []){ 11880 * 10, 0 },
+	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK,
+	.set_xclk		= rm680_sec_camera_set_xclk,
+	.set_xshutdown		= rm680_sec_camera_set_xshutdown,
+};
+
+/*
+ *
+ * Init all the modules
+ *
+ */
+
+#define CAMERA_I2C_BUS_NUM		2
+#define AD5836_I2C_BUS_NUM		2
+#define AS3645A_I2C_BUS_NUM		2
+
+static struct i2c_board_info rm696_camera_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_ALT_I2C_ADDR),
+		.platform_data = &rm696_main_camera_platform_data,
+	},
+	{
+		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_DFL_I2C_ADDR),
+		.platform_data = &rm696_sec_camera_platform_data,
+	},
+};
+
+static struct i2c_board_info rm680_camera_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_ALT_I2C_ADDR),
+		.platform_data = &rm680_main_camera_platform_data,
+	},
+	{
+		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_DFL_I2C_ADDR),
+		.platform_data = &rm680_sec_camera_platform_data,
+	},
+};
+
+static struct isp_subdev_i2c_board_info rm696_camera_primary_subdevs[] = {
+	{
+		.board_info = &rm696_camera_i2c_devices[0],
+		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
+	},
+	{ NULL, 0, },
+};
+
+static struct isp_subdev_i2c_board_info rm696_camera_secondary_subdevs[] = {
+	{
+		.board_info = &rm696_camera_i2c_devices[1],
+		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
+	},
+	{ NULL, 0, },
+};
+
+static struct isp_subdev_i2c_board_info rm680_camera_primary_subdevs[] = {
+	{
+		.board_info = &rm680_camera_i2c_devices[0],
+		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
+	},
+	{ NULL, 0, },
+};
+
+static struct isp_subdev_i2c_board_info rm680_camera_secondary_subdevs[] = {
+	{
+		.board_info = &rm680_camera_i2c_devices[1],
+		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
+	},
+	{ NULL, 0, },
+};
+
+static struct isp_v4l2_subdevs_group rm696_camera_subdevs[] = {
+	{
+		.subdevs = rm696_camera_primary_subdevs,
+		.interface = ISP_INTERFACE_CSI2A_PHY2,
+		.bus = { .csi2 = {
+			.crc		= 1,
+			.vpclk_div	= 1,
+			.lanecfg	= &rm696_main_camera_csi2_lanecfg,
+		} },
+	},
+	{
+		.subdevs = rm696_camera_secondary_subdevs,
+		.interface = ISP_INTERFACE_CCP2B_PHY1,
+		.bus = { .ccp2 = {
+			.strobe_clk_pol	= 0,
+			.crc		= 0,
+			.ccp2_mode	= 0,
+			.phy_layer	= 0,
+			.vpclk_div	= 2,
+			.lanecfg	= &rm680_sec_camera_csiphy_lanecfg,
+		} },
+	},
+	{ NULL, 0, },
+};
+
+static struct isp_v4l2_subdevs_group rm680_camera_subdevs[] = {
+	{
+		.subdevs = rm680_camera_primary_subdevs,
+		.interface = ISP_INTERFACE_CSI2A_PHY2,
+		.bus = { .csi2 = {
+			.crc		= 1,
+			.vpclk_div	= 1,
+			.lanecfg	= &rm680_main_camera_csi2_lanecfg,
+		} },
+	},
+	{
+		.subdevs = rm680_camera_secondary_subdevs,
+		.interface = ISP_INTERFACE_CCP2B_PHY1,
+		.bus = { .ccp2 = {
+			.strobe_clk_pol	= 0,
+			.crc		= 0,
+			.ccp2_mode	= 0,
+			.phy_layer	= 0,
+			.vpclk_div	= 2,
+			.lanecfg	= &rm680_sec_camera_csiphy_lanecfg,
+		} },
+	},
+	{ NULL, 0, },
+};
+
+static struct isp_platform_data rm696_isp_platform_data = {
+	.subdevs = rm696_camera_subdevs,
+};
+
+static struct isp_platform_data rm680_isp_platform_data = {
+	.subdevs = rm680_camera_subdevs,
+};
+
+static inline int board_is_rm680(void)
+{
+	return (system_rev & 0x00f0) == 0x0020;
+}
+
+void __init rm680_camera_init(void)
+{
+	struct isp_platform_data *pdata;
+	int rval;
+
+	rval = rm680_camera_hw_init();
+	if (rval) {
+		printk(KERN_WARNING "%s: unable to initialise camera\n",
+		       __func__);
+		return;
+	}
+
+	if (board_is_rm680())
+		pdata = &rm680_isp_platform_data;
+	else
+		pdata = &rm696_isp_platform_data;
+
+	if (omap3_init_camera(pdata) < 0)
+		printk(KERN_WARNING
+		       "%s: unable to register camera platform device\n",
+		       __func__);
+}
diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c
index a5bcc75..a1e33d4 100644
--- a/arch/arm/mach-omap2/board-rm680.c
+++ b/arch/arm/mach-omap2/board-rm680.c
@@ -66,6 +66,43 @@ static struct platform_device rm680_vemmc_device = {
 	},
 };
 
+#define REGULATOR_INIT_DATA(_name, _min, _max, _apply, _ops_mask) \
+	static struct regulator_init_data _name##_data = { \
+		.constraints = { \
+			.name                   = #_name, \
+			.min_uV                 = _min, \
+			.max_uV                 = _max, \
+			.apply_uV               = _apply, \
+			.valid_modes_mask       = REGULATOR_MODE_NORMAL | \
+						REGULATOR_MODE_STANDBY, \
+			.valid_ops_mask         = _ops_mask, \
+		}, \
+		.num_consumer_supplies  = ARRAY_SIZE(_name##_consumers), \
+		.consumer_supplies      = _name##_consumers, \
+}
+#define REGULATOR_INIT_DATA_FIXED(_name, _voltage) \
+	REGULATOR_INIT_DATA(_name, _voltage, _voltage, true, \
+				REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE)
+
+static struct regulator_consumer_supply rm680_vaux2_consumers[] = {
+	REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"),	/* OMAP ISP */
+	REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"),	/* OMAP ISP */
+	{
+		.supply		= "vaux2",
+	},
+};
+REGULATOR_INIT_DATA_FIXED(rm680_vaux2, 1800000);
+
+static struct regulator_consumer_supply rm680_vaux3_consumers[] = {
+	REGULATOR_SUPPLY("VANA", "2-0037"),	/* Main Camera Sensor */
+	REGULATOR_SUPPLY("VANA", "2-000e"),	/* Main Camera Lens */
+	REGULATOR_SUPPLY("VANA", "2-0010"),	/* Front Camera */
+	{
+		.supply		= "vaux3",
+	},
+};
+REGULATOR_INIT_DATA_FIXED(rm680_vaux3, 2800000);
+
 static struct platform_device *rm680_peripherals_devices[] __initdata = {
 	&rm680_vemmc_device,
 };
@@ -82,6 +119,8 @@ static struct twl4030_gpio_platform_data rm680_gpio_data = {
 static struct twl4030_platform_data rm680_twl_data = {
 	.gpio			= &rm680_gpio_data,
 	/* add rest of the children here */
+	.vaux2			= &rm680_vaux2_data,
+	.vaux3			= &rm680_vaux3_data,
 };
 
 static void __init rm680_i2c_init(void)
@@ -129,6 +168,8 @@ static struct omap_board_mux board_mux[] __initdata = {
 };
 #endif
 
+void rm680_camera_init(void);
+
 static void __init rm680_init(void)
 {
 	struct omap_sdrc_params *sdrc_params;
@@ -141,6 +182,7 @@ static void __init rm680_init(void)
 
 	usb_musb_init(NULL);
 	rm680_peripherals_init();
+	rm680_camera_init();
 }
 
 MACHINE_START(NOKIA_RM680, "Nokia RM-680 board")
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [yavta PATCH 1/1] Support integer menus.
  2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
                   ` (16 preceding siblings ...)
  2011-12-20 20:28 ` [RFC 17/17] rm680: Add camera init Sakari Ailus
@ 2011-12-28  9:47 ` Sakari Ailus
  2012-01-05 16:03   ` Laurent Pinchart
  17 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2011-12-28  9:47 UTC (permalink / raw)
  To: linux-media
  Cc: laurent.pinchart, snjw23, hverkuil, andriy.shevchenko,
	t.stanislaws, tuukkat76, k.debski, riverful

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
---
 yavta.c |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/yavta.c b/yavta.c
index c0e9acb..9b8a80e 100644
--- a/yavta.c
+++ b/yavta.c
@@ -551,6 +551,7 @@ static int video_enable(struct device *dev, int enable)
 }
 
 static void video_query_menu(struct device *dev, unsigned int id,
+			     unsigned int type,
 			     unsigned int min, unsigned int max)
 {
 	struct v4l2_querymenu menu;
@@ -562,7 +563,10 @@ static void video_query_menu(struct device *dev, unsigned int id,
 		if (ret < 0)
 			continue;
 
-		printf("  %u: %.32s\n", menu.index, menu.name);
+		if (type == V4L2_CTRL_TYPE_MENU)
+			printf("  %u: %.32s\n", menu.index, menu.name);
+		else
+			printf("  %u: %lld\n", menu.index, menu.value);
 	};
 }
 
@@ -607,8 +611,10 @@ static void video_list_controls(struct device *dev)
 			query.id, query.name, query.minimum, query.maximum,
 			query.step, query.default_value, value);
 
-		if (query.type == V4L2_CTRL_TYPE_MENU)
-			video_query_menu(dev, query.id, query.minimum, query.maximum);
+		if (query.type == V4L2_CTRL_TYPE_MENU ||
+		    query.type == V4L2_CTRL_TYPE_INTEGER_MENU)
+			video_query_menu(dev, query.id, query.type,
+					 query.minimum, query.maximum);
 
 		nctrls++;
 	}
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [RFC 01/17] v4l: Introduce integer menu controls
  2011-12-20 20:27 ` [RFC 01/17] v4l: Introduce integer menu controls Sakari Ailus
@ 2012-01-05 15:53   ` Laurent Pinchart
  2012-01-06  9:50     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-05 15:53 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:27:53 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Create a new control type called V4L2_CTRL_TYPE_INTEGER_MENU. Integer menu
> controls are just like menu controls but the menu items are 64-bit integers
> rather than strings.

[snip]

> diff --git a/drivers/media/video/v4l2-ctrls.c
> b/drivers/media/video/v4l2-ctrls.c index 0f415da..083bb79 100644
> --- a/drivers/media/video/v4l2-ctrls.c
> +++ b/drivers/media/video/v4l2-ctrls.c

> @@ -1775,16 +1797,22 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl,
> struct v4l2_querymenu *qm)
> 
>  	qm->reserved = 0;
>  	/* Sanity checks */

You should return -EINVAL here if the control is not of a menu type. It was 
done implictly before by the ctrl->qmenu == NULL check, but that's now 
conditioned to the control type being V4L2_CTRL_TYPE_MENU.

> -	if (ctrl->qmenu == NULL ||
> +	if ((ctrl->type == V4L2_CTRL_TYPE_MENU && ctrl->qmenu == NULL) ||
> +	    (ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU
> +	     && ctrl->qmenu_int == NULL) ||
>  	    i < ctrl->minimum || i > ctrl->maximum)
>  		return -EINVAL;
>  	/* Use mask to see if this menu item should be skipped */
>  	if (ctrl->menu_skip_mask & (1 << i))
>  		return -EINVAL;
>  	/* Empty menu items should also be skipped */
> -	if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
> -		return -EINVAL;
> -	strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
> +	if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
> +		if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
> +			return -EINVAL;
> +		strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
> +	} else if (ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU) {

And you can then replace the else if by an else.

> +		qm->value = ctrl->qmenu_int[i];
> +	}
>  	return 0;
>  }
>  EXPORT_SYMBOL(v4l2_querymenu);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 02/17] v4l: Document integer menu controls
  2011-12-20 20:27 ` [RFC 02/17] v4l: Document " Sakari Ailus
@ 2012-01-05 15:55   ` Laurent Pinchart
  2012-01-06 10:07     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-05 15:55 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:27:54 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  Documentation/DocBook/media/v4l/compat.xml         |   10 +++++
>  Documentation/DocBook/media/v4l/v4l2.xml           |    7 ++++
>  .../DocBook/media/v4l/vidioc-queryctrl.xml         |   39
> +++++++++++++++++++- 3 files changed, 54 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/DocBook/media/v4l/compat.xml
> b/Documentation/DocBook/media/v4l/compat.xml index b68698f..569efd1 100644
> --- a/Documentation/DocBook/media/v4l/compat.xml
> +++ b/Documentation/DocBook/media/v4l/compat.xml
> @@ -2379,6 +2379,16 @@ that used it. It was originally scheduled for
> removal in 2.6.35. </orderedlist>
>      </section>
> 
> +    <section>
> +      <title>V4L2 in Linux 3.3</title>

Seems it will be for 3.4 :-) Same for Documentation/DocBook/media/v4l/v4l2.xml

> +      <orderedlist>
> +        <listitem>
> +	  <para>Added integer menus, the new type will be
> +	  V4L2_CTRL_TYPE_INTEGER_MENU.</para>
> +        </listitem>
> +      </orderedlist>
> +    </section>
> +
>      <section id="other">
>        <title>Relation of V4L2 to other Linux multimedia APIs</title>
> 

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 03/17] vivi: Add an integer menu test control
  2011-12-20 20:27 ` [RFC 03/17] vivi: Add an integer menu test control Sakari Ailus
@ 2012-01-05 15:59   ` Laurent Pinchart
  2012-01-06 10:19     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-05 15:59 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:27:55 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Add an integer menu test control for the vivi driver.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  drivers/media/video/vivi.c |   21 +++++++++++++++++++++
>  1 files changed, 21 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
> index 7d754fb..763ec23 100644
> --- a/drivers/media/video/vivi.c
> +++ b/drivers/media/video/vivi.c
> @@ -177,6 +177,7 @@ struct vivi_dev {
>  	struct v4l2_ctrl	   *menu;
>  	struct v4l2_ctrl	   *string;
>  	struct v4l2_ctrl	   *bitmask;
> +	struct v4l2_ctrl	   *int_menu;
> 
>  	spinlock_t                 slock;
>  	struct mutex		   mutex;
> @@ -503,6 +504,10 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct
> vivi_buffer *buf) dev->boolean->cur.val,
>  			dev->menu->qmenu[dev->menu->cur.val],
>  			dev->string->cur.string);
> +	snprintf(str, sizeof(str), " integer_menu %s, value %lld ",
> +			dev->int_menu->qmenu[dev->int_menu->cur.val],

Shouldn't you print the content of qmenu_int as a 64-bit integer instead ?

> +			dev->int64->cur.val64);

Shouldn't this be dev->int_menu->cur.val ?

> +	gen_text(dev, vbuf, line++ * 16, 16, str);
>  	mutex_unlock(&dev->ctrl_handler.lock);
>  	gen_text(dev, vbuf, line++ * 16, 16, str);
>  	if (dev->button_pressed) {
> @@ -1183,6 +1188,22 @@ static const struct v4l2_ctrl_config
> vivi_ctrl_bitmask = { .step = 0,
>  };
> 
> +static const s64 * const vivi_ctrl_int_menu_values[] = {
> +	1, 1, 2, 3, 5, 8, 13, 21, 42,
> +};
> +
> +static const struct v4l2_ctrl_config vivi_ctrl_string = {
> +	.ops = &vivi_ctrl_ops,
> +	.id = VIDI_CID_CUSTOM_BASE + 7
> +	.name = "Integer menu",
> +	.type = V4L2_CTRL_TYPE_INTEGER_MENU,
> +	.min = 1,
> +	.max = 8,

There are 9 values in your vivi_ctrl_int_menu_values array. Is 8 on purpose 
here ?

> +	.def = 4,
> +	.menu_skip_mask = 0x02,
> +	.qmenu_int = &vivi_ctrl_int_menu_values,
> +};
> +
>  static const struct v4l2_file_operations vivi_fops = {
>  	.owner		= THIS_MODULE,
>  	.open           = v4l2_fh_open,

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [yavta PATCH 1/1] Support integer menus.
  2011-12-28  9:47 ` [yavta PATCH 1/1] Support integer menus Sakari Ailus
@ 2012-01-05 16:03   ` Laurent Pinchart
  0 siblings, 0 replies; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-05 16:03 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, snjw23, hverkuil, andriy.shevchenko, t.stanislaws,
	tuukkat76, k.debski, riverful

Hi Sakari,

Thanks for the patch.

On Wednesday 28 December 2011 10:47:01 Sakari Ailus wrote:
> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  yavta.c |   12 +++++++++---
>  1 files changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/yavta.c b/yavta.c
> index c0e9acb..9b8a80e 100644
> --- a/yavta.c
> +++ b/yavta.c
> @@ -551,6 +551,7 @@ static int video_enable(struct device *dev, int enable)
>  }
> 
>  static void video_query_menu(struct device *dev, unsigned int id,
> +			     unsigned int type,
>  			     unsigned int min, unsigned int max)
>  {
>  	struct v4l2_querymenu menu;
> @@ -562,7 +563,10 @@ static void video_query_menu(struct device *dev,
> unsigned int id, if (ret < 0)
>  			continue;
> 
> -		printf("  %u: %.32s\n", menu.index, menu.name);
> +		if (type == V4L2_CTRL_TYPE_MENU)
> +			printf("  %u: %.32s\n", menu.index, menu.name);
> +		else
> +			printf("  %u: %lld\n", menu.index, menu.value);
>  	};
>  }
> 
> @@ -607,8 +611,10 @@ static void video_list_controls(struct device *dev)
>  			query.id, query.name, query.minimum, query.maximum,
>  			query.step, query.default_value, value);
> 
> -		if (query.type == V4L2_CTRL_TYPE_MENU)
> -			video_query_menu(dev, query.id, query.minimum, query.maximum);
> +		if (query.type == V4L2_CTRL_TYPE_MENU ||
> +		    query.type == V4L2_CTRL_TYPE_INTEGER_MENU)
> +			video_query_menu(dev, query.id, query.type,
> +					 query.minimum, query.maximum);

What about passing &query to the function instead ?

> 
>  		nctrls++;
>  	}

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs
  2011-12-20 20:27 ` [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs Sakari Ailus
@ 2012-01-05 16:12   ` Laurent Pinchart
  2012-01-06 11:27     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-05 16:12 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:27:56 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Add support for VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION
> IOCTLs. They replace functionality provided by VIDIOC_SUBDEV_S_CROP and
> VIDIOC_SUBDEV_G_CROP IOCTLs and also add new functionality (composing).
> 
> VIDIOC_SUBDEV_G_CROP and VIDIOC_SUBDEV_S_CROP continue to be supported.

As those ioctls are experimental, should we deprecate them ?

> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  drivers/media/video/v4l2-subdev.c |   26 ++++++++++++++++++++-
>  include/linux/v4l2-subdev.h       |   45 ++++++++++++++++++++++++++++++++++
>  include/media/v4l2-subdev.h       |    5 ++++
>  3 files changed, 75 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/media/video/v4l2-subdev.c
> b/drivers/media/video/v4l2-subdev.c index 65ade5f..e8ae098 100644
> --- a/drivers/media/video/v4l2-subdev.c
> +++ b/drivers/media/video/v4l2-subdev.c
> @@ -36,13 +36,17 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh,
> struct v4l2_subdev *sd) {
>  #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
>  	/* Allocate try format and crop in the same memory block */
> -	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
> +	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop)
> +			       + sizeof(*fh->try_compose))
>  			      * sd->entity.num_pads, GFP_KERNEL);

Could you check how the 3 structures are aligned on 64-bit platforms ? I'm a 
bit worried about the compiler expecting a 64-bit alignment for one of them, 
and getting only a 32-bit alignment in the end.

What about using kcalloc ?

>  	if (fh->try_fmt == NULL)
>  		return -ENOMEM;
> 
>  	fh->try_crop = (struct v4l2_rect *)
>  		(fh->try_fmt + sd->entity.num_pads);
> +
> +	fh->try_compose = (struct v4l2_rect *)
> +		(fh->try_crop + sd->entity.num_pads);
>  #endif
>  	return 0;
>  }
> @@ -281,6 +285,26 @@ static long subdev_do_ioctl(struct file *file,
> unsigned int cmd, void *arg) return v4l2_subdev_call(sd, pad,
> enum_frame_interval, subdev_fh, fie);
>  	}
> +
> +	case VIDIOC_SUBDEV_G_SELECTION: {
> +		struct v4l2_subdev_selection *sel = arg;

Shouldn't you check sel->which ?

> +		if (sel->pad >= sd->entity.num_pads)
> +			return -EINVAL;
> +
> +		return v4l2_subdev_call(
> +			sd, pad, get_selection, subdev_fh, sel);
> +	}
> +
> +	case VIDIOC_SUBDEV_S_SELECTION: {
> +		struct v4l2_subdev_selection *sel = arg;

And here too ?

> +		if (sel->pad >= sd->entity.num_pads)
> +			return -EINVAL;
> +
> +		return v4l2_subdev_call(
> +			sd, pad, set_selection, subdev_fh, sel);
> +	}
>  #endif
>  	default:
>  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
> index ed29cbb..d53d775 100644
> --- a/include/linux/v4l2-subdev.h
> +++ b/include/linux/v4l2-subdev.h
> @@ -123,6 +123,47 @@ struct v4l2_subdev_frame_interval_enum {
>  	__u32 reserved[9];
>  };
> 
> +#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE			(1 << 0)
> +#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE			(1 << 1)
> +#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG		(1 << 2)
> +
> +/* active cropping area */
> +#define V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE			0
> +/* default cropping area */
> +#define V4L2_SUBDEV_SEL_TGT_CROP_DEFAULT		1
> +/* cropping bounds */
> +#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS			2
> +/* current composing area */
> +#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE		256
> +/* default composing area */
> +#define V4L2_SUBDEV_SEL_TGT_COMPOSE_DEFAULT		257
> +/* composing bounds */
> +#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS		258
> +
> +
> +/**
> + * struct v4l2_subdev_selection - selection info
> + *
> + * @which: either V4L2_SUBDEV_FORMAT_ACTIVE or V4L2_SUBDEV_FORMAT_TRY
> + * @pad: pad number, as reported by the media API
> + * @target: selection target, used to choose one of possible rectangles
> + * @flags: constraints flags
> + * @r: coordinates of selection window
> + * @reserved: for future use, rounds structure size to 64 bytes, set to
> zero + *
> + * Hardware may use multiple helper window to process a video stream.
> + * The structure is used to exchange this selection areas between
> + * an application and a driver.
> + */
> +struct v4l2_subdev_selection {
> +	__u32 which;
> +	__u32 pad;
> +	__u32 target;
> +	__u32 flags;
> +	struct v4l2_rect r;
> +	__u32 reserved[8];
> +};
> +
>  #define VIDIOC_SUBDEV_G_FMT	_IOWR('V',  4, struct v4l2_subdev_format)
>  #define VIDIOC_SUBDEV_S_FMT	_IOWR('V',  5, struct v4l2_subdev_format)
>  #define VIDIOC_SUBDEV_G_FRAME_INTERVAL \
> @@ -137,5 +178,9 @@ struct v4l2_subdev_frame_interval_enum {
>  			_IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)
>  #define VIDIOC_SUBDEV_G_CROP	_IOWR('V', 59, struct v4l2_subdev_crop)
>  #define VIDIOC_SUBDEV_S_CROP	_IOWR('V', 60, struct v4l2_subdev_crop)
> +#define VIDIOC_SUBDEV_G_SELECTION \
> +	_IOWR('V', 61, struct v4l2_subdev_selection)
> +#define VIDIOC_SUBDEV_S_SELECTION \
> +	_IOWR('V', 62, struct v4l2_subdev_selection)
> 
>  #endif
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index f0f3358..26eeaa4 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -466,6 +466,10 @@ struct v4l2_subdev_pad_ops {
>  		       struct v4l2_subdev_crop *crop);
>  	int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
>  		       struct v4l2_subdev_crop *crop);
> +	int (*get_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
> +			     struct v4l2_subdev_selection *sel);
> +	int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
> +			     struct v4l2_subdev_selection *sel);
>  };
> 
>  struct v4l2_subdev_ops {
> @@ -551,6 +555,7 @@ struct v4l2_subdev_fh {
>  #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
>  	struct v4l2_mbus_framefmt *try_fmt;
>  	struct v4l2_rect *try_crop;
> +	struct v4l2_rect *try_compose;
>  #endif
>  };

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 05/17] v4l: Support s_crop and g_crop through s/g_selection
  2011-12-20 20:27 ` [RFC 05/17] v4l: Support s_crop and g_crop through s/g_selection Sakari Ailus
@ 2012-01-05 16:13   ` Laurent Pinchart
  2012-01-08 20:54     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-05 16:13 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:27:57 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Revert to s_selection if s_crop isn't implemented by a driver. Same for
> g_selection / g_crop.

Shouldn't this say "Fall back" instead of "Revert" ?

> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  drivers/media/video/v4l2-subdev.c |   37
> +++++++++++++++++++++++++++++++++++-- 1 files changed, 35 insertions(+), 2
> deletions(-)
> 
> diff --git a/drivers/media/video/v4l2-subdev.c
> b/drivers/media/video/v4l2-subdev.c index e8ae098..f8de551 100644
> --- a/drivers/media/video/v4l2-subdev.c
> +++ b/drivers/media/video/v4l2-subdev.c
> @@ -226,6 +226,8 @@ static long subdev_do_ioctl(struct file *file, unsigned
> int cmd, void *arg)
> 
>  	case VIDIOC_SUBDEV_G_CROP: {
>  		struct v4l2_subdev_crop *crop = arg;
> +		struct v4l2_subdev_selection sel;
> +		int rval;
> 
>  		if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
>  		    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
> @@ -234,11 +236,27 @@ static long subdev_do_ioctl(struct file *file,
> unsigned int cmd, void *arg) if (crop->pad >= sd->entity.num_pads)
>  			return -EINVAL;
> 
> -		return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
> +		rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
> +		if (rval != -ENOIOCTLCMD)
> +			return rval;
> +
> +		memset(&sel, 0, sizeof(sel));
> +		sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;

Shouldn't sel.which be set to crop->which ?

> +		sel.pad = crop->pad;
> +		sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE;
> +
> +		rval = v4l2_subdev_call(
> +			sd, pad, get_selection, subdev_fh, &sel);
> +
> +		crop->rect = sel.r;
> +
> +		return rval;
>  	}
> 
>  	case VIDIOC_SUBDEV_S_CROP: {
>  		struct v4l2_subdev_crop *crop = arg;
> +		struct v4l2_subdev_selection sel;
> +		int rval;
> 
>  		if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
>  		    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
> @@ -247,7 +265,22 @@ static long subdev_do_ioctl(struct file *file,
> unsigned int cmd, void *arg) if (crop->pad >= sd->entity.num_pads)
>  			return -EINVAL;
> 
> -		return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
> +		rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
> +		if (rval != -ENOIOCTLCMD)
> +			return rval;
> +
> +		memset(&sel, 0, sizeof(sel));
> +		sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;

Same here.

> +		sel.pad = crop->pad;
> +		sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE;
> +		sel.r = crop->rect;
> +
> +		rval = v4l2_subdev_call(
> +			sd, pad, set_selection, subdev_fh, &sel);
> +
> +		crop->rect = sel.r;
> +
> +		return rval;
>  	}
> 
>  	case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 08/17] v4l: Image source control class
  2011-12-20 20:28 ` [RFC 08/17] v4l: Image source control class Sakari Ailus
@ 2012-01-05 16:23   ` Laurent Pinchart
  2012-01-14 20:51     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-05 16:23 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:28:00 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Add image source control class. This control class is intended to contain
> low level controls which deal with control of the image capture process ---
> the A/D converter in image sensors, for example.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  Documentation/DocBook/media/v4l/controls.xml       |  101 +++++++++++++++++
>  .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       |    6 +
>  drivers/media/video/v4l2-ctrls.c                   |   10 ++
>  include/linux/videodev2.h                          |   10 ++
>  4 files changed, 127 insertions(+), 0 deletions(-)
> 
> diff --git a/Documentation/DocBook/media/v4l/controls.xml
> b/Documentation/DocBook/media/v4l/controls.xml index 3bc5ee8..69ede83
> 100644
> --- a/Documentation/DocBook/media/v4l/controls.xml
> +++ b/Documentation/DocBook/media/v4l/controls.xml
> @@ -3356,6 +3356,107 @@ interface and may change in the future.</para>
>        </table>
> 
>      </section>
> +
> +    <section id="image-source-controls">
> +      <title>Image Source Control Reference</title>
> +
> +      <note>
> +	<title>Experimental</title>
> +
> +	<para>This is an <link
> +	linkend="experimental">experimental</link> interface and may
> +	change in the future.</para>
> +      </note>
> +
> +      <para>
> +	The Image Source control class is intended for low-level
> +	control of image source devices such as image sensors. The
> +	devices feature an analogue to digital converter and a bus

Is the V4L2 documentation written in US or UK English ? US uses analog, UK 
uses analogue. Analog would be shorter in control names.

> +	transmitter to transmit the image data out of the device.
> +      </para>
> +
> +      <table pgwide="1" frame="none" id="image-source-control-id">
> +      <title>Image Source Control IDs</title>
> +
> +      <tgroup cols="4">
> +	<colspec colname="c1" colwidth="1*" />
> +	<colspec colname="c2" colwidth="6*" />
> +	<colspec colname="c3" colwidth="2*" />
> +	<colspec colname="c4" colwidth="6*" />
> +	<spanspec namest="c1" nameend="c2" spanname="id" />
> +	<spanspec namest="c2" nameend="c4" spanname="descr" />
> +	<thead>
> +	  <row>
> +	    <entry spanname="id" align="left">ID</entry>
> +	    <entry align="left">Type</entry>
> +	  </row><row rowsep="1"><entry spanname="descr"
> align="left">Description</entry> +	  </row>
> +	</thead>
> +	<tbody valign="top">
> +	  <row><entry></entry></row>
> +	  <row>
> +	    <entry
> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry> +	 
>   <entry>class</entry>
> +	  </row>
> +	  <row>
> +	    <entry spanname="descr">The IMAGE_SOURCE class descriptor.</entry>
> +	  </row>
> +	  <row>
> +	    <entry
> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_VBLANK</constant></entry> +	
>    <entry>integer</entry>
> +	  </row>
> +	  <row>
> +	    <entry spanname="descr">Vertical blanking. The idle
> +	    preriod after every frame during which no image data is

s/preriod/period/

> +	    produced. The unit of vertical blanking is a line. Every
> +	    line has length of the image width plus horizontal
> +	    blanking at the pixel clock specified by struct
> +	    v4l2_mbus_framefmt <xref linkend="v4l2-mbus-framefmt"
> +	    />.</entry>
> +	  </row>
> +	  <row>
> +	    <entry
> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_HBLANK</constant></entry> +	
>    <entry>integer</entry>
> +	  </row>
> +	  <row>
> +	    <entry spanname="descr">Horizontal blanking. The idle
> +	    preriod after every line of image data during which no

s/preriod/period/

> +	    image data is produced. The unit of horizontal blanking is
> +	    pixels.</entry>
> +	  </row>
> +	  <row>
> +	    <entry
> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_LINK_FREQ</constant></entry>
> +	    <entry>integer menu</entry>
> +	  </row>
> +	  <row>
> +	    <entry spanname="descr">Image source's data bus frequency.

What's the frequency unit ? Sample/second ?

> +	    Together with the media bus pixel code, bus type (clock
> +	    cycles per sample), the data bus frequency defines the
> +	    pixel clock. <xref linkend="v4l2-mbus-framefmt" /> The
> +	    frame rate can be calculated from the pixel clock, image
> +	    width and height and horizontal and vertical blanking. The
> +	    frame rate control is performed by selecting the desired
> +	    horizontal and vertical blanking.
> +	    </entry>
> +	  </row>
> +	  <row>
> +	    <entry
> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN</constant></en
> try> +	    <entry>integer</entry>
> +	  </row>
> +	  <row>
> +	    <entry spanname="descr">Analogue gain is gain affecting
> +	    all colour components in the pixel matrix. The gain
> +	    operation is performed in the analogue domain before A/D
> +	    conversion.

Should we define one gain per color component ?

> +	    </entry>
> +	  </row>
> +	  <row><entry></entry></row>
> +	</tbody>
> +      </tgroup>
> +      </table>
> +
> +    </section>
> +
>  </section>
> 
>    <!--
> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
> b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml index
> 5122ce8..250c1cf 100644
> --- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
> +++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
> @@ -257,6 +257,12 @@ These controls are described in <xref
>  These controls are described in <xref
>  		linkend="flash-controls" />.</entry>
>  	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_CTRL_CLASS_IMAGE_SOURCE</constant></entry>
> +	    <entry>0x9d0000</entry> <entry>The class containing image
> +	    source controls. These controls are described in <xref
> +	    linkend="image-source-controls" />.</entry>
> +	  </row>
>  	</tbody>
>        </tgroup>
>      </table>
> diff --git a/drivers/media/video/v4l2-ctrls.c
> b/drivers/media/video/v4l2-ctrls.c index 083bb79..da1ec52 100644
> --- a/drivers/media/video/v4l2-ctrls.c
> +++ b/drivers/media/video/v4l2-ctrls.c
> @@ -606,6 +606,12 @@ const char *v4l2_ctrl_get_name(u32 id)
>  	case V4L2_CID_FLASH_CHARGE:		return "Charge";
>  	case V4L2_CID_FLASH_READY:		return "Ready to strobe";
> 
> +	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image source controls";
> +	case V4L2_CID_IMAGE_SOURCE_VBLANK:	return "Vertical blanking";
> +	case V4L2_CID_IMAGE_SOURCE_HBLANK:	return "Horizontal blanking";
> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:	return "Link frequency";
> +	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN: return "Analogue gain";

Please capitalize each word, as done for the other controls.

>  	default:
>  		return NULL;
>  	}
> @@ -694,6 +700,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum
> v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
>  		*type = V4L2_CTRL_TYPE_MENU;
>  		break;
> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:
> +		*type = V4L2_CTRL_TYPE_INTEGER_MENU;
> +		break;

Will this always be an integer menu control, or can you foresee cases where 
the range would be continuous ?

We already have drivers for Aptina parallel sensors that include a 
configurable PLL. The pixel clock can be configured more or less freely in 
that case, although I'm not sure if that's useful in practice.

>  	case V4L2_CID_RDS_TX_PS_NAME:
>  	case V4L2_CID_RDS_TX_RADIO_TEXT:
>  		*type = V4L2_CTRL_TYPE_STRING;
> @@ -703,6 +712,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum
> v4l2_ctrl_type *type, case V4L2_CID_MPEG_CLASS:
>  	case V4L2_CID_FM_TX_CLASS:
>  	case V4L2_CID_FLASH_CLASS:
> +	case V4L2_CID_IMAGE_SOURCE_CLASS:
>  		*type = V4L2_CTRL_TYPE_CTRL_CLASS;
>  		/* You can neither read not write these */
>  		*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> index 9633c69..0f8f904 100644
> --- a/include/linux/videodev2.h
> +++ b/include/linux/videodev2.h
> @@ -1080,6 +1080,7 @@ struct v4l2_ext_controls {
>  #define V4L2_CTRL_CLASS_CAMERA 0x009a0000	/* Camera class controls */
>  #define V4L2_CTRL_CLASS_FM_TX 0x009b0000	/* FM Modulator control class */
>  #define V4L2_CTRL_CLASS_FLASH 0x009c0000	/* Camera flash controls */
> +#define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009d0000	/* Image source flash
> controls */
> 
>  #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
>  #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
> @@ -1690,6 +1691,15 @@ enum v4l2_flash_strobe_source {
>  #define V4L2_CID_FLASH_CHARGE			(V4L2_CID_FLASH_CLASS_BASE + 11)
>  #define V4L2_CID_FLASH_READY			(V4L2_CID_FLASH_CLASS_BASE + 12)
> 
> +/* Image source controls */
> +#define V4L2_CID_IMAGE_SOURCE_CLASS_BASE	(V4L2_CTRL_CLASS_IMAGE_SOURCE |
> 0x900) +#define V4L2_CID_IMAGE_SOURCE_CLASS		
(V4L2_CTRL_CLASS_IMAGE_SOURCE
> | 1) +
> +#define V4L2_CID_IMAGE_SOURCE_VBLANK		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE 
+
> 1) +#define
> V4L2_CID_IMAGE_SOURCE_HBLANK		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
> +#define
> V4L2_CID_IMAGE_SOURCE_LINK_FREQ		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
> +#define
> V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN	(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4)
> +
>  /*
>   *	T U N I N G
>   */

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 09/17] v4l: Add pad op for pipeline validation
  2011-12-20 20:28 ` [RFC 09/17] v4l: Add pad op for pipeline validation Sakari Ailus
@ 2012-01-06  9:42   ` Laurent Pinchart
  2012-01-07 23:28     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-06  9:42 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:28:01 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> smiapp_pad_ops.validate_pipeline is intended to validate the full pipeline
> which is implemented by the driver to which the subdev implementing this op
> belongs to.

Should this be documented in Documentation/video4linux/v4l2-framework.txt ?

> The validate_pipeline op must also call validate_pipeline on any external
> entity which is linked to its sink pads.

I'm uncertain about this. Subdev drivers would then have to implement the 
pipeline walk logic, resulting in duplicate code. Our current situation isn't 
optimal either: walking the pipeline should be implemented in the media code. 
Would it suit your needs if the validate_pipeline operation was replaced by a 
validate_link operation, with a media_pipeline_validate() function in the 
media core to walk the pipeline and call validate_link in each pad (or maybe 
each sink pad) ?

> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  include/media/v4l2-subdev.h |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)
> 
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 26eeaa4..a5ebe86 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -470,6 +470,7 @@ struct v4l2_subdev_pad_ops {
>  			     struct v4l2_subdev_selection *sel);
>  	int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
>  			     struct v4l2_subdev_selection *sel);
> +	int (*validate_pipeline)(struct v4l2_subdev *sd);
>  };
> 
>  struct v4l2_subdev_ops {

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 01/17] v4l: Introduce integer menu controls
  2012-01-05 15:53   ` Laurent Pinchart
@ 2012-01-06  9:50     ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-06  9:50 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thanks for the patch.

Thanks for the review!

> On Tuesday 20 December 2011 21:27:53 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Create a new control type called V4L2_CTRL_TYPE_INTEGER_MENU. Integer menu
>> controls are just like menu controls but the menu items are 64-bit integers
>> rather than strings.
> 
> [snip]
> 
>> diff --git a/drivers/media/video/v4l2-ctrls.c
>> b/drivers/media/video/v4l2-ctrls.c index 0f415da..083bb79 100644
>> --- a/drivers/media/video/v4l2-ctrls.c
>> +++ b/drivers/media/video/v4l2-ctrls.c
> 
>> @@ -1775,16 +1797,22 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl,
>> struct v4l2_querymenu *qm)
>>
>>  	qm->reserved = 0;
>>  	/* Sanity checks */
> 
> You should return -EINVAL here if the control is not of a menu type. It was 
> done implictly before by the ctrl->qmenu == NULL check, but that's now 
> conditioned to the control type being V4L2_CTRL_TYPE_MENU.

Good point. Fixed.

>> -	if (ctrl->qmenu == NULL ||
>> +	if ((ctrl->type == V4L2_CTRL_TYPE_MENU && ctrl->qmenu == NULL) ||
>> +	    (ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU
>> +	     && ctrl->qmenu_int == NULL) ||
>>  	    i < ctrl->minimum || i > ctrl->maximum)
>>  		return -EINVAL;
>>  	/* Use mask to see if this menu item should be skipped */
>>  	if (ctrl->menu_skip_mask & (1 << i))
>>  		return -EINVAL;
>>  	/* Empty menu items should also be skipped */
>> -	if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
>> -		return -EINVAL;
>> -	strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
>> +	if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
>> +		if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
>> +			return -EINVAL;
>> +		strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
>> +	} else if (ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU) {
> 
> And you can then replace the else if by an else.

As well as this one.

>> +		qm->value = ctrl->qmenu_int[i];
>> +	}
>>  	return 0;
>>  }
>>  EXPORT_SYMBOL(v4l2_querymenu);
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2011-12-20 20:28 ` [RFC 13/17] omap3isp: Configure CSI-2 phy based on " Sakari Ailus
@ 2012-01-06 10:01   ` Laurent Pinchart
  2012-01-07 22:51     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-06 10:01 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:28:05 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Configure CSI-2 phy based on platform data in the ISP driver rather than in
> platform code.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  drivers/media/video/omap3isp/isp.c       |   38 ++++++++++++--
>  drivers/media/video/omap3isp/isp.h       |    3 -
>  drivers/media/video/omap3isp/ispcsiphy.c |   83 +++++++++++++++++++++++----
>  drivers/media/video/omap3isp/ispcsiphy.h |    4 ++
>  4 files changed, 111 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/media/video/omap3isp/isp.c
> b/drivers/media/video/omap3isp/isp.c index b818cac..6020fd7 100644
> --- a/drivers/media/video/omap3isp/isp.c
> +++ b/drivers/media/video/omap3isp/isp.c
> @@ -737,7 +737,7 @@ static int isp_pipeline_enable(struct isp_pipeline
> *pipe, struct isp_device *isp = pipe->output->isp;
>  	struct media_entity *entity;
>  	struct media_pad *pad;
> -	struct v4l2_subdev *subdev;
> +	struct v4l2_subdev *subdev = NULL, *prev_subdev;
>  	unsigned long flags;
>  	int ret;
> 
> @@ -759,11 +759,41 @@ static int isp_pipeline_enable(struct isp_pipeline
> *pipe, break;
> 
>  		entity = pad->entity;
> +		prev_subdev = subdev;
>  		subdev = media_entity_to_v4l2_subdev(entity);
> 
> -		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
> -		if (ret < 0 && ret != -ENOIOCTLCMD)
> -			return ret;
> +		/* Configure CSI-2 receiver based on sensor format. */
> +		if (prev_subdev == &isp->isp_csi2a.subdev
> +		    || prev_subdev == &isp->isp_csi2c.subdev) {
> +			struct v4l2_subdev_format fmt;
> +
> +			fmt.pad = pad->index;
> +			fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +			ret = v4l2_subdev_call(subdev, pad, get_fmt,
> +					       NULL, &fmt);
> +			if (ret < 0)
> +				return -EPIPE;
> +
> +			ret = omap3isp_csiphy_config(
> +				isp, prev_subdev, subdev,
> +				&fmt.format);
> +			if (ret < 0)
> +				return -EPIPE;
> +
> +			/* Start CSI-2 after configuration. */
> +			ret = v4l2_subdev_call(prev_subdev, video,
> +					       s_stream, mode);
> +			if (ret < 0 && ret != -ENOIOCTLCMD)
> +				return ret;
> +		}
> +
> +		/* Start any other subdev except the CSI-2 receivers. */
> +		if (subdev != &isp->isp_csi2a.subdev
> +		    && subdev != &isp->isp_csi2c.subdev) {
> +			ret = v4l2_subdev_call(subdev, video, s_stream, mode);
> +			if (ret < 0 && ret != -ENOIOCTLCMD)
> +				return ret;
> +		}

What about moving this to the CSI2 s_stream subdev operation ?

> 
>  		if (subdev == &isp->isp_ccdc.subdev) {
>  			v4l2_subdev_call(&isp->isp_aewb.subdev, video,
> diff --git a/drivers/media/video/omap3isp/isp.h
> b/drivers/media/video/omap3isp/isp.h index 705946e..c5935ae 100644
> --- a/drivers/media/video/omap3isp/isp.h
> +++ b/drivers/media/video/omap3isp/isp.h
> @@ -126,9 +126,6 @@ struct isp_reg {
> 
>  struct isp_platform_callback {
>  	u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
> -	int (*csiphy_config)(struct isp_csiphy *phy,
> -			     struct isp_csiphy_dphy_cfg *dphy,
> -			     struct isp_csiphy_lanes_cfg *lanes);
>  	void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
>  };
> 
> diff --git a/drivers/media/video/omap3isp/ispcsiphy.c
> b/drivers/media/video/omap3isp/ispcsiphy.c index 5be37ce..f027ece 100644
> --- a/drivers/media/video/omap3isp/ispcsiphy.c
> +++ b/drivers/media/video/omap3isp/ispcsiphy.c
> @@ -28,6 +28,8 @@
>  #include <linux/device.h>
>  #include <linux/regulator/consumer.h>
> 
> +#include "../../../../arch/arm/mach-omap2/control.h"
> +

#include <mach/control.h>

(untested) ?

>  #include "isp.h"
>  #include "ispreg.h"
>  #include "ispcsiphy.h"
> @@ -138,15 +140,78 @@ static void csiphy_dphy_config(struct isp_csiphy
> *phy) isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
>  }
> 
> -static int csiphy_config(struct isp_csiphy *phy,
> -			 struct isp_csiphy_dphy_cfg *dphy,
> -			 struct isp_csiphy_lanes_cfg *lanes)
> +/*
> + * TCLK values are OK at their reset values
> + */
> +#define TCLK_TERM	0
> +#define TCLK_MISS	1
> +#define TCLK_SETTLE	14
> +
> +int omap3isp_csiphy_config(struct isp_device *isp,
> +			   struct v4l2_subdev *csi2_subdev,
> +			   struct v4l2_subdev *sensor,
> +			   struct v4l2_mbus_framefmt *sensor_fmt)
>  {
> +	struct isp_v4l2_subdevs_group *subdevs = sensor->host_priv;
> +	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(csi2_subdev);
> +	struct isp_csiphy_dphy_cfg csi2phy;
> +	int csi2_ddrclk_khz;
> +	struct isp_csiphy_lanes_cfg *lanes;
>  	unsigned int used_lanes = 0;
>  	unsigned int i;
> +	u32 cam_phy_ctrl;
> +
> +	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1
> +	    || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
> +		lanes = subdevs->bus.ccp2.lanecfg;
> +	else
> +		lanes = subdevs->bus.csi2.lanecfg;

Shouldn't lane configuration be retrieved from the sensor instead ? Sensors 
could use different lane configuration depending on the mode. This could also 
be implemented later when needed, but I don't think it would be too difficult 
to get it right now.

> +
> +	if (!lanes) {
> +		dev_err(isp->dev, "no lane configuration\n");
> +		return -EINVAL;
> +	}
> +
> +	cam_phy_ctrl = omap_readl(
> +		OMAP343X_CTRL_BASE + OMAP3630_CONTROL_CAMERA_PHY_CTRL);
> +	/*
> +	 * SCM.CONTROL_CAMERA_PHY_CTRL
> +	 * - bit[4]    : CSIPHY1 data sent to CSIB
> +	 * - bit [3:2] : CSIPHY1 config: 00 d-phy, 01/10 ccp2
> +	 * - bit [1:0] : CSIPHY2 config: 00 d-phy, 01/10 ccp2
> +	 */
> +	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1)
> +		cam_phy_ctrl |= 1 << 2;
> +	else if (subdevs->interface == ISP_INTERFACE_CSI2C_PHY1)
> +		cam_phy_ctrl &= 1 << 2;
> +
> +	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
> +		cam_phy_ctrl |= 1;
> +	else if (subdevs->interface == ISP_INTERFACE_CSI2A_PHY2)
> +		cam_phy_ctrl &= 1;
> +
> +	/* FIXME: Do 34xx / 35xx require something here? */
> +	if (cpu_is_omap3630())
> +		omap_writel(cam_phy_ctrl,
> +			    OMAP343X_CTRL_BASE
> +			    + OMAP3630_CONTROL_CAMERA_PHY_CTRL);

You use cam_phy_ctrl inside the if statement only, you can move its 
computation there.

> +
> +	csi2_ddrclk_khz = sensor_fmt->pixelrate
> +		/ (2 * csi2->phy->num_data_lanes)
> +		* omap3isp_video_format_info(sensor_fmt->code)->bpp;
> +
> +	/*
> +	 * THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1.
> +	 * THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3.
> +	 */
> +	csi2phy.ths_term = DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1;
> +	csi2phy.ths_settle = DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3;
> +	csi2phy.tclk_term = TCLK_TERM;
> +	csi2phy.tclk_miss = TCLK_MISS;
> +	csi2phy.tclk_settle = TCLK_SETTLE;
> 
>  	/* Clock and data lanes verification */
> -	for (i = 0; i < phy->num_data_lanes; i++) {
> +	for (i = 0; i < csi2->phy->num_data_lanes; i++) {
>  		if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
>  			return -EINVAL;
> 
> @@ -162,10 +227,10 @@ static int csiphy_config(struct isp_csiphy *phy,
>  	if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
>  		return -EINVAL;
> 
> -	mutex_lock(&phy->mutex);
> -	phy->dphy = *dphy;
> -	phy->lanes = *lanes;
> -	mutex_unlock(&phy->mutex);
> +	mutex_lock(&csi2->phy->mutex);
> +	csi2->phy->dphy = csi2phy;
> +	csi2->phy->lanes = *lanes;
> +	mutex_unlock(&csi2->phy->mutex);
> 
>  	return 0;
>  }
> @@ -225,8 +290,6 @@ int omap3isp_csiphy_init(struct isp_device *isp)
>  	struct isp_csiphy *phy1 = &isp->isp_csiphy1;
>  	struct isp_csiphy *phy2 = &isp->isp_csiphy2;
> 
> -	isp->platform_cb.csiphy_config = csiphy_config;
> -
>  	phy2->isp = isp;
>  	phy2->csi2 = &isp->isp_csi2a;
>  	phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES;
> diff --git a/drivers/media/video/omap3isp/ispcsiphy.h
> b/drivers/media/video/omap3isp/ispcsiphy.h index e93a661..9f93222 100644
> --- a/drivers/media/video/omap3isp/ispcsiphy.h
> +++ b/drivers/media/video/omap3isp/ispcsiphy.h
> @@ -56,6 +56,10 @@ struct isp_csiphy {
>  	struct isp_csiphy_dphy_cfg dphy;
>  };
> 
> +int omap3isp_csiphy_config(struct isp_device *isp,
> +			   struct v4l2_subdev *csi2_subdev,
> +			   struct v4l2_subdev *sensor,
> +			   struct v4l2_mbus_framefmt *fmt);
>  int omap3isp_csiphy_acquire(struct isp_csiphy *phy);
>  void omap3isp_csiphy_release(struct isp_csiphy *phy);
>  int omap3isp_csiphy_init(struct isp_device *isp);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 12/17] omap3isp: Add lane configuration to platform data
  2011-12-20 20:28 ` [RFC 12/17] omap3isp: Add lane configuration to platform data Sakari Ailus
@ 2012-01-06 10:06   ` Laurent Pinchart
  2012-01-07 23:39     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-06 10:06 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:28:04 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Add lane configuration (order of clock and data lane) to platform data on
> both CCP2 and CSI-2.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  drivers/media/video/omap3isp/ispcsiphy.h |   15 ++-------------
>  include/media/omap3isp.h                 |   15 +++++++++++++++
>  2 files changed, 17 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/media/video/omap3isp/ispcsiphy.h
> b/drivers/media/video/omap3isp/ispcsiphy.h index 9596dc6..e93a661 100644
> --- a/drivers/media/video/omap3isp/ispcsiphy.h
> +++ b/drivers/media/video/omap3isp/ispcsiphy.h
> @@ -27,22 +27,11 @@
>  #ifndef OMAP3_ISP_CSI_PHY_H
>  #define OMAP3_ISP_CSI_PHY_H
> 
> +#include <media/omap3isp.h>
> +
>  struct isp_csi2_device;
>  struct regulator;
> 
> -struct csiphy_lane {
> -	u8 pos;
> -	u8 pol;
> -};
> -
> -#define ISP_CSIPHY2_NUM_DATA_LANES	2
> -#define ISP_CSIPHY1_NUM_DATA_LANES	1
> -
> -struct isp_csiphy_lanes_cfg {
> -	struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
> -	struct csiphy_lane clk;
> -};
> -
>  struct isp_csiphy_dphy_cfg {
>  	u8 ths_term;
>  	u8 ths_settle;
> diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
> index e917b1d..8fe0bdf 100644
> --- a/include/media/omap3isp.h
> +++ b/include/media/omap3isp.h
> @@ -86,6 +86,19 @@ enum {
>  	ISP_CCP2_MODE_CCP2 = 1,
>  };
> 
> +struct csiphy_lane {
> +	u8 pos;
> +	u8 pol;
> +};
> +
> +#define ISP_CSIPHY2_NUM_DATA_LANES	2
> +#define ISP_CSIPHY1_NUM_DATA_LANES	1
> +
> +struct isp_csiphy_lanes_cfg {
> +	struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
> +	struct csiphy_lane clk;
> +};

Could you please document the two structures using kerneldoc ?

> +
>  /**
>   * struct isp_ccp2_platform_data - CCP2 interface platform data
>   * @strobe_clk_pol: Strobe/clock polarity
> @@ -105,6 +118,7 @@ struct isp_ccp2_platform_data {
>  	unsigned int ccp2_mode:1;
>  	unsigned int phy_layer:1;
>  	unsigned int vpclk_div:2;
> +	struct isp_csiphy_lanes_cfg *lanecfg;

Lane configuration is mandatory, what about embedding struct 
isp_csiphy_lanes_cfg inside struct isp_ccp2_platform instead of having a 
pointer ?

>  };
> 
>  /**
> @@ -115,6 +129,7 @@ struct isp_ccp2_platform_data {
>  struct isp_csi2_platform_data {
>  	unsigned crc:1;
>  	unsigned vpclk_div:2;
> +	struct isp_csiphy_lanes_cfg *lanecfg;

Same here.

>  };
> 
>  struct isp_subdev_i2c_board_info {

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 02/17] v4l: Document integer menu controls
  2012-01-05 15:55   ` Laurent Pinchart
@ 2012-01-06 10:07     ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-06 10:07 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thanks for the patch.
> 
> On Tuesday 20 December 2011 21:27:54 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>> ---
>>  Documentation/DocBook/media/v4l/compat.xml         |   10 +++++
>>  Documentation/DocBook/media/v4l/v4l2.xml           |    7 ++++
>>  .../DocBook/media/v4l/vidioc-queryctrl.xml         |   39
>> +++++++++++++++++++- 3 files changed, 54 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/DocBook/media/v4l/compat.xml
>> b/Documentation/DocBook/media/v4l/compat.xml index b68698f..569efd1 100644
>> --- a/Documentation/DocBook/media/v4l/compat.xml
>> +++ b/Documentation/DocBook/media/v4l/compat.xml
>> @@ -2379,6 +2379,16 @@ that used it. It was originally scheduled for
>> removal in 2.6.35. </orderedlist>
>>      </section>
>>
>> +    <section>
>> +      <title>V4L2 in Linux 3.3</title>
> 
> Seems it will be for 3.4 :-) Same for Documentation/DocBook/media/v4l/v4l2.xml

Right. I'll make the change for now but I don't of course mind if we get
this to 3.3 already. However, if we want a driver using this go in at
the same time, the smia++ driver for almost certain is not going to be
3.3 since it depends on a large set of other patches.

Regards,

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 14/17] omap3isp: Use pixelrate from sensor media bus frameformat
  2011-12-20 20:28 ` [RFC 14/17] omap3isp: Use pixelrate from sensor media bus frameformat Sakari Ailus
@ 2012-01-06 10:14   ` Laurent Pinchart
  2012-01-07 23:05     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-06 10:14 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:28:06 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Configure the ISP based on the pixelrate in media bus frame format.
> Previously the same was configured from the board code.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  drivers/media/video/omap3isp/isp.c |   24 +++++++++++++++++++++---
>  drivers/media/video/omap3isp/isp.h |    1 -
>  2 files changed, 21 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/video/omap3isp/isp.c
> b/drivers/media/video/omap3isp/isp.c index 6020fd7..92f9716 100644
> --- a/drivers/media/video/omap3isp/isp.c
> +++ b/drivers/media/video/omap3isp/isp.c
> @@ -749,10 +749,14 @@ static int isp_pipeline_enable(struct isp_pipeline
> *pipe,
> 
>  	entity = &pipe->output->video.entity;
>  	while (1) {
> -		pad = &entity->pads[0];
> -		if (!(pad->flags & MEDIA_PAD_FL_SINK))
> +		/*
> +		 * Is this an external subdev connected to us? If so,
> +		 * we're done.
> +		 */
> +		if (subdev && subdev->host_priv)
>  			break;

This doesn't seem to be related to the patch title. Should it be moved to a 
separate patch ? You could also move the check to the bottom of the while 
loop, it would allow you to remove the first part of the condition as subdev 
will always be non-NULL then (or even possible as the while() condition).

> +		pad = &entity->pads[0];
>  		pad = media_entity_remote_source(pad);
>  		if (pad == NULL ||
>  		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
> @@ -762,6 +766,21 @@ static int isp_pipeline_enable(struct isp_pipeline
> *pipe, prev_subdev = subdev;
>  		subdev = media_entity_to_v4l2_subdev(entity);
> 
> +		/* Configure CCDC pixel clock */
> +		if (subdev->host_priv) {
> +			struct v4l2_subdev_format fmt;
> +
> +			fmt.pad = pad->index;
> +			fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +			ret = v4l2_subdev_call(subdev, pad, get_fmt,
> +					       NULL, &fmt);
> +			if (ret < 0)
> +				return -EINVAL;
> +
> +			isp_set_pixel_clock(isp,
> +					    fmt.format.pixelrate * 1000);
> +		}
> +
>  		/* Configure CSI-2 receiver based on sensor format. */
>  		if (prev_subdev == &isp->isp_csi2a.subdev
> 
>  		    || prev_subdev == &isp->isp_csi2c.subdev) {
> 
> @@ -2102,7 +2121,6 @@ static int isp_probe(struct platform_device *pdev)
> 
>  	isp->autoidle = autoidle;
>  	isp->platform_cb.set_xclk = isp_set_xclk;
> -	isp->platform_cb.set_pixel_clock = isp_set_pixel_clock;
> 
>  	mutex_init(&isp->isp_mutex);
>  	spin_lock_init(&isp->stat_lock);
> diff --git a/drivers/media/video/omap3isp/isp.h
> b/drivers/media/video/omap3isp/isp.h index c5935ae..7d73a39 100644
> --- a/drivers/media/video/omap3isp/isp.h
> +++ b/drivers/media/video/omap3isp/isp.h
> @@ -126,7 +126,6 @@ struct isp_reg {
> 
>  struct isp_platform_callback {
>  	u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
> -	void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
>  };
> 
>  /*

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 03/17] vivi: Add an integer menu test control
  2012-01-05 15:59   ` Laurent Pinchart
@ 2012-01-06 10:19     ` Sakari Ailus
  2012-01-06 10:22       ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-06 10:19 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thanks for the patch.

Thanks for the review!

> On Tuesday 20 December 2011 21:27:55 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Add an integer menu test control for the vivi driver.
>>
>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>> ---
>>  drivers/media/video/vivi.c |   21 +++++++++++++++++++++
>>  1 files changed, 21 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
>> index 7d754fb..763ec23 100644
>> --- a/drivers/media/video/vivi.c
>> +++ b/drivers/media/video/vivi.c
>> @@ -177,6 +177,7 @@ struct vivi_dev {
>>  	struct v4l2_ctrl	   *menu;
>>  	struct v4l2_ctrl	   *string;
>>  	struct v4l2_ctrl	   *bitmask;
>> +	struct v4l2_ctrl	   *int_menu;
>>
>>  	spinlock_t                 slock;
>>  	struct mutex		   mutex;
>> @@ -503,6 +504,10 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct
>> vivi_buffer *buf) dev->boolean->cur.val,
>>  			dev->menu->qmenu[dev->menu->cur.val],
>>  			dev->string->cur.string);
>> +	snprintf(str, sizeof(str), " integer_menu %s, value %lld ",
>> +			dev->int_menu->qmenu[dev->int_menu->cur.val],
> 
> Shouldn't you print the content of qmenu_int as a 64-bit integer instead ?

Oh, yes; I should. Also the value would be wrong, as well as the menu
item array --- should be the int one.

>> +			dev->int64->cur.val64);
> 
> Shouldn't this be dev->int_menu->cur.val ?
> 
>> +	gen_text(dev, vbuf, line++ * 16, 16, str);
>>  	mutex_unlock(&dev->ctrl_handler.lock);
>>  	gen_text(dev, vbuf, line++ * 16, 16, str);
>>  	if (dev->button_pressed) {
>> @@ -1183,6 +1188,22 @@ static const struct v4l2_ctrl_config
>> vivi_ctrl_bitmask = { .step = 0,
>>  };
>>
>> +static const s64 * const vivi_ctrl_int_menu_values[] = {
>> +	1, 1, 2, 3, 5, 8, 13, 21, 42,
>> +};
>> +
>> +static const struct v4l2_ctrl_config vivi_ctrl_string = {
>> +	.ops = &vivi_ctrl_ops,
>> +	.id = VIDI_CID_CUSTOM_BASE + 7
>> +	.name = "Integer menu",
>> +	.type = V4L2_CTRL_TYPE_INTEGER_MENU,
>> +	.min = 1,
>> +	.max = 8,
> 
> There are 9 values in your vivi_ctrl_int_menu_values array. Is 8 on purpose 
> here ?

I put it there to limit the maximum to 8 instead of 9, but 9 would be
equally good. I'll change it.

>> +	.def = 4,
>> +	.menu_skip_mask = 0x02,
>> +	.qmenu_int = &vivi_ctrl_int_menu_values,
>> +};
>> +
>>  static const struct v4l2_file_operations vivi_fops = {
>>  	.owner		= THIS_MODULE,
>>  	.open           = v4l2_fh_open,
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 17/17] rm680: Add camera init
  2011-12-20 20:28 ` [RFC 17/17] rm680: Add camera init Sakari Ailus
@ 2012-01-06 10:21   ` Laurent Pinchart
  2012-01-07 21:30     ` Sakari Ailus
  2012-01-06 14:58   ` Sylwester Nawrocki
  1 sibling, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-06 10:21 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:28:09 Sakari Ailus wrote:
> This currently introduces an extra file to the arch/arm/mach-omap2
> directory: board-rm680-camera.c. Keeping the device tree in mind, the
> context of the file could be represented as static data with one exception:
> the external clock to the sensor.
> 
> This external clock is provided by the OMAP 3 SoC and required by the
> sensor. The issue is that the clock originates from the ISP and not from
> PRCM block as the other clocks and thus is not supported by the clock
> framework. Otherwise the sensor driver could just clk_get() and
> clk_enable() it, just like the regulators and gpios.

This will hopefully be fixable with the new generic clock struct. Have you had 
a look at it lately BTW ?

> Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
> ---
>  arch/arm/mach-omap2/Makefile             |    3 +-
>  arch/arm/mach-omap2/board-rm680-camera.c |  408
> ++++++++++++++++++++++++++++++ arch/arm/mach-omap2/board-rm680.c        | 
>  42 +++
>  3 files changed, 452 insertions(+), 1 deletions(-)
>  create mode 100644 arch/arm/mach-omap2/board-rm680-camera.c
> 
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index 69ab1c0..1444bc5 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -201,7 +201,8 @@ obj-$(CONFIG_MACH_OMAP3_PANDORA)	+=
> board-omap3pandora.o obj-$(CONFIG_MACH_OMAP_3430SDP)		+= board-3430sdp.o
>  obj-$(CONFIG_MACH_NOKIA_N8X0)		+= board-n8x0.o
>  obj-$(CONFIG_MACH_NOKIA_RM680)		+= board-rm680.o \
> -					   sdram-nokia.o
> +					   sdram-nokia.o \
> +					   board-rm680-camera.o
>  obj-$(CONFIG_MACH_NOKIA_RX51)		+= board-rx51.o \
>  					   sdram-nokia.o \
>  					   board-rx51-peripherals.o \
> diff --git a/arch/arm/mach-omap2/board-rm680-camera.c
> b/arch/arm/mach-omap2/board-rm680-camera.c new file mode 100644
> index 0000000..4cc1ced
> --- /dev/null
> +++ b/arch/arm/mach-omap2/board-rm680-camera.c
> @@ -0,0 +1,408 @@
> +/**
> + * arch/arm/mach-omap2/board-rm680-camera.c
> + *
> + * Copyright (C) 2010--2011 Nokia Corporation

2012 ? :-)

> + * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
> + *
> + * Based on board-rx71-camera.c by Vimarsh Zutshi

This one isn't upstream, I'm not sure if it's worth mentioning it.

> + * Based on board-rx51-camera.c by Sakari Ailus
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/mm.h>
> +#include <linux/platform_device.h>
> +#include <linux/videodev2.h>
> +
> +#include <linux/gpio.h>
> +#include <plat/omap-pm.h>
> +
> +#include "../../../drivers/media/video/omap3isp/isp.h"

What do we still miss in <media/omap3isp.h> ?

> +#include <media/omap3isp.h>
> +#include <media/smiapp.h>
> +#include <asm/mach-types.h>
> +
> +#include "../../../drivers/media/video/smiapp.h"

Time to create <media/smiapp.h> ?

> +
> +#include "devices.h"
> +
> +#define SEC_CAMERA_RESET_GPIO	97
> +
> +#define RM680_PRI_SENSOR	1
> +#define RM680_PRI_LENS		2
> +#define RM680_SEC_SENSOR	3
> +#define MAIN_CAMERA_XCLK	ISP_XCLK_A
> +#define SEC_CAMERA_XCLK		ISP_XCLK_B
> +
> +/*
> + *
> + * HW initialization
> + *
> + *
> + */
> +static int __init rm680_sec_camera_init(void)
> +{
> +	if (gpio_request(SEC_CAMERA_RESET_GPIO, "sec_camera reset") != 0) {
> +		printk(KERN_INFO "%s: unable to acquire secondary "
> +		       "camera reset gpio\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	/* XSHUTDOWN off, reset  */
> +	gpio_direction_output(SEC_CAMERA_RESET_GPIO, 0);
> +	gpio_set_value(SEC_CAMERA_RESET_GPIO, 0);

gpio_request_one() would be helpful here (and possibly in other locations in 
this file).

> +
> +	return 0;
> +}
> +
> +static int __init rm680_camera_hw_init(void)
> +{
> +	return rm680_sec_camera_init();

Maybe you could merge the two functions ?

> +}
> +
> +/*
> + *
> + * Main Camera Module EXTCLK
> + * Used by the sensor and the actuator driver.
> + *
> + */
> +static struct camera_xclk {
> +	u32 hz;
> +	u32 lock;
> +	u8 xclksel;
> +} cameras_xclk;
> +
> +static DEFINE_MUTEX(lock_xclk);
> +
> +static int rm680_update_xclk(struct v4l2_subdev *subdev, u32 hz, u32
> which, +			     u8 xclksel)
> +{
> +	struct isp_device *isp = v4l2_dev_to_isp_device(subdev->v4l2_dev);
> +	int ret;
> +
> +	mutex_lock(&lock_xclk);
> +
> +	if (which == RM680_SEC_SENSOR) {
> +		if (cameras_xclk.xclksel == MAIN_CAMERA_XCLK) {
> +			ret = -EBUSY;
> +			goto done;
> +		}
> +	} else {
> +		if (cameras_xclk.xclksel == SEC_CAMERA_XCLK) {
> +			ret = -EBUSY;
> +			goto done;
> +		}
> +	}
> +
> +	if (hz) {	/* Turn on */
> +		cameras_xclk.lock |= which;
> +		if (cameras_xclk.hz == 0) {
> +			isp->platform_cb.set_xclk(isp, hz, xclksel);
> +			cameras_xclk.hz = hz;
> +			cameras_xclk.xclksel = xclksel;
> +		}
> +	} else {	/* Turn off */
> +		cameras_xclk.lock &= ~which;
> +		if (cameras_xclk.lock == 0) {
> +			isp->platform_cb.set_xclk(isp, 0, xclksel);
> +			cameras_xclk.hz = 0;
> +			cameras_xclk.xclksel = 0;
> +		}
> +	}
> +
> +	ret = cameras_xclk.hz;
> +
> +done:
> +	mutex_unlock(&lock_xclk);
> +	return ret;
> +}
> +
> +/*
> + *
> + * Main Camera Sensor
> + *
> + */
> +
> +static struct isp_csiphy_lanes_cfg rm696_main_camera_csi2_lanecfg = {
> +	.clk = {
> +		.pol = 1,
> +		.pos = 2,
> +	},
> +	.data[0] = {
> +		.pol = 1,
> +		.pos = 1,
> +	},
> +	.data[1] = {
> +		.pol = 1,
> +		.pos = 3,
> +	},
> +};
> +
> +static struct isp_csiphy_lanes_cfg rm680_main_camera_csi2_lanecfg = {
> +	.clk = {
> +		.pol = 1,
> +		.pos = 2,
> +	},
> +	.data[0] = {
> +		.pol = 1,
> +		.pos = 3,
> +	},
> +	.data[1] = {
> +		.pol = 1,
> +		.pos = 1,
> +	},
> +};
> +
> +static int rm680_main_camera_set_xclk(struct v4l2_subdev *sd, int hz)
> +{
> +	return rm680_update_xclk(sd, hz, RM680_PRI_SENSOR, MAIN_CAMERA_XCLK);
> +}
> +
> +static struct smiapp_flash_strobe_parms rm680_main_camera_strobe_setup = {
> +	.mode			= 0x0c,
> +	.strobe_width_high_us	= 100000,
> +	.strobe_delay		= 0,
> +	.stobe_start_point	= 0,
> +	.trigger		= 0,
> +};
> +
> +static struct smiapp_platform_data rm696_main_camera_platform_data = {
> +	.i2c_addr_dfl		= SMIAPP_DFL_I2C_ADDR,
> +	.i2c_addr_alt		= SMIAPP_ALT_I2C_ADDR,
> +	.nvm_size		= 16 * 64,
> +	.ext_clk		= (9.6 * 1000 * 1000),
> +	.lanes			= 2,
> +	.op_sys_clock		= (s64 []){ 796800 / 2, 840000 / 2,
> +					    1996800 / 2, 0 },
> +	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CSI2,
> +	.strobe_setup		= &rm680_main_camera_strobe_setup,
> +	.set_xclk		= rm680_main_camera_set_xclk,
> +};
> +
> +static struct smiapp_platform_data rm680_main_camera_platform_data = {
> +	.i2c_addr_dfl		= SMIAPP_DFL_I2C_ADDR,
> +	.i2c_addr_alt		= SMIAPP_ALT_I2C_ADDR,
> +	.nvm_size		= 16 * 64,
> +	.ext_clk		= (9.6 * 1000 * 1000),
> +	.lanes			= 2,
> +	.op_sys_clock		= (s64 []){ 840000 / 2, 1334400 / 2,
> +					    1593600 / 2, 0 },
> +	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CSI2,
> +	.module_board_orient	= SMIAPP_MODULE_BOARD_ORIENT_180,
> +	.strobe_setup		= &rm680_main_camera_strobe_setup,
> +	.set_xclk		= rm680_main_camera_set_xclk,
> +};
> +
> +/*
> + *
> + * SECONDARY CAMERA Sensor
> + *
> + */
> +
> +#define SEC_CAMERA_XCLK		ISP_XCLK_B
> +
> +static struct isp_csiphy_lanes_cfg rm680_sec_camera_csiphy_lanecfg = {
> +	.clk = {
> +		.pol = 0,
> +		.pos = 1,
> +	},
> +	.data[0] = {
> +		.pol = 0,
> +		.pos = 2,
> +	},
> +};
> +
> +static int rm680_sec_camera_set_xclk(struct v4l2_subdev *sd, int hz)
> +{
> +	return rm680_update_xclk(sd, hz, RM680_SEC_SENSOR, SEC_CAMERA_XCLK);
> +}
> +
> +static int rm680_sec_camera_set_xshutdown(struct v4l2_subdev *subdev, u8
> set) +{
> +	gpio_set_value(SEC_CAMERA_RESET_GPIO, !!set);
> +	return 0;
> +}
> +
> +static struct smiapp_platform_data rm696_sec_camera_platform_data = {
> +	.ext_clk		= (10.8 * 1000 * 1000),
> +	.lanes			= 1,
> +	.op_sys_clock		= (s64 []){ 13770 * 10, 0 },
> +	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK,
> +	.module_board_orient	= SMIAPP_MODULE_BOARD_ORIENT_180,
> +	.set_xclk		= rm680_sec_camera_set_xclk,
> +	.set_xshutdown		= rm680_sec_camera_set_xshutdown,
> +};
> +
> +static struct smiapp_platform_data rm680_sec_camera_platform_data = {
> +	.ext_clk		= (10.8 * 1000 * 1000),
> +	.lanes			= 1,
> +	.op_sys_clock		= (s64 []){ 11880 * 10, 0 },
> +	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK,
> +	.set_xclk		= rm680_sec_camera_set_xclk,
> +	.set_xshutdown		= rm680_sec_camera_set_xshutdown,

What about passing the GPIO number to the smiapp driver instead of using a 
callback function ?

> +};
> +
> +/*
> + *
> + * Init all the modules
> + *
> + */
> +
> +#define CAMERA_I2C_BUS_NUM		2
> +#define AD5836_I2C_BUS_NUM		2
> +#define AS3645A_I2C_BUS_NUM		2
> +
> +static struct i2c_board_info rm696_camera_i2c_devices[] = {
> +	{
> +		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_ALT_I2C_ADDR),
> +		.platform_data = &rm696_main_camera_platform_data,
> +	},
> +	{
> +		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_DFL_I2C_ADDR),
> +		.platform_data = &rm696_sec_camera_platform_data,
> +	},
> +};
> +
> +static struct i2c_board_info rm680_camera_i2c_devices[] = {
> +	{
> +		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_ALT_I2C_ADDR),
> +		.platform_data = &rm680_main_camera_platform_data,
> +	},
> +	{
> +		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_DFL_I2C_ADDR),
> +		.platform_data = &rm680_sec_camera_platform_data,
> +	},
> +};
> +
> +static struct isp_subdev_i2c_board_info rm696_camera_primary_subdevs[] = {
> +	{
> +		.board_info = &rm696_camera_i2c_devices[0],
> +		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
> +	},
> +	{ NULL, 0, },
> +};
> +
> +static struct isp_subdev_i2c_board_info rm696_camera_secondary_subdevs[] =
> { +	{
> +		.board_info = &rm696_camera_i2c_devices[1],
> +		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
> +	},
> +	{ NULL, 0, },
> +};
> +
> +static struct isp_subdev_i2c_board_info rm680_camera_primary_subdevs[] = {
> +	{
> +		.board_info = &rm680_camera_i2c_devices[0],
> +		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
> +	},
> +	{ NULL, 0, },
> +};
> +
> +static struct isp_subdev_i2c_board_info rm680_camera_secondary_subdevs[] =
> { +	{
> +		.board_info = &rm680_camera_i2c_devices[1],
> +		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
> +	},
> +	{ NULL, 0, },
> +};
> +
> +static struct isp_v4l2_subdevs_group rm696_camera_subdevs[] = {
> +	{
> +		.subdevs = rm696_camera_primary_subdevs,
> +		.interface = ISP_INTERFACE_CSI2A_PHY2,
> +		.bus = { .csi2 = {
> +			.crc		= 1,
> +			.vpclk_div	= 1,
> +			.lanecfg	= &rm696_main_camera_csi2_lanecfg,
> +		} },
> +	},
> +	{
> +		.subdevs = rm696_camera_secondary_subdevs,
> +		.interface = ISP_INTERFACE_CCP2B_PHY1,
> +		.bus = { .ccp2 = {
> +			.strobe_clk_pol	= 0,
> +			.crc		= 0,
> +			.ccp2_mode	= 0,
> +			.phy_layer	= 0,
> +			.vpclk_div	= 2,
> +			.lanecfg	= &rm680_sec_camera_csiphy_lanecfg,
> +		} },
> +	},
> +	{ NULL, 0, },
> +};
> +
> +static struct isp_v4l2_subdevs_group rm680_camera_subdevs[] = {
> +	{
> +		.subdevs = rm680_camera_primary_subdevs,
> +		.interface = ISP_INTERFACE_CSI2A_PHY2,
> +		.bus = { .csi2 = {
> +			.crc		= 1,
> +			.vpclk_div	= 1,
> +			.lanecfg	= &rm680_main_camera_csi2_lanecfg,
> +		} },
> +	},
> +	{
> +		.subdevs = rm680_camera_secondary_subdevs,
> +		.interface = ISP_INTERFACE_CCP2B_PHY1,
> +		.bus = { .ccp2 = {
> +			.strobe_clk_pol	= 0,
> +			.crc		= 0,
> +			.ccp2_mode	= 0,
> +			.phy_layer	= 0,
> +			.vpclk_div	= 2,
> +			.lanecfg	= &rm680_sec_camera_csiphy_lanecfg,
> +		} },
> +	},
> +	{ NULL, 0, },
> +};
> +
> +static struct isp_platform_data rm696_isp_platform_data = {
> +	.subdevs = rm696_camera_subdevs,
> +};
> +
> +static struct isp_platform_data rm680_isp_platform_data = {
> +	.subdevs = rm680_camera_subdevs,
> +};
> +
> +static inline int board_is_rm680(void)
> +{
> +	return (system_rev & 0x00f0) == 0x0020;
> +}
> +
> +void __init rm680_camera_init(void)
> +{
> +	struct isp_platform_data *pdata;
> +	int rval;
> +
> +	rval = rm680_camera_hw_init();
> +	if (rval) {
> +		printk(KERN_WARNING "%s: unable to initialise camera\n",
> +		       __func__);
> +		return;
> +	}
> +
> +	if (board_is_rm680())
> +		pdata = &rm680_isp_platform_data;
> +	else
> +		pdata = &rm696_isp_platform_data;
> +
> +	if (omap3_init_camera(pdata) < 0)
> +		printk(KERN_WARNING
> +		       "%s: unable to register camera platform device\n",
> +		       __func__);
> +}
> diff --git a/arch/arm/mach-omap2/board-rm680.c
> b/arch/arm/mach-omap2/board-rm680.c index a5bcc75..a1e33d4 100644
> --- a/arch/arm/mach-omap2/board-rm680.c
> +++ b/arch/arm/mach-omap2/board-rm680.c
> @@ -66,6 +66,43 @@ static struct platform_device rm680_vemmc_device = {
>  	},
>  };
> 
> +#define REGULATOR_INIT_DATA(_name, _min, _max, _apply, _ops_mask) \
> +	static struct regulator_init_data _name##_data = { \
> +		.constraints = { \
> +			.name                   = #_name, \
> +			.min_uV                 = _min, \
> +			.max_uV                 = _max, \
> +			.apply_uV               = _apply, \
> +			.valid_modes_mask       = REGULATOR_MODE_NORMAL | \
> +						REGULATOR_MODE_STANDBY, \
> +			.valid_ops_mask         = _ops_mask, \
> +		}, \
> +		.num_consumer_supplies  = ARRAY_SIZE(_name##_consumers), \
> +		.consumer_supplies      = _name##_consumers, \
> +}
> +#define REGULATOR_INIT_DATA_FIXED(_name, _voltage) \
> +	REGULATOR_INIT_DATA(_name, _voltage, _voltage, true, \
> +				REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE)
> +
> +static struct regulator_consumer_supply rm680_vaux2_consumers[] = {
> +	REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"),	/* OMAP ISP */
> +	REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"),	/* OMAP ISP */
> +	{
> +		.supply		= "vaux2",
> +	},
> +};
> +REGULATOR_INIT_DATA_FIXED(rm680_vaux2, 1800000);
> +
> +static struct regulator_consumer_supply rm680_vaux3_consumers[] = {
> +	REGULATOR_SUPPLY("VANA", "2-0037"),	/* Main Camera Sensor */
> +	REGULATOR_SUPPLY("VANA", "2-000e"),	/* Main Camera Lens */

The lens driver isn't upstream yet. We could keep the regulator supply 
definition to avoid forgetting it later though.

> +	REGULATOR_SUPPLY("VANA", "2-0010"),	/* Front Camera */
> +	{
> +		.supply		= "vaux3",
> +	},
> +};
> +REGULATOR_INIT_DATA_FIXED(rm680_vaux3, 2800000);
> +
>  static struct platform_device *rm680_peripherals_devices[] __initdata = {
>  	&rm680_vemmc_device,
>  };
> @@ -82,6 +119,8 @@ static struct twl4030_gpio_platform_data rm680_gpio_data
> = { static struct twl4030_platform_data rm680_twl_data = {
>  	.gpio			= &rm680_gpio_data,
>  	/* add rest of the children here */
> +	.vaux2			= &rm680_vaux2_data,
> +	.vaux3			= &rm680_vaux3_data,
>  };
> 
>  static void __init rm680_i2c_init(void)
> @@ -129,6 +168,8 @@ static struct omap_board_mux board_mux[] __initdata = {
>  };
>  #endif
> 
> +void rm680_camera_init(void);
> +
>  static void __init rm680_init(void)
>  {
>  	struct omap_sdrc_params *sdrc_params;
> @@ -141,6 +182,7 @@ static void __init rm680_init(void)
> 
>  	usb_musb_init(NULL);
>  	rm680_peripherals_init();
> +	rm680_camera_init();
>  }
> 
>  MACHINE_START(NOKIA_RM680, "Nokia RM-680 board")

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 03/17] vivi: Add an integer menu test control
  2012-01-06 10:19     ` Sakari Ailus
@ 2012-01-06 10:22       ` Sakari Ailus
  2012-01-06 10:28         ` Laurent Pinchart
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-06 10:22 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Sakari Ailus wrote:
...
> I put it there to limit the maximum to 8 instead of 9, but 9 would be
> equally good. I'll change it.

Or not. 8 is still the index of the last value. min is one  to start the
menu from the second item. Would you like that to be changed to zero?

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 07/17] v4l: Add pixelrate to struct v4l2_mbus_framefmt
  2011-12-20 20:27 ` [RFC 07/17] v4l: Add pixelrate to struct v4l2_mbus_framefmt Sakari Ailus
@ 2012-01-06 10:26   ` Laurent Pinchart
  2012-01-08 21:16     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-06 10:26 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:27:59 Sakari Ailus wrote:
> From: Sakari Ailus <sakari.ailus@iki.fi>
> 
> Pixelrate is an essential part of the image data parameters. Add this.
> Together, the current parameters also define the frame rate.
> 
> Sensors do not have a concept of frame rate; pixelrate is much more
> meaningful in this context. Also, it is best to combine the pixelrate with
> the other format parameters since there are dependencies between them.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> ---
>  Documentation/DocBook/media/v4l/subdev-formats.xml |   10 +++++++++-
>  include/linux/v4l2-mediabus.h                      |    4 +++-
>  2 files changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml
> b/Documentation/DocBook/media/v4l/subdev-formats.xml index
> 49c532e..a6a6630 100644
> --- a/Documentation/DocBook/media/v4l/subdev-formats.xml
> +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml
> @@ -35,7 +35,15 @@
>  	</row>
>  	<row>
>  	  <entry>__u32</entry>
> -	  <entry><structfield>reserved</structfield>[7]</entry>
> +	  <entry><structfield>pixelrate</structfield></entry>
> +	  <entry>Pixel rate in kp/s.

kPix/s or kPixel/s ?

> This clock is the maximum rate at

Is it really a clock ?

> +	  which pixels are transferred on the bus. The
> +	  <structfield>pixelrate</structfield> field is
> +	  read-only.</entry>

Does that mean that userspace isn't required to propagate the value down the 
pipeline when configuring it ? I'm fine with that, but it should probably be 
documented explictly somewhere to make sure that drivers don't rely on it.

> +	</row>
> +	<row>
> +	  <entry>__u32</entry>
> +	  <entry><structfield>reserved</structfield>[6]</entry>
>  	  <entry>Reserved for future extensions. Applications and drivers must
>  	  set the array to zero.</entry>
>  	</row>
> diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
> index 5ea7f75..35c6b96 100644
> --- a/include/linux/v4l2-mediabus.h
> +++ b/include/linux/v4l2-mediabus.h
> @@ -101,6 +101,7 @@ enum v4l2_mbus_pixelcode {
>   * @code:	data format code (from enum v4l2_mbus_pixelcode)
>   * @field:	used interlacing type (from enum v4l2_field)
>   * @colorspace:	colorspace of the data (from enum v4l2_colorspace)
> + * @pixel_clock: pixel clock, in kHz

I think you forgot to update the comment.

>   */
>  struct v4l2_mbus_framefmt {
>  	__u32			width;
> @@ -108,7 +109,8 @@ struct v4l2_mbus_framefmt {
>  	__u32			code;
>  	__u32			field;
>  	__u32			colorspace;
> -	__u32			reserved[7];
> +	__u32			pixelrate;
> +	__u32			reserved[6];
>  };
> 
>  #endif

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 03/17] vivi: Add an integer menu test control
  2012-01-06 10:22       ` Sakari Ailus
@ 2012-01-06 10:28         ` Laurent Pinchart
  0 siblings, 0 replies; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-06 10:28 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

On Friday 06 January 2012 11:22:00 Sakari Ailus wrote:
> Sakari Ailus wrote:
> ...
> 
> > I put it there to limit the maximum to 8 instead of 9, but 9 would be
> > equally good. I'll change it.
> 
> Or not. 8 is still the index of the last value. min is one  to start the
> menu from the second item. Would you like that to be changed to zero?

If it was done on purpose I'm fine with it. I was just pointing it out in case 
it was done by mistake.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs
  2012-01-05 16:12   ` Laurent Pinchart
@ 2012-01-06 11:27     ` Sakari Ailus
  2012-01-06 12:00       ` Laurent Pinchart
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-06 11:27 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Thanks for the comments!

Laurent Pinchart wrote:
> On Tuesday 20 December 2011 21:27:56 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Add support for VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION
>> IOCTLs. They replace functionality provided by VIDIOC_SUBDEV_S_CROP and
>> VIDIOC_SUBDEV_G_CROP IOCTLs and also add new functionality (composing).
>>
>> VIDIOC_SUBDEV_G_CROP and VIDIOC_SUBDEV_S_CROP continue to be supported.
> 
> As those ioctls are experimental, should we deprecate them ?

I'm also in favour of doing that. But I'll make it a separate patch.

>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>> ---
>>  drivers/media/video/v4l2-subdev.c |   26 ++++++++++++++++++++-
>>  include/linux/v4l2-subdev.h       |   45 ++++++++++++++++++++++++++++++++++
>>  include/media/v4l2-subdev.h       |    5 ++++
>>  3 files changed, 75 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/media/video/v4l2-subdev.c
>> b/drivers/media/video/v4l2-subdev.c index 65ade5f..e8ae098 100644
>> --- a/drivers/media/video/v4l2-subdev.c
>> +++ b/drivers/media/video/v4l2-subdev.c
>> @@ -36,13 +36,17 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh,
>> struct v4l2_subdev *sd) {
>>  #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
>>  	/* Allocate try format and crop in the same memory block */
>> -	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
>> +	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop)
>> +			       + sizeof(*fh->try_compose))
>>  			      * sd->entity.num_pads, GFP_KERNEL);
> 
> Could you check how the 3 structures are aligned on 64-bit platforms ? I'm a 
> bit worried about the compiler expecting a 64-bit alignment for one of them, 
> and getting only a 32-bit alignment in the end.
> 
> What about using kcalloc ?

kcalloc won't make a difference --- see the implementation. Do you think
this is really an issue in practice?

If we want to ensure alignment I'd just allocate them separately. Or
create a struct out of them locally, and get the pointers from that
struct --- then the alignment would be the same as if those were part of
a single struct. That achieves the desired result and also keeps error
handling trivial.

I wouldn't want to start relying on the alignment based on the sizes of
these structures.

>>  	if (fh->try_fmt == NULL)
>>  		return -ENOMEM;
>>
>>  	fh->try_crop = (struct v4l2_rect *)
>>  		(fh->try_fmt + sd->entity.num_pads);
>> +
>> +	fh->try_compose = (struct v4l2_rect *)
>> +		(fh->try_crop + sd->entity.num_pads);
>>  #endif
>>  	return 0;
>>  }
>> @@ -281,6 +285,26 @@ static long subdev_do_ioctl(struct file *file,
>> unsigned int cmd, void *arg) return v4l2_subdev_call(sd, pad,
>> enum_frame_interval, subdev_fh, fie);
>>  	}
>> +
>> +	case VIDIOC_SUBDEV_G_SELECTION: {
>> +		struct v4l2_subdev_selection *sel = arg;
> 
> Shouldn't you check sel->which ?

Yes.

>> +		if (sel->pad >= sd->entity.num_pads)
>> +			return -EINVAL;
>> +
>> +		return v4l2_subdev_call(
>> +			sd, pad, get_selection, subdev_fh, sel);
>> +	}
>> +
>> +	case VIDIOC_SUBDEV_S_SELECTION: {
>> +		struct v4l2_subdev_selection *sel = arg;
> 
> And here too ?

Yes.

>> +		if (sel->pad >= sd->entity.num_pads)
>> +			return -EINVAL;
>> +
>> +		return v4l2_subdev_call(
>> +			sd, pad, set_selection, subdev_fh, sel);
>> +	}
>>  #endif
>>  	default:
>>  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
>> diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
>> index ed29cbb..d53d775 100644
>> --- a/include/linux/v4l2-subdev.h
>> +++ b/include/linux/v4l2-subdev.h
>> @@ -123,6 +123,47 @@ struct v4l2_subdev_frame_interval_enum {
>>  	__u32 reserved[9];
>>  };
>>
>> +#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE			(1 << 0)
>> +#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE			(1 << 1)
>> +#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG		(1 << 2)
>> +
>> +/* active cropping area */
>> +#define V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE			0
>> +/* default cropping area */
>> +#define V4L2_SUBDEV_SEL_TGT_CROP_DEFAULT		1
>> +/* cropping bounds */
>> +#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS			2
>> +/* current composing area */
>> +#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE		256
>> +/* default composing area */
>> +#define V4L2_SUBDEV_SEL_TGT_COMPOSE_DEFAULT		257
>> +/* composing bounds */
>> +#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS		258
>> +
>> +
>> +/**
>> + * struct v4l2_subdev_selection - selection info
>> + *
>> + * @which: either V4L2_SUBDEV_FORMAT_ACTIVE or V4L2_SUBDEV_FORMAT_TRY
>> + * @pad: pad number, as reported by the media API
>> + * @target: selection target, used to choose one of possible rectangles
>> + * @flags: constraints flags
>> + * @r: coordinates of selection window
>> + * @reserved: for future use, rounds structure size to 64 bytes, set to
>> zero + *
>> + * Hardware may use multiple helper window to process a video stream.
>> + * The structure is used to exchange this selection areas between
>> + * an application and a driver.
>> + */
>> +struct v4l2_subdev_selection {
>> +	__u32 which;
>> +	__u32 pad;
>> +	__u32 target;
>> +	__u32 flags;
>> +	struct v4l2_rect r;
>> +	__u32 reserved[8];
>> +};
>> +
>>  #define VIDIOC_SUBDEV_G_FMT	_IOWR('V',  4, struct v4l2_subdev_format)
>>  #define VIDIOC_SUBDEV_S_FMT	_IOWR('V',  5, struct v4l2_subdev_format)
>>  #define VIDIOC_SUBDEV_G_FRAME_INTERVAL \
>> @@ -137,5 +178,9 @@ struct v4l2_subdev_frame_interval_enum {
>>  			_IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)
>>  #define VIDIOC_SUBDEV_G_CROP	_IOWR('V', 59, struct v4l2_subdev_crop)
>>  #define VIDIOC_SUBDEV_S_CROP	_IOWR('V', 60, struct v4l2_subdev_crop)
>> +#define VIDIOC_SUBDEV_G_SELECTION \
>> +	_IOWR('V', 61, struct v4l2_subdev_selection)
>> +#define VIDIOC_SUBDEV_S_SELECTION \
>> +	_IOWR('V', 62, struct v4l2_subdev_selection)
>>
>>  #endif
>> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
>> index f0f3358..26eeaa4 100644
>> --- a/include/media/v4l2-subdev.h
>> +++ b/include/media/v4l2-subdev.h
>> @@ -466,6 +466,10 @@ struct v4l2_subdev_pad_ops {
>>  		       struct v4l2_subdev_crop *crop);
>>  	int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
>>  		       struct v4l2_subdev_crop *crop);
>> +	int (*get_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
>> +			     struct v4l2_subdev_selection *sel);
>> +	int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
>> +			     struct v4l2_subdev_selection *sel);
>>  };
>>
>>  struct v4l2_subdev_ops {
>> @@ -551,6 +555,7 @@ struct v4l2_subdev_fh {
>>  #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
>>  	struct v4l2_mbus_framefmt *try_fmt;
>>  	struct v4l2_rect *try_crop;
>> +	struct v4l2_rect *try_compose;
>>  #endif
>>  };
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 06/17] v4l: Add selections documentation.
  2011-12-20 20:27 ` [RFC 06/17] v4l: Add selections documentation Sakari Ailus
@ 2012-01-06 11:43   ` Laurent Pinchart
  2012-01-09 18:16     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-06 11:43 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

Thanks for the patch.

On Tuesday 20 December 2011 21:27:58 Sakari Ailus wrote:

[snip]

> diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml
> b/Documentation/DocBook/media/v4l/dev-subdev.xml index 0916a73..722db60
> 100644
> --- a/Documentation/DocBook/media/v4l/dev-subdev.xml
> +++ b/Documentation/DocBook/media/v4l/dev-subdev.xml

[snip]

> @@ -288,26 +288,81 @@

[snip]

> +      <para>Scaling operation changes the size of the image by scaling
> +      it to new dimensions. Some sub-devices support it. The scaled
> +      size (width and height) is represented by &v4l2-rect;. In the
> +      case of scaling, top and left will always be zero. Scaling is
> +      configured using &sub-subdev-g-selection; and
> +      <constant>V4L2_SUBDEV_SEL_COMPOSE_ACTIVE</constant> selection
> +      target on the sink pad of the subdev. The scaling is performed
> +      related to the width and height of the crop rectangle on the
> +      subdev's sink pad.</para>
> +
> +      <para>As for pad formats, drivers store try and active
> +      rectangles for the selection targets of ACTIVE type <xref
> +      linkend="v4l2-subdev-selection-targets">.</xref></para>
> +
> +      <para>On sink pads, cropping is applied relatively to the
> +      current pad format. The pad format represents the image size as
> +      received by the sub-device from the previous block in the
> +      pipeline, and the crop rectangle represents the sub-image that
> +      will be transmitted further inside the sub-device for
> +      processing.</para>
> +
> +      <para>On source pads, cropping is similar to sink pads, with the
> +      exception that the source size from which the cropping is
> +      performed, is the COMPOSE rectangle on the sink pad. In both
> +      sink and source pads, the crop rectangle must be entirely
> +      containted inside the source image size for the crop
> +      operation.</para>
> +
> +      <para>The drivers should always use the closest possible
> +      rectangle the user requests on all selection targets, unless
> +      specificly told otherwise<xref
> +      linkend="v4l2-subdev-selection-flags">.</xref></para>
> +    </section>

This sounds a bit confusing to me. One issue is that composing is not formally 
defined. I think it would help if you could draw a diagram that shows how the 
operations are applied, and modify the text to describe the diagram, using the 
natural order of the compose and crop operations on sink and source pads.

> +    <section>
> +      <title>Order of configuration and format propagation</title>
> +
> +      <para>The order of image processing steps will always be from
> +      the sink pad towards the source pad. This is also reflected in
> +      the order in which the configuration must be performed by the
> +      user. The format is propagated within the subdev along the later
> +      processing steps. For example, setting the sink pad format
> +      causes all the selection rectangles and the source pad format to
> +      be set to sink pad format --- if allowed by the hardware, and if
> +      not, then closest possible. The coordinates to a step always
> +      refer to the active size of the previous step.</para>

This also sounds a bit ambiguous if I try to ignore the fact that I know how 
it works :-) You should at least make it explicit that propagation inside 
subdevs is performed by the driver(s), and that propagation outside subdevs is 
to be handled by userspace.

> +      <orderedlist>
> +	<listitem>Sink pad format. The user configures the sink pad
> +	format. This format defines the parameters of the image the
> +	entity receives through the pad for further processing.</listitem>
> 
> -      <para>Cropping behaviour on output pads is not defined.</para>
> +	<listitem>Sink pad active crop selection. The sink pad crop
> +	defines the performed to the sink pad format.</listitem>
> 
> +	<listitem>Sink pad active compose selection. The sink pad compose
> +	rectangle defines the scaling ratio compared to the size of
> +	the sink pad crop rectangle.</listitem>
> +
> +	<listitem>Source pad active crop selection. Crop on the source
> +	pad defines crop performed to the image scaled according to
> +	the sink pad compose rectangle.</listitem>
> +
> +	<listitem>Source pad active compose selection. The source pad
> +	compose defines the size and location of the compose
> +	rectangle.</listitem>
> +
> +	<listitem>Source pad format. The source pad format defines the
> +	output pixel format of the subdev, as well as the other
> +	parameters with the exception of the image width and
> +	height.</listitem>
> +
> +      </orderedlist>
>      </section>
> +
>    </section>
> 
>    &sub-subdev-formats;

[snip]

> diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
> b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml new file
> mode 100644
> index 0000000..5fbcd65
> --- /dev/null
> +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
> @@ -0,0 +1,226 @@

[snip]

> +  <refsect1>
> +    <title>Description</title>
> +
> +    <note>
> +      <title>Experimental</title>
> +      <para>This is an <link linkend="experimental">experimental</link>
> +      interface and may change in the future.</para>
> +    </note>
> +
> +    <para>The selections are used to configure various image
> +    processing functionality performed by the subdevs which affect the
> +    image size. This currently includes cropping, scaling and
> +    composition.</para>
> +
> +    <para>The selections replace the crop API &sub-subdev-g-crop;. All
> +    the function of the crop API, and more, are supported by the
> +    selections API.</para>
> +
> +    <para>See <xref linkend="subdev">Sub-device interface</xref> for
> +    more information on how each selection target affects the image
> +    processing pipeline inside the subdevice.</para>
> +
> +    <section>
> +      <title>Types of selection targets</title>
> +
> +      <para>The are four types of selection targets: active, default,
> +      bounds and padding. The ACTIVE targets are the targets which
> +      configure the hardware. The DEFAULT target provides the default
> +      for the ACTIVE selection. The BOUNDS target will return the
> +      maximum width and height of the target.

What about the minimum ?

> The PADDED target
> +      provides the width and height for the padded image,

Is it valid for both crop and compose rectangles ?

> and is
> +      directly affected by the ACTIVE target. The PADDED targets may
> +      be configurable depending on the hardware.</para>

If that's configurable drivers will need a way to store it in the file handle.

> +    </section>
> +
> +    <table pgwide="1" frame="none" id="v4l2-subdev-selection-targets">
> +      <title>V4L2 subdev selection targets</title>
> +      <tgroup cols="3">
> +        &cs-def;
> +	<tbody valign="top">
> +	  <row>
> +	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE</constant></entry>
> +	    <entry>0</entry>
> +	    <entry>Active crop. Defines the cropping
> +	    performed by the processing step.</entry>
> +	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_DEFAULT</constant></entry>
> +	    <entry>1</entry>
> +	    <entry>Default crop rectangle.</entry>
> +	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS</constant></entry>
> +	    <entry>2</entry>
> +	    <entry>Bounds of the crop rectangle.</entry>
> +	  </row>
> +	  <row>
> +	   
> <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE</constant></entry> +	 
>   <entry>256</entry>
> +	    <entry>Active compose rectangle. Used to configure scaling
> +	    on sink pads and composition on source pads.</entry>
> +	  </row>
> +	  <row>
> +	   
> <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_DEFAULT</constant></entry> +	
>    <entry>257</entry>
> +	    <entry>Default compose rectangle.</entry>
> +	  </row>
> +	  <row>
> +	   
> <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS</constant></entry> +	 
>   <entry>258</entry>
> +	    <entry>Bounds of the compose rectangle.</entry>
> +	  </row>
> +	</tbody>
> +      </tgroup>
> +    </table>
> +
> +    <table pgwide="1" frame="none" id="v4l2-subdev-selection-flags">
> +      <title>V4L2 subdev selection flags</title>
> +      <tgroup cols="3">
> +        &cs-def;
> +	<tbody valign="top">
> +	  <row>
> +	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant></entry>
> +	    <entry>(1 &lt;&lt; 0)</entry>
> +	    <entry>Suggest the driver it should choose greater or
> +	    equal rectangle (in size) than was requested.</entry>
> +	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant></entry>
> +	    <entry>(1 &lt;&lt; 1)</entry>
> +	    <entry>Suggest the driver it should choose lesser or
> +	    equal rectangle (in size) than was requested.</entry>
> +	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant></entry>
> +	    <entry>(1 &lt;&lt; 2)</entry>
> +	    <entry>The configuration should not be propagated to any
> +	    further processing steps. If this flag is not given, the
> +	    configuration is propagated inside the subdevice to all
> +	    further processing steps.</entry>
> +	  </row>
> +	</tbody>
> +      </tgroup>
> +    </table>
> +
> +    <table pgwide="1" frame="none" id="v4l2-subdev-selection">
> +      <title>struct <structname>v4l2_subdev_selection</structname></title>
> +      <tgroup cols="3">
> +        &cs-str;
> +	<tbody valign="top">
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>which</structfield></entry>
> +	    <entry>Active or try selection, from
> +	    &v4l2-subdev-format-whence;.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>pad</structfield></entry>
> +	    <entry>Pad number as reported by the media framework.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>target</structfield></entry>
> +	    <entry>Target selection rectangle. See
> +	    <xref linkend="v4l2-subdev-selection-targets">.</xref>.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>flags</structfield></entry>
> +	    <entry>Flags. See
> +	    <xref linkend="v4l2-subdev-selection-flags">.</xref></entry>
> +	  </row>
> +	  <row>
> +	    <entry>&v4l2-rect;</entry>
> +	    <entry><structfield>rect</structfield></entry>
> +	    <entry>Crop rectangle boundaries, in pixels.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>reserved</structfield>[8]</entry>
> +	    <entry>Reserved for future extensions. Applications and drivers must
> +	    set the array to zero.</entry>
> +	  </row>
> +	</tbody>
> +      </tgroup>
> +    </table>
> +
> +  </refsect1>
> +
> +  <refsect1>
> +    &return-value;
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><errorcode>EBUSY</errorcode></term>
> +	<listitem>
> +	  <para>The selection rectangle can't be changed because the
> +	  pad is currently busy. This can be caused, for instance, by
> +	  an active video stream on the pad. The ioctl must not be
> +	  retried without performing another action to fix the problem
> +	  first. Only returned by
> +	  <constant>VIDIOC_SUBDEV_S_SELECTION</constant></para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><errorcode>EINVAL</errorcode></term>
> +	<listitem>
> +	  <para>The &v4l2-subdev-selection;
> +	  <structfield>pad</structfield> references a non-existing
> +	  pad, the <structfield>which</structfield> field references a
> +	  non-existing format, or the selection target is not
> +	  supported on the given subdev pad.</para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +</refentry>

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs
  2012-01-06 11:27     ` Sakari Ailus
@ 2012-01-06 12:00       ` Laurent Pinchart
  2012-01-07  9:09         ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-06 12:00 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

On Friday 06 January 2012 12:27:03 Sakari Ailus wrote:
> Laurent Pinchart wrote:
> > On Tuesday 20 December 2011 21:27:56 Sakari Ailus wrote:
> >> From: Sakari Ailus <sakari.ailus@iki.fi>
> >> 
> >> Add support for VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION
> >> IOCTLs. They replace functionality provided by VIDIOC_SUBDEV_S_CROP and
> >> VIDIOC_SUBDEV_G_CROP IOCTLs and also add new functionality (composing).
> >> 
> >> VIDIOC_SUBDEV_G_CROP and VIDIOC_SUBDEV_S_CROP continue to be supported.
> > 
> > As those ioctls are experimental, should we deprecate them ?
> 
> I'm also in favour of doing that. But I'll make it a separate patch.
> 
> >> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> >> ---
> >> 
> >>  drivers/media/video/v4l2-subdev.c |   26 ++++++++++++++++++++-
> >>  include/linux/v4l2-subdev.h       |   45
> >>  ++++++++++++++++++++++++++++++++++ include/media/v4l2-subdev.h       |
> >>     5 ++++
> >>  3 files changed, 75 insertions(+), 1 deletions(-)
> >> 
> >> diff --git a/drivers/media/video/v4l2-subdev.c
> >> b/drivers/media/video/v4l2-subdev.c index 65ade5f..e8ae098 100644
> >> --- a/drivers/media/video/v4l2-subdev.c
> >> +++ b/drivers/media/video/v4l2-subdev.c
> >> @@ -36,13 +36,17 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh,
> >> struct v4l2_subdev *sd) {
> >> 
> >>  #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
> >>  
> >>  	/* Allocate try format and crop in the same memory block */
> >> 
> >> -	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
> >> +	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop)
> >> +			       + sizeof(*fh->try_compose))
> >> 
> >>  			      * sd->entity.num_pads, GFP_KERNEL);
> > 
> > Could you check how the 3 structures are aligned on 64-bit platforms ?
> > I'm a bit worried about the compiler expecting a 64-bit alignment for
> > one of them, and getting only a 32-bit alignment in the end.
> > 
> > What about using kcalloc ?
> 
> kcalloc won't make a difference --- see the implementation. Do you think
> this is really an issue in practice?

It won't make a difference for the alignment, it's just that we allocate an 
array, so kcalloc seemed right.

> If we want to ensure alignment I'd just allocate them separately. Or
> create a struct out of them locally, and get the pointers from that
> struct --- then the alignment would be the same as if those were part of
> a single struct. That achieves the desired result and also keeps error
> handling trivial.
>
> I wouldn't want to start relying on the alignment based on the sizes of
> these structures.

Sounds good to me. Allocating them as part of a bigger structure internally 
could be more efficient than separate allocations, but I'm fine with both.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 17/17] rm680: Add camera init
  2011-12-20 20:28 ` [RFC 17/17] rm680: Add camera init Sakari Ailus
  2012-01-06 10:21   ` Laurent Pinchart
@ 2012-01-06 14:58   ` Sylwester Nawrocki
  2012-01-07 22:59     ` Sakari Ailus
  1 sibling, 1 reply; 76+ messages in thread
From: Sylwester Nawrocki @ 2012-01-06 14:58 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, laurent.pinchart, dacohen

Hi Sakari,

On 12/20/2011 09:28 PM, Sakari Ailus wrote:
> +
> +static int rm680_sec_camera_set_xshutdown(struct v4l2_subdev *subdev, u8 set)

It may be more efficient to just use u32.

> +{
> +	gpio_set_value(SEC_CAMERA_RESET_GPIO, !!set);
> +	return 0;
> +}
> +
...
> +void __init rm680_camera_init(void)
> +{
> +	struct isp_platform_data *pdata;
> +	int rval;
> +
> +	rval = rm680_camera_hw_init();
> +	if (rval) {
> +		printk(KERN_WARNING "%s: unable to initialise camera\n",

pr_warn is preferred for new code.

> +		       __func__);
> +		return;
> +	}
> +
> +	if (board_is_rm680())
> +		pdata =&rm680_isp_platform_data;
> +	else
> +		pdata =&rm696_isp_platform_data;
> +
> +	if (omap3_init_camera(pdata)<  0)
> +		printk(KERN_WARNING

pr_warn

> +		       "%s: unable to register camera platform device\n",
> +		       __func__);
> +}
...
> +static struct regulator_consumer_supply rm680_vaux2_consumers[] = {
> +	REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"),	/* OMAP ISP */
> +	REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"),	/* OMAP ISP */
> +	{
> +		.supply		= "vaux2",
> +	},

Could also be
	REGULATOR_SUPPLY("vaux2", NULL),

> +};
> +REGULATOR_INIT_DATA_FIXED(rm680_vaux2, 1800000);
> +
> +static struct regulator_consumer_supply rm680_vaux3_consumers[] = {
> +	REGULATOR_SUPPLY("VANA", "2-0037"),	/* Main Camera Sensor */
> +	REGULATOR_SUPPLY("VANA", "2-000e"),	/* Main Camera Lens */
> +	REGULATOR_SUPPLY("VANA", "2-0010"),	/* Front Camera */
> +	{
> +		.supply		= "vaux3",
> +	},

and 	REGULATOR_SUPPLY("vaux3", NULL),

> +};

--
Regards,
Sylwester

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 16/17] smiapp: Add driver.
  2011-12-20 20:28 ` [RFC 16/17] smiapp: Add driver Sakari Ailus
@ 2012-01-06 17:12   ` Sylwester Nawrocki
  2012-01-07 23:01     ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Sylwester Nawrocki @ 2012-01-06 17:12 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, laurent.pinchart, dacohen

Hi Sakari,

I have a just a few comments below. It was rather brief a review, given the
size of the patch.. :-)

On 12/20/2011 09:28 PM, Sakari Ailus wrote:
> Add driver for SMIA++/SMIA image sensors. The driver exposes the sensor as
> three subdevs, pixel array, binner and scaler --- in case the device has a
> scaler.
> 
> Currently it relies on the board code for external clock handling. There is
> no fast way out of this dependency before the ISP drivers (omap3isp) among
> others will be able to export that clock through the clock framework
> instead.
> 
> Signed-off-by: Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>
> ---
>   drivers/media/video/Kconfig           |   13 +
>   drivers/media/video/Makefile          |    3 +
>   drivers/media/video/smiapp-core.c     | 2595 +++++++++++++++++++++++++++++++++
>   drivers/media/video/smiapp-debug.h    |   32 +
>   drivers/media/video/smiapp-limits.c   |  132 ++
>   drivers/media/video/smiapp-limits.h   |  128 ++
>   drivers/media/video/smiapp-pll.c      |  664 +++++++++
>   drivers/media/video/smiapp-quirk.c    |  264 ++++
>   drivers/media/video/smiapp-quirk.h    |   72 +
>   drivers/media/video/smiapp-reg-defs.h |  733 ++++++++++
>   drivers/media/video/smiapp-reg.h      |  119 ++
>   drivers/media/video/smiapp-regs.c     |  222 +++
>   drivers/media/video/smiapp.h          |  250 ++++
>   include/media/smiapp-regs.h           |   51 +
>   include/media/smiapp.h                |   82 +
>   15 files changed, 5360 insertions(+), 0 deletions(-)
>   create mode 100644 drivers/media/video/smiapp-core.c
>   create mode 100644 drivers/media/video/smiapp-debug.h
>   create mode 100644 drivers/media/video/smiapp-limits.c
>   create mode 100644 drivers/media/video/smiapp-limits.h
>   create mode 100644 drivers/media/video/smiapp-pll.c
>   create mode 100644 drivers/media/video/smiapp-quirk.c
>   create mode 100644 drivers/media/video/smiapp-quirk.h
>   create mode 100644 drivers/media/video/smiapp-reg-defs.h
>   create mode 100644 drivers/media/video/smiapp-reg.h
>   create mode 100644 drivers/media/video/smiapp-regs.c
>   create mode 100644 drivers/media/video/smiapp.h

How about creating new directory, e.g. drivers/media/video/smiapp/ ? 

>   create mode 100644 include/media/smiapp-regs.h
>   create mode 100644 include/media/smiapp.h
> 
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index 4e8a0c4..0aa8f13 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -524,6 +524,19 @@ config VIDEO_S5K6AA
>   	  This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
>   	  camera sensor with an embedded SoC image signal processor.
> 
> +config VIDEO_SMIAPP
> +	tristate "SMIA++/SMIA sensor support"
> +	depends on I2C&&  VIDEO_V4L2

There is no dependency on VIDEO_V4L2_SUBDEV_API ?

> +	---help---
> +	  This is a generic driver for SMIA++/SMIA camera modules.
> +
> +config VIDEO_SMIAPP_DEBUG
> +	bool "Enable debugging for the generic SMIA++/SMIA driver"
> +	depends on VIDEO_SMIAPP
> +	---help---
> +	  Enable debugging output in the generic SMIA++/SMIA driver. If you
> +	  are developing the driver you might want to enable this.
> +
>   comment "Flash devices"
> 
>   config VIDEO_ADP1653
> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
> index ddeaa6c..82a0cea 100644
> --- a/drivers/media/video/Makefile
> +++ b/drivers/media/video/Makefile
> @@ -73,6 +73,9 @@ obj-$(CONFIG_VIDEO_SR030PC30)	+= sr030pc30.o
>   obj-$(CONFIG_VIDEO_NOON010PC30)	+= noon010pc30.o
>   obj-$(CONFIG_VIDEO_M5MOLS)	+= m5mols/
>   obj-$(CONFIG_VIDEO_S5K6AA)	+= s5k6aa.o
> +smiapp-objs			+= smiapp-core.o smiapp-regs.o smiapp-pll.o \
> +				   smiapp-quirk.o smiapp-limits.o
> +obj-$(CONFIG_VIDEO_SMIAPP)	+= smiapp.o
>   obj-$(CONFIG_VIDEO_ADP1653)	+= adp1653.o
> 
>   obj-$(CONFIG_SOC_CAMERA_IMX074)		+= imx074.o
> diff --git a/drivers/media/video/smiapp-core.c b/drivers/media/video/smiapp-core.c
> new file mode 100644
> index 0000000..1d15c1d
> --- /dev/null
> +++ b/drivers/media/video/smiapp-core.c
> @@ -0,0 +1,2595 @@
> +/*
> + * drivers/media/video/smiapp-core.c
> + *
> + * Generic driver for SMIA/SMIA++ compliant camera modules
> + *
> + * Copyright (C) 2010--2011 Nokia Corporation
> + * Contact: Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>
> + *
> + * Based on smiapp driver by Vimarsh Zutshi
> + * Based on jt8ev1.c by Vimarsh Zutshi
> + * Based on smia-sensor.c by Tuukka Toivonen<tuukkat76@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#include "smiapp-debug.h"
> +
> +#include<linux/delay.h>
> +#include<linux/device.h>
> +#include<linux/module.h>
> +#include<linux/regulator/consumer.h>
> +#include<linux/v4l2-mediabus.h>
> +#include<media/v4l2-device.h>
> +
> +#include "smiapp.h"
> +
> +#define SMIAPP_ALIGN_DIM(dim, flags)	      \
> +	(flags&  V4L2_SUBDEV_SEL_FLAG_SIZE_GE \
> +	 ? ALIGN(dim, 2)		      \
> +	 : dim&  ~1)
> +
> +/*
> + * smiapp_module_idents - supported camera modules
> + */
> +static const struct smiapp_module_ident smiapp_module_idents[] = {
> +	SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1",&smiapp_jt8ev1_quirk),
> +	SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es",&smiapp_imx125es_quirk),
> +	SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"),
> +	SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"),
> +	SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"),
> +	SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md",&smiapp_tcm8500md_quirk),
> +	SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"),
> +	SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"),
> +	SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9",&smiapp_jt8ew9_quirk),
> +	SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"),
> +	SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"),
> +};
> +
> +/*
> + *
> + * Dynamic Capability Identification
> + *
> + */
> +
[...]
> +/*
> + *
> + * V4L2 Controls handling
> + *
> + */
> +
> +static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
> +{
> +	struct v4l2_ctrl *ctrl = sensor->exposure;
> +	int max;
> +
> +	max = sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].height
> +		+ sensor->vblank->val -
> +		sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
> +
> +	ctrl->maximum = max;
> +	if (ctrl->default_value>  max)
> +		ctrl->default_value = max;
> +	if (ctrl->val>  max)
> +		ctrl->val = max;
> +	if (ctrl->cur.val>  max)
> +		ctrl->cur.val = max;
> +}

One more driver that needs control value range update. :)

> +
[...]
> +
> +#define SCALING_GOODNESS		100000
> +#define SCALING_GOODNESS_EXTREME	100000000

Interesting parameter.. :)

> +static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
> +			    int h, int ask_h, u32 flags)
> +{
> +	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
> +	struct i2c_client *client = v4l2_get_subdevdata(subdev);
> +	int val = 0;
> +
> +	w&= ~1;
> +	ask_w&= ~1;
> +	h&= ~1;
> +	ask_h&= ~1;
> +
> +	if (flags&  V4L2_SUBDEV_SEL_FLAG_SIZE_GE) {
> +		if (w<  ask_w)
> +			val -= SCALING_GOODNESS;
> +		if (h<  ask_h)
> +			val -= SCALING_GOODNESS;
> +	}
> +
> +	if (flags&  V4L2_SUBDEV_SEL_FLAG_SIZE_LE) {
> +		if (w>  ask_w)
> +			val -= SCALING_GOODNESS;
> +		if (h>  ask_h)
> +			val -= SCALING_GOODNESS;
> +	}
> +
> +	val -= abs(w - ask_w);
> +	val -= abs(h - ask_h);
> +
> +	if (w<  sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
> +		val -= SCALING_GOODNESS_EXTREME;
> +
> +	dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
> +		w, ask_h, h, ask_h, val);
> +
> +	return val;
> +}
> +
[...]
> +static int smiapp_set_selection(struct v4l2_subdev *subdev,
> +				struct v4l2_subdev_fh *fh,
> +				struct v4l2_subdev_selection *sel)
> +{
> +	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
> +	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
> +	struct v4l2_rect *comps, *crops;
> +	int ret;
> +
> +	ret = __smiapp_sel_supported(subdev, sel);
> +	if (ret)
> +		return ret;
> +
> +	sel->r.left = sel->r.left&  ~1;
> +	sel->r.top = sel->r.top&  ~1;
> +	sel->r.width = SMIAPP_ALIGN_DIM(sel->r.width, sel->flags);
> +	sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags);
> +
> +	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> +		crops = ssd->crop;
> +		comps = ssd->compose;
> +	} else {
> +		crops = fh->try_crop;
> +		comps = fh->try_compose;
> +	}
> +
> +	sel->r.left&= ~1;
> +	sel->r.top&= ~1;
> +	sel->r.width&= ~1;
> +	sel->r.height&= ~1;
> +
> +	sel->r.left = max(0, sel->r.left);
> +	sel->r.top = max(0, sel->r.top);
> +	sel->r.width = max(0, sel->r.width);
> +	sel->r.height = max(0, sel->r.height);
> +
> +	sel->r.width = max_t(unsigned int,
> +			     sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
> +			     sel->r.width);
> +	sel->r.height = max_t(unsigned int,
> +			      sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
> +			      sel->r.height);
> +
> +	switch (sel->target) {
> +	case V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE:
> +		return smiapp_set_crop(subdev, fh, sel);
> +	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE:
> +		return smiapp_set_compose(subdev, fh, sel);
> +	}
> +
> +	BUG();
> +}
> +
> +static int smiapp_validate_pipeline(struct v4l2_subdev *subdev)
> +{
> +	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
> +	struct smiapp_subdev *ssds[] = {
> +		sensor->scaler, sensor->binner, sensor->pixel_array };
> +	int i;
> +	struct smiapp_subdev *last = NULL;
> +
> +	if (sensor->src->crop[SMIAPP_PAD_SOURCE].width
> +	<  sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
> +		return -EPIPE;
> +	if (sensor->src->crop[SMIAPP_PAD_SOURCE].height
> +	<  sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE])
> +		return -EPIPE;
> +
> +	for (i = 0; i<  SMIAPP_SUBDEVS; i++) {
> +		struct smiapp_subdev *this = ssds[i];
> +
> +		if (!this)
> +			continue;
> +
> +		if (!last) {
> +			last = this;
> +			continue;
> +		}
> +
> +		if (last->sink_fmt.width
> +		    != this->compose[SMIAPP_PAD_SOURCE].width)
> +			return -EPIPE;
> +		if (last->sink_fmt.height
> +		    != this->compose[SMIAPP_PAD_SOURCE].height)
> +			return -EPIPE;
> +
> +		last = this;
> +	}
> +
> +	return 0;
> +}
> +
[...]
> +
> +static int __init smiapp_init(void)
> +{
> +	int rval;
> +
> +	rval = i2c_add_driver(&smiapp_i2c_driver);
> +	if (rval)
> +		printk(KERN_ERR "Failed registering driver" SMIAPP_NAME "\n");

Using pr_<level> is expected for new drivers.

> +
> +	return rval;
> +}
> +
> +static void __exit smiapp_exit(void)
> +{
> +	i2c_del_driver(&smiapp_i2c_driver);
> +}
> +
> +module_init(smiapp_init);
> +module_exit(smiapp_exit);
> +
> +MODULE_AUTHOR("Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>");
> +MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver");
> +MODULE_LICENSE("GPL");

[...]
> +/*
> + * Write to a 8/16-bit register.
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +int smia_i2c_write_reg(struct i2c_client *client, u32 reg, u32 val)
> +{
> +	struct i2c_msg msg[1];
> +	unsigned char data[6];
> +	unsigned int retries = 5;
> +	unsigned int flags = reg>>  24;
> +	unsigned int len = (u8)(reg>>  16);
> +	u16 offset = reg;
> +	int r;
> +
> +	if (!client->adapter)
> +		return -ENODEV;
> +
> +	if ((len != SMIA_REG_8BIT&&  len != SMIA_REG_16BIT&&
> +	     len != SMIA_REG_32BIT) || flags)
> +		return -EINVAL;
> +
> +	smia_i2c_create_msg(client, len, offset, val, msg, data);
> +
> +	do {
> +		/*
> +		 * Due to unknown reason sensor stops responding. This
> +		 * loop is a temporaty solution until the root cause
> +		 * is found.
> +		 */
> +		r = i2c_transfer(client->adapter, msg, 1);
> +		if (r>= 0)
> +			break;

I think r == 0 indicates failure (0 messages transferred), it's probably
never returned in that case though. It might be better to test for r == 1.

> +
> +		usleep_range(2000, 2000);
> +	} while (retries--);
> +
> +	if (r<  0)
> +		dev_err(&client->dev,
> +			"wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
> +	else
> +		r = 0; /* on success i2c_transfer() return messages trasfered */
> +
> +	if (retries<  5)
> +		dev_err(&client->dev, "sensor i2c stall encountered. "
> +			"retries: %d\n", 5 - retries);
> +
> +	return r;
> +}
[...]
> diff --git a/include/media/smiapp-regs.h b/include/media/smiapp-regs.h
> new file mode 100644
> index 0000000..3109b02
> --- /dev/null
> +++ b/include/media/smiapp-regs.h
> @@ -0,0 +1,51 @@
> +/*
> + * include/media/smiapp-regs.h
> + *
> + * Generic driver for SMIA/SMIA++ compliant camera modules
> + *
> + * Copyright (C) 2011 Nokia Corporation
> + * Contact: Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef SMIAPP_REGS_H
> +#define SMIAPP_REGS_H
> +
> +#include<linux/i2c.h>
> +#include<linux/types.h>

> +#include<linux/videodev2.h>
> +#include<linux/v4l2-subdev.h>

Are these two headers really needed ?

> +
> +struct v4l2_mbus_framefmt;
> +struct v4l2_subdev_pad_mbus_code_enum;

Also these 2 lines seem redundant.

> +
> +/* Use upper 8 bits of the type field for flags */
> +#define SMIA_REG_FLAG_FLOAT		(1<<  24)
> +
> +#define SMIA_REG_8BIT			1
> +#define SMIA_REG_16BIT			2
> +#define SMIA_REG_32BIT			4
> +struct smia_reg {
> +	u16 type;
> +	u16 reg;			/* 16-bit offset */
> +	u32 val;			/* 8/16/32-bit value */
> +};
> +
> +int smia_i2c_read_reg(struct i2c_client *client, u32 reg, u32 *val);
> +int smia_i2c_write_reg(struct i2c_client *client, u32 reg, u32 val);
> +
> +#endif
> diff --git a/include/media/smiapp.h b/include/media/smiapp.h
> new file mode 100644
> index 0000000..b302570
> --- /dev/null
> +++ b/include/media/smiapp.h
> @@ -0,0 +1,82 @@
> +/*
> + * include/media/smiapp.h
> + *
> + * Generic driver for SMIA/SMIA++ compliant camera modules
> + *
> + * Copyright (C) 2011 Nokia Corporation
> + * Contact: Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef __SMIAPP_H_
> +#define __SMIAPP_H_
> +
> +#include<media/smiapp-regs.h>
> +#include<media/v4l2-subdev.h>
> +
> +#define SMIAPP_NAME		"smiapp"
> +
> +#define SMIAPP_DFL_I2C_ADDR	(0x20>>  1) /* Default I2C Address */
> +#define SMIAPP_ALT_I2C_ADDR	(0x6e>>  1) /* Alternate I2C Address */
> +
> +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK	0
> +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE	1
> +#define SMIAPP_CSI_SIGNALLING_MODE_CSI2			2
> +
> +/*
> + * Sometimes due to board layout considerations the camera module can be
> + * mounted rotated. The typical rotation used is 180 degrees which can be
> + * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
> + * FIXME: rotation also changes the bayer pattern.
> + */
> +enum smiapp_module_board_orient {
> +	SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
> +	SMIAPP_MODULE_BOARD_ORIENT_180,
> +};
> +
> +struct smiapp_flash_strobe_parms {
> +	u8 mode;
> +	u32 strobe_width_high_us;
> +	u16 strobe_delay;
> +	u16 stobe_start_point;
> +	u8 trigger;
> +};
> +
> +struct smiapp_platform_data {
> +	/*
> +	 * Change the cci address if i2c_addr_alt is set.
> +	 * Both default and alternate cci addr need to be present
> +	 */
> +	unsigned short i2c_addr_dfl;	/* Default i2c addr */
> +	unsigned short i2c_addr_alt;	/* Alternate i2c addr */
> +
> +	unsigned int nvm_size;			/* bytes */
> +	unsigned int ext_clk;			/* sensor external clk */
> +
> +	unsigned int lanes;		/* Number of CSI-2 lanes */
> +	u8 csi_signalling_mode;		/* SMIAPP_CSI_SIGNALLING_MODE_* */
> +	const s64 *op_sys_clock;
> +
> +	enum smiapp_module_board_orient module_board_orient;
> +
> +	struct smiapp_flash_strobe_parms *strobe_setup;
> +
> +	int (*set_xclk)(struct v4l2_subdev *sd, int hz);
> +	int (*set_xshutdown)(struct v4l2_subdev *sd, u8 set);

There is no chance to avoid this callback, e.g. by passing GPIO(s) number(s)
directly to the driver ?

> +};
> +
> +#endif /* __SMIAPP_H_  */

--
Regards,
Sylwester

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs
  2012-01-06 12:00       ` Laurent Pinchart
@ 2012-01-07  9:09         ` Sakari Ailus
  2012-01-07 11:09           ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07  9:09 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> Hi Sakari,
> 
> On Friday 06 January 2012 12:27:03 Sakari Ailus wrote:
>> Laurent Pinchart wrote:
>>> On Tuesday 20 December 2011 21:27:56 Sakari Ailus wrote:
>>>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>>>
>>>> Add support for VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION
>>>> IOCTLs. They replace functionality provided by VIDIOC_SUBDEV_S_CROP and
>>>> VIDIOC_SUBDEV_G_CROP IOCTLs and also add new functionality (composing).
>>>>
>>>> VIDIOC_SUBDEV_G_CROP and VIDIOC_SUBDEV_S_CROP continue to be supported.
>>>
>>> As those ioctls are experimental, should we deprecate them ?
>>
>> I'm also in favour of doing that. But I'll make it a separate patch.
>>
>>>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>>>> ---
>>>>
>>>>  drivers/media/video/v4l2-subdev.c |   26 ++++++++++++++++++++-
>>>>  include/linux/v4l2-subdev.h       |   45
>>>>  ++++++++++++++++++++++++++++++++++ include/media/v4l2-subdev.h       |
>>>>     5 ++++
>>>>  3 files changed, 75 insertions(+), 1 deletions(-)
>>>>
>>>> diff --git a/drivers/media/video/v4l2-subdev.c
>>>> b/drivers/media/video/v4l2-subdev.c index 65ade5f..e8ae098 100644
>>>> --- a/drivers/media/video/v4l2-subdev.c
>>>> +++ b/drivers/media/video/v4l2-subdev.c
>>>> @@ -36,13 +36,17 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh,
>>>> struct v4l2_subdev *sd) {
>>>>
>>>>  #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
>>>>  
>>>>  	/* Allocate try format and crop in the same memory block */
>>>>
>>>> -	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
>>>> +	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop)
>>>> +			       + sizeof(*fh->try_compose))
>>>>
>>>>  			      * sd->entity.num_pads, GFP_KERNEL);
>>>
>>> Could you check how the 3 structures are aligned on 64-bit platforms ?
>>> I'm a bit worried about the compiler expecting a 64-bit alignment for
>>> one of them, and getting only a 32-bit alignment in the end.
>>>
>>> What about using kcalloc ?
>>
>> kcalloc won't make a difference --- see the implementation. Do you think
>> this is really an issue in practice?
> 
> It won't make a difference for the alignment, it's just that we allocate an 
> array, so kcalloc seemed right.
> 
>> If we want to ensure alignment I'd just allocate them separately. Or
>> create a struct out of them locally, and get the pointers from that
>> struct --- then the alignment would be the same as if those were part of
>> a single struct. That achieves the desired result and also keeps error
>> handling trivial.
>>
>> I wouldn't want to start relying on the alignment based on the sizes of
>> these structures.
> 
> Sounds good to me. Allocating them as part of a bigger structure internally 
> could be more efficient than separate allocations, but I'm fine with both.

On second thought, I think I'll combine them into a new anonymous struct
the field name of which I call "pad", unless that requires too intrusive
changes in other drivers. How about that?

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs
  2012-01-07  9:09         ` Sakari Ailus
@ 2012-01-07 11:09           ` Sakari Ailus
  2012-01-07 15:54             ` Laurent Pinchart
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07 11:09 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Sakari Ailus wrote:
...
> On second thought, I think I'll combine them into a new anonymous struct
> the field name of which I call "pad", unless that requires too intrusive
> changes in other drivers. How about that?

And the answer to that is "no". The smia++ driver does store the format,
crop and compose values in arrays indexed by pad numbers which I think
is a natural thing for the driver to do. In many functiona the driver
uses internally it's trivial to choose the array either from driver's
internal data structure (V4L2_SUBDEV_FORMAT_ACTIVE) or the file handle
(V4L2_SUBDEV_FORMAT_TRY).

Alternatively a named struct could be created for the same, but the
drivers might not need all the fields at all, or choose to store them in
a different form.

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs
  2012-01-07 11:09           ` Sakari Ailus
@ 2012-01-07 15:54             ` Laurent Pinchart
  2012-01-07 16:53               ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-07 15:54 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

On Saturday 07 January 2012 12:09:29 Sakari Ailus wrote:
> Sakari Ailus wrote:
> ...
> 
> > On second thought, I think I'll combine them into a new anonymous struct
> > the field name of which I call "pad", unless that requires too intrusive
> > changes in other drivers. How about that?
> 
> And the answer to that is "no". The smia++ driver does store the format,
> crop and compose values in arrays indexed by pad numbers which I think
> is a natural thing for the driver to do. In many functiona the driver
> uses internally it's trivial to choose the array either from driver's
> internal data structure (V4L2_SUBDEV_FORMAT_ACTIVE) or the file handle
> (V4L2_SUBDEV_FORMAT_TRY).
> 
> Alternatively a named struct could be created for the same, but the
> drivers might not need all the fields at all, or choose to store them in
> a different form.

Drivers should use the v4l2_subdev_get_try_format(), 
v4l2_subdev_get_try_crop() and v4l2_subdev_get_try_compose() functions to 
access TRY formats and selection rectangles on file handles, so they shouldn't 
care about the allocation details.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs
  2012-01-07 15:54             ` Laurent Pinchart
@ 2012-01-07 16:53               ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07 16:53 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Laurent Pinchart wrote:
> Hi Sakari,
> 
> On Saturday 07 January 2012 12:09:29 Sakari Ailus wrote:
>> Sakari Ailus wrote:
>> ...
>>
>>> On second thought, I think I'll combine them into a new anonymous struct
>>> the field name of which I call "pad", unless that requires too intrusive
>>> changes in other drivers. How about that?
>>
>> And the answer to that is "no". The smia++ driver does store the format,
>> crop and compose values in arrays indexed by pad numbers which I think
>> is a natural thing for the driver to do. In many functiona the driver
>> uses internally it's trivial to choose the array either from driver's
>> internal data structure (V4L2_SUBDEV_FORMAT_ACTIVE) or the file handle
>> (V4L2_SUBDEV_FORMAT_TRY).
>>
>> Alternatively a named struct could be created for the same, but the
>> drivers might not need all the fields at all, or choose to store them in
>> a different form.
> 
> Drivers should use the v4l2_subdev_get_try_format(), 
> v4l2_subdev_get_try_crop() and v4l2_subdev_get_try_compose() functions to 
> access TRY formats and selection rectangles on file handles, so they shouldn't 
> care about the allocation details.

Good point... That requires some changes as well, like introduction of
v4l2_subdev_get_try_compose(). :-)

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 17/17] rm680: Add camera init
  2012-01-06 10:21   ` Laurent Pinchart
@ 2012-01-07 21:30     ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07 21:30 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Thanks for the review!

Laurent Pinchart wrote:
> On Tuesday 20 December 2011 21:28:09 Sakari Ailus wrote:
>> This currently introduces an extra file to the arch/arm/mach-omap2
>> directory: board-rm680-camera.c. Keeping the device tree in mind, the
>> context of the file could be represented as static data with one exception:
>> the external clock to the sensor.
>>
>> This external clock is provided by the OMAP 3 SoC and required by the
>> sensor. The issue is that the clock originates from the ISP and not from
>> PRCM block as the other clocks and thus is not supported by the clock
>> framework. Otherwise the sensor driver could just clk_get() and
>> clk_enable() it, just like the regulators and gpios.
> 
> This will hopefully be fixable with the new generic clock struct. Have you had 
> a look at it lately BTW ?

Not since the ELc-E. It'd be nice to get that so we can get rid of the
final issue between OMAP 3 ISP and the device tree --- well, there may
be others but I can't say to know about them. :-)

>> Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
>> ---
>>  arch/arm/mach-omap2/Makefile             |    3 +-
>>  arch/arm/mach-omap2/board-rm680-camera.c |  408
>> ++++++++++++++++++++++++++++++ arch/arm/mach-omap2/board-rm680.c        | 
>>  42 +++
>>  3 files changed, 452 insertions(+), 1 deletions(-)
>>  create mode 100644 arch/arm/mach-omap2/board-rm680-camera.c
>>
>> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
>> index 69ab1c0..1444bc5 100644
>> --- a/arch/arm/mach-omap2/Makefile
>> +++ b/arch/arm/mach-omap2/Makefile
>> @@ -201,7 +201,8 @@ obj-$(CONFIG_MACH_OMAP3_PANDORA)	+=
>> board-omap3pandora.o obj-$(CONFIG_MACH_OMAP_3430SDP)		+= board-3430sdp.o
>>  obj-$(CONFIG_MACH_NOKIA_N8X0)		+= board-n8x0.o
>>  obj-$(CONFIG_MACH_NOKIA_RM680)		+= board-rm680.o \
>> -					   sdram-nokia.o
>> +					   sdram-nokia.o \
>> +					   board-rm680-camera.o
>>  obj-$(CONFIG_MACH_NOKIA_RX51)		+= board-rx51.o \
>>  					   sdram-nokia.o \
>>  					   board-rx51-peripherals.o \
>> diff --git a/arch/arm/mach-omap2/board-rm680-camera.c
>> b/arch/arm/mach-omap2/board-rm680-camera.c new file mode 100644
>> index 0000000..4cc1ced
>> --- /dev/null
>> +++ b/arch/arm/mach-omap2/board-rm680-camera.c
>> @@ -0,0 +1,408 @@
>> +/**
>> + * arch/arm/mach-omap2/board-rm680-camera.c
>> + *
>> + * Copyright (C) 2010--2011 Nokia Corporation
> 
> 2012 ? :-)

Good point. I'll make the change for the rest of the files as well.

>> + * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
>> + *
>> + * Based on board-rx71-camera.c by Vimarsh Zutshi
> 
> This one isn't upstream, I'm not sure if it's worth mentioning it.

It's still of historical importance; that is still publicly available if
not in mainline. If you really think I should remove it I will.

>> + * Based on board-rx51-camera.c by Sakari Ailus
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
>> + * 02110-1301 USA
>> + *
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/mm.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/videodev2.h>
>> +
>> +#include <linux/gpio.h>
>> +#include <plat/omap-pm.h>
>> +
>> +#include "../../../drivers/media/video/omap3isp/isp.h"
> 
> What do we still miss in <media/omap3isp.h> ?

I think it's mostly the xclk stuff. Everything else is where it should be.

>> +#include <media/omap3isp.h>
>> +#include <media/smiapp.h>
>> +#include <asm/mach-types.h>
>> +
>> +#include "../../../drivers/media/video/smiapp.h"
> 
> Time to create <media/smiapp.h> ?

Now that you ask; the file is there and it contains all the necessary
definitions. I had forgotten to remove the line. ;-)

>> +
>> +#include "devices.h"
>> +
>> +#define SEC_CAMERA_RESET_GPIO	97
>> +
>> +#define RM680_PRI_SENSOR	1
>> +#define RM680_PRI_LENS		2
>> +#define RM680_SEC_SENSOR	3
>> +#define MAIN_CAMERA_XCLK	ISP_XCLK_A
>> +#define SEC_CAMERA_XCLK		ISP_XCLK_B
>> +
>> +/*
>> + *
>> + * HW initialization
>> + *
>> + *
>> + */
>> +static int __init rm680_sec_camera_init(void)
>> +{
>> +	if (gpio_request(SEC_CAMERA_RESET_GPIO, "sec_camera reset") != 0) {
>> +		printk(KERN_INFO "%s: unable to acquire secondary "
>> +		       "camera reset gpio\n", __func__);
>> +		return -ENODEV;
>> +	}
>> +
>> +	/* XSHUTDOWN off, reset  */
>> +	gpio_direction_output(SEC_CAMERA_RESET_GPIO, 0);
>> +	gpio_set_value(SEC_CAMERA_RESET_GPIO, 0);
> 
> gpio_request_one() would be helpful here (and possibly in other locations in 
> this file).

Moved to smiapp-core.c as suggested by Sylwester.

>> +
>> +	return 0;
>> +}
>> +
>> +static int __init rm680_camera_hw_init(void)
>> +{
>> +	return rm680_sec_camera_init();
> 
> Maybe you could merge the two functions ?

Removed.

>> +}
>> +
>> +/*
>> + *
>> + * Main Camera Module EXTCLK
>> + * Used by the sensor and the actuator driver.
>> + *
>> + */
>> +static struct camera_xclk {
>> +	u32 hz;
>> +	u32 lock;
>> +	u8 xclksel;
>> +} cameras_xclk;
>> +
>> +static DEFINE_MUTEX(lock_xclk);
>> +
>> +static int rm680_update_xclk(struct v4l2_subdev *subdev, u32 hz, u32
>> which, +			     u8 xclksel)
>> +{
>> +	struct isp_device *isp = v4l2_dev_to_isp_device(subdev->v4l2_dev);
>> +	int ret;
>> +
>> +	mutex_lock(&lock_xclk);
>> +
>> +	if (which == RM680_SEC_SENSOR) {
>> +		if (cameras_xclk.xclksel == MAIN_CAMERA_XCLK) {
>> +			ret = -EBUSY;
>> +			goto done;
>> +		}
>> +	} else {
>> +		if (cameras_xclk.xclksel == SEC_CAMERA_XCLK) {
>> +			ret = -EBUSY;
>> +			goto done;
>> +		}
>> +	}
>> +
>> +	if (hz) {	/* Turn on */
>> +		cameras_xclk.lock |= which;
>> +		if (cameras_xclk.hz == 0) {
>> +			isp->platform_cb.set_xclk(isp, hz, xclksel);
>> +			cameras_xclk.hz = hz;
>> +			cameras_xclk.xclksel = xclksel;
>> +		}
>> +	} else {	/* Turn off */
>> +		cameras_xclk.lock &= ~which;
>> +		if (cameras_xclk.lock == 0) {
>> +			isp->platform_cb.set_xclk(isp, 0, xclksel);
>> +			cameras_xclk.hz = 0;
>> +			cameras_xclk.xclksel = 0;
>> +		}
>> +	}
>> +
>> +	ret = cameras_xclk.hz;
>> +
>> +done:
>> +	mutex_unlock(&lock_xclk);
>> +	return ret;
>> +}
>> +
>> +/*
>> + *
>> + * Main Camera Sensor
>> + *
>> + */
>> +
>> +static struct isp_csiphy_lanes_cfg rm696_main_camera_csi2_lanecfg = {
>> +	.clk = {
>> +		.pol = 1,
>> +		.pos = 2,
>> +	},
>> +	.data[0] = {
>> +		.pol = 1,
>> +		.pos = 1,
>> +	},
>> +	.data[1] = {
>> +		.pol = 1,
>> +		.pos = 3,
>> +	},
>> +};
>> +
>> +static struct isp_csiphy_lanes_cfg rm680_main_camera_csi2_lanecfg = {
>> +	.clk = {
>> +		.pol = 1,
>> +		.pos = 2,
>> +	},
>> +	.data[0] = {
>> +		.pol = 1,
>> +		.pos = 3,
>> +	},
>> +	.data[1] = {
>> +		.pol = 1,
>> +		.pos = 1,
>> +	},
>> +};
>> +
>> +static int rm680_main_camera_set_xclk(struct v4l2_subdev *sd, int hz)
>> +{
>> +	return rm680_update_xclk(sd, hz, RM680_PRI_SENSOR, MAIN_CAMERA_XCLK);
>> +}
>> +
>> +static struct smiapp_flash_strobe_parms rm680_main_camera_strobe_setup = {
>> +	.mode			= 0x0c,
>> +	.strobe_width_high_us	= 100000,
>> +	.strobe_delay		= 0,
>> +	.stobe_start_point	= 0,
>> +	.trigger		= 0,
>> +};
>> +
>> +static struct smiapp_platform_data rm696_main_camera_platform_data = {
>> +	.i2c_addr_dfl		= SMIAPP_DFL_I2C_ADDR,
>> +	.i2c_addr_alt		= SMIAPP_ALT_I2C_ADDR,
>> +	.nvm_size		= 16 * 64,
>> +	.ext_clk		= (9.6 * 1000 * 1000),
>> +	.lanes			= 2,
>> +	.op_sys_clock		= (s64 []){ 796800 / 2, 840000 / 2,
>> +					    1996800 / 2, 0 },
>> +	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CSI2,
>> +	.strobe_setup		= &rm680_main_camera_strobe_setup,
>> +	.set_xclk		= rm680_main_camera_set_xclk,
>> +};
>> +
>> +static struct smiapp_platform_data rm680_main_camera_platform_data = {
>> +	.i2c_addr_dfl		= SMIAPP_DFL_I2C_ADDR,
>> +	.i2c_addr_alt		= SMIAPP_ALT_I2C_ADDR,
>> +	.nvm_size		= 16 * 64,
>> +	.ext_clk		= (9.6 * 1000 * 1000),
>> +	.lanes			= 2,
>> +	.op_sys_clock		= (s64 []){ 840000 / 2, 1334400 / 2,
>> +					    1593600 / 2, 0 },
>> +	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CSI2,
>> +	.module_board_orient	= SMIAPP_MODULE_BOARD_ORIENT_180,
>> +	.strobe_setup		= &rm680_main_camera_strobe_setup,
>> +	.set_xclk		= rm680_main_camera_set_xclk,
>> +};
>> +
>> +/*
>> + *
>> + * SECONDARY CAMERA Sensor
>> + *
>> + */
>> +
>> +#define SEC_CAMERA_XCLK		ISP_XCLK_B
>> +
>> +static struct isp_csiphy_lanes_cfg rm680_sec_camera_csiphy_lanecfg = {
>> +	.clk = {
>> +		.pol = 0,
>> +		.pos = 1,
>> +	},
>> +	.data[0] = {
>> +		.pol = 0,
>> +		.pos = 2,
>> +	},
>> +};
>> +
>> +static int rm680_sec_camera_set_xclk(struct v4l2_subdev *sd, int hz)
>> +{
>> +	return rm680_update_xclk(sd, hz, RM680_SEC_SENSOR, SEC_CAMERA_XCLK);
>> +}
>> +
>> +static int rm680_sec_camera_set_xshutdown(struct v4l2_subdev *subdev, u8
>> set) +{
>> +	gpio_set_value(SEC_CAMERA_RESET_GPIO, !!set);
>> +	return 0;
>> +}
>> +
>> +static struct smiapp_platform_data rm696_sec_camera_platform_data = {
>> +	.ext_clk		= (10.8 * 1000 * 1000),
>> +	.lanes			= 1,
>> +	.op_sys_clock		= (s64 []){ 13770 * 10, 0 },
>> +	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK,
>> +	.module_board_orient	= SMIAPP_MODULE_BOARD_ORIENT_180,
>> +	.set_xclk		= rm680_sec_camera_set_xclk,
>> +	.set_xshutdown		= rm680_sec_camera_set_xshutdown,
>> +};
>> +
>> +static struct smiapp_platform_data rm680_sec_camera_platform_data = {
>> +	.ext_clk		= (10.8 * 1000 * 1000),
>> +	.lanes			= 1,
>> +	.op_sys_clock		= (s64 []){ 11880 * 10, 0 },
>> +	.csi_signalling_mode	= SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK,
>> +	.set_xclk		= rm680_sec_camera_set_xclk,
>> +	.set_xshutdown		= rm680_sec_camera_set_xshutdown,
> 
> What about passing the GPIO number to the smiapp driver instead of using a 
> callback function ?

Done.

>> +};
>> +
>> +/*
>> + *
>> + * Init all the modules
>> + *
>> + */
>> +
>> +#define CAMERA_I2C_BUS_NUM		2
>> +#define AD5836_I2C_BUS_NUM		2
>> +#define AS3645A_I2C_BUS_NUM		2
>> +
>> +static struct i2c_board_info rm696_camera_i2c_devices[] = {
>> +	{
>> +		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_ALT_I2C_ADDR),
>> +		.platform_data = &rm696_main_camera_platform_data,
>> +	},
>> +	{
>> +		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_DFL_I2C_ADDR),
>> +		.platform_data = &rm696_sec_camera_platform_data,
>> +	},
>> +};
>> +
>> +static struct i2c_board_info rm680_camera_i2c_devices[] = {
>> +	{
>> +		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_ALT_I2C_ADDR),
>> +		.platform_data = &rm680_main_camera_platform_data,
>> +	},
>> +	{
>> +		I2C_BOARD_INFO(SMIAPP_NAME, SMIAPP_DFL_I2C_ADDR),
>> +		.platform_data = &rm680_sec_camera_platform_data,
>> +	},
>> +};
>> +
>> +static struct isp_subdev_i2c_board_info rm696_camera_primary_subdevs[] = {
>> +	{
>> +		.board_info = &rm696_camera_i2c_devices[0],
>> +		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
>> +	},
>> +	{ NULL, 0, },
>> +};
>> +
>> +static struct isp_subdev_i2c_board_info rm696_camera_secondary_subdevs[] =
>> { +	{
>> +		.board_info = &rm696_camera_i2c_devices[1],
>> +		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
>> +	},
>> +	{ NULL, 0, },
>> +};
>> +
>> +static struct isp_subdev_i2c_board_info rm680_camera_primary_subdevs[] = {
>> +	{
>> +		.board_info = &rm680_camera_i2c_devices[0],
>> +		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
>> +	},
>> +	{ NULL, 0, },
>> +};
>> +
>> +static struct isp_subdev_i2c_board_info rm680_camera_secondary_subdevs[] =
>> { +	{
>> +		.board_info = &rm680_camera_i2c_devices[1],
>> +		.i2c_adapter_id = CAMERA_I2C_BUS_NUM,
>> +	},
>> +	{ NULL, 0, },
>> +};
>> +
>> +static struct isp_v4l2_subdevs_group rm696_camera_subdevs[] = {
>> +	{
>> +		.subdevs = rm696_camera_primary_subdevs,
>> +		.interface = ISP_INTERFACE_CSI2A_PHY2,
>> +		.bus = { .csi2 = {
>> +			.crc		= 1,
>> +			.vpclk_div	= 1,
>> +			.lanecfg	= &rm696_main_camera_csi2_lanecfg,
>> +		} },
>> +	},
>> +	{
>> +		.subdevs = rm696_camera_secondary_subdevs,
>> +		.interface = ISP_INTERFACE_CCP2B_PHY1,
>> +		.bus = { .ccp2 = {
>> +			.strobe_clk_pol	= 0,
>> +			.crc		= 0,
>> +			.ccp2_mode	= 0,
>> +			.phy_layer	= 0,
>> +			.vpclk_div	= 2,
>> +			.lanecfg	= &rm680_sec_camera_csiphy_lanecfg,
>> +		} },
>> +	},
>> +	{ NULL, 0, },
>> +};
>> +
>> +static struct isp_v4l2_subdevs_group rm680_camera_subdevs[] = {
>> +	{
>> +		.subdevs = rm680_camera_primary_subdevs,
>> +		.interface = ISP_INTERFACE_CSI2A_PHY2,
>> +		.bus = { .csi2 = {
>> +			.crc		= 1,
>> +			.vpclk_div	= 1,
>> +			.lanecfg	= &rm680_main_camera_csi2_lanecfg,
>> +		} },
>> +	},
>> +	{
>> +		.subdevs = rm680_camera_secondary_subdevs,
>> +		.interface = ISP_INTERFACE_CCP2B_PHY1,
>> +		.bus = { .ccp2 = {
>> +			.strobe_clk_pol	= 0,
>> +			.crc		= 0,
>> +			.ccp2_mode	= 0,
>> +			.phy_layer	= 0,
>> +			.vpclk_div	= 2,
>> +			.lanecfg	= &rm680_sec_camera_csiphy_lanecfg,
>> +		} },
>> +	},
>> +	{ NULL, 0, },
>> +};
>> +
>> +static struct isp_platform_data rm696_isp_platform_data = {
>> +	.subdevs = rm696_camera_subdevs,
>> +};
>> +
>> +static struct isp_platform_data rm680_isp_platform_data = {
>> +	.subdevs = rm680_camera_subdevs,
>> +};
>> +
>> +static inline int board_is_rm680(void)
>> +{
>> +	return (system_rev & 0x00f0) == 0x0020;
>> +}
>> +
>> +void __init rm680_camera_init(void)
>> +{
>> +	struct isp_platform_data *pdata;
>> +	int rval;
>> +
>> +	rval = rm680_camera_hw_init();
>> +	if (rval) {
>> +		printk(KERN_WARNING "%s: unable to initialise camera\n",
>> +		       __func__);
>> +		return;
>> +	}
>> +
>> +	if (board_is_rm680())
>> +		pdata = &rm680_isp_platform_data;
>> +	else
>> +		pdata = &rm696_isp_platform_data;
>> +
>> +	if (omap3_init_camera(pdata) < 0)
>> +		printk(KERN_WARNING
>> +		       "%s: unable to register camera platform device\n",
>> +		       __func__);
>> +}
>> diff --git a/arch/arm/mach-omap2/board-rm680.c
>> b/arch/arm/mach-omap2/board-rm680.c index a5bcc75..a1e33d4 100644
>> --- a/arch/arm/mach-omap2/board-rm680.c
>> +++ b/arch/arm/mach-omap2/board-rm680.c
>> @@ -66,6 +66,43 @@ static struct platform_device rm680_vemmc_device = {
>>  	},
>>  };
>>
>> +#define REGULATOR_INIT_DATA(_name, _min, _max, _apply, _ops_mask) \
>> +	static struct regulator_init_data _name##_data = { \
>> +		.constraints = { \
>> +			.name                   = #_name, \
>> +			.min_uV                 = _min, \
>> +			.max_uV                 = _max, \
>> +			.apply_uV               = _apply, \
>> +			.valid_modes_mask       = REGULATOR_MODE_NORMAL | \
>> +						REGULATOR_MODE_STANDBY, \
>> +			.valid_ops_mask         = _ops_mask, \
>> +		}, \
>> +		.num_consumer_supplies  = ARRAY_SIZE(_name##_consumers), \
>> +		.consumer_supplies      = _name##_consumers, \
>> +}
>> +#define REGULATOR_INIT_DATA_FIXED(_name, _voltage) \
>> +	REGULATOR_INIT_DATA(_name, _voltage, _voltage, true, \
>> +				REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE)
>> +
>> +static struct regulator_consumer_supply rm680_vaux2_consumers[] = {
>> +	REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"),	/* OMAP ISP */
>> +	REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"),	/* OMAP ISP */
>> +	{
>> +		.supply		= "vaux2",
>> +	},
>> +};
>> +REGULATOR_INIT_DATA_FIXED(rm680_vaux2, 1800000);
>> +
>> +static struct regulator_consumer_supply rm680_vaux3_consumers[] = {
>> +	REGULATOR_SUPPLY("VANA", "2-0037"),	/* Main Camera Sensor */
>> +	REGULATOR_SUPPLY("VANA", "2-000e"),	/* Main Camera Lens */
> 
> The lens driver isn't upstream yet. We could keep the regulator supply 
> definition to avoid forgetting it later though.

Sounds good to me.

>> +	REGULATOR_SUPPLY("VANA", "2-0010"),	/* Front Camera */
>> +	{
>> +		.supply		= "vaux3",
>> +	},
>> +};
>> +REGULATOR_INIT_DATA_FIXED(rm680_vaux3, 2800000);
>> +
>>  static struct platform_device *rm680_peripherals_devices[] __initdata = {
>>  	&rm680_vemmc_device,
>>  };
>> @@ -82,6 +119,8 @@ static struct twl4030_gpio_platform_data rm680_gpio_data
>> = { static struct twl4030_platform_data rm680_twl_data = {
>>  	.gpio			= &rm680_gpio_data,
>>  	/* add rest of the children here */
>> +	.vaux2			= &rm680_vaux2_data,
>> +	.vaux3			= &rm680_vaux3_data,
>>  };
>>
>>  static void __init rm680_i2c_init(void)
>> @@ -129,6 +168,8 @@ static struct omap_board_mux board_mux[] __initdata = {
>>  };
>>  #endif
>>
>> +void rm680_camera_init(void);
>> +
>>  static void __init rm680_init(void)
>>  {
>>  	struct omap_sdrc_params *sdrc_params;
>> @@ -141,6 +182,7 @@ static void __init rm680_init(void)
>>
>>  	usb_musb_init(NULL);
>>  	rm680_peripherals_init();
>> +	rm680_camera_init();
>>  }
>>
>>  MACHINE_START(NOKIA_RM680, "Nokia RM-680 board")
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2012-01-06 10:01   ` Laurent Pinchart
@ 2012-01-07 22:51     ` Sakari Ailus
  2012-01-08  1:02       ` Laurent Pinchart
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07 22:51 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Thanks for the review!!!

Laurent Pinchart wrote:
> On Tuesday 20 December 2011 21:28:05 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Configure CSI-2 phy based on platform data in the ISP driver rather than in
>> platform code.
>>
>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>> ---
>>  drivers/media/video/omap3isp/isp.c       |   38 ++++++++++++--
>>  drivers/media/video/omap3isp/isp.h       |    3 -
>>  drivers/media/video/omap3isp/ispcsiphy.c |   83 +++++++++++++++++++++++----
>>  drivers/media/video/omap3isp/ispcsiphy.h |    4 ++
>>  4 files changed, 111 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/media/video/omap3isp/isp.c
>> b/drivers/media/video/omap3isp/isp.c index b818cac..6020fd7 100644
>> --- a/drivers/media/video/omap3isp/isp.c
>> +++ b/drivers/media/video/omap3isp/isp.c
>> @@ -737,7 +737,7 @@ static int isp_pipeline_enable(struct isp_pipeline
>> *pipe, struct isp_device *isp = pipe->output->isp;
>>  	struct media_entity *entity;
>>  	struct media_pad *pad;
>> -	struct v4l2_subdev *subdev;
>> +	struct v4l2_subdev *subdev = NULL, *prev_subdev;
>>  	unsigned long flags;
>>  	int ret;
>>
>> @@ -759,11 +759,41 @@ static int isp_pipeline_enable(struct isp_pipeline
>> *pipe, break;
>>
>>  		entity = pad->entity;
>> +		prev_subdev = subdev;
>>  		subdev = media_entity_to_v4l2_subdev(entity);
>>
>> -		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
>> -		if (ret < 0 && ret != -ENOIOCTLCMD)
>> -			return ret;
>> +		/* Configure CSI-2 receiver based on sensor format. */
>> +		if (prev_subdev == &isp->isp_csi2a.subdev
>> +		    || prev_subdev == &isp->isp_csi2c.subdev) {
>> +			struct v4l2_subdev_format fmt;
>> +
>> +			fmt.pad = pad->index;
>> +			fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
>> +			ret = v4l2_subdev_call(subdev, pad, get_fmt,
>> +					       NULL, &fmt);
>> +			if (ret < 0)
>> +				return -EPIPE;
>> +
>> +			ret = omap3isp_csiphy_config(
>> +				isp, prev_subdev, subdev,
>> +				&fmt.format);
>> +			if (ret < 0)
>> +				return -EPIPE;
>> +
>> +			/* Start CSI-2 after configuration. */
>> +			ret = v4l2_subdev_call(prev_subdev, video,
>> +					       s_stream, mode);
>> +			if (ret < 0 && ret != -ENOIOCTLCMD)
>> +				return ret;
>> +		}
>> +
>> +		/* Start any other subdev except the CSI-2 receivers. */
>> +		if (subdev != &isp->isp_csi2a.subdev
>> +		    && subdev != &isp->isp_csi2c.subdev) {
>> +			ret = v4l2_subdev_call(subdev, video, s_stream, mode);
>> +			if (ret < 0 && ret != -ENOIOCTLCMD)
>> +				return ret;
>> +		}
> 
> What about moving this to the CSI2 s_stream subdev operation ?

Done.

>>
>>  		if (subdev == &isp->isp_ccdc.subdev) {
>>  			v4l2_subdev_call(&isp->isp_aewb.subdev, video,
>> diff --git a/drivers/media/video/omap3isp/isp.h
>> b/drivers/media/video/omap3isp/isp.h index 705946e..c5935ae 100644
>> --- a/drivers/media/video/omap3isp/isp.h
>> +++ b/drivers/media/video/omap3isp/isp.h
>> @@ -126,9 +126,6 @@ struct isp_reg {
>>
>>  struct isp_platform_callback {
>>  	u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
>> -	int (*csiphy_config)(struct isp_csiphy *phy,
>> -			     struct isp_csiphy_dphy_cfg *dphy,
>> -			     struct isp_csiphy_lanes_cfg *lanes);
>>  	void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
>>  };
>>
>> diff --git a/drivers/media/video/omap3isp/ispcsiphy.c
>> b/drivers/media/video/omap3isp/ispcsiphy.c index 5be37ce..f027ece 100644
>> --- a/drivers/media/video/omap3isp/ispcsiphy.c
>> +++ b/drivers/media/video/omap3isp/ispcsiphy.c
>> @@ -28,6 +28,8 @@
>>  #include <linux/device.h>
>>  #include <linux/regulator/consumer.h>
>>
>> +#include "../../../../arch/arm/mach-omap2/control.h"
>> +
> 
> #include <mach/control.h>
> 
> (untested) ?

I'm afraid it won't work. The above directory isn't in any include path
and likely shouldn't be. That file is included locally elsewhere, I believe.

I wonder what would be the right way to access that register definition
I need from the file:

	OMAP343X_CTRL_BASE
	OMAP3630_CONTROL_CAMERA_PHY_CTRL

>>  #include "isp.h"
>>  #include "ispreg.h"
>>  #include "ispcsiphy.h"
>> @@ -138,15 +140,78 @@ static void csiphy_dphy_config(struct isp_csiphy
>> *phy) isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
>>  }
>>
>> -static int csiphy_config(struct isp_csiphy *phy,
>> -			 struct isp_csiphy_dphy_cfg *dphy,
>> -			 struct isp_csiphy_lanes_cfg *lanes)
>> +/*
>> + * TCLK values are OK at their reset values
>> + */
>> +#define TCLK_TERM	0
>> +#define TCLK_MISS	1
>> +#define TCLK_SETTLE	14
>> +
>> +int omap3isp_csiphy_config(struct isp_device *isp,
>> +			   struct v4l2_subdev *csi2_subdev,
>> +			   struct v4l2_subdev *sensor,
>> +			   struct v4l2_mbus_framefmt *sensor_fmt)
>>  {
>> +	struct isp_v4l2_subdevs_group *subdevs = sensor->host_priv;
>> +	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(csi2_subdev);
>> +	struct isp_csiphy_dphy_cfg csi2phy;
>> +	int csi2_ddrclk_khz;
>> +	struct isp_csiphy_lanes_cfg *lanes;
>>  	unsigned int used_lanes = 0;
>>  	unsigned int i;
>> +	u32 cam_phy_ctrl;
>> +
>> +	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1
>> +	    || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
>> +		lanes = subdevs->bus.ccp2.lanecfg;
>> +	else
>> +		lanes = subdevs->bus.csi2.lanecfg;
> 
> Shouldn't lane configuration be retrieved from the sensor instead ? Sensors 
> could use different lane configuration depending on the mode. This could also 
> be implemented later when needed, but I don't think it would be too difficult 
> to get it right now.

I think we'd first need to standardise the CSI-2 bus configuration. I
don't see a practical need to make the lane configuration dynamic. You
could just use a lower frequency to achieve the same if you really need to.

Ideally it might be nice to do but there's really nothing I know that
required or even benefited from it --- at least for now.

>> +
>> +	if (!lanes) {
>> +		dev_err(isp->dev, "no lane configuration\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	cam_phy_ctrl = omap_readl(
>> +		OMAP343X_CTRL_BASE + OMAP3630_CONTROL_CAMERA_PHY_CTRL);
>> +	/*
>> +	 * SCM.CONTROL_CAMERA_PHY_CTRL
>> +	 * - bit[4]    : CSIPHY1 data sent to CSIB
>> +	 * - bit [3:2] : CSIPHY1 config: 00 d-phy, 01/10 ccp2
>> +	 * - bit [1:0] : CSIPHY2 config: 00 d-phy, 01/10 ccp2
>> +	 */
>> +	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1)
>> +		cam_phy_ctrl |= 1 << 2;
>> +	else if (subdevs->interface == ISP_INTERFACE_CSI2C_PHY1)
>> +		cam_phy_ctrl &= 1 << 2;
>> +
>> +	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
>> +		cam_phy_ctrl |= 1;
>> +	else if (subdevs->interface == ISP_INTERFACE_CSI2A_PHY2)
>> +		cam_phy_ctrl &= 1;
>> +
>> +	/* FIXME: Do 34xx / 35xx require something here? */
>> +	if (cpu_is_omap3630())
>> +		omap_writel(cam_phy_ctrl,
>> +			    OMAP343X_CTRL_BASE
>> +			    + OMAP3630_CONTROL_CAMERA_PHY_CTRL);
> 
> You use cam_phy_ctrl inside the if statement only, you can move its 
> computation there.

Will fix.

>> +
>> +	csi2_ddrclk_khz = sensor_fmt->pixelrate
>> +		/ (2 * csi2->phy->num_data_lanes)
>> +		* omap3isp_video_format_info(sensor_fmt->code)->bpp;
>> +
>> +	/*
>> +	 * THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1.
>> +	 * THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3.
>> +	 */
>> +	csi2phy.ths_term = DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1;
>> +	csi2phy.ths_settle = DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3;
>> +	csi2phy.tclk_term = TCLK_TERM;
>> +	csi2phy.tclk_miss = TCLK_MISS;
>> +	csi2phy.tclk_settle = TCLK_SETTLE;
>>
>>  	/* Clock and data lanes verification */
>> -	for (i = 0; i < phy->num_data_lanes; i++) {
>> +	for (i = 0; i < csi2->phy->num_data_lanes; i++) {
>>  		if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
>>  			return -EINVAL;
>>
>> @@ -162,10 +227,10 @@ static int csiphy_config(struct isp_csiphy *phy,
>>  	if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
>>  		return -EINVAL;
>>
>> -	mutex_lock(&phy->mutex);
>> -	phy->dphy = *dphy;
>> -	phy->lanes = *lanes;
>> -	mutex_unlock(&phy->mutex);
>> +	mutex_lock(&csi2->phy->mutex);
>> +	csi2->phy->dphy = csi2phy;
>> +	csi2->phy->lanes = *lanes;
>> +	mutex_unlock(&csi2->phy->mutex);
>>
>>  	return 0;
>>  }
>> @@ -225,8 +290,6 @@ int omap3isp_csiphy_init(struct isp_device *isp)
>>  	struct isp_csiphy *phy1 = &isp->isp_csiphy1;
>>  	struct isp_csiphy *phy2 = &isp->isp_csiphy2;
>>
>> -	isp->platform_cb.csiphy_config = csiphy_config;
>> -
>>  	phy2->isp = isp;
>>  	phy2->csi2 = &isp->isp_csi2a;
>>  	phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES;
>> diff --git a/drivers/media/video/omap3isp/ispcsiphy.h
>> b/drivers/media/video/omap3isp/ispcsiphy.h index e93a661..9f93222 100644
>> --- a/drivers/media/video/omap3isp/ispcsiphy.h
>> +++ b/drivers/media/video/omap3isp/ispcsiphy.h
>> @@ -56,6 +56,10 @@ struct isp_csiphy {
>>  	struct isp_csiphy_dphy_cfg dphy;
>>  };
>>
>> +int omap3isp_csiphy_config(struct isp_device *isp,
>> +			   struct v4l2_subdev *csi2_subdev,
>> +			   struct v4l2_subdev *sensor,
>> +			   struct v4l2_mbus_framefmt *fmt);
>>  int omap3isp_csiphy_acquire(struct isp_csiphy *phy);
>>  void omap3isp_csiphy_release(struct isp_csiphy *phy);
>>  int omap3isp_csiphy_init(struct isp_device *isp);
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 17/17] rm680: Add camera init
  2012-01-06 14:58   ` Sylwester Nawrocki
@ 2012-01-07 22:59     ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07 22:59 UTC (permalink / raw)
  To: Sylwester Nawrocki; +Cc: linux-media, laurent.pinchart, dacohen

Hi Sylwester,

Thanks for the review!

Sylwester Nawrocki wrote:
> On 12/20/2011 09:28 PM, Sakari Ailus wrote:
>> +
>> +static int rm680_sec_camera_set_xshutdown(struct v4l2_subdev *subdev,
>> u8 set)
> 
> It may be more efficient to just use u32.

The function got removed already. ;-)

>> +{
>> +    gpio_set_value(SEC_CAMERA_RESET_GPIO, !!set);
>> +    return 0;
>> +}
>> +
> ...
>> +void __init rm680_camera_init(void)
>> +{
>> +    struct isp_platform_data *pdata;
>> +    int rval;
>> +
>> +    rval = rm680_camera_hw_init();
>> +    if (rval) {
>> +        printk(KERN_WARNING "%s: unable to initialise camera\n",
> 
> pr_warn is preferred for new code.

Fixed.

>> +               __func__);
>> +        return;
>> +    }
>> +
>> +    if (board_is_rm680())
>> +        pdata =&rm680_isp_platform_data;
>> +    else
>> +        pdata =&rm696_isp_platform_data;
>> +
>> +    if (omap3_init_camera(pdata)<  0)
>> +        printk(KERN_WARNING
> 
> pr_warn

Ditto.

>> +               "%s: unable to register camera platform device\n",
>> +               __func__);
>> +}
> ...
>> +static struct regulator_consumer_supply rm680_vaux2_consumers[] = {
>> +    REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"),    /* OMAP ISP */
>> +    REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"),    /* OMAP ISP */
>> +    {
>> +        .supply        = "vaux2",
>> +    },
> 
> Could also be
>     REGULATOR_SUPPLY("vaux2", NULL),

Fixed.

>> +};
>> +REGULATOR_INIT_DATA_FIXED(rm680_vaux2, 1800000);
>> +
>> +static struct regulator_consumer_supply rm680_vaux3_consumers[] = {
>> +    REGULATOR_SUPPLY("VANA", "2-0037"),    /* Main Camera Sensor */
>> +    REGULATOR_SUPPLY("VANA", "2-000e"),    /* Main Camera Lens */
>> +    REGULATOR_SUPPLY("VANA", "2-0010"),    /* Front Camera */
>> +    {
>> +        .supply        = "vaux3",
>> +    },
> 
> and     REGULATOR_SUPPLY("vaux3", NULL),

Ditto.

>> +};
> 
> -- 
> Regards,
> Sylwester
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 16/17] smiapp: Add driver.
  2012-01-06 17:12   ` Sylwester Nawrocki
@ 2012-01-07 23:01     ` Sakari Ailus
  2012-01-16 21:57       ` Sylwester Nawrocki
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07 23:01 UTC (permalink / raw)
  To: Sylwester Nawrocki; +Cc: linux-media, laurent.pinchart, dacohen

Hi Sylwester,

Thanks for the review!!!

Sylwester Nawrocki wrote:
> Hi Sakari,
> 
> I have a just a few comments below. It was rather brief a review, given the
> size of the patch.. :-)

Good points. I'll make the changes, as well as those Laurent pointed
out, and send a new version of the driver. I expect I'll be able to do
that early next week.

> On 12/20/2011 09:28 PM, Sakari Ailus wrote:
>> Add driver for SMIA++/SMIA image sensors. The driver exposes the sensor as
>> three subdevs, pixel array, binner and scaler --- in case the device has a
>> scaler.
>>
>> Currently it relies on the board code for external clock handling. There is
>> no fast way out of this dependency before the ISP drivers (omap3isp) among
>> others will be able to export that clock through the clock framework
>> instead.
>>
>> Signed-off-by: Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>
>> ---
>>   drivers/media/video/Kconfig           |   13 +
>>   drivers/media/video/Makefile          |    3 +
>>   drivers/media/video/smiapp-core.c     | 2595 +++++++++++++++++++++++++++++++++
>>   drivers/media/video/smiapp-debug.h    |   32 +
>>   drivers/media/video/smiapp-limits.c   |  132 ++
>>   drivers/media/video/smiapp-limits.h   |  128 ++
>>   drivers/media/video/smiapp-pll.c      |  664 +++++++++
>>   drivers/media/video/smiapp-quirk.c    |  264 ++++
>>   drivers/media/video/smiapp-quirk.h    |   72 +
>>   drivers/media/video/smiapp-reg-defs.h |  733 ++++++++++
>>   drivers/media/video/smiapp-reg.h      |  119 ++
>>   drivers/media/video/smiapp-regs.c     |  222 +++
>>   drivers/media/video/smiapp.h          |  250 ++++
>>   include/media/smiapp-regs.h           |   51 +
>>   include/media/smiapp.h                |   82 +
>>   15 files changed, 5360 insertions(+), 0 deletions(-)
>>   create mode 100644 drivers/media/video/smiapp-core.c
>>   create mode 100644 drivers/media/video/smiapp-debug.h
>>   create mode 100644 drivers/media/video/smiapp-limits.c
>>   create mode 100644 drivers/media/video/smiapp-limits.h
>>   create mode 100644 drivers/media/video/smiapp-pll.c
>>   create mode 100644 drivers/media/video/smiapp-quirk.c
>>   create mode 100644 drivers/media/video/smiapp-quirk.h
>>   create mode 100644 drivers/media/video/smiapp-reg-defs.h
>>   create mode 100644 drivers/media/video/smiapp-reg.h
>>   create mode 100644 drivers/media/video/smiapp-regs.c
>>   create mode 100644 drivers/media/video/smiapp.h
> 
> How about creating new directory, e.g. drivers/media/video/smiapp/ ? 

Good question. When I started working on this, I just had a few files
which didn't justify creating a new directory. I think you're right; now
it's time for that.

>>   create mode 100644 include/media/smiapp-regs.h
>>   create mode 100644 include/media/smiapp.h
>>
>> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
>> index 4e8a0c4..0aa8f13 100644
>> --- a/drivers/media/video/Kconfig
>> +++ b/drivers/media/video/Kconfig
>> @@ -524,6 +524,19 @@ config VIDEO_S5K6AA
>>   	  This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
>>   	  camera sensor with an embedded SoC image signal processor.
>>
>> +config VIDEO_SMIAPP
>> +	tristate "SMIA++/SMIA sensor support"
>> +	depends on I2C&&  VIDEO_V4L2
> 
> There is no dependency on VIDEO_V4L2_SUBDEV_API ?

Yes, there is.

>> +	---help---
>> +	  This is a generic driver for SMIA++/SMIA camera modules.
>> +
>> +config VIDEO_SMIAPP_DEBUG
>> +	bool "Enable debugging for the generic SMIA++/SMIA driver"
>> +	depends on VIDEO_SMIAPP
>> +	---help---
>> +	  Enable debugging output in the generic SMIA++/SMIA driver. If you
>> +	  are developing the driver you might want to enable this.
>> +
>>   comment "Flash devices"
>>
>>   config VIDEO_ADP1653
>> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
>> index ddeaa6c..82a0cea 100644
>> --- a/drivers/media/video/Makefile
>> +++ b/drivers/media/video/Makefile
>> @@ -73,6 +73,9 @@ obj-$(CONFIG_VIDEO_SR030PC30)	+= sr030pc30.o
>>   obj-$(CONFIG_VIDEO_NOON010PC30)	+= noon010pc30.o
>>   obj-$(CONFIG_VIDEO_M5MOLS)	+= m5mols/
>>   obj-$(CONFIG_VIDEO_S5K6AA)	+= s5k6aa.o
>> +smiapp-objs			+= smiapp-core.o smiapp-regs.o smiapp-pll.o \
>> +				   smiapp-quirk.o smiapp-limits.o
>> +obj-$(CONFIG_VIDEO_SMIAPP)	+= smiapp.o
>>   obj-$(CONFIG_VIDEO_ADP1653)	+= adp1653.o
>>
>>   obj-$(CONFIG_SOC_CAMERA_IMX074)		+= imx074.o
>> diff --git a/drivers/media/video/smiapp-core.c b/drivers/media/video/smiapp-core.c
>> new file mode 100644
>> index 0000000..1d15c1d
>> --- /dev/null
>> +++ b/drivers/media/video/smiapp-core.c
>> @@ -0,0 +1,2595 @@
>> +/*
>> + * drivers/media/video/smiapp-core.c
>> + *
>> + * Generic driver for SMIA/SMIA++ compliant camera modules
>> + *
>> + * Copyright (C) 2010--2011 Nokia Corporation
>> + * Contact: Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>
>> + *
>> + * Based on smiapp driver by Vimarsh Zutshi
>> + * Based on jt8ev1.c by Vimarsh Zutshi
>> + * Based on smia-sensor.c by Tuukka Toivonen<tuukkat76@gmail.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
>> + * 02110-1301 USA
>> + *
>> + */
>> +
>> +#include "smiapp-debug.h"
>> +
>> +#include<linux/delay.h>
>> +#include<linux/device.h>
>> +#include<linux/module.h>
>> +#include<linux/regulator/consumer.h>
>> +#include<linux/v4l2-mediabus.h>
>> +#include<media/v4l2-device.h>
>> +
>> +#include "smiapp.h"
>> +
>> +#define SMIAPP_ALIGN_DIM(dim, flags)	      \
>> +	(flags&  V4L2_SUBDEV_SEL_FLAG_SIZE_GE \
>> +	 ? ALIGN(dim, 2)		      \
>> +	 : dim&  ~1)
>> +
>> +/*
>> + * smiapp_module_idents - supported camera modules
>> + */
>> +static const struct smiapp_module_ident smiapp_module_idents[] = {
>> +	SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1",&smiapp_jt8ev1_quirk),
>> +	SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es",&smiapp_imx125es_quirk),
>> +	SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"),
>> +	SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"),
>> +	SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"),
>> +	SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md",&smiapp_tcm8500md_quirk),
>> +	SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"),
>> +	SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"),
>> +	SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9",&smiapp_jt8ew9_quirk),
>> +	SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"),
>> +	SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"),
>> +};
>> +
>> +/*
>> + *
>> + * Dynamic Capability Identification
>> + *
>> + */
>> +
> [...]
>> +/*
>> + *
>> + * V4L2 Controls handling
>> + *
>> + */
>> +
>> +static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
>> +{
>> +	struct v4l2_ctrl *ctrl = sensor->exposure;
>> +	int max;
>> +
>> +	max = sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].height
>> +		+ sensor->vblank->val -
>> +		sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
>> +
>> +	ctrl->maximum = max;
>> +	if (ctrl->default_value>  max)
>> +		ctrl->default_value = max;
>> +	if (ctrl->val>  max)
>> +		ctrl->val = max;
>> +	if (ctrl->cur.val>  max)
>> +		ctrl->cur.val = max;
>> +}
> 
> One more driver that needs control value range update. :)

:-)

Are there other drivers that would need something like that, too?
Anything in the control framework that I have missed related to this?

>> +
> [...]
>> +
>> +#define SCALING_GOODNESS		100000
>> +#define SCALING_GOODNESS_EXTREME	100000000
> 
> Interesting parameter.. :)
> 
>> +static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
>> +			    int h, int ask_h, u32 flags)
>> +{
>> +	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
>> +	struct i2c_client *client = v4l2_get_subdevdata(subdev);
>> +	int val = 0;
>> +
>> +	w&= ~1;
>> +	ask_w&= ~1;
>> +	h&= ~1;
>> +	ask_h&= ~1;
>> +
>> +	if (flags&  V4L2_SUBDEV_SEL_FLAG_SIZE_GE) {
>> +		if (w<  ask_w)
>> +			val -= SCALING_GOODNESS;
>> +		if (h<  ask_h)
>> +			val -= SCALING_GOODNESS;
>> +	}
>> +
>> +	if (flags&  V4L2_SUBDEV_SEL_FLAG_SIZE_LE) {
>> +		if (w>  ask_w)
>> +			val -= SCALING_GOODNESS;
>> +		if (h>  ask_h)
>> +			val -= SCALING_GOODNESS;
>> +	}
>> +
>> +	val -= abs(w - ask_w);
>> +	val -= abs(h - ask_h);
>> +
>> +	if (w<  sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
>> +		val -= SCALING_GOODNESS_EXTREME;
>> +
>> +	dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
>> +		w, ask_h, h, ask_h, val);
>> +
>> +	return val;
>> +}
>> +
> [...]
>> +static int smiapp_set_selection(struct v4l2_subdev *subdev,
>> +				struct v4l2_subdev_fh *fh,
>> +				struct v4l2_subdev_selection *sel)
>> +{
>> +	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
>> +	struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
>> +	struct v4l2_rect *comps, *crops;
>> +	int ret;
>> +
>> +	ret = __smiapp_sel_supported(subdev, sel);
>> +	if (ret)
>> +		return ret;
>> +
>> +	sel->r.left = sel->r.left&  ~1;
>> +	sel->r.top = sel->r.top&  ~1;
>> +	sel->r.width = SMIAPP_ALIGN_DIM(sel->r.width, sel->flags);
>> +	sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags);
>> +
>> +	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
>> +		crops = ssd->crop;
>> +		comps = ssd->compose;
>> +	} else {
>> +		crops = fh->try_crop;
>> +		comps = fh->try_compose;
>> +	}
>> +
>> +	sel->r.left&= ~1;
>> +	sel->r.top&= ~1;
>> +	sel->r.width&= ~1;
>> +	sel->r.height&= ~1;
>> +
>> +	sel->r.left = max(0, sel->r.left);
>> +	sel->r.top = max(0, sel->r.top);
>> +	sel->r.width = max(0, sel->r.width);
>> +	sel->r.height = max(0, sel->r.height);
>> +
>> +	sel->r.width = max_t(unsigned int,
>> +			     sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
>> +			     sel->r.width);
>> +	sel->r.height = max_t(unsigned int,
>> +			      sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
>> +			      sel->r.height);
>> +
>> +	switch (sel->target) {
>> +	case V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE:
>> +		return smiapp_set_crop(subdev, fh, sel);
>> +	case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE:
>> +		return smiapp_set_compose(subdev, fh, sel);
>> +	}
>> +
>> +	BUG();
>> +}
>> +
>> +static int smiapp_validate_pipeline(struct v4l2_subdev *subdev)
>> +{
>> +	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
>> +	struct smiapp_subdev *ssds[] = {
>> +		sensor->scaler, sensor->binner, sensor->pixel_array };
>> +	int i;
>> +	struct smiapp_subdev *last = NULL;
>> +
>> +	if (sensor->src->crop[SMIAPP_PAD_SOURCE].width
>> +	<  sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
>> +		return -EPIPE;
>> +	if (sensor->src->crop[SMIAPP_PAD_SOURCE].height
>> +	<  sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE])
>> +		return -EPIPE;
>> +
>> +	for (i = 0; i<  SMIAPP_SUBDEVS; i++) {
>> +		struct smiapp_subdev *this = ssds[i];
>> +
>> +		if (!this)
>> +			continue;
>> +
>> +		if (!last) {
>> +			last = this;
>> +			continue;
>> +		}
>> +
>> +		if (last->sink_fmt.width
>> +		    != this->compose[SMIAPP_PAD_SOURCE].width)
>> +			return -EPIPE;
>> +		if (last->sink_fmt.height
>> +		    != this->compose[SMIAPP_PAD_SOURCE].height)
>> +			return -EPIPE;
>> +
>> +		last = this;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
> [...]
>> +
>> +static int __init smiapp_init(void)
>> +{
>> +	int rval;
>> +
>> +	rval = i2c_add_driver(&smiapp_i2c_driver);
>> +	if (rval)
>> +		printk(KERN_ERR "Failed registering driver" SMIAPP_NAME "\n");
> 
> Using pr_<level> is expected for new drivers.

Fixed.

>> +
>> +	return rval;
>> +}
>> +
>> +static void __exit smiapp_exit(void)
>> +{
>> +	i2c_del_driver(&smiapp_i2c_driver);
>> +}
>> +
>> +module_init(smiapp_init);
>> +module_exit(smiapp_exit);
>> +
>> +MODULE_AUTHOR("Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>");
>> +MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver");
>> +MODULE_LICENSE("GPL");
> 
> [...]
>> +/*
>> + * Write to a 8/16-bit register.
>> + * Returns zero if successful, or non-zero otherwise.
>> + */
>> +int smia_i2c_write_reg(struct i2c_client *client, u32 reg, u32 val)
>> +{
>> +	struct i2c_msg msg[1];
>> +	unsigned char data[6];
>> +	unsigned int retries = 5;
>> +	unsigned int flags = reg>>  24;
>> +	unsigned int len = (u8)(reg>>  16);
>> +	u16 offset = reg;
>> +	int r;
>> +
>> +	if (!client->adapter)
>> +		return -ENODEV;
>> +
>> +	if ((len != SMIA_REG_8BIT&&  len != SMIA_REG_16BIT&&
>> +	     len != SMIA_REG_32BIT) || flags)
>> +		return -EINVAL;
>> +
>> +	smia_i2c_create_msg(client, len, offset, val, msg, data);
>> +
>> +	do {
>> +		/*
>> +		 * Due to unknown reason sensor stops responding. This
>> +		 * loop is a temporaty solution until the root cause
>> +		 * is found.
>> +		 */
>> +		r = i2c_transfer(client->adapter, msg, 1);
>> +		if (r>= 0)
>> +			break;
> 
> I think r == 0 indicates failure (0 messages transferred), it's probably
> never returned in that case though. It might be better to test for r == 1.

Fixed. By doing so one must make sure that when an error is encountered,
a negative error code will be returned.

>> +
>> +		usleep_range(2000, 2000);
>> +	} while (retries--);
>> +
>> +	if (r<  0)
>> +		dev_err(&client->dev,
>> +			"wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
>> +	else
>> +		r = 0; /* on success i2c_transfer() return messages trasfered */
>> +
>> +	if (retries<  5)
>> +		dev_err(&client->dev, "sensor i2c stall encountered. "
>> +			"retries: %d\n", 5 - retries);
>> +
>> +	return r;
>> +}
> [...]
>> diff --git a/include/media/smiapp-regs.h b/include/media/smiapp-regs.h
>> new file mode 100644
>> index 0000000..3109b02
>> --- /dev/null
>> +++ b/include/media/smiapp-regs.h
>> @@ -0,0 +1,51 @@
>> +/*
>> + * include/media/smiapp-regs.h
>> + *
>> + * Generic driver for SMIA/SMIA++ compliant camera modules
>> + *
>> + * Copyright (C) 2011 Nokia Corporation
>> + * Contact: Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
>> + * 02110-1301 USA
>> + *
>> + */
>> +
>> +#ifndef SMIAPP_REGS_H
>> +#define SMIAPP_REGS_H
>> +
>> +#include<linux/i2c.h>
>> +#include<linux/types.h>
> 
>> +#include<linux/videodev2.h>
>> +#include<linux/v4l2-subdev.h>
> 
> Are these two headers really needed ?
> 
>> +
>> +struct v4l2_mbus_framefmt;
>> +struct v4l2_subdev_pad_mbus_code_enum;
> 
> Also these 2 lines seem redundant.

Removed both. I think they're remnants from the time this header file
used to contain something else as well.

>> +
>> +/* Use upper 8 bits of the type field for flags */
>> +#define SMIA_REG_FLAG_FLOAT		(1<<  24)
>> +
>> +#define SMIA_REG_8BIT			1
>> +#define SMIA_REG_16BIT			2
>> +#define SMIA_REG_32BIT			4
>> +struct smia_reg {
>> +	u16 type;
>> +	u16 reg;			/* 16-bit offset */
>> +	u32 val;			/* 8/16/32-bit value */
>> +};
>> +
>> +int smia_i2c_read_reg(struct i2c_client *client, u32 reg, u32 *val);
>> +int smia_i2c_write_reg(struct i2c_client *client, u32 reg, u32 val);
>> +
>> +#endif
>> diff --git a/include/media/smiapp.h b/include/media/smiapp.h
>> new file mode 100644
>> index 0000000..b302570
>> --- /dev/null
>> +++ b/include/media/smiapp.h
>> @@ -0,0 +1,82 @@
>> +/*
>> + * include/media/smiapp.h
>> + *
>> + * Generic driver for SMIA/SMIA++ compliant camera modules
>> + *
>> + * Copyright (C) 2011 Nokia Corporation
>> + * Contact: Sakari Ailus<sakari.ailus@maxwell.research.nokia.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
>> + * 02110-1301 USA
>> + *
>> + */
>> +
>> +#ifndef __SMIAPP_H_
>> +#define __SMIAPP_H_
>> +
>> +#include<media/smiapp-regs.h>
>> +#include<media/v4l2-subdev.h>
>> +
>> +#define SMIAPP_NAME		"smiapp"
>> +
>> +#define SMIAPP_DFL_I2C_ADDR	(0x20>>  1) /* Default I2C Address */
>> +#define SMIAPP_ALT_I2C_ADDR	(0x6e>>  1) /* Alternate I2C Address */
>> +
>> +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK	0
>> +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE	1
>> +#define SMIAPP_CSI_SIGNALLING_MODE_CSI2			2
>> +
>> +/*
>> + * Sometimes due to board layout considerations the camera module can be
>> + * mounted rotated. The typical rotation used is 180 degrees which can be
>> + * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
>> + * FIXME: rotation also changes the bayer pattern.
>> + */
>> +enum smiapp_module_board_orient {
>> +	SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
>> +	SMIAPP_MODULE_BOARD_ORIENT_180,
>> +};
>> +
>> +struct smiapp_flash_strobe_parms {
>> +	u8 mode;
>> +	u32 strobe_width_high_us;
>> +	u16 strobe_delay;
>> +	u16 stobe_start_point;
>> +	u8 trigger;
>> +};
>> +
>> +struct smiapp_platform_data {
>> +	/*
>> +	 * Change the cci address if i2c_addr_alt is set.
>> +	 * Both default and alternate cci addr need to be present
>> +	 */
>> +	unsigned short i2c_addr_dfl;	/* Default i2c addr */
>> +	unsigned short i2c_addr_alt;	/* Alternate i2c addr */
>> +
>> +	unsigned int nvm_size;			/* bytes */
>> +	unsigned int ext_clk;			/* sensor external clk */
>> +
>> +	unsigned int lanes;		/* Number of CSI-2 lanes */
>> +	u8 csi_signalling_mode;		/* SMIAPP_CSI_SIGNALLING_MODE_* */
>> +	const s64 *op_sys_clock;
>> +
>> +	enum smiapp_module_board_orient module_board_orient;
>> +
>> +	struct smiapp_flash_strobe_parms *strobe_setup;
>> +
>> +	int (*set_xclk)(struct v4l2_subdev *sd, int hz);
>> +	int (*set_xshutdown)(struct v4l2_subdev *sd, u8 set);
> 
> There is no chance to avoid this callback, e.g. by passing GPIO(s) number(s)
> directly to the driver ?

I think Laurent also commented that. Yes, I'll fix that. We won't get
completely rid of these callbacks until we can have the generic clock
framework so we could control the ISP external clock to the sensor using
the regular clk_* functions.

>> +};
>> +
>> +#endif /* __SMIAPP_H_  */

Cheers,

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 14/17] omap3isp: Use pixelrate from sensor media bus frameformat
  2012-01-06 10:14   ` Laurent Pinchart
@ 2012-01-07 23:05     ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07 23:05 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> On Tuesday 20 December 2011 21:28:06 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Configure the ISP based on the pixelrate in media bus frame format.
>> Previously the same was configured from the board code.
>>
>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>> ---
>>  drivers/media/video/omap3isp/isp.c |   24 +++++++++++++++++++++---
>>  drivers/media/video/omap3isp/isp.h |    1 -
>>  2 files changed, 21 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/media/video/omap3isp/isp.c
>> b/drivers/media/video/omap3isp/isp.c index 6020fd7..92f9716 100644
>> --- a/drivers/media/video/omap3isp/isp.c
>> +++ b/drivers/media/video/omap3isp/isp.c
>> @@ -749,10 +749,14 @@ static int isp_pipeline_enable(struct isp_pipeline
>> *pipe,
>>
>>  	entity = &pipe->output->video.entity;
>>  	while (1) {
>> -		pad = &entity->pads[0];
>> -		if (!(pad->flags & MEDIA_PAD_FL_SINK))
>> +		/*
>> +		 * Is this an external subdev connected to us? If so,
>> +		 * we're done.
>> +		 */
>> +		if (subdev && subdev->host_priv)
>>  			break;
> 
> This doesn't seem to be related to the patch title. Should it be moved to a 
> separate patch ? You could also move the check to the bottom of the while 
> loop, it would allow you to remove the first part of the condition as subdev 
> will always be non-NULL then (or even possible as the while() condition).

The change got removed based on your other suggestions. ;-) The CSI-2
configuration moved to csi2_set_stream, so a lot of cruft got removed
from here.

>> +		pad = &entity->pads[0];
>>  		pad = media_entity_remote_source(pad);
>>  		if (pad == NULL ||
>>  		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
>> @@ -762,6 +766,21 @@ static int isp_pipeline_enable(struct isp_pipeline
>> *pipe, prev_subdev = subdev;
>>  		subdev = media_entity_to_v4l2_subdev(entity);
>>
>> +		/* Configure CCDC pixel clock */
>> +		if (subdev->host_priv) {
>> +			struct v4l2_subdev_format fmt;
>> +
>> +			fmt.pad = pad->index;
>> +			fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
>> +			ret = v4l2_subdev_call(subdev, pad, get_fmt,
>> +					       NULL, &fmt);
>> +			if (ret < 0)
>> +				return -EINVAL;
>> +
>> +			isp_set_pixel_clock(isp,
>> +					    fmt.format.pixelrate * 1000);
>> +		}
>> +
>>  		/* Configure CSI-2 receiver based on sensor format. */
>>  		if (prev_subdev == &isp->isp_csi2a.subdev
>>
>>  		    || prev_subdev == &isp->isp_csi2c.subdev) {
>>
>> @@ -2102,7 +2121,6 @@ static int isp_probe(struct platform_device *pdev)
>>
>>  	isp->autoidle = autoidle;
>>  	isp->platform_cb.set_xclk = isp_set_xclk;
>> -	isp->platform_cb.set_pixel_clock = isp_set_pixel_clock;
>>
>>  	mutex_init(&isp->isp_mutex);
>>  	spin_lock_init(&isp->stat_lock);
>> diff --git a/drivers/media/video/omap3isp/isp.h
>> b/drivers/media/video/omap3isp/isp.h index c5935ae..7d73a39 100644
>> --- a/drivers/media/video/omap3isp/isp.h
>> +++ b/drivers/media/video/omap3isp/isp.h
>> @@ -126,7 +126,6 @@ struct isp_reg {
>>
>>  struct isp_platform_callback {
>>  	u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
>> -	void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
>>  };
>>
>>  /*
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 09/17] v4l: Add pad op for pipeline validation
  2012-01-06  9:42   ` Laurent Pinchart
@ 2012-01-07 23:28     ` Sakari Ailus
  2012-01-08 18:20       ` Laurent Pinchart
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07 23:28 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Thanks for the review!!

Laurent Pinchart wrote:
> On Tuesday 20 December 2011 21:28:01 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> smiapp_pad_ops.validate_pipeline is intended to validate the full pipeline
>> which is implemented by the driver to which the subdev implementing this op
>> belongs to.
> 
> Should this be documented in Documentation/video4linux/v4l2-framework.txt ?
> 
>> The validate_pipeline op must also call validate_pipeline on any external
>> entity which is linked to its sink pads.
> 
> I'm uncertain about this. Subdev drivers would then have to implement the 
> pipeline walk logic, resulting in duplicate code. Our current situation isn't 
> optimal either: walking the pipeline should be implemented in the media code. 
> Would it suit your needs if the validate_pipeline operation was replaced by a 
> validate_link operation, with a media_pipeline_validate() function in the 
> media core to walk the pipeline and call validate_link in each pad (or maybe 
> each sink pad) ?

Albeit I don't see the pipeline checking a big problem in the subdev
drivers, that does seem like a viable alternative --- it's definitely
more generic. Any benefit of that is directly bound to the existence of
generic pipeline validation function, which definitely shouldn't be too
difficult to write.

It is also true that in practice, I assume, considering the pipeline
validation inside subdev drivers, the SMIA++ driver is almost as complex
any sensor driver will get in the near future. But once a practice has
been established it's difficult to change that.

I'm for validate_link() op.

I assume that in the implementation the Media controller framework would
walk the pipeline and call entity specific link_validate() ops. We
already have link_setup() op there. Those would, in turn, check that the
link requirements are fulfilled. How does that sound like to you?

Regards,

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 12/17] omap3isp: Add lane configuration to platform data
  2012-01-06 10:06   ` Laurent Pinchart
@ 2012-01-07 23:39     ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-07 23:39 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> On Tuesday 20 December 2011 21:28:04 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Add lane configuration (order of clock and data lane) to platform data on
>> both CCP2 and CSI-2.
>>
>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>> ---
>>  drivers/media/video/omap3isp/ispcsiphy.h |   15 ++-------------
>>  include/media/omap3isp.h                 |   15 +++++++++++++++
>>  2 files changed, 17 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/media/video/omap3isp/ispcsiphy.h
>> b/drivers/media/video/omap3isp/ispcsiphy.h index 9596dc6..e93a661 100644
>> --- a/drivers/media/video/omap3isp/ispcsiphy.h
>> +++ b/drivers/media/video/omap3isp/ispcsiphy.h
>> @@ -27,22 +27,11 @@
>>  #ifndef OMAP3_ISP_CSI_PHY_H
>>  #define OMAP3_ISP_CSI_PHY_H
>>
>> +#include <media/omap3isp.h>
>> +
>>  struct isp_csi2_device;
>>  struct regulator;
>>
>> -struct csiphy_lane {
>> -	u8 pos;
>> -	u8 pol;
>> -};
>> -
>> -#define ISP_CSIPHY2_NUM_DATA_LANES	2
>> -#define ISP_CSIPHY1_NUM_DATA_LANES	1
>> -
>> -struct isp_csiphy_lanes_cfg {
>> -	struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
>> -	struct csiphy_lane clk;
>> -};
>> -
>>  struct isp_csiphy_dphy_cfg {
>>  	u8 ths_term;
>>  	u8 ths_settle;
>> diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
>> index e917b1d..8fe0bdf 100644
>> --- a/include/media/omap3isp.h
>> +++ b/include/media/omap3isp.h
>> @@ -86,6 +86,19 @@ enum {
>>  	ISP_CCP2_MODE_CCP2 = 1,
>>  };
>>
>> +struct csiphy_lane {
>> +	u8 pos;
>> +	u8 pol;
>> +};
>> +
>> +#define ISP_CSIPHY2_NUM_DATA_LANES	2
>> +#define ISP_CSIPHY1_NUM_DATA_LANES	1
>> +
>> +struct isp_csiphy_lanes_cfg {
>> +	struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
>> +	struct csiphy_lane clk;
>> +};
> 
> Could you please document the two structures using kerneldoc ?

Done.

>> +
>>  /**
>>   * struct isp_ccp2_platform_data - CCP2 interface platform data
>>   * @strobe_clk_pol: Strobe/clock polarity
>> @@ -105,6 +118,7 @@ struct isp_ccp2_platform_data {
>>  	unsigned int ccp2_mode:1;
>>  	unsigned int phy_layer:1;
>>  	unsigned int vpclk_div:2;
>> +	struct isp_csiphy_lanes_cfg *lanecfg;
> 
> Lane configuration is mandatory, what about embedding struct 
> isp_csiphy_lanes_cfg inside struct isp_ccp2_platform instead of having a 
> pointer ?

Done.

>>  };
>>
>>  /**
>> @@ -115,6 +129,7 @@ struct isp_ccp2_platform_data {
>>  struct isp_csi2_platform_data {
>>  	unsigned crc:1;
>>  	unsigned vpclk_div:2;
>> +	struct isp_csiphy_lanes_cfg *lanecfg;
> 
> Same here.

Ditto.

>>  };
>>
>>  struct isp_subdev_i2c_board_info {
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2012-01-07 22:51     ` Sakari Ailus
@ 2012-01-08  1:02       ` Laurent Pinchart
  2012-01-08 10:26         ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-08  1:02 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

On Saturday 07 January 2012 23:51:24 Sakari Ailus wrote:
> Laurent Pinchart wrote:
> > On Tuesday 20 December 2011 21:28:05 Sakari Ailus wrote:
> >> From: Sakari Ailus <sakari.ailus@iki.fi>
> >> 
> >> Configure CSI-2 phy based on platform data in the ISP driver rather than
> >> in platform code.
> >> 
> >> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>

[snip]

> >> diff --git a/drivers/media/video/omap3isp/ispcsiphy.c
> >> b/drivers/media/video/omap3isp/ispcsiphy.c index 5be37ce..f027ece 100644
> >> --- a/drivers/media/video/omap3isp/ispcsiphy.c
> >> +++ b/drivers/media/video/omap3isp/ispcsiphy.c
> >> @@ -28,6 +28,8 @@
> >> 
> >>  #include <linux/device.h>
> >>  #include <linux/regulator/consumer.h>
> >> 
> >> +#include "../../../../arch/arm/mach-omap2/control.h"
> >> +
> > 
> > #include <mach/control.h>
> > 
> > (untested) ?
> 
> I'm afraid it won't work. The above directory isn't in any include path
> and likely shouldn't be. That file is included locally elsewhere, I
> believe.

You're right, I spoke too fast.

> I wonder what would be the right way to access that register definition
> I need from the file:
> 
> 	OMAP343X_CTRL_BASE
> 	OMAP3630_CONTROL_CAMERA_PHY_CTRL

Maybe the file (or part of it) should be moved to an include directory ?

> >>  #include "isp.h"
> >>  #include "ispreg.h"
> >>  #include "ispcsiphy.h"
> >> 
> >> @@ -138,15 +140,78 @@ static void csiphy_dphy_config(struct isp_csiphy
> >> *phy) isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
> >> 
> >>  }
> >> 
> >> -static int csiphy_config(struct isp_csiphy *phy,
> >> -			 struct isp_csiphy_dphy_cfg *dphy,
> >> -			 struct isp_csiphy_lanes_cfg *lanes)
> >> +/*
> >> + * TCLK values are OK at their reset values
> >> + */
> >> +#define TCLK_TERM	0
> >> +#define TCLK_MISS	1
> >> +#define TCLK_SETTLE	14
> >> +
> >> +int omap3isp_csiphy_config(struct isp_device *isp,
> >> +			   struct v4l2_subdev *csi2_subdev,
> >> +			   struct v4l2_subdev *sensor,
> >> +			   struct v4l2_mbus_framefmt *sensor_fmt)
> >> 
> >>  {
> >> 
> >> +	struct isp_v4l2_subdevs_group *subdevs = sensor->host_priv;
> >> +	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(csi2_subdev);
> >> +	struct isp_csiphy_dphy_cfg csi2phy;
> >> +	int csi2_ddrclk_khz;
> >> +	struct isp_csiphy_lanes_cfg *lanes;
> >> 
> >>  	unsigned int used_lanes = 0;
> >>  	unsigned int i;
> >> 
> >> +	u32 cam_phy_ctrl;
> >> +
> >> +	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1
> >> +	    || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
> >> +		lanes = subdevs->bus.ccp2.lanecfg;
> >> +	else
> >> +		lanes = subdevs->bus.csi2.lanecfg;
> > 
> > Shouldn't lane configuration be retrieved from the sensor instead ?
> > Sensors could use different lane configuration depending on the mode.
> > This could also be implemented later when needed, but I don't think it
> > would be too difficult to get it right now.
> 
> I think we'd first need to standardise the CSI-2 bus configuration. I
> don't see a practical need to make the lane configuration dynamic. You
> could just use a lower frequency to achieve the same if you really need to.
> 
> Ideally it might be nice to do but there's really nothing I know that
> required or even benefited from it --- at least for now.

Does this mean that lane configuration needs to be duplicated in board code, 
on for the SMIA++ platform data and one of the OMAP3 ISP platform data ?

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2012-01-08  1:02       ` Laurent Pinchart
@ 2012-01-08 10:26         ` Sakari Ailus
  2012-01-08 11:07           ` Sylwester Nawrocki
  2012-01-08 11:15           ` Laurent Pinchart
  0 siblings, 2 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-08 10:26 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> Hi Sakari,
> 
> On Saturday 07 January 2012 23:51:24 Sakari Ailus wrote:
>> Laurent Pinchart wrote:
>>> On Tuesday 20 December 2011 21:28:05 Sakari Ailus wrote:
>>>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>>>
>>>> Configure CSI-2 phy based on platform data in the ISP driver rather than
>>>> in platform code.
>>>>
>>>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> 
> [snip]
> 
>>>> diff --git a/drivers/media/video/omap3isp/ispcsiphy.c
>>>> b/drivers/media/video/omap3isp/ispcsiphy.c index 5be37ce..f027ece 100644
>>>> --- a/drivers/media/video/omap3isp/ispcsiphy.c
>>>> +++ b/drivers/media/video/omap3isp/ispcsiphy.c
>>>> @@ -28,6 +28,8 @@
>>>>
>>>>  #include <linux/device.h>
>>>>  #include <linux/regulator/consumer.h>
>>>>
>>>> +#include "../../../../arch/arm/mach-omap2/control.h"
>>>> +
>>>
>>> #include <mach/control.h>
>>>
>>> (untested) ?
>>
>> I'm afraid it won't work. The above directory isn't in any include path
>> and likely shouldn't be. That file is included locally elsewhere, I
>> believe.
> 
> You're right, I spoke too fast.
> 
>> I wonder what would be the right way to access that register definition
>> I need from the file:
>>
>> 	OMAP343X_CTRL_BASE
>> 	OMAP3630_CONTROL_CAMERA_PHY_CTRL
> 
> Maybe the file (or part of it) should be moved to an include directory ?

Yes, but which one?

>>>>  #include "isp.h"
>>>>  #include "ispreg.h"
>>>>  #include "ispcsiphy.h"
>>>>
>>>> @@ -138,15 +140,78 @@ static void csiphy_dphy_config(struct isp_csiphy
>>>> *phy) isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
>>>>
>>>>  }
>>>>
>>>> -static int csiphy_config(struct isp_csiphy *phy,
>>>> -			 struct isp_csiphy_dphy_cfg *dphy,
>>>> -			 struct isp_csiphy_lanes_cfg *lanes)
>>>> +/*
>>>> + * TCLK values are OK at their reset values
>>>> + */
>>>> +#define TCLK_TERM	0
>>>> +#define TCLK_MISS	1
>>>> +#define TCLK_SETTLE	14
>>>> +
>>>> +int omap3isp_csiphy_config(struct isp_device *isp,
>>>> +			   struct v4l2_subdev *csi2_subdev,
>>>> +			   struct v4l2_subdev *sensor,
>>>> +			   struct v4l2_mbus_framefmt *sensor_fmt)
>>>>
>>>>  {
>>>>
>>>> +	struct isp_v4l2_subdevs_group *subdevs = sensor->host_priv;
>>>> +	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(csi2_subdev);
>>>> +	struct isp_csiphy_dphy_cfg csi2phy;
>>>> +	int csi2_ddrclk_khz;
>>>> +	struct isp_csiphy_lanes_cfg *lanes;
>>>>
>>>>  	unsigned int used_lanes = 0;
>>>>  	unsigned int i;
>>>>
>>>> +	u32 cam_phy_ctrl;
>>>> +
>>>> +	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1
>>>> +	    || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
>>>> +		lanes = subdevs->bus.ccp2.lanecfg;
>>>> +	else
>>>> +		lanes = subdevs->bus.csi2.lanecfg;
>>>
>>> Shouldn't lane configuration be retrieved from the sensor instead ?
>>> Sensors could use different lane configuration depending on the mode.
>>> This could also be implemented later when needed, but I don't think it
>>> would be too difficult to get it right now.
>>
>> I think we'd first need to standardise the CSI-2 bus configuration. I
>> don't see a practical need to make the lane configuration dynamic. You
>> could just use a lower frequency to achieve the same if you really need to.
>>
>> Ideally it might be nice to do but there's really nothing I know that
>> required or even benefited from it --- at least for now.
> 
> Does this mean that lane configuration needs to be duplicated in board code, 
> on for the SMIA++ platform data and one of the OMAP3 ISP platform data ?

It's mostly the number of lanes, and the polarity --- in theory it is
possible to invert the signals on the bus, albeit I'm not sure if anyone
does that; I can't see a reason for that, but hey, I don't know why it's
possible to specify polarity either. :-)

If both sides support mapping of the lanes, a mapping that matches on
both sides has to be provided.

I agree we should standardise the configuration of CSI-2 as well as the
configuration of other busses. However, I would prefer to do that later
on since I'm already depending on a number of other patches on the
SMIA++ driver.

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2012-01-08 10:26         ` Sakari Ailus
@ 2012-01-08 11:07           ` Sylwester Nawrocki
  2012-01-08 11:16             ` Sakari Ailus
  2012-01-08 11:15           ` Laurent Pinchart
  1 sibling, 1 reply; 76+ messages in thread
From: Sylwester Nawrocki @ 2012-01-08 11:07 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Laurent Pinchart, linux-media, dacohen, Guennadi Liakhovetski

Hi,

On 01/08/2012 11:26 AM, Sakari Ailus wrote:
>>>> Shouldn't lane configuration be retrieved from the sensor instead ?
>>>> Sensors could use different lane configuration depending on the mode.
>>>> This could also be implemented later when needed, but I don't think it
>>>> would be too difficult to get it right now.
>>>
>>> I think we'd first need to standardise the CSI-2 bus configuration. I
>>> don't see a practical need to make the lane configuration dynamic. You
>>> could just use a lower frequency to achieve the same if you really need to.
>>>
>>> Ideally it might be nice to do but there's really nothing I know that
>>> required or even benefited from it --- at least for now.
>>
>> Does this mean that lane configuration needs to be duplicated in board code, 
>> on for the SMIA++ platform data and one of the OMAP3 ISP platform data ?
> 
> It's mostly the number of lanes, and the polarity --- in theory it is
> possible to invert the signals on the bus, albeit I'm not sure if anyone
> does that; I can't see a reason for that, but hey, I don't know why it's
> possible to specify polarity either. :-)

I've never seen polarity configuration option in any datasheet, neither
MIPI CSI-2 or D-PHY mentions that. Does OMAP3 ISP really allow MIPI-CSI
lane signal polarity configuration ? MIPI-CSI2 uses differential signals
after all. What would be a point of changing polarity ?

> If both sides support mapping of the lanes, a mapping that matches on
> both sides has to be provided.

In Samsung SoC (both sensor and host interface) I've seen only possibility
to configure the number of data lanes, FWIW I think it is assumed that
when you use e.g. 2 data lanes always lane1 and lane2 are utilised for
transmission, for 3 lanes - lane 1,2,3, etc. Also I've never seen on
schematics that someone wires data lane3 and lane4 when only 2 lanes
are utilised, so this makes me wonder if the lane mapping is ever needed.

Has anyone different experience with that ?

Also the standard seem to specify that Data1+ lane at a transmitter(Tx) is
connected to Data1+ lane at a receiver(Rx), Data1-(Tx) to Data1-(Rx),
Data2+(Tx) to Data2+(Rx), etc. I think this is needed due to explicitly
defined data distribution and merging scheme among the lanes, i.e. to allow
interworking of various receivers and transmitters.

Thus it seems all we need need is just a number of data lanes used.

> I agree we should standardise the configuration of CSI-2 as well as the
> configuration of other busses. However, I would prefer to do that later
> on since I'm already depending on a number of other patches on the
> SMIA++ driver.

--

Regards,
Sylwester

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2012-01-08 10:26         ` Sakari Ailus
  2012-01-08 11:07           ` Sylwester Nawrocki
@ 2012-01-08 11:15           ` Laurent Pinchart
  1 sibling, 0 replies; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-08 11:15 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

On Sunday 08 January 2012 11:26:02 Sakari Ailus wrote:
> Laurent Pinchart wrote:
> > On Saturday 07 January 2012 23:51:24 Sakari Ailus wrote:
> >> Laurent Pinchart wrote:
> >>> On Tuesday 20 December 2011 21:28:05 Sakari Ailus wrote:
> >>>> From: Sakari Ailus <sakari.ailus@iki.fi>
> >>>> 
> >>>> Configure CSI-2 phy based on platform data in the ISP driver rather
> >>>> than in platform code.
> >>>> 
> >>>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> > 
> > [snip]
> > 
> >>>> diff --git a/drivers/media/video/omap3isp/ispcsiphy.c
> >>>> b/drivers/media/video/omap3isp/ispcsiphy.c index 5be37ce..f027ece
> >>>> 100644 --- a/drivers/media/video/omap3isp/ispcsiphy.c
> >>>> +++ b/drivers/media/video/omap3isp/ispcsiphy.c
> >>>> @@ -28,6 +28,8 @@
> >>>> 
> >>>>  #include <linux/device.h>
> >>>>  #include <linux/regulator/consumer.h>
> >>>> 
> >>>> +#include "../../../../arch/arm/mach-omap2/control.h"
> >>>> +
> >>> 
> >>> #include <mach/control.h>
> >>> 
> >>> (untested) ?
> >> 
> >> I'm afraid it won't work. The above directory isn't in any include path
> >> and likely shouldn't be. That file is included locally elsewhere, I
> >> believe.
> > 
> > You're right, I spoke too fast.
> > 
> >> I wonder what would be the right way to access that register definition
> >> 
> >> I need from the file:
> >> 	OMAP343X_CTRL_BASE
> >> 	OMAP3630_CONTROL_CAMERA_PHY_CTRL
> > 
> > Maybe the file (or part of it) should be moved to an include directory ?
> 
> Yes, but which one?

Good question. The content of control.h doesn't seem to have been meant to be 
exported. Maybe you should ask on linux-omap@vger.kernel.org ?

> >>>>  #include "isp.h"
> >>>>  #include "ispreg.h"
> >>>>  #include "ispcsiphy.h"
> >>>> 
> >>>> @@ -138,15 +140,78 @@ static void csiphy_dphy_config(struct isp_csiphy
> >>>> *phy) isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
> >>>> 
> >>>>  }
> >>>> 
> >>>> -static int csiphy_config(struct isp_csiphy *phy,
> >>>> -			 struct isp_csiphy_dphy_cfg *dphy,
> >>>> -			 struct isp_csiphy_lanes_cfg *lanes)
> >>>> +/*
> >>>> + * TCLK values are OK at their reset values
> >>>> + */
> >>>> +#define TCLK_TERM	0
> >>>> +#define TCLK_MISS	1
> >>>> +#define TCLK_SETTLE	14
> >>>> +
> >>>> +int omap3isp_csiphy_config(struct isp_device *isp,
> >>>> +			   struct v4l2_subdev *csi2_subdev,
> >>>> +			   struct v4l2_subdev *sensor,
> >>>> +			   struct v4l2_mbus_framefmt *sensor_fmt)
> >>>> 
> >>>>  {
> >>>> 
> >>>> +	struct isp_v4l2_subdevs_group *subdevs = sensor->host_priv;
> >>>> +	struct isp_csi2_device *csi2 = v4l2_get_subdevdata(csi2_subdev);
> >>>> +	struct isp_csiphy_dphy_cfg csi2phy;
> >>>> +	int csi2_ddrclk_khz;
> >>>> +	struct isp_csiphy_lanes_cfg *lanes;
> >>>> 
> >>>>  	unsigned int used_lanes = 0;
> >>>>  	unsigned int i;
> >>>> 
> >>>> +	u32 cam_phy_ctrl;
> >>>> +
> >>>> +	if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1
> >>>> +	    || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2)
> >>>> +		lanes = subdevs->bus.ccp2.lanecfg;
> >>>> +	else
> >>>> +		lanes = subdevs->bus.csi2.lanecfg;
> >>> 
> >>> Shouldn't lane configuration be retrieved from the sensor instead ?
> >>> Sensors could use different lane configuration depending on the mode.
> >>> This could also be implemented later when needed, but I don't think it
> >>> would be too difficult to get it right now.
> >> 
> >> I think we'd first need to standardise the CSI-2 bus configuration. I
> >> don't see a practical need to make the lane configuration dynamic. You
> >> could just use a lower frequency to achieve the same if you really need
> >> to.
> >> 
> >> Ideally it might be nice to do but there's really nothing I know that
> >> required or even benefited from it --- at least for now.
> > 
> > Does this mean that lane configuration needs to be duplicated in board
> > code, on for the SMIA++ platform data and one of the OMAP3 ISP platform
> > data ?
> 
> It's mostly the number of lanes, and the polarity --- in theory it is
> possible to invert the signals on the bus, albeit I'm not sure if anyone
> does that; I can't see a reason for that, but hey, I don't know why it's
> possible to specify polarity either. :-)
> 
> If both sides support mapping of the lanes, a mapping that matches on
> both sides has to be provided.
> 
> I agree we should standardise the configuration of CSI-2 as well as the
> configuration of other busses. However, I would prefer to do that later
> on since I'm already depending on a number of other patches on the
> SMIA++ driver.

OK.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2012-01-08 11:07           ` Sylwester Nawrocki
@ 2012-01-08 11:16             ` Sakari Ailus
  2012-01-08 13:09               ` Sylwester Nawrocki
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-08 11:16 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: Laurent Pinchart, linux-media, dacohen, Guennadi Liakhovetski

Hi Sylwester,

Sylwester Nawrocki wrote:
> Hi,
> 
> On 01/08/2012 11:26 AM, Sakari Ailus wrote:
>>>>> Shouldn't lane configuration be retrieved from the sensor instead ?
>>>>> Sensors could use different lane configuration depending on the mode.
>>>>> This could also be implemented later when needed, but I don't think it
>>>>> would be too difficult to get it right now.
>>>>
>>>> I think we'd first need to standardise the CSI-2 bus configuration. I
>>>> don't see a practical need to make the lane configuration dynamic. You
>>>> could just use a lower frequency to achieve the same if you really need to.
>>>>
>>>> Ideally it might be nice to do but there's really nothing I know that
>>>> required or even benefited from it --- at least for now.
>>>
>>> Does this mean that lane configuration needs to be duplicated in board code, 
>>> on for the SMIA++ platform data and one of the OMAP3 ISP platform data ?
>>
>> It's mostly the number of lanes, and the polarity --- in theory it is
>> possible to invert the signals on the bus, albeit I'm not sure if anyone
>> does that; I can't see a reason for that, but hey, I don't know why it's
>> possible to specify polarity either. :-)
> 
> I've never seen polarity configuration option in any datasheet, neither
> MIPI CSI-2 or D-PHY mentions that. Does OMAP3 ISP really allow MIPI-CSI
> lane signal polarity configuration ? MIPI-CSI2 uses differential signals
> after all. What would be a point of changing polarity ?

I don't know. It's also the same for CSI-1 on OMAP 3.

This is actually one of the issues here: also device specific
configuration is required. The standard configuration must contain
probably at least what the spec defines.

>> If both sides support mapping of the lanes, a mapping that matches on
>> both sides has to be provided.
> 
> In Samsung SoC (both sensor and host interface) I've seen only possibility
> to configure the number of data lanes, FWIW I think it is assumed that
> when you use e.g. 2 data lanes always lane1 and lane2 are utilised for
> transmission, for 3 lanes - lane 1,2,3, etc. Also I've never seen on
> schematics that someone wires data lane3 and lane4 when only 2 lanes
> are utilised, so this makes me wonder if the lane mapping is ever needed.
> 
> Has anyone different experience with that ?
> 
> Also the standard seem to specify that Data1+ lane at a transmitter(Tx) is
> connected to Data1+ lane at a receiver(Rx), Data1-(Tx) to Data1-(Rx),
> Data2+(Tx) to Data2+(Rx), etc. I think this is needed due to explicitly
> defined data distribution and merging scheme among the lanes, i.e. to allow
> interworking of various receivers and transmitters.
> 
> Thus it seems all we need need is just a number of data lanes used.

The standard of course specifies that the data lanes must be connected
correctly. :-) It can't specify which SoC pins do they use, so for added
flexibility it's good to be able to reorder them.

Have you ever worked with single-layer PCBs by any chance? :-) More
layers are used these days but it still doesn't solve all possible issues.

So I think I can say reordering generally must be supported by software
if the hardware can do that.

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2012-01-08 11:16             ` Sakari Ailus
@ 2012-01-08 13:09               ` Sylwester Nawrocki
  2012-01-11  8:08                 ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Sylwester Nawrocki @ 2012-01-08 13:09 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Laurent Pinchart, linux-media, dacohen, Guennadi Liakhovetski

Hi Sakari,

On 01/08/2012 12:16 PM, Sakari Ailus wrote:
>>>>>> Shouldn't lane configuration be retrieved from the sensor instead ?
>>>>>> Sensors could use different lane configuration depending on the mode.
>>>>>> This could also be implemented later when needed, but I don't think it
>>>>>> would be too difficult to get it right now.
>>>>>
>>>>> I think we'd first need to standardise the CSI-2 bus configuration. I
>>>>> don't see a practical need to make the lane configuration dynamic. You
>>>>> could just use a lower frequency to achieve the same if you really need to.
>>>>>
>>>>> Ideally it might be nice to do but there's really nothing I know that
>>>>> required or even benefited from it --- at least for now.
>>>>
>>>> Does this mean that lane configuration needs to be duplicated in board code, 
>>>> on for the SMIA++ platform data and one of the OMAP3 ISP platform data ?
>>>
>>> It's mostly the number of lanes, and the polarity --- in theory it is
>>> possible to invert the signals on the bus, albeit I'm not sure if anyone
>>> does that; I can't see a reason for that, but hey, I don't know why it's
>>> possible to specify polarity either. :-)

I think it just enables to swap D+ and D- functions on the physical pins.

>> I've never seen polarity configuration option in any datasheet, neither
>> MIPI CSI-2 or D-PHY mentions that. Does OMAP3 ISP really allow MIPI-CSI
>> lane signal polarity configuration ? MIPI-CSI2 uses differential signals
>> after all. What would be a point of changing polarity ?
> 
> I don't know. It's also the same for CSI-1 on OMAP 3.
> 
> This is actually one of the issues here: also device specific
> configuration is required. The standard configuration must contain
> probably at least what the spec defines.
> 
>>> If both sides support mapping of the lanes, a mapping that matches on
>>> both sides has to be provided.
>>
>> In Samsung SoC (both sensor and host interface) I've seen only possibility
>> to configure the number of data lanes, FWIW I think it is assumed that
>> when you use e.g. 2 data lanes always lane1 and lane2 are utilised for
>> transmission, for 3 lanes - lane 1,2,3, etc. Also I've never seen on
>> schematics that someone wires data lane3 and lane4 when only 2 lanes
>> are utilised, so this makes me wonder if the lane mapping is ever needed.
>>
>> Has anyone different experience with that ?
>>
>> Also the standard seem to specify that Data1+ lane at a transmitter(Tx) is
>> connected to Data1+ lane at a receiver(Rx), Data1-(Tx) to Data1-(Rx),
>> Data2+(Tx) to Data2+(Rx), etc. I think this is needed due to explicitly
>> defined data distribution and merging scheme among the lanes, i.e. to allow
>> interworking of various receivers and transmitters.
>>
>> Thus it seems all we need need is just a number of data lanes used.
> 
> The standard of course specifies that the data lanes must be connected
> correctly. :-) It can't specify which SoC pins do they use, so for added
> flexibility it's good to be able to reorder them.
> 
> Have you ever worked with single-layer PCBs by any chance? :-) More
> layers are used these days but it still doesn't solve all possible issues.

Yes, I have. I know what you mean. It just seemed uncommon to me to reorder
the signals. But since H/W doing that exists..and that might become more
widely used in the future it might make sense to standardize lane
configuration.

> So I think I can say reordering generally must be supported by software
> if the hardware can do that.

Yes, however there is always a board specific information involved, isn't it ?
I.e. transmitter can reorder signals between its pins, the same can happen at
a receiver and additionally the transmitter's pins can be connected differently
to the receiver pins, depending on the board ?

Then do we make board specific information part of sensor's or host platform
data ? It probably should be at both, let's take an evaluation and a camera
daughter boards as an example.

We also need device tree bindings for that, if possible the best would be to
design common bindings, at least basic ones, to which device specific ones
could be added.

--
Regards,
Sylwester

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 09/17] v4l: Add pad op for pipeline validation
  2012-01-07 23:28     ` Sakari Ailus
@ 2012-01-08 18:20       ` Laurent Pinchart
  0 siblings, 0 replies; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-08 18:20 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

On Sunday 08 January 2012 00:28:40 Sakari Ailus wrote:
> Laurent Pinchart wrote:
> > On Tuesday 20 December 2011 21:28:01 Sakari Ailus wrote:
> >> From: Sakari Ailus <sakari.ailus@iki.fi>
> >> 
> >> smiapp_pad_ops.validate_pipeline is intended to validate the full
> >> pipeline which is implemented by the driver to which the subdev
> >> implementing this op belongs to.
> > 
> > Should this be documented in Documentation/video4linux/v4l2-framework.txt
> > ?
> > 
> >> The validate_pipeline op must also call validate_pipeline on any
> >> external entity which is linked to its sink pads.
> > 
> > I'm uncertain about this. Subdev drivers would then have to implement the
> > pipeline walk logic, resulting in duplicate code. Our current situation
> > isn't optimal either: walking the pipeline should be implemented in the
> > media code. Would it suit your needs if the validate_pipeline operation
> > was replaced by a validate_link operation, with a
> > media_pipeline_validate() function in the media core to walk the
> > pipeline and call validate_link in each pad (or maybe each sink pad) ?
> 
> Albeit I don't see the pipeline checking a big problem in the subdev
> drivers, that does seem like a viable alternative --- it's definitely
> more generic. Any benefit of that is directly bound to the existence of
> generic pipeline validation function, which definitely shouldn't be too
> difficult to write.
> 
> It is also true that in practice, I assume, considering the pipeline
> validation inside subdev drivers, the SMIA++ driver is almost as complex
> any sensor driver will get in the near future. But once a practice has
> been established it's difficult to change that.
> 
> I'm for validate_link() op.
> 
> I assume that in the implementation the Media controller framework would
> walk the pipeline and call entity specific link_validate() ops. We
> already have link_setup() op there. Those would, in turn, check that the
> link requirements are fulfilled. How does that sound like to you?

That sounds good to me. If the operation isn't implemented, the core should 
just make sure that code, width and height are identical on the two ends of 
the link. That will be the usual requirement, checking it in the core will 
make drivers simpler.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 05/17] v4l: Support s_crop and g_crop through s/g_selection
  2012-01-05 16:13   ` Laurent Pinchart
@ 2012-01-08 20:54     ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-08 20:54 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thanks for the patch.
> 
> On Tuesday 20 December 2011 21:27:57 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Revert to s_selection if s_crop isn't implemented by a driver. Same for
>> g_selection / g_crop.
> 
> Shouldn't this say "Fall back" instead of "Revert" ?

Fixed all issues you mentioned in this e-mail.

>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>> ---
>>  drivers/media/video/v4l2-subdev.c |   37
>> +++++++++++++++++++++++++++++++++++-- 1 files changed, 35 insertions(+), 2
>> deletions(-)
>>
>> diff --git a/drivers/media/video/v4l2-subdev.c
>> b/drivers/media/video/v4l2-subdev.c index e8ae098..f8de551 100644
>> --- a/drivers/media/video/v4l2-subdev.c
>> +++ b/drivers/media/video/v4l2-subdev.c
>> @@ -226,6 +226,8 @@ static long subdev_do_ioctl(struct file *file, unsigned
>> int cmd, void *arg)
>>
>>  	case VIDIOC_SUBDEV_G_CROP: {
>>  		struct v4l2_subdev_crop *crop = arg;
>> +		struct v4l2_subdev_selection sel;
>> +		int rval;
>>
>>  		if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
>>  		    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
>> @@ -234,11 +236,27 @@ static long subdev_do_ioctl(struct file *file,
>> unsigned int cmd, void *arg) if (crop->pad >= sd->entity.num_pads)
>>  			return -EINVAL;
>>
>> -		return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
>> +		rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
>> +		if (rval != -ENOIOCTLCMD)
>> +			return rval;
>> +
>> +		memset(&sel, 0, sizeof(sel));
>> +		sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> 
> Shouldn't sel.which be set to crop->which ?
> 
>> +		sel.pad = crop->pad;
>> +		sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE;
>> +
>> +		rval = v4l2_subdev_call(
>> +			sd, pad, get_selection, subdev_fh, &sel);
>> +
>> +		crop->rect = sel.r;
>> +
>> +		return rval;
>>  	}
>>
>>  	case VIDIOC_SUBDEV_S_CROP: {
>>  		struct v4l2_subdev_crop *crop = arg;
>> +		struct v4l2_subdev_selection sel;
>> +		int rval;
>>
>>  		if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
>>  		    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
>> @@ -247,7 +265,22 @@ static long subdev_do_ioctl(struct file *file,
>> unsigned int cmd, void *arg) if (crop->pad >= sd->entity.num_pads)
>>  			return -EINVAL;
>>
>> -		return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
>> +		rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
>> +		if (rval != -ENOIOCTLCMD)
>> +			return rval;
>> +
>> +		memset(&sel, 0, sizeof(sel));
>> +		sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> 
> Same here.
> 
>> +		sel.pad = crop->pad;
>> +		sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE;
>> +		sel.r = crop->rect;
>> +
>> +		rval = v4l2_subdev_call(
>> +			sd, pad, set_selection, subdev_fh, &sel);
>> +
>> +		crop->rect = sel.r;
>> +
>> +		return rval;
>>  	}
>>
>>  	case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 07/17] v4l: Add pixelrate to struct v4l2_mbus_framefmt
  2012-01-06 10:26   ` Laurent Pinchart
@ 2012-01-08 21:16     ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-08 21:16 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> On Tuesday 20 December 2011 21:27:59 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Pixelrate is an essential part of the image data parameters. Add this.
>> Together, the current parameters also define the frame rate.
>>
>> Sensors do not have a concept of frame rate; pixelrate is much more
>> meaningful in this context. Also, it is best to combine the pixelrate with
>> the other format parameters since there are dependencies between them.
>>
>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>> ---
>>  Documentation/DocBook/media/v4l/subdev-formats.xml |   10 +++++++++-
>>  include/linux/v4l2-mediabus.h                      |    4 +++-
>>  2 files changed, 12 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml
>> b/Documentation/DocBook/media/v4l/subdev-formats.xml index
>> 49c532e..a6a6630 100644
>> --- a/Documentation/DocBook/media/v4l/subdev-formats.xml
>> +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml
>> @@ -35,7 +35,15 @@
>>  	</row>
>>  	<row>
>>  	  <entry>__u32</entry>
>> -	  <entry><structfield>reserved</structfield>[7]</entry>
>> +	  <entry><structfield>pixelrate</structfield></entry>
>> +	  <entry>Pixel rate in kp/s.
> 
> kPix/s or kPixel/s ?

Hmm. kilo-pixels / second?

Albeit I have to say I'm increasingly inclined to think this field
doesn't really belong to this struct --- we should discuss that tomorrow.

There are two things this is needed in the user space:

1) To calculate detailed hardware timing information.

2) To figure out whether streaming is possible, or to figure out why it
failed in case it did.

And in kernel space:

1) To configure devices. The OMAP 3 ISP CSI-2 receiver and CCDC blocks
must be configured based on the pixel rate.

2) Validate pipeline pixel rate for each subdev. Some subdevs require it
to be withint limits. A good example is the OMAP 3 ISP where most blocks
have 100 Mp/s maximum whereas the CSI-2 receiver has 200 Mp/s maximum.

This could be implemented using pad-specific controls. In drivers the
subdev in sink end of the link would get the controls from the source.

>> This clock is the maximum rate at
> 
> Is it really a clock ?
> 
>> +	  which pixels are transferred on the bus. The
>> +	  <structfield>pixelrate</structfield> field is
>> +	  read-only.</entry>
> 
> Does that mean that userspace isn't required to propagate the value down the 
> pipeline when configuring it ? I'm fine with that, but it should probably be 
> documented explictly somewhere to make sure that drivers don't rely on it.
> 
>> +	</row>
>> +	<row>
>> +	  <entry>__u32</entry>
>> +	  <entry><structfield>reserved</structfield>[6]</entry>
>>  	  <entry>Reserved for future extensions. Applications and drivers must
>>  	  set the array to zero.</entry>
>>  	</row>
>> diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
>> index 5ea7f75..35c6b96 100644
>> --- a/include/linux/v4l2-mediabus.h
>> +++ b/include/linux/v4l2-mediabus.h
>> @@ -101,6 +101,7 @@ enum v4l2_mbus_pixelcode {
>>   * @code:	data format code (from enum v4l2_mbus_pixelcode)
>>   * @field:	used interlacing type (from enum v4l2_field)
>>   * @colorspace:	colorspace of the data (from enum v4l2_colorspace)
>> + * @pixel_clock: pixel clock, in kHz
> 
> I think you forgot to update the comment.
> 
>>   */
>>  struct v4l2_mbus_framefmt {
>>  	__u32			width;
>> @@ -108,7 +109,8 @@ struct v4l2_mbus_framefmt {
>>  	__u32			code;
>>  	__u32			field;
>>  	__u32			colorspace;
>> -	__u32			reserved[7];
>> +	__u32			pixelrate;
>> +	__u32			reserved[6];
>>  };
>>
>>  #endif
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 06/17] v4l: Add selections documentation.
  2012-01-06 11:43   ` Laurent Pinchart
@ 2012-01-09 18:16     ` Sakari Ailus
  2012-01-10 11:20       ` Tomasz Stanislawski
  2012-01-15 22:53       ` Laurent Pinchart
  0 siblings, 2 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-09 18:16 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23, Tomasz Stanislawski

Hi Laurent,

Thanks for the comments!

Laurent Pinchart wrote:
> On Tuesday 20 December 2011 21:27:58 Sakari Ailus wrote:
> 
> [snip]
> 
>> diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml
>> b/Documentation/DocBook/media/v4l/dev-subdev.xml index 0916a73..722db60
>> 100644
>> --- a/Documentation/DocBook/media/v4l/dev-subdev.xml
>> +++ b/Documentation/DocBook/media/v4l/dev-subdev.xml
> 
> [snip]
> 
>> @@ -288,26 +288,81 @@
> 
> [snip]
> 
>> +      <para>Scaling operation changes the size of the image by scaling
>> +      it to new dimensions. Some sub-devices support it. The scaled
>> +      size (width and height) is represented by &v4l2-rect;. In the
>> +      case of scaling, top and left will always be zero. Scaling is
>> +      configured using &sub-subdev-g-selection; and
>> +      <constant>V4L2_SUBDEV_SEL_COMPOSE_ACTIVE</constant> selection
>> +      target on the sink pad of the subdev. The scaling is performed
>> +      related to the width and height of the crop rectangle on the
>> +      subdev's sink pad.</para>
>> +
>> +      <para>As for pad formats, drivers store try and active
>> +      rectangles for the selection targets of ACTIVE type <xref
>> +      linkend="v4l2-subdev-selection-targets">.</xref></para>
>> +
>> +      <para>On sink pads, cropping is applied relatively to the
>> +      current pad format. The pad format represents the image size as
>> +      received by the sub-device from the previous block in the
>> +      pipeline, and the crop rectangle represents the sub-image that
>> +      will be transmitted further inside the sub-device for
>> +      processing.</para>
>> +
>> +      <para>On source pads, cropping is similar to sink pads, with the
>> +      exception that the source size from which the cropping is
>> +      performed, is the COMPOSE rectangle on the sink pad. In both
>> +      sink and source pads, the crop rectangle must be entirely
>> +      containted inside the source image size for the crop
>> +      operation.</para>
>> +
>> +      <para>The drivers should always use the closest possible
>> +      rectangle the user requests on all selection targets, unless
>> +      specificly told otherwise<xref
>> +      linkend="v4l2-subdev-selection-flags">.</xref></para>
>> +    </section>
> 
> This sounds a bit confusing to me. One issue is that composing is not formally 
> defined. I think it would help if you could draw a diagram that shows how the 
> operations are applied, and modify the text to describe the diagram, using the 
> natural order of the compose and crop operations on sink and source pads.

I drew a diagram based on your suggestion, but I'd prefer the formal
definition would come from someone who needs composition and better
understands the use cases.

Also cc Tomasz.

>> +    <section>
>> +      <title>Order of configuration and format propagation</title>
>> +
>> +      <para>The order of image processing steps will always be from
>> +      the sink pad towards the source pad. This is also reflected in
>> +      the order in which the configuration must be performed by the
>> +      user. The format is propagated within the subdev along the later
>> +      processing steps. For example, setting the sink pad format
>> +      causes all the selection rectangles and the source pad format to
>> +      be set to sink pad format --- if allowed by the hardware, and if
>> +      not, then closest possible. The coordinates to a step always
>> +      refer to the active size of the previous step.</para>
> 
> This also sounds a bit ambiguous if I try to ignore the fact that I know how 
> it works :-) You should at least make it explicit that propagation inside 
> subdevs is performed by the driver(s), and that propagation outside subdevs is 
> to be handled by userspace.

Agreed. I'll reword it.

>> +      <orderedlist>
>> +	<listitem>Sink pad format. The user configures the sink pad
>> +	format. This format defines the parameters of the image the
>> +	entity receives through the pad for further processing.</listitem>
>>
>> -      <para>Cropping behaviour on output pads is not defined.</para>
>> +	<listitem>Sink pad active crop selection. The sink pad crop
>> +	defines the performed to the sink pad format.</listitem>
>>
>> +	<listitem>Sink pad active compose selection. The sink pad compose
>> +	rectangle defines the scaling ratio compared to the size of
>> +	the sink pad crop rectangle.</listitem>
>> +
>> +	<listitem>Source pad active crop selection. Crop on the source
>> +	pad defines crop performed to the image scaled according to
>> +	the sink pad compose rectangle.</listitem>
>> +
>> +	<listitem>Source pad active compose selection. The source pad
>> +	compose defines the size and location of the compose
>> +	rectangle.</listitem>
>> +
>> +	<listitem>Source pad format. The source pad format defines the
>> +	output pixel format of the subdev, as well as the other
>> +	parameters with the exception of the image width and
>> +	height.</listitem>
>> +
>> +      </orderedlist>
>>      </section>
>> +
>>    </section>
>>
>>    &sub-subdev-formats;
> 
> [snip]
> 
>> diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
>> b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml new file
>> mode 100644
>> index 0000000..5fbcd65
>> --- /dev/null
>> +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
>> @@ -0,0 +1,226 @@
> 
> [snip]
> 
>> +  <refsect1>
>> +    <title>Description</title>
>> +
>> +    <note>
>> +      <title>Experimental</title>
>> +      <para>This is an <link linkend="experimental">experimental</link>
>> +      interface and may change in the future.</para>
>> +    </note>
>> +
>> +    <para>The selections are used to configure various image
>> +    processing functionality performed by the subdevs which affect the
>> +    image size. This currently includes cropping, scaling and
>> +    composition.</para>
>> +
>> +    <para>The selections replace the crop API &sub-subdev-g-crop;. All
>> +    the function of the crop API, and more, are supported by the
>> +    selections API.</para>
>> +
>> +    <para>See <xref linkend="subdev">Sub-device interface</xref> for
>> +    more information on how each selection target affects the image
>> +    processing pipeline inside the subdevice.</para>
>> +
>> +    <section>
>> +      <title>Types of selection targets</title>
>> +
>> +      <para>The are four types of selection targets: active, default,
>> +      bounds and padding. The ACTIVE targets are the targets which
>> +      configure the hardware. The DEFAULT target provides the default
>> +      for the ACTIVE selection. The BOUNDS target will return the
>> +      maximum width and height of the target.
> 
> What about the minimum ?

Good question. We could also specify that the minimum is obtained by
using the V4L2_SUBDEV_SEL_FLAG_LE flag with the BOUNDS target.

>> The PADDED target
>> +      provides the width and height for the padded image,
> 
> Is it valid for both crop and compose rectangles ?

I think all targets are valid for all rectangles. Should I mention that?

The practical use cases may be more limited, though. I wonder if I
should remove the padded targets until we get use cases for them. I
included them for the reason that they also exist in the V4L2.

Tomasz, Sylwester: do you have use for the PADDED targets?

I think we also must define what will be done in cases where crop (on
either sink or source) / scaling / composition is not supported by the
subdev. That's currently undefined. I think it'd be most clear to return
an error code but I'm not sure which one --- EINVAL is an obvious
candidate but that is also returned when the pad is wrong. It looks
still like the best choice to me.

>> and is
>> +      directly affected by the ACTIVE target. The PADDED targets may
>> +      be configurable depending on the hardware.</para>
> 
> If that's configurable drivers will need a way to store it in the file handle.

Good point. I'll add it if we end up defining the padded targets now.

>> +    </section>
>> +
>> +    <table pgwide="1" frame="none" id="v4l2-subdev-selection-targets">
>> +      <title>V4L2 subdev selection targets</title>
>> +      <tgroup cols="3">
>> +        &cs-def;
>> +	<tbody valign="top">
>> +	  <row>
>> +	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_ACTIVE</constant></entry>
>> +	    <entry>0</entry>
>> +	    <entry>Active crop. Defines the cropping
>> +	    performed by the processing step.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_DEFAULT</constant></entry>
>> +	    <entry>1</entry>
>> +	    <entry>Default crop rectangle.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS</constant></entry>
>> +	    <entry>2</entry>
>> +	    <entry>Bounds of the crop rectangle.</entry>
>> +	  </row>
>> +	  <row>
>> +	   
>> <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTIVE</constant></entry> +	 
>>   <entry>256</entry>
>> +	    <entry>Active compose rectangle. Used to configure scaling
>> +	    on sink pads and composition on source pads.</entry>
>> +	  </row>
>> +	  <row>
>> +	   
>> <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_DEFAULT</constant></entry> +	
>>    <entry>257</entry>
>> +	    <entry>Default compose rectangle.</entry>
>> +	  </row>
>> +	  <row>
>> +	   
>> <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS</constant></entry> +	 
>>   <entry>258</entry>
>> +	    <entry>Bounds of the compose rectangle.</entry>
>> +	  </row>
>> +	</tbody>
>> +      </tgroup>
>> +    </table>
>> +
>> +    <table pgwide="1" frame="none" id="v4l2-subdev-selection-flags">
>> +      <title>V4L2 subdev selection flags</title>
>> +      <tgroup cols="3">
>> +        &cs-def;
>> +	<tbody valign="top">
>> +	  <row>
>> +	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant></entry>
>> +	    <entry>(1 &lt;&lt; 0)</entry>
>> +	    <entry>Suggest the driver it should choose greater or
>> +	    equal rectangle (in size) than was requested.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant></entry>
>> +	    <entry>(1 &lt;&lt; 1)</entry>
>> +	    <entry>Suggest the driver it should choose lesser or
>> +	    equal rectangle (in size) than was requested.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry><constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant></entry>
>> +	    <entry>(1 &lt;&lt; 2)</entry>
>> +	    <entry>The configuration should not be propagated to any
>> +	    further processing steps. If this flag is not given, the
>> +	    configuration is propagated inside the subdevice to all
>> +	    further processing steps.</entry>
>> +	  </row>
>> +	</tbody>
>> +      </tgroup>
>> +    </table>
>> +
>> +    <table pgwide="1" frame="none" id="v4l2-subdev-selection">
>> +      <title>struct <structname>v4l2_subdev_selection</structname></title>
>> +      <tgroup cols="3">
>> +        &cs-str;
>> +	<tbody valign="top">
>> +	  <row>
>> +	    <entry>__u32</entry>
>> +	    <entry><structfield>which</structfield></entry>
>> +	    <entry>Active or try selection, from
>> +	    &v4l2-subdev-format-whence;.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry>__u32</entry>
>> +	    <entry><structfield>pad</structfield></entry>
>> +	    <entry>Pad number as reported by the media framework.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry>__u32</entry>
>> +	    <entry><structfield>target</structfield></entry>
>> +	    <entry>Target selection rectangle. See
>> +	    <xref linkend="v4l2-subdev-selection-targets">.</xref>.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry>__u32</entry>
>> +	    <entry><structfield>flags</structfield></entry>
>> +	    <entry>Flags. See
>> +	    <xref linkend="v4l2-subdev-selection-flags">.</xref></entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry>&v4l2-rect;</entry>
>> +	    <entry><structfield>rect</structfield></entry>
>> +	    <entry>Crop rectangle boundaries, in pixels.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry>__u32</entry>
>> +	    <entry><structfield>reserved</structfield>[8]</entry>
>> +	    <entry>Reserved for future extensions. Applications and drivers must
>> +	    set the array to zero.</entry>
>> +	  </row>
>> +	</tbody>
>> +      </tgroup>
>> +    </table>
>> +
>> +  </refsect1>
>> +
>> +  <refsect1>
>> +    &return-value;
>> +
>> +    <variablelist>
>> +      <varlistentry>
>> +	<term><errorcode>EBUSY</errorcode></term>
>> +	<listitem>
>> +	  <para>The selection rectangle can't be changed because the
>> +	  pad is currently busy. This can be caused, for instance, by
>> +	  an active video stream on the pad. The ioctl must not be
>> +	  retried without performing another action to fix the problem
>> +	  first. Only returned by
>> +	  <constant>VIDIOC_SUBDEV_S_SELECTION</constant></para>
>> +	</listitem>
>> +      </varlistentry>
>> +      <varlistentry>
>> +	<term><errorcode>EINVAL</errorcode></term>
>> +	<listitem>
>> +	  <para>The &v4l2-subdev-selection;
>> +	  <structfield>pad</structfield> references a non-existing
>> +	  pad, the <structfield>which</structfield> field references a
>> +	  non-existing format, or the selection target is not
>> +	  supported on the given subdev pad.</para>
>> +	</listitem>
>> +      </varlistentry>
>> +    </variablelist>
>> +  </refsect1>
>> +</refentry>
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 06/17] v4l: Add selections documentation.
  2012-01-09 18:16     ` Sakari Ailus
@ 2012-01-10 11:20       ` Tomasz Stanislawski
  2012-01-14 19:04         ` Sakari Ailus
  2012-01-15 22:53       ` Laurent Pinchart
  1 sibling, 1 reply; 76+ messages in thread
From: Tomasz Stanislawski @ 2012-01-10 11:20 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: Laurent Pinchart, linux-media, dacohen, snjw23

Hi Sakari,

> Hi Laurent,
>
> Thanks for the comments!
>
> Laurent Pinchart wrote:
>> On Tuesday 20 December 2011 21:27:58 Sakari Ailus wrote:
>>
>> [snip]
>>
>>> diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml
>>> b/Documentation/DocBook/media/v4l/dev-subdev.xml index 0916a73..722db60
>>> 100644
>>> --- a/Documentation/DocBook/media/v4l/dev-subdev.xml
>>> +++ b/Documentation/DocBook/media/v4l/dev-subdev.xml

[snip]

>>
>> This sounds a bit confusing to me. One issue is that composing is not formally
>> defined. I think it would help if you could draw a diagram that shows how the
>> operations are applied, and modify the text to describe the diagram, using the
>> natural order of the compose and crop operations on sink and source pads.
>
> I drew a diagram based on your suggestion, but I'd prefer the formal
> definition would come from someone who needs composition and better
> understands the use cases.
>
> Also cc Tomasz.
>
>>> +<section>
>>> +<title>Order of configuration and format propagation</title>
>>> +
>>> +<para>The order of image processing steps will always be from
>>> +      the sink pad towards the source pad. This is also reflected in
>>> +      the order in which the configuration must be performed by the
>>> +      user. The format is propagated within the subdev along the later
>>> +      processing steps. For example, setting the sink pad format
>>> +      causes all the selection rectangles and the source pad format to
>>> +      be set to sink pad format --- if allowed by the hardware, and if
>>> +      not, then closest possible. The coordinates to a step always
>>> +      refer to the active size of the previous step.</para>
>>
>> This also sounds a bit ambiguous if I try to ignore the fact that I know how
>> it works :-) You should at least make it explicit that propagation inside
>> subdevs is performed by the driver(s), and that propagation outside subdevs is
>> to be handled by userspace.
>
> Agreed. I'll reword it.
>

[snip]

>>> +<para>The are four types of selection targets: active, default,
>>> +      bounds and padding. The ACTIVE targets are the targets which
>>> +      configure the hardware. The DEFAULT target provides the default
>>> +      for the ACTIVE selection. The BOUNDS target will return the
>>> +      maximum width and height of the target.
>>
>> What about the minimum ?

There are multiple problems with idea of the maximal rectangle because 
one has to provide definition how to compare size of two rectangles. If 
you had to compare rectangles 10x1, 1x10, 5x5 which would you choose as 
the largest? Such problems may appear if HW has width, height and size 
constraints. One encounters similar problem with definition of the 
smallest rectangle. I prefer to define "is larger" as "contains". 
Rectangle 10x10 contains all three overmentioned rectangles therefore it 
is the maximal rectangle. The problem with such a definition is that 
such a rectangle may not be accepted by HW.

>
> Good question. We could also specify that the minimum is obtained by
> using the V4L2_SUBDEV_SEL_FLAG_LE flag with the BOUNDS target.
>

As I remember bounds rectangle is fixed and there is no such a thing as 
minimal/maximal bounds. For V4L2 video node API, the bounds rectangle is 
read-only value describing rectangle that contains all pixels.
Could you describe the use case that utilities minimal bounds rectangle?

>>> The PADDED target
>>> +      provides the width and height for the padded image,
>>
>> Is it valid for both crop and compose rectangles ?
>
> I think all targets are valid for all rectangles. Should I mention that?
>
> The practical use cases may be more limited, though. I wonder if I
> should remove the padded targets until we get use cases for them. I
> included them for the reason that they also exist in the V4L2.
>
> Tomasz, Sylwester: do you have use for the PADDED targets?

S5P-TV and S5P-JPEG (by Andrzej Pietrasiewicz) makes use of PADDED 
target. The padded target is very hardware/application dependent 
parameter. It is defined only for composing targets. Basically it refers 
to all pixels that are modified by the hardware. In S5P-TV the padded 
rectangle is equal to active rectangle. However, if having no good idea 
about padded area, then it is always safe/consistent to make padded 
rectangle equal to bounds one.

>
> I think we also must define what will be done in cases where crop (on
> either sink or source) / scaling / composition is not supported by the
> subdev. That's currently undefined. I think it'd be most clear to return
> an error code but I'm not sure which one --- EINVAL is an obvious
> candidate but that is also returned when the pad is wrong. It looks
> still like the best choice to me.

Maybe one should return EPERM or EACCES if S_SELECTION is called on 
read-only target. Other idea is to introduce V4L2_SEL_FLAG_RDONLY flag 
which is set by VIDIOC_G_SELECTION for a given target. The driver may 
return EINVAL if target is not supported. It would imply that support 
for the target is not implemented in the driver.

Regards,
Tomasz Stanislawski

>
>>> and is
>>> +      directly affected by the ACTIVE target. The PADDED targets may
>>> +      be configurable depending on the hardware.</para>
>>
>> If that's configurable drivers will need a way to store it in the file handle.
>
> Good point. I'll add it if we end up defining the padded targets now.
>
>>> +</section>
>>> +

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 13/17] omap3isp: Configure CSI-2 phy based on platform data
  2012-01-08 13:09               ` Sylwester Nawrocki
@ 2012-01-11  8:08                 ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-11  8:08 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: Laurent Pinchart, linux-media, dacohen, Guennadi Liakhovetski

Hi Sylwester,

Sylwester Nawrocki wrote:
> On 01/08/2012 12:16 PM, Sakari Ailus wrote:
>>>>>>> Shouldn't lane configuration be retrieved from the sensor instead ?
>>>>>>> Sensors could use different lane configuration depending on the mode.
>>>>>>> This could also be implemented later when needed, but I don't think it
>>>>>>> would be too difficult to get it right now.
>>>>>>
>>>>>> I think we'd first need to standardise the CSI-2 bus configuration. I
>>>>>> don't see a practical need to make the lane configuration dynamic. You
>>>>>> could just use a lower frequency to achieve the same if you really need to.
>>>>>>
>>>>>> Ideally it might be nice to do but there's really nothing I know that
>>>>>> required or even benefited from it --- at least for now.
>>>>>
>>>>> Does this mean that lane configuration needs to be duplicated in board code, 
>>>>> on for the SMIA++ platform data and one of the OMAP3 ISP platform data ?
>>>>
>>>> It's mostly the number of lanes, and the polarity --- in theory it is
>>>> possible to invert the signals on the bus, albeit I'm not sure if anyone
>>>> does that; I can't see a reason for that, but hey, I don't know why it's
>>>> possible to specify polarity either. :-)
> 
> I think it just enables to swap D+ and D- functions on the physical pins.

Good thinking. :-) Yeah, it's differential, so yes, I think so too now
that you mention it.

>>> I've never seen polarity configuration option in any datasheet, neither
>>> MIPI CSI-2 or D-PHY mentions that. Does OMAP3 ISP really allow MIPI-CSI
>>> lane signal polarity configuration ? MIPI-CSI2 uses differential signals
>>> after all. What would be a point of changing polarity ?
>>
>> I don't know. It's also the same for CSI-1 on OMAP 3.
>>
>> This is actually one of the issues here: also device specific
>> configuration is required. The standard configuration must contain
>> probably at least what the spec defines.
>>
>>>> If both sides support mapping of the lanes, a mapping that matches on
>>>> both sides has to be provided.
>>>
>>> In Samsung SoC (both sensor and host interface) I've seen only possibility
>>> to configure the number of data lanes, FWIW I think it is assumed that
>>> when you use e.g. 2 data lanes always lane1 and lane2 are utilised for
>>> transmission, for 3 lanes - lane 1,2,3, etc. Also I've never seen on
>>> schematics that someone wires data lane3 and lane4 when only 2 lanes
>>> are utilised, so this makes me wonder if the lane mapping is ever needed.
>>>
>>> Has anyone different experience with that ?
>>>
>>> Also the standard seem to specify that Data1+ lane at a transmitter(Tx) is
>>> connected to Data1+ lane at a receiver(Rx), Data1-(Tx) to Data1-(Rx),
>>> Data2+(Tx) to Data2+(Rx), etc. I think this is needed due to explicitly
>>> defined data distribution and merging scheme among the lanes, i.e. to allow
>>> interworking of various receivers and transmitters.
>>>
>>> Thus it seems all we need need is just a number of data lanes used.
>>
>> The standard of course specifies that the data lanes must be connected
>> correctly. :-) It can't specify which SoC pins do they use, so for added
>> flexibility it's good to be able to reorder them.
>>
>> Have you ever worked with single-layer PCBs by any chance? :-) More
>> layers are used these days but it still doesn't solve all possible issues.
> 
> Yes, I have. I know what you mean. It just seemed uncommon to me to reorder
> the signals. But since H/W doing that exists..and that might become more
> widely used in the future it might make sense to standardize lane
> configuration.

We'll need different mapping configuration for the receiver and the
transmitter, and not all the hardware supports it. It won't be many
bytes, though.

>> So I think I can say reordering generally must be supported by software
>> if the hardware can do that.
> 
> Yes, however there is always a board specific information involved, isn't it ?
> I.e. transmitter can reorder signals between its pins, the same can happen at
> a receiver and additionally the transmitter's pins can be connected differently
> to the receiver pins, depending on the board ?

Exactly. That's the reason, I think, why the hardware does support it.

> Then do we make board specific information part of sensor's or host platform
> data ? It probably should be at both, let's take an evaluation and a camera
> daughter boards as an example.
> 
> We also need device tree bindings for that, if possible the best would be to
> design common bindings, at least basic ones, to which device specific ones
> could be added.

Sounds good to me.

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 06/17] v4l: Add selections documentation.
  2012-01-10 11:20       ` Tomasz Stanislawski
@ 2012-01-14 19:04         ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-14 19:04 UTC (permalink / raw)
  To: Tomasz Stanislawski; +Cc: Laurent Pinchart, linux-media, dacohen, snjw23

Hi Tomasz,

Thanks for your reply.

Tomasz Stanislawski wrote:
>> Laurent Pinchart wrote:
>>> On Tuesday 20 December 2011 21:27:58 Sakari Ailus wrote:
>>>
>>> [snip]
>>>
>>>> diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml
>>>> b/Documentation/DocBook/media/v4l/dev-subdev.xml index 0916a73..722db60
>>>> 100644
>>>> --- a/Documentation/DocBook/media/v4l/dev-subdev.xml
>>>> +++ b/Documentation/DocBook/media/v4l/dev-subdev.xml
> 
> [snip]
> 
>>>
>>> This sounds a bit confusing to me. One issue is that composing is not
>>> formally
>>> defined. I think it would help if you could draw a diagram that shows
>>> how the
>>> operations are applied, and modify the text to describe the diagram,
>>> using the
>>> natural order of the compose and crop operations on sink and source
>>> pads.
>>
>> I drew a diagram based on your suggestion, but I'd prefer the formal
>> definition would come from someone who needs composition and better
>> understands the use cases.
>>
>> Also cc Tomasz.
>>
>>>> +<section>
>>>> +<title>Order of configuration and format propagation</title>
>>>> +
>>>> +<para>The order of image processing steps will always be from
>>>> +      the sink pad towards the source pad. This is also reflected in
>>>> +      the order in which the configuration must be performed by the
>>>> +      user. The format is propagated within the subdev along the later
>>>> +      processing steps. For example, setting the sink pad format
>>>> +      causes all the selection rectangles and the source pad format to
>>>> +      be set to sink pad format --- if allowed by the hardware, and if
>>>> +      not, then closest possible. The coordinates to a step always
>>>> +      refer to the active size of the previous step.</para>
>>>
>>> This also sounds a bit ambiguous if I try to ignore the fact that I
>>> know how
>>> it works :-) You should at least make it explicit that propagation
>>> inside
>>> subdevs is performed by the driver(s), and that propagation outside
>>> subdevs is
>>> to be handled by userspace.
>>
>> Agreed. I'll reword it.
>>
> 
> [snip]
> 
>>>> +<para>The are four types of selection targets: active, default,
>>>> +      bounds and padding. The ACTIVE targets are the targets which
>>>> +      configure the hardware. The DEFAULT target provides the default
>>>> +      for the ACTIVE selection. The BOUNDS target will return the
>>>> +      maximum width and height of the target.
>>>
>>> What about the minimum ?
> 
> There are multiple problems with idea of the maximal rectangle because
> one has to provide definition how to compare size of two rectangles. If
> you had to compare rectangles 10x1, 1x10, 5x5 which would you choose as
> the largest? Such problems may appear if HW has width, height and size
> constraints. One encounters similar problem with definition of the
> smallest rectangle. I prefer to define "is larger" as "contains".
> Rectangle 10x10 contains all three overmentioned rectangles therefore it
> is the maximal rectangle. The problem with such a definition is that
> such a rectangle may not be accepted by HW.
> 
>>
>> Good question. We could also specify that the minimum is obtained by
>> using the V4L2_SUBDEV_SEL_FLAG_LE flag with the BOUNDS target.
>>
> 
> As I remember bounds rectangle is fixed and there is no such a thing as
> minimal/maximal bounds. For V4L2 video node API, the bounds rectangle is
> read-only value describing rectangle that contains all pixels.
> Could you describe the use case that utilities minimal bounds rectangle?

Most devices do have a minimum width and height for the image they can
process. This is typically relatively large: from 32 pixels to around
200 pixels. Not that these limits typically would be hit in practice,
but it might still be good to be able to tell they exist.

The user will notice that from the rectangle returned from s_selection, too.

But from your explanation I understand that the bounds rectangle is
something different. In which situations the bounds rectangle would be
different from the active one?

>>>> The PADDED target
>>>> +      provides the width and height for the padded image,
>>>
>>> Is it valid for both crop and compose rectangles ?
>>
>> I think all targets are valid for all rectangles. Should I mention that?
>>
>> The practical use cases may be more limited, though. I wonder if I
>> should remove the padded targets until we get use cases for them. I
>> included them for the reason that they also exist in the V4L2.
>>
>> Tomasz, Sylwester: do you have use for the PADDED targets?
> 
> S5P-TV and S5P-JPEG (by Andrzej Pietrasiewicz) makes use of PADDED
> target. The padded target is very hardware/application dependent
> parameter. It is defined only for composing targets. Basically it refers
> to all pixels that are modified by the hardware. In S5P-TV the padded
> rectangle is equal to active rectangle. However, if having no good idea
> about padded area, then it is always safe/consistent to make padded
> rectangle equal to bounds one.

Why not the active target?

If the hardware modifies more pixels in composition than really wanted,
isn't that an issue? Or do you think it'd be the responsibility of the
subdev at the other end of the link to discard it?

I'm beginning to wonder if padded or bounds target makes sense for
subdevs. Don't get me wrong --- I would just like to understad the use
case for them.

>> I think we also must define what will be done in cases where crop (on
>> either sink or source) / scaling / composition is not supported by the
>> subdev. That's currently undefined. I think it'd be most clear to return
>> an error code but I'm not sure which one --- EINVAL is an obvious
>> candidate but that is also returned when the pad is wrong. It looks
>> still like the best choice to me.
> 
> Maybe one should return EPERM or EACCES if S_SELECTION is called on
> read-only target. Other idea is to introduce V4L2_SEL_FLAG_RDONLY flag
> which is set by VIDIOC_G_SELECTION for a given target. The driver may
> return EINVAL if target is not supported. It would imply that support
> for the target is not implemented in the driver.

That brings us to another question: if a subdev does not support
something, for example scaling, should it provide a way to get, or even
set the related rectangle? Providing a way to get it might well make
sense, but to set it should likely, as you propose, return EACCES (EPERM
suggests it's a permission issue which it isn't).

Opinions?

Regards,

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 08/17] v4l: Image source control class
  2012-01-05 16:23   ` Laurent Pinchart
@ 2012-01-14 20:51     ` Sakari Ailus
  2012-01-15  1:43       ` Laurent Pinchart
  2012-01-15 16:16       ` Sylwester Nawrocki
  0 siblings, 2 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-14 20:51 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Thanks for the review!

Laurent Pinchart wrote:
> On Tuesday 20 December 2011 21:28:00 Sakari Ailus wrote:
>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>
>> Add image source control class. This control class is intended to contain
>> low level controls which deal with control of the image capture process ---
>> the A/D converter in image sensors, for example.
>>
>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>> ---
>>  Documentation/DocBook/media/v4l/controls.xml       |  101 +++++++++++++++++
>>  .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       |    6 +
>>  drivers/media/video/v4l2-ctrls.c                   |   10 ++
>>  include/linux/videodev2.h                          |   10 ++
>>  4 files changed, 127 insertions(+), 0 deletions(-)
>>
>> diff --git a/Documentation/DocBook/media/v4l/controls.xml
>> b/Documentation/DocBook/media/v4l/controls.xml index 3bc5ee8..69ede83
>> 100644
>> --- a/Documentation/DocBook/media/v4l/controls.xml
>> +++ b/Documentation/DocBook/media/v4l/controls.xml
>> @@ -3356,6 +3356,107 @@ interface and may change in the future.</para>
>>        </table>
>>
>>      </section>
>> +
>> +    <section id="image-source-controls">
>> +      <title>Image Source Control Reference</title>
>> +
>> +      <note>
>> +	<title>Experimental</title>
>> +
>> +	<para>This is an <link
>> +	linkend="experimental">experimental</link> interface and may
>> +	change in the future.</para>
>> +      </note>
>> +
>> +      <para>
>> +	The Image Source control class is intended for low-level
>> +	control of image source devices such as image sensors. The
>> +	devices feature an analogue to digital converter and a bus
> 
> Is the V4L2 documentation written in US or UK English ? US uses analog, UK 
> uses analogue. Analog would be shorter in control names.

Both appear to be used, but the US English appears to be more commonly
used. I guess it's mostly chosen by whatever happened to be used by the
author of the patch. I prefer UK spelling which you might have noticed
already. :-)

I remember there was a discussion on this topic years ago within the
kernel community but I don't remember how it ended up with... LWN.net
appears to remember better than I do, but by a quick check I can't find
any definitive conclusion.

<URL:http://lwn.net/Articles/44262/>
<URL:http://lkml.org/lkml/2003/8/7/245>

>> +	transmitter to transmit the image data out of the device.
>> +      </para>
>> +
>> +      <table pgwide="1" frame="none" id="image-source-control-id">
>> +      <title>Image Source Control IDs</title>
>> +
>> +      <tgroup cols="4">
>> +	<colspec colname="c1" colwidth="1*" />
>> +	<colspec colname="c2" colwidth="6*" />
>> +	<colspec colname="c3" colwidth="2*" />
>> +	<colspec colname="c4" colwidth="6*" />
>> +	<spanspec namest="c1" nameend="c2" spanname="id" />
>> +	<spanspec namest="c2" nameend="c4" spanname="descr" />
>> +	<thead>
>> +	  <row>
>> +	    <entry spanname="id" align="left">ID</entry>
>> +	    <entry align="left">Type</entry>
>> +	  </row><row rowsep="1"><entry spanname="descr"
>> align="left">Description</entry> +	  </row>
>> +	</thead>
>> +	<tbody valign="top">
>> +	  <row><entry></entry></row>
>> +	  <row>
>> +	    <entry
>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry> +	 
>>   <entry>class</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry spanname="descr">The IMAGE_SOURCE class descriptor.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry
>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_VBLANK</constant></entry> +	
>>    <entry>integer</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry spanname="descr">Vertical blanking. The idle
>> +	    preriod after every frame during which no image data is
> 
> s/preriod/period/
> 
>> +	    produced. The unit of vertical blanking is a line. Every
>> +	    line has length of the image width plus horizontal
>> +	    blanking at the pixel clock specified by struct
>> +	    v4l2_mbus_framefmt <xref linkend="v4l2-mbus-framefmt"
>> +	    />.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry
>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_HBLANK</constant></entry> +	
>>    <entry>integer</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry spanname="descr">Horizontal blanking. The idle
>> +	    preriod after every line of image data during which no
> 
> s/preriod/period/
> 
>> +	    image data is produced. The unit of horizontal blanking is
>> +	    pixels.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry
>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_LINK_FREQ</constant></entry>
>> +	    <entry>integer menu</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry spanname="descr">Image source's data bus frequency.
> 
> What's the frequency unit ? Sample/second ?

Hz --- that's the unit of frequency. I fixed that in the new version.

>> +	    Together with the media bus pixel code, bus type (clock
>> +	    cycles per sample), the data bus frequency defines the
>> +	    pixel clock. <xref linkend="v4l2-mbus-framefmt" /> The
>> +	    frame rate can be calculated from the pixel clock, image
>> +	    width and height and horizontal and vertical blanking. The
>> +	    frame rate control is performed by selecting the desired
>> +	    horizontal and vertical blanking.
>> +	    </entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry
>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN</constant></en
>> try> +	    <entry>integer</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry spanname="descr">Analogue gain is gain affecting
>> +	    all colour components in the pixel matrix. The gain
>> +	    operation is performed in the analogue domain before A/D
>> +	    conversion.
> 
> Should we define one gain per color component ?

I think that in the end we may need up to six analogue gains:

- Gain for all components
- Blue gain
- Red gain
- Green gain (for both greens)
- Gr gain
- Gb gain

It may be debatable whether Gr / Gb gain will always be the same or not.
I'm not fully certain about that. As Hans G. suggested, it might be
possible to go with just one for green.

>> +	    </entry>
>> +	  </row>
>> +	  <row><entry></entry></row>
>> +	</tbody>
>> +      </tgroup>
>> +      </table>
>> +
>> +    </section>
>> +
>>  </section>
>>
>>    <!--
>> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
>> b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml index
>> 5122ce8..250c1cf 100644
>> --- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
>> +++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
>> @@ -257,6 +257,12 @@ These controls are described in <xref
>>  These controls are described in <xref
>>  		linkend="flash-controls" />.</entry>
>>  	  </row>
>> +	  <row>
>> +	    <entry><constant>V4L2_CTRL_CLASS_IMAGE_SOURCE</constant></entry>
>> +	    <entry>0x9d0000</entry> <entry>The class containing image
>> +	    source controls. These controls are described in <xref
>> +	    linkend="image-source-controls" />.</entry>
>> +	  </row>
>>  	</tbody>
>>        </tgroup>
>>      </table>
>> diff --git a/drivers/media/video/v4l2-ctrls.c
>> b/drivers/media/video/v4l2-ctrls.c index 083bb79..da1ec52 100644
>> --- a/drivers/media/video/v4l2-ctrls.c
>> +++ b/drivers/media/video/v4l2-ctrls.c
>> @@ -606,6 +606,12 @@ const char *v4l2_ctrl_get_name(u32 id)
>>  	case V4L2_CID_FLASH_CHARGE:		return "Charge";
>>  	case V4L2_CID_FLASH_READY:		return "Ready to strobe";
>>
>> +	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image source controls";
>> +	case V4L2_CID_IMAGE_SOURCE_VBLANK:	return "Vertical blanking";
>> +	case V4L2_CID_IMAGE_SOURCE_HBLANK:	return "Horizontal blanking";
>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:	return "Link frequency";
>> +	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN: return "Analogue gain";
> 
> Please capitalize each word, as done for the other controls.

This isn't done for the flash controls either, have you noticed that?

Well, I guess I have to admit that they were added by myself. ;-)

I can fix this for the next patchset.

>>  	default:
>>  		return NULL;
>>  	}
>> @@ -694,6 +700,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum
>> v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
>>  		*type = V4L2_CTRL_TYPE_MENU;
>>  		break;
>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:
>> +		*type = V4L2_CTRL_TYPE_INTEGER_MENU;
>> +		break;
> 
> Will this always be an integer menu control, or can you foresee cases where 
> the range would be continuous ?

Good question. On some hardware this definitely is an integer menu, but
hardware may exist where more selections would be available.

However, on e.g. the SMIA++ sensor the calculation of the clock tree
values depends heavily on the selected link rate. Choosing a wrong link
rate may yield to the clock tree calculation to fail. So the driver
likely would need to enforce some rules which values are allowed. That
might prove unfeasible --- already the PLL code in the SMIA++ driver is
relatively complex.

I don't see much benefit in being able to specify this freely.

AFAIR the conclusion was that controls may only have one type when the
control framework was written.

> We already have drivers for Aptina parallel sensors that include a 
> configurable PLL. The pixel clock can be configured more or less freely in 
> that case, although I'm not sure if that's useful in practice.
> 
>>  	case V4L2_CID_RDS_TX_PS_NAME:
>>  	case V4L2_CID_RDS_TX_RADIO_TEXT:
>>  		*type = V4L2_CTRL_TYPE_STRING;
>> @@ -703,6 +712,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum
>> v4l2_ctrl_type *type, case V4L2_CID_MPEG_CLASS:
>>  	case V4L2_CID_FM_TX_CLASS:
>>  	case V4L2_CID_FLASH_CLASS:
>> +	case V4L2_CID_IMAGE_SOURCE_CLASS:
>>  		*type = V4L2_CTRL_TYPE_CTRL_CLASS;
>>  		/* You can neither read not write these */
>>  		*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
>> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
>> index 9633c69..0f8f904 100644
>> --- a/include/linux/videodev2.h
>> +++ b/include/linux/videodev2.h
>> @@ -1080,6 +1080,7 @@ struct v4l2_ext_controls {
>>  #define V4L2_CTRL_CLASS_CAMERA 0x009a0000	/* Camera class controls */
>>  #define V4L2_CTRL_CLASS_FM_TX 0x009b0000	/* FM Modulator control class */
>>  #define V4L2_CTRL_CLASS_FLASH 0x009c0000	/* Camera flash controls */
>> +#define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009d0000	/* Image source flash
>> controls */
>>
>>  #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
>>  #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
>> @@ -1690,6 +1691,15 @@ enum v4l2_flash_strobe_source {
>>  #define V4L2_CID_FLASH_CHARGE			(V4L2_CID_FLASH_CLASS_BASE + 11)
>>  #define V4L2_CID_FLASH_READY			(V4L2_CID_FLASH_CLASS_BASE + 12)
>>
>> +/* Image source controls */
>> +#define V4L2_CID_IMAGE_SOURCE_CLASS_BASE	(V4L2_CTRL_CLASS_IMAGE_SOURCE |
>> 0x900) +#define V4L2_CID_IMAGE_SOURCE_CLASS		
> (V4L2_CTRL_CLASS_IMAGE_SOURCE
>> | 1) +
>> +#define V4L2_CID_IMAGE_SOURCE_VBLANK		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE 
> +
>> 1) +#define
>> V4L2_CID_IMAGE_SOURCE_HBLANK		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
>> +#define
>> V4L2_CID_IMAGE_SOURCE_LINK_FREQ		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
>> +#define
>> V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN	(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4)
>> +
>>  /*
>>   *	T U N I N G
>>   */
> 


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 08/17] v4l: Image source control class
  2012-01-14 20:51     ` Sakari Ailus
@ 2012-01-15  1:43       ` Laurent Pinchart
  2012-01-15 19:44         ` Sakari Ailus
  2012-01-15 16:16       ` Sylwester Nawrocki
  1 sibling, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-15  1:43 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

On Saturday 14 January 2012 21:51:31 Sakari Ailus wrote:
> Laurent Pinchart wrote:
> > On Tuesday 20 December 2011 21:28:00 Sakari Ailus wrote:
> >> From: Sakari Ailus <sakari.ailus@iki.fi>
> >> 
> >> Add image source control class. This control class is intended to
> >> contain low level controls which deal with control of the image capture
> >> process --- the A/D converter in image sensors, for example.
> >> 
> >> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> >> ---
> >> 
> >>  Documentation/DocBook/media/v4l/controls.xml       |  101
> >>  +++++++++++++++++ .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       |
> >>     6 +
> >>  drivers/media/video/v4l2-ctrls.c                   |   10 ++
> >>  include/linux/videodev2.h                          |   10 ++
> >>  4 files changed, 127 insertions(+), 0 deletions(-)
> >> 
> >> diff --git a/Documentation/DocBook/media/v4l/controls.xml
> >> b/Documentation/DocBook/media/v4l/controls.xml index 3bc5ee8..69ede83
> >> 100644
> >> --- a/Documentation/DocBook/media/v4l/controls.xml
> >> +++ b/Documentation/DocBook/media/v4l/controls.xml
> >> @@ -3356,6 +3356,107 @@ interface and may change in the future.</para>
> >> 
> >>        </table>
> >>      
> >>      </section>
> >> 
> >> +
> >> +    <section id="image-source-controls">
> >> +      <title>Image Source Control Reference</title>
> >> +
> >> +      <note>
> >> +	<title>Experimental</title>
> >> +
> >> +	<para>This is an <link
> >> +	linkend="experimental">experimental</link> interface and may
> >> +	change in the future.</para>
> >> +      </note>
> >> +
> >> +      <para>
> >> +	The Image Source control class is intended for low-level
> >> +	control of image source devices such as image sensors. The
> >> +	devices feature an analogue to digital converter and a bus
> > 
> > Is the V4L2 documentation written in US or UK English ? US uses analog,
> > UK uses analogue. Analog would be shorter in control names.
> 
> Both appear to be used, but the US English appears to be more commonly
> used. I guess it's mostly chosen by whatever happened to be used by the
> author of the patch. I prefer UK spelling which you might have noticed
> already. :-)

Yes I have. I haven't checked whether V4L2 prefers the UK or US spelling. I'll 
trust you on that.

> I remember there was a discussion on this topic years ago within the
> kernel community but I don't remember how it ended up with... LWN.net
> appears to remember better than I do, but by a quick check I can't find
> any definitive conclusion.
> 
> <URL:http://lwn.net/Articles/44262/>
> <URL:http://lkml.org/lkml/2003/8/7/245>
> 
> >> +	transmitter to transmit the image data out of the device.
> >> +      </para>
> >> +
> >> +      <table pgwide="1" frame="none" id="image-source-control-id">
> >> +      <title>Image Source Control IDs</title>
> >> +
> >> +      <tgroup cols="4">
> >> +	<colspec colname="c1" colwidth="1*" />
> >> +	<colspec colname="c2" colwidth="6*" />
> >> +	<colspec colname="c3" colwidth="2*" />
> >> +	<colspec colname="c4" colwidth="6*" />
> >> +	<spanspec namest="c1" nameend="c2" spanname="id" />
> >> +	<spanspec namest="c2" nameend="c4" spanname="descr" />
> >> +	<thead>
> >> +	  <row>
> >> +	    <entry spanname="id" align="left">ID</entry>
> >> +	    <entry align="left">Type</entry>
> >> +	  </row><row rowsep="1"><entry spanname="descr"
> >> align="left">Description</entry> +	  </row>
> >> +	</thead>
> >> +	<tbody valign="top">
> >> +	  <row><entry></entry></row>
> >> +	  <row>
> >> +	    <entry
> >> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry> +
> >> 
> >>   <entry>class</entry>
> >> 
> >> +	  </row>
> >> +	  <row>
> >> +	    <entry spanname="descr">The IMAGE_SOURCE class descriptor.</entry>
> >> +	  </row>
> >> +	  <row>
> >> +	    <entry
> >> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_VBLANK</constant></entry>
> >> +
> >> 
> >>    <entry>integer</entry>
> >> 
> >> +	  </row>
> >> +	  <row>
> >> +	    <entry spanname="descr">Vertical blanking. The idle
> >> +	    preriod after every frame during which no image data is
> > 
> > s/preriod/period/
> > 
> >> +	    produced. The unit of vertical blanking is a line. Every
> >> +	    line has length of the image width plus horizontal
> >> +	    blanking at the pixel clock specified by struct
> >> +	    v4l2_mbus_framefmt <xref linkend="v4l2-mbus-framefmt"
> >> +	    />.</entry>
> >> +	  </row>
> >> +	  <row>
> >> +	    <entry
> >> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_HBLANK</constant></entry>
> >> +
> >> 
> >>    <entry>integer</entry>
> >> 
> >> +	  </row>
> >> +	  <row>
> >> +	    <entry spanname="descr">Horizontal blanking. The idle
> >> +	    preriod after every line of image data during which no
> > 
> > s/preriod/period/
> > 
> >> +	    image data is produced. The unit of horizontal blanking is
> >> +	    pixels.</entry>
> >> +	  </row>
> >> +	  <row>
> >> +	    <entry
> >> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_LINK_FREQ</constant></entr
> >> y> +	    <entry>integer menu</entry>
> >> +	  </row>
> >> +	  <row>
> >> +	    <entry spanname="descr">Image source's data bus frequency.
> > 
> > What's the frequency unit ? Sample/second ?
> 
> Hz --- that's the unit of frequency. I fixed that in the new version.

Is the user supposed to compute the pixel clock from this information ? That's 
what the text below seems to imply.

> >> +	    Together with the media bus pixel code, bus type (clock
> >> +	    cycles per sample), the data bus frequency defines the
> >> +	    pixel clock. <xref linkend="v4l2-mbus-framefmt" /> The
> >> +	    frame rate can be calculated from the pixel clock, image
> >> +	    width and height and horizontal and vertical blanking. The
> >> +	    frame rate control is performed by selecting the desired
> >> +	    horizontal and vertical blanking.
> >> +	    </entry>
> >> +	  </row>
> >> +	  <row>
> >> +	    <entry
> >> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN</constant></
> >> en try> +	    <entry>integer</entry>
> >> +	  </row>
> >> +	  <row>
> >> +	    <entry spanname="descr">Analogue gain is gain affecting
> >> +	    all colour components in the pixel matrix. The gain
> >> +	    operation is performed in the analogue domain before A/D
> >> +	    conversion.
> > 
> > Should we define one gain per color component ?
> 
> I think that in the end we may need up to six analogue gains:
> 
> - Gain for all components

Many sensors that provide per-component gains also provide a global gain 
control that sets the four component gains. I'm not sure how (and if) we 
should handle that.

> - Blue gain
> - Red gain
> - Green gain (for both greens)
> - Gr gain
> - Gb gain
> 
> It may be debatable whether Gr / Gb gain will always be the same or not.
> I'm not fully certain about that. As Hans G. suggested, it might be
> possible to go with just one for green.

I'm also unsure about that. Having different gains for the two green 
components doesn't seem very useful. On the other hand, if we find a use case 
later, we'll have to break driver ABIs.

> >> +	    </entry>
> >> +	  </row>
> >> +	  <row><entry></entry></row>
> >> +	</tbody>
> >> +      </tgroup>
> >> +      </table>
> >> +
> >> +    </section>
> >> +
> >> 
> >>  </section>
> >>  
> >>    <!--
> >> 
> >> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
> >> b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml index
> >> 5122ce8..250c1cf 100644
> >> --- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
> >> +++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
> >> @@ -257,6 +257,12 @@ These controls are described in <xref
> >> 
> >>  These controls are described in <xref
> >>  
> >>  		linkend="flash-controls" />.</entry>
> >>  		
> >>  	  </row>
> >> 
> >> +	  <row>
> >> +	    <entry><constant>V4L2_CTRL_CLASS_IMAGE_SOURCE</constant></entry>
> >> +	    <entry>0x9d0000</entry> <entry>The class containing image
> >> +	    source controls. These controls are described in <xref
> >> +	    linkend="image-source-controls" />.</entry>
> >> +	  </row>
> >> 
> >>  	</tbody>
> >>  	
> >>        </tgroup>
> >>      
> >>      </table>
> >> 
> >> diff --git a/drivers/media/video/v4l2-ctrls.c
> >> b/drivers/media/video/v4l2-ctrls.c index 083bb79..da1ec52 100644
> >> --- a/drivers/media/video/v4l2-ctrls.c
> >> +++ b/drivers/media/video/v4l2-ctrls.c
> >> @@ -606,6 +606,12 @@ const char *v4l2_ctrl_get_name(u32 id)
> >> 
> >>  	case V4L2_CID_FLASH_CHARGE:		return "Charge";
> >>  	case V4L2_CID_FLASH_READY:		return "Ready to strobe";
> >> 
> >> +	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image source controls";
> >> +	case V4L2_CID_IMAGE_SOURCE_VBLANK:	return "Vertical blanking";
> >> +	case V4L2_CID_IMAGE_SOURCE_HBLANK:	return "Horizontal blanking";
> >> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:	return "Link frequency";
> >> +	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN: return "Analogue gain";
> > 
> > Please capitalize each word, as done for the other controls.
> 
> This isn't done for the flash controls either, have you noticed that?
> 
> Well, I guess I have to admit that they were added by myself. ;-)
> 
> I can fix this for the next patchset.
> 
> >>  	default:
> >>  		return NULL;
> >>  	
> >>  	}
> >> 
> >> @@ -694,6 +700,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum
> >> 
> >> v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
> >>  		*type = V4L2_CTRL_TYPE_MENU;
> >>  		break;
> >> 
> >> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:
> >> +		*type = V4L2_CTRL_TYPE_INTEGER_MENU;
> >> +		break;
> > 
> > Will this always be an integer menu control, or can you foresee cases
> > where the range would be continuous ?
> 
> Good question. On some hardware this definitely is an integer menu, but
> hardware may exist where more selections would be available.
> 
> However, on e.g. the SMIA++ sensor the calculation of the clock tree
> values depends heavily on the selected link rate. Choosing a wrong link
> rate may yield to the clock tree calculation to fail. So the driver
> likely would need to enforce some rules which values are allowed. That
> might prove unfeasible --- already the PLL code in the SMIA++ driver is
> relatively complex.
> 
> I don't see much benefit in being able to specify this freely.

For SMIA++, definitely not. For other sensors, I don't know.

> AFAIR the conclusion was that controls may only have one type when the
> control framework was written.

Yes, but I'm not sure whether that's a good conclusion :-)

> > We already have drivers for Aptina parallel sensors that include a
> > configurable PLL. The pixel clock can be configured more or less freely
> > in that case, although I'm not sure if that's useful in practice.
> > 
> >>  	case V4L2_CID_RDS_TX_PS_NAME:
> >>  	
> >>  	case V4L2_CID_RDS_TX_RADIO_TEXT:
> >>  		*type = V4L2_CTRL_TYPE_STRING;
> >> 
> >> @@ -703,6 +712,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum
> >> 
> >> v4l2_ctrl_type *type, case V4L2_CID_MPEG_CLASS:
> >>  	case V4L2_CID_FM_TX_CLASS:
> >> 
> >>  	case V4L2_CID_FLASH_CLASS:
> >> +	case V4L2_CID_IMAGE_SOURCE_CLASS:
> >>  		*type = V4L2_CTRL_TYPE_CTRL_CLASS;
> >>  		/* You can neither read not write these */
> >>  		*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
> >> 
> >> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> >> index 9633c69..0f8f904 100644
> >> --- a/include/linux/videodev2.h
> >> +++ b/include/linux/videodev2.h
> >> @@ -1080,6 +1080,7 @@ struct v4l2_ext_controls {
> >> 
> >>  #define V4L2_CTRL_CLASS_CAMERA 0x009a0000	/* Camera class controls */
> >>  #define V4L2_CTRL_CLASS_FM_TX 0x009b0000	/* FM Modulator control class
> >>  */ #define V4L2_CTRL_CLASS_FLASH 0x009c0000	/* Camera flash controls
> >>  */
> >> 
> >> +#define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009d0000	/* Image source flash
> >> controls */
> >> 
> >>  #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
> >>  #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
> >> 
> >> @@ -1690,6 +1691,15 @@ enum v4l2_flash_strobe_source {
> >> 
> >>  #define V4L2_CID_FLASH_CHARGE			(V4L2_CID_FLASH_CLASS_BASE + 11)
> >>  #define V4L2_CID_FLASH_READY			(V4L2_CID_FLASH_CLASS_BASE + 12)
> >> 
> >> +/* Image source controls */
> >> +#define V4L2_CID_IMAGE_SOURCE_CLASS_BASE	(V4L2_CTRL_CLASS_IMAGE_SOURCE
> >> | 0x900) +#define V4L2_CID_IMAGE_SOURCE_CLASS
> > 
> > (V4L2_CTRL_CLASS_IMAGE_SOURCE
> > 
> >> | 1) +
> >> 
> >> +#define V4L2_CID_IMAGE_SOURCE_VBLANK		
(V4L2_CID_IMAGE_SOURCE_CLASS_BASE
> > 
> > +
> > 
> >> 1) +#define
> >> V4L2_CID_IMAGE_SOURCE_HBLANK		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
> >> +#define
> >> V4L2_CID_IMAGE_SOURCE_LINK_FREQ		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE 
+ 3)
> >> +#define
> >> V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN	(V4L2_CID_IMAGE_SOURCE_CLASS_BASE 
+
> >> 4) +
> >> 
> >>  /*
> >>  
> >>   *	T U N I N G
> >>   */

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 08/17] v4l: Image source control class
  2012-01-14 20:51     ` Sakari Ailus
  2012-01-15  1:43       ` Laurent Pinchart
@ 2012-01-15 16:16       ` Sylwester Nawrocki
  2012-01-15 19:30         ` Sakari Ailus
  1 sibling, 1 reply; 76+ messages in thread
From: Sylwester Nawrocki @ 2012-01-15 16:16 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: Laurent Pinchart, linux-media, dacohen

Hi Sakari,

On 01/14/2012 09:51 PM, Sakari Ailus wrote:
>>> diff --git a/drivers/media/video/v4l2-ctrls.c
>>> b/drivers/media/video/v4l2-ctrls.c index 083bb79..da1ec52 100644
>>> --- a/drivers/media/video/v4l2-ctrls.c
>>> +++ b/drivers/media/video/v4l2-ctrls.c
>>> @@ -606,6 +606,12 @@ const char *v4l2_ctrl_get_name(u32 id)
>>>   	case V4L2_CID_FLASH_CHARGE:		return "Charge";
>>>   	case V4L2_CID_FLASH_READY:		return "Ready to strobe";
>>>
>>> +	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image source controls";
>>> +	case V4L2_CID_IMAGE_SOURCE_VBLANK:	return "Vertical blanking";
>>> +	case V4L2_CID_IMAGE_SOURCE_HBLANK:	return "Horizontal blanking";
>>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:	return "Link frequency";
>>> +	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN: return "Analogue gain";
>>
>> Please capitalize each word, as done for the other controls.
> 
> This isn't done for the flash controls either, have you noticed that?
> 
> Well, I guess I have to admit that they were added by myself. ;-)
> 
> I can fix this for the next patchset.
 
I don't want to be annoying (too much ;)) but the FLASH controls documentation
is missing some <constant> tags in the text.  Other classes use them for
standard identifiers.

Regards, 
Sylwester

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 08/17] v4l: Image source control class
  2012-01-15 16:16       ` Sylwester Nawrocki
@ 2012-01-15 19:30         ` Sakari Ailus
  2012-01-15 20:08           ` Sylwester Nawrocki
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-15 19:30 UTC (permalink / raw)
  To: Sylwester Nawrocki; +Cc: Laurent Pinchart, linux-media, dacohen

Hi Sylwester,

Sylwester Nawrocki wrote:
> On 01/14/2012 09:51 PM, Sakari Ailus wrote:
>>>> diff --git a/drivers/media/video/v4l2-ctrls.c
>>>> b/drivers/media/video/v4l2-ctrls.c index 083bb79..da1ec52 100644
>>>> --- a/drivers/media/video/v4l2-ctrls.c
>>>> +++ b/drivers/media/video/v4l2-ctrls.c
>>>> @@ -606,6 +606,12 @@ const char *v4l2_ctrl_get_name(u32 id)
>>>>   	case V4L2_CID_FLASH_CHARGE:		return "Charge";
>>>>   	case V4L2_CID_FLASH_READY:		return "Ready to strobe";
>>>>
>>>> +	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image source controls";
>>>> +	case V4L2_CID_IMAGE_SOURCE_VBLANK:	return "Vertical blanking";
>>>> +	case V4L2_CID_IMAGE_SOURCE_HBLANK:	return "Horizontal blanking";
>>>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:	return "Link frequency";
>>>> +	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN: return "Analogue gain";
>>>
>>> Please capitalize each word, as done for the other controls.
>>
>> This isn't done for the flash controls either, have you noticed that?
>>
>> Well, I guess I have to admit that they were added by myself. ;-)
>>
>> I can fix this for the next patchset.
>  
> I don't want to be annoying (too much ;)) but the FLASH controls documentation
> is missing some <constant> tags in the text.  Other classes use them for
> standard identifiers.

Thanks for letting me know --- that could be fixed with the flash timing
control API, or unrelated to that. We should btw. continue discussion on
that one. :-)

Speaking of things to do... The colour of the object to point and press
V4L2_CID_DO_WHITE_BALANCE (or what was it called) to fix the white
balance --- is that white, gray, something else or implementation
dependent? I vaguely remember having seen some grayish plates being used
for that but I'm definitely not sure. :-) Any idea?

Regards,

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 08/17] v4l: Image source control class
  2012-01-15  1:43       ` Laurent Pinchart
@ 2012-01-15 19:44         ` Sakari Ailus
  2012-01-15 20:00           ` Laurent Pinchart
  0 siblings, 1 reply; 76+ messages in thread
From: Sakari Ailus @ 2012-01-15 19:44 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> On Saturday 14 January 2012 21:51:31 Sakari Ailus wrote:
>> Laurent Pinchart wrote:
>>> On Tuesday 20 December 2011 21:28:00 Sakari Ailus wrote:
>>>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>>>
>>>> Add image source control class. This control class is intended to
>>>> contain low level controls which deal with control of the image capture
>>>> process --- the A/D converter in image sensors, for example.
>>>>
>>>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>>>> ---
>>>>
>>>>  Documentation/DocBook/media/v4l/controls.xml       |  101
>>>>  +++++++++++++++++ .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       |
>>>>     6 +
>>>>  drivers/media/video/v4l2-ctrls.c                   |   10 ++
>>>>  include/linux/videodev2.h                          |   10 ++
>>>>  4 files changed, 127 insertions(+), 0 deletions(-)
>>>>
>>>> diff --git a/Documentation/DocBook/media/v4l/controls.xml
>>>> b/Documentation/DocBook/media/v4l/controls.xml index 3bc5ee8..69ede83
>>>> 100644
>>>> --- a/Documentation/DocBook/media/v4l/controls.xml
>>>> +++ b/Documentation/DocBook/media/v4l/controls.xml
>>>> @@ -3356,6 +3356,107 @@ interface and may change in the future.</para>
>>>>
>>>>        </table>
>>>>      
>>>>      </section>
>>>>
>>>> +
>>>> +    <section id="image-source-controls">
>>>> +      <title>Image Source Control Reference</title>
>>>> +
>>>> +      <note>
>>>> +	<title>Experimental</title>
>>>> +
>>>> +	<para>This is an <link
>>>> +	linkend="experimental">experimental</link> interface and may
>>>> +	change in the future.</para>
>>>> +      </note>
>>>> +
>>>> +      <para>
>>>> +	The Image Source control class is intended for low-level
>>>> +	control of image source devices such as image sensors. The
>>>> +	devices feature an analogue to digital converter and a bus
>>>
>>> Is the V4L2 documentation written in US or UK English ? US uses analog,
>>> UK uses analogue. Analog would be shorter in control names.
>>
>> Both appear to be used, but the US English appears to be more commonly
>> used. I guess it's mostly chosen by whatever happened to be used by the
>> author of the patch. I prefer UK spelling which you might have noticed
>> already. :-)
> 
> Yes I have. I haven't checked whether V4L2 prefers the UK or US spelling. I'll 
> trust you on that.

I have checked and most seem to have used US spelling. If you wish me to
change it, I can do that.

>> I remember there was a discussion on this topic years ago within the
>> kernel community but I don't remember how it ended up with... LWN.net
>> appears to remember better than I do, but by a quick check I can't find
>> any definitive conclusion.
>>
>> <URL:http://lwn.net/Articles/44262/>
>> <URL:http://lkml.org/lkml/2003/8/7/245>
>>
>>>> +	transmitter to transmit the image data out of the device.
>>>> +      </para>
>>>> +
>>>> +      <table pgwide="1" frame="none" id="image-source-control-id">
>>>> +      <title>Image Source Control IDs</title>
>>>> +
>>>> +      <tgroup cols="4">
>>>> +	<colspec colname="c1" colwidth="1*" />
>>>> +	<colspec colname="c2" colwidth="6*" />
>>>> +	<colspec colname="c3" colwidth="2*" />
>>>> +	<colspec colname="c4" colwidth="6*" />
>>>> +	<spanspec namest="c1" nameend="c2" spanname="id" />
>>>> +	<spanspec namest="c2" nameend="c4" spanname="descr" />
>>>> +	<thead>
>>>> +	  <row>
>>>> +	    <entry spanname="id" align="left">ID</entry>
>>>> +	    <entry align="left">Type</entry>
>>>> +	  </row><row rowsep="1"><entry spanname="descr"
>>>> align="left">Description</entry> +	  </row>
>>>> +	</thead>
>>>> +	<tbody valign="top">
>>>> +	  <row><entry></entry></row>
>>>> +	  <row>
>>>> +	    <entry
>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry> +
>>>>
>>>>   <entry>class</entry>
>>>>
>>>> +	  </row>
>>>> +	  <row>
>>>> +	    <entry spanname="descr">The IMAGE_SOURCE class descriptor.</entry>
>>>> +	  </row>
>>>> +	  <row>
>>>> +	    <entry
>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_VBLANK</constant></entry>
>>>> +
>>>>
>>>>    <entry>integer</entry>
>>>>
>>>> +	  </row>
>>>> +	  <row>
>>>> +	    <entry spanname="descr">Vertical blanking. The idle
>>>> +	    preriod after every frame during which no image data is
>>>
>>> s/preriod/period/
>>>
>>>> +	    produced. The unit of vertical blanking is a line. Every
>>>> +	    line has length of the image width plus horizontal
>>>> +	    blanking at the pixel clock specified by struct
>>>> +	    v4l2_mbus_framefmt <xref linkend="v4l2-mbus-framefmt"
>>>> +	    />.</entry>
>>>> +	  </row>
>>>> +	  <row>
>>>> +	    <entry
>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_HBLANK</constant></entry>
>>>> +
>>>>
>>>>    <entry>integer</entry>
>>>>
>>>> +	  </row>
>>>> +	  <row>
>>>> +	    <entry spanname="descr">Horizontal blanking. The idle
>>>> +	    preriod after every line of image data during which no
>>>
>>> s/preriod/period/
>>>
>>>> +	    image data is produced. The unit of horizontal blanking is
>>>> +	    pixels.</entry>
>>>> +	  </row>
>>>> +	  <row>
>>>> +	    <entry
>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_LINK_FREQ</constant></entr
>>>> y> +	    <entry>integer menu</entry>
>>>> +	  </row>
>>>> +	  <row>
>>>> +	    <entry spanname="descr">Image source's data bus frequency.
>>>
>>> What's the frequency unit ? Sample/second ?
>>
>> Hz --- that's the unit of frequency. I fixed that in the new version.
> 
> Is the user supposed to compute the pixel clock from this information ? That's 
> what the text below seems to imply.

Apparently I have forgotten to update this in the new patchset. But yes,
these factors do define it. The sensors' internal clock tree will be
involved and calculation is non-trivial. This is why we also have the
PIXEL_RATE control --- where I will refer to in the next patchset.

>>>> +	    Together with the media bus pixel code, bus type (clock
>>>> +	    cycles per sample), the data bus frequency defines the
>>>> +	    pixel clock. <xref linkend="v4l2-mbus-framefmt" /> The
>>>> +	    frame rate can be calculated from the pixel clock, image
>>>> +	    width and height and horizontal and vertical blanking. The
>>>> +	    frame rate control is performed by selecting the desired
>>>> +	    horizontal and vertical blanking.
>>>> +	    </entry>
>>>> +	  </row>
>>>> +	  <row>
>>>> +	    <entry
>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN</constant></
>>>> en try> +	    <entry>integer</entry>
>>>> +	  </row>
>>>> +	  <row>
>>>> +	    <entry spanname="descr">Analogue gain is gain affecting
>>>> +	    all colour components in the pixel matrix. The gain
>>>> +	    operation is performed in the analogue domain before A/D
>>>> +	    conversion.
>>>
>>> Should we define one gain per color component ?
>>
>> I think that in the end we may need up to six analogue gains:
>>
>> - Gain for all components
> 
> Many sensors that provide per-component gains also provide a global gain 
> control that sets the four component gains. I'm not sure how (and if) we 
> should handle that.

If it directly affects all of them, I don't think we should support it.
But if it's independent of the colour-specific ones, then, sure, it
should be supported.

>> - Blue gain
>> - Red gain
>> - Green gain (for both greens)
>> - Gr gain
>> - Gb gain
>>
>> It may be debatable whether Gr / Gb gain will always be the same or not.
>> I'm not fully certain about that. As Hans G. suggested, it might be
>> possible to go with just one for green.
> 
> I'm also unsure about that. Having different gains for the two green 
> components doesn't seem very useful. On the other hand, if we find a use case 
> later, we'll have to break driver ABIs.

Let's add the gains later on. Now we'll need a single analogue gain for
all components and that's good for the time being.

>>>> +	    </entry>
>>>> +	  </row>
>>>> +	  <row><entry></entry></row>
>>>> +	</tbody>
>>>> +      </tgroup>
>>>> +      </table>
>>>> +
>>>> +    </section>
>>>> +
>>>>
>>>>  </section>
>>>>  
>>>>    <!--
>>>>
>>>> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
>>>> b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml index
>>>> 5122ce8..250c1cf 100644
>>>> --- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
>>>> +++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
>>>> @@ -257,6 +257,12 @@ These controls are described in <xref
>>>>
>>>>  These controls are described in <xref
>>>>  
>>>>  		linkend="flash-controls" />.</entry>
>>>>  		
>>>>  	  </row>
>>>>
>>>> +	  <row>
>>>> +	    <entry><constant>V4L2_CTRL_CLASS_IMAGE_SOURCE</constant></entry>
>>>> +	    <entry>0x9d0000</entry> <entry>The class containing image
>>>> +	    source controls. These controls are described in <xref
>>>> +	    linkend="image-source-controls" />.</entry>
>>>> +	  </row>
>>>>
>>>>  	</tbody>
>>>>  	
>>>>        </tgroup>
>>>>      
>>>>      </table>
>>>>
>>>> diff --git a/drivers/media/video/v4l2-ctrls.c
>>>> b/drivers/media/video/v4l2-ctrls.c index 083bb79..da1ec52 100644
>>>> --- a/drivers/media/video/v4l2-ctrls.c
>>>> +++ b/drivers/media/video/v4l2-ctrls.c
>>>> @@ -606,6 +606,12 @@ const char *v4l2_ctrl_get_name(u32 id)
>>>>
>>>>  	case V4L2_CID_FLASH_CHARGE:		return "Charge";
>>>>  	case V4L2_CID_FLASH_READY:		return "Ready to strobe";
>>>>
>>>> +	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image source controls";
>>>> +	case V4L2_CID_IMAGE_SOURCE_VBLANK:	return "Vertical blanking";
>>>> +	case V4L2_CID_IMAGE_SOURCE_HBLANK:	return "Horizontal blanking";
>>>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:	return "Link frequency";
>>>> +	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN: return "Analogue gain";
>>>
>>> Please capitalize each word, as done for the other controls.
>>
>> This isn't done for the flash controls either, have you noticed that?
>>
>> Well, I guess I have to admit that they were added by myself. ;-)
>>
>> I can fix this for the next patchset.
>>
>>>>  	default:
>>>>  		return NULL;
>>>>  	
>>>>  	}
>>>>
>>>> @@ -694,6 +700,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum
>>>>
>>>> v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
>>>>  		*type = V4L2_CTRL_TYPE_MENU;
>>>>  		break;
>>>>
>>>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:
>>>> +		*type = V4L2_CTRL_TYPE_INTEGER_MENU;
>>>> +		break;
>>>
>>> Will this always be an integer menu control, or can you foresee cases
>>> where the range would be continuous ?
>>
>> Good question. On some hardware this definitely is an integer menu, but
>> hardware may exist where more selections would be available.
>>
>> However, on e.g. the SMIA++ sensor the calculation of the clock tree
>> values depends heavily on the selected link rate. Choosing a wrong link
>> rate may yield to the clock tree calculation to fail. So the driver
>> likely would need to enforce some rules which values are allowed. That
>> might prove unfeasible --- already the PLL code in the SMIA++ driver is
>> relatively complex.
>>
>> I don't see much benefit in being able to specify this freely.
> 
> For SMIA++, definitely not. For other sensors, I don't know.

At least one Aptina sensor had a clock tree which basically had a few
dividers and a multiplier. The same restrictions apply.

>> AFAIR the conclusion was that controls may only have one type when the
>> control framework was written.
> 
> Yes, but I'm not sure whether that's a good conclusion :-)

It allows you to assume a type for controls, whether that's good or not.

This could be one use case for that, but I don't really see much
advantage in (attepmpting) to support fully free sensor link frequency
configuration.

Regards,

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 08/17] v4l: Image source control class
  2012-01-15 19:44         ` Sakari Ailus
@ 2012-01-15 20:00           ` Laurent Pinchart
  2012-01-15 21:27             ` Sakari Ailus
  0 siblings, 1 reply; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-15 20:00 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23

Hi Sakari,

On Sunday 15 January 2012 20:44:02 Sakari Ailus wrote:
> Laurent Pinchart wrote:
> > On Saturday 14 January 2012 21:51:31 Sakari Ailus wrote:
> >> Laurent Pinchart wrote:
> >>> On Tuesday 20 December 2011 21:28:00 Sakari Ailus wrote:
> >>>> From: Sakari Ailus <sakari.ailus@iki.fi>
> >>>> 
> >>>> Add image source control class. This control class is intended to
> >>>> contain low level controls which deal with control of the image
> >>>> capture process --- the A/D converter in image sensors, for example.
> >>>> 
> >>>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
> >>>> ---
> >>>> 
> >>>>  Documentation/DocBook/media/v4l/controls.xml       |  101
> >>>>  +++++++++++++++++ .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml      
> >>>>  |
> >>>>  
> >>>>     6 +
> >>>>  
> >>>>  drivers/media/video/v4l2-ctrls.c                   |   10 ++
> >>>>  include/linux/videodev2.h                          |   10 ++
> >>>>  4 files changed, 127 insertions(+), 0 deletions(-)
> >>>> 
> >>>> diff --git a/Documentation/DocBook/media/v4l/controls.xml
> >>>> b/Documentation/DocBook/media/v4l/controls.xml index 3bc5ee8..69ede83
> >>>> 100644
> >>>> --- a/Documentation/DocBook/media/v4l/controls.xml
> >>>> +++ b/Documentation/DocBook/media/v4l/controls.xml
> >>>> @@ -3356,6 +3356,107 @@ interface and may change in the future.</para>
> >>>> 
> >>>>        </table>
> >>>>      
> >>>>      </section>
> >>>> 
> >>>> +
> >>>> +    <section id="image-source-controls">
> >>>> +      <title>Image Source Control Reference</title>
> >>>> +
> >>>> +      <note>
> >>>> +	<title>Experimental</title>
> >>>> +
> >>>> +	<para>This is an <link
> >>>> +	linkend="experimental">experimental</link> interface and may
> >>>> +	change in the future.</para>
> >>>> +      </note>
> >>>> +
> >>>> +      <para>
> >>>> +	The Image Source control class is intended for low-level
> >>>> +	control of image source devices such as image sensors. The
> >>>> +	devices feature an analogue to digital converter and a bus
> >>> 
> >>> Is the V4L2 documentation written in US or UK English ? US uses analog,
> >>> UK uses analogue. Analog would be shorter in control names.
> >> 
> >> Both appear to be used, but the US English appears to be more commonly
> >> used. I guess it's mostly chosen by whatever happened to be used by the
> >> author of the patch. I prefer UK spelling which you might have noticed
> >> already. :-)
> > 
> > Yes I have. I haven't checked whether V4L2 prefers the UK or US spelling.
> > I'll trust you on that.
> 
> I have checked and most seem to have used US spelling. If you wish me to
> change it, I can do that.

As you (and others) wish.

> >> I remember there was a discussion on this topic years ago within the
> >> kernel community but I don't remember how it ended up with... LWN.net
> >> appears to remember better than I do, but by a quick check I can't find
> >> any definitive conclusion.
> >> 
> >> <URL:http://lwn.net/Articles/44262/>
> >> <URL:http://lkml.org/lkml/2003/8/7/245>
> >> 
> >>>> +	transmitter to transmit the image data out of the device.
> >>>> +      </para>
> >>>> +
> >>>> +      <table pgwide="1" frame="none" id="image-source-control-id">
> >>>> +      <title>Image Source Control IDs</title>
> >>>> +
> >>>> +      <tgroup cols="4">
> >>>> +	<colspec colname="c1" colwidth="1*" />
> >>>> +	<colspec colname="c2" colwidth="6*" />
> >>>> +	<colspec colname="c3" colwidth="2*" />
> >>>> +	<colspec colname="c4" colwidth="6*" />
> >>>> +	<spanspec namest="c1" nameend="c2" spanname="id" />
> >>>> +	<spanspec namest="c2" nameend="c4" spanname="descr" />
> >>>> +	<thead>
> >>>> +	  <row>
> >>>> +	    <entry spanname="id" align="left">ID</entry>
> >>>> +	    <entry align="left">Type</entry>
> >>>> +	  </row><row rowsep="1"><entry spanname="descr"
> >>>> align="left">Description</entry> +	  </row>
> >>>> +	</thead>
> >>>> +	<tbody valign="top">
> >>>> +	  <row><entry></entry></row>
> >>>> +	  <row>
> >>>> +	    <entry
> >>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry>
> >>>> +
> >>>> 
> >>>>   <entry>class</entry>
> >>>> 
> >>>> +	  </row>
> >>>> +	  <row>
> >>>> +	    <entry spanname="descr">The IMAGE_SOURCE class
> >>>> descriptor.</entry> +	  </row>
> >>>> +	  <row>
> >>>> +	    <entry
> >>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_VBLANK</constant></entry
> >>>> > +
> >>>> 
> >>>>    <entry>integer</entry>
> >>>> 
> >>>> +	  </row>
> >>>> +	  <row>
> >>>> +	    <entry spanname="descr">Vertical blanking. The idle
> >>>> +	    preriod after every frame during which no image data is
> >>> 
> >>> s/preriod/period/
> >>> 
> >>>> +	    produced. The unit of vertical blanking is a line. Every
> >>>> +	    line has length of the image width plus horizontal
> >>>> +	    blanking at the pixel clock specified by struct
> >>>> +	    v4l2_mbus_framefmt <xref linkend="v4l2-mbus-framefmt"
> >>>> +	    />.</entry>
> >>>> +	  </row>
> >>>> +	  <row>
> >>>> +	    <entry
> >>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_HBLANK</constant></entry
> >>>> > +
> >>>> 
> >>>>    <entry>integer</entry>
> >>>> 
> >>>> +	  </row>
> >>>> +	  <row>
> >>>> +	    <entry spanname="descr">Horizontal blanking. The idle
> >>>> +	    preriod after every line of image data during which no
> >>> 
> >>> s/preriod/period/
> >>> 
> >>>> +	    image data is produced. The unit of horizontal blanking is
> >>>> +	    pixels.</entry>
> >>>> +	  </row>
> >>>> +	  <row>
> >>>> +	    <entry
> >>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_LINK_FREQ</constant></en
> >>>> tr y> +	    <entry>integer menu</entry>
> >>>> +	  </row>
> >>>> +	  <row>
> >>>> +	    <entry spanname="descr">Image source's data bus frequency.
> >>> 
> >>> What's the frequency unit ? Sample/second ?
> >> 
> >> Hz --- that's the unit of frequency. I fixed that in the new version.
> > 
> > Is the user supposed to compute the pixel clock from this information ?
> > That's what the text below seems to imply.
> 
> Apparently I have forgotten to update this in the new patchset. But yes,
> these factors do define it. The sensors' internal clock tree will be
> involved and calculation is non-trivial. This is why we also have the
> PIXEL_RATE control --- where I will refer to in the next patchset.

How is the sensor clock tree involved ? My understanding is that it will 
define the data bus frequency based on the sensor input clock, but the bus 
data rate shouldn't be influenced by the clock tree for a given bus frequency.

Computing the pixel rate from the bus frequency isn't trivial and shouldn't be 
done by userspace if my understanding is correct. Documenting all this clearly 
would probably help :-)

> >>>> +	    Together with the media bus pixel code, bus type (clock
> >>>> +	    cycles per sample), the data bus frequency defines the
> >>>> +	    pixel clock. <xref linkend="v4l2-mbus-framefmt" /> The
> >>>> +	    frame rate can be calculated from the pixel clock, image
> >>>> +	    width and height and horizontal and vertical blanking. The
> >>>> +	    frame rate control is performed by selecting the desired
> >>>> +	    horizontal and vertical blanking.
> >>>> +	    </entry>
> >>>> +	  </row>
> >>>> +	  <row>
> >>>> +	    <entry
> >>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN</constant>
> >>>> </ en try> +	    <entry>integer</entry>
> >>>> +	  </row>
> >>>> +	  <row>
> >>>> +	    <entry spanname="descr">Analogue gain is gain affecting
> >>>> +	    all colour components in the pixel matrix. The gain
> >>>> +	    operation is performed in the analogue domain before A/D
> >>>> +	    conversion.
> >>> 
> >>> Should we define one gain per color component ?
> >> 
> >> I think that in the end we may need up to six analogue gains:
> >> 
> >> - Gain for all components
> > 
> > Many sensors that provide per-component gains also provide a global gain
> > control that sets the four component gains. I'm not sure how (and if) we
> > should handle that.
> 
> If it directly affects all of them, I don't think we should support it.
> But if it's independent of the colour-specific ones, then, sure, it
> should be supported.

It directly affects them. It's a shortcut. Maybe the R, G and B gain controls 
should then be put in a cluster, and if the user sets them to the same value 
the driver would optimize I2C communication by using the global gain control.

> >> - Blue gain
> >> - Red gain
> >> - Green gain (for both greens)
> >> - Gr gain
> >> - Gb gain
> >> 
> >> It may be debatable whether Gr / Gb gain will always be the same or not.
> >> I'm not fully certain about that. As Hans G. suggested, it might be
> >> possible to go with just one for green.
> > 
> > I'm also unsure about that. Having different gains for the two green
> > components doesn't seem very useful. On the other hand, if we find a use
> > case later, we'll have to break driver ABIs.
> 
> Let's add the gains later on. Now we'll need a single analogue gain for
> all components and that's good for the time being.
> 
> >>>> +	    </entry>
> >>>> +	  </row>
> >>>> +	  <row><entry></entry></row>
> >>>> +	</tbody>
> >>>> +      </tgroup>
> >>>> +      </table>
> >>>> +
> >>>> +    </section>
> >>>> +
> >>>> 
> >>>>  </section>
> >>>>  
> >>>>    <!--
> >>>> 
> >>>> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
> >>>> b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml index
> >>>> 5122ce8..250c1cf 100644
> >>>> --- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
> >>>> +++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
> >>>> @@ -257,6 +257,12 @@ These controls are described in <xref
> >>>> 
> >>>>  These controls are described in <xref
> >>>>  
> >>>>  		linkend="flash-controls" />.</entry>
> >>>>  		
> >>>>  	  </row>
> >>>> 
> >>>> +	  <row>
> >>>> +	    
<entry><constant>V4L2_CTRL_CLASS_IMAGE_SOURCE</constant></entry>
> >>>> +	    <entry>0x9d0000</entry> <entry>The class containing image
> >>>> +	    source controls. These controls are described in <xref
> >>>> +	    linkend="image-source-controls" />.</entry>
> >>>> +	  </row>
> >>>> 
> >>>>  	</tbody>
> >>>>  	
> >>>>        </tgroup>
> >>>>      
> >>>>      </table>
> >>>> 
> >>>> diff --git a/drivers/media/video/v4l2-ctrls.c
> >>>> b/drivers/media/video/v4l2-ctrls.c index 083bb79..da1ec52 100644
> >>>> --- a/drivers/media/video/v4l2-ctrls.c
> >>>> +++ b/drivers/media/video/v4l2-ctrls.c
> >>>> @@ -606,6 +606,12 @@ const char *v4l2_ctrl_get_name(u32 id)
> >>>> 
> >>>>  	case V4L2_CID_FLASH_CHARGE:		return "Charge";
> >>>>  	case V4L2_CID_FLASH_READY:		return "Ready to strobe";
> >>>> 
> >>>> +	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image source 
controls";
> >>>> +	case V4L2_CID_IMAGE_SOURCE_VBLANK:	return "Vertical blanking";
> >>>> +	case V4L2_CID_IMAGE_SOURCE_HBLANK:	return "Horizontal blanking";
> >>>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:	return "Link frequency";
> >>>> +	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN: return "Analogue gain";
> >>> 
> >>> Please capitalize each word, as done for the other controls.
> >> 
> >> This isn't done for the flash controls either, have you noticed that?
> >> 
> >> Well, I guess I have to admit that they were added by myself. ;-)
> >> 
> >> I can fix this for the next patchset.
> >> 
> >>>>  	default:
> >>>>  		return NULL;
> >>>>  	
> >>>>  	}
> >>>> 
> >>>> @@ -694,6 +700,9 @@ void v4l2_ctrl_fill(u32 id, const char **name,
> >>>> enum
> >>>> 
> >>>> v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
> >>>>  		*type = V4L2_CTRL_TYPE_MENU;
> >>>>  		break;
> >>>> 
> >>>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:
> >>>> +		*type = V4L2_CTRL_TYPE_INTEGER_MENU;
> >>>> +		break;
> >>> 
> >>> Will this always be an integer menu control, or can you foresee cases
> >>> where the range would be continuous ?
> >> 
> >> Good question. On some hardware this definitely is an integer menu, but
> >> hardware may exist where more selections would be available.
> >> 
> >> However, on e.g. the SMIA++ sensor the calculation of the clock tree
> >> values depends heavily on the selected link rate. Choosing a wrong link
> >> rate may yield to the clock tree calculation to fail. So the driver
> >> likely would need to enforce some rules which values are allowed. That
> >> might prove unfeasible --- already the PLL code in the SMIA++ driver is
> >> relatively complex.
> >> 
> >> I don't see much benefit in being able to specify this freely.
> > 
> > For SMIA++, definitely not. For other sensors, I don't know.
> 
> At least one Aptina sensor had a clock tree which basically had a few
> dividers and a multiplier. The same restrictions apply.
> 
> >> AFAIR the conclusion was that controls may only have one type when the
> >> control framework was written.
> > 
> > Yes, but I'm not sure whether that's a good conclusion :-)
> 
> It allows you to assume a type for controls, whether that's good or not.
> 
> This could be one use case for that, but I don't really see much
> advantage in (attepmpting) to support fully free sensor link frequency
> configuration.

Who will then be responsible for creating the list of available frequencies ?

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 08/17] v4l: Image source control class
  2012-01-15 19:30         ` Sakari Ailus
@ 2012-01-15 20:08           ` Sylwester Nawrocki
  0 siblings, 0 replies; 76+ messages in thread
From: Sylwester Nawrocki @ 2012-01-15 20:08 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: Laurent Pinchart, linux-media, dacohen

On 01/15/2012 08:30 PM, Sakari Ailus wrote:
> Hi Sylwester,
> 
> Sylwester Nawrocki wrote:
>> On 01/14/2012 09:51 PM, Sakari Ailus wrote:
>>>>> diff --git a/drivers/media/video/v4l2-ctrls.c
>>>>> b/drivers/media/video/v4l2-ctrls.c index 083bb79..da1ec52 100644
>>>>> --- a/drivers/media/video/v4l2-ctrls.c
>>>>> +++ b/drivers/media/video/v4l2-ctrls.c
>>>>> @@ -606,6 +606,12 @@ const char *v4l2_ctrl_get_name(u32 id)
>>>>>    	case V4L2_CID_FLASH_CHARGE:		return "Charge";
>>>>>    	case V4L2_CID_FLASH_READY:		return "Ready to strobe";
>>>>>
>>>>> +	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image source controls";
>>>>> +	case V4L2_CID_IMAGE_SOURCE_VBLANK:	return "Vertical blanking";
>>>>> +	case V4L2_CID_IMAGE_SOURCE_HBLANK:	return "Horizontal blanking";
>>>>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:	return "Link frequency";
>>>>> +	case V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN: return "Analogue gain";
>>>>
>>>> Please capitalize each word, as done for the other controls.
>>>
>>> This isn't done for the flash controls either, have you noticed that?
>>>
>>> Well, I guess I have to admit that they were added by myself. ;-)
>>>
>>> I can fix this for the next patchset.
>>
>> I don't want to be annoying (too much ;)) but the FLASH controls documentation
>> is missing some<constant>  tags in the text.  Other classes use them for
>> standard identifiers.
> 
> Thanks for letting me know --- that could be fixed with the flash timing
> control API, or unrelated to that. We should btw. continue discussion on
> that one. :-)

Sure, I remember having a patch for that style correction somewhere around.

Certainly the Flash topic needs continuation, I'll get back to it shortly.
I just need to do some more research about it and it is not of really high
priority on my side now. Plus I have temporarily been out of order for the
last week..

I have just prepared an auto focus controls draft patch. I'll post it
hopefully tonight to move things forward.

> Speaking of things to do... The colour of the object to point and press
> V4L2_CID_DO_WHITE_BALANCE (or what was it called) to fix the white
> balance --- is that white, gray, something else or implementation
> dependent? I vaguely remember having seen some grayish plates being used
> for that but I'm definitely not sure. :-) Any idea?

As far as I know it should be always an object which is perceived as white.
Something else don't seem to be terribly useful to set up white balance.
Unfortunately I don't have much of experience with that yet.

--
Regards,
Sylwester

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 08/17] v4l: Image source control class
  2012-01-15 20:00           ` Laurent Pinchart
@ 2012-01-15 21:27             ` Sakari Ailus
  0 siblings, 0 replies; 76+ messages in thread
From: Sakari Ailus @ 2012-01-15 21:27 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, dacohen, snjw23

Hi Laurent,

Laurent Pinchart wrote:
> On Sunday 15 January 2012 20:44:02 Sakari Ailus wrote:
>> Laurent Pinchart wrote:
>>> On Saturday 14 January 2012 21:51:31 Sakari Ailus wrote:
>>>> Laurent Pinchart wrote:
>>>>> On Tuesday 20 December 2011 21:28:00 Sakari Ailus wrote:
>>>>>> From: Sakari Ailus <sakari.ailus@iki.fi>
>>>>>>
>>>>>> Add image source control class. This control class is intended to
>>>>>> contain low level controls which deal with control of the image
>>>>>> capture process --- the A/D converter in image sensors, for example.
>>>>>>
>>>>>> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
>>>>>> ---
>>>>>>
>>>>>>  Documentation/DocBook/media/v4l/controls.xml       |  101
>>>>>>  +++++++++++++++++ .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml      
>>>>>>  |
>>>>>>  
>>>>>>     6 +
>>>>>>  
>>>>>>  drivers/media/video/v4l2-ctrls.c                   |   10 ++
>>>>>>  include/linux/videodev2.h                          |   10 ++
>>>>>>  4 files changed, 127 insertions(+), 0 deletions(-)
>>>>>>
>>>>>> diff --git a/Documentation/DocBook/media/v4l/controls.xml
>>>>>> b/Documentation/DocBook/media/v4l/controls.xml index 3bc5ee8..69ede83
>>>>>> 100644
>>>>>> --- a/Documentation/DocBook/media/v4l/controls.xml
>>>>>> +++ b/Documentation/DocBook/media/v4l/controls.xml
>>>>>> @@ -3356,6 +3356,107 @@ interface and may change in the future.</para>
>>>>>>
>>>>>>        </table>
>>>>>>      
>>>>>>      </section>
>>>>>>
>>>>>> +
>>>>>> +    <section id="image-source-controls">
>>>>>> +      <title>Image Source Control Reference</title>
>>>>>> +
>>>>>> +      <note>
>>>>>> +	<title>Experimental</title>
>>>>>> +
>>>>>> +	<para>This is an <link
>>>>>> +	linkend="experimental">experimental</link> interface and may
>>>>>> +	change in the future.</para>
>>>>>> +      </note>
>>>>>> +
>>>>>> +      <para>
>>>>>> +	The Image Source control class is intended for low-level
>>>>>> +	control of image source devices such as image sensors. The
>>>>>> +	devices feature an analogue to digital converter and a bus
>>>>>
>>>>> Is the V4L2 documentation written in US or UK English ? US uses analog,
>>>>> UK uses analogue. Analog would be shorter in control names.
>>>>
>>>> Both appear to be used, but the US English appears to be more commonly
>>>> used. I guess it's mostly chosen by whatever happened to be used by the
>>>> author of the patch. I prefer UK spelling which you might have noticed
>>>> already. :-)
>>>
>>> Yes I have. I haven't checked whether V4L2 prefers the UK or US spelling.
>>> I'll trust you on that.
>>
>> I have checked and most seem to have used US spelling. If you wish me to
>> change it, I can do that.
> 
> As you (and others) wish.
> 
>>>> I remember there was a discussion on this topic years ago within the
>>>> kernel community but I don't remember how it ended up with... LWN.net
>>>> appears to remember better than I do, but by a quick check I can't find
>>>> any definitive conclusion.
>>>>
>>>> <URL:http://lwn.net/Articles/44262/>
>>>> <URL:http://lkml.org/lkml/2003/8/7/245>
>>>>
>>>>>> +	transmitter to transmit the image data out of the device.
>>>>>> +      </para>
>>>>>> +
>>>>>> +      <table pgwide="1" frame="none" id="image-source-control-id">
>>>>>> +      <title>Image Source Control IDs</title>
>>>>>> +
>>>>>> +      <tgroup cols="4">
>>>>>> +	<colspec colname="c1" colwidth="1*" />
>>>>>> +	<colspec colname="c2" colwidth="6*" />
>>>>>> +	<colspec colname="c3" colwidth="2*" />
>>>>>> +	<colspec colname="c4" colwidth="6*" />
>>>>>> +	<spanspec namest="c1" nameend="c2" spanname="id" />
>>>>>> +	<spanspec namest="c2" nameend="c4" spanname="descr" />
>>>>>> +	<thead>
>>>>>> +	  <row>
>>>>>> +	    <entry spanname="id" align="left">ID</entry>
>>>>>> +	    <entry align="left">Type</entry>
>>>>>> +	  </row><row rowsep="1"><entry spanname="descr"
>>>>>> align="left">Description</entry> +	  </row>
>>>>>> +	</thead>
>>>>>> +	<tbody valign="top">
>>>>>> +	  <row><entry></entry></row>
>>>>>> +	  <row>
>>>>>> +	    <entry
>>>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry>
>>>>>> +
>>>>>>
>>>>>>   <entry>class</entry>
>>>>>>
>>>>>> +	  </row>
>>>>>> +	  <row>
>>>>>> +	    <entry spanname="descr">The IMAGE_SOURCE class
>>>>>> descriptor.</entry> +	  </row>
>>>>>> +	  <row>
>>>>>> +	    <entry
>>>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_VBLANK</constant></entry
>>>>>>> +
>>>>>>
>>>>>>    <entry>integer</entry>
>>>>>>
>>>>>> +	  </row>
>>>>>> +	  <row>
>>>>>> +	    <entry spanname="descr">Vertical blanking. The idle
>>>>>> +	    preriod after every frame during which no image data is
>>>>>
>>>>> s/preriod/period/
>>>>>
>>>>>> +	    produced. The unit of vertical blanking is a line. Every
>>>>>> +	    line has length of the image width plus horizontal
>>>>>> +	    blanking at the pixel clock specified by struct
>>>>>> +	    v4l2_mbus_framefmt <xref linkend="v4l2-mbus-framefmt"
>>>>>> +	    />.</entry>
>>>>>> +	  </row>
>>>>>> +	  <row>
>>>>>> +	    <entry
>>>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_HBLANK</constant></entry
>>>>>>> +
>>>>>>
>>>>>>    <entry>integer</entry>
>>>>>>
>>>>>> +	  </row>
>>>>>> +	  <row>
>>>>>> +	    <entry spanname="descr">Horizontal blanking. The idle
>>>>>> +	    preriod after every line of image data during which no
>>>>>
>>>>> s/preriod/period/
>>>>>
>>>>>> +	    image data is produced. The unit of horizontal blanking is
>>>>>> +	    pixels.</entry>
>>>>>> +	  </row>
>>>>>> +	  <row>
>>>>>> +	    <entry
>>>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_LINK_FREQ</constant></en
>>>>>> tr y> +	    <entry>integer menu</entry>
>>>>>> +	  </row>
>>>>>> +	  <row>
>>>>>> +	    <entry spanname="descr">Image source's data bus frequency.
>>>>>
>>>>> What's the frequency unit ? Sample/second ?
>>>>
>>>> Hz --- that's the unit of frequency. I fixed that in the new version.
>>>
>>> Is the user supposed to compute the pixel clock from this information ?
>>> That's what the text below seems to imply.
>>
>> Apparently I have forgotten to update this in the new patchset. But yes,
>> these factors do define it. The sensors' internal clock tree will be
>> involved and calculation is non-trivial. This is why we also have the
>> PIXEL_RATE control --- where I will refer to in the next patchset.
> 
> How is the sensor clock tree involved ? My understanding is that it will 
> define the data bus frequency based on the sensor input clock, but the bus 
> data rate shouldn't be influenced by the clock tree for a given bus frequency.

Uh, I was referring to the  pixel array. On the CSI-2 receiver, there
are also factors like data bus width, bits-per-pixel and lane count that
affect the pixel rate on the bus. I don't think the user should be
required to know about them.

> Computing the pixel rate from the bus frequency isn't trivial and shouldn't be 
> done by userspace if my understanding is correct. Documenting all this clearly 
> would probably help :-)

The idea is that by defining all these factors one can query the real
pixel rate from the pixel array. That pixel rate will be constant as
long as all the above parameters are. Then blanking can be changed to
lower the frame rate (taking the policy decisions at the same time).

I guess I could put it in a more clear way.

>>>>>> +	    Together with the media bus pixel code, bus type (clock
>>>>>> +	    cycles per sample), the data bus frequency defines the
>>>>>> +	    pixel clock. <xref linkend="v4l2-mbus-framefmt" /> The
>>>>>> +	    frame rate can be calculated from the pixel clock, image
>>>>>> +	    width and height and horizontal and vertical blanking. The
>>>>>> +	    frame rate control is performed by selecting the desired
>>>>>> +	    horizontal and vertical blanking.
>>>>>> +	    </entry>
>>>>>> +	  </row>
>>>>>> +	  <row>
>>>>>> +	    <entry
>>>>>> spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_ANALOGUE_GAIN</constant>
>>>>>> </ en try> +	    <entry>integer</entry>
>>>>>> +	  </row>
>>>>>> +	  <row>
>>>>>> +	    <entry spanname="descr">Analogue gain is gain affecting
>>>>>> +	    all colour components in the pixel matrix. The gain
>>>>>> +	    operation is performed in the analogue domain before A/D
>>>>>> +	    conversion.
>>>>>
>>>>> Should we define one gain per color component ?
>>>>
>>>> I think that in the end we may need up to six analogue gains:
>>>>
>>>> - Gain for all components
>>>
>>> Many sensors that provide per-component gains also provide a global gain
>>> control that sets the four component gains. I'm not sure how (and if) we
>>> should handle that.
>>
>> If it directly affects all of them, I don't think we should support it.
>> But if it's independent of the colour-specific ones, then, sure, it
>> should be supported.
> 
> It directly affects them. It's a shortcut. Maybe the R, G and B gain controls 
> should then be put in a cluster, and if the user sets them to the same value 
> the driver would optimize I2C communication by using the global gain control.

A cluster would be fine, I guess. But on some other hardware the
all-component gain could be independent of the per-component ones.

...

>>>>>> @@ -694,6 +700,9 @@ void v4l2_ctrl_fill(u32 id, const char **name,
>>>>>> enum
>>>>>>
>>>>>> v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
>>>>>>  		*type = V4L2_CTRL_TYPE_MENU;
>>>>>>  		break;
>>>>>>
>>>>>> +	case V4L2_CID_IMAGE_SOURCE_LINK_FREQ:
>>>>>> +		*type = V4L2_CTRL_TYPE_INTEGER_MENU;
>>>>>> +		break;
>>>>>
>>>>> Will this always be an integer menu control, or can you foresee cases
>>>>> where the range would be continuous ?
>>>>
>>>> Good question. On some hardware this definitely is an integer menu, but
>>>> hardware may exist where more selections would be available.
>>>>
>>>> However, on e.g. the SMIA++ sensor the calculation of the clock tree
>>>> values depends heavily on the selected link rate. Choosing a wrong link
>>>> rate may yield to the clock tree calculation to fail. So the driver
>>>> likely would need to enforce some rules which values are allowed. That
>>>> might prove unfeasible --- already the PLL code in the SMIA++ driver is
>>>> relatively complex.
>>>>
>>>> I don't see much benefit in being able to specify this freely.
>>>
>>> For SMIA++, definitely not. For other sensors, I don't know.
>>
>> At least one Aptina sensor had a clock tree which basically had a few
>> dividers and a multiplier. The same restrictions apply.
>>
>>>> AFAIR the conclusion was that controls may only have one type when the
>>>> control framework was written.
>>>
>>> Yes, but I'm not sure whether that's a good conclusion :-)
>>
>> It allows you to assume a type for controls, whether that's good or not.
>>
>> This could be one use case for that, but I don't really see much
>> advantage in (attepmpting) to support fully free sensor link frequency
>> configuration.
> 
> Who will then be responsible for creating the list of available frequencies ?

That would be the one who defines also the other board specific
parameters such as the number of lanes. The link frequency has to fill
several requirements, and some of that is policy whereas some is not.

Things to consider are system memory bus data rate, CSI-2 receiver's (or
ISP's) memory access priority compared to other users, maximum pixel
rate of the CSI-2 receiver (and also that of the ISP, if the CSI-2
receiver is part of it), sensor's external clock frequency and
properties of the sensor clock tree (the frequency must be achievable
using the available PLL divisors and multipliers) and at least on some
boards, also system's EMC requirements.

I don't think the above list is exhaustive.

For example, on OMAP 3[67]xx based boards it could make sense to define
data rates which can produce pixel rates close to 500 MHz and 250 MHz
which correspond to the maximum speed of the CSI-2 receiver and the ISP
(100 Mp/s) with two lanes (CSI-2 transfers 2 bits for every clock cycle).

One could also define the highest operating point to be less than that,
which would likely have an effect to the desired link frequencies. 34xx
has smaller maximum ISP data rate, so if you connect the same sensor to
that you'll likely want to change the supported link rate(s).

Regards,

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 06/17] v4l: Add selections documentation.
  2012-01-09 18:16     ` Sakari Ailus
  2012-01-10 11:20       ` Tomasz Stanislawski
@ 2012-01-15 22:53       ` Laurent Pinchart
  1 sibling, 0 replies; 76+ messages in thread
From: Laurent Pinchart @ 2012-01-15 22:53 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, dacohen, snjw23, Tomasz Stanislawski

Hi Sakari,

On Monday 09 January 2012 19:16:16 Sakari Ailus wrote:
> Laurent Pinchart wrote:
> > On Tuesday 20 December 2011 21:27:58 Sakari Ailus wrote:

[snip]

> >> The PADDED target
> >> +      provides the width and height for the padded image,
> > 
> > Is it valid for both crop and compose rectangles ?
> 
> I think all targets are valid for all rectangles. Should I mention that?
> 
> The practical use cases may be more limited, though. I wonder if I
> should remove the padded targets until we get use cases for them. I
> included them for the reason that they also exist in the V4L2.
> 
> Tomasz, Sylwester: do you have use for the PADDED targets?
> 
> I think we also must define what will be done in cases where crop (on
> either sink or source) / scaling / composition is not supported by the
> subdev. That's currently undefined. I think it'd be most clear to return
> an error code but I'm not sure which one --- EINVAL is an obvious
> candidate but that is also returned when the pad is wrong. It looks
> still like the best choice to me.

If the rectangle isn't supported, EINVAL is appropriate. Do we need a way to 
discover what rectangles are supported ?

If the rectangle is supported by the size is out of range, the driver should 
adjust it instead of returning an error.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [RFC 16/17] smiapp: Add driver.
  2012-01-07 23:01     ` Sakari Ailus
@ 2012-01-16 21:57       ` Sylwester Nawrocki
  0 siblings, 0 replies; 76+ messages in thread
From: Sylwester Nawrocki @ 2012-01-16 21:57 UTC (permalink / raw)
  To: Sakari Ailus; +Cc: linux-media, laurent.pinchart, dacohen

Hi Sakari,

On 01/08/2012 12:01 AM, Sakari Ailus wrote:
>>> +/*
>>> + *
>>> + * V4L2 Controls handling
>>> + *
>>> + */
>>> +
>>> +static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
>>> +{
>>> +	struct v4l2_ctrl *ctrl = sensor->exposure;
>>> +	int max;
>>> +
>>> +	max = sensor->pixel_array->compose[SMIAPP_PAD_SOURCE].height
>>> +		+ sensor->vblank->val -
>>> +		sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
>>> +
>>> +	ctrl->maximum = max;
>>> +	if (ctrl->default_value>   max)
>>> +		ctrl->default_value = max;
>>> +	if (ctrl->val>   max)
>>> +		ctrl->val = max;
>>> +	if (ctrl->cur.val>   max)
>>> +		ctrl->cur.val = max;
>>> +}
>>
>> One more driver that needs control value range update. :)
> 
> :-)
> 
> Are there other drivers that would need something like that, too?
> Anything in the control framework that I have missed related to this?

Yes, I needed that in s5p-fimc driver for the alpha component control.
The alpha channel value range depends on colour format and the control 
needs to be updated accordingly to changes done with VIDIOC_S_FMT.

And no, there is yet nothing in the control framework to support this.
Hans just prepared some proof-of-concept patch [1], but the decision was
to hold on until there appear more drivers needing control value range
update, due to hight complication of life in the userland.

[1] http://www.mail-archive.com/linux-media@vger.kernel.org/msg39674.html

--
Regards,
Sylwester

^ permalink raw reply	[flat|nested] 76+ messages in thread

end of thread, other threads:[~2012-01-16 21:57 UTC | newest]

Thread overview: 76+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-20 20:27 [RFC 0/17] V4L2 subdev and sensor control changes, SMIA++ driver and N9 camera board code Sakari Ailus
2011-12-20 20:27 ` [RFC 01/17] v4l: Introduce integer menu controls Sakari Ailus
2012-01-05 15:53   ` Laurent Pinchart
2012-01-06  9:50     ` Sakari Ailus
2011-12-20 20:27 ` [RFC 02/17] v4l: Document " Sakari Ailus
2012-01-05 15:55   ` Laurent Pinchart
2012-01-06 10:07     ` Sakari Ailus
2011-12-20 20:27 ` [RFC 03/17] vivi: Add an integer menu test control Sakari Ailus
2012-01-05 15:59   ` Laurent Pinchart
2012-01-06 10:19     ` Sakari Ailus
2012-01-06 10:22       ` Sakari Ailus
2012-01-06 10:28         ` Laurent Pinchart
2011-12-20 20:27 ` [RFC 04/17] v4l: VIDIOC_SUBDEV_S_SELECTION and VIDIOC_SUBDEV_G_SELECTION IOCTLs Sakari Ailus
2012-01-05 16:12   ` Laurent Pinchart
2012-01-06 11:27     ` Sakari Ailus
2012-01-06 12:00       ` Laurent Pinchart
2012-01-07  9:09         ` Sakari Ailus
2012-01-07 11:09           ` Sakari Ailus
2012-01-07 15:54             ` Laurent Pinchart
2012-01-07 16:53               ` Sakari Ailus
2011-12-20 20:27 ` [RFC 05/17] v4l: Support s_crop and g_crop through s/g_selection Sakari Ailus
2012-01-05 16:13   ` Laurent Pinchart
2012-01-08 20:54     ` Sakari Ailus
2011-12-20 20:27 ` [RFC 06/17] v4l: Add selections documentation Sakari Ailus
2012-01-06 11:43   ` Laurent Pinchart
2012-01-09 18:16     ` Sakari Ailus
2012-01-10 11:20       ` Tomasz Stanislawski
2012-01-14 19:04         ` Sakari Ailus
2012-01-15 22:53       ` Laurent Pinchart
2011-12-20 20:27 ` [RFC 07/17] v4l: Add pixelrate to struct v4l2_mbus_framefmt Sakari Ailus
2012-01-06 10:26   ` Laurent Pinchart
2012-01-08 21:16     ` Sakari Ailus
2011-12-20 20:28 ` [RFC 08/17] v4l: Image source control class Sakari Ailus
2012-01-05 16:23   ` Laurent Pinchart
2012-01-14 20:51     ` Sakari Ailus
2012-01-15  1:43       ` Laurent Pinchart
2012-01-15 19:44         ` Sakari Ailus
2012-01-15 20:00           ` Laurent Pinchart
2012-01-15 21:27             ` Sakari Ailus
2012-01-15 16:16       ` Sylwester Nawrocki
2012-01-15 19:30         ` Sakari Ailus
2012-01-15 20:08           ` Sylwester Nawrocki
2011-12-20 20:28 ` [RFC 09/17] v4l: Add pad op for pipeline validation Sakari Ailus
2012-01-06  9:42   ` Laurent Pinchart
2012-01-07 23:28     ` Sakari Ailus
2012-01-08 18:20       ` Laurent Pinchart
2011-12-20 20:28 ` [RFC 10/17] omap3: add definition for CONTROL_CAMERA_PHY_CTRL Sakari Ailus
2011-12-20 20:28 ` [RFC 11/17] omap3isp: Implement validate_pipeline Sakari Ailus
2011-12-20 20:28 ` [RFC 12/17] omap3isp: Add lane configuration to platform data Sakari Ailus
2012-01-06 10:06   ` Laurent Pinchart
2012-01-07 23:39     ` Sakari Ailus
2011-12-20 20:28 ` [RFC 13/17] omap3isp: Configure CSI-2 phy based on " Sakari Ailus
2012-01-06 10:01   ` Laurent Pinchart
2012-01-07 22:51     ` Sakari Ailus
2012-01-08  1:02       ` Laurent Pinchart
2012-01-08 10:26         ` Sakari Ailus
2012-01-08 11:07           ` Sylwester Nawrocki
2012-01-08 11:16             ` Sakari Ailus
2012-01-08 13:09               ` Sylwester Nawrocki
2012-01-11  8:08                 ` Sakari Ailus
2012-01-08 11:15           ` Laurent Pinchart
2011-12-20 20:28 ` [RFC 14/17] omap3isp: Use pixelrate from sensor media bus frameformat Sakari Ailus
2012-01-06 10:14   ` Laurent Pinchart
2012-01-07 23:05     ` Sakari Ailus
2011-12-20 20:28 ` [RFC 15/17] omap3isp: Move definitions required by board code under include/media Sakari Ailus
2011-12-20 20:28 ` [RFC 16/17] smiapp: Add driver Sakari Ailus
2012-01-06 17:12   ` Sylwester Nawrocki
2012-01-07 23:01     ` Sakari Ailus
2012-01-16 21:57       ` Sylwester Nawrocki
2011-12-20 20:28 ` [RFC 17/17] rm680: Add camera init Sakari Ailus
2012-01-06 10:21   ` Laurent Pinchart
2012-01-07 21:30     ` Sakari Ailus
2012-01-06 14:58   ` Sylwester Nawrocki
2012-01-07 22:59     ` Sakari Ailus
2011-12-28  9:47 ` [yavta PATCH 1/1] Support integer menus Sakari Ailus
2012-01-05 16:03   ` Laurent Pinchart

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.