ソースを参照

Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:
 - removal of sn9c102.  This device driver was replaced a long time ago
   by gspca
 - solo6x10 and go7007 webcam drivers moved from staging into
   mainstream.  They were waiting for an API to allow setting the image
   detection matrix
 - SDR drivers moved from staging into mainstream: sdr-msi3101 (renamed
   as msi2500) and rtl2832
 - added SDR driver for airspy
 - added demux driver: si2165
 - rework at several RC subsystem, making the code for RC-5 SZ variant
   to be added at the standard RC5 decoder
 - added decoder for the XMP IR protocol
 - tuner driver moved from staging into mainstream: msi3101 (renamed as
   msi001)
 - added documentation for some additional SDR pixfmt
 - some device tree bindings documented
 - added support for exynos3250 at s5p-jpeg
 - remove the obsolete, unmaintained and broken mx1_camera driver
 - added support for remote controllers at au0828 driver
 - added a RC driver: sunxi-cir
 - several driver fixes, enhancements and cleanups.

* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (455 commits)
  [media] cx23885: fix UNSET/TUNER_ABSENT confusion
  [media] coda: fix build error by making reset control optional
  [media] radio-miropcm20: fix sparse NULL pointer warning
  [media] MAINTAINERS: Update go7007 pattern
  [media] MAINTAINERS: Update solo6x10 patterns
  [media] media: atmel-isi: add primary DT support
  [media] media: atmel-isi: convert the pdata from pointer to structure
  [media] media: atmel-isi: add v4l2 async probe support
  [media] rcar_vin: add devicetree support
  [media] media: pxa_camera device-tree support
  [media] media: mt9m111: add device-tree suppport
  [media] soc_camera: add support for dt binding soc_camera drivers
  [media] media: soc_camera: pxa_camera documentation device-tree support
  [media] media: mt9m111: add device-tree documentation
  [media] s5p-mfc: remove unnecessary calling to function video_devdata()
  [media] s5p-jpeg: add chroma subsampling adjustment for Exynos3250
  [media] s5p-jpeg: Prevent erroneous downscaling for Exynos3250 SoC
  [media] s5p-jpeg: Assure proper crop rectangle initialization
  [media] s5p-jpeg: fix g_selection op
  [media] s5p-jpeg: Adjust jpeg_bound_align_image to Exynos3250 needs
  ...
Linus Torvalds 11 年 前
コミット
f4d33337ea
100 ファイル変更4544 行追加1610 行削除
  1. 1 1
      Documentation/DocBook/media/Makefile
  2. 40 4
      Documentation/DocBook/media/dvb/dvbproperty.xml
  3. 334 74
      Documentation/DocBook/media/v4l/controls.xml
  4. 9 3
      Documentation/DocBook/media/v4l/dev-raw-vbi.xml
  5. 14 4
      Documentation/DocBook/media/v4l/dev-sdr.xml
  6. 8 1
      Documentation/DocBook/media/v4l/dev-sliced-vbi.xml
  7. 7 2
      Documentation/DocBook/media/v4l/io.xml
  8. 395 23
      Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
  9. 44 0
      Documentation/DocBook/media/v4l/pixfmt-sdr-cs08.xml
  10. 47 0
      Documentation/DocBook/media/v4l/pixfmt-sdr-cs14le.xml
  11. 40 0
      Documentation/DocBook/media/v4l/pixfmt-sdr-ru12le.xml
  12. 1 1
      Documentation/DocBook/media/v4l/pixfmt-srggb12.xml
  13. 56 5
      Documentation/DocBook/media/v4l/pixfmt.xml
  14. 47 48
      Documentation/DocBook/media/v4l/selection-api.xml
  15. 8 0
      Documentation/DocBook/media/v4l/v4l2.xml
  16. 50 0
      Documentation/DocBook/media/v4l/vidioc-dqevent.xml
  17. 43 8
      Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
  18. 4 8
      Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml
  19. 19 21
      Documentation/DocBook/media/v4l/vidioc-g-selection.xml
  20. 6 0
      Documentation/DocBook/media/v4l/vidioc-querycap.xml
  21. 197 37
      Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
  22. 8 0
      Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
  23. 51 0
      Documentation/devicetree/bindings/media/atmel-isi.txt
  24. 8 4
      Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt
  25. 28 0
      Documentation/devicetree/bindings/media/i2c/mt9m111.txt
  26. 43 0
      Documentation/devicetree/bindings/media/pxa-camera.txt
  27. 86 0
      Documentation/devicetree/bindings/media/rcar_vin.txt
  28. 23 0
      Documentation/devicetree/bindings/media/sunxi-ir.txt
  29. 32 1
      Documentation/dvb/get_dvb_firmware
  30. 2 0
      Documentation/video4linux/CARDLIST.cx23885
  31. 1 1
      Documentation/video4linux/CARDLIST.em28xx
  32. 39 24
      Documentation/video4linux/v4l2-controls.txt
  33. 1 7
      Documentation/video4linux/v4l2-framework.txt
  34. 0 5
      Documentation/video4linux/v4l2-pci-skeleton.c
  35. 1 6
      Documentation/zh_CN/video4linux/v4l2-framework.txt
  36. 28 24
      MAINTAINERS
  37. 1 1
      drivers/hid/hid-picolcd_cir.c
  38. 10 2
      drivers/media/Kconfig
  39. 6 8
      drivers/media/common/saa7146/saa7146_fops.c
  40. 1 2
      drivers/media/common/siano/Kconfig
  41. 1 1
      drivers/media/common/siano/smsir.c
  42. 2 0
      drivers/media/dvb-core/dvb-usb-ids.h
  43. 17 19
      drivers/media/dvb-core/dvb_frontend.c
  44. 6 0
      drivers/media/dvb-core/dvb_frontend.h
  45. 4 0
      drivers/media/dvb-core/dvbdev.h
  46. 18 0
      drivers/media/dvb-frontends/Kconfig
  47. 7 0
      drivers/media/dvb-frontends/Makefile
  48. 0 1
      drivers/media/dvb-frontends/af9013.c
  49. 121 59
      drivers/media/dvb-frontends/au8522_decoder.c
  50. 2 0
      drivers/media/dvb-frontends/au8522_priv.h
  51. 6 0
      drivers/media/dvb-frontends/cxd2820r.h
  52. 1 0
      drivers/media/dvb-frontends/cxd2820r_c.c
  53. 1 0
      drivers/media/dvb-frontends/cxd2820r_t.c
  54. 1 0
      drivers/media/dvb-frontends/cxd2820r_t2.c
  55. 12 3
      drivers/media/dvb-frontends/dib0090.c
  56. 1 4
      drivers/media/dvb-frontends/dib7000m.c
  57. 401 32
      drivers/media/dvb-frontends/dib7000p.c
  58. 22 109
      drivers/media/dvb-frontends/dib7000p.h
  59. 389 343
      drivers/media/dvb-frontends/dib8000.c
  60. 25 125
      drivers/media/dvb-frontends/dib8000.h
  61. 9 4
      drivers/media/dvb-frontends/dib9000.c
  62. 109 119
      drivers/media/dvb-frontends/drx39xyj/drxj.c
  63. 0 1
      drivers/media/dvb-frontends/drxd.h
  64. 1 2
      drivers/media/dvb-frontends/drxd_hard.c
  65. 83 2
      drivers/media/dvb-frontends/m88ds3103.c
  66. 2 0
      drivers/media/dvb-frontends/m88ds3103_priv.h
  67. 13 22
      drivers/media/dvb-frontends/mb86a20s.c
  68. 77 23
      drivers/media/dvb-frontends/rtl2832_sdr.c
  69. 0 0
      drivers/media/dvb-frontends/rtl2832_sdr.h
  70. 1040 0
      drivers/media/dvb-frontends/si2165.c
  71. 62 0
      drivers/media/dvb-frontends/si2165.h
  72. 23 0
      drivers/media/dvb-frontends/si2165_priv.h
  73. 104 162
      drivers/media/dvb-frontends/si2168.c
  74. 6 3
      drivers/media/dvb-frontends/si2168_priv.h
  75. 16 26
      drivers/media/dvb-frontends/stb6100_cfg.h
  76. 10 24
      drivers/media/dvb-frontends/stb6100_proc.h
  77. 2 7
      drivers/media/dvb-frontends/stv0367.c
  78. 1 1
      drivers/media/dvb-frontends/tda18271c2dd.c
  79. 4 4
      drivers/media/dvb-frontends/tda18271c2dd_maps.h
  80. 11 19
      drivers/media/dvb-frontends/tda8261_cfg.h
  81. 1 0
      drivers/media/i2c/Kconfig
  82. 0 1
      drivers/media/i2c/adv7180.c
  83. 4 1
      drivers/media/i2c/adv7604.c
  84. 48 47
      drivers/media/i2c/ir-kbd-i2c.c
  85. 94 76
      drivers/media/i2c/mt9v032.c
  86. 1 0
      drivers/media/i2c/noon010pc30.c
  87. 1 0
      drivers/media/i2c/s5k4ecgx.c
  88. 2 0
      drivers/media/i2c/s5k5baf.c
  89. 1 0
      drivers/media/i2c/s5k6a3.c
  90. 10 7
      drivers/media/i2c/smiapp/smiapp-core.c
  91. 3 3
      drivers/media/i2c/soc_camera/mt9m001.c
  92. 12 0
      drivers/media/i2c/soc_camera/mt9m111.c
  93. 3 3
      drivers/media/i2c/soc_camera/mt9t031.c
  94. 2 2
      drivers/media/i2c/soc_camera/mt9v022.c
  95. 13 22
      drivers/media/i2c/tvp5150.c
  96. 0 2
      drivers/media/media-device.c
  97. 0 3
      drivers/media/parport/bw-qcam.c
  98. 0 1
      drivers/media/parport/c-qcam.c
  99. 0 1
      drivers/media/parport/pms.c
  100. 0 1
      drivers/media/parport/w9966.c

+ 1 - 1
Documentation/DocBook/media/Makefile

@@ -174,7 +174,7 @@ FILENAME = \
 DOCUMENTED = \
 	-e "s/\(enum *\)v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1<link linkend=\"\2\">v4l2_mpeg_cx2341x_video_\2<\/link>/g" \
 	-e "s/\(\(enum\|struct\) *\)\(v4l2_[a-zA-Z0-9_]*\)/\1<link linkend=\"\3\">\3<\/link>/g" \
-	-e "s/\(V4L2_PIX_FMT_[A-Z0-9_]\+\) /<link linkend=\"\1\">\1<\/link> /g" \
+	-e "s/\(V4L2_PIX_FMT_[A-Z0-9_]\+\)\(\s\+v4l2_fourcc\)/<link linkend=\"\1\">\1<\/link>\2/g" \
 	-e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \
 	-e "s/v4l2\-mpeg\-vbi\-ITV0/v4l2-mpeg-vbi-itv0-1/g"
 

+ 40 - 4
Documentation/DocBook/media/dvb/dvbproperty.xml

@@ -555,10 +555,46 @@ typedef enum fe_delivery_system {
 		</section>
 		<section id="DTV-ISDBT-LAYER-TIME-INTERLEAVING">
 			<title><constant>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</constant></title>
-			<para>Possible values: 0, 1, 2, 3, -1 (AUTO)</para>
-			<para>Note: The real inter-leaver depth-names depend on the mode (fft-size); the values
-				here are referring to what can be found in the TMCC-structure -
-				independent of the mode.</para>
+			<para>Valid values: 0, 1, 2, 4, -1 (AUTO)</para>
+			<para>when DTV_ISDBT_SOUND_BROADCASTING is active, value 8 is also valid.</para>
+			<para>Note: The real time interleaving length depends on the mode (fft-size). The values
+				here are referring to what can be found in the TMCC-structure, as shown in the table below.</para>
+			<informaltable id="isdbt-layer-interleaving-table">
+				<tgroup cols="4" align="center">
+					<tbody>
+						<row>
+							<entry>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</entry>
+							<entry>Mode 1 (2K FFT)</entry>
+							<entry>Mode 2 (4K FFT)</entry>
+							<entry>Mode 3 (8K FFT)</entry>
+						</row>
+						<row>
+							<entry>0</entry>
+							<entry>0</entry>
+							<entry>0</entry>
+							<entry>0</entry>
+						</row>
+						<row>
+							<entry>1</entry>
+							<entry>4</entry>
+							<entry>2</entry>
+							<entry>1</entry>
+						</row>
+						<row>
+							<entry>2</entry>
+							<entry>8</entry>
+							<entry>4</entry>
+							<entry>2</entry>
+						</row>
+						<row>
+							<entry>4</entry>
+							<entry>16</entry>
+							<entry>8</entry>
+							<entry>4</entry>
+						</row>
+					</tbody>
+				</tgroup>
+			</informaltable>
 		</section>
 		<section id="DTV-ATSCMH-FIC-VER">
 			<title><constant>DTV_ATSCMH_FIC_VER</constant></title>

+ 334 - 74
Documentation/DocBook/media/v4l/controls.xml

@@ -13,6 +13,19 @@ correctly with any device.</para>
     <para>All controls are accessed using an ID value. V4L2 defines
 several IDs for specific purposes. Drivers can also implement their
 own custom controls using <constant>V4L2_CID_PRIVATE_BASE</constant>
+<footnote><para>The use of <constant>V4L2_CID_PRIVATE_BASE</constant>
+is problematic because different drivers may use the same
+<constant>V4L2_CID_PRIVATE_BASE</constant> ID for different controls.
+This makes it hard to programatically set such controls since the meaning
+of the control with that ID is driver dependent. In order to resolve this
+drivers use unique IDs and the <constant>V4L2_CID_PRIVATE_BASE</constant>
+IDs are mapped to those unique IDs by the kernel. Consider these
+<constant>V4L2_CID_PRIVATE_BASE</constant> IDs as aliases to the real
+IDs.</para>
+<para>Many applications today still use the <constant>V4L2_CID_PRIVATE_BASE</constant>
+IDs instead of using &VIDIOC-QUERYCTRL; with the <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>
+flag to enumerate all IDs, so support for <constant>V4L2_CID_PRIVATE_BASE</constant>
+is still around.</para></footnote>
 and higher values. The pre-defined control IDs have the prefix
 <constant>V4L2_CID_</constant>, and are listed in <xref
 linkend="control-id" />. The ID is used when querying the attributes of
@@ -31,25 +44,22 @@ the current video input or output, tuner or modulator, or audio input
 or output. Different in the sense of other bounds, another default and
 current value, step size or other menu items. A control with a certain
 <emphasis>custom</emphasis> ID can also change name and
-type.<footnote>
-	<para>It will be more convenient for applications if drivers
-make use of the <constant>V4L2_CTRL_FLAG_DISABLED</constant> flag, but
-that was never required.</para>
-      </footnote> Control values are stored globally, they do not
+type.</para>
+
+    <para>If a control is not applicable to the current configuration
+of the device (for example, it doesn't apply to the current video input)
+drivers set the <constant>V4L2_CTRL_FLAG_INACTIVE</constant> flag.</para>
+
+    <para>Control values are stored globally, they do not
 change when switching except to stay within the reported bounds. They
 also do not change &eg; when the device is opened or closed, when the
 tuner radio frequency is changed or generally never without
-application request. Since V4L2 specifies no event mechanism, panel
-applications intended to cooperate with other panel applications (be
-they built into a larger application, as a TV viewer) may need to
-regularly poll control values to update their user
-interface.<footnote>
-	<para>Applications could call an ioctl to request events.
-After another process called &VIDIOC-S-CTRL; or another ioctl changing
-shared properties the &func-select; function would indicate
-readability until any ioctl (querying the properties) is
-called.</para>
-      </footnote></para>
+application request.</para>
+
+    <para>V4L2 specifies an event mechanism to notify applications
+when controls change value (see &VIDIOC-SUBSCRIBE-EVENT;, event
+<constant>V4L2_EVENT_CTRL</constant>), panel applications might want to make
+use of that in order to always reflect the correct control value.</para>
 
     <para>
       All controls use machine endianness.
@@ -398,14 +408,17 @@ to work.</entry>
 	  <row id="v4l2-alpha-component">
 	    <entry><constant>V4L2_CID_ALPHA_COMPONENT</constant></entry>
 	    <entry>integer</entry>
-	    <entry> Sets the alpha color component on the capture device or on
-	    the capture buffer queue of a mem-to-mem device. When a mem-to-mem
-	    device produces frame format that includes an alpha component
+	    <entry>Sets the alpha color component. When a capture device (or
+	    capture queue of a mem-to-mem device) produces a frame format that
+	    includes an alpha component
 	    (e.g. <link linkend="rgb-formats">packed RGB image formats</link>)
-	    and the alpha value is not defined by the mem-to-mem input data
-	    this control lets you select the alpha component value of all
-	    pixels. It is applicable to any pixel format that contains an alpha
-	    component.
+	    and the alpha value is not defined by the device or the mem-to-mem
+	    input data this control lets you select the alpha component value of
+	    all pixels. When an output device (or output queue of a mem-to-mem
+	    device) consumes a frame format that doesn't include an alpha
+	    component and the device supports alpha channel processing this
+	    control lets you set the alpha component value of all pixels for
+	    further processing in the device.
 	    </entry>
 	  </row>
 	  <row>
@@ -434,73 +447,98 @@ Drivers must implement <constant>VIDIOC_QUERYCTRL</constant>,
 controls, <constant>VIDIOC_QUERYMENU</constant> when it has one or
 more menu type controls.</para>
 
-    <example>
-      <title>Enumerating all controls</title>
+    <example id="enum_all_controls">
+      <title>Enumerating all user controls</title>
 
       <programlisting>
 &v4l2-queryctrl; queryctrl;
 &v4l2-querymenu; querymenu;
 
-static void
-enumerate_menu (void)
+static void enumerate_menu(void)
 {
-	printf ("  Menu items:\n");
+	printf("  Menu items:\n");
 
-	memset (&amp;querymenu, 0, sizeof (querymenu));
+	memset(&amp;querymenu, 0, sizeof(querymenu));
 	querymenu.id = queryctrl.id;
 
 	for (querymenu.index = queryctrl.minimum;
 	     querymenu.index &lt;= queryctrl.maximum;
-	      querymenu.index++) {
-		if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
-			printf ("  %s\n", querymenu.name);
+	     querymenu.index++) {
+		if (0 == ioctl(fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
+			printf("  %s\n", querymenu.name);
 		}
 	}
 }
 
-memset (&amp;queryctrl, 0, sizeof (queryctrl));
+memset(&amp;queryctrl, 0, sizeof(queryctrl));
 
 for (queryctrl.id = V4L2_CID_BASE;
      queryctrl.id &lt; V4L2_CID_LASTP1;
      queryctrl.id++) {
-	if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+	if (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
 		if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
 			continue;
 
-		printf ("Control %s\n", queryctrl.name);
+		printf("Control %s\n", queryctrl.name);
 
 		if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
-			enumerate_menu ();
+			enumerate_menu();
 	} else {
 		if (errno == EINVAL)
 			continue;
 
-		perror ("VIDIOC_QUERYCTRL");
-		exit (EXIT_FAILURE);
+		perror("VIDIOC_QUERYCTRL");
+		exit(EXIT_FAILURE);
 	}
 }
 
 for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
      queryctrl.id++) {
-	if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+	if (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
 		if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
 			continue;
 
-		printf ("Control %s\n", queryctrl.name);
+		printf("Control %s\n", queryctrl.name);
 
 		if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
-			enumerate_menu ();
+			enumerate_menu();
 	} else {
 		if (errno == EINVAL)
 			break;
 
-		perror ("VIDIOC_QUERYCTRL");
-		exit (EXIT_FAILURE);
+		perror("VIDIOC_QUERYCTRL");
+		exit(EXIT_FAILURE);
 	}
 }
 </programlisting>
     </example>
 
+    <example>
+      <title>Enumerating all user controls (alternative)</title>
+	<programlisting>
+memset(&amp;queryctrl, 0, sizeof(queryctrl));
+
+queryctrl.id = V4L2_CTRL_CLASS_USER | V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+	if (V4L2_CTRL_ID2CLASS(queryctrl.id) != V4L2_CTRL_CLASS_USER)
+		break;
+	if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
+		continue;
+
+	printf("Control %s\n", queryctrl.name);
+
+	if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+		enumerate_menu();
+
+	queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}
+if (errno != EINVAL) {
+	perror("VIDIOC_QUERYCTRL");
+	exit(EXIT_FAILURE);
+}
+</programlisting>
+    </example>
+
     <example>
       <title>Changing controls</title>
 
@@ -508,53 +546,53 @@ for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
 &v4l2-queryctrl; queryctrl;
 &v4l2-control; control;
 
-memset (&amp;queryctrl, 0, sizeof (queryctrl));
+memset(&amp;queryctrl, 0, sizeof(queryctrl));
 queryctrl.id = V4L2_CID_BRIGHTNESS;
 
-if (-1 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+if (-1 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
 	if (errno != EINVAL) {
-		perror ("VIDIOC_QUERYCTRL");
-		exit (EXIT_FAILURE);
+		perror("VIDIOC_QUERYCTRL");
+		exit(EXIT_FAILURE);
 	} else {
-		printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+		printf("V4L2_CID_BRIGHTNESS is not supported\n");
 	}
 } else if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED) {
-	printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+	printf("V4L2_CID_BRIGHTNESS is not supported\n");
 } else {
-	memset (&amp;control, 0, sizeof (control));
+	memset(&amp;control, 0, sizeof (control));
 	control.id = V4L2_CID_BRIGHTNESS;
 	control.value = queryctrl.default_value;
 
-	if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)) {
-		perror ("VIDIOC_S_CTRL");
-		exit (EXIT_FAILURE);
+	if (-1 == ioctl(fd, &VIDIOC-S-CTRL;, &amp;control)) {
+		perror("VIDIOC_S_CTRL");
+		exit(EXIT_FAILURE);
 	}
 }
 
-memset (&amp;control, 0, sizeof (control));
+memset(&amp;control, 0, sizeof(control));
 control.id = V4L2_CID_CONTRAST;
 
-if (0 == ioctl (fd, &VIDIOC-G-CTRL;, &amp;control)) {
+if (0 == ioctl(fd, &VIDIOC-G-CTRL;, &amp;control)) {
 	control.value += 1;
 
 	/* The driver may clamp the value or return ERANGE, ignored here */
 
-	if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)
+	if (-1 == ioctl(fd, &VIDIOC-S-CTRL;, &amp;control)
 	    &amp;&amp; errno != ERANGE) {
-		perror ("VIDIOC_S_CTRL");
-		exit (EXIT_FAILURE);
+		perror("VIDIOC_S_CTRL");
+		exit(EXIT_FAILURE);
 	}
 /* Ignore if V4L2_CID_CONTRAST is unsupported */
 } else if (errno != EINVAL) {
-	perror ("VIDIOC_G_CTRL");
-	exit (EXIT_FAILURE);
+	perror("VIDIOC_G_CTRL");
+	exit(EXIT_FAILURE);
 }
 
 control.id = V4L2_CID_AUDIO_MUTE;
-control.value = TRUE; /* silence */
+control.value = 1; /* silence */
 
 /* Errors ignored */
-ioctl (fd, VIDIOC_S_CTRL, &amp;control);
+ioctl(fd, VIDIOC_S_CTRL, &amp;control);
 </programlisting>
     </example>
   </section>
@@ -625,16 +663,29 @@ supported.</para>
 &v4l2-control;, except for the fact that it also allows for 64-bit
 values and pointers to be passed.</para>
 
+      <para>Since the &v4l2-ext-control; supports pointers it is now
+also possible to have controls with compound types such as N-dimensional arrays
+and/or structures. You need to specify the <constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant>
+when enumerating controls to actually be able to see such compound controls.
+In other words, these controls with compound types should only be used
+programmatically.</para>
+
+      <para>Since such compound controls need to expose more information
+about themselves than is possible with &VIDIOC-QUERYCTRL; the
+&VIDIOC-QUERY-EXT-CTRL; ioctl was added. In particular, this ioctl gives
+the dimensions of the N-dimensional array if this control consists of more than
+one element.</para>
+
       <para>It is important to realize that due to the flexibility of
 controls it is necessary to check whether the control you want to set
 actually is supported in the driver and what the valid range of values
-is. So use the &VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls to
-check this. Also note that it is possible that some of the menu
-indices in a control of type <constant>V4L2_CTRL_TYPE_MENU</constant>
-may not be supported (<constant>VIDIOC_QUERYMENU</constant> will
-return an error). A good example is the list of supported MPEG audio
-bitrates. Some drivers only support one or two bitrates, others
-support a wider range.</para>
+is. So use the &VIDIOC-QUERYCTRL; (or &VIDIOC-QUERY-EXT-CTRL;) and
+&VIDIOC-QUERYMENU; ioctls to check this. Also note that it is possible
+that some of the menu indices in a control of type
+<constant>V4L2_CTRL_TYPE_MENU</constant> may not be supported
+(<constant>VIDIOC_QUERYMENU</constant> will return an error). A good
+example is the list of supported MPEG audio bitrates. Some drivers only
+support one or two bitrates, others support a wider range.</para>
 
       <para>
 	All controls use machine endianness.
@@ -675,12 +726,12 @@ control class is found:</para>
       <informalexample>
 	<programlisting>
 qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
-while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
-	if (V4L2_CTRL_ID2CLASS (qctrl.id) != V4L2_CTRL_CLASS_MPEG)
+while (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
+	if (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_MPEG)
 		break;
 		/* ... */
-		qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
-	}
+	qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}
 </programlisting>
       </informalexample>
 
@@ -700,7 +751,7 @@ ID based on a control ID.</para>
 <constant>VIDIOC_QUERYCTRL</constant> will fail when used in
 combination with <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>. In
 that case the old method of enumerating control should be used (see
-1.8). But if it is supported, then it is guaranteed to enumerate over
+<xref linkend="enum_all_controls" />). But if it is supported, then it is guaranteed to enumerate over
 all controls, including driver-private controls.</para>
     </section>
 
@@ -3998,6 +4049,68 @@ in Annex E of <xref linkend="iec62106" />. The length of Radio Text strings depe
 used to transmit it, either 32 (2A block) or 64 (2B block).  However, it is also possible
 to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
 with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_MONO_STEREO</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the Mono/Stereo bit of the Decoder Identification code. If set,
+then the audio was recorded as stereo.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_ARTIFICIAL_HEAD</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the
+<ulink url="http://en.wikipedia.org/wiki/Artificial_head">Artificial Head</ulink> bit of the Decoder
+Identification code. If set, then the audio was recorded using an artificial head.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_COMPRESSED</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the Compressed bit of the Decoder Identification code. If set,
+then the audio is compressed.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_DYNAMIC_PTY</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the Dynamic PTY bit of the Decoder Identification code. If set,
+then the PTY code is dynamically switched.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then a traffic announcement is in progress.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_TRAFFIC_PROGRAM</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then the tuned programme carries traffic announcements.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_MUSIC_SPEECH</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then this channel broadcasts music. If cleared, then it
+broadcasts speech. If the transmitter doesn't make this distinction, then it should be set.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_ALT_FREQS_ENABLE</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then transmit alternate frequencies.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_ALT_FREQS</constant>&nbsp;</entry>
+	    <entry>__u32 array</entry>
+	  </row>
+	  <row><entry spanname="descr">The alternate frequencies in kHz units. The RDS standard allows
+for up to 25 frequencies to be defined. Drivers may support fewer frequencies so check
+the array size.</entry>
 	  </row>
 	  <row>
 	    <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_ENABLED</constant>&nbsp;</entry>
@@ -4976,6 +5089,57 @@ description of this control class.</entry>
           </row><row><entry spanname="descr">Enables/disables RDS
 	  reception by the radio tuner</entry>
           </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_PTY</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Gets RDS Programme Type field.
+This encodes up to 31 pre-defined programme types.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_PS_NAME</constant>&nbsp;</entry>
+	    <entry>string</entry>
+	  </row>
+	  <row><entry spanname="descr">Gets the Programme Service name (PS_NAME).
+It is intended for static display on a receiver. It is the primary aid to listeners in programme service
+identification and selection.  In Annex E of <xref linkend="iec62106" />, the RDS specification,
+there is a full description of the correct character encoding for Programme Service name strings.
+Also from RDS specification, PS is usually a single eight character text. However, it is also possible
+to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
+with steps of 8 characters. The result is it must always contain a string with size multiple of 8.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_RADIO_TEXT</constant>&nbsp;</entry>
+	    <entry>string</entry>
+	  </row>
+	  <row><entry spanname="descr">Gets the Radio Text info. It is a textual description of
+what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
+programme-related information or any other text. In these cases, RadioText can be used in addition to
+<constant>V4L2_CID_RDS_RX_PS_NAME</constant>. The encoding for Radio Text strings is also fully described
+in Annex E of <xref linkend="iec62106" />. The length of Radio Text strings depends on which RDS Block is being
+used to transmit it, either 32 (2A block) or 64 (2B block).  However, it is also possible
+to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
+with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then a traffic announcement is in progress.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_TRAFFIC_PROGRAM</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then the tuned programme carries traffic announcements.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_MUSIC_SPEECH</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then this channel broadcasts music. If cleared, then it
+broadcasts speech. If the transmitter doesn't make this distinction, then it will be set.</entry>
+	  </row>
           <row>
 	    <entry spanname="id"><constant>V4L2_CID_TUNE_DEEMPHASIS</constant>&nbsp;</entry>
 	    <entry>enum v4l2_deemphasis</entry>
@@ -5007,6 +5171,102 @@ defines possible values for de-emphasis. Here they are:</entry>
         </tbody>
       </tgroup>
       </table>
+    </section>
+
+    <section id="detect-controls">
+      <title>Detect Control Reference</title>
+
+      <para>The Detect class includes controls for common features of
+      various motion or object detection capable devices.</para>
+
+      <table pgwide="1" frame="none" id="detect-control-id">
+      <title>Detect 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_DETECT_CLASS</constant>&nbsp;</entry>
+            <entry>class</entry>
+          </row><row><entry spanname="descr">The Detect class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.</entry>
+          </row>
+          <row>
+            <entry spanname="id"><constant>V4L2_CID_DETECT_MD_MODE</constant>&nbsp;</entry>
+            <entry>menu</entry>
+          </row><row><entry spanname="descr">Sets the motion detection mode.</entry>
+          </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_DETECT_MD_MODE_DISABLED</constant>
+		  </entry><entry>Disable motion detection.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_DETECT_MD_MODE_GLOBAL</constant>
+		  </entry><entry>Use a single motion detection threshold.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_DETECT_MD_MODE_THRESHOLD_GRID</constant>
+		  </entry><entry>The image is divided into a grid, each cell with its own
+		  motion detection threshold. These thresholds are set through the
+		  <constant>V4L2_CID_DETECT_MD_THRESHOLD_GRID</constant> matrix control.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_DETECT_MD_MODE_REGION_GRID</constant>
+		  </entry><entry>The image is divided into a grid, each cell with its own
+		  region value that specifies which per-region motion detection thresholds
+		  should be used. Each region has its own thresholds. How these per-region
+		  thresholds are set up is driver-specific. The region values for the grid are set
+		  through the <constant>V4L2_CID_DETECT_MD_REGION_GRID</constant> matrix
+		  control.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+          <row>
+	    <entry spanname="id"><constant>V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the global motion detection threshold to be
+	  used with the <constant>V4L2_DETECT_MD_MODE_GLOBAL</constant> motion detection mode.</entry>
+          </row>
+          <row>
+	    <entry spanname="id"><constant>V4L2_CID_DETECT_MD_THRESHOLD_GRID</constant>&nbsp;</entry>
+	    <entry>__u16 matrix</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the motion detection thresholds for each cell in the grid.
+	  To be used with the <constant>V4L2_DETECT_MD_MODE_THRESHOLD_GRID</constant>
+	  motion detection mode. Matrix element (0, 0) represents the cell at the top-left of the
+	  grid.</entry>
+          </row>
+          <row>
+	    <entry spanname="id"><constant>V4L2_CID_DETECT_MD_REGION_GRID</constant>&nbsp;</entry>
+	    <entry>__u8 matrix</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the motion detection region value for each cell in the grid.
+	  To be used with the <constant>V4L2_DETECT_MD_MODE_REGION_GRID</constant>
+	  motion detection mode. Matrix element (0, 0) represents the cell at the top-left of the
+	  grid.</entry>
+          </row>
+        </tbody>
+      </tgroup>
+      </table>
 
       </section>
 

+ 9 - 3
Documentation/DocBook/media/v4l/dev-raw-vbi.xml

@@ -150,9 +150,15 @@ signal. Drivers shall not convert the sample format by software.</para></entry>
 	      <entry>This is the scanning system line number
 associated with the first line of the VBI image, of the first and the
 second field respectively. See <xref linkend="vbi-525" /> and
-<xref linkend="vbi-625" /> for valid values. VBI input drivers can
-return start values 0 if the hardware cannot reliable identify
-scanning lines, VBI acquisition may not require this
+<xref linkend="vbi-625" /> for valid values.
+The <constant>V4L2_VBI_ITU_525_F1_START</constant>,
+<constant>V4L2_VBI_ITU_525_F2_START</constant>,
+<constant>V4L2_VBI_ITU_625_F1_START</constant> and
+<constant>V4L2_VBI_ITU_625_F2_START</constant> defines give the start line
+numbers for each field for each 525 or 625 line format as a convenience.
+Don't forget that ITU line numbering starts at 1, not 0.
+VBI input drivers can return start values 0 if the hardware cannot
+reliable identify scanning lines, VBI acquisition may not require this
 information.</entry>
 	    </row>
 	    <row>

+ 14 - 4
Documentation/DocBook/media/v4l/dev-sdr.xml

@@ -72,9 +72,12 @@ To use the <link linkend="format">format</link> ioctls applications set the
 <constant>V4L2_BUF_TYPE_SDR_CAPTURE</constant> and use the &v4l2-sdr-format;
 <structfield>sdr</structfield> member of the <structfield>fmt</structfield>
 union as needed per the desired operation.
-Currently only the <structfield>pixelformat</structfield> field of
-&v4l2-sdr-format; is used. The content of that field is the V4L2 fourcc code
-of the data format.
+Currently there is two fields, <structfield>pixelformat</structfield> and
+<structfield>buffersize</structfield>, of struct &v4l2-sdr-format; which are
+used. Content of the <structfield>pixelformat</structfield> is V4L2 FourCC
+code of the data format. The <structfield>buffersize</structfield> field is
+maximum buffer size in bytes required for data transfer, set by the driver in
+order to inform application.
     </para>
 
     <table pgwide="1" frame="none" id="v4l2-sdr-format">
@@ -91,9 +94,16 @@ little endian <link linkend="v4l2-fourcc">four character code</link>.
 V4L2 defines SDR formats in <xref linkend="sdr-formats" />.
            </entry>
           </row>
+          <row>
+            <entry>__u32</entry>
+            <entry><structfield>buffersize</structfield></entry>
+            <entry>
+Maximum size in bytes required for data. Value is set by the driver.
+           </entry>
+          </row>
           <row>
             <entry>__u8</entry>
-            <entry><structfield>reserved[28]</structfield></entry>
+            <entry><structfield>reserved[24]</structfield></entry>
             <entry>This array is reserved for future extensions.
 Drivers and applications must set it to zero.</entry>
           </row>

+ 8 - 1
Documentation/DocBook/media/v4l/dev-sliced-vbi.xml

@@ -185,7 +185,14 @@ tables, sigh. --></para></entry>
 	    <entry></entry>
 	    <entry spanname="hspan">Drivers must set
 <structfield>service_lines</structfield>[0][0] and
-<structfield>service_lines</structfield>[1][0] to zero.</entry>
+<structfield>service_lines</structfield>[1][0] to zero.
+The <constant>V4L2_VBI_ITU_525_F1_START</constant>,
+<constant>V4L2_VBI_ITU_525_F2_START</constant>,
+<constant>V4L2_VBI_ITU_625_F1_START</constant> and
+<constant>V4L2_VBI_ITU_625_F2_START</constant> defines give the start
+line numbers for each field for each 525 or 625 line format as a
+convenience.  Don't forget that ITU line numbering starts at 1, not 0.
+</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>

+ 7 - 2
Documentation/DocBook/media/v4l/io.xml

@@ -870,7 +870,8 @@ should set this to 0.</entry>
 	      If the application sets this to 0 for an output stream, then
 	      <structfield>bytesused</structfield> will be set to the size of the
 	      plane (see the <structfield>length</structfield> field of this struct)
-	      by the driver.</entry>
+	      by the driver. Note that the actual image data starts at
+	      <structfield>data_offset</structfield> which may not be 0.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
@@ -919,6 +920,10 @@ should set this to 0.</entry>
 	    <entry>Offset in bytes to video data in the plane.
 	      Drivers must set this field when <structfield>type</structfield>
 	      refers to an input stream, applications when it refers to an output stream.
+	      Note that data_offset is included in <structfield>bytesused</structfield>.
+	      So the size of the image in the plane is
+	      <structfield>bytesused</structfield>-<structfield>data_offset</structfield> at
+	      offset <structfield>data_offset</structfield> from the start of the plane.
 	    </entry>
 	  </row>
 	  <row>
@@ -1066,7 +1071,7 @@ state, in the application domain so to say.</entry>
 	  <entry>Drivers set or clear this flag when calling the
 <constant>VIDIOC_DQBUF</constant> ioctl. It may be set by video
 capture devices when the buffer contains a compressed image which is a
-key frame (or field), &ie; can be decompressed on its own. Also know as
+key frame (or field), &ie; can be decompressed on its own. Also known as
 an I-frame.  Applications can set this bit when <structfield>type</structfield>
 refers to an output stream.</entry>
 	  </row>

+ 395 - 23
Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml

@@ -15,9 +15,6 @@ typical PC graphics frame buffers. They occupy 8, 16, 24 or 32 bits
 per pixel. These are all packed-pixel formats, meaning all the data
 for a pixel lie next to each other in memory.</para>
 
-    <para>When one of these formats is used, drivers shall report the
-colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
-
     <table pgwide="1" frame="none" id="rgb-formats">
       <title>Packed RGB Image Formats</title>
       <tgroup cols="37" align="center">
@@ -130,9 +127,9 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
 	    <entry>b<subscript>1</subscript></entry>
 	    <entry>b<subscript>0</subscript></entry>
 	  </row>
-	  <row id="V4L2-PIX-FMT-RGB444">
-	    <entry><constant>V4L2_PIX_FMT_RGB444</constant></entry>
-	    <entry>'R444'</entry>
+	  <row id="V4L2-PIX-FMT-ARGB444">
+	    <entry><constant>V4L2_PIX_FMT_ARGB444</constant></entry>
+	    <entry>'AR12'</entry>
 	    <entry></entry>
 	    <entry>g<subscript>3</subscript></entry>
 	    <entry>g<subscript>2</subscript></entry>
@@ -152,9 +149,31 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
 	    <entry>r<subscript>1</subscript></entry>
 	    <entry>r<subscript>0</subscript></entry>
 	  </row>
-	  <row id="V4L2-PIX-FMT-RGB555">
-	    <entry><constant>V4L2_PIX_FMT_RGB555</constant></entry>
-	    <entry>'RGBO'</entry>
+	  <row id="V4L2-PIX-FMT-XRGB444">
+	    <entry><constant>V4L2_PIX_FMT_XRGB444</constant></entry>
+	    <entry>'XR12'</entry>
+	    <entry></entry>
+	    <entry>g<subscript>3</subscript></entry>
+	    <entry>g<subscript>2</subscript></entry>
+	    <entry>g<subscript>1</subscript></entry>
+	    <entry>g<subscript>0</subscript></entry>
+	    <entry>b<subscript>3</subscript></entry>
+	    <entry>b<subscript>2</subscript></entry>
+	    <entry>b<subscript>1</subscript></entry>
+	    <entry>b<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>r<subscript>3</subscript></entry>
+	    <entry>r<subscript>2</subscript></entry>
+	    <entry>r<subscript>1</subscript></entry>
+	    <entry>r<subscript>0</subscript></entry>
+	  </row>
+	  <row id="V4L2-PIX-FMT-ARGB555">
+	    <entry><constant>V4L2_PIX_FMT_ARGB555</constant></entry>
+	    <entry>'AR15'</entry>
 	    <entry></entry>
 	    <entry>g<subscript>2</subscript></entry>
 	    <entry>g<subscript>1</subscript></entry>
@@ -174,6 +193,28 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
 	    <entry>g<subscript>4</subscript></entry>
 	    <entry>g<subscript>3</subscript></entry>
 	  </row>
+	  <row id="V4L2-PIX-FMT-XRGB555">
+	    <entry><constant>V4L2_PIX_FMT_XRGB555</constant></entry>
+	    <entry>'XR15'</entry>
+	    <entry></entry>
+	    <entry>g<subscript>2</subscript></entry>
+	    <entry>g<subscript>1</subscript></entry>
+	    <entry>g<subscript>0</subscript></entry>
+	    <entry>b<subscript>4</subscript></entry>
+	    <entry>b<subscript>3</subscript></entry>
+	    <entry>b<subscript>2</subscript></entry>
+	    <entry>b<subscript>1</subscript></entry>
+	    <entry>b<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>-</entry>
+	    <entry>r<subscript>4</subscript></entry>
+	    <entry>r<subscript>3</subscript></entry>
+	    <entry>r<subscript>2</subscript></entry>
+	    <entry>r<subscript>1</subscript></entry>
+	    <entry>r<subscript>0</subscript></entry>
+	    <entry>g<subscript>4</subscript></entry>
+	    <entry>g<subscript>3</subscript></entry>
+	  </row>
 	  <row id="V4L2-PIX-FMT-RGB565">
 	    <entry><constant>V4L2_PIX_FMT_RGB565</constant></entry>
 	    <entry>'RGBP'</entry>
@@ -341,9 +382,9 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
 	    <entry>b<subscript>1</subscript></entry>
 	    <entry>b<subscript>0</subscript></entry>
 	  </row>
-	  <row id="V4L2-PIX-FMT-BGR32">
-	    <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
-	    <entry>'BGR4'</entry>
+	  <row id="V4L2-PIX-FMT-ABGR32">
+	    <entry><constant>V4L2_PIX_FMT_ABGR32</constant></entry>
+	    <entry>'AR24'</entry>
 	    <entry></entry>
 	    <entry>b<subscript>7</subscript></entry>
 	    <entry>b<subscript>6</subscript></entry>
@@ -381,9 +422,49 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
 	    <entry>a<subscript>1</subscript></entry>
 	    <entry>a<subscript>0</subscript></entry>
 	  </row>
-	  <row id="V4L2-PIX-FMT-RGB32">
-	    <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
-	    <entry>'RGB4'</entry>
+	  <row id="V4L2-PIX-FMT-XBGR32">
+	    <entry><constant>V4L2_PIX_FMT_XBGR32</constant></entry>
+	    <entry>'XR24'</entry>
+	    <entry></entry>
+	    <entry>b<subscript>7</subscript></entry>
+	    <entry>b<subscript>6</subscript></entry>
+	    <entry>b<subscript>5</subscript></entry>
+	    <entry>b<subscript>4</subscript></entry>
+	    <entry>b<subscript>3</subscript></entry>
+	    <entry>b<subscript>2</subscript></entry>
+	    <entry>b<subscript>1</subscript></entry>
+	    <entry>b<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>g<subscript>7</subscript></entry>
+	    <entry>g<subscript>6</subscript></entry>
+	    <entry>g<subscript>5</subscript></entry>
+	    <entry>g<subscript>4</subscript></entry>
+	    <entry>g<subscript>3</subscript></entry>
+	    <entry>g<subscript>2</subscript></entry>
+	    <entry>g<subscript>1</subscript></entry>
+	    <entry>g<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>r<subscript>7</subscript></entry>
+	    <entry>r<subscript>6</subscript></entry>
+	    <entry>r<subscript>5</subscript></entry>
+	    <entry>r<subscript>4</subscript></entry>
+	    <entry>r<subscript>3</subscript></entry>
+	    <entry>r<subscript>2</subscript></entry>
+	    <entry>r<subscript>1</subscript></entry>
+	    <entry>r<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	  </row>
+	  <row id="V4L2-PIX-FMT-ARGB32">
+	    <entry><constant>V4L2_PIX_FMT_ARGB32</constant></entry>
+	    <entry>'AX24'</entry>
 	    <entry></entry>
 	    <entry>a<subscript>7</subscript></entry>
 	    <entry>a<subscript>6</subscript></entry>
@@ -421,18 +502,76 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
 	    <entry>b<subscript>1</subscript></entry>
 	    <entry>b<subscript>0</subscript></entry>
 	  </row>
+	  <row id="V4L2-PIX-FMT-XRGB32">
+	    <entry><constant>V4L2_PIX_FMT_XRGB32</constant></entry>
+	    <entry>'BX24'</entry>
+	    <entry></entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry>-</entry>
+	    <entry></entry>
+	    <entry>r<subscript>7</subscript></entry>
+	    <entry>r<subscript>6</subscript></entry>
+	    <entry>r<subscript>5</subscript></entry>
+	    <entry>r<subscript>4</subscript></entry>
+	    <entry>r<subscript>3</subscript></entry>
+	    <entry>r<subscript>2</subscript></entry>
+	    <entry>r<subscript>1</subscript></entry>
+	    <entry>r<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>g<subscript>7</subscript></entry>
+	    <entry>g<subscript>6</subscript></entry>
+	    <entry>g<subscript>5</subscript></entry>
+	    <entry>g<subscript>4</subscript></entry>
+	    <entry>g<subscript>3</subscript></entry>
+	    <entry>g<subscript>2</subscript></entry>
+	    <entry>g<subscript>1</subscript></entry>
+	    <entry>g<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>b<subscript>7</subscript></entry>
+	    <entry>b<subscript>6</subscript></entry>
+	    <entry>b<subscript>5</subscript></entry>
+	    <entry>b<subscript>4</subscript></entry>
+	    <entry>b<subscript>3</subscript></entry>
+	    <entry>b<subscript>2</subscript></entry>
+	    <entry>b<subscript>1</subscript></entry>
+	    <entry>b<subscript>0</subscript></entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
 
-    <para>Bit 7 is the most significant bit. The value of the a = alpha
-bits is undefined when reading from the driver, ignored when writing
-to the driver, except when alpha blending has been negotiated for a
-<link linkend="overlay">Video Overlay</link> or <link linkend="osd">
-Video Output Overlay</link> or when the alpha component has been configured
-for a <link linkend="capture">Video Capture</link> by means of <link
-linkend="v4l2-alpha-component"> <constant>V4L2_CID_ALPHA_COMPONENT
-</constant> </link> control.</para>
+    <para>Bit 7 is the most significant bit.</para>
+
+    <para>The usage and value of the alpha bits (a) in the ARGB and ABGR formats
+    (collectively referred to as alpha formats) depend on the device type and
+    hardware operation. <link linkend="capture">Capture</link> devices
+    (including capture queues of mem-to-mem devices) fill the alpha component in
+    memory. When the device outputs an alpha channel the alpha component will
+    have a meaningful value. Otherwise, when the device doesn't output an alpha
+    channel but can set the alpha bit to a user-configurable value, the <link
+    linkend="v4l2-alpha-component"><constant>V4L2_CID_ALPHA_COMPONENT</constant>
+    </link> control is used to specify that alpha value, and the alpha component
+    of all pixels will be set to the value specified by that control. Otherwise
+    a corresponding format without an alpha component (XRGB or XBGR) must be
+    used instead of an alpha format.</para>
+
+    <para><link linkend="output">Output</link> devices (including output queues
+    of mem-to-mem devices and <link linkend="osd">video output overlay</link>
+    devices) read the alpha component from memory. When the device processes the
+    alpha channel the alpha component must be filled with meaningful values by
+    applications. Otherwise a corresponding format without an alpha component
+    (XRGB or XBGR) must be used instead of an alpha format.</para>
+
+    <para>The XRGB and XBGR formats contain undefined bits (-). Applications,
+    devices and drivers must ignore those bits, for both <link
+    linkend="capture">capture</link> and <link linkend="output">output</link>
+    devices.</para>
 
     <example>
       <title><constant>V4L2_PIX_FMT_BGR24</constant> 4 &times; 4 pixel
@@ -512,6 +651,239 @@ image</title>
       </formalpara>
     </example>
 
+    <para>Formats defined in <xref linkend="rgb-formats-deprecated"/> are
+    deprecated and must not be used by new drivers. They are documented here for
+    reference. The meaning of their alpha bits (a) is ill-defined and
+    interpreted as in either the corresponding ARGB or XRGB format, depending on
+    the driver.</para>
+
+    <table pgwide="1" frame="none" id="rgb-formats-deprecated">
+      <title>Deprecated Packed RGB Image Formats</title>
+      <tgroup cols="37" align="center">
+	<colspec colname="id" align="left" />
+	<colspec colname="fourcc" />
+	<colspec colname="bit" />
+
+	<colspec colnum="4" colname="b07" align="center" />
+	<colspec colnum="5" colname="b06" align="center" />
+	<colspec colnum="6" colname="b05" align="center" />
+	<colspec colnum="7" colname="b04" align="center" />
+	<colspec colnum="8" colname="b03" align="center" />
+	<colspec colnum="9" colname="b02" align="center" />
+	<colspec colnum="10" colname="b01" align="center" />
+	<colspec colnum="11" colname="b00" align="center" />
+
+	<colspec colnum="13" colname="b17" align="center" />
+	<colspec colnum="14" colname="b16" align="center" />
+	<colspec colnum="15" colname="b15" align="center" />
+	<colspec colnum="16" colname="b14" align="center" />
+	<colspec colnum="17" colname="b13" align="center" />
+	<colspec colnum="18" colname="b12" align="center" />
+	<colspec colnum="19" colname="b11" align="center" />
+	<colspec colnum="20" colname="b10" align="center" />
+
+	<colspec colnum="22" colname="b27" align="center" />
+	<colspec colnum="23" colname="b26" align="center" />
+	<colspec colnum="24" colname="b25" align="center" />
+	<colspec colnum="25" colname="b24" align="center" />
+	<colspec colnum="26" colname="b23" align="center" />
+	<colspec colnum="27" colname="b22" align="center" />
+	<colspec colnum="28" colname="b21" align="center" />
+	<colspec colnum="29" colname="b20" align="center" />
+
+	<colspec colnum="31" colname="b37" align="center" />
+	<colspec colnum="32" colname="b36" align="center" />
+	<colspec colnum="33" colname="b35" align="center" />
+	<colspec colnum="34" colname="b34" align="center" />
+	<colspec colnum="35" colname="b33" align="center" />
+	<colspec colnum="36" colname="b32" align="center" />
+	<colspec colnum="37" colname="b31" align="center" />
+	<colspec colnum="38" colname="b30" align="center" />
+
+	<spanspec namest="b07" nameend="b00" spanname="b0" />
+	<spanspec namest="b17" nameend="b10" spanname="b1" />
+	<spanspec namest="b27" nameend="b20" spanname="b2" />
+	<spanspec namest="b37" nameend="b30" spanname="b3" />
+	<thead>
+	  <row>
+	    <entry>Identifier</entry>
+	    <entry>Code</entry>
+	    <entry>&nbsp;</entry>
+	    <entry spanname="b0">Byte&nbsp;0 in memory</entry>
+	    <entry spanname="b1">Byte&nbsp;1</entry>
+	    <entry spanname="b2">Byte&nbsp;2</entry>
+	    <entry spanname="b3">Byte&nbsp;3</entry>
+	  </row>
+	  <row>
+	    <entry>&nbsp;</entry>
+	    <entry>&nbsp;</entry>
+	    <entry>Bit</entry>
+	    <entry>7</entry>
+	    <entry>6</entry>
+	    <entry>5</entry>
+	    <entry>4</entry>
+	    <entry>3</entry>
+	    <entry>2</entry>
+	    <entry>1</entry>
+	    <entry>0</entry>
+	    <entry>&nbsp;</entry>
+	    <entry>7</entry>
+	    <entry>6</entry>
+	    <entry>5</entry>
+	    <entry>4</entry>
+	    <entry>3</entry>
+	    <entry>2</entry>
+	    <entry>1</entry>
+	    <entry>0</entry>
+	    <entry>&nbsp;</entry>
+	    <entry>7</entry>
+	    <entry>6</entry>
+	    <entry>5</entry>
+	    <entry>4</entry>
+	    <entry>3</entry>
+	    <entry>2</entry>
+	    <entry>1</entry>
+	    <entry>0</entry>
+	    <entry>&nbsp;</entry>
+	    <entry>7</entry>
+	    <entry>6</entry>
+	    <entry>5</entry>
+	    <entry>4</entry>
+	    <entry>3</entry>
+	    <entry>2</entry>
+	    <entry>1</entry>
+	    <entry>0</entry>
+	  </row>
+	</thead>
+	<tbody>
+	  <row id="V4L2-PIX-FMT-RGB444">
+	    <entry><constant>V4L2_PIX_FMT_RGB444</constant></entry>
+	    <entry>'R444'</entry>
+	    <entry></entry>
+	    <entry>g<subscript>3</subscript></entry>
+	    <entry>g<subscript>2</subscript></entry>
+	    <entry>g<subscript>1</subscript></entry>
+	    <entry>g<subscript>0</subscript></entry>
+	    <entry>b<subscript>3</subscript></entry>
+	    <entry>b<subscript>2</subscript></entry>
+	    <entry>b<subscript>1</subscript></entry>
+	    <entry>b<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>a<subscript>3</subscript></entry>
+	    <entry>a<subscript>2</subscript></entry>
+	    <entry>a<subscript>1</subscript></entry>
+	    <entry>a<subscript>0</subscript></entry>
+	    <entry>r<subscript>3</subscript></entry>
+	    <entry>r<subscript>2</subscript></entry>
+	    <entry>r<subscript>1</subscript></entry>
+	    <entry>r<subscript>0</subscript></entry>
+	  </row>
+	  <row id="V4L2-PIX-FMT-RGB555">
+	    <entry><constant>V4L2_PIX_FMT_RGB555</constant></entry>
+	    <entry>'RGBO'</entry>
+	    <entry></entry>
+	    <entry>g<subscript>2</subscript></entry>
+	    <entry>g<subscript>1</subscript></entry>
+	    <entry>g<subscript>0</subscript></entry>
+	    <entry>b<subscript>4</subscript></entry>
+	    <entry>b<subscript>3</subscript></entry>
+	    <entry>b<subscript>2</subscript></entry>
+	    <entry>b<subscript>1</subscript></entry>
+	    <entry>b<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>a</entry>
+	    <entry>r<subscript>4</subscript></entry>
+	    <entry>r<subscript>3</subscript></entry>
+	    <entry>r<subscript>2</subscript></entry>
+	    <entry>r<subscript>1</subscript></entry>
+	    <entry>r<subscript>0</subscript></entry>
+	    <entry>g<subscript>4</subscript></entry>
+	    <entry>g<subscript>3</subscript></entry>
+	  </row>
+	  <row id="V4L2-PIX-FMT-BGR32">
+	    <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
+	    <entry>'BGR4'</entry>
+	    <entry></entry>
+	    <entry>b<subscript>7</subscript></entry>
+	    <entry>b<subscript>6</subscript></entry>
+	    <entry>b<subscript>5</subscript></entry>
+	    <entry>b<subscript>4</subscript></entry>
+	    <entry>b<subscript>3</subscript></entry>
+	    <entry>b<subscript>2</subscript></entry>
+	    <entry>b<subscript>1</subscript></entry>
+	    <entry>b<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>g<subscript>7</subscript></entry>
+	    <entry>g<subscript>6</subscript></entry>
+	    <entry>g<subscript>5</subscript></entry>
+	    <entry>g<subscript>4</subscript></entry>
+	    <entry>g<subscript>3</subscript></entry>
+	    <entry>g<subscript>2</subscript></entry>
+	    <entry>g<subscript>1</subscript></entry>
+	    <entry>g<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>r<subscript>7</subscript></entry>
+	    <entry>r<subscript>6</subscript></entry>
+	    <entry>r<subscript>5</subscript></entry>
+	    <entry>r<subscript>4</subscript></entry>
+	    <entry>r<subscript>3</subscript></entry>
+	    <entry>r<subscript>2</subscript></entry>
+	    <entry>r<subscript>1</subscript></entry>
+	    <entry>r<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>a<subscript>7</subscript></entry>
+	    <entry>a<subscript>6</subscript></entry>
+	    <entry>a<subscript>5</subscript></entry>
+	    <entry>a<subscript>4</subscript></entry>
+	    <entry>a<subscript>3</subscript></entry>
+	    <entry>a<subscript>2</subscript></entry>
+	    <entry>a<subscript>1</subscript></entry>
+	    <entry>a<subscript>0</subscript></entry>
+	  </row>
+	  <row id="V4L2-PIX-FMT-RGB32">
+	    <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
+	    <entry>'RGB4'</entry>
+	    <entry></entry>
+	    <entry>a<subscript>7</subscript></entry>
+	    <entry>a<subscript>6</subscript></entry>
+	    <entry>a<subscript>5</subscript></entry>
+	    <entry>a<subscript>4</subscript></entry>
+	    <entry>a<subscript>3</subscript></entry>
+	    <entry>a<subscript>2</subscript></entry>
+	    <entry>a<subscript>1</subscript></entry>
+	    <entry>a<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>r<subscript>7</subscript></entry>
+	    <entry>r<subscript>6</subscript></entry>
+	    <entry>r<subscript>5</subscript></entry>
+	    <entry>r<subscript>4</subscript></entry>
+	    <entry>r<subscript>3</subscript></entry>
+	    <entry>r<subscript>2</subscript></entry>
+	    <entry>r<subscript>1</subscript></entry>
+	    <entry>r<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>g<subscript>7</subscript></entry>
+	    <entry>g<subscript>6</subscript></entry>
+	    <entry>g<subscript>5</subscript></entry>
+	    <entry>g<subscript>4</subscript></entry>
+	    <entry>g<subscript>3</subscript></entry>
+	    <entry>g<subscript>2</subscript></entry>
+	    <entry>g<subscript>1</subscript></entry>
+	    <entry>g<subscript>0</subscript></entry>
+	    <entry></entry>
+	    <entry>b<subscript>7</subscript></entry>
+	    <entry>b<subscript>6</subscript></entry>
+	    <entry>b<subscript>5</subscript></entry>
+	    <entry>b<subscript>4</subscript></entry>
+	    <entry>b<subscript>3</subscript></entry>
+	    <entry>b<subscript>2</subscript></entry>
+	    <entry>b<subscript>1</subscript></entry>
+	    <entry>b<subscript>0</subscript></entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
     <para>A test utility to determine which RGB formats a driver
 actually supports is available from the LinuxTV v4l-dvb repository.
 See &v4l-dvb; for access instructions.</para>

+ 44 - 0
Documentation/DocBook/media/v4l/pixfmt-sdr-cs08.xml

@@ -0,0 +1,44 @@
+<refentry id="V4L2-SDR-FMT-CS08">
+  <refmeta>
+    <refentrytitle>V4L2_SDR_FMT_CS8 ('CS08')</refentrytitle>
+    &manvol;
+  </refmeta>
+    <refnamediv>
+      <refname>
+        <constant>V4L2_SDR_FMT_CS8</constant>
+      </refname>
+      <refpurpose>Complex signed 8-bit IQ sample</refpurpose>
+    </refnamediv>
+    <refsect1>
+      <title>Description</title>
+      <para>
+This format contains sequence of complex number samples. Each complex number
+consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
+represented as a 8 bit signed number. I value comes first and Q value after
+that.
+      </para>
+    <example>
+      <title><constant>V4L2_SDR_FMT_CS8</constant> 1 sample</title>
+      <formalpara>
+        <title>Byte Order.</title>
+        <para>Each cell is one byte.
+          <informaltable frame="none">
+            <tgroup cols="2" align="center">
+              <colspec align="left" colwidth="2*" />
+              <tbody valign="top">
+                <row>
+                  <entry>start&nbsp;+&nbsp;0:</entry>
+                  <entry>I'<subscript>0</subscript></entry>
+                </row>
+                <row>
+                  <entry>start&nbsp;+&nbsp;1:</entry>
+                  <entry>Q'<subscript>0</subscript></entry>
+                </row>
+              </tbody>
+            </tgroup>
+          </informaltable>
+        </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>

+ 47 - 0
Documentation/DocBook/media/v4l/pixfmt-sdr-cs14le.xml

@@ -0,0 +1,47 @@
+<refentry id="V4L2-SDR-FMT-CS14LE">
+  <refmeta>
+    <refentrytitle>V4L2_SDR_FMT_CS14LE ('CS14')</refentrytitle>
+    &manvol;
+  </refmeta>
+    <refnamediv>
+      <refname>
+        <constant>V4L2_SDR_FMT_CS14LE</constant>
+      </refname>
+      <refpurpose>Complex signed 14-bit little endian IQ sample</refpurpose>
+    </refnamediv>
+    <refsect1>
+      <title>Description</title>
+      <para>
+This format contains sequence of complex number samples. Each complex number
+consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
+represented as a 14 bit signed little endian number. I value comes first
+and Q value after that. 14 bit value is stored in 16 bit space with unused
+high bits padded with 0.
+      </para>
+    <example>
+      <title><constant>V4L2_SDR_FMT_CS14LE</constant> 1 sample</title>
+      <formalpara>
+        <title>Byte Order.</title>
+        <para>Each cell is one byte.
+          <informaltable frame="none">
+            <tgroup cols="3" align="center">
+              <colspec align="left" colwidth="2*" />
+              <tbody valign="top">
+                <row>
+                  <entry>start&nbsp;+&nbsp;0:</entry>
+                  <entry>I'<subscript>0[7:0]</subscript></entry>
+                  <entry>I'<subscript>0[13:8]</subscript></entry>
+                </row>
+                <row>
+                  <entry>start&nbsp;+&nbsp;2:</entry>
+                  <entry>Q'<subscript>0[7:0]</subscript></entry>
+                  <entry>Q'<subscript>0[13:8]</subscript></entry>
+                </row>
+              </tbody>
+            </tgroup>
+          </informaltable>
+        </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>

+ 40 - 0
Documentation/DocBook/media/v4l/pixfmt-sdr-ru12le.xml

@@ -0,0 +1,40 @@
+<refentry id="V4L2-SDR-FMT-RU12LE">
+  <refmeta>
+    <refentrytitle>V4L2_SDR_FMT_RU12LE ('RU12')</refentrytitle>
+    &manvol;
+  </refmeta>
+    <refnamediv>
+      <refname>
+        <constant>V4L2_SDR_FMT_RU12LE</constant>
+      </refname>
+      <refpurpose>Real unsigned 12-bit little endian sample</refpurpose>
+    </refnamediv>
+    <refsect1>
+      <title>Description</title>
+      <para>
+This format contains sequence of real number samples. Each sample is
+represented as a 12 bit unsigned little endian number. Sample is stored
+in 16 bit space with unused high bits padded with 0.
+      </para>
+    <example>
+      <title><constant>V4L2_SDR_FMT_RU12LE</constant> 1 sample</title>
+      <formalpara>
+        <title>Byte Order.</title>
+        <para>Each cell is one byte.
+          <informaltable frame="none">
+            <tgroup cols="3" align="center">
+              <colspec align="left" colwidth="2*" />
+              <tbody valign="top">
+                <row>
+                  <entry>start&nbsp;+&nbsp;0:</entry>
+                  <entry>I'<subscript>0[7:0]</subscript></entry>
+                  <entry>I'<subscript>0[11:8]</subscript></entry>
+                </row>
+              </tbody>
+            </tgroup>
+          </informaltable>
+        </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>

+ 1 - 1
Documentation/DocBook/media/v4l/pixfmt-srggb12.xml

@@ -18,7 +18,7 @@
 	<title>Description</title>
 
 	<para>The following four pixel formats are raw sRGB / Bayer formats with
-12 bits per colour. Each colour component is stored in a 16-bit word, with 6
+12 bits per colour. Each colour component is stored in a 16-bit word, with 4
 unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
 and n/2 blue or red samples, with alternating red and blue rows. Bytes are
 stored in memory in little endian order. They are conventionally described

+ 56 - 5
Documentation/DocBook/media/v4l/pixfmt.xml

@@ -112,9 +112,34 @@ see <xref linkend="colorspaces" />.</entry>
 	<row>
 	  <entry>__u32</entry>
 	  <entry><structfield>priv</structfield></entry>
-	  <entry>Reserved for custom (driver defined) additional
-information about formats. When not used drivers and applications must
-set this field to zero.</entry>
+	  <entry><para>This field indicates whether the remaining fields of the
+<structname>v4l2_pix_format</structname> structure, also called the extended
+fields, are valid. When set to <constant>V4L2_PIX_FMT_PRIV_MAGIC</constant>, it
+indicates that the extended fields have been correctly initialized. When set to
+any other value it indicates that the extended fields contain undefined values.
+</para>
+<para>Applications that wish to use the pixel format extended fields must first
+ensure that the feature is supported by querying the device for the
+<link linkend="querycap"><constant>V4L2_CAP_EXT_PIX_FORMAT</constant></link>
+capability. If the capability isn't set the pixel format extended fields are not
+supported and using the extended fields will lead to undefined results.</para>
+<para>To use the extended fields, applications must set the
+<structfield>priv</structfield> field to
+<constant>V4L2_PIX_FMT_PRIV_MAGIC</constant>, initialize all the extended fields
+and zero the unused bytes of the <structname>v4l2_format</structname>
+<structfield>raw_data</structfield> field.</para>
+<para>When the <structfield>priv</structfield> field isn't set to
+<constant>V4L2_PIX_FMT_PRIV_MAGIC</constant> drivers must act as if all the
+extended fields were set to zero. On return drivers must set the
+<structfield>priv</structfield> field to
+<constant>V4L2_PIX_FMT_PRIV_MAGIC</constant> and all the extended fields to
+applicable values.</para></entry>
+	</row>
+	<row>
+	  <entry>__u32</entry>
+	  <entry><structfield>flags</structfield></entry>
+	    <entry>Flags set by the application or driver, see <xref
+linkend="format-flags" />.</entry>
 	</row>
       </tbody>
     </tgroup>
@@ -201,9 +226,15 @@ codes can be used.</entry>
           and the number of valid entries in the
           <structfield>plane_fmt</structfield> array.</entry>
         </row>
+	<row>
+	  <entry>__u8</entry>
+	  <entry><structfield>flags</structfield></entry>
+	  <entry>Flags set by the application or driver, see <xref
+linkend="format-flags" />.</entry>
+	</row>
         <row>
           <entry>__u8</entry>
-          <entry><structfield>reserved[11]</structfield></entry>
+          <entry><structfield>reserved[10]</structfield></entry>
           <entry>Reserved for future extensions. Should be zeroed by the
            application.</entry>
         </row>
@@ -248,7 +279,7 @@ has just as many pad bytes after it as the other rows.</para>
 
     <para>In V4L2 each format has an identifier which looks like
 <constant>PIX_FMT_XXX</constant>, defined in the <link
-linkend="videodev">videodev.h</link> header file. These identifiers
+linkend="videodev">videodev2.h</link> header file. These identifiers
 represent <link linkend="v4l2-fourcc">four character (FourCC) codes</link>
 which are also listed below, however they are not the same as those
 used in the Windows world.</para>
@@ -828,6 +859,9 @@ interface only.</para>
 
     &sub-sdr-cu08;
     &sub-sdr-cu16le;
+    &sub-sdr-cs08;
+    &sub-sdr-cs14le;
+    &sub-sdr-ru12le;
 
   </section>
 
@@ -1060,4 +1094,21 @@ concatenated to form the JPEG stream. </para>
 	</tbody>
       </tgroup>
     </table>
+
+    <table frame="none" pgwide="1" id="format-flags">
+      <title>Format Flags</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_PIX_FMT_FLAG_PREMUL_ALPHA</constant></entry>
+	    <entry>0x00000001</entry>
+	    <entry>The color values are premultiplied by the alpha channel
+value. For example, if a light blue pixel with 50% transparency was described by
+RGBA values (128, 192, 255, 128), the same pixel described with premultiplied
+colors would be described by RGBA values (64, 96, 128, 128) </entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
   </section>

+ 47 - 48
Documentation/DocBook/media/v4l/selection-api.xml

@@ -86,47 +86,47 @@ selection targets available for a video capture device.  It is recommended to
 configure the cropping targets before to the composing targets.</para>
 
 <para>The range of coordinates of the top left corner, width and height of
-areas that can be sampled is given by the <constant> V4L2_SEL_TGT_CROP_BOUNDS
-</constant> target. It is recommended for the driver developers to put the
-top/left corner at position <constant> (0,0) </constant>.  The rectangle's
+areas that can be sampled is given by the <constant>V4L2_SEL_TGT_CROP_BOUNDS</constant>
+target. It is recommended for the driver developers to put the
+top/left corner at position <constant>(0,0)</constant>.  The rectangle's
 coordinates are expressed in pixels.</para>
 
 <para>The top left corner, width and height of the source rectangle, that is
-the area actually sampled, is given by the <constant> V4L2_SEL_TGT_CROP
-</constant> target. It uses the same coordinate system as <constant>
-V4L2_SEL_TGT_CROP_BOUNDS </constant>. The active cropping area must lie
-completely inside the capture boundaries. The driver may further adjust the
-requested size and/or position according to hardware limitations.</para>
+the area actually sampled, is given by the <constant>V4L2_SEL_TGT_CROP</constant>
+target. It uses the same coordinate system as <constant>V4L2_SEL_TGT_CROP_BOUNDS</constant>.
+The active cropping area must lie completely inside the capture boundaries. The
+driver may further adjust the requested size and/or position according to hardware
+limitations.</para>
 
 <para>Each capture device has a default source rectangle, given by the
-<constant> V4L2_SEL_TGT_CROP_DEFAULT </constant> target. This rectangle shall
+<constant>V4L2_SEL_TGT_CROP_DEFAULT</constant> target. This rectangle shall
 over what the driver writer considers the complete picture.  Drivers shall set
 the active crop rectangle to the default when the driver is first loaded, but
 not later.</para>
 
 <para>The composing targets refer to a memory buffer. The limits of composing
-coordinates are obtained using <constant> V4L2_SEL_TGT_COMPOSE_BOUNDS
-</constant>.  All coordinates are expressed in pixels. The rectangle's top/left
-corner must be located at position <constant> (0,0) </constant>. The width and
-height are equal to the image size set by <constant> VIDIOC_S_FMT </constant>.
+coordinates are obtained using <constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant>.
+All coordinates are expressed in pixels. The rectangle's top/left
+corner must be located at position <constant>(0,0)</constant>. The width and
+height are equal to the image size set by <constant>VIDIOC_S_FMT</constant>.
 </para>
 
 <para>The part of a buffer into which the image is inserted by the hardware is
-controlled by the <constant> V4L2_SEL_TGT_COMPOSE </constant> target.
+controlled by the <constant>V4L2_SEL_TGT_COMPOSE</constant> target.
 The rectangle's coordinates are also expressed in the same coordinate system as
 the bounds rectangle. The composing rectangle must lie completely inside bounds
 rectangle. The driver must adjust the composing rectangle to fit to the
 bounding limits. Moreover, the driver can perform other adjustments according
 to hardware limitations. The application can control rounding behaviour using
-<link linkend="v4l2-selection-flags"> constraint flags </link>.</para>
+<link linkend="v4l2-selection-flags"> constraint flags</link>.</para>
 
 <para>For capture devices the default composing rectangle is queried using
-<constant> V4L2_SEL_TGT_COMPOSE_DEFAULT </constant>. It is usually equal to the
+<constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant>. It is usually equal to the
 bounding rectangle.</para>
 
 <para>The part of a buffer that is modified by the hardware is given by
-<constant> V4L2_SEL_TGT_COMPOSE_PADDED </constant>. It contains all pixels
-defined using <constant> V4L2_SEL_TGT_COMPOSE </constant> plus all
+<constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant>. It contains all pixels
+defined using <constant>V4L2_SEL_TGT_COMPOSE</constant> plus all
 padding data modified by hardware during insertion process. All pixels outside
 this rectangle <emphasis>must not</emphasis> be changed by the hardware. The
 content of pixels that lie inside the padded area but outside active area is
@@ -140,52 +140,51 @@ where the rubbish pixels are located and remove them if needed.</para>
    <title>Configuration of video output</title>
 
 <para>For output devices targets and ioctls are used similarly to the video
-capture case. The <emphasis> composing </emphasis> rectangle refers to the
+capture case. The <emphasis>composing</emphasis> rectangle refers to the
 insertion of an image into a video signal. The cropping rectangles refer to a
 memory buffer. It is recommended to configure the composing targets before to
 the cropping targets.</para>
 
 <para>The cropping targets refer to the memory buffer that contains an image to
 be inserted into a video signal or graphical screen. The limits of cropping
-coordinates are obtained using <constant> V4L2_SEL_TGT_CROP_BOUNDS </constant>.
+coordinates are obtained using <constant>V4L2_SEL_TGT_CROP_BOUNDS</constant>.
 All coordinates are expressed in pixels. The top/left corner is always point
-<constant> (0,0) </constant>.  The width and height is equal to the image size
-specified using <constant> VIDIOC_S_FMT </constant> ioctl.</para>
+<constant>(0,0)</constant>.  The width and height is equal to the image size
+specified using <constant>VIDIOC_S_FMT</constant> ioctl.</para>
 
 <para>The top left corner, width and height of the source rectangle, that is
 the area from which image date are processed by the hardware, is given by the
-<constant> V4L2_SEL_TGT_CROP </constant>. Its coordinates are expressed
+<constant>V4L2_SEL_TGT_CROP</constant>. Its coordinates are expressed
 in in the same coordinate system as the bounds rectangle. The active cropping
 area must lie completely inside the crop boundaries and the driver may further
 adjust the requested size and/or position according to hardware
 limitations.</para>
 
 <para>For output devices the default cropping rectangle is queried using
-<constant> V4L2_SEL_TGT_CROP_DEFAULT </constant>. It is usually equal to the
+<constant>V4L2_SEL_TGT_CROP_DEFAULT</constant>. It is usually equal to the
 bounding rectangle.</para>
 
 <para>The part of a video signal or graphics display where the image is
-inserted by the hardware is controlled by <constant>
-V4L2_SEL_TGT_COMPOSE </constant> target.  The rectangle's coordinates
-are expressed in pixels. The composing rectangle must lie completely inside the
-bounds rectangle.  The driver must adjust the area to fit to the bounding
-limits.  Moreover, the driver can perform other adjustments according to
-hardware limitations. </para>
-
-<para>The device has a default composing rectangle, given by the <constant>
-V4L2_SEL_TGT_COMPOSE_DEFAULT </constant> target. This rectangle shall cover what
+inserted by the hardware is controlled by <constant>V4L2_SEL_TGT_COMPOSE</constant>
+target.  The rectangle's coordinates are expressed in pixels. The composing
+rectangle must lie completely inside the bounds rectangle.  The driver must
+adjust the area to fit to the bounding limits.  Moreover, the driver can
+perform other adjustments according to hardware limitations.</para>
+
+<para>The device has a default composing rectangle, given by the
+<constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant> target. This rectangle shall cover what
 the driver writer considers the complete picture. It is recommended for the
-driver developers to put the top/left corner at position <constant> (0,0)
-</constant>. Drivers shall set the active composing rectangle to the default
+driver developers to put the top/left corner at position <constant>(0,0)</constant>.
+Drivers shall set the active composing rectangle to the default
 one when the driver is first loaded.</para>
 
 <para>The devices may introduce additional content to video signal other than
 an image from memory buffers.  It includes borders around an image. However,
 such a padded area is driver-dependent feature not covered by this document.
 Driver developers are encouraged to keep padded rectangle equal to active one.
-The padded target is accessed by the <constant> V4L2_SEL_TGT_COMPOSE_PADDED
-</constant> identifier.  It must contain all pixels from the <constant>
-V4L2_SEL_TGT_COMPOSE </constant> target.</para>
+The padded target is accessed by the <constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant>
+identifier.  It must contain all pixels from the <constant>V4L2_SEL_TGT_COMPOSE</constant>
+target.</para>
 
    </section>
 
@@ -194,8 +193,8 @@ V4L2_SEL_TGT_COMPOSE </constant> target.</para>
      <title>Scaling control</title>
 
 <para>An application can detect if scaling is performed by comparing the width
-and the height of rectangles obtained using <constant> V4L2_SEL_TGT_CROP
-</constant> and <constant> V4L2_SEL_TGT_COMPOSE </constant> targets. If
+and the height of rectangles obtained using <constant>V4L2_SEL_TGT_CROP</constant>
+and <constant>V4L2_SEL_TGT_COMPOSE</constant> targets. If
 these are not equal then the scaling is applied. The application can compute
 the scaling ratios using these values.</para>
 
@@ -208,7 +207,7 @@ the scaling ratios using these values.</para>
     <title>Comparison with old cropping API</title>
 
 <para>The selection API was introduced to cope with deficiencies of previous
-<link linkend="crop"> API </link>, that was designed to control simple capture
+<link linkend="crop"> API</link>, that was designed to control simple capture
 devices. Later the cropping API was adopted by video output drivers. The ioctls
 are used to select a part of the display were the video signal is inserted. It
 should be considered as an API abuse because the described operation is
@@ -220,7 +219,7 @@ part of an image by abusing V4L2 API.  Cropping a smaller image from a larger
 one is achieved by setting the field
 &v4l2-pix-format;<structfield>::bytesperline</structfield>.  Introducing an image offsets
 could be done by modifying field &v4l2-buffer;<structfield>::m_userptr</structfield>
-before calling <constant> VIDIOC_QBUF </constant>. Those
+before calling <constant>VIDIOC_QBUF</constant>. Those
 operations should be avoided because they are not portable (endianness), and do
 not work for macroblock and Bayer formats and mmap buffers.  The selection API
 deals with configuration of buffer cropping/composing in a clear, intuitive and
@@ -229,7 +228,7 @@ and constraints flags are introduced.  Finally, &v4l2-crop; and &v4l2-cropcap;
 have no reserved fields. Therefore there is no way to extend their functionality.
 The new &v4l2-selection; provides a lot of place for future
 extensions.  Driver developers are encouraged to implement only selection API.
-The former cropping API would be simulated using the new one. </para>
+The former cropping API would be simulated using the new one.</para>
 
   </section>
 
@@ -238,9 +237,9 @@ The former cropping API would be simulated using the new one. </para>
       <example>
 	<title>Resetting the cropping parameters</title>
 
-	<para>(A video capture device is assumed; change <constant>
-V4L2_BUF_TYPE_VIDEO_CAPTURE </constant> for other devices; change target to
-<constant> V4L2_SEL_TGT_COMPOSE_* </constant> family to configure composing
+	<para>(A video capture device is assumed; change
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> for other devices; change target to
+<constant>V4L2_SEL_TGT_COMPOSE_*</constant> family to configure composing
 area)</para>
 
 	<programlisting>
@@ -292,8 +291,8 @@ area)</para>
 
       <example>
 	<title>Querying for scaling factors</title>
-	<para>A video output device is assumed; change <constant>
-V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> for other devices</para>
+	<para>A video output device is assumed; change
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> for other devices</para>
 	<programlisting>
 
 	&v4l2-selection; compose = {

+ 8 - 0
Documentation/DocBook/media/v4l/v4l2.xml

@@ -151,6 +151,14 @@ structs, ioctls) must be noted in more detail in the history chapter
 (compat.xml), along with the possible impact on existing drivers and
 applications. -->
 
+      <revision>
+	<revnumber>3.16</revnumber>
+	<date>2014-05-27</date>
+	<authorinitials>lp</authorinitials>
+	<revremark>Extended &v4l2-pix-format;. Added format flags.
+	</revremark>
+      </revision>
+
       <revision>
 	<revnumber>3.15</revnumber>
 	<date>2014-02-03</date>

+ 50 - 0
Documentation/DocBook/media/v4l/vidioc-dqevent.xml

@@ -92,6 +92,18 @@
             <entry><structfield>frame_sync</structfield></entry>
 	    <entry>Event data for event V4L2_EVENT_FRAME_SYNC.</entry>
 	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>&v4l2-event-motion-det;</entry>
+            <entry><structfield>motion_det</structfield></entry>
+	    <entry>Event data for event V4L2_EVENT_MOTION_DET.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>&v4l2-event-src-change;</entry>
+            <entry><structfield>src_change</structfield></entry>
+	    <entry>Event data for event V4L2_EVENT_SOURCE_CHANGE.</entry>
+	  </row>
 	  <row>
 	    <entry></entry>
 	    <entry>__u8</entry>
@@ -258,6 +270,44 @@
       </tgroup>
     </table>
 
+    <table frame="none" pgwide="1" id="v4l2-event-motion-det">
+      <title>struct <structname>v4l2_event_motion_det</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>flags</structfield></entry>
+	    <entry>
+	      Currently only one flag is available: if <constant>V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ</constant>
+	      is set, then the <structfield>frame_sequence</structfield> field is valid,
+	      otherwise that field should be ignored.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>frame_sequence</structfield></entry>
+	    <entry>
+	      The sequence number of the frame being received. Only valid if the
+	      <constant>V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ</constant> flag was set.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>region_mask</structfield></entry>
+	    <entry>
+	      The bitmask of the regions that reported motion. There is at least one
+	      region. If this field is 0, then no motion was detected at all.
+	      If there is no <constant>V4L2_CID_DETECT_MD_REGION_GRID</constant> control
+	      (see <xref linkend="detect-controls" />) to assign a different region
+	      to each cell in the motion detection grid, then that all cells
+	      are automatically assigned to the default region 0.
+	    </entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
     <table pgwide="1" frame="none" id="changes-flags">
       <title>Changes</title>
       <tgroup cols="3">

+ 43 - 8
Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml

@@ -72,23 +72,30 @@ initialize the <structfield>id</structfield>,
 <structfield>size</structfield> and <structfield>reserved2</structfield> fields
 of each &v4l2-ext-control; and call the
 <constant>VIDIOC_G_EXT_CTRLS</constant> ioctl. String controls controls
-must also set the <structfield>string</structfield> field.</para>
+must also set the <structfield>string</structfield> field. Controls
+of compound types (<constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is set)
+must set the <structfield>ptr</structfield> field.</para>
 
     <para>If the <structfield>size</structfield> is too small to
 receive the control result (only relevant for pointer-type controls
 like strings), then the driver will set <structfield>size</structfield>
 to a valid value and return an &ENOSPC;. You should re-allocate the
-string memory to this new size and try again. It is possible that the
-same issue occurs again if the string has grown in the meantime. It is
+memory to this new size and try again. For the string type it is possible that
+the same issue occurs again if the string has grown in the meantime. It is
 recommended to call &VIDIOC-QUERYCTRL; first and use
 <structfield>maximum</structfield>+1 as the new <structfield>size</structfield>
 value. It is guaranteed that that is sufficient memory.
 </para>
 
+    <para>N-dimensional arrays are set and retrieved row-by-row. You cannot set a partial
+array, all elements have to be set or retrieved. The total size is calculated
+as <structfield>elems</structfield> * <structfield>elem_size</structfield>.
+These values can be obtained by calling &VIDIOC-QUERY-EXT-CTRL;.</para>
+
     <para>To change the value of a set of controls applications
 initialize the <structfield>id</structfield>, <structfield>size</structfield>,
 <structfield>reserved2</structfield> and
-<structfield>value/string</structfield> fields of each &v4l2-ext-control; and
+<structfield>value/value64/string/ptr</structfield> fields of each &v4l2-ext-control; and
 call the <constant>VIDIOC_S_EXT_CTRLS</constant> ioctl. The controls
 will only be set if <emphasis>all</emphasis> control values are
 valid.</para>
@@ -96,7 +103,7 @@ valid.</para>
     <para>To check if a set of controls have correct values applications
 initialize the <structfield>id</structfield>, <structfield>size</structfield>,
 <structfield>reserved2</structfield> and
-<structfield>value/string</structfield> fields of each &v4l2-ext-control; and
+<structfield>value/value64/string/ptr</structfield> fields of each &v4l2-ext-control; and
 call the <constant>VIDIOC_TRY_EXT_CTRLS</constant> ioctl. It is up to
 the driver whether wrong values are automatically adjusted to a valid
 value or if an error is returned.</para>
@@ -158,19 +165,47 @@ applications must set the array to zero.</entry>
 	    <entry></entry>
 	    <entry>__s32</entry>
 	    <entry><structfield>value</structfield></entry>
-	    <entry>New value or current value.</entry>
+	    <entry>New value or current value. Valid if this control is not of
+type <constant>V4L2_CTRL_TYPE_INTEGER64</constant> and
+<constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is not set.</entry>
 	  </row>
 	  <row>
 	    <entry></entry>
 	    <entry>__s64</entry>
 	    <entry><structfield>value64</structfield></entry>
-	    <entry>New value or current value.</entry>
+	    <entry>New value or current value. Valid if this control is of
+type <constant>V4L2_CTRL_TYPE_INTEGER64</constant> and
+<constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is not set.</entry>
 	  </row>
 	  <row>
 	    <entry></entry>
 	    <entry>char *</entry>
 	    <entry><structfield>string</structfield></entry>
-	    <entry>A pointer to a string.</entry>
+	    <entry>A pointer to a string. Valid if this control is of
+type <constant>V4L2_CTRL_TYPE_STRING</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>__u8 *</entry>
+	    <entry><structfield>p_u8</structfield></entry>
+	    <entry>A pointer to a matrix control of unsigned 8-bit values.
+Valid if this control is of type <constant>V4L2_CTRL_TYPE_U8</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>__u16 *</entry>
+	    <entry><structfield>p_u16</structfield></entry>
+	    <entry>A pointer to a matrix control of unsigned 16-bit values.
+Valid if this control is of type <constant>V4L2_CTRL_TYPE_U16</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>void *</entry>
+	    <entry><structfield>ptr</structfield></entry>
+	    <entry>A pointer to a compound type which can be an N-dimensional array and/or a
+compound type (the control's type is >= <constant>V4L2_CTRL_COMPOUND_TYPES</constant>).
+Valid if <constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is set for this control.
+</entry>
 	  </row>
 	</tbody>
       </tgroup>

+ 4 - 8
Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml

@@ -152,13 +152,10 @@ a valid base address, so applications can find the corresponding Linux
 framebuffer device (see <xref linkend="osd" />).</entry>
 	  </row>
 	  <row>
-	    <entry>&v4l2-pix-format;</entry>
+	    <entry>struct</entry>
 	    <entry><structfield>fmt</structfield></entry>
 	    <entry></entry>
-	    <entry>Layout of the frame buffer. The
-<structname>v4l2_pix_format</structname> structure is defined in <xref
-linkend="pixfmt" />, for clarification the fields and acceptable values
-	    are listed below:</entry>
+	    <entry>Layout of the frame buffer.</entry>
 	  </row>
 	  <row>
 	    <entry></entry>
@@ -276,9 +273,8 @@ see <xref linkend="colorspaces" />.</entry>
 	    <entry></entry>
 	    <entry>__u32</entry>
 	    <entry><structfield>priv</structfield></entry>
-	    <entry>Reserved for additional information about custom
-(driver defined) formats. When not used drivers and applications must
-set this field to zero.</entry>
+	    <entry>Reserved. Drivers and applications must set this field to
+zero.</entry>
 	  </row>
 	</tbody>
       </tgroup>

+ 19 - 21
Documentation/DocBook/media/v4l/vidioc-g-selection.xml

@@ -58,17 +58,16 @@
 
     <para>The ioctls are used to query and configure selection rectangles.</para>
 
-<para> To query the cropping (composing) rectangle set &v4l2-selection;
+<para>To query the cropping (composing) rectangle set &v4l2-selection;
 <structfield> type </structfield> field to the respective buffer type.
-Do not use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
-</constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
-</constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
-<constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
+Do not use multiplanar buffers.  Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>
+instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>.  Use
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> instead of
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>.  The next step is
 setting the value of &v4l2-selection; <structfield>target</structfield> field
-to <constant> V4L2_SEL_TGT_CROP </constant> (<constant>
-V4L2_SEL_TGT_COMPOSE </constant>).  Please refer to table <xref
-linkend="v4l2-selections-common" /> or <xref linkend="selection-api" /> for additional
-targets.  The <structfield>flags</structfield> and <structfield>reserved
+to <constant>V4L2_SEL_TGT_CROP</constant> (<constant>V4L2_SEL_TGT_COMPOSE</constant>).
+Please refer to table <xref linkend="v4l2-selections-common" /> or <xref linkend="selection-api" />
+for additional targets.  The <structfield>flags</structfield> and <structfield>reserved
 </structfield> fields of &v4l2-selection; are ignored and they must be filled
 with zeros.  The driver fills the rest of the structure or
 returns &EINVAL; if incorrect buffer type or target was used. If cropping
@@ -77,19 +76,18 @@ always equal to the bounds rectangle.  Finally, the &v4l2-rect;
 <structfield>r</structfield> rectangle is filled with the current cropping
 (composing) coordinates. The coordinates are expressed in driver-dependent
 units. The only exception are rectangles for images in raw formats, whose
-coordinates are always expressed in pixels.  </para>
+coordinates are always expressed in pixels.</para>
 
-<para> To change the cropping (composing) rectangle set the &v4l2-selection;
+<para>To change the cropping (composing) rectangle set the &v4l2-selection;
 <structfield>type</structfield> field to the respective buffer type.  Do not
-use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
-</constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
-</constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
-<constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
+use multiplanar buffers.  Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>
+instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>.  Use
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> instead of
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>.  The next step is
 setting the value of &v4l2-selection; <structfield>target</structfield> to
-<constant>V4L2_SEL_TGT_CROP</constant> (<constant>
-V4L2_SEL_TGT_COMPOSE </constant>). Please refer to table <xref
-linkend="v4l2-selections-common" /> or <xref linkend="selection-api" /> for additional
-targets.  The &v4l2-rect; <structfield>r</structfield> rectangle need to be
+<constant>V4L2_SEL_TGT_CROP</constant> (<constant>V4L2_SEL_TGT_COMPOSE</constant>).
+Please refer to table <xref linkend="v4l2-selections-common" /> or <xref linkend="selection-api" />
+for additional targets.  The &v4l2-rect; <structfield>r</structfield> rectangle need to be
 set to the desired active area. Field &v4l2-selection; <structfield> reserved
 </structfield> is ignored and must be filled with zeros.  The driver may adjust
 coordinates of the requested rectangle. An application may
@@ -149,8 +147,8 @@ On success the &v4l2-rect; <structfield>r</structfield> field contains
 the adjusted rectangle. When the parameters are unsuitable the application may
 modify the cropping (composing) or image parameters and repeat the cycle until
 satisfactory parameters have been negotiated. If constraints flags have to be
-violated at then ERANGE is returned. The error indicates that <emphasis> there
-exist no rectangle </emphasis> that satisfies the constraints.</para>
+violated at then ERANGE is returned. The error indicates that <emphasis>there
+exist no rectangle</emphasis> that satisfies the constraints.</para>
 
   <para>Selection targets and flags are documented in <xref
   linkend="v4l2-selections-common"/>.</para>

+ 6 - 0
Documentation/DocBook/media/v4l/vidioc-querycap.xml

@@ -300,6 +300,12 @@ modulator programming see
 	    <entry>0x00100000</entry>
 	    <entry>The device supports the
 <link linkend="sdr">SDR Capture</link> interface.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CAP_EXT_PIX_FORMAT</constant></entry>
+	    <entry>0x00200000</entry>
+	    <entry>The device supports the &v4l2-pix-format; extended
+fields.</entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CAP_READWRITE</constant></entry>

+ 197 - 37
Documentation/DocBook/media/v4l/vidioc-queryctrl.xml

@@ -1,11 +1,12 @@
 <refentry id="vidioc-queryctrl">
   <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU</refentrytitle>
+    <refentrytitle>ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERY_EXT_CTRL, VIDIOC_QUERYMENU</refentrytitle>
     &manvol;
   </refmeta>
 
   <refnamediv>
     <refname>VIDIOC_QUERYCTRL</refname>
+    <refname>VIDIOC_QUERY_EXT_CTRL</refname>
     <refname>VIDIOC_QUERYMENU</refname>
     <refpurpose>Enumerate controls and menu control items</refpurpose>
   </refnamediv>
@@ -19,6 +20,14 @@
 	<paramdef>struct v4l2_queryctrl *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_query_ext_ctrl *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
     <funcsynopsis>
       <funcprototype>
 	<funcdef>int <function>ioctl</function></funcdef>
@@ -42,7 +51,7 @@
       <varlistentry>
 	<term><parameter>request</parameter></term>
 	<listitem>
-	  <para>VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU</para>
+	  <para>VIDIOC_QUERYCTRL, VIDIOC_QUERY_EXT_CTRL, VIDIOC_QUERYMENU</para>
 	</listitem>
       </varlistentry>
       <varlistentry>
@@ -67,7 +76,7 @@ structure. The driver fills the rest of the structure or returns an
 <constant>VIDIOC_QUERYCTRL</constant> with successive
 <structfield>id</structfield> values starting from
 <constant>V4L2_CID_BASE</constant> up to and exclusive
-<constant>V4L2_CID_BASE_LASTP1</constant>. Drivers may return
+<constant>V4L2_CID_LASTP1</constant>. Drivers may return
 <errorcode>EINVAL</errorcode> if a control in this range is not
 supported. Further applications can enumerate private controls, which
 are not defined in this specification, by starting at
@@ -89,9 +98,23 @@ prematurely end the enumeration).</para></footnote></para>
 
     <para>When the application ORs <structfield>id</structfield> with
 <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> the driver returns the
-next supported control, or <errorcode>EINVAL</errorcode> if there is
-none. Drivers which do not support this flag yet always return
-<errorcode>EINVAL</errorcode>.</para>
+next supported non-compound control, or <errorcode>EINVAL</errorcode>
+if there is none. In addition, the <constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant>
+flag can be specified to enumerate all compound controls (i.e. controls
+with type &ge; <constant>V4L2_CTRL_COMPOUND_TYPES</constant>). Specify both
+<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> and
+<constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant> in order to enumerate
+all controls, compound or not. Drivers which do not support these flags yet
+always return <errorcode>EINVAL</errorcode>.</para>
+
+    <para>The <constant>VIDIOC_QUERY_EXT_CTRL</constant> ioctl was
+introduced in order to better support controls that can use compound
+types, and to expose additional control information that cannot be
+returned in &v4l2-queryctrl; since that structure is full.</para>
+
+    <para><constant>VIDIOC_QUERY_EXT_CTRL</constant> is used in the
+same way as <constant>VIDIOC_QUERYCTRL</constant>, except that the
+<structfield>reserved</structfield> array must be zeroed as well.</para>
 
     <para>Additional information is required for menu controls: the
 names of the menu items. To query them applications set the
@@ -142,38 +165,23 @@ string. This information is intended for the user.</entry>
 	    <entry>__s32</entry>
 	    <entry><structfield>minimum</structfield></entry>
 	    <entry>Minimum value, inclusive. This field gives a lower
-bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
-lowest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant> controls.
-For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the minimum value
-gives the minimum length of the string. This length <emphasis>does not include the terminating
-zero</emphasis>. It may not be valid for any other type of control, including
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant> controls. Note that this is a
-signed value.</entry>
+bound for the control. See &v4l2-ctrl-type; how the minimum value is to
+be used for each possible control type. Note that this a signed 32-bit value.</entry>
 	  </row>
 	  <row>
 	    <entry>__s32</entry>
 	    <entry><structfield>maximum</structfield></entry>
 	    <entry>Maximum value, inclusive. This field gives an upper
-bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
-highest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant>
-controls. For <constant>V4L2_CTRL_TYPE_BITMASK</constant> controls it is the
-set of usable bits.
-For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the maximum value
-gives the maximum length of the string. This length <emphasis>does not include the terminating
-zero</emphasis>. It may not be valid for any other type of control, including
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant> controls. Note that this is a
-signed value.</entry>
+bound for the control. See &v4l2-ctrl-type; how the maximum value is to
+be used for each possible control type. Note that this a signed 32-bit value.</entry>
 	  </row>
 	  <row>
 	    <entry>__s32</entry>
 	    <entry><structfield>step</structfield></entry>
-	    <entry><para>This field gives a step size for
-<constant>V4L2_CTRL_TYPE_INTEGER</constant> controls. For
-<constant>V4L2_CTRL_TYPE_STRING</constant> controls this field refers to
-the string length that has to be a multiple of this step size.
-It may not be valid for any other type of control, including
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant>
-controls.</para><para>Generally drivers should not scale hardware
+	    <entry><para>This field gives a step size for the control.
+See &v4l2-ctrl-type; how the step value is to be used for each possible
+control type. Note that this an unsigned 32-bit value.
+</para><para>Generally drivers should not scale hardware
 control values. It may be necessary for example when the
 <structfield>name</structfield> or <structfield>id</structfield> imply
 a particular unit and the hardware actually accepts only multiples of
@@ -192,10 +200,11 @@ be always positive.</para></entry>
 	    <entry><structfield>default_value</structfield></entry>
 	    <entry>The default value of a
 <constant>V4L2_CTRL_TYPE_INTEGER</constant>,
-<constant>_BOOLEAN</constant> or <constant>_MENU</constant> control.
-Not valid for other types of controls. Drivers reset controls only
-when the driver is loaded, not later, in particular not when the
-func-open; is called.</entry>
+<constant>_BOOLEAN</constant>, <constant>_BITMASK</constant>,
+<constant>_MENU</constant> or <constant>_INTEGER_MENU</constant> control.
+Not valid for other types of controls.
+Note that drivers reset controls to their default value only when the
+driver is first loaded, never afterwards.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
@@ -213,6 +222,126 @@ the array to zero.</entry>
       </tgroup>
     </table>
 
+    <table pgwide="1" frame="none" id="v4l2-query-ext-ctrl">
+      <title>struct <structname>v4l2_query_ext_ctrl</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>id</structfield></entry>
+	    <entry>Identifies the control, set by the application. See
+<xref linkend="control-id" /> for predefined IDs. When the ID is ORed
+with <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> the driver clears the
+flag and returns the first non-compound control with a higher ID. When the
+ID is ORed with <constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant> the driver
+clears the flag and returns the first compound control with a higher ID.
+Set both to get the first control (compound or not) with a higher ID.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>type</structfield></entry>
+	    <entry>Type of control, see <xref
+		linkend="v4l2-ctrl-type" />.</entry>
+	  </row>
+	  <row>
+	    <entry>char</entry>
+	    <entry><structfield>name</structfield>[32]</entry>
+	    <entry>Name of the control, a NUL-terminated ASCII
+string. This information is intended for the user.</entry>
+	  </row>
+	  <row>
+	    <entry>__s64</entry>
+	    <entry><structfield>minimum</structfield></entry>
+	    <entry>Minimum value, inclusive. This field gives a lower
+bound for the control. See &v4l2-ctrl-type; how the minimum value is to
+be used for each possible control type. Note that this a signed 64-bit value.</entry>
+	  </row>
+	  <row>
+	    <entry>__s64</entry>
+	    <entry><structfield>maximum</structfield></entry>
+	    <entry>Maximum value, inclusive. This field gives an upper
+bound for the control. See &v4l2-ctrl-type; how the maximum value is to
+be used for each possible control type. Note that this a signed 64-bit value.</entry>
+	  </row>
+	  <row>
+	    <entry>__u64</entry>
+	    <entry><structfield>step</structfield></entry>
+	    <entry><para>This field gives a step size for the control.
+See &v4l2-ctrl-type; how the step value is to be used for each possible
+control type. Note that this an unsigned 64-bit value.
+</para><para>Generally drivers should not scale hardware
+control values. It may be necessary for example when the
+<structfield>name</structfield> or <structfield>id</structfield> imply
+a particular unit and the hardware actually accepts only multiples of
+said unit. If so, drivers must take care values are properly rounded
+when scaling, such that errors will not accumulate on repeated
+read-write cycles.</para><para>This field gives the smallest change of
+an integer control actually affecting hardware. Often the information
+is needed when the user can change controls by keyboard or GUI
+buttons, rather than a slider. When for example a hardware register
+accepts values 0-511 and the driver reports 0-65535, step should be
+128.</para></entry>
+	  </row>
+	  <row>
+	    <entry>__s64</entry>
+	    <entry><structfield>default_value</structfield></entry>
+	    <entry>The default value of a
+<constant>V4L2_CTRL_TYPE_INTEGER</constant>, <constant>_INTEGER64</constant>,
+<constant>_BOOLEAN</constant>, <constant>_BITMASK</constant>,
+<constant>_MENU</constant>, <constant>_INTEGER_MENU</constant>,
+<constant>_U8</constant> or <constant>_U16</constant> control.
+Not valid for other types of controls.
+Note that drivers reset controls to their default value only when the
+driver is first loaded, never afterwards.
+</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>flags</structfield></entry>
+	    <entry>Control flags, see <xref
+		linkend="control-flags" />.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>elem_size</structfield></entry>
+	    <entry>The size in bytes of a single element of the array.
+Given a char pointer <constant>p</constant> to a 3-dimensional array you can find the
+position of cell <constant>(z, y, x)</constant> as follows:
+<constant>p + ((z * dims[1] + y) * dims[0] + x) * elem_size</constant>. <structfield>elem_size</structfield>
+is always valid, also when the control isn't an array. For string controls
+<structfield>elem_size</structfield> is equal to <structfield>maximum + 1</structfield>.
+</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>elems</structfield></entry>
+	    <entry>The number of elements in the N-dimensional array. If this control
+is not an array, then <structfield>elems</structfield> is 1. The <structfield>elems</structfield>
+field can never be 0.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>nr_of_dims</structfield></entry>
+	    <entry>The number of dimension in the N-dimensional array. If this control
+is not an array, then this field is 0.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>dims[V4L2_CTRL_MAX_DIMS]</structfield></entry>
+	    <entry>The size of each dimension. The first <structfield>nr_of_dims</structfield>
+elements of this array must be non-zero, all remaining elements must be zero.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[32]</entry>
+	    <entry>Reserved for future extensions. Applications and drivers
+must set the array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
     <table pgwide="1" frame="none" id="v4l2-querymenu">
       <title>struct <structname>v4l2_querymenu</structname></title>
       <tgroup cols="4">
@@ -347,11 +476,14 @@ Drivers must ignore the value passed with
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CTRL_TYPE_INTEGER64</constant></entry>
-	    <entry>n/a</entry>
-	    <entry>n/a</entry>
-	    <entry>n/a</entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
 	    <entry>A 64-bit integer valued control. Minimum, maximum
-and step size cannot be queried.</entry>
+and step size cannot be queried using <constant>VIDIOC_QUERYCTRL</constant>.
+Only <constant>VIDIOC_QUERY_EXT_CTRL</constant> can retrieve the 64-bit
+min/max/step values, they should be interpreted as n/a when using
+<constant>VIDIOC_QUERYCTRL</constant>.</entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CTRL_TYPE_STRING</constant></entry>
@@ -379,6 +511,26 @@ ioctl returns the name of the control class and this control type.
 Older drivers which do not support this feature return an
 &EINVAL;.</entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_TYPE_U8</constant></entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>An unsigned 8-bit valued control ranging from minimum to
+maximum inclusive. The step value indicates the increment between
+values which are actually different on the hardware.
+</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_TYPE_U16</constant></entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>An unsigned 16-bit valued control ranging from minimum to
+maximum inclusive. The step value indicates the increment between
+values which are actually different on the hardware.
+</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
@@ -450,6 +602,14 @@ is in auto-gain mode. In such a case the hardware calculates the gain value base
 the lighting conditions which can change over time. Note that setting a new value for
 a volatile control will have no effect. The new value will just be ignored.</entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant></entry>
+	    <entry>0x0100</entry>
+	    <entry>This control has a pointer type, so its value has to be accessed
+using one of the pointer fields of &v4l2-ext-control;. This flag is set for controls
+that are an array, string, or have a compound type. In all cases you have to set a
+pointer to memory containing the payload of the control.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>

+ 8 - 0
Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml

@@ -174,6 +174,14 @@
 	      will have the ORed value of all the events generated.</para>
 	    </entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_EVENT_MOTION_DET</constant></entry>
+	    <entry>5</entry>
+	    <entry>
+	      <para>Triggered whenever the motion detection state for one or more of the regions
+	      changes. This event has a &v4l2-event-motion-det; associated with it.</para>
+	    </entry>
+	  </row>
 	  <row>
 	    <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
 	    <entry>0x08000000</entry>

+ 51 - 0
Documentation/devicetree/bindings/media/atmel-isi.txt

@@ -0,0 +1,51 @@
+Atmel Image Sensor Interface (ISI) SoC Camera Subsystem
+----------------------------------------------
+
+Required properties:
+- compatible: must be "atmel,at91sam9g45-isi"
+- reg: physical base address and length of the registers set for the device;
+- interrupts: should contain IRQ line for the ISI;
+- clocks: list of clock specifiers, corresponding to entries in
+          the clock-names property;
+- clock-names: must contain "isi_clk", which is the isi peripherial clock.
+
+ISI supports a single port node with parallel bus. It should contain one
+'port' child node with child 'endpoint' node. Please refer to the bindings
+defined in Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example:
+	isi: isi@f0034000 {
+		compatible = "atmel,at91sam9g45-isi";
+		reg = <0xf0034000 0x4000>;
+		interrupts = <37 IRQ_TYPE_LEVEL_HIGH 5>;
+
+		clocks = <&isi_clk>;
+		clock-names = "isi_clk";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_isi>;
+
+		port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			isi_0: endpoint {
+				remote-endpoint = <&ov2640_0>;
+				bus-width = <8>;
+			};
+		};
+	};
+
+	i2c1: i2c@f0018000 {
+		ov2640: camera@0x30 {
+			compatible = "omnivision,ov2640";
+			reg = <0x30>;
+
+			port {
+				ov2640_0: endpoint {
+					remote-endpoint = <&isi_0>;
+					bus-width = <8>;
+				};
+			};
+		};
+	};

+ 8 - 4
Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt

@@ -3,9 +3,13 @@ Samsung S5P/EXYNOS SoC series JPEG codec
 Required properties:
 
 - compatible	: should be one of:
-		  "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg";
+		  "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg",
+		  "samsung,exynos3250-jpeg";
 - reg		: address and length of the JPEG codec IP register set;
 - interrupts	: specifies the JPEG codec IP interrupt;
-- clocks	: should contain the JPEG codec IP gate clock specifier, from the
-		  common clock bindings;
-- clock-names	: should contain "jpeg" entry.
+- clock-names   : should contain:
+		   - "jpeg" for the core gate clock,
+		   - "sclk" for the special clock (optional).
+- clocks	: should contain the clock specifier and clock ID list
+		  matching entries in the clock-names property; from
+		  the common clock bindings.

+ 28 - 0
Documentation/devicetree/bindings/media/i2c/mt9m111.txt

@@ -0,0 +1,28 @@
+Micron 1.3Mp CMOS Digital Image Sensor
+
+The Micron MT9M111 is a CMOS active pixel digital image sensor with an active
+array size of 1280H x 1024V. It is programmable through a simple two-wire serial
+interface.
+
+Required Properties:
+- compatible: value should be "micron,mt9m111"
+
+For further reading on port node refer to
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example:
+
+	i2c_master {
+		mt9m111@5d {
+			compatible = "micron,mt9m111";
+			reg = <0x5d>;
+
+			remote = <&pxa_camera>;
+			port {
+				mt9m111_1: endpoint {
+					bus-width = <8>;
+					remote-endpoint = <&pxa_camera>;
+				};
+			};
+		};
+	};

+ 43 - 0
Documentation/devicetree/bindings/media/pxa-camera.txt

@@ -0,0 +1,43 @@
+Marvell PXA camera host interface
+
+Required properties:
+ - compatible: Should be "marvell,pxa270-qci"
+ - reg: register base and size
+ - interrupts: the interrupt number
+ - any required generic properties defined in video-interfaces.txt
+
+Optional properties:
+ - clocks: input clock (see clock-bindings.txt)
+ - clock-output-names: should contain the name of the clock driving the
+                       sensor master clock MCLK
+ - clock-frequency: host interface is driving MCLK, and MCLK rate is this rate
+
+Example:
+
+	pxa_camera: pxa_camera@50000000 {
+		compatible = "marvell,pxa270-qci";
+		reg = <0x50000000 0x1000>;
+		interrupts = <33>;
+
+		clocks = <&pxa2xx_clks 24>;
+		clock-names = "ciclk";
+		clock-frequency = <50000000>;
+		clock-output-names = "qci_mclk";
+
+		status = "okay";
+
+		port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			/* Parallel bus endpoint */
+			qci: endpoint@0 {
+				reg = <0>;		/* Local endpoint # */
+				remote-endpoint = <&mt9m111_1>;
+				bus-width = <8>;	/* Used data lines */
+				hsync-active = <0>;	/* Active low */
+				vsync-active = <0>;	/* Active low */
+				pclk-sample = <1>;	/* Rising */
+			};
+		};
+	};

+ 86 - 0
Documentation/devicetree/bindings/media/rcar_vin.txt

@@ -0,0 +1,86 @@
+Renesas RCar Video Input driver (rcar_vin)
+------------------------------------------
+
+The rcar_vin device provides video input capabilities for the Renesas R-Car
+family of devices. The current blocks are always slaves and suppot one input
+channel which can be either RGB, YUYV or BT656.
+
+ - compatible: Must be one of the following
+   - "renesas,vin-r8a7791" for the R8A7791 device
+   - "renesas,vin-r8a7790" for the R8A7790 device
+   - "renesas,vin-r8a7779" for the R8A7779 device
+   - "renesas,vin-r8a7778" for the R8A7778 device
+ - reg: the register base and size for the device registers
+ - interrupts: the interrupt for the device
+ - clocks: Reference to the parent clock
+
+Additionally, an alias named vinX will need to be created to specify
+which video input device this is.
+
+The per-board settings:
+ - port sub-node describing a single endpoint connected to the vin
+   as described in video-interfaces.txt[1]. Only the first one will
+   be considered as each vin interface has one input port.
+
+   These settings are used to work out video input format and widths
+   into the system.
+
+
+Device node example
+-------------------
+
+	aliases {
+	       vin0 = &vin0;
+	};
+
+        vin0: vin@0xe6ef0000 {
+                compatible = "renesas,vin-r8a7790";
+                clocks = <&mstp8_clks R8A7790_CLK_VIN0>;
+                reg = <0 0xe6ef0000 0 0x1000>;
+                interrupts = <0 188 IRQ_TYPE_LEVEL_HIGH>;
+                status = "disabled";
+        };
+
+Board setup example (vin1 composite video input)
+------------------------------------------------
+
+&i2c2   {
+        status = "ok";
+        pinctrl-0 = <&i2c2_pins>;
+        pinctrl-names = "default";
+
+        adv7180@20 {
+                compatible = "adi,adv7180";
+                reg = <0x20>;
+                remote = <&vin1>;
+
+                port {
+                        adv7180: endpoint {
+                                bus-width = <8>;
+                                remote-endpoint = <&vin1ep0>;
+                        };
+                };
+        };
+};
+
+/* composite video input */
+&vin1 {
+        pinctrl-0 = <&vin1_pins>;
+        pinctrl-names = "default";
+
+        status = "ok";
+
+        port {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                vin1ep0: endpoint {
+                        remote-endpoint = <&adv7180>;
+                        bus-width = <8>;
+                };
+        };
+};
+
+
+
+[1] video-interfaces.txt common video media interface

+ 23 - 0
Documentation/devicetree/bindings/media/sunxi-ir.txt

@@ -0,0 +1,23 @@
+Device-Tree bindings for SUNXI IR controller found in sunXi SoC family
+
+Required properties:
+- compatible	    : should be "allwinner,sun4i-a10-ir";
+- clocks	    : list of clock specifiers, corresponding to
+		      entries in clock-names property;
+- clock-names	    : should contain "apb" and "ir" entries;
+- interrupts	    : should contain IR IRQ number;
+- reg		    : should contain IO map address for IR.
+
+Optional properties:
+- linux,rc-map-name : Remote control map name.
+
+Example:
+
+ir0: ir@01c21800 {
+	compatible = "allwinner,sun4i-a10-ir";
+	clocks = <&apb0_gates 6>, <&ir0_clk>;
+	clock-names = "apb", "ir";
+	interrupts = <0 5 1>;
+	reg = <0x01C21800 0x40>;
+	linux,rc-map-name = "rc-rc6-mce";
+};

+ 32 - 1
Documentation/dvb/get_dvb_firmware

@@ -29,7 +29,7 @@ use IO::Handle;
 		"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
 		"lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
 		"drxk_hauppauge_hvr930c", "tda10071", "it9135", "drxk_pctv",
-		"drxk_terratec_htc_stick", "sms1xxx_hcw");
+		"drxk_terratec_htc_stick", "sms1xxx_hcw", "si2165");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -783,6 +783,37 @@ sub sms1xxx_hcw {
     $allfiles;
 }
 
+sub si2165 {
+    my $sourcefile = "model_111xxx_122xxx_driver_6_0_119_31191_WHQL.zip";
+    my $url = "http://www.hauppauge.de/files/drivers/";
+    my $hash = "76633e7c76b0edee47c3ba18ded99336";
+    my $fwfile = "dvb-demod-si2165.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url . $sourcefile);
+    verify($sourcefile, $hash);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/Driver10/Hcw10bda.sys", 0x80788, 0x81E08-0x80788, "$tmpdir/fw1");
+
+    delzero("$tmpdir/fw1","$tmpdir/fw1-1");
+    #verify("$tmpdir/fw1","5e0909858fdf0b5b09ad48b9fe622e70");
+
+    my $CRC="\x0A\xCC";
+    my $BLOCKS_MAIN="\x27";
+    open FW,">$fwfile";
+    print FW "\x01\x00"; # just a version id for the driver itself
+    print FW "\x9A"; # fw version
+    print FW "\x00"; # padding
+    print FW "$BLOCKS_MAIN"; # number of blocks of main part
+    print FW "\x00"; # padding
+    print FW "$CRC"; # 16bit crc value of main part
+    appendfile(FW,"$tmpdir/fw1");
+
+    "$fwfile";
+}
+
 # ---------------------------------------------------------------
 # Utilities
 

+ 2 - 0
Documentation/video4linux/CARDLIST.cx23885

@@ -41,3 +41,5 @@
  40 -> TurboSight TBS 6981                                 [6981:8888]
  41 -> TurboSight TBS 6980                                 [6980:8888]
  42 -> Leadtek Winfast PxPVR2200                           [107d:6f21]
+ 43 -> Hauppauge ImpactVCB-e                               [0070:7133]
+ 44 -> DViCO FusionHDTV DVB-T Dual Express2                [18ac:db98]

+ 1 - 1
Documentation/video4linux/CARDLIST.em28xx

@@ -77,7 +77,7 @@
  76 -> KWorld PlusTV 340U or UB435-Q (ATSC)     (em2870)        [1b80:a340]
  77 -> EM2874 Leadership ISDBT                  (em2874)
  78 -> PCTV nanoStick T2 290e                   (em28174)
- 79 -> Terratec Cinergy H5                      (em2884)        [0ccd:10a2,0ccd:10ad,0ccd:10b6]
+ 79 -> Terratec Cinergy H5                      (em2884)        [eb1a:2885,0ccd:10a2,0ccd:10ad,0ccd:10b6]
  80 -> PCTV DVB-S2 Stick (460e)                 (em28174)
  81 -> Hauppauge WinTV HVR 930C                 (em2884)        [2040:1605]
  82 -> Terratec Cinergy HTC Stick               (em2884)        [0ccd:00b2]

+ 39 - 24
Documentation/video4linux/v4l2-controls.txt

@@ -77,9 +77,9 @@ Basic usage for V4L2 and sub-device drivers
 
   Where foo->v4l2_dev is of type struct v4l2_device.
 
-  Finally, remove all control functions from your v4l2_ioctl_ops:
-  vidioc_queryctrl, vidioc_querymenu, vidioc_g_ctrl, vidioc_s_ctrl,
-  vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls.
+  Finally, remove all control functions from your v4l2_ioctl_ops (if any):
+  vidioc_queryctrl, vidioc_query_ext_ctrl, vidioc_querymenu, vidioc_g_ctrl,
+  vidioc_s_ctrl, vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls.
   Those are now no longer needed.
 
 1.3.2) For sub-device drivers do this:
@@ -258,8 +258,8 @@ The new control value has already been validated, so all you need to do is
 to actually update the hardware registers.
 
 You're done! And this is sufficient for most of the drivers we have. No need
-to do any validation of control values, or implement QUERYCTRL/QUERYMENU. And
-G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically supported.
+to do any validation of control values, or implement QUERYCTRL, QUERY_EXT_CTRL
+and QUERYMENU. And G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically supported.
 
 
 ==============================================================================
@@ -288,30 +288,45 @@ of v4l2_device.
 Accessing Control Values
 ========================
 
-The v4l2_ctrl struct contains these two unions:
+The following union is used inside the control framework to access control
+values:
 
-	/* The current control value. */
-	union {
+union v4l2_ctrl_ptr {
+	s32 *p_s32;
+	s64 *p_s64;
+	char *p_char;
+	void *p;
+};
+
+The v4l2_ctrl struct contains these fields that can be used to access both
+current and new values:
+
+	s32 val;
+	struct {
 		s32 val;
-		s64 val64;
-		char *string;
 	} cur;
 
-	/* The new control value. */
-	union {
-		s32 val;
-		s64 val64;
-		char *string;
-	};
 
-Within the control ops you can freely use these. The val and val64 speak for
-themselves. The string pointers point to character buffers of length
+	union v4l2_ctrl_ptr p_new;
+	union v4l2_ctrl_ptr p_cur;
+
+If the control has a simple s32 type type, then:
+
+	&ctrl->val == ctrl->p_new.p_s32
+	&ctrl->cur.val == ctrl->p_cur.p_s32
+
+For all other types use ctrl->p_cur.p<something>. Basically the val
+and cur.val fields can be considered an alias since these are used so often.
+
+Within the control ops you can freely use these. The val and cur.val speak for
+themselves. The p_char pointers point to character buffers of length
 ctrl->maximum + 1, and are always 0-terminated.
 
-In most cases 'cur' contains the current cached control value. When you create
-a new control this value is made identical to the default value. After calling
-v4l2_ctrl_handler_setup() this value is passed to the hardware. It is generally
-a good idea to call this function.
+Unless the control is marked volatile the p_cur field points to the the
+current cached control value. When you create a new control this value is made
+identical to the default value. After calling v4l2_ctrl_handler_setup() this
+value is passed to the hardware. It is generally a good idea to call this
+function.
 
 Whenever a new value is set that new value is automatically cached. This means
 that most drivers do not need to implement the g_volatile_ctrl() op. The
@@ -362,8 +377,8 @@ will result in a deadlock since these helpers lock the handler as well.
 You can also take the handler lock yourself:
 
 	mutex_lock(&state->ctrl_handler.lock);
-	printk(KERN_INFO "String value is '%s'\n", ctrl1->cur.string);
-	printk(KERN_INFO "Integer value is '%s'\n", ctrl2->cur.val);
+	pr_info("String value is '%s'\n", ctrl1->p_cur.p_char);
+	pr_info("Integer value is '%s'\n", ctrl2->cur.val);
 	mutex_unlock(&state->ctrl_handler.lock);
 
 

+ 1 - 7
Documentation/video4linux/v4l2-framework.txt

@@ -675,11 +675,6 @@ You should also set these fields:
   video_device is initialized you *do* know which parent PCI device to use and
   so you set dev_device to the correct PCI device.
 
-- flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the framework
-  handle the VIDIOC_G/S_PRIORITY ioctls. This requires that you use struct
-  v4l2_fh. Eventually this flag will disappear once all drivers use the core
-  priority handling. But for now it has to be set explicitly.
-
 If you use v4l2_ioctl_ops, then you should set .unlocked_ioctl to video_ioctl2
 in your v4l2_file_operations struct.
 
@@ -909,8 +904,7 @@ struct v4l2_fh
 
 struct v4l2_fh provides a way to easily keep file handle specific data
 that is used by the V4L2 framework. New drivers must use struct v4l2_fh
-since it is also used to implement priority handling (VIDIOC_G/S_PRIORITY)
-if the video_device flag V4L2_FL_USE_FH_PRIO is also set.
+since it is also used to implement priority handling (VIDIOC_G/S_PRIORITY).
 
 The users of v4l2_fh (in the V4L2 framework, not the driver) know
 whether a driver uses v4l2_fh as its file->private_data pointer by

+ 0 - 5
Documentation/video4linux/v4l2-pci-skeleton.c

@@ -883,11 +883,6 @@ static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	vdev->v4l2_dev = &skel->v4l2_dev;
 	/* Supported SDTV standards, if any */
 	vdev->tvnorms = SKEL_TVNORMS;
-	/* If this bit is set, then the v4l2 core will provide the support
-	 * for the VIDIOC_G/S_PRIORITY ioctls. This flag will eventually
-	 * go away once all drivers have been converted to use struct v4l2_fh.
-	 */
-	set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
 	video_set_drvdata(vdev, skel);
 
 	ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);

+ 1 - 6
Documentation/zh_CN/video4linux/v4l2-framework.txt

@@ -580,11 +580,6 @@ release()回调必须被设置,且在最后一个 video_device 用户退出之
   v4l2_device 无法与特定的 PCI 设备关联,所有没有设置父设备。但当
   video_device 配置后,就知道使用哪个父 PCI 设备了。
 
-- flags:可选。如果你要让框架处理设置 VIDIOC_G/S_PRIORITY ioctls,
-  请设置 V4L2_FL_USE_FH_PRIO。这要求你使用 v4l2_fh 结构体。
-  一旦所有驱动使用了核心的优先级处理,最终这个标志将消失。但现在它
-  必须被显式设置。
-
 如果你使用 v4l2_ioctl_ops,则应该在 v4l2_file_operations 结构体中
 设置 .unlocked_ioctl 指向 video_ioctl2。
 
@@ -789,7 +784,7 @@ v4l2_fh 结构体
 -------------
 
 v4l2_fh 结构体提供一个保存用于 V4L2 框架的文件句柄特定数据的简单方法。
-如果 video_device 的 flag 设置了 V4L2_FL_USE_FH_PRIO 标志,新驱动
+如果 video_device 标志,新驱动
 必须使用 v4l2_fh 结构体,因为它也用于实现优先级处理(VIDIOC_G/S_PRIORITY)。
 
 v4l2_fh 的用户(位于 V4l2 框架中,并非驱动)可通过测试

+ 28 - 24
MAINTAINERS

@@ -516,6 +516,16 @@ S:	Supported
 F:	fs/aio.c
 F:	include/linux/*aio*.h
 
+AIRSPY MEDIA DRIVER
+M:	Antti Palosaari <crope@iki.fi>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+W:	http://palosaari.fi/linux/
+Q:	http://patchwork.linuxtv.org/project/linux-media/list/
+T:	git git://linuxtv.org/anttip/media_tree.git
+S:	Maintained
+F:	drivers/media/usb/airspy/
+
 ALCATEL SPEEDTOUCH USB DRIVER
 M:	Duncan Sands <duncan.sands@free.fr>
 L:	linux-usb@vger.kernel.org
@@ -3993,6 +4003,12 @@ F:	Documentation/isdn/README.gigaset
 F:	drivers/isdn/gigaset/
 F:	include/uapi/linux/gigaset_dev.h
 
+GO7007 MPEG CODEC
+M:	Hans Verkuil <hans.verkuil@cisco.com>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	drivers/media/usb/go7007/
+
 GPIO SUBSYSTEM
 M:	Linus Walleij <linus.walleij@linaro.org>
 M:	Alexandre Courbot <gnurou@gmail.com>
@@ -5965,9 +5981,9 @@ W:	http://palosaari.fi/linux/
 Q:	http://patchwork.linuxtv.org/project/linux-media/list/
 T:	git git://linuxtv.org/anttip/media_tree.git
 S:	Maintained
-F:	drivers/staging/media/msi3101/msi001*
+F:	drivers/media/tuners/msi001*
 
-MSI3101 MEDIA DRIVER
+MSI2500 MEDIA DRIVER
 M:	Antti Palosaari <crope@iki.fi>
 L:	linux-media@vger.kernel.org
 W:	http://linuxtv.org/
@@ -5975,7 +5991,7 @@ W:	http://palosaari.fi/linux/
 Q:	http://patchwork.linuxtv.org/project/linux-media/list/
 T:	git git://linuxtv.org/anttip/media_tree.git
 S:	Maintained
-F:	drivers/staging/media/msi3101/sdr-msi3101*
+F:	drivers/media/usb/msi2500/
 
 MT9M032 APTINA SENSOR DRIVER
 M:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -6499,11 +6515,12 @@ L:	linux-omap@vger.kernel.org
 S:	Maintained
 F:	arch/arm/mach-omap2/omap_hwmod_44xx_data.c
 
-OMAP IMAGE SIGNAL PROCESSOR (ISP)
+OMAP IMAGING SUBSYSTEM (OMAP3 ISP and OMAP4 ISS)
 M:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:	linux-media@vger.kernel.org
 S:	Maintained
 F:	drivers/media/platform/omap3isp/
+F:	drivers/staging/media/omap4iss/
 
 OMAP USB SUPPORT
 M:	Felipe Balbi <balbi@ti.com>
@@ -7611,7 +7628,7 @@ W:	http://palosaari.fi/linux/
 Q:	http://patchwork.linuxtv.org/project/linux-media/list/
 T:	git git://linuxtv.org/anttip/media_tree.git
 S:	Maintained
-F:	drivers/staging/media/rtl2832u_sdr/rtl2832_sdr*
+F:	drivers/media/dvb-frontends/rtl2832_sdr*
 
 RTL8180 WIRELESS DRIVER
 M:	"John W. Linville" <linville@tuxdriver.com>
@@ -8380,6 +8397,12 @@ M:	Chris Boot <bootc@bootc.net>
 S:	Maintained
 F:	drivers/leds/leds-net48xx.c
 
+SOFTLOGIC 6x10 MPEG CODEC
+M:	Ismael Luceno <ismael.luceno@corp.bluecherry.net>
+L:	linux-media@vger.kernel.org
+S:	Supported
+F:	drivers/media/pci/solo6x10/
+
 SOFTWARE RAID (Multiple Disks) SUPPORT
 M:	Neil Brown <neilb@suse.de>
 L:	linux-raid@vger.kernel.org
@@ -8586,11 +8609,6 @@ M:	Marek Belisko <marek.belisko@gmail.com>
 S:	Odd Fixes
 F:	drivers/staging/ft1000/
 
-STAGING - GO7007 MPEG CODEC
-M:	Hans Verkuil <hans.verkuil@cisco.com>
-S:	Maintained
-F:	drivers/staging/media/go7007/
-
 STAGING - INDUSTRIAL IO
 M:	Jonathan Cameron <jic23@kernel.org>
 L:	linux-iio@vger.kernel.org
@@ -8648,11 +8666,6 @@ M:	Christopher Harrer <charrer@alacritech.com>
 S:	Odd Fixes
 F:	drivers/staging/slicoss/
 
-STAGING - SOFTLOGIC 6x10 MPEG CODEC
-M:	Ismael Luceno <ismael.luceno@corp.bluecherry.net>
-S:	Supported
-F:	drivers/staging/media/solo6x10/
-
 STAGING - SPEAKUP CONSOLE SPEECH DRIVER
 M:	William Hubbs <w.d.hubbs@gmail.com>
 M:	Chris Brannon <chris@the-brannons.com>
@@ -9519,15 +9532,6 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 F:	drivers/net/usb/smsc95xx.*
 
-USB SN9C1xx DRIVER
-M:	Luca Risolia <luca.risolia@studio.unibo.it>
-L:	linux-usb@vger.kernel.org
-L:	linux-media@vger.kernel.org
-T:	git git://linuxtv.org/media_tree.git
-W:	http://www.linux-projects.org
-S:	Maintained
-F:	drivers/staging/media/sn9c102/
-
 USB SUBSYSTEM
 M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:	linux-usb@vger.kernel.org

+ 1 - 1
drivers/hid/hid-picolcd_cir.c

@@ -114,7 +114,7 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
 
 	rdev->priv             = data;
 	rdev->driver_type      = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+	rdev->allowed_protocols = RC_BIT_ALL;
 	rdev->open             = picolcd_cir_open;
 	rdev->close            = picolcd_cir_close;
 	rdev->input_name       = data->hdev->name;

+ 10 - 2
drivers/media/Kconfig

@@ -59,6 +59,13 @@ config MEDIA_RADIO_SUPPORT
 		support radio reception. Disabling this option will
 		disable support for them.
 
+config MEDIA_SDR_SUPPORT
+	bool "Software defined radio support"
+	---help---
+	  Enable software defined radio support.
+
+	  Say Y when you have a software defined radio device.
+
 config MEDIA_RC_SUPPORT
 	bool "Remote Controller support"
 	depends on INPUT
@@ -95,7 +102,7 @@ config MEDIA_CONTROLLER
 config VIDEO_DEV
 	tristate
 	depends on MEDIA_SUPPORT
-	depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT
+	depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT
 	default y
 
 config VIDEO_V4L2_SUBDEV_API
@@ -171,10 +178,11 @@ comment "Media ancillary drivers (tuners, sensors, i2c, frontends)"
 
 config MEDIA_SUBDRV_AUTOSELECT
 	bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)"
-	depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT
+	depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT || MEDIA_SDR_SUPPORT
 	depends on HAS_IOMEM
 	select I2C
 	select I2C_MUX
+	select SPI
 	default y
 	help
 	  By default, a media driver auto-selects all possible ancillary

+ 6 - 8
drivers/media/common/saa7146/saa7146_fops.c

@@ -533,13 +533,12 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
 	if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
 		saa7146_vbi_uops.init(dev,vv);
 
-	fmt = &vv->ov_fb.fmt;
-	fmt->width = vv->standard->h_max_out;
-	fmt->height = vv->standard->v_max_out;
-	fmt->pixelformat = V4L2_PIX_FMT_RGB565;
-	fmt->bytesperline = 2 * fmt->width;
-	fmt->sizeimage = fmt->bytesperline * fmt->height;
-	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+	vv->ov_fb.fmt.width = vv->standard->h_max_out;
+	vv->ov_fb.fmt.height = vv->standard->v_max_out;
+	vv->ov_fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
+	vv->ov_fb.fmt.bytesperline = 2 * vv->ov_fb.fmt.width;
+	vv->ov_fb.fmt.sizeimage = vv->ov_fb.fmt.bytesperline * vv->ov_fb.fmt.height;
+	vv->ov_fb.fmt.colorspace = V4L2_COLORSPACE_SRGB;
 
 	fmt = &vv->video_fmt;
 	fmt->width = 384;
@@ -613,7 +612,6 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 	vfd->lock = &dev->v4l2_lock;
 	vfd->v4l2_dev = &dev->v4l2_dev;
 	vfd->tvnorms = 0;
-	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
 	for (i = 0; i < dev->ext_vv_data->num_stds; i++)
 		vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
 	strlcpy(vfd->name, name, sizeof(vfd->name));

+ 1 - 2
drivers/media/common/siano/Kconfig

@@ -22,8 +22,7 @@ config SMS_SIANO_DEBUGFS
 	bool "Enable debugfs for smsdvb"
 	depends on SMS_SIANO_MDTV
 	depends on DEBUG_FS
-	depends on SMS_USB_DRV
-	depends on CONFIG_SMS_USB_DRV = CONFIG_SMS_SDIO_DRV
+	depends on SMS_USB_DRV = SMS_SDIO_DRV
 
 	---help---
 	  Choose Y to enable visualizing a dump of the frontend

+ 1 - 1
drivers/media/common/siano/smsir.c

@@ -88,7 +88,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
 
 	dev->priv = coredev;
 	dev->driver_type = RC_DRIVER_IR_RAW;
-	rc_set_allowed_protocols(dev, RC_BIT_ALL);
+	dev->allowed_protocols = RC_BIT_ALL;
 	dev->map_name = sms_get_board(board_id)->rc_codes;
 	dev->driver_name = MODULE_NAME;
 

+ 2 - 0
drivers/media/dvb-core/dvb-usb-ids.h

@@ -244,6 +244,7 @@
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM	0x3009
 #define USB_PID_TECHNOTREND_CONNECT_CT3650		0x300d
+#define USB_PID_TECHNOTREND_TVSTICK_CT2_4400		0x3014
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2	0x0081
 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058
@@ -363,6 +364,7 @@
 #define USB_PID_TVWAY_PLUS				0x0002
 #define USB_PID_SVEON_STV20				0xe39d
 #define USB_PID_SVEON_STV20_RTL2832U			0xd39d
+#define USB_PID_SVEON_STV21				0xd3b0
 #define USB_PID_SVEON_STV22				0xe401
 #define USB_PID_SVEON_STV22_IT9137			0xe411
 #define USB_PID_AZUREWAVE_AZ6027			0x3275

+ 17 - 19
drivers/media/dvb-core/dvb_frontend.c

@@ -96,10 +96,6 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
  * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
  */
 
-#define DVB_FE_NO_EXIT	0
-#define DVB_FE_NORMAL_EXIT	1
-#define DVB_FE_DEVICE_REMOVED	2
-
 static DEFINE_MUTEX(frontend_mutex);
 
 struct dvb_frontend_private {
@@ -113,7 +109,6 @@ struct dvb_frontend_private {
 	wait_queue_head_t wait_queue;
 	struct task_struct *thread;
 	unsigned long release_jiffies;
-	unsigned int exit;
 	unsigned int wakeup;
 	fe_status_t status;
 	unsigned long tune_mode_flags;
@@ -565,7 +560,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 {
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
-	if (fepriv->exit != DVB_FE_NO_EXIT)
+	if (fe->exit != DVB_FE_NO_EXIT)
 		return 1;
 
 	if (fepriv->dvbdev->writers == 1)
@@ -629,7 +624,7 @@ restart:
 			/* got signal or quitting */
 			if (!down_interruptible(&fepriv->sem))
 				semheld = true;
-			fepriv->exit = DVB_FE_NORMAL_EXIT;
+			fe->exit = DVB_FE_NORMAL_EXIT;
 			break;
 		}
 
@@ -739,9 +734,9 @@ restart:
 
 	fepriv->thread = NULL;
 	if (kthread_should_stop())
-		fepriv->exit = DVB_FE_DEVICE_REMOVED;
+		fe->exit = DVB_FE_DEVICE_REMOVED;
 	else
-		fepriv->exit = DVB_FE_NO_EXIT;
+		fe->exit = DVB_FE_NO_EXIT;
 	mb();
 
 	if (semheld)
@@ -756,7 +751,8 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
 
 	dev_dbg(fe->dvb->device, "%s:\n", __func__);
 
-	fepriv->exit = DVB_FE_NORMAL_EXIT;
+	if (fe->exit != DVB_FE_DEVICE_REMOVED)
+		fe->exit = DVB_FE_NORMAL_EXIT;
 	mb();
 
 	if (!fepriv->thread)
@@ -826,7 +822,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
 	dev_dbg(fe->dvb->device, "%s:\n", __func__);
 
 	if (fepriv->thread) {
-		if (fepriv->exit == DVB_FE_NO_EXIT)
+		if (fe->exit == DVB_FE_NO_EXIT)
 			return 0;
 		else
 			dvb_frontend_stop (fe);
@@ -838,7 +834,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
 		return -EINTR;
 
 	fepriv->state = FESTATE_IDLE;
-	fepriv->exit = DVB_FE_NO_EXIT;
+	fe->exit = DVB_FE_NO_EXIT;
 	fepriv->thread = NULL;
 	mb();
 
@@ -1906,7 +1902,7 @@ static int dvb_frontend_ioctl(struct file *file,
 	if (down_interruptible(&fepriv->sem))
 		return -ERESTARTSYS;
 
-	if (fepriv->exit != DVB_FE_NO_EXIT) {
+	if (fe->exit != DVB_FE_NO_EXIT) {
 		up(&fepriv->sem);
 		return -ENODEV;
 	}
@@ -2424,7 +2420,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
 	int ret;
 
 	dev_dbg(fe->dvb->device, "%s:\n", __func__);
-	if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
+	if (fe->exit == DVB_FE_DEVICE_REMOVED)
 		return -ENODEV;
 
 	if (adapter->mfe_shared) {
@@ -2529,7 +2525,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
 
 	if (dvbdev->users == -1) {
 		wake_up(&fepriv->wait_queue);
-		if (fepriv->exit != DVB_FE_NO_EXIT)
+		if (fe->exit != DVB_FE_NO_EXIT)
 			wake_up(&dvbdev->wait_queue);
 		if (fe->ops.ts_bus_ctrl)
 			fe->ops.ts_bus_ctrl(fe, 0);
@@ -2572,12 +2568,14 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
 	dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
 			fe->id);
 
+	fe->exit = DVB_FE_DEVICE_RESUME;
 	if (fe->ops.init)
 		ret = fe->ops.init(fe);
 
 	if (fe->ops.tuner_ops.init)
 		ret = fe->ops.tuner_ops.init(fe);
 
+	fe->exit = DVB_FE_NO_EXIT;
 	fepriv->state = FESTATE_RETUNE;
 	dvb_frontend_wakeup(fe);
 
@@ -2666,20 +2664,20 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
 
 	if (fe->ops.release_sec) {
 		fe->ops.release_sec(fe);
-		symbol_put_addr(fe->ops.release_sec);
+		dvb_detach(fe->ops.release_sec);
 	}
 	if (fe->ops.tuner_ops.release) {
 		fe->ops.tuner_ops.release(fe);
-		symbol_put_addr(fe->ops.tuner_ops.release);
+		dvb_detach(fe->ops.tuner_ops.release);
 	}
 	if (fe->ops.analog_ops.release) {
 		fe->ops.analog_ops.release(fe);
-		symbol_put_addr(fe->ops.analog_ops.release);
+		dvb_detach(fe->ops.analog_ops.release);
 	}
 	ptr = (void*)fe->ops.release;
 	if (ptr) {
 		fe->ops.release(fe);
-		symbol_put_addr(ptr);
+		dvb_detach(ptr);
 	}
 }
 #else

+ 6 - 0
drivers/media/dvb-core/dvb_frontend.h

@@ -405,6 +405,11 @@ struct dtv_frontend_properties {
 	struct dtv_fe_stats	block_count;
 };
 
+#define DVB_FE_NO_EXIT  0
+#define DVB_FE_NORMAL_EXIT      1
+#define DVB_FE_DEVICE_REMOVED   2
+#define DVB_FE_DEVICE_RESUME    3
+
 struct dvb_frontend {
 	struct dvb_frontend_ops ops;
 	struct dvb_adapter *dvb;
@@ -418,6 +423,7 @@ struct dvb_frontend {
 #define DVB_FRONTEND_COMPONENT_DEMOD 1
 	int (*callback)(void *adapter_priv, int component, int cmd, int arg);
 	int id;
+	unsigned int exit;
 };
 
 extern int dvb_register_frontend(struct dvb_adapter *dvb,

+ 4 - 0
drivers/media/dvb-core/dvbdev.h

@@ -136,11 +136,15 @@ extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
 	__r; \
 })
 
+#define dvb_detach(FUNC)	symbol_put_addr(FUNC)
+
 #else
 #define dvb_attach(FUNCTION, ARGS...) ({ \
 	FUNCTION(ARGS); \
 })
 
+#define dvb_detach(FUNC)	{}
+
 #endif
 
 #endif /* #ifndef _DVBDEV_H_ */

+ 18 - 0
drivers/media/dvb-frontends/Kconfig

@@ -63,6 +63,15 @@ config DVB_TDA18271C2DD
 
 	  Say Y when you want to support this tuner.
 
+config DVB_SI2165
+	tristate "Silicon Labs si2165 based"
+	depends on DVB_CORE && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  A DVB-C/T demodulator.
+
+	  Say Y when you want to support this frontend.
+
 comment "DVB-S (satellite) frontends"
 	depends on DVB_CORE
 
@@ -446,6 +455,15 @@ config DVB_RTL2832
 	help
 	  Say Y when you want to support this frontend.
 
+config DVB_RTL2832_SDR
+	tristate "Realtek RTL2832 SDR"
+	depends on DVB_CORE && I2C && I2C_MUX && VIDEO_V4L2 && MEDIA_SDR_SUPPORT && USB
+	select DVB_RTL2832
+	select VIDEOBUF2_VMALLOC
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Say Y when you want to support this SDR module.
+
 config DVB_SI2168
 	tristate "Silicon Labs Si2168"
 	depends on DVB_CORE && I2C && I2C_MUX

+ 7 - 0
drivers/media/dvb-frontends/Makefile

@@ -5,6 +5,11 @@
 ccflags-y += -I$(srctree)/drivers/media/dvb-core/
 ccflags-y += -I$(srctree)/drivers/media/tuners/
 
+# FIXME: RTL2832 SDR driver uses power management directly from USB IF driver
+ifdef CONFIG_DVB_RTL2832_SDR
+	ccflags-y += -I$(srctree)/drivers/media/usb/dvb-usb-v2
+endif
+
 stb0899-objs := stb0899_drv.o stb0899_algo.o
 stv0900-objs := stv0900_core.o stv0900_sw.o
 drxd-objs := drxd_firm.o drxd_hard.o
@@ -100,10 +105,12 @@ obj-$(CONFIG_DVB_STV0367) += stv0367.o
 obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
 obj-$(CONFIG_DVB_DRXK) += drxk.o
 obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
+obj-$(CONFIG_DVB_SI2165) += si2165.o
 obj-$(CONFIG_DVB_A8293) += a8293.o
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
 obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
+obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
 

+ 0 - 1
drivers/media/dvb-frontends/af9013.c

@@ -470,7 +470,6 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe)
 		break;
 	default:
 		goto err;
-		break;
 	}
 
 	for (i = 0; i < len; i++) {

+ 121 - 59
drivers/media/dvb-frontends/au8522_decoder.c

@@ -220,7 +220,7 @@ static void setup_vbi(struct au8522_state *state, int aud_input)
 
 }
 
-static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
+static void setup_decoder_defaults(struct au8522_state *state, bool is_svideo)
 {
 	int i;
 	int filter_coef_type;
@@ -237,13 +237,10 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
 	/* Other decoder registers */
 	au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
 
-	if (input_mode == 0x23) {
-		/* S-Video input mapping */
+	if (is_svideo)
 		au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
-	} else {
-		/* All other modes (CVBS/ATVRF etc.) */
+	else
 		au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
-	}
 
 	au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
 			AU8522_TVDEC_PGA_REG012H_CVBS);
@@ -251,12 +248,23 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
 			AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
 	au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
 			AU8522_TVDED_DBG_MODE_REG060H_CVBS);
-	au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
-			AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
-			AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
-			AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN);
-	au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
-			AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC);
+
+	if (state->std == V4L2_STD_PAL_M) {
+		au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
+				AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
+				AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
+				AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_AUTO);
+		au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
+				AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_PAL_M);
+	} else {
+		/* NTSC */
+		au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
+				AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
+				AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
+				AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN);
+		au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
+				AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC);
+	}
 	au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
 			AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
 	au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
@@ -275,8 +283,7 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
 			AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
 	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
 			AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
-	if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
-	    input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+	if (is_svideo) {
 		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
 				AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
 		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
@@ -317,8 +324,7 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
 
 	setup_vbi(state, 0);
 
-	if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
-	    input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+	if (is_svideo) {
 		/* Despite what the table says, for the HVR-950q we still need
 		   to be in CVBS mode for the S-Video input (reason unknown). */
 		/* filter_coef_type = 3; */
@@ -346,7 +352,7 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
 	au8522_writereg(state, AU8522_REG436H, 0x3c);
 }
 
-static void au8522_setup_cvbs_mode(struct au8522_state *state)
+static void au8522_setup_cvbs_mode(struct au8522_state *state, u8 input_mode)
 {
 	/* here we're going to try the pre-programmed route */
 	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
@@ -358,16 +364,16 @@ static void au8522_setup_cvbs_mode(struct au8522_state *state)
 	/* Enable clamping control */
 	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
 
-	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
-			AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
 
-	setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+	setup_decoder_defaults(state, false);
 
 	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
 			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
 }
 
-static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
+static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state,
+					 u8 input_mode)
 {
 	/* here we're going to try the pre-programmed route */
 	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
@@ -384,24 +390,22 @@ static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
 	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
 
 	/* Set input mode to CVBS on channel 4 with SIF audio input enabled */
-	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
-			AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
 
-	setup_decoder_defaults(state,
-			       AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+	setup_decoder_defaults(state, false);
 
 	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
 			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
 }
 
-static void au8522_setup_svideo_mode(struct au8522_state *state)
+static void au8522_setup_svideo_mode(struct au8522_state *state,
+				     u8 input_mode)
 {
 	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
 			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
 
 	/* Set input to Y on Channe1, C on Channel 3 */
-	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
-			AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
 
 	/* PGA in automatic mode */
 	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
@@ -409,8 +413,7 @@ static void au8522_setup_svideo_mode(struct au8522_state *state)
 	/* Enable clamping control */
 	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
 
-	setup_decoder_defaults(state,
-			       AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+	setup_decoder_defaults(state, true);
 
 	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
 			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
@@ -432,8 +435,9 @@ static void disable_audio_input(struct au8522_state *state)
 }
 
 /* 0=disable, 1=SIF */
-static void set_audio_input(struct au8522_state *state, int aud_input)
+static void set_audio_input(struct au8522_state *state)
 {
+	int aud_input = state->aud_input;
 	int i;
 
 	/* Note that this function needs to be used in conjunction with setting
@@ -465,8 +469,9 @@ static void set_audio_input(struct au8522_state *state, int aud_input)
 	au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
 	msleep(150);
 	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00);
-	msleep(1);
-	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d);
+	msleep(10);
+	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
 	msleep(50);
 	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
 	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
@@ -539,58 +544,109 @@ static int au8522_s_register(struct v4l2_subdev *sd,
 }
 #endif
 
+static void au8522_video_set(struct au8522_state *state)
+{
+	u8 input_mode;
+
+	au8522_writereg(state, 0xa4, 1 << 5);
+
+	switch (state->vid_input) {
+	case AU8522_COMPOSITE_CH1:
+		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH1;
+		au8522_setup_cvbs_mode(state, input_mode);
+		break;
+	case AU8522_COMPOSITE_CH2:
+		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH2;
+		au8522_setup_cvbs_mode(state, input_mode);
+		break;
+	case AU8522_COMPOSITE_CH3:
+		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH3;
+		au8522_setup_cvbs_mode(state, input_mode);
+		break;
+	case AU8522_COMPOSITE_CH4:
+		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4;
+		au8522_setup_cvbs_mode(state, input_mode);
+		break;
+	case AU8522_SVIDEO_CH13:
+		input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13;
+		au8522_setup_svideo_mode(state, input_mode);
+		break;
+	case AU8522_SVIDEO_CH24:
+		input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24;
+		au8522_setup_svideo_mode(state, input_mode);
+		break;
+	default:
+	case AU8522_COMPOSITE_CH4_SIF:
+		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF;
+		au8522_setup_cvbs_tuner_mode(state, input_mode);
+		break;
+	}
+}
+
 static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct au8522_state *state = to_state(sd);
 
 	if (enable) {
+		/*
+		 * Clear out any state associated with the digital side of the
+		 * chip, so that when it gets powered back up it won't think
+		 * that it is already tuned
+		 */
+		state->current_frequency = 0;
+
 		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
 				0x01);
-		msleep(1);
-		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
-				AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+		msleep(10);
+
+		au8522_video_set(state);
+		set_audio_input(state);
+
+		state->operational_mode = AU8522_ANALOG_MODE;
 	} else {
 		/* This does not completely power down the device
 		   (it only reduces it from around 140ma to 80ma) */
 		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
 				1 << 5);
+		state->operational_mode = AU8522_SUSPEND_MODE;
 	}
 	return 0;
 }
 
-static int au8522_reset(struct v4l2_subdev *sd, u32 val)
+static int au8522_s_video_routing(struct v4l2_subdev *sd,
+					u32 input, u32 output, u32 config)
 {
 	struct au8522_state *state = to_state(sd);
 
-	state->operational_mode = AU8522_ANALOG_MODE;
-
-	/* Clear out any state associated with the digital side of the
-	   chip, so that when it gets powered back up it won't think
-	   that it is already tuned */
-	state->current_frequency = 0;
+	switch(input) {
+	case AU8522_COMPOSITE_CH1:
+	case AU8522_SVIDEO_CH13:
+	case AU8522_COMPOSITE_CH4_SIF:
+		state->vid_input = input;
+		break;
+	default:
+		printk(KERN_ERR "au8522 mode not currently supported\n");
+		return -EINVAL;
+	}
 
-	au8522_writereg(state, 0xa4, 1 << 5);
+	if (state->operational_mode == AU8522_ANALOG_MODE)
+		au8522_video_set(state);
 
 	return 0;
 }
 
-static int au8522_s_video_routing(struct v4l2_subdev *sd,
-					u32 input, u32 output, u32 config)
+static int au8522_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
 	struct au8522_state *state = to_state(sd);
 
-	au8522_reset(sd, 0);
-
-	if (input == AU8522_COMPOSITE_CH1) {
-		au8522_setup_cvbs_mode(state);
-	} else if (input == AU8522_SVIDEO_CH13) {
-		au8522_setup_svideo_mode(state);
-	} else if (input == AU8522_COMPOSITE_CH4_SIF) {
-		au8522_setup_cvbs_tuner_mode(state);
-	} else {
-		printk(KERN_ERR "au8522 mode not currently supported\n");
+	if ((std & (V4L2_STD_PAL_M | V4L2_STD_NTSC_M)) == 0)
 		return -EINVAL;
-	}
+
+	state->std = std;
+
+	if (state->operational_mode == AU8522_ANALOG_MODE)
+		au8522_video_set(state);
+
 	return 0;
 }
 
@@ -598,7 +654,12 @@ static int au8522_s_audio_routing(struct v4l2_subdev *sd,
 					u32 input, u32 output, u32 config)
 {
 	struct au8522_state *state = to_state(sd);
-	set_audio_input(state, input);
+
+	state->aud_input = input;
+
+	if (state->operational_mode == AU8522_ANALOG_MODE)
+		set_audio_input(state);
+
 	return 0;
 }
 
@@ -629,7 +690,6 @@ static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 
 static const struct v4l2_subdev_core_ops au8522_core_ops = {
 	.log_status = v4l2_ctrl_subdev_log_status,
-	.reset = au8522_reset,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.g_register = au8522_g_register,
 	.s_register = au8522_s_register,
@@ -647,6 +707,7 @@ static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
 static const struct v4l2_subdev_video_ops au8522_video_ops = {
 	.s_routing = au8522_s_video_routing,
 	.s_stream = au8522_s_stream,
+	.s_std = au8522_s_std,
 };
 
 static const struct v4l2_subdev_ops au8522_ops = {
@@ -729,6 +790,7 @@ static int au8522_probe(struct i2c_client *client,
 	}
 
 	state->c = client;
+	state->std = V4L2_STD_NTSC_M;
 	state->vid_input = AU8522_COMPOSITE_CH1;
 	state->aud_input = AU8522_AUDIO_NONE;
 	state->id = 8522;

+ 2 - 0
drivers/media/dvb-frontends/au8522_priv.h

@@ -37,6 +37,7 @@
 
 #define AU8522_ANALOG_MODE 0
 #define AU8522_DIGITAL_MODE 1
+#define AU8522_SUSPEND_MODE 2
 
 struct au8522_state {
 	struct i2c_client *c;
@@ -347,6 +348,7 @@ int au8522_led_ctrl(struct au8522_state *state, int led);
 /* Format control 2 */
 #define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_AUTODETECT	0x00
 #define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC		0x01
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_PAL_M		0x02
 
 
 #define AU8522_INPUT_CONTROL_REG081H_ATSC               	0xC4

+ 6 - 0
drivers/media/dvb-frontends/cxd2820r.h

@@ -52,6 +52,12 @@ struct cxd2820r_config {
 	 */
 	u8 ts_mode;
 
+	/* TS clock inverted.
+	 * Default: 0
+	 * Values: 0, 1
+	 */
+	bool ts_clock_inv;
+
 	/* IF AGC polarity.
 	 * Default: 0
 	 * Values: 0, 1

+ 1 - 0
drivers/media/dvb-frontends/cxd2820r_c.c

@@ -45,6 +45,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
 		{ 0x1008b, 0x07, 0xff },
 		{ 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 },
 		{ 0x10070, priv->cfg.ts_mode, 0xff },
+		{ 0x10071, !priv->cfg.ts_clock_inv << 4, 0x10 },
 	};
 
 	dev_dbg(&priv->i2c->dev, "%s: frequency=%d symbol_rate=%d\n", __func__,

+ 1 - 0
drivers/media/dvb-frontends/cxd2820r_t.c

@@ -46,6 +46,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
 		{ 0x00088, 0x01, 0xff },
 
 		{ 0x00070, priv->cfg.ts_mode, 0xff },
+		{ 0x00071, !priv->cfg.ts_clock_inv << 4, 0x10 },
 		{ 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
 		{ 0x000a5, 0x00, 0x01 },
 		{ 0x00082, 0x20, 0x60 },

+ 1 - 0
drivers/media/dvb-frontends/cxd2820r_t2.c

@@ -47,6 +47,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe)
 		{ 0x02083, 0x0a, 0xff },
 		{ 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 },
 		{ 0x02070, priv->cfg.ts_mode, 0xff },
+		{ 0x02071, !priv->cfg.ts_clock_inv << 6, 0x40 },
 		{ 0x020b5, priv->cfg.spec_inv << 4, 0x10 },
 		{ 0x02567, 0x07, 0x0f },
 		{ 0x02569, 0x03, 0x03 },

+ 12 - 3
drivers/media/dvb-frontends/dib0090.c

@@ -2557,10 +2557,19 @@ static int dib0090_set_params(struct dvb_frontend *fe)
 
 	do {
 		ret = dib0090_tune(fe);
-		if (ret != FE_CALLBACK_TIME_NEVER)
-			msleep(ret / 10);
-		else
+		if (ret == FE_CALLBACK_TIME_NEVER)
 			break;
+
+		/*
+		 * Despite dib0090_tune returns time at a 0.1 ms range,
+		 * the actual sleep time depends on CONFIG_HZ. The worse case
+		 * is when CONFIG_HZ=100. In such case, the minimum granularity
+		 * is 10ms. On some real field tests, the tuner sometimes don't
+		 * lock when this timer is lower than 10ms. So, enforce a 10ms
+		 * granularity and use usleep_range() instead of msleep().
+		 */
+		ret = 10 * (ret + 99)/100;
+		usleep_range(ret * 1000, (ret + 1) * 1000);
 	} while (state->tune_state != CT_TUNER_STOP);
 
 	return 0;

+ 1 - 4
drivers/media/dvb-frontends/dib7000m.c

@@ -1041,10 +1041,7 @@ static int dib7000m_tune(struct dvb_frontend *demod)
 	u16 value;
 
 	// we are already tuned - just resuming from suspend
-	if (ch != NULL)
-		dib7000m_set_channel(state, ch, 0);
-	else
-		return -EINVAL;
+	dib7000m_set_channel(state, ch, 0);
 
 	// restart demod
 	ret |= dib7000m_write_word(state, 898, 0x4000);

+ 401 - 32
drivers/media/dvb-frontends/dib7000p.c

@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
+#include <asm/div64.h>
 
 #include "dvb_math.h"
 #include "dvb_frontend.h"
@@ -72,6 +73,12 @@ struct dib7000p_state {
 	struct mutex i2c_buffer_lock;
 
 	u8 input_mode_mpeg;
+
+	/* for DVBv5 stats */
+	s64 old_ucb;
+	unsigned long per_jiffies_stats;
+	unsigned long ber_jiffies_stats;
+	unsigned long get_stats_time;
 };
 
 enum dib7000p_power_mode {
@@ -401,7 +408,7 @@ static int dib7000p_sad_calib(struct dib7000p_state *state)
 	return 0;
 }
 
-int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
+static int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
 {
 	struct dib7000p_state *state = demod->demodulator_priv;
 	if (value > 4095)
@@ -409,9 +416,8 @@ int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
 	state->wbd_ref = value;
 	return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
 }
-EXPORT_SYMBOL(dib7000p_set_wbd_ref);
 
-int dib7000p_get_agc_values(struct dvb_frontend *fe,
+static int dib7000p_get_agc_values(struct dvb_frontend *fe,
 		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
@@ -427,14 +433,12 @@ int dib7000p_get_agc_values(struct dvb_frontend *fe,
 
 	return 0;
 }
-EXPORT_SYMBOL(dib7000p_get_agc_values);
 
-int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
+static int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
 	return dib7000p_write_word(state, 108,  v);
 }
-EXPORT_SYMBOL(dib7000p_set_agc1_min);
 
 static void dib7000p_reset_pll(struct dib7000p_state *state)
 {
@@ -478,7 +482,7 @@ static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
 	return internal;
 }
 
-int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
+static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
 	u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
@@ -513,7 +517,6 @@ int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config
 	}
 	return -EIO;
 }
-EXPORT_SYMBOL(dib7000p_update_pll);
 
 static int dib7000p_reset_gpio(struct dib7000p_state *st)
 {
@@ -546,12 +549,11 @@ static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
 	return 0;
 }
 
-int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
+static int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
 {
 	struct dib7000p_state *state = demod->demodulator_priv;
 	return dib7000p_cfg_gpio(state, num, dir, val);
 }
-EXPORT_SYMBOL(dib7000p_set_gpio);
 
 static u16 dib7000p_defaults[] = {
 	// auto search configuration
@@ -636,6 +638,8 @@ static u16 dib7000p_defaults[] = {
 	0,
 };
 
+static void dib7000p_reset_stats(struct dvb_frontend *fe);
+
 static int dib7000p_demod_reset(struct dib7000p_state *state)
 {
 	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
@@ -934,7 +938,7 @@ static void dib7000p_update_timf(struct dib7000p_state *state)
 
 }
 
-u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
+static u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
 	switch (op) {
@@ -950,7 +954,6 @@ u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
 	dib7000p_set_bandwidth(state, state->current_bandwidth);
 	return state->timf;
 }
-EXPORT_SYMBOL(dib7000p_ctrl_timf);
 
 static void dib7000p_set_channel(struct dib7000p_state *state,
 				 struct dtv_frontend_properties *ch, u8 seq)
@@ -1360,6 +1363,9 @@ static int dib7000p_tune(struct dvb_frontend *demod)
 		dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
 
 	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
+
+	dib7000p_reset_stats(demod);
+
 	return 0;
 }
 
@@ -1552,6 +1558,8 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe)
 	return ret;
 }
 
+static int dib7000p_get_stats(struct dvb_frontend *fe, fe_status_t stat);
+
 static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
@@ -1570,6 +1578,8 @@ static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
 	if ((lock & 0x0038) == 0x38)
 		*stat |= FE_HAS_LOCK;
 
+	dib7000p_get_stats(fe, *stat);
+
 	return 0;
 }
 
@@ -1595,7 +1605,7 @@ static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength
 	return 0;
 }
 
-static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
+static u32 dib7000p_get_snr(struct dvb_frontend *fe)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
 	u16 val;
@@ -1625,10 +1635,351 @@ static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
 	else
 		result -= intlog10(2) * 10 * noise_exp - 100;
 
+	return result;
+}
+
+static int dib7000p_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	u32 result;
+
+	result = dib7000p_get_snr(fe);
+
 	*snr = result / ((1 << 24) / 10);
 	return 0;
 }
 
+static void dib7000p_reset_stats(struct dvb_frontend *demod)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
+	u32 ucb;
+
+	memset(&c->strength, 0, sizeof(c->strength));
+	memset(&c->cnr, 0, sizeof(c->cnr));
+	memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
+	memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
+	memset(&c->block_error, 0, sizeof(c->block_error));
+
+	c->strength.len = 1;
+	c->cnr.len = 1;
+	c->block_error.len = 1;
+	c->block_count.len = 1;
+	c->post_bit_error.len = 1;
+	c->post_bit_count.len = 1;
+
+	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+	c->strength.stat[0].uvalue = 0;
+
+	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+	dib7000p_read_unc_blocks(demod, &ucb);
+
+	state->old_ucb = ucb;
+	state->ber_jiffies_stats = 0;
+	state->per_jiffies_stats = 0;
+}
+
+struct linear_segments {
+	unsigned x;
+	signed y;
+};
+
+/*
+ * Table to estimate signal strength in dBm.
+ * This table should be empirically determinated by measuring the signal
+ * strength generated by a RF generator directly connected into
+ * a device.
+ * This table was determinated by measuring the signal strength generated
+ * by a DTA-2111 RF generator directly connected into a dib7000p device
+ * (a Hauppauge Nova-TD stick), using a good quality 3 meters length
+ * RC6 cable and good RC6 connectors, connected directly to antenna 1.
+ * As the minimum output power of DTA-2111 is -31dBm, a 16 dBm attenuator
+ * were used, for the lower power values.
+ * The real value can actually be on other devices, or even at the
+ * second antena input, depending on several factors, like if LNA
+ * is enabled or not, if diversity is enabled, type of connectors, etc.
+ * Yet, it is better to use this measure in dB than a random non-linear
+ * percentage value, especially for antenna adjustments.
+ * On my tests, the precision of the measure using this table is about
+ * 0.5 dB, with sounds reasonable enough to adjust antennas.
+ */
+#define DB_OFFSET 131000
+
+static struct linear_segments strength_to_db_table[] = {
+	{ 63630, DB_OFFSET - 20500},
+	{ 62273, DB_OFFSET - 21000},
+	{ 60162, DB_OFFSET - 22000},
+	{ 58730, DB_OFFSET - 23000},
+	{ 58294, DB_OFFSET - 24000},
+	{ 57778, DB_OFFSET - 25000},
+	{ 57320, DB_OFFSET - 26000},
+	{ 56779, DB_OFFSET - 27000},
+	{ 56293, DB_OFFSET - 28000},
+	{ 55724, DB_OFFSET - 29000},
+	{ 55145, DB_OFFSET - 30000},
+	{ 54680, DB_OFFSET - 31000},
+	{ 54293, DB_OFFSET - 32000},
+	{ 53813, DB_OFFSET - 33000},
+	{ 53427, DB_OFFSET - 34000},
+	{ 52981, DB_OFFSET - 35000},
+
+	{ 52636, DB_OFFSET - 36000},
+	{ 52014, DB_OFFSET - 37000},
+	{ 51674, DB_OFFSET - 38000},
+	{ 50692, DB_OFFSET - 39000},
+	{ 49824, DB_OFFSET - 40000},
+	{ 49052, DB_OFFSET - 41000},
+	{ 48436, DB_OFFSET - 42000},
+	{ 47836, DB_OFFSET - 43000},
+	{ 47368, DB_OFFSET - 44000},
+	{ 46468, DB_OFFSET - 45000},
+	{ 45597, DB_OFFSET - 46000},
+	{ 44586, DB_OFFSET - 47000},
+	{ 43667, DB_OFFSET - 48000},
+	{ 42673, DB_OFFSET - 49000},
+	{ 41816, DB_OFFSET - 50000},
+	{ 40876, DB_OFFSET - 51000},
+	{     0,      0},
+};
+
+static u32 interpolate_value(u32 value, struct linear_segments *segments,
+			     unsigned len)
+{
+	u64 tmp64;
+	u32 dx;
+	s32 dy;
+	int i, ret;
+
+	if (value >= segments[0].x)
+		return segments[0].y;
+	if (value < segments[len-1].x)
+		return segments[len-1].y;
+
+	for (i = 1; i < len - 1; i++) {
+		/* If value is identical, no need to interpolate */
+		if (value == segments[i].x)
+			return segments[i].y;
+		if (value > segments[i].x)
+			break;
+	}
+
+	/* Linear interpolation between the two (x,y) points */
+	dy = segments[i - 1].y - segments[i].y;
+	dx = segments[i - 1].x - segments[i].x;
+
+	tmp64 = value - segments[i].x;
+	tmp64 *= dy;
+	do_div(tmp64, dx);
+	ret = segments[i].y + tmp64;
+
+	return ret;
+}
+
+/* FIXME: may require changes - this one was borrowed from dib8000 */
+static u32 dib7000p_get_time_us(struct dvb_frontend *demod, int layer)
+{
+	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
+	u64 time_us, tmp64;
+	u32 tmp, denom;
+	int guard, rate_num, rate_denum = 1, bits_per_symbol;
+	int interleaving = 0, fft_div;
+
+	switch (c->guard_interval) {
+	case GUARD_INTERVAL_1_4:
+		guard = 4;
+		break;
+	case GUARD_INTERVAL_1_8:
+		guard = 8;
+		break;
+	case GUARD_INTERVAL_1_16:
+		guard = 16;
+		break;
+	default:
+	case GUARD_INTERVAL_1_32:
+		guard = 32;
+		break;
+	}
+
+	switch (c->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		fft_div = 4;
+		break;
+	case TRANSMISSION_MODE_4K:
+		fft_div = 2;
+		break;
+	default:
+	case TRANSMISSION_MODE_8K:
+		fft_div = 1;
+		break;
+	}
+
+	switch (c->modulation) {
+	case DQPSK:
+	case QPSK:
+		bits_per_symbol = 2;
+		break;
+	case QAM_16:
+		bits_per_symbol = 4;
+		break;
+	default:
+	case QAM_64:
+		bits_per_symbol = 6;
+		break;
+	}
+
+	switch ((c->hierarchy == 0 || 1 == 1) ? c->code_rate_HP : c->code_rate_LP) {
+	case FEC_1_2:
+		rate_num = 1;
+		rate_denum = 2;
+		break;
+	case FEC_2_3:
+		rate_num = 2;
+		rate_denum = 3;
+		break;
+	case FEC_3_4:
+		rate_num = 3;
+		rate_denum = 4;
+		break;
+	case FEC_5_6:
+		rate_num = 5;
+		rate_denum = 6;
+		break;
+	default:
+	case FEC_7_8:
+		rate_num = 7;
+		rate_denum = 8;
+		break;
+	}
+
+	interleaving = interleaving;
+
+	denom = bits_per_symbol * rate_num * fft_div * 384;
+
+	/* If calculus gets wrong, wait for 1s for the next stats */
+	if (!denom)
+		return 0;
+
+	/* Estimate the period for the total bit rate */
+	time_us = rate_denum * (1008 * 1562500L);
+	tmp64 = time_us;
+	do_div(tmp64, guard);
+	time_us = time_us + tmp64;
+	time_us += denom / 2;
+	do_div(time_us, denom);
+
+	tmp = 1008 * 96 * interleaving;
+	time_us += tmp + tmp / guard;
+
+	return time_us;
+}
+
+static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
+	int i;
+	int show_per_stats = 0;
+	u32 time_us = 0, val, snr;
+	u64 blocks, ucb;
+	s32 db;
+	u16 strength;
+
+	/* Get Signal strength */
+	dib7000p_read_signal_strength(demod, &strength);
+	val = strength;
+	db = interpolate_value(val,
+			       strength_to_db_table,
+			       ARRAY_SIZE(strength_to_db_table)) - DB_OFFSET;
+	c->strength.stat[0].svalue = db;
+
+	/* UCB/BER/CNR measures require lock */
+	if (!(stat & FE_HAS_LOCK)) {
+		c->cnr.len = 1;
+		c->block_count.len = 1;
+		c->block_error.len = 1;
+		c->post_bit_error.len = 1;
+		c->post_bit_count.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		return 0;
+	}
+
+	/* Check if time for stats was elapsed */
+	if (time_after(jiffies, state->per_jiffies_stats)) {
+		state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
+
+		/* Get SNR */
+		snr = dib7000p_get_snr(demod);
+		if (snr)
+			snr = (1000L * snr) >> 24;
+		else
+			snr = 0;
+		c->cnr.stat[0].svalue = snr;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+
+		/* Get UCB measures */
+		dib7000p_read_unc_blocks(demod, &val);
+		ucb = val - state->old_ucb;
+		if (val < state->old_ucb)
+			ucb += 0x100000000LL;
+
+		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->block_error.stat[0].uvalue = ucb;
+
+		/* Estimate the number of packets based on bitrate */
+		if (!time_us)
+			time_us = dib7000p_get_time_us(demod, -1);
+
+		if (time_us) {
+			blocks = 1250000ULL * 1000000ULL;
+			do_div(blocks, time_us * 8 * 204);
+			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->block_count.stat[0].uvalue += blocks;
+		}
+
+		show_per_stats = 1;
+	}
+
+	/* Get post-BER measures */
+	if (time_after(jiffies, state->ber_jiffies_stats)) {
+		time_us = dib7000p_get_time_us(demod, -1);
+		state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
+
+		dprintk("Next all layers stats available in %u us.", time_us);
+
+		dib7000p_read_ber(demod, &val);
+		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_error.stat[0].uvalue += val;
+
+		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_count.stat[0].uvalue += 100000000;
+	}
+
+	/* Get PER measures */
+	if (show_per_stats) {
+		dib7000p_read_unc_blocks(demod, &val);
+
+		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->block_error.stat[0].uvalue += val;
+
+		time_us = dib7000p_get_time_us(demod, i);
+		if (time_us) {
+			blocks = 1250000ULL * 1000000ULL;
+			do_div(blocks, time_us * 8 * 204);
+			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->block_count.stat[0].uvalue += blocks;
+		}
+	}
+	return 0;
+}
+
 static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
 {
 	tune->min_delay_ms = 1000;
@@ -1643,7 +1994,7 @@ static void dib7000p_release(struct dvb_frontend *demod)
 	kfree(st);
 }
 
-int dib7000pc_detection(struct i2c_adapter *i2c_adap)
+static int dib7000pc_detection(struct i2c_adapter *i2c_adap)
 {
 	u8 *tx, *rx;
 	struct i2c_msg msg[2] = {
@@ -1688,16 +2039,14 @@ rx_memory_error:
 	kfree(tx);
 	return ret;
 }
-EXPORT_SYMBOL(dib7000pc_detection);
 
-struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
+static struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
 {
 	struct dib7000p_state *st = demod->demodulator_priv;
 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
 }
-EXPORT_SYMBOL(dib7000p_get_i2c_master);
 
-int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
 	u16 val = dib7000p_read_word(state, 235) & 0xffef;
@@ -1705,17 +2054,15 @@ int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
 	dprintk("PID filter enabled %d", onoff);
 	return dib7000p_write_word(state, 235, val);
 }
-EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
 
-int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
 	dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
 	return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
 }
-EXPORT_SYMBOL(dib7000p_pid_filter);
 
-int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
+static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
 {
 	struct dib7000p_state *dpst;
 	int k = 0;
@@ -1774,7 +2121,6 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
 	kfree(dpst);
 	return 0;
 }
-EXPORT_SYMBOL(dib7000p_i2c_enumeration);
 
 static const s32 lut_1000ln_mant[] = {
 	6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
@@ -2032,12 +2378,11 @@ static struct i2c_algorithm dib7090_tuner_xfer_algo = {
 	.functionality = dib7000p_i2c_func,
 };
 
-struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
+static struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
 {
 	struct dib7000p_state *st = fe->demodulator_priv;
 	return &st->dib7090_tuner_adap;
 }
-EXPORT_SYMBOL(dib7090_get_i2c_tuner);
 
 static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
 {
@@ -2329,7 +2674,7 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
 	return ret;
 }
 
-int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
+static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
 	u16 en_cur_state;
@@ -2352,15 +2697,13 @@ int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
 
 	return 0;
 }
-EXPORT_SYMBOL(dib7090_tuner_sleep);
 
-int dib7090_get_adc_power(struct dvb_frontend *fe)
+static int dib7090_get_adc_power(struct dvb_frontend *fe)
 {
 	return dib7000p_get_adc_power(fe);
 }
-EXPORT_SYMBOL(dib7090_get_adc_power);
 
-int dib7090_slave_reset(struct dvb_frontend *fe)
+static int dib7090_slave_reset(struct dvb_frontend *fe)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
 	u16 reg;
@@ -2371,10 +2714,9 @@ int dib7090_slave_reset(struct dvb_frontend *fe)
 	dib7000p_write_word(state, 1032, 0xffff);
 	return 0;
 }
-EXPORT_SYMBOL(dib7090_slave_reset);
 
 static struct dvb_frontend_ops dib7000p_ops;
-struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
+static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
 {
 	struct dvb_frontend *demod;
 	struct dib7000p_state *st;
@@ -2423,6 +2765,8 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
 
 	dib7000p_demod_reset(st);
 
+	dib7000p_reset_stats(demod);
+
 	if (st->version == SOC7090) {
 		dib7090_set_output_mode(demod, st->cfg.output_mode);
 		dib7090_set_diversity_in(demod, 0);
@@ -2434,6 +2778,31 @@ error:
 	kfree(st);
 	return NULL;
 }
+
+void *dib7000p_attach(struct dib7000p_ops *ops)
+{
+	if (!ops)
+		return NULL;
+
+	ops->slave_reset = dib7090_slave_reset;
+	ops->get_adc_power = dib7090_get_adc_power;
+	ops->dib7000pc_detection = dib7000pc_detection;
+	ops->get_i2c_tuner = dib7090_get_i2c_tuner;
+	ops->tuner_sleep = dib7090_tuner_sleep;
+	ops->init = dib7000p_init;
+	ops->set_agc1_min = dib7000p_set_agc1_min;
+	ops->set_gpio = dib7000p_set_gpio;
+	ops->i2c_enumeration = dib7000p_i2c_enumeration;
+	ops->pid_filter = dib7000p_pid_filter;
+	ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl;
+	ops->get_i2c_master = dib7000p_get_i2c_master;
+	ops->update_pll = dib7000p_update_pll;
+	ops->ctrl_timf = dib7000p_ctrl_timf;
+	ops->get_agc_values = dib7000p_get_agc_values;
+	ops->set_wbd_ref = dib7000p_set_wbd_ref;
+
+	return ops;
+}
 EXPORT_SYMBOL(dib7000p_attach);
 
 static struct dvb_frontend_ops dib7000p_ops = {

+ 22 - 109
drivers/media/dvb-frontends/dib7000p.h

@@ -46,121 +46,34 @@ struct dib7000p_config {
 
 #define DEFAULT_DIB7000P_I2C_ADDRESS 18
 
-#if IS_ENABLED(CONFIG_DVB_DIB7000P)
-extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
-extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
-extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
-extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
-extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
-extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
-extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw);
-extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf);
-extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff);
-extern int dib7090_get_adc_power(struct dvb_frontend *fe);
-extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe);
-extern int dib7090_slave_reset(struct dvb_frontend *fe);
-extern int dib7000p_get_agc_values(struct dvb_frontend *fe,
+struct dib7000p_ops {
+	int (*set_wbd_ref)(struct dvb_frontend *demod, u16 value);
+	int (*get_agc_values)(struct dvb_frontend *fe,
 		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd);
-extern int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v);
-#else
-static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-
-static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7090_get_adc_power(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
+	int (*set_agc1_min)(struct dvb_frontend *fe, u16 v);
+	int (*update_pll)(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw);
+	int (*set_gpio)(struct dvb_frontend *demod, u8 num, u8 dir, u8 val);
+	u32 (*ctrl_timf)(struct dvb_frontend *fe, u8 op, u32 timf);
+	int (*dib7000pc_detection)(struct i2c_adapter *i2c_adap);
+	struct i2c_adapter *(*get_i2c_master)(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating);
+	int (*pid_filter_ctrl)(struct dvb_frontend *fe, u8 onoff);
+	int (*pid_filter)(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff);
+	int (*i2c_enumeration)(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
+	struct i2c_adapter *(*get_i2c_tuner)(struct dvb_frontend *fe);
+	int (*tuner_sleep)(struct dvb_frontend *fe, int onoff);
+	int (*get_adc_power)(struct dvb_frontend *fe);
+	int (*slave_reset)(struct dvb_frontend *fe);
+	struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+};
 
-static inline struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
+#if IS_ENABLED(CONFIG_DVB_DIB7000P)
+void *dib7000p_attach(struct dib7000p_ops *ops);
+#else
+static inline void *dib7000p_attach(struct dib7000p_ops *ops)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
-
-static inline int dib7090_slave_reset(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_get_agc_values(struct dvb_frontend *fe,
-		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
 #endif
 
 #endif

+ 389 - 343
drivers/media/dvb-frontends/dib8000.c

@@ -115,7 +115,7 @@ struct dib8000_state {
 	u16 found_guard;
 	u8 subchannel;
 	u8 symbol_duration;
-	u32 timeout;
+	unsigned long timeout;
 	u8 longest_intlv_layer;
 	u16 output_mode;
 
@@ -588,8 +588,8 @@ static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_s
 		break;
 
 	case DIBX000_ADC_OFF:	// leave the VBG voltage on
-		reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
-		reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+		reg_907 = (1 << 13) | (1 << 12);
+		reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1);
 		break;
 
 	case DIBX000_VBG_ENABLE:
@@ -656,7 +656,7 @@ static int dib8000_sad_calib(struct dib8000_state *state)
 	return 0;
 }
 
-int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	if (value > 4095)
@@ -664,7 +664,6 @@ int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
 	state->wbd_ref = value;
 	return dib8000_write_word(state, 106, value);
 }
-EXPORT_SYMBOL(dib8000_set_wbd_ref);
 
 static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
 {
@@ -739,7 +738,7 @@ static void dib8000_reset_pll(struct dib8000_state *state)
 	dib8000_reset_pll_common(state, pll);
 }
 
-int dib8000_update_pll(struct dvb_frontend *fe,
+static int dib8000_update_pll(struct dvb_frontend *fe,
 		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
@@ -815,8 +814,6 @@ int dib8000_update_pll(struct dvb_frontend *fe,
 
 	return 0;
 }
-EXPORT_SYMBOL(dib8000_update_pll);
-
 
 static int dib8000_reset_gpio(struct dib8000_state *st)
 {
@@ -849,13 +846,12 @@ static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
 	return 0;
 }
 
-int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	return dib8000_cfg_gpio(state, num, dir, val);
 }
 
-EXPORT_SYMBOL(dib8000_set_gpio);
 static const u16 dib8000_defaults[] = {
 	/* auto search configuration - lock0 by default waiting
 	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
@@ -1054,6 +1050,7 @@ static int dib8000_reset(struct dvb_frontend *fe)
 	dib8000_write_word(state, 770, 0xffff);
 	dib8000_write_word(state, 771, 0xffff);
 	dib8000_write_word(state, 772, 0xfffc);
+	dib8000_write_word(state, 898, 0x000c);	/* restart sad */
 	if (state->revision == 0x8090)
 		dib8000_write_word(state, 1280, 0x0045);
 	else
@@ -1228,20 +1225,19 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
 	return 0;
 }
 
-void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
+static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
 	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
 }
-EXPORT_SYMBOL(dib8000_pwm_agc_reset);
 
 static int dib8000_agc_soft_split(struct dib8000_state *state)
 {
 	u16 agc, split_offset;
 
 	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
-		return FE_CALLBACK_TIME_NEVER;
+		return 0;
 
 	// n_agc_global
 	agc = dib8000_read_word(state, 390);
@@ -1881,14 +1877,13 @@ static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
 	.functionality = dib8096p_i2c_func,
 };
 
-struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
+static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
 {
 	struct dib8000_state *st = fe->demodulator_priv;
 	return &st->dib8096p_tuner_adap;
 }
-EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
 
-int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
+static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	u16 en_cur_state;
@@ -1912,14 +1907,13 @@ int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
 
 	return 0;
 }
-EXPORT_SYMBOL(dib8096p_tuner_sleep);
 
 static const s32 lut_1000ln_mant[] =
 {
 	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
 };
 
-s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
+static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
@@ -1937,9 +1931,8 @@ s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
 	}
 	return val;
 }
-EXPORT_SYMBOL(dib8000_get_adc_power);
 
-int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
+static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	int val = 0;
@@ -1957,7 +1950,6 @@ int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
 
 	return val;
 }
-EXPORT_SYMBOL(dib8090p_get_dc_power);
 
 static void dib8000_update_timf(struct dib8000_state *state)
 {
@@ -1968,7 +1960,7 @@ static void dib8000_update_timf(struct dib8000_state *state)
 	dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
 }
 
-u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
+static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 
@@ -1986,21 +1978,11 @@ u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
 
 	return state->timf;
 }
-EXPORT_SYMBOL(dib8000_ctrl_timf);
 
 static const u16 adc_target_16dB[11] = {
-	(1 << 13) - 825 - 117,
-	(1 << 13) - 837 - 117,
-	(1 << 13) - 811 - 117,
-	(1 << 13) - 766 - 117,
-	(1 << 13) - 737 - 117,
-	(1 << 13) - 693 - 117,
-	(1 << 13) - 648 - 117,
-	(1 << 13) - 619 - 117,
-	(1 << 13) - 575 - 117,
-	(1 << 13) - 531 - 117,
-	(1 << 13) - 501 - 117
+	7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574
 };
+
 static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
 
 static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
@@ -2043,9 +2025,8 @@ static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 ma
 			break;
 	}
 
-	if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1)))
-		time_intlv = c->layer[layer_index].interleaving;
-	else
+	time_intlv = fls(c->layer[layer_index].interleaving);
+	if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
 		time_intlv = 0;
 
 	dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
@@ -2362,6 +2343,9 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq
 	int init_prbs;
 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
 
+	if (autosearching)
+		c->isdbt_partial_reception = 1;
+
 	/* P_mode */
 	dib8000_write_word(state, 10, (seq << 4));
 
@@ -2856,12 +2840,12 @@ static void dib8000_set_sync_wait(struct dib8000_state *state)
 	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
 }
 
-static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
+static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
 {
 	if (mode == SYMBOL_DEPENDENT_ON)
-		return systime() + (delay * state->symbol_duration);
-	else
-		return systime() + delay;
+		delay *= state->symbol_duration;
+
+	return jiffies + usecs_to_jiffies(delay * 100);
 }
 
 static s32 dib8000_get_status(struct dvb_frontend *fe)
@@ -2870,21 +2854,19 @@ static s32 dib8000_get_status(struct dvb_frontend *fe)
 	return state->status;
 }
 
-enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
+static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	return state->tune_state;
 }
-EXPORT_SYMBOL(dib8000_get_tune_state);
 
-int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 
 	state->tune_state = tune_state;
 	return 0;
 }
-EXPORT_SYMBOL(dib8000_set_tune_state);
 
 static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
 {
@@ -3015,8 +2997,8 @@ static int dib8000_tune(struct dvb_frontend *fe)
 	u16 locks, deeper_interleaver = 0, i;
 	int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
 
-	u32 *timeout = &state->timeout;
-	u32 now = systime();
+	unsigned long *timeout = &state->timeout;
+	unsigned long now = jiffies;
 #ifdef DIB8000_AGC_FREEZE
 	u16 agc1, agc2;
 #endif
@@ -3026,318 +3008,327 @@ static int dib8000_tune(struct dvb_frontend *fe)
 
 #if 0
 	if (*tune_state < CT_DEMOD_STOP)
-		dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
+		dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu",
+			state->channel_parameters_set, *tune_state, state->autosearch_state, now);
 #endif
 
 	switch (*tune_state) {
 	case CT_DEMOD_START: /* 30 */
-			dib8000_reset_stats(fe);
+		dib8000_reset_stats(fe);
 
-			if (state->revision == 0x8090)
-				dib8090p_init_sdram(state);
-			state->status = FE_STATUS_TUNE_PENDING;
-			state->channel_parameters_set = is_manual_mode(c);
+		if (state->revision == 0x8090)
+			dib8090p_init_sdram(state);
+		state->status = FE_STATUS_TUNE_PENDING;
+		state->channel_parameters_set = is_manual_mode(c);
 
-			dprintk("Tuning channel on %s search mode",
-				state->channel_parameters_set ? "manual" : "auto");
+		dprintk("Tuning channel on %s search mode",
+			state->channel_parameters_set ? "manual" : "auto");
 
-			dib8000_viterbi_state(state, 0); /* force chan dec in restart */
+		dib8000_viterbi_state(state, 0); /* force chan dec in restart */
 
-			/* Layer monitor */
-			dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
+		/* Layer monitor */
+		dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
 
-			dib8000_set_frequency_offset(state);
-			dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
+		dib8000_set_frequency_offset(state);
+		dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
 
-			if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
+		if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
 #ifdef DIB8000_AGC_FREEZE
-				if (state->revision != 0x8090) {
-					state->agc1_max = dib8000_read_word(state, 108);
-					state->agc1_min = dib8000_read_word(state, 109);
-					state->agc2_max = dib8000_read_word(state, 110);
-					state->agc2_min = dib8000_read_word(state, 111);
-					agc1 = dib8000_read_word(state, 388);
-					agc2 = dib8000_read_word(state, 389);
-					dib8000_write_word(state, 108, agc1);
-					dib8000_write_word(state, 109, agc1);
-					dib8000_write_word(state, 110, agc2);
-					dib8000_write_word(state, 111, agc2);
-				}
-#endif
-				state->autosearch_state = AS_SEARCHING_FFT;
-				state->found_nfft = TRANSMISSION_MODE_AUTO;
-				state->found_guard = GUARD_INTERVAL_AUTO;
-				*tune_state = CT_DEMOD_SEARCH_NEXT;
-			} else { /* we already know the channel struct so TUNE only ! */
-				state->autosearch_state = AS_DONE;
-				*tune_state = CT_DEMOD_STEP_3;
+			if (state->revision != 0x8090) {
+				state->agc1_max = dib8000_read_word(state, 108);
+				state->agc1_min = dib8000_read_word(state, 109);
+				state->agc2_max = dib8000_read_word(state, 110);
+				state->agc2_min = dib8000_read_word(state, 111);
+				agc1 = dib8000_read_word(state, 388);
+				agc2 = dib8000_read_word(state, 389);
+				dib8000_write_word(state, 108, agc1);
+				dib8000_write_word(state, 109, agc1);
+				dib8000_write_word(state, 110, agc2);
+				dib8000_write_word(state, 111, agc2);
 			}
-			state->symbol_duration = dib8000_get_symbol_duration(state);
-			break;
+#endif
+			state->autosearch_state = AS_SEARCHING_FFT;
+			state->found_nfft = TRANSMISSION_MODE_AUTO;
+			state->found_guard = GUARD_INTERVAL_AUTO;
+			*tune_state = CT_DEMOD_SEARCH_NEXT;
+		} else { /* we already know the channel struct so TUNE only ! */
+			state->autosearch_state = AS_DONE;
+			*tune_state = CT_DEMOD_STEP_3;
+		}
+		state->symbol_duration = dib8000_get_symbol_duration(state);
+		break;
 
 	case CT_DEMOD_SEARCH_NEXT: /* 51 */
-			dib8000_autosearch_start(fe);
-			if (state->revision == 0x8090)
-				ret = 50;
-			else
-				ret = 15;
-			*tune_state = CT_DEMOD_STEP_1;
-			break;
+		dib8000_autosearch_start(fe);
+		if (state->revision == 0x8090)
+			ret = 50;
+		else
+			ret = 15;
+		*tune_state = CT_DEMOD_STEP_1;
+		break;
 
 	case CT_DEMOD_STEP_1: /* 31 */
-			switch (dib8000_autosearch_irq(fe)) {
-			case 1: /* fail */
-					state->status = FE_STATUS_TUNE_FAILED;
-					state->autosearch_state = AS_DONE;
-					*tune_state = CT_DEMOD_STOP; /* else we are done here */
-					break;
-			case 2: /* Succes */
-					state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
-					*tune_state = CT_DEMOD_STEP_3;
-					if (state->autosearch_state == AS_SEARCHING_GUARD)
-						*tune_state = CT_DEMOD_STEP_2;
-					else
-						state->autosearch_state = AS_DONE;
-					break;
-			case 3: /* Autosearch FFT max correlation endded */
-					*tune_state = CT_DEMOD_STEP_2;
-					break;
-			}
+		switch (dib8000_autosearch_irq(fe)) {
+		case 1: /* fail */
+			state->status = FE_STATUS_TUNE_FAILED;
+			state->autosearch_state = AS_DONE;
+			*tune_state = CT_DEMOD_STOP; /* else we are done here */
+			break;
+		case 2: /* Succes */
+			state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
+			*tune_state = CT_DEMOD_STEP_3;
+			if (state->autosearch_state == AS_SEARCHING_GUARD)
+				*tune_state = CT_DEMOD_STEP_2;
+			else
+				state->autosearch_state = AS_DONE;
 			break;
+		case 3: /* Autosearch FFT max correlation endded */
+			*tune_state = CT_DEMOD_STEP_2;
+			break;
+		}
+		break;
 
 	case CT_DEMOD_STEP_2:
-			switch (state->autosearch_state) {
-			case AS_SEARCHING_FFT:
-					/* searching for the correct FFT */
-				if (state->revision == 0x8090) {
-					corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
-					corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
-					corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
-				} else {
-					corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
-					corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
-					corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
-				}
-					/* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
+		switch (state->autosearch_state) {
+		case AS_SEARCHING_FFT:
+			/* searching for the correct FFT */
+			if (state->revision == 0x8090) {
+				corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
+				corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
+				corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
+			} else {
+				corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
+				corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
+				corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
+			}
+			/* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
 
-					max_value = 0;
-					for (find_index = 1 ; find_index < 3 ; find_index++) {
-						if (corm[max_value] < corm[find_index])
-							max_value = find_index ;
-					}
+			max_value = 0;
+			for (find_index = 1 ; find_index < 3 ; find_index++) {
+				if (corm[max_value] < corm[find_index])
+					max_value = find_index ;
+			}
 
-					switch (max_value) {
-					case 0:
-							state->found_nfft = TRANSMISSION_MODE_2K;
-							break;
-					case 1:
-							state->found_nfft = TRANSMISSION_MODE_4K;
-							break;
-					case 2:
-					default:
-							state->found_nfft = TRANSMISSION_MODE_8K;
-							break;
-					}
-					/* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
-
-					*tune_state = CT_DEMOD_SEARCH_NEXT;
-					state->autosearch_state = AS_SEARCHING_GUARD;
-					if (state->revision == 0x8090)
-						ret = 50;
-					else
-						ret = 10;
-					break;
-			case AS_SEARCHING_GUARD:
-					/* searching for the correct guard interval */
-					if (state->revision == 0x8090)
-						state->found_guard = dib8000_read_word(state, 572) & 0x3;
-					else
-						state->found_guard = dib8000_read_word(state, 570) & 0x3;
-					/* dprintk("guard interval found=%i", state->found_guard); */
-
-					*tune_state = CT_DEMOD_STEP_3;
-					break;
+			switch (max_value) {
+			case 0:
+				state->found_nfft = TRANSMISSION_MODE_2K;
+				break;
+			case 1:
+				state->found_nfft = TRANSMISSION_MODE_4K;
+				break;
+			case 2:
 			default:
-					/* the demod should never be in this state */
-					state->status = FE_STATUS_TUNE_FAILED;
-					state->autosearch_state = AS_DONE;
-					*tune_state = CT_DEMOD_STOP; /* else we are done here */
-					break;
+				state->found_nfft = TRANSMISSION_MODE_8K;
+				break;
 			}
+			/* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
+
+			*tune_state = CT_DEMOD_SEARCH_NEXT;
+			state->autosearch_state = AS_SEARCHING_GUARD;
+			if (state->revision == 0x8090)
+				ret = 50;
+			else
+				ret = 10;
 			break;
+		case AS_SEARCHING_GUARD:
+			/* searching for the correct guard interval */
+			if (state->revision == 0x8090)
+				state->found_guard = dib8000_read_word(state, 572) & 0x3;
+			else
+				state->found_guard = dib8000_read_word(state, 570) & 0x3;
+			/* dprintk("guard interval found=%i", state->found_guard); */
 
-	case CT_DEMOD_STEP_3: /* 33 */
-			state->symbol_duration = dib8000_get_symbol_duration(state);
-			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
-			dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
-			*tune_state = CT_DEMOD_STEP_4;
+			*tune_state = CT_DEMOD_STEP_3;
 			break;
+		default:
+			/* the demod should never be in this state */
+			state->status = FE_STATUS_TUNE_FAILED;
+			state->autosearch_state = AS_DONE;
+			*tune_state = CT_DEMOD_STOP; /* else we are done here */
+			break;
+		}
+		break;
+
+	case CT_DEMOD_STEP_3: /* 33 */
+		dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
+		dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
+		*tune_state = CT_DEMOD_STEP_4;
+		break;
 
 	case CT_DEMOD_STEP_4: /* (34) */
-			dib8000_demod_restart(state);
+		dib8000_demod_restart(state);
 
-			dib8000_set_sync_wait(state);
-			dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
+		dib8000_set_sync_wait(state);
+		dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
 
-			locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
-			/* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
-			*timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
-			*tune_state = CT_DEMOD_STEP_5;
-			break;
+		locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
+		/* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
+		*timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
+		*tune_state = CT_DEMOD_STEP_5;
+		break;
 
 	case CT_DEMOD_STEP_5: /* (35) */
-			locks = dib8000_read_lock(fe);
-			if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
-				dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
-				if (!state->differential_constellation) {
-					/* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
-					*timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
-					*tune_state = CT_DEMOD_STEP_7;
-				} else {
-					*tune_state = CT_DEMOD_STEP_8;
-				}
-			} else if (now > *timeout) {
-				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+		locks = dib8000_read_lock(fe);
+		if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
+			dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
+			if (!state->differential_constellation) {
+				/* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
+				*timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
+				*tune_state = CT_DEMOD_STEP_7;
+			} else {
+				*tune_state = CT_DEMOD_STEP_8;
 			}
-			break;
+		} else if (time_after(now, *timeout)) {
+			*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+		}
+		break;
 
 	case CT_DEMOD_STEP_6: /* (36)  if there is an input (diversity) */
-			if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
-				/* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */
-				if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
-					*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
-				else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
-					*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
-					dib8000_viterbi_state(state, 1); /* start viterbi chandec */
-					dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
-					state->status = FE_STATUS_TUNE_FAILED;
-				}
-			} else {
+		if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
+			/* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */
+			if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
+				*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
+			else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
+				*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
 				dib8000_viterbi_state(state, 1); /* start viterbi chandec */
 				dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
-				*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
 				state->status = FE_STATUS_TUNE_FAILED;
 			}
-			break;
+		} else {
+			dib8000_viterbi_state(state, 1); /* start viterbi chandec */
+			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+			*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
+			state->status = FE_STATUS_TUNE_FAILED;
+		}
+		break;
 
 	case CT_DEMOD_STEP_7: /* 37 */
-			locks = dib8000_read_lock(fe);
-			if (locks & (1<<10)) { /* lmod4_lock */
-				ret = 14; /* wait for 14 symbols */
-				*tune_state = CT_DEMOD_STEP_8;
-			} else if (now > *timeout)
-				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
-			break;
+		locks = dib8000_read_lock(fe);
+		if (locks & (1<<10)) { /* lmod4_lock */
+			ret = 14; /* wait for 14 symbols */
+			*tune_state = CT_DEMOD_STEP_8;
+		} else if (time_after(now, *timeout))
+			*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+		break;
 
 	case CT_DEMOD_STEP_8: /* 38 */
-			dib8000_viterbi_state(state, 1); /* start viterbi chandec */
-			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
-
-			/* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
-			if (c->isdbt_sb_mode
-			    && c->isdbt_sb_subchannel < 14
-			    && !state->differential_constellation) {
-				state->subchannel = 0;
-				*tune_state = CT_DEMOD_STEP_11;
-			} else {
-				*tune_state = CT_DEMOD_STEP_9;
-				state->status = FE_STATUS_LOCKED;
-			}
-			break;
+		dib8000_viterbi_state(state, 1); /* start viterbi chandec */
+		dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+
+		/* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
+		if (c->isdbt_sb_mode
+		    && c->isdbt_sb_subchannel < 14
+		    && !state->differential_constellation) {
+			state->subchannel = 0;
+			*tune_state = CT_DEMOD_STEP_11;
+		} else {
+			*tune_state = CT_DEMOD_STEP_9;
+			state->status = FE_STATUS_LOCKED;
+		}
+		break;
 
 	case CT_DEMOD_STEP_9: /* 39 */
-			if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
-				/* defines timeout for mpeg lock depending on interleaver length of longest layer */
-				for (i = 0; i < 3; i++) {
-					if (c->layer[i].interleaving >= deeper_interleaver) {
-						dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
-						if (c->layer[i].segment_count > 0) { /* valid layer */
-							deeper_interleaver = c->layer[0].interleaving;
-							state->longest_intlv_layer = i;
-						}
+		if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
+			/* defines timeout for mpeg lock depending on interleaver length of longest layer */
+			for (i = 0; i < 3; i++) {
+				if (c->layer[i].interleaving >= deeper_interleaver) {
+					dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
+					if (c->layer[i].segment_count > 0) { /* valid layer */
+						deeper_interleaver = c->layer[0].interleaving;
+						state->longest_intlv_layer = i;
 					}
 				}
+			}
 
-				if (deeper_interleaver == 0)
-					locks = 2; /* locks is the tmp local variable name */
-				else if (deeper_interleaver == 3)
-					locks = 8;
-				else
-					locks = 2 * deeper_interleaver;
+			if (deeper_interleaver == 0)
+				locks = 2; /* locks is the tmp local variable name */
+			else if (deeper_interleaver == 3)
+				locks = 8;
+			else
+				locks = 2 * deeper_interleaver;
 
-				if (state->diversity_onoff != 0) /* because of diversity sync */
-					locks *= 2;
+			if (state->diversity_onoff != 0) /* because of diversity sync */
+				locks *= 2;
 
-				*timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
-				dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
+			*timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */
+			dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld",
+				deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
 
-				*tune_state = CT_DEMOD_STEP_10;
-			} else
-				*tune_state = CT_DEMOD_STOP;
-			break;
+			*tune_state = CT_DEMOD_STEP_10;
+		} else
+			*tune_state = CT_DEMOD_STOP;
+		break;
 
 	case CT_DEMOD_STEP_10: /* 40 */
-			locks = dib8000_read_lock(fe);
-			if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
-				dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
-				if (c->isdbt_sb_mode
-				    && c->isdbt_sb_subchannel < 14
-				    && !state->differential_constellation)
-					/* signal to the upper layer, that there was a channel found and the parameters can be read */
-					state->status = FE_STATUS_DEMOD_SUCCESS;
-				else
+		locks = dib8000_read_lock(fe);
+		if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
+			dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s",
+				c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
+				c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
+				c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
+			if (c->isdbt_sb_mode
+			    && c->isdbt_sb_subchannel < 14
+			    && !state->differential_constellation)
+				/* signal to the upper layer, that there was a channel found and the parameters can be read */
+				state->status = FE_STATUS_DEMOD_SUCCESS;
+			else
+				state->status = FE_STATUS_DATA_LOCKED;
+			*tune_state = CT_DEMOD_STOP;
+		} else if (time_after(now, *timeout)) {
+			if (c->isdbt_sb_mode
+			    && c->isdbt_sb_subchannel < 14
+			    && !state->differential_constellation) { /* continue to try init prbs autosearch */
+				state->subchannel += 3;
+				*tune_state = CT_DEMOD_STEP_11;
+			} else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
+				if (locks & (0x7 << 5)) {
+					dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s",
+						jiffies_to_msecs(now - *timeout),
+						c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
+						c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
+						c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
+
 					state->status = FE_STATUS_DATA_LOCKED;
+				} else
+					state->status = FE_STATUS_TUNE_FAILED;
 				*tune_state = CT_DEMOD_STOP;
-			} else if (now > *timeout) {
-				if (c->isdbt_sb_mode
-				    && c->isdbt_sb_subchannel < 14
-				    && !state->differential_constellation) { /* continue to try init prbs autosearch */
-					state->subchannel += 3;
-					*tune_state = CT_DEMOD_STEP_11;
-				} else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
-					if (locks & (0x7<<5)) {
-						dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
-						state->status = FE_STATUS_DATA_LOCKED;
-					} else
-						state->status = FE_STATUS_TUNE_FAILED;
-					*tune_state = CT_DEMOD_STOP;
-				}
 			}
-			break;
+		}
+		break;
 
 	case CT_DEMOD_STEP_11:  /* 41 : init prbs autosearch */
-			if (state->subchannel <= 41) {
-				dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
-				*tune_state = CT_DEMOD_STEP_9;
-			} else {
-				*tune_state = CT_DEMOD_STOP;
-				state->status = FE_STATUS_TUNE_FAILED;
-			}
-			break;
+		if (state->subchannel <= 41) {
+			dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
+			*tune_state = CT_DEMOD_STEP_9;
+		} else {
+			*tune_state = CT_DEMOD_STOP;
+			state->status = FE_STATUS_TUNE_FAILED;
+		}
+		break;
 
 	default:
-			break;
+		break;
 	}
 
 	/* tuning is finished - cleanup the demod */
 	switch (*tune_state) {
 	case CT_DEMOD_STOP: /* (42) */
 #ifdef DIB8000_AGC_FREEZE
-			if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
-				dib8000_write_word(state, 108, state->agc1_max);
-				dib8000_write_word(state, 109, state->agc1_min);
-				dib8000_write_word(state, 110, state->agc2_max);
-				dib8000_write_word(state, 111, state->agc2_min);
-				state->agc1_max = 0;
-				state->agc1_min = 0;
-				state->agc2_max = 0;
-				state->agc2_min = 0;
-			}
+		if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
+			dib8000_write_word(state, 108, state->agc1_max);
+			dib8000_write_word(state, 109, state->agc1_min);
+			dib8000_write_word(state, 110, state->agc2_max);
+			dib8000_write_word(state, 111, state->agc2_min);
+			state->agc1_max = 0;
+			state->agc1_min = 0;
+			state->agc2_max = 0;
+			state->agc2_min = 0;
+		}
 #endif
-			ret = FE_CALLBACK_TIME_NEVER;
-			break;
+		ret = 0;
+		break;
 	default:
-			break;
+		break;
 	}
 
 	if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
@@ -3408,7 +3399,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
 	if (!(stat & FE_HAS_SYNC))
 		return 0;
 
-	dprintk("TMCC lock");
+	dprintk("dib8000_get_frontend: TMCC lock");
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
 		if (stat&FE_HAS_SYNC) {
@@ -3444,91 +3435,117 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
 	switch ((val & 0x30) >> 4) {
 	case 1:
 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
+		dprintk("dib8000_get_frontend: transmission mode 2K");
+		break;
+	case 2:
+		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K;
+		dprintk("dib8000_get_frontend: transmission mode 4K");
 		break;
 	case 3:
 	default:
 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+		dprintk("dib8000_get_frontend: transmission mode 8K");
 		break;
 	}
 
 	switch (val & 0x3) {
 	case 0:
 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
-		dprintk("dib8000_get_frontend GI = 1/32 ");
+		dprintk("dib8000_get_frontend: Guard Interval = 1/32 ");
 		break;
 	case 1:
 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
-		dprintk("dib8000_get_frontend GI = 1/16 ");
+		dprintk("dib8000_get_frontend: Guard Interval = 1/16 ");
 		break;
 	case 2:
-		dprintk("dib8000_get_frontend GI = 1/8 ");
+		dprintk("dib8000_get_frontend: Guard Interval = 1/8 ");
 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
 		break;
 	case 3:
-		dprintk("dib8000_get_frontend GI = 1/4 ");
+		dprintk("dib8000_get_frontend: Guard Interval = 1/4 ");
 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
 		break;
 	}
 
 	val = dib8000_read_word(state, 505);
 	fe->dtv_property_cache.isdbt_partial_reception = val & 1;
-	dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
+	dprintk("dib8000_get_frontend: partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
 
 	for (i = 0; i < 3; i++) {
-		val = dib8000_read_word(state, 493 + i);
-		fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
-		dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
+		int show;
+
+		val = dib8000_read_word(state, 493 + i) & 0x0f;
+		fe->dtv_property_cache.layer[i].segment_count = val;
+
+		if (val == 0 || val > 13)
+			show = 0;
+		else
+			show = 1;
+
+		if (show)
+			dprintk("dib8000_get_frontend: Layer %d segments = %d ",
+				i, fe->dtv_property_cache.layer[i].segment_count);
 
 		val = dib8000_read_word(state, 499 + i) & 0x3;
 		/* Interleaving can be 0, 1, 2 or 4 */
 		if (val == 3)
 			val = 4;
 		fe->dtv_property_cache.layer[i].interleaving = val;
-		dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ",
-			i, fe->dtv_property_cache.layer[i].interleaving);
+		if (show)
+			dprintk("dib8000_get_frontend: Layer %d time_intlv = %d ",
+				i, fe->dtv_property_cache.layer[i].interleaving);
 
 		val = dib8000_read_word(state, 481 + i);
 		switch (val & 0x7) {
 		case 1:
 			fe->dtv_property_cache.layer[i].fec = FEC_1_2;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
+			if (show)
+				dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2 ", i);
 			break;
 		case 2:
 			fe->dtv_property_cache.layer[i].fec = FEC_2_3;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
+			if (show)
+				dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3 ", i);
 			break;
 		case 3:
 			fe->dtv_property_cache.layer[i].fec = FEC_3_4;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
+			if (show)
+				dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4 ", i);
 			break;
 		case 5:
 			fe->dtv_property_cache.layer[i].fec = FEC_5_6;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
+			if (show)
+				dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6 ", i);
 			break;
 		default:
 			fe->dtv_property_cache.layer[i].fec = FEC_7_8;
-			dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
+			if (show)
+				dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8 ", i);
 			break;
 		}
 
 		val = dib8000_read_word(state, 487 + i);
 		switch (val & 0x3) {
 		case 0:
-			dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
 			fe->dtv_property_cache.layer[i].modulation = DQPSK;
+			if (show)
+				dprintk("dib8000_get_frontend: Layer %d DQPSK ", i);
 			break;
 		case 1:
 			fe->dtv_property_cache.layer[i].modulation = QPSK;
-			dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
+			if (show)
+				dprintk("dib8000_get_frontend: Layer %d QPSK ", i);
 			break;
 		case 2:
 			fe->dtv_property_cache.layer[i].modulation = QAM_16;
-			dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
+			if (show)
+				dprintk("dib8000_get_frontend: Layer %d QAM16 ", i);
 			break;
 		case 3:
 		default:
-			dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
 			fe->dtv_property_cache.layer[i].modulation = QAM_64;
+			if (show)
+				dprintk("dib8000_get_frontend: Layer %d QAM64 ", i);
 			break;
 		}
 	}
@@ -3554,9 +3571,9 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
-	int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER;
+	int l, i, active, time, time_slave = 0;
 	u8 exit_condition, index_frontend;
-	u32 delay, callback_time;
+	unsigned long delay, callback_time;
 
 	if (c->frequency == 0) {
 		dprintk("dib8000: must at least specify frequency ");
@@ -3608,15 +3625,24 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
 		time = dib8000_agc_startup(state->fe[0]);
 		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
-			if (time == FE_CALLBACK_TIME_NEVER)
+			if (time == 0)
 				time = time_slave;
-			else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
+			else if ((time_slave != 0) && (time_slave > time))
 				time = time_slave;
 		}
-		if (time != FE_CALLBACK_TIME_NEVER)
-			msleep(time / 10);
-		else
+		if (time == 0)
 			break;
+
+		/*
+		 * Despite dib8000_agc_startup returns time at a 0.1 ms range,
+		 * the actual sleep time depends on CONFIG_HZ. The worse case
+		 * is when CONFIG_HZ=100. In such case, the minimum granularity
+		 * is 10ms. On some real field tests, the tuner sometimes don't
+		 * lock when this timer is lower than 10ms. So, enforce a 10ms
+		 * granularity.
+		 */
+		time = 10 * (time + 99)/100;
+		usleep_range(time * 1000, (time + 1) * 1000);
 		exit_condition = 1;
 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
@@ -3631,11 +3657,14 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
 
 	active = 1;
 	do {
-		callback_time = FE_CALLBACK_TIME_NEVER;
+		callback_time = 0;
 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 			delay = dib8000_tune(state->fe[index_frontend]);
-			if (delay != FE_CALLBACK_TIME_NEVER)
-				delay += systime();
+			if (delay != 0) {
+				delay = jiffies + usecs_to_jiffies(100 * delay);
+				if (!callback_time || delay < callback_time)
+					callback_time = delay;
+			}
 
 			/* we are in autosearch */
 			if (state->channel_parameters_set == 0) { /* searching */
@@ -3646,6 +3675,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
 
 					for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
 						if (l != index_frontend) { /* and for all frontend except the successful one */
+							dprintk("Restarting frontend %d\n", l);
 							dib8000_tune_restart_from_demod(state->fe[l]);
 
 							state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
@@ -3664,8 +3694,6 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
 					}
 				}
 			}
-			if (delay < callback_time)
-				callback_time = delay;
 		}
 		/* tuning is done when the master frontend is done (failed or success) */
 		if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
@@ -3681,12 +3709,12 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
 				dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
 		}
 
-		if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
+		if ((active == 1) && (callback_time == 0)) {
 			dprintk("strange callback time something went wrong");
 			active = 0;
 		}
 
-		while ((active == 1) && (systime() < callback_time))
+		while ((active == 1) && (time_before(jiffies, callback_time)))
 			msleep(100);
 	} while (active);
 
@@ -4201,7 +4229,7 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
 	return 0;
 }
 
-int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	u8 index_frontend = 1;
@@ -4217,9 +4245,8 @@ int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_
 	dprintk("too many slave frontend");
 	return -ENOMEM;
 }
-EXPORT_SYMBOL(dib8000_set_slave_frontend);
 
-int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
+static int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	u8 index_frontend = 1;
@@ -4235,9 +4262,8 @@ int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
 	dprintk("no frontend to be removed");
 	return -ENODEV;
 }
-EXPORT_SYMBOL(dib8000_remove_slave_frontend);
 
-struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 
@@ -4245,10 +4271,8 @@ struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int sla
 		return NULL;
 	return state->fe[slave_index];
 }
-EXPORT_SYMBOL(dib8000_get_slave_frontend);
 
-
-int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
+static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
 		u8 default_addr, u8 first_addr, u8 is_dib8096p)
 {
 	int k = 0, ret = 0;
@@ -4325,7 +4349,6 @@ error_memory_read:
 	return ret;
 }
 
-EXPORT_SYMBOL(dib8000_i2c_enumeration);
 static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
 {
 	tune->min_delay_ms = 1000;
@@ -4348,15 +4371,13 @@ static void dib8000_release(struct dvb_frontend *fe)
 	kfree(st);
 }
 
-struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
+static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
 {
 	struct dib8000_state *st = fe->demodulator_priv;
 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
 }
 
-EXPORT_SYMBOL(dib8000_get_i2c_master);
-
-int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
 {
 	struct dib8000_state *st = fe->demodulator_priv;
 	u16 val = dib8000_read_word(st, 299) & 0xffef;
@@ -4365,15 +4386,13 @@ int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
 	dprintk("pid filter enabled %d", onoff);
 	return dib8000_write_word(st, 299, val);
 }
-EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
 
-int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
 {
 	struct dib8000_state *st = fe->demodulator_priv;
 	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
 	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
 }
-EXPORT_SYMBOL(dib8000_pid_filter);
 
 static const struct dvb_frontend_ops dib8000_ops = {
 	.delsys = { SYS_ISDBT },
@@ -4405,12 +4424,12 @@ static const struct dvb_frontend_ops dib8000_ops = {
 	.read_ucblocks = dib8000_read_unc_blocks,
 };
 
-struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
+static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
 {
 	struct dvb_frontend *fe;
 	struct dib8000_state *state;
 
-	dprintk("dib8000_attach");
+	dprintk("dib8000_init");
 
 	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
 	if (state == NULL)
@@ -4467,6 +4486,33 @@ error:
 	return NULL;
 }
 
+void *dib8000_attach(struct dib8000_ops *ops)
+{
+	if (!ops)
+		return NULL;
+
+	ops->pwm_agc_reset = dib8000_pwm_agc_reset;
+	ops->get_dc_power = dib8090p_get_dc_power;
+	ops->set_gpio = dib8000_set_gpio;
+	ops->get_slave_frontend = dib8000_get_slave_frontend;
+	ops->set_tune_state = dib8000_set_tune_state;
+	ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
+	ops->remove_slave_frontend = dib8000_remove_slave_frontend;
+	ops->get_adc_power = dib8000_get_adc_power;
+	ops->update_pll = dib8000_update_pll;
+	ops->tuner_sleep = dib8096p_tuner_sleep;
+	ops->get_tune_state = dib8000_get_tune_state;
+	ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
+	ops->set_slave_frontend = dib8000_set_slave_frontend;
+	ops->pid_filter = dib8000_pid_filter;
+	ops->ctrl_timf = dib8000_ctrl_timf;
+	ops->init = dib8000_init;
+	ops->get_i2c_master = dib8000_get_i2c_master;
+	ops->i2c_enumeration = dib8000_i2c_enumeration;
+	ops->set_wbd_ref = dib8000_set_wbd_ref;
+
+	return ops;
+}
 EXPORT_SYMBOL(dib8000_attach);
 
 MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");

+ 25 - 125
drivers/media/dvb-frontends/dib8000.h

@@ -39,134 +39,34 @@ struct dib8000_config {
 
 #define DEFAULT_DIB8000_I2C_ADDRESS 18
 
-#if IS_ENABLED(CONFIG_DVB_DIB8000)
-extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
-extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
-
-extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
+struct dib8000_ops {
+	int (*set_wbd_ref)(struct dvb_frontend *fe, u16 value);
+	int (*update_pll)(struct dvb_frontend *fe,
+		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio);
+	int (*set_gpio)(struct dvb_frontend *fe, u8 num, u8 dir, u8 val);
+	void (*pwm_agc_reset)(struct dvb_frontend *fe);
+	struct i2c_adapter *(*get_i2c_tuner)(struct dvb_frontend *fe);
+	int (*tuner_sleep)(struct dvb_frontend *fe, int onoff);
+	s32 (*get_adc_power)(struct dvb_frontend *fe, u8 mode);
+	int (*get_dc_power)(struct dvb_frontend *fe, u8 IQ);
+	u32 (*ctrl_timf)(struct dvb_frontend *fe, uint8_t op, uint32_t timf);
+	enum frontend_tune_state (*get_tune_state)(struct dvb_frontend *fe);
+	int (*set_tune_state)(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
+	int (*set_slave_frontend)(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
+	int (*remove_slave_frontend)(struct dvb_frontend *fe);
+	struct dvb_frontend *(*get_slave_frontend)(struct dvb_frontend *fe, int slave_index);
+	int (*i2c_enumeration)(struct i2c_adapter *host, int no_of_demods,
 		u8 default_addr, u8 first_addr, u8 is_dib8096p);
+	struct i2c_adapter *(*get_i2c_master)(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating);
+	int (*pid_filter_ctrl)(struct dvb_frontend *fe, u8 onoff);
+	int (*pid_filter)(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff);
+	struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
+};
 
-extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
-extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value);
-extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff);
-extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
-extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
-extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe);
-extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe);
-extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode);
-extern struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe);
-extern int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff);
-extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ);
-extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
-		uint8_t op, uint32_t timf);
-extern int dib8000_update_pll(struct dvb_frontend *fe,
-		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio);
-extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
-extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe);
-extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
+#if IS_ENABLED(CONFIG_DVB_DIB8000)
+void *dib8000_attach(struct dib8000_ops *ops);
 #else
-static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int dib8000_i2c_enumeration(struct i2c_adapter *host,
-		int no_of_demods, u8 default_addr, u8 first_addr,
-		u8 is_dib8096p)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return CT_SHUTDOWN;
-}
-static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-}
-static inline struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-static inline int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-static inline int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
-		uint8_t op, uint32_t timf)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return 0;
-}
-static inline int dib8000_update_pll(struct dvb_frontend *fe,
-		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+static inline int dib8000_attach(struct dib8000_ops *ops)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;

+ 9 - 4
drivers/media/dvb-frontends/dib9000.c

@@ -1040,13 +1040,18 @@ static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 addres
 	if (address >= 1024 || !state->platform.risc.fw_is_running)
 		return -EINVAL;
 
+	if (len > 18)
+		return -EINVAL;
+
 	/* dprintk( "APB access thru wr fw %d %x", address, attribute); */
 
-	mb[0] = (unsigned short)address;
-	for (i = 0; i < len && i < 20; i += 2)
-		mb[1 + (i / 2)] = (b[i] << 8 | b[i + 1]);
+	mb[0] = (u16)address;
+	for (i = 0; i + 1 < len; i += 2)
+		mb[1 + i / 2] = b[i] << 8 | b[i + 1];
+	if (len & 1)
+		mb[1 + len / 2] = b[len - 1] << 8;
 
-	dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, 1 + len / 2, attribute);
+	dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, (3 + len) / 2, attribute);
 	return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL;
 }
 

+ 109 - 119
drivers/media/dvb-frontends/drx39xyj/drxj.c

@@ -2159,7 +2159,7 @@ int drxj_dap_atomic_read_write_block(struct i2c_device_addr *dev_addr,
 	return 0;
 
 rw_error:
-	return -EIO;
+	return rc;
 
 }
 
@@ -2252,7 +2252,7 @@ static int hi_cfg_command(const struct drx_demod_instance *demod)
 	return 0;
 
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -2363,7 +2363,7 @@ hi_command(struct i2c_device_addr *dev_addr, const struct drxj_hi_cmd *cmd, u16
 	/* if ( powerdown_cmd == true ) */
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -2434,7 +2434,7 @@ static int init_hi(const struct drx_demod_instance *demod)
 	return 0;
 
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -2650,7 +2650,7 @@ static int get_device_capabilities(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -3338,7 +3338,7 @@ ctrl_set_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_o
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*----------------------------------------------------------------------------*/
@@ -3421,7 +3421,7 @@ static int set_mpegtei_handling(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*----------------------------------------------------------------------------*/
@@ -3464,7 +3464,7 @@ static int bit_reverse_mpeg_output(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*----------------------------------------------------------------------------*/
@@ -3508,7 +3508,7 @@ static int set_mpeg_start_width(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*----------------------------------------------------------------------------*/
@@ -3652,7 +3652,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -3854,7 +3854,7 @@ ctrl_uio_write(struct drx_demod_instance *demod, struct drxuio_data *uio_data)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -3969,7 +3969,7 @@ static int smart_ant_init(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 static int scu_command(struct i2c_device_addr *dev_addr, struct drxjscu_cmd *cmd)
@@ -4109,7 +4109,7 @@ static int scu_command(struct i2c_device_addr *dev_addr, struct drxjscu_cmd *cmd
 	return 0;
 
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -4178,7 +4178,7 @@ int drxj_dap_scu_atomic_read_write_block(struct i2c_device_addr *dev_addr, u32 a
 	return 0;
 
 rw_error:
-	return -EIO;
+	return rc;
 
 }
 
@@ -4290,7 +4290,7 @@ static int adc_sync_measurement(struct drx_demod_instance *demod, u16 *count)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -4349,7 +4349,7 @@ static int adc_synchronization(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -4734,7 +4734,7 @@ static int init_agc(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -4831,7 +4831,7 @@ set_frequency(struct drx_demod_instance *demod,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -4879,7 +4879,7 @@ static int get_acc_pkt_err(struct drx_demod_instance *demod, u16 *packet_err)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 #endif
 
@@ -5097,7 +5097,7 @@ set_agc_rf(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -5326,7 +5326,7 @@ set_agc_if(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -5362,7 +5362,7 @@ static int set_iqm_af(struct drx_demod_instance *demod, bool active)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -5470,7 +5470,7 @@ static int power_down_vsb(struct drx_demod_instance *demod, bool primary)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -5686,7 +5686,7 @@ static int set_vsb_leak_n_gain(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -6192,7 +6192,7 @@ static int set_vsb(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -6231,7 +6231,7 @@ static int get_vsb_post_rs_pck_err(struct i2c_device_addr *dev_addr,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -6276,7 +6276,7 @@ static int get_vs_bpost_viterbi_ber(struct i2c_device_addr *dev_addr,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -6321,7 +6321,7 @@ static int get_vsbmer(struct i2c_device_addr *dev_addr, u16 *mer)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 
@@ -6434,7 +6434,7 @@ static int power_down_qam(struct drx_demod_instance *demod, bool primary)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -6646,7 +6646,7 @@ set_qam_measurement(struct drx_demod_instance *demod,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -6881,7 +6881,7 @@ static int set_qam16(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -7116,7 +7116,7 @@ static int set_qam32(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -7351,7 +7351,7 @@ static int set_qam64(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -7586,7 +7586,7 @@ static int set_qam128(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -7821,7 +7821,7 @@ static int set_qam256(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -8650,7 +8650,7 @@ set_qam(struct drx_demod_instance *demod,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -8831,7 +8831,7 @@ static int qam_flip_spec(struct drx_demod_instance *demod, struct drx_channel *c
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 
 }
 
@@ -8984,7 +8984,7 @@ qam64auto(struct drx_demod_instance *demod,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -9068,7 +9068,7 @@ qam256auto(struct drx_demod_instance *demod,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -9273,7 +9273,7 @@ rw_error:
 	/* restore starting value */
 	if (auto_flag)
 		channel->constellation = DRX_CONSTELLATION_AUTO;
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -9344,7 +9344,7 @@ get_qamrs_err_count(struct i2c_device_addr *dev_addr,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -9425,8 +9425,8 @@ static int get_sig_strength(struct drx_demod_instance *demod, u16 *sig_strength)
 		*sig_strength = 0;
 
 	return 0;
-	rw_error:
-	return -EIO;
+rw_error:
+	return rc;
 }
 
 /**
@@ -9643,7 +9643,7 @@ rw_error:
 	p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 	p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 
-	return -EIO;
+	return rc;
 }
 
 #endif /* #ifndef DRXJ_VSB_ONLY */
@@ -9810,7 +9810,7 @@ power_down_atv(struct drx_demod_instance *demod, enum drx_standard standard, boo
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -9840,7 +9840,7 @@ static int power_down_aud(struct drx_demod_instance *demod)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -9874,7 +9874,7 @@ static int set_orx_nsu_aox(struct drx_demod_instance *demod, bool active)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /**
@@ -10398,7 +10398,7 @@ static int ctrl_set_oob(struct drx_demod_instance *demod, struct drxoob *oob_par
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -10638,7 +10638,7 @@ ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel)
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*=============================================================================
@@ -10756,7 +10756,7 @@ ctrl_sig_quality(struct drx_demod_instance *demod,
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -10844,7 +10844,7 @@ ctrl_lock_status(struct drx_demod_instance *demod, enum drx_lock_status *lock_st
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -10941,7 +10941,7 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard)
 rw_error:
 	/* Don't know what the standard is now ... try again */
 	ext_attr->standard = DRX_STANDARD_UNKNOWN;
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -11222,7 +11222,7 @@ ctrl_set_cfg_pre_saw(struct drx_demod_instance *demod, struct drxj_cfg_pre_saw *
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -11303,7 +11303,7 @@ ctrl_set_cfg_afe_gain(struct drx_demod_instance *demod, struct drxj_cfg_afe_gain
 
 	return 0;
 rw_error:
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -11315,6 +11315,7 @@ rw_error:
 static int drx_ctrl_u_code(struct drx_demod_instance *demod,
 		       struct drxu_code_info *mc_info,
 		       enum drxu_code_action action);
+static int drxj_set_lna_state(struct drx_demod_instance *demod, bool state);
 
 /**
 * \fn drxj_open()
@@ -11527,10 +11528,11 @@ static int drxj_open(struct drx_demod_instance *demod)
 	ext_attr->aud_data = drxj_default_aud_data_g;
 
 	demod->my_common_attr->is_opened = true;
+	drxj_set_lna_state(demod, false);
 	return 0;
 rw_error:
 	common_attr->is_opened = false;
-	return -EIO;
+	return rc;
 }
 
 /*============================================================================*/
@@ -11578,7 +11580,7 @@ static int drxj_close(struct drx_demod_instance *demod)
 rw_error:
 	DRX_ATTR_ISOPENED(demod) = false;
 
-	return -EIO;
+	return rc;
 }
 
 /*
@@ -11890,6 +11892,33 @@ release:
 	return rc;
 }
 
+/* caller is expeced to check if lna is supported before enabling */
+static int drxj_set_lna_state(struct drx_demod_instance *demod, bool state)
+{
+	struct drxuio_cfg uio_cfg;
+	struct drxuio_data uio_data;
+	int result;
+
+	uio_cfg.uio = DRX_UIO1;
+	uio_cfg.mode = DRX_UIO_MODE_READWRITE;
+	/* Configure user-I/O #3: enable read/write */
+	result = ctrl_set_uio_cfg(demod, &uio_cfg);
+	if (result) {
+		pr_err("Failed to setup LNA GPIO!\n");
+		return result;
+	}
+
+	uio_data.uio = DRX_UIO1;
+	uio_data.value = state;
+	result = ctrl_uio_write(demod, &uio_data);
+	if (result != 0) {
+		pr_err("Failed to %sable LNA!\n",
+		       state ? "en" : "dis");
+		return result;
+	}
+	return 0;
+}
+
 /*
  * The Linux DVB Driver for Micronas DRX39xx family (drx3933j)
  *
@@ -12040,7 +12069,6 @@ static int drx39xxj_set_frontend(struct dvb_frontend *fe)
 	enum drx_standard standard = DRX_STANDARD_8VSB;
 	struct drx_channel channel;
 	int result;
-	struct drxuio_data uio_data;
 	static const struct drx_channel def_channel = {
 		/* frequency      */ 0,
 		/* bandwidth      */ DRX_BANDWIDTH_6MHZ,
@@ -12125,13 +12153,7 @@ static int drx39xxj_set_frontend(struct dvb_frontend *fe)
 		return -EINVAL;
 	}
 	/* Just for giggles, let's shut off the LNA again.... */
-	uio_data.uio = DRX_UIO1;
-	uio_data.value = false;
-	result = ctrl_uio_write(demod, &uio_data);
-	if (result != 0) {
-		pr_err("Failed to disable LNA!\n");
-		return 0;
-	}
+	drxj_set_lna_state(demod, false);
 
 	/* After set_frontend, except for strength, stats aren't available */
 	p->strength.stat[0].scale = FE_SCALE_RELATIVE;
@@ -12180,21 +12202,28 @@ static int drx39xxj_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 
 static int drx39xxj_init(struct dvb_frontend *fe)
 {
-	/* Bring the demod out of sleep */
-	drx39xxj_set_powerstate(fe, 1);
+	struct drx39xxj_state *state = fe->demodulator_priv;
+	struct drx_demod_instance *demod = state->demod;
+	int rc = 0;
 
-	return 0;
+	if (fe->exit == DVB_FE_DEVICE_RESUME) {
+		/* so drxj_open() does what it needs to do */
+		demod->my_common_attr->is_opened = false;
+		rc = drxj_open(demod);
+		if (rc != 0)
+			pr_err("drx39xxj_init(): DRX open failed rc=%d!\n", rc);
+	} else
+		drx39xxj_set_powerstate(fe, 1);
+
+	return rc;
 }
 
 static int drx39xxj_set_lna(struct dvb_frontend *fe)
 {
-	int result;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct drx39xxj_state *state = fe->demodulator_priv;
 	struct drx_demod_instance *demod = state->demod;
 	struct drxj_data *ext_attr = demod->my_ext_attr;
-	struct drxuio_cfg uio_cfg;
-	struct drxuio_data uio_data;
 
 	if (c->lna) {
 		if (!ext_attr->has_lna) {
@@ -12204,26 +12233,7 @@ static int drx39xxj_set_lna(struct dvb_frontend *fe)
 		}
 	}
 
-	/* Turn off the LNA */
-	uio_cfg.uio = DRX_UIO1;
-	uio_cfg.mode = DRX_UIO_MODE_READWRITE;
-	/* Configure user-I/O #3: enable read/write */
-	result = ctrl_set_uio_cfg(demod, &uio_cfg);
-	if (result) {
-		pr_err("Failed to setup LNA GPIO!\n");
-		return result;
-	}
-
-	uio_data.uio = DRX_UIO1;
-	uio_data.value = c->lna;
-	result = ctrl_uio_write(demod, &uio_data);
-	if (result != 0) {
-		pr_err("Failed to %sable LNA!\n",
-		       c->lna ? "en" : "dis");
-		return result;
-	}
-
-	return 0;
+	return drxj_set_lna_state(demod, c->lna);
 }
 
 static int drx39xxj_get_tune_settings(struct dvb_frontend *fe,
@@ -12238,7 +12248,9 @@ static void drx39xxj_release(struct dvb_frontend *fe)
 	struct drx39xxj_state *state = fe->demodulator_priv;
 	struct drx_demod_instance *demod = state->demod;
 
-	drxj_close(demod);
+	/* if device is removed don't access it */
+	if (fe->exit != DVB_FE_DEVICE_REMOVED)
+		drxj_close(demod);
 
 	kfree(demod->my_ext_attr);
 	kfree(demod->my_common_attr);
@@ -12259,8 +12271,6 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c)
 	struct drxj_data *demod_ext_attr = NULL;
 	struct drx_demod_instance *demod = NULL;
 	struct dtv_frontend_properties *p;
-	struct drxuio_cfg uio_cfg;
-	struct drxuio_data uio_data;
 	int result;
 
 	/* allocate memory for the internal state */
@@ -12272,22 +12282,20 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c)
 	if (demod == NULL)
 		goto error;
 
-	demod_addr = kmalloc(sizeof(struct i2c_device_addr), GFP_KERNEL);
+	demod_addr = kmemdup(&drxj_default_addr_g,
+			     sizeof(struct i2c_device_addr), GFP_KERNEL);
 	if (demod_addr == NULL)
 		goto error;
-	memcpy(demod_addr, &drxj_default_addr_g,
-	       sizeof(struct i2c_device_addr));
 
-	demod_comm_attr = kmalloc(sizeof(struct drx_common_attr), GFP_KERNEL);
+	demod_comm_attr = kmemdup(&drxj_default_comm_attr_g,
+				  sizeof(struct drx_common_attr), GFP_KERNEL);
 	if (demod_comm_attr == NULL)
 		goto error;
-	memcpy(demod_comm_attr, &drxj_default_comm_attr_g,
-	       sizeof(struct drx_common_attr));
 
-	demod_ext_attr = kmalloc(sizeof(struct drxj_data), GFP_KERNEL);
+	demod_ext_attr = kmemdup(&drxj_data_g, sizeof(struct drxj_data),
+				 GFP_KERNEL);
 	if (demod_ext_attr == NULL)
 		goto error;
-	memcpy(demod_ext_attr, &drxj_data_g, sizeof(struct drxj_data));
 
 	/* setup the state */
 	state->i2c = i2c;
@@ -12313,24 +12321,6 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c)
 		goto error;
 	}
 
-	/* Turn off the LNA */
-	uio_cfg.uio = DRX_UIO1;
-	uio_cfg.mode = DRX_UIO_MODE_READWRITE;
-	/* Configure user-I/O #3: enable read/write */
-	result = ctrl_set_uio_cfg(demod, &uio_cfg);
-	if (result) {
-		pr_err("Failed to setup LNA GPIO!\n");
-		goto error;
-	}
-
-	uio_data.uio = DRX_UIO1;
-	uio_data.value = false;
-	result = ctrl_uio_write(demod, &uio_data);
-	if (result != 0) {
-		pr_err("Failed to disable LNA!\n");
-		goto error;
-	}
-
 	/* create dvb_frontend */
 	memcpy(&state->frontend.ops, &drx39xxj_ops,
 	       sizeof(struct dvb_frontend_ops));

+ 0 - 1
drivers/media/dvb-frontends/drxd.h

@@ -69,5 +69,4 @@ struct dvb_frontend *drxd_attach(const struct drxd_config *config,
 }
 #endif
 
-extern int drxd_config_i2c(struct dvb_frontend *, int);
 #endif

+ 1 - 2
drivers/media/dvb-frontends/drxd_hard.c

@@ -2840,7 +2840,7 @@ static int drxd_init(struct dvb_frontend *fe)
 	return err;
 }
 
-int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
+static int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
 {
 	struct drxd_state *state = fe->demodulator_priv;
 
@@ -2849,7 +2849,6 @@ int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
 
 	return DRX_ConfigureI2CBridge(state, onoff);
 }
-EXPORT_SYMBOL(drxd_config_i2c);
 
 static int drxd_get_tune_settings(struct dvb_frontend *fe,
 				  struct dvb_frontend_tune_settings *sets)

+ 83 - 2
drivers/media/dvb-frontends/m88ds3103.c

@@ -879,7 +879,7 @@ static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr)
 		/* SNR(X) dB = 10 * ln(X) / ln(10) dB */
 		tmp = DIV_ROUND_CLOSEST(tmp, 8 * M88DS3103_SNR_ITERATIONS);
 		if (tmp)
-			*snr = 100ul * intlog2(tmp) / intlog2(10);
+			*snr = div_u64((u64) 100 * intlog2(tmp), intlog2(10));
 		else
 			*snr = 0;
 		break;
@@ -908,7 +908,7 @@ static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr)
 		/* SNR(X) dB = 10 * log10(X) dB */
 		if (signal > noise) {
 			tmp = signal / noise;
-			*snr = 100ul * intlog10(tmp) / (1 << 24);
+			*snr = div_u64((u64) 100 * intlog10(tmp), (1 << 24));
 		} else {
 			*snr = 0;
 		}
@@ -926,6 +926,86 @@ err:
 	return ret;
 }
 
+static int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct m88ds3103_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+	unsigned int utmp;
+	u8 buf[3], u8tmp;
+	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		ret = m88ds3103_wr_reg(priv, 0xf9, 0x04);
+		if (ret)
+			goto err;
+
+		ret = m88ds3103_rd_reg(priv, 0xf8, &u8tmp);
+		if (ret)
+			goto err;
+
+		if (!(u8tmp & 0x10)) {
+			u8tmp |= 0x10;
+
+			ret = m88ds3103_rd_regs(priv, 0xf6, buf, 2);
+			if (ret)
+				goto err;
+
+			priv->ber = (buf[1] << 8) | (buf[0] << 0);
+
+			/* restart counters */
+			ret = m88ds3103_wr_reg(priv, 0xf8, u8tmp);
+			if (ret)
+				goto err;
+		}
+		break;
+	case SYS_DVBS2:
+		ret = m88ds3103_rd_regs(priv, 0xd5, buf, 3);
+		if (ret)
+			goto err;
+
+		utmp = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0);
+
+		if (utmp > 3000) {
+			ret = m88ds3103_rd_regs(priv, 0xf7, buf, 2);
+			if (ret)
+				goto err;
+
+			priv->ber = (buf[1] << 8) | (buf[0] << 0);
+
+			/* restart counters */
+			ret = m88ds3103_wr_reg(priv, 0xd1, 0x01);
+			if (ret)
+				goto err;
+
+			ret = m88ds3103_wr_reg(priv, 0xf9, 0x01);
+			if (ret)
+				goto err;
+
+			ret = m88ds3103_wr_reg(priv, 0xf9, 0x00);
+			if (ret)
+				goto err;
+
+			ret = m88ds3103_wr_reg(priv, 0xd1, 0x00);
+			if (ret)
+				goto err;
+		}
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
+				__func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	*ber = priv->ber;
+
+	return 0;
+err:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
 
 static int m88ds3103_set_tone(struct dvb_frontend *fe,
 	fe_sec_tone_mode_t fe_sec_tone_mode)
@@ -1284,6 +1364,7 @@ static struct dvb_frontend_ops m88ds3103_ops = {
 
 	.read_status = m88ds3103_read_status,
 	.read_snr = m88ds3103_read_snr,
+	.read_ber = m88ds3103_read_ber,
 
 	.diseqc_send_master_cmd = m88ds3103_diseqc_send_master_cmd,
 	.diseqc_send_burst = m88ds3103_diseqc_send_burst,

+ 2 - 0
drivers/media/dvb-frontends/m88ds3103_priv.h

@@ -22,6 +22,7 @@
 #include "dvb_math.h"
 #include <linux/firmware.h>
 #include <linux/i2c-mux.h>
+#include <linux/math64.h>
 
 #define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
 #define M88DS3103_MCLK_KHZ 96000
@@ -34,6 +35,7 @@ struct m88ds3103_priv {
 	struct dvb_frontend fe;
 	fe_delivery_system_t delivery_system;
 	fe_status_t fe_status;
+	u32 ber;
 	bool warm; /* FW running */
 	struct i2c_adapter *i2c_adapter;
 };

+ 13 - 22
drivers/media/dvb-frontends/mb86a20s.c

@@ -459,6 +459,9 @@ static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
 				     unsigned layer)
 {
 	int rc;
+	int interleaving[] = {
+		0, 1, 2, 4, 8
+	};
 
 	static unsigned char reg[] = {
 		[0] = 0x88,	/* Layer A */
@@ -475,20 +478,7 @@ static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
 	if (rc < 0)
 		return rc;
 
-	switch ((rc >> 4) & 0x07) {
-	case 1:
-		return GUARD_INTERVAL_1_4;
-	case 2:
-		return GUARD_INTERVAL_1_8;
-	case 3:
-		return GUARD_INTERVAL_1_16;
-	case 4:
-		return GUARD_INTERVAL_1_32;
-
-	default:
-	case 0:
-		return GUARD_INTERVAL_AUTO;
-	}
+	return interleaving[(rc >> 4) & 0x07];
 }
 
 static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
@@ -566,7 +556,7 @@ static u32 isdbt_rate[3][5][4] = {
 
 static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
 				   u32 modulation, u32 forward_error_correction,
-				   u32 interleaving,
+				   u32 guard_interval,
 				   u32 segment)
 {
 	struct mb86a20s_state *state = fe->demodulator_priv;
@@ -574,7 +564,7 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
 	int mod, fec, guard;
 
 	/*
-	 * If modulation/fec/interleaving is not detected, the default is
+	 * If modulation/fec/guard is not detected, the default is
 	 * to consider the lowest bit rate, to avoid taking too long time
 	 * to get BER.
 	 */
@@ -612,7 +602,7 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
 		break;
 	}
 
-	switch (interleaving) {
+	switch (guard_interval) {
 	default:
 	case GUARD_INTERVAL_1_4:
 		guard = 0;
@@ -703,7 +693,7 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe)
 		c->layer[layer].interleaving = rc;
 		mb86a20s_layer_bitrate(fe, layer, c->layer[layer].modulation,
 				       c->layer[layer].fec,
-				       c->layer[layer].interleaving,
+				       c->guard_interval,
 				       c->layer[layer].segment_count);
 	}
 
@@ -721,11 +711,10 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe)
 	rc = mb86a20s_readreg(state, 0x07);
 	if (rc < 0)
 		return rc;
+	c->transmission_mode = TRANSMISSION_MODE_AUTO;
 	if ((rc & 0x60) == 0x20) {
-		switch (rc & 0x0c >> 2) {
-		case 0:
-			c->transmission_mode = TRANSMISSION_MODE_2K;
-			break;
+		/* Only modes 2 and 3 are supported */
+		switch ((rc >> 2) & 0x03) {
 		case 1:
 			c->transmission_mode = TRANSMISSION_MODE_4K;
 			break;
@@ -734,7 +723,9 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe)
 			break;
 		}
 	}
+	c->guard_interval = GUARD_INTERVAL_AUTO;
 	if (!(rc & 0x10)) {
+		/* Guard interval 1/32 is not supported */
 		switch (rc & 0x3) {
 		case 0:
 			c->guard_interval = GUARD_INTERVAL_1_4;

+ 77 - 23
drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c → drivers/media/dvb-frontends/rtl2832_sdr.c

@@ -35,6 +35,10 @@
 #include <linux/jiffies.h>
 #include <linux/math64.h>
 
+static bool rtl2832_sdr_emulated_fmt;
+module_param_named(emulated_formats, rtl2832_sdr_emulated_fmt, bool, 0644);
+MODULE_PARM_DESC(emulated_formats, "enable emulated formats (disappears in future)");
+
 #define MAX_BULK_BUFS            (10)
 #define BULK_BUFFER_SIZE         (128 * 512)
 
@@ -80,15 +84,18 @@ static const struct v4l2_frequency_band bands_fm[] = {
 struct rtl2832_sdr_format {
 	char	*name;
 	u32	pixelformat;
+	u32	buffersize;
 };
 
 static struct rtl2832_sdr_format formats[] = {
 	{
-		.name		= "IQ U8",
-		.pixelformat	=  V4L2_SDR_FMT_CU8,
+		.name		= "Complex U8",
+		.pixelformat	= V4L2_SDR_FMT_CU8,
+		.buffersize	= BULK_BUFFER_SIZE,
 	}, {
-		.name		= "IQ U16LE (emulated)",
+		.name		= "Complex U16LE (emulated)",
 		.pixelformat	= V4L2_SDR_FMT_CU16LE,
+		.buffersize	= BULK_BUFFER_SIZE * 2,
 	},
 };
 
@@ -139,6 +146,8 @@ struct rtl2832_sdr_state {
 
 	unsigned int f_adc, f_tuner;
 	u32 pixelformat;
+	u32 buffersize;
+	unsigned int num_formats;
 
 	/* Controls */
 	struct v4l2_ctrl_handler hdl;
@@ -348,6 +357,7 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
 		/* convert u8 to u16 */
 		unsigned int i;
 		u16 *u16dst = dst;
+
 		for (i = 0; i < src_len; i++)
 			*u16dst++ = (src[i] << 8) | (src[i] >> 0);
 		dst_len = 2 * src_len;
@@ -359,6 +369,7 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
 	if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
 #define MSECS 10000UL
 		unsigned int samples = s->sample - s->sample_measured;
+
 		s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
 		s->sample_measured = s->sample;
 		dev_dbg(&s->udev->dev,
@@ -560,11 +571,13 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s)
 static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
 {
 	unsigned long flags = 0;
+
 	dev_dbg(&s->udev->dev, "%s:\n", __func__);
 
 	spin_lock_irqsave(&s->queued_bufs_lock, flags);
 	while (!list_empty(&s->queued_bufs)) {
 		struct rtl2832_sdr_frame_buf *buf;
+
 		buf = list_entry(s->queued_bufs.next,
 				struct rtl2832_sdr_frame_buf, list);
 		list_del(&buf->list);
@@ -577,6 +590,7 @@ static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
 static void rtl2832_sdr_release_sec(struct dvb_frontend *fe)
 {
 	struct rtl2832_sdr_state *s = fe->sec_priv;
+
 	dev_dbg(&s->udev->dev, "%s:\n", __func__);
 
 	mutex_lock(&s->vb_queue_lock);
@@ -598,6 +612,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh,
 		struct v4l2_capability *cap)
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
+
 	dev_dbg(&s->udev->dev, "%s:\n", __func__);
 
 	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
@@ -615,14 +630,14 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
 		unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
 {
 	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+
 	dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
 
 	/* Need at least 8 buffers */
 	if (vq->num_buffers + *nbuffers < 8)
 		*nbuffers = 8 - vq->num_buffers;
 	*nplanes = 1;
-	/* 2 = max 16-bit sample returned */
-	sizes[0] = PAGE_ALIGN(BULK_BUFFER_SIZE * 2);
+	sizes[0] = PAGE_ALIGN(s->buffersize);
 	dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
 			__func__, *nbuffers, sizes[0]);
 	return 0;
@@ -665,6 +680,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
 	u8 buf[4], u8tmp1, u8tmp2;
 	u64 u64tmp;
 	u32 u32tmp;
+
 	dev_dbg(&s->udev->dev, "%s: f_adc=%u\n", __func__, s->f_adc);
 
 	if (!test_bit(POWER_ON, &s->flags))
@@ -935,7 +951,8 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
 	/*
 	 * bandwidth (Hz)
 	 */
-	bandwidth_auto = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO);
+	bandwidth_auto = v4l2_ctrl_find(&s->hdl,
+					V4L2_CID_RF_TUNER_BANDWIDTH_AUTO);
 	bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH);
 	if (v4l2_ctrl_g_ctrl(bandwidth_auto)) {
 		c->bandwidth_hz = s->f_adc;
@@ -987,6 +1004,7 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
 	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
 	int ret;
+
 	dev_dbg(&s->udev->dev, "%s:\n", __func__);
 
 	if (!s->udev)
@@ -1035,6 +1053,7 @@ err:
 static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
 {
 	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+
 	dev_dbg(&s->udev->dev, "%s:\n", __func__);
 
 	mutex_lock(&s->v4l2_lock);
@@ -1068,6 +1087,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
 		struct v4l2_tuner *v)
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
+
 	dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n",
 			__func__, v->index, v->type);
 
@@ -1094,6 +1114,7 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
 		const struct v4l2_tuner *v)
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
+
 	dev_dbg(&s->udev->dev, "%s:\n", __func__);
 
 	if (v->index > 1)
@@ -1105,6 +1126,7 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
 		struct v4l2_frequency_band *band)
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
+
 	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
 			__func__, band->tuner, band->type, band->index);
 
@@ -1130,6 +1152,7 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 	int ret  = 0;
+
 	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
 			__func__, f->tuner, f->type);
 
@@ -1193,9 +1216,10 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
 		struct v4l2_fmtdesc *f)
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
+
 	dev_dbg(&s->udev->dev, "%s:\n", __func__);
 
-	if (f->index >= NUM_FORMATS)
+	if (f->index >= s->num_formats)
 		return -EINVAL;
 
 	strlcpy(f->description, formats[f->index].name, sizeof(f->description));
@@ -1208,9 +1232,12 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
 		struct v4l2_format *f)
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
+
 	dev_dbg(&s->udev->dev, "%s:\n", __func__);
 
 	f->fmt.sdr.pixelformat = s->pixelformat;
+	f->fmt.sdr.buffersize = s->buffersize;
+
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
 
 	return 0;
@@ -1222,6 +1249,7 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 	struct vb2_queue *q = &s->vb_queue;
 	int i;
+
 	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
 			(char *)&f->fmt.sdr.pixelformat);
 
@@ -1229,15 +1257,19 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
 		return -EBUSY;
 
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
-	for (i = 0; i < NUM_FORMATS; i++) {
+	for (i = 0; i < s->num_formats; i++) {
 		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
-			s->pixelformat = f->fmt.sdr.pixelformat;
+			s->pixelformat = formats[i].pixelformat;
+			s->buffersize = formats[i].buffersize;
+			f->fmt.sdr.buffersize = formats[i].buffersize;
 			return 0;
 		}
 	}
 
-	f->fmt.sdr.pixelformat = formats[0].pixelformat;
 	s->pixelformat = formats[0].pixelformat;
+	s->buffersize = formats[0].buffersize;
+	f->fmt.sdr.pixelformat = formats[0].pixelformat;
+	f->fmt.sdr.buffersize = formats[0].buffersize;
 
 	return 0;
 }
@@ -1247,16 +1279,20 @@ static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 	int i;
+
 	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
 			(char *)&f->fmt.sdr.pixelformat);
 
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
-	for (i = 0; i < NUM_FORMATS; i++) {
-		if (formats[i].pixelformat == f->fmt.sdr.pixelformat)
+	for (i = 0; i < s->num_formats; i++) {
+		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+			f->fmt.sdr.buffersize = formats[i].buffersize;
 			return 0;
+		}
 	}
 
 	f->fmt.sdr.pixelformat = formats[0].pixelformat;
+	f->fmt.sdr.buffersize = formats[0].buffersize;
 
 	return 0;
 }
@@ -1316,8 +1352,9 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
 	struct dvb_frontend *fe = s->fe;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
+
 	dev_dbg(&s->udev->dev,
-			"%s: id=%d name=%s val=%d min=%d max=%d step=%d\n",
+			"%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
 			__func__, ctrl->id, ctrl->name, ctrl->val,
 			ctrl->minimum, ctrl->maximum, ctrl->step);
 
@@ -1327,14 +1364,16 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
 		/* TODO: these controls should be moved to tuner drivers */
 		if (s->bandwidth_auto->val) {
 			/* Round towards the closest legal value */
-			s32 val = s->f_adc + s->bandwidth->step / 2;
+			s32 val = s->f_adc + div_u64(s->bandwidth->step, 2);
 			u32 offset;
-			val = clamp(val, s->bandwidth->minimum, s->bandwidth->maximum);
+
+			val = clamp_t(s32, val, s->bandwidth->minimum,
+				      s->bandwidth->maximum);
 			offset = val - s->bandwidth->minimum;
-			offset = s->bandwidth->step * (offset / s->bandwidth->step);
+			offset = s->bandwidth->step *
+				div_u64(offset, s->bandwidth->step);
 			s->bandwidth->val = s->bandwidth->minimum + offset;
 		}
-
 		c->bandwidth_hz = s->bandwidth->val;
 
 		if (!test_bit(POWER_ON, &s->flags))
@@ -1390,7 +1429,11 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
 	s->cfg = cfg;
 	s->f_adc = bands_adc[0].rangelow;
 	s->f_tuner = bands_fm[0].rangelow;
-	s->pixelformat =  V4L2_SDR_FMT_CU8;
+	s->pixelformat = formats[0].pixelformat;
+	s->buffersize = formats[0].buffersize;
+	s->num_formats = NUM_FORMATS;
+	if (rtl2832_sdr_emulated_fmt == false)
+		s->num_formats -= 1;
 
 	mutex_init(&s->v4l2_lock);
 	mutex_init(&s->vb_queue_lock);
@@ -1420,15 +1463,24 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
 		break;
 	case RTL2832_TUNER_R820T:
 		v4l2_ctrl_handler_init(&s->hdl, 2);
-		s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
-		s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 0, 8000000, 100000, 0);
+		s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops,
+						      V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+						      0, 1, 1, 1);
+		s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops,
+						 V4L2_CID_RF_TUNER_BANDWIDTH,
+						 0, 8000000, 100000, 0);
 		v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
 		break;
 	case RTL2832_TUNER_FC0012:
 	case RTL2832_TUNER_FC0013:
 		v4l2_ctrl_handler_init(&s->hdl, 2);
-		s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
-		s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 6000000, 8000000, 1000000, 6000000);
+		s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops,
+						      V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+						      0, 1, 1, 1);
+		s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops,
+						 V4L2_CID_RF_TUNER_BANDWIDTH,
+						 6000000, 8000000, 1000000,
+						 6000000);
 		v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
 		break;
 	default:
@@ -1448,7 +1500,6 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
 	s->vdev = rtl2832_sdr_template;
 	s->vdev.queue = &s->vb_queue;
 	s->vdev.queue->lock = &s->vb_queue_lock;
-	set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev.flags);
 	video_set_drvdata(&s->vdev, s);
 
 	/* Register the v4l2_device structure */
@@ -1480,6 +1531,9 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
 
 	dev_info(&s->i2c->dev, "%s: Realtek RTL2832 SDR attached\n",
 			KBUILD_MODNAME);
+	dev_notice(&s->udev->dev,
+			"%s: SDR API is still slightly experimental and functionality changes may follow\n",
+			KBUILD_MODNAME);
 	return fe;
 
 err_unregister_v4l2_dev:

+ 0 - 0
drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h → drivers/media/dvb-frontends/rtl2832_sdr.h


+ 1040 - 0
drivers/media/dvb-frontends/si2165.c

@@ -0,0 +1,1040 @@
+/*
+    Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+
+    Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+
+    References:
+    http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "si2165_priv.h"
+#include "si2165.h"
+
+/* Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx
+ * uses 16 MHz xtal */
+
+/* Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx
+ * uses 24 MHz clock provided by tuner */
+
+struct si2165_state {
+	struct i2c_adapter *i2c;
+
+	struct dvb_frontend frontend;
+
+	struct si2165_config config;
+
+	/* chip revision */
+	u8 revcode;
+	/* chip type */
+	u8 chip_type;
+
+	/* calculated by xtal and div settings */
+	u32 fvco_hz;
+	u32 sys_clk;
+	u32 adc_clk;
+
+	bool has_dvbc;
+	bool has_dvbt;
+	bool firmware_loaded;
+};
+
+#define DEBUG_OTHER	0x01
+#define DEBUG_I2C_WRITE	0x02
+#define DEBUG_I2C_READ	0x04
+#define DEBUG_REG_READ	0x08
+#define DEBUG_REG_WRITE	0x10
+#define DEBUG_FW_LOAD	0x20
+
+static int debug = 0x00;
+
+#define dprintk(args...) \
+	do { \
+		if (debug & DEBUG_OTHER) \
+			printk(KERN_DEBUG "si2165: " args); \
+	} while (0)
+
+#define deb_i2c_write(args...) \
+	do { \
+		if (debug & DEBUG_I2C_WRITE) \
+			printk(KERN_DEBUG "si2165: i2c write: " args); \
+	} while (0)
+
+#define deb_i2c_read(args...) \
+	do { \
+		if (debug & DEBUG_I2C_READ) \
+			printk(KERN_DEBUG "si2165: i2c read: " args); \
+	} while (0)
+
+#define deb_readreg(args...) \
+	do { \
+		if (debug & DEBUG_REG_READ) \
+			printk(KERN_DEBUG "si2165: reg read: " args); \
+	} while (0)
+
+#define deb_writereg(args...) \
+	do { \
+		if (debug & DEBUG_REG_WRITE) \
+			printk(KERN_DEBUG "si2165: reg write: " args); \
+	} while (0)
+
+#define deb_fw_load(args...) \
+	do { \
+		if (debug & DEBUG_FW_LOAD) \
+			printk(KERN_DEBUG "si2165: fw load: " args); \
+	} while (0)
+
+static int si2165_write(struct si2165_state *state, const u16 reg,
+		       const u8 *src, const int count)
+{
+	int ret;
+	struct i2c_msg msg;
+	u8 buf[2 + 4]; /* write a maximum of 4 bytes of data */
+
+	if (count + 2 > sizeof(buf)) {
+		dev_warn(&state->i2c->dev,
+			  "%s: i2c wr reg=%04x: count=%d is too big!\n",
+			  KBUILD_MODNAME, reg, count);
+		return -EINVAL;
+	}
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+	memcpy(buf + 2, src, count);
+
+	msg.addr = state->config.i2c_addr;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = count + 2;
+
+	if (debug & DEBUG_I2C_WRITE)
+		deb_i2c_write("reg: 0x%04x, data: %*ph\n", reg, count, src);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1) {
+		dev_err(&state->i2c->dev, "%s: ret == %d\n", __func__, ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int si2165_read(struct si2165_state *state,
+		       const u16 reg, u8 *val, const int count)
+{
+	int ret;
+	u8 reg_buf[] = { reg >> 8, reg & 0xff };
+	struct i2c_msg msg[] = {
+		{ .addr = state->config.i2c_addr,
+		  .flags = 0, .buf = reg_buf, .len = 2 },
+		{ .addr = state->config.i2c_addr,
+		  .flags = I2C_M_RD, .buf = val, .len = count },
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		dev_err(&state->i2c->dev, "%s: error (addr %02x reg %04x error (ret == %i)\n",
+			__func__, state->config.i2c_addr, reg, ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EREMOTEIO;
+	}
+
+	if (debug & DEBUG_I2C_READ)
+		deb_i2c_read("reg: 0x%04x, data: %*ph\n", reg, count, val);
+
+	return 0;
+}
+
+static int si2165_readreg8(struct si2165_state *state,
+		       const u16 reg, u8 *val)
+{
+	int ret;
+
+	ret = si2165_read(state, reg, val, 1);
+	deb_readreg("R(0x%04x)=0x%02x\n", reg, *val);
+	return ret;
+}
+
+static int si2165_readreg16(struct si2165_state *state,
+		       const u16 reg, u16 *val)
+{
+	u8 buf[2];
+
+	int ret = si2165_read(state, reg, buf, 2);
+	*val = buf[0] | buf[1] << 8;
+	deb_readreg("R(0x%04x)=0x%04x\n", reg, *val);
+	return ret;
+}
+
+static int si2165_writereg8(struct si2165_state *state, const u16 reg, u8 val)
+{
+	return si2165_write(state, reg, &val, 1);
+}
+
+static int si2165_writereg16(struct si2165_state *state, const u16 reg, u16 val)
+{
+	u8 buf[2] = { val & 0xff, (val >> 8) & 0xff };
+
+	return si2165_write(state, reg, buf, 2);
+}
+
+static int si2165_writereg24(struct si2165_state *state, const u16 reg, u32 val)
+{
+	u8 buf[3] = { val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff };
+
+	return si2165_write(state, reg, buf, 3);
+}
+
+static int si2165_writereg32(struct si2165_state *state, const u16 reg, u32 val)
+{
+	u8 buf[4] = {
+		val & 0xff,
+		(val >> 8) & 0xff,
+		(val >> 16) & 0xff,
+		(val >> 24) & 0xff
+	};
+	return si2165_write(state, reg, buf, 4);
+}
+
+static int si2165_writereg_mask8(struct si2165_state *state, const u16 reg,
+				 u8 val, u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	if (mask != 0xff) {
+		ret = si2165_readreg8(state, reg, &tmp);
+		if (ret < 0)
+			goto err;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	ret = si2165_writereg8(state, reg, val);
+err:
+	return ret;
+}
+
+static int si2165_get_tune_settings(struct dvb_frontend *fe,
+				    struct dvb_frontend_tune_settings *s)
+{
+	s->min_delay_ms = 1000;
+	return 0;
+}
+
+static int si2165_init_pll(struct si2165_state *state)
+{
+	u32 ref_freq_Hz = state->config.ref_freq_Hz;
+	u8 divr = 1; /* 1..7 */
+	u8 divp = 1; /* only 1 or 4 */
+	u8 divn = 56; /* 1..63 */
+	u8 divm = 8;
+	u8 divl = 12;
+	u8 buf[4];
+
+	/* hardcoded values can be deleted if calculation is verified
+	 * or it yields the same values as the windows driver */
+	switch (ref_freq_Hz) {
+	case 16000000u:
+		divn = 56;
+		break;
+	case 24000000u:
+		divr = 2;
+		divp = 4;
+		divn = 19;
+		break;
+	default:
+		/* ref_freq / divr must be between 4 and 16 MHz */
+		if (ref_freq_Hz > 16000000u)
+			divr = 2;
+
+		/* now select divn and divp such that
+		 * fvco is in 1624..1824 MHz */
+		if (1624000000u * divr > ref_freq_Hz * 2u * 63u)
+			divp = 4;
+
+		/* is this already correct regarding rounding? */
+		divn = 1624000000u * divr / (ref_freq_Hz * 2u * divp);
+		break;
+	}
+
+	/* adc_clk and sys_clk depend on xtal and pll settings */
+	state->fvco_hz = ref_freq_Hz / divr
+			* 2u * divn * divp;
+	state->adc_clk = state->fvco_hz / (divm * 4u);
+	state->sys_clk = state->fvco_hz / (divl * 2u);
+
+	/* write pll registers 0x00a0..0x00a3 at once */
+	buf[0] = divl;
+	buf[1] = divm;
+	buf[2] = (divn & 0x3f) | ((divp == 1) ? 0x40 : 0x00) | 0x80;
+	buf[3] = divr;
+	return si2165_write(state, 0x00a0, buf, 4);
+}
+
+static int si2165_adjust_pll_divl(struct si2165_state *state, u8 divl)
+{
+	state->sys_clk = state->fvco_hz / (divl * 2u);
+	return si2165_writereg8(state, 0x00a0, divl); /* pll_divl */
+}
+
+static u32 si2165_get_fe_clk(struct si2165_state *state)
+{
+	/* assume Oversampling mode Ovr4 is used */
+	return state->adc_clk;
+}
+
+static bool si2165_wait_init_done(struct si2165_state *state)
+{
+	int ret = -EINVAL;
+	u8 val = 0;
+	int i;
+
+	for (i = 0; i < 3; ++i) {
+		si2165_readreg8(state, 0x0054, &val);
+		if (val == 0x01)
+			return 0;
+		usleep_range(1000, 50000);
+	}
+	dev_err(&state->i2c->dev, "%s: init_done was not set\n",
+		KBUILD_MODNAME);
+	return ret;
+}
+
+static int si2165_upload_firmware_block(struct si2165_state *state,
+	const u8 *data, u32 len, u32 *poffset, u32 block_count)
+{
+	int ret;
+	u8 buf_ctrl[4] = { 0x00, 0x00, 0x00, 0xc0 };
+	u8 wordcount;
+	u32 cur_block = 0;
+	u32 offset = poffset ? *poffset : 0;
+
+	if (len < 4)
+		return -EINVAL;
+	if (len % 4 != 0)
+		return -EINVAL;
+
+	deb_fw_load("si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n",
+				len, offset, block_count);
+	while (offset+12 <= len && cur_block < block_count) {
+		deb_fw_load("si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+					len, offset, cur_block, block_count);
+		wordcount = data[offset];
+		if (wordcount < 1 || data[offset+1] ||
+		    data[offset+2] || data[offset+3]) {
+			dev_warn(&state->i2c->dev,
+				 "%s: bad fw data[0..3] = %*ph\n",
+				KBUILD_MODNAME, 4, data);
+			return -EINVAL;
+		}
+
+		if (offset + 8 + wordcount * 4 > len) {
+			dev_warn(&state->i2c->dev,
+				 "%s: len is too small for block len=%d, wordcount=%d\n",
+				KBUILD_MODNAME, len, wordcount);
+			return -EINVAL;
+		}
+
+		buf_ctrl[0] = wordcount - 1;
+
+		ret = si2165_write(state, 0x0364, buf_ctrl, 4);
+		if (ret < 0)
+			goto error;
+		ret = si2165_write(state, 0x0368, data+offset+4, 4);
+		if (ret < 0)
+			goto error;
+
+		offset += 8;
+
+		while (wordcount > 0) {
+			ret = si2165_write(state, 0x36c, data+offset, 4);
+			if (ret < 0)
+				goto error;
+			wordcount--;
+			offset += 4;
+		}
+		cur_block++;
+	}
+
+	deb_fw_load("si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+				len, offset, cur_block, block_count);
+
+	if (poffset)
+		*poffset = offset;
+
+	deb_fw_load("si2165_upload_firmware_block returned offset=0x%x\n",
+				offset);
+
+	return 0;
+error:
+	return ret;
+}
+
+static int si2165_upload_firmware(struct si2165_state *state)
+{
+	/* int ret; */
+	u8 val[3];
+	u16 val16;
+	int ret;
+
+	const struct firmware *fw = NULL;
+	u8 *fw_file = SI2165_FIRMWARE;
+	const u8 *data;
+	u32 len;
+	u32 offset;
+	u8 patch_version;
+	u8 block_count;
+	u16 crc_expected;
+
+	/* request the firmware, this will block and timeout */
+	ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
+	if (ret) {
+		dev_warn(&state->i2c->dev, "%s: firmare file '%s' not found\n",
+				KBUILD_MODNAME, fw_file);
+		goto error;
+	}
+
+	data = fw->data;
+	len = fw->size;
+
+	dev_info(&state->i2c->dev, "%s: downloading firmware from file '%s' size=%d\n",
+			KBUILD_MODNAME, fw_file, len);
+
+	if (len % 4 != 0) {
+		dev_warn(&state->i2c->dev, "%s: firmware size is not multiple of 4\n",
+				KBUILD_MODNAME);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/* check header (8 bytes) */
+	if (len < 8) {
+		dev_warn(&state->i2c->dev, "%s: firmware header is missing\n",
+				KBUILD_MODNAME);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	if (data[0] != 1 || data[1] != 0) {
+		dev_warn(&state->i2c->dev, "%s: firmware file version is wrong\n",
+				KBUILD_MODNAME);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	patch_version = data[2];
+	block_count = data[4];
+	crc_expected = data[7] << 8 | data[6];
+
+	/* start uploading fw */
+	/* boot/wdog status */
+	ret = si2165_writereg8(state, 0x0341, 0x00);
+	if (ret < 0)
+		goto error;
+	/* reset */
+	ret = si2165_writereg8(state, 0x00c0, 0x00);
+	if (ret < 0)
+		goto error;
+	/* boot/wdog status */
+	ret = si2165_readreg8(state, 0x0341, val);
+	if (ret < 0)
+		goto error;
+
+	/* enable reset on error */
+	ret = si2165_readreg8(state, 0x035c, val);
+	if (ret < 0)
+		goto error;
+	ret = si2165_readreg8(state, 0x035c, val);
+	if (ret < 0)
+		goto error;
+	ret = si2165_writereg8(state, 0x035c, 0x02);
+	if (ret < 0)
+		goto error;
+
+	/* start right after the header */
+	offset = 8;
+
+	dev_info(&state->i2c->dev, "%s: si2165_upload_firmware extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n",
+		KBUILD_MODNAME, patch_version, block_count, crc_expected);
+
+	ret = si2165_upload_firmware_block(state, data, len, &offset, 1);
+	if (ret < 0)
+		goto error;
+
+	ret = si2165_writereg8(state, 0x0344, patch_version);
+	if (ret < 0)
+		goto error;
+
+	/* reset crc */
+	ret = si2165_writereg8(state, 0x0379, 0x01);
+	if (ret)
+		return ret;
+
+	ret = si2165_upload_firmware_block(state, data, len,
+					   &offset, block_count);
+	if (ret < 0) {
+		dev_err(&state->i2c->dev,
+			"%s: firmare could not be uploaded\n",
+			KBUILD_MODNAME);
+		goto error;
+	}
+
+	/* read crc */
+	ret = si2165_readreg16(state, 0x037a, &val16);
+	if (ret)
+		goto error;
+
+	if (val16 != crc_expected) {
+		dev_err(&state->i2c->dev,
+			"%s: firmware crc mismatch %04x != %04x\n",
+			KBUILD_MODNAME, val16, crc_expected);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	ret = si2165_upload_firmware_block(state, data, len, &offset, 5);
+	if (ret)
+		goto error;
+
+	if (len != offset) {
+		dev_err(&state->i2c->dev,
+			"%s: firmare len mismatch %04x != %04x\n",
+			KBUILD_MODNAME, len, offset);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/* reset watchdog error register */
+	ret = si2165_writereg_mask8(state, 0x0341, 0x02, 0x02);
+	if (ret < 0)
+		goto error;
+
+	/* enable reset on error */
+	ret = si2165_writereg_mask8(state, 0x035c, 0x01, 0x01);
+	if (ret < 0)
+		goto error;
+
+	dev_info(&state->i2c->dev, "%s: fw load finished\n", KBUILD_MODNAME);
+
+	ret = 0;
+	state->firmware_loaded = true;
+error:
+	if (fw) {
+		release_firmware(fw);
+		fw = NULL;
+	}
+
+	return ret;
+}
+
+static int si2165_init(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	struct si2165_state *state = fe->demodulator_priv;
+	u8 val;
+	u8 patch_version = 0x00;
+
+	dprintk("%s: called\n", __func__);
+
+	/* powerup */
+	ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
+	if (ret < 0)
+		goto error;
+	/* dsp_clock_enable */
+	ret = si2165_writereg8(state, 0x0104, 0x01);
+	if (ret < 0)
+		goto error;
+	ret = si2165_readreg8(state, 0x0000, &val); /* verify chip_mode */
+	if (ret < 0)
+		goto error;
+	if (val != state->config.chip_mode) {
+		dev_err(&state->i2c->dev, "%s: could not set chip_mode\n",
+			KBUILD_MODNAME);
+		return -EINVAL;
+	}
+
+	/* agc */
+	ret = si2165_writereg8(state, 0x018b, 0x00);
+	if (ret < 0)
+		goto error;
+	ret = si2165_writereg8(state, 0x0190, 0x01);
+	if (ret < 0)
+		goto error;
+	ret = si2165_writereg8(state, 0x0170, 0x00);
+	if (ret < 0)
+		goto error;
+	ret = si2165_writereg8(state, 0x0171, 0x07);
+	if (ret < 0)
+		goto error;
+	/* rssi pad */
+	ret = si2165_writereg8(state, 0x0646, 0x00);
+	if (ret < 0)
+		goto error;
+	ret = si2165_writereg8(state, 0x0641, 0x00);
+	if (ret < 0)
+		goto error;
+
+	ret = si2165_init_pll(state);
+	if (ret < 0)
+		goto error;
+
+	/* enable chip_init */
+	ret = si2165_writereg8(state, 0x0050, 0x01);
+	if (ret < 0)
+		goto error;
+	/* set start_init */
+	ret = si2165_writereg8(state, 0x0096, 0x01);
+	if (ret < 0)
+		goto error;
+	ret = si2165_wait_init_done(state);
+	if (ret < 0)
+		goto error;
+
+	/* disable chip_init */
+	ret = si2165_writereg8(state, 0x0050, 0x00);
+	if (ret < 0)
+		goto error;
+
+	/* ber_pkt */
+	ret = si2165_writereg16(state, 0x0470 , 0x7530);
+	if (ret < 0)
+		goto error;
+
+	ret = si2165_readreg8(state, 0x0344, &patch_version);
+	if (ret < 0)
+		goto error;
+
+	ret = si2165_writereg8(state, 0x00cb, 0x00);
+	if (ret < 0)
+		goto error;
+
+	/* dsp_addr_jump */
+	ret = si2165_writereg32(state, 0x0348, 0xf4000000);
+	if (ret < 0)
+		goto error;
+	/* boot/wdog status */
+	ret = si2165_readreg8(state, 0x0341, &val);
+	if (ret < 0)
+		goto error;
+
+	if (patch_version == 0x00) {
+		ret = si2165_upload_firmware(state);
+		if (ret < 0)
+			goto error;
+	}
+
+	/* write adc values after each reset*/
+	ret = si2165_writereg8(state, 0x012a, 0x46);
+	if (ret < 0)
+		goto error;
+	ret = si2165_writereg8(state, 0x012c, 0x00);
+	if (ret < 0)
+		goto error;
+	ret = si2165_writereg8(state, 0x012e, 0x0a);
+	if (ret < 0)
+		goto error;
+	ret = si2165_writereg8(state, 0x012f, 0xff);
+	if (ret < 0)
+		goto error;
+	ret = si2165_writereg8(state, 0x0123, 0x70);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+error:
+	return ret;
+}
+
+static int si2165_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+	struct si2165_state *state = fe->demodulator_priv;
+
+	/* dsp clock disable */
+	ret = si2165_writereg8(state, 0x0104, 0x00);
+	if (ret < 0)
+		return ret;
+	/* chip mode */
+	ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int si2165_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	int ret;
+	u8 fec_lock = 0;
+	struct si2165_state *state = fe->demodulator_priv;
+
+	if (!state->has_dvbt)
+		return -EINVAL;
+
+	/* check fec_lock */
+	ret = si2165_readreg8(state, 0x4e0, &fec_lock);
+	if (ret < 0)
+		return ret;
+	*status = 0;
+	if (fec_lock & 0x01) {
+		*status |= FE_HAS_SIGNAL;
+		*status |= FE_HAS_CARRIER;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+		*status |= FE_HAS_LOCK;
+	}
+
+	return 0;
+}
+
+static int si2165_set_oversamp(struct si2165_state *state, u32 dvb_rate)
+{
+	u64 oversamp;
+	u32 reg_value;
+
+	oversamp = si2165_get_fe_clk(state);
+	oversamp <<= 23;
+	do_div(oversamp, dvb_rate);
+	reg_value = oversamp & 0x3fffffff;
+
+	/* oversamp, usbdump contained 0x03100000; */
+	return si2165_writereg32(state, 0x00e4, reg_value);
+}
+
+static int si2165_set_if_freq_shift(struct si2165_state *state, u32 IF)
+{
+	u64 if_freq_shift;
+	s32 reg_value = 0;
+	u32 fe_clk = si2165_get_fe_clk(state);
+
+	if_freq_shift = IF;
+	if_freq_shift <<= 29;
+
+	do_div(if_freq_shift, fe_clk);
+	reg_value = (s32)if_freq_shift;
+
+	if (state->config.inversion)
+		reg_value = -reg_value;
+
+	reg_value = reg_value & 0x1fffffff;
+
+	/* if_freq_shift, usbdump contained 0x023ee08f; */
+	return si2165_writereg32(state, 0x00e8, reg_value);
+}
+
+static int si2165_set_parameters(struct dvb_frontend *fe)
+{
+	int ret;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct si2165_state *state = fe->demodulator_priv;
+	u8 val[3];
+	u32 IF;
+	u32 dvb_rate = 0;
+	u16 bw10k;
+
+	dprintk("%s: called\n", __func__);
+
+	if (!fe->ops.tuner_ops.get_if_frequency) {
+		dev_err(&state->i2c->dev,
+			"%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n",
+			KBUILD_MODNAME);
+		return -EINVAL;
+	}
+
+	if (!state->has_dvbt)
+		return -EINVAL;
+
+	if (p->bandwidth_hz > 0) {
+		dvb_rate = p->bandwidth_hz * 8 / 7;
+		bw10k = p->bandwidth_hz / 10000;
+	} else {
+		dvb_rate = 8 * 8 / 7;
+		bw10k = 800;
+	}
+
+	/* standard = DVB-T */
+	ret = si2165_writereg8(state, 0x00ec, 0x01);
+	if (ret < 0)
+		return ret;
+	ret = si2165_adjust_pll_divl(state, 12);
+	if (ret < 0)
+		return ret;
+
+	fe->ops.tuner_ops.get_if_frequency(fe, &IF);
+	ret = si2165_set_if_freq_shift(state, IF);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg8(state, 0x08f8, 0x00);
+	if (ret < 0)
+		return ret;
+	/* ts output config */
+	ret = si2165_writereg8(state, 0x04e4, 0x20);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg16(state, 0x04ef, 0x00fe);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg24(state, 0x04f4, 0x555555);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg8(state, 0x04e5, 0x01);
+	if (ret < 0)
+		return ret;
+	/* bandwidth in 10KHz steps */
+	ret = si2165_writereg16(state, 0x0308, bw10k);
+	if (ret < 0)
+		return ret;
+	ret = si2165_set_oversamp(state, dvb_rate);
+	if (ret < 0)
+		return ret;
+	/* impulsive_noise_remover */
+	ret = si2165_writereg8(state, 0x031c, 0x01);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg8(state, 0x00cb, 0x00);
+	if (ret < 0)
+		return ret;
+	/* agc2 */
+	ret = si2165_writereg8(state, 0x016e, 0x41);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg8(state, 0x016c, 0x0e);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg8(state, 0x016d, 0x10);
+	if (ret < 0)
+		return ret;
+	/* agc */
+	ret = si2165_writereg8(state, 0x015b, 0x03);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg8(state, 0x0150, 0x78);
+	if (ret < 0)
+		return ret;
+	/* agc */
+	ret = si2165_writereg8(state, 0x01a0, 0x78);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg8(state, 0x01c8, 0x68);
+	if (ret < 0)
+		return ret;
+	/* freq_sync_range */
+	ret = si2165_writereg16(state, 0x030c, 0x0064);
+	if (ret < 0)
+		return ret;
+	/* gp_reg0 */
+	ret = si2165_readreg8(state, 0x0387, val);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg8(state, 0x0387, 0x00);
+	if (ret < 0)
+		return ret;
+	/* dsp_addr_jump */
+	ret = si2165_writereg32(state, 0x0348, 0xf4000000);
+	if (ret < 0)
+		return ret;
+
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	/* recalc if_freq_shift if IF might has changed */
+	fe->ops.tuner_ops.get_if_frequency(fe, &IF);
+	ret = si2165_set_if_freq_shift(state, IF);
+	if (ret < 0)
+		return ret;
+
+	/* boot/wdog status */
+	ret = si2165_readreg8(state, 0x0341, val);
+	if (ret < 0)
+		return ret;
+	ret = si2165_writereg8(state, 0x0341, 0x00);
+	if (ret < 0)
+		return ret;
+	/* reset all */
+	ret = si2165_writereg8(state, 0x00c0, 0x00);
+	if (ret < 0)
+		return ret;
+	/* gp_reg0 */
+	ret = si2165_writereg32(state, 0x0384, 0x00000000);
+	if (ret < 0)
+		return ret;
+	/* start_synchro */
+	ret = si2165_writereg8(state, 0x02e0, 0x01);
+	if (ret < 0)
+		return ret;
+	/* boot/wdog status */
+	ret = si2165_readreg8(state, 0x0341, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void si2165_release(struct dvb_frontend *fe)
+{
+	struct si2165_state *state = fe->demodulator_priv;
+
+	dprintk("%s: called\n", __func__);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops si2165_ops = {
+	.info = {
+		.name = "Silicon Labs Si2165",
+		.caps =	FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_32 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 |
+			FE_CAN_QAM_256 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_MUTE_TS |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_RECOVER
+	},
+
+	.get_tune_settings = si2165_get_tune_settings,
+
+	.init = si2165_init,
+	.sleep = si2165_sleep,
+
+	.set_frontend      = si2165_set_parameters,
+	.read_status       = si2165_read_status,
+
+	.release = si2165_release,
+};
+
+struct dvb_frontend *si2165_attach(const struct si2165_config *config,
+				   struct i2c_adapter *i2c)
+{
+	struct si2165_state *state = NULL;
+	int n;
+	int io_ret;
+	u8 val;
+
+	if (config == NULL || i2c == NULL)
+		goto error;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct si2165_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	state->config = *config;
+
+	if (state->config.ref_freq_Hz < 4000000
+	    || state->config.ref_freq_Hz > 27000000) {
+		dev_err(&state->i2c->dev, "%s: ref_freq of %d Hz not supported by this driver\n",
+			 KBUILD_MODNAME, state->config.ref_freq_Hz);
+		goto error;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &si2165_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	/* powerup */
+	io_ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
+	if (io_ret < 0)
+		goto error;
+
+	io_ret = si2165_readreg8(state, 0x0000, &val);
+	if (io_ret < 0)
+		goto error;
+	if (val != state->config.chip_mode)
+		goto error;
+
+	io_ret = si2165_readreg8(state, 0x0023 , &state->revcode);
+	if (io_ret < 0)
+		goto error;
+
+	io_ret = si2165_readreg8(state, 0x0118, &state->chip_type);
+	if (io_ret < 0)
+		goto error;
+
+	/* powerdown */
+	io_ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
+	if (io_ret < 0)
+		goto error;
+
+	dev_info(&state->i2c->dev, "%s: hardware revision 0x%02x, chip type 0x%02x\n",
+		 KBUILD_MODNAME, state->revcode, state->chip_type);
+
+	/* It is a guess that register 0x0118 (chip type?) can be used to
+	 * differ between si2161, si2163 and si2165
+	 * Only si2165 has been tested.
+	 */
+	if (state->revcode == 0x03 && state->chip_type == 0x07) {
+		state->has_dvbt = true;
+		state->has_dvbc = true;
+	} else {
+		dev_err(&state->i2c->dev, "%s: Unsupported chip.\n",
+			KBUILD_MODNAME);
+		goto error;
+	}
+
+	n = 0;
+	if (state->has_dvbt) {
+		state->frontend.ops.delsys[n++] = SYS_DVBT;
+		strlcat(state->frontend.ops.info.name, " DVB-T",
+			sizeof(state->frontend.ops.info.name));
+	}
+	if (state->has_dvbc)
+		dev_warn(&state->i2c->dev, "%s: DVB-C is not yet supported.\n",
+		       KBUILD_MODNAME);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(si2165_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Silicon Labs Si2165 DVB-C/-T Demodulator driver");
+MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(SI2165_FIRMWARE);

+ 62 - 0
drivers/media/dvb-frontends/si2165.h

@@ -0,0 +1,62 @@
+/*
+    Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+
+    Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+
+    References:
+    http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
+*/
+
+#ifndef _DVB_SI2165_H
+#define _DVB_SI2165_H
+
+#include <linux/dvb/frontend.h>
+
+enum {
+	SI2165_MODE_OFF = 0x00,
+	SI2165_MODE_PLL_EXT = 0x20,
+	SI2165_MODE_PLL_XTAL = 0x21
+};
+
+struct si2165_config {
+	/* i2c addr
+	 * possible values: 0x64,0x65,0x66,0x67 */
+	u8 i2c_addr;
+
+	/* external clock or XTAL */
+	u8 chip_mode;
+
+	/* frequency of external clock or xtal in Hz
+	 * possible values: 4000000, 16000000, 20000000, 240000000, 27000000
+	 */
+	u32 ref_freq_Hz;
+
+	/* invert the spectrum */
+	bool inversion;
+};
+
+#if IS_ENABLED(CONFIG_DVB_SI2165)
+struct dvb_frontend *si2165_attach(
+	const struct si2165_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *si2165_attach(
+	const struct si2165_config *config,
+	struct i2c_adapter *i2c)
+{
+	pr_warn("%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_SI2165 */
+
+#endif /* _DVB_SI2165_H */

+ 23 - 0
drivers/media/dvb-frontends/si2165_priv.h

@@ -0,0 +1,23 @@
+/*
+    Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+
+    Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+
+*/
+
+#ifndef _DVB_SI2165_PRIV
+#define _DVB_SI2165_PRIV
+
+#define SI2165_FIRMWARE "dvb-demod-si2165.fw"
+
+#endif /* _DVB_SI2165_PRIV */

+ 104 - 162
drivers/media/dvb-frontends/si2168.c

@@ -95,20 +95,17 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
 	switch (c->delivery_system) {
 	case SYS_DVBT:
-		cmd.args[0] = 0xa0;
-		cmd.args[1] = 0x01;
+		memcpy(cmd.args, "\xa0\x01", 2);
 		cmd.wlen = 2;
 		cmd.rlen = 13;
 		break;
 	case SYS_DVBC_ANNEX_A:
-		cmd.args[0] = 0x90;
-		cmd.args[1] = 0x01;
+		memcpy(cmd.args, "\x90\x01", 2);
 		cmd.wlen = 2;
 		cmd.rlen = 9;
 		break;
 	case SYS_DVBT2:
-		cmd.args[0] = 0x50;
-		cmd.args[1] = 0x01;
+		memcpy(cmd.args, "\x50\x01", 2);
 		cmd.wlen = 2;
 		cmd.rlen = 14;
 		break;
@@ -144,6 +141,15 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
 	s->fe_status = *status;
 
+	if (*status & FE_HAS_LOCK) {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = cmd.args[3] * 1000 / 4;
+	} else {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
+
 	dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n",
 			__func__, *status, cmd.rlen, cmd.args);
 
@@ -243,51 +249,23 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 	if (ret)
 		goto err;
 
-	memcpy(cmd.args, "\x14\x00\x01\x04\x00\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x03\x10\x17\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x02\x10\x15\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
 	memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6);
 	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
 	memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6);
 	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x0b\x10\x88\x13", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
 	memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6);
 	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
@@ -295,124 +273,66 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 	memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6);
 	cmd.args[4] = delivery_system | bandwidth;
 	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x04\x10\x15\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
-	memcpy(cmd.args, "\x14\x00\x05\x10\xa1\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
+	/* set DVB-C symbol rate */
+	if (c->delivery_system == SYS_DVBC_ANNEX_A) {
+		memcpy(cmd.args, "\x14\x00\x02\x11", 4);
+		cmd.args[4] = (c->symbol_rate / 1000) & 0xff;
+		cmd.args[5] = ((c->symbol_rate / 1000) >> 8) & 0xff;
+		cmd.wlen = 6;
+		cmd.rlen = 4;
+		ret = si2168_cmd_execute(s, &cmd);
+		if (ret)
+			goto err;
+	}
 
 	memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6);
 	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
-	memcpy(cmd.args, "\x14\x00\x0d\x10\xd0\x02", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6);
+	memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6);
 	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
 	memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6);
 	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
 	memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x15", 6);
 	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x04\x03\x00\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x03\x03\x00\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x08\x03\x00\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x07\x03\x01\x02", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x06\x03\x00\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x05\x03\x00\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x40", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
-	memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6);
+	memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6);
 	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
-	memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6);
+	memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x00", 6);
 	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
-	cmd.args[0] = 0x85;
+	memcpy(cmd.args, "\x85", 1);
 	cmd.wlen = 1;
 	cmd.rlen = 1;
 	ret = si2168_cmd_execute(s, &cmd);
@@ -432,59 +352,61 @@ static int si2168_init(struct dvb_frontend *fe)
 	struct si2168 *s = fe->demodulator_priv;
 	int ret, len, remaining;
 	const struct firmware *fw = NULL;
-	u8 *fw_file = SI2168_FIRMWARE;
+	u8 *fw_file;
 	const unsigned int i2c_wr_max = 8;
 	struct si2168_cmd cmd;
+	unsigned int chip_id;
 
 	dev_dbg(&s->client->dev, "%s:\n", __func__);
 
-	cmd.args[0] = 0x13;
-	cmd.wlen = 1;
-	cmd.rlen = 0;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
-	cmd.args[0] = 0xc0;
-	cmd.args[1] = 0x12;
-	cmd.args[2] = 0x00;
-	cmd.args[3] = 0x0c;
-	cmd.args[4] = 0x00;
-	cmd.args[5] = 0x0d;
-	cmd.args[6] = 0x16;
-	cmd.args[7] = 0x00;
-	cmd.args[8] = 0x00;
-	cmd.args[9] = 0x00;
-	cmd.args[10] = 0x00;
-	cmd.args[11] = 0x00;
-	cmd.args[12] = 0x00;
+	memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13);
 	cmd.wlen = 13;
 	cmd.rlen = 0;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
-	cmd.args[0] = 0xc0;
-	cmd.args[1] = 0x06;
-	cmd.args[2] = 0x01;
-	cmd.args[3] = 0x0f;
-	cmd.args[4] = 0x00;
-	cmd.args[5] = 0x20;
-	cmd.args[6] = 0x20;
-	cmd.args[7] = 0x01;
+	memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8);
 	cmd.wlen = 8;
 	cmd.rlen = 1;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
-	cmd.args[0] = 0x02;
+	/* query chip revision */
+	memcpy(cmd.args, "\x02", 1);
 	cmd.wlen = 1;
 	cmd.rlen = 13;
 	ret = si2168_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
+	chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 |
+			cmd.args[4] << 0;
+
+	#define SI2168_A20 ('A' << 24 | 68 << 16 | '2' << 8 | '0' << 0)
+	#define SI2168_A30 ('A' << 24 | 68 << 16 | '3' << 8 | '0' << 0)
+	#define SI2168_B40 ('B' << 24 | 68 << 16 | '4' << 8 | '0' << 0)
+
+	switch (chip_id) {
+	case SI2168_A20:
+		fw_file = SI2168_A20_FIRMWARE;
+		break;
+	case SI2168_A30:
+		fw_file = SI2168_A30_FIRMWARE;
+		break;
+	case SI2168_B40:
+		fw_file = SI2168_B40_FIRMWARE;
+		break;
+	default:
+		dev_err(&s->client->dev,
+				"%s: unkown chip version Si21%d-%c%c%c\n",
+				KBUILD_MODNAME, cmd.args[2], cmd.args[1],
+				cmd.args[3], cmd.args[4]);
+		ret = -EINVAL;
+		goto err;
+	}
+
 	/* cold state - try to download firmware */
 	dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
 			KBUILD_MODNAME, si2168_ops.info.name);
@@ -492,9 +414,22 @@ static int si2168_init(struct dvb_frontend *fe)
 	/* request the firmware, this will block and timeout */
 	ret = request_firmware(&fw, fw_file, &s->client->dev);
 	if (ret) {
-		dev_err(&s->client->dev, "%s: firmare file '%s' not found\n",
-				KBUILD_MODNAME, fw_file);
-		goto err;
+		/* fallback mechanism to handle old name for Si2168 B40 fw */
+		if (chip_id == SI2168_B40) {
+			fw_file = SI2168_B40_FIRMWARE_FALLBACK;
+			ret = request_firmware(&fw, fw_file, &s->client->dev);
+		}
+
+		if (ret == 0) {
+			dev_notice(&s->client->dev,
+					"%s: please install firmware file '%s'\n",
+					KBUILD_MODNAME, SI2168_B40_FIRMWARE);
+		} else {
+			dev_err(&s->client->dev,
+					"%s: firmware file '%s' not found\n",
+					KBUILD_MODNAME, fw_file);
+			goto err;
+		}
 	}
 
 	dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
@@ -520,8 +455,7 @@ static int si2168_init(struct dvb_frontend *fe)
 	release_firmware(fw);
 	fw = NULL;
 
-	cmd.args[0] = 0x01;
-	cmd.args[1] = 0x01;
+	memcpy(cmd.args, "\x01\x01", 2);
 	cmd.wlen = 2;
 	cmd.rlen = 1;
 	ret = si2168_cmd_execute(s, &cmd);
@@ -545,12 +479,24 @@ err:
 static int si2168_sleep(struct dvb_frontend *fe)
 {
 	struct si2168 *s = fe->demodulator_priv;
+	int ret;
+	struct si2168_cmd cmd;
 
 	dev_dbg(&s->client->dev, "%s:\n", __func__);
 
 	s->active = false;
 
+	memcpy(cmd.args, "\x13", 1);
+	cmd.wlen = 1;
+	cmd.rlen = 0;
+	ret = si2168_cmd_execute(s, &cmd);
+	if (ret)
+		goto err;
+
 	return 0;
+err:
+	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
 }
 
 static int si2168_get_tune_settings(struct dvb_frontend *fe,
@@ -660,7 +606,6 @@ static int si2168_probe(struct i2c_client *client,
 	struct si2168_config *config = client->dev.platform_data;
 	struct si2168 *s;
 	int ret;
-	struct si2168_cmd cmd;
 
 	dev_dbg(&client->dev, "%s:\n", __func__);
 
@@ -674,18 +619,13 @@ static int si2168_probe(struct i2c_client *client,
 	s->client = client;
 	mutex_init(&s->i2c_mutex);
 
-	/* check if the demod is there */
-	cmd.wlen = 0;
-	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
 	/* create mux i2c adapter for tuner */
 	s->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, s,
 			0, 0, 0, si2168_select, si2168_deselect);
-	if (s->adapter == NULL)
+	if (s->adapter == NULL) {
+		ret = -ENODEV;
 		goto err;
+	}
 
 	/* create dvb_frontend */
 	memcpy(&s->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
@@ -743,4 +683,6 @@ module_i2c_driver(si2168_driver);
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Silicon Labs Si2168 DVB-T/T2/C demodulator driver");
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(SI2168_FIRMWARE);
+MODULE_FIRMWARE(SI2168_A20_FIRMWARE);
+MODULE_FIRMWARE(SI2168_A30_FIRMWARE);
+MODULE_FIRMWARE(SI2168_B40_FIRMWARE);

+ 6 - 3
drivers/media/dvb-frontends/si2168_priv.h

@@ -22,7 +22,10 @@
 #include <linux/firmware.h>
 #include <linux/i2c-mux.h>
 
-#define SI2168_FIRMWARE "dvb-demod-si2168-02.fw"
+#define SI2168_A20_FIRMWARE "dvb-demod-si2168-a20-01.fw"
+#define SI2168_A30_FIRMWARE "dvb-demod-si2168-a30-01.fw"
+#define SI2168_B40_FIRMWARE "dvb-demod-si2168-b40-01.fw"
+#define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw"
 
 /* state struct */
 struct si2168 {
@@ -36,9 +39,9 @@ struct si2168 {
 };
 
 /* firmare command struct */
-#define SI2157_ARGLEN      30
+#define SI2168_ARGLEN      30
 struct si2168_cmd {
-	u8 args[SI2157_ARGLEN];
+	u8 args[SI2168_ARGLEN];
 	unsigned wlen;
 	unsigned rlen;
 };

+ 16 - 26
drivers/media/dvb-frontends/stb6100_cfg.h

@@ -21,17 +21,14 @@
 
 static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	struct tuner_state	t_state;
 	int err = 0;
 
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
 	if (tuner_ops->get_state) {
-		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+		err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+		if (err < 0) {
 			printk("%s: Invalid parameter\n", __func__);
 			return err;
 		}
@@ -42,18 +39,16 @@ static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 
 static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	struct tuner_state	t_state;
 	int err = 0;
 
 	t_state.frequency = frequency;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
+
 	if (tuner_ops->set_state) {
-		if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+		err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+		if (err < 0) {
 			printk("%s: Invalid parameter\n", __func__);
 			return err;
 		}
@@ -68,12 +63,9 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 	struct tuner_state	t_state;
 	int err = 0;
 
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
 	if (tuner_ops->get_state) {
-		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+		err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+		if (err < 0) {
 			printk("%s: Invalid parameter\n", __func__);
 			return err;
 		}
@@ -84,18 +76,16 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 
 static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	struct tuner_state	t_state;
 	int err = 0;
 
 	t_state.bandwidth = bandwidth;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
+
 	if (tuner_ops->set_state) {
-		if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+		err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+		if (err < 0) {
 			printk("%s: Invalid parameter\n", __func__);
 			return err;
 		}

+ 10 - 24
drivers/media/dvb-frontends/stb6100_proc.h

@@ -19,15 +19,11 @@
 
 static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	struct tuner_state	state;
 	int err = 0;
 
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
 	if (tuner_ops->get_state) {
 		if (frontend_ops->i2c_gate_ctrl)
 			frontend_ops->i2c_gate_ctrl(fe, 1);
@@ -49,16 +45,13 @@ static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
 
 static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	struct tuner_state	state;
 	int err = 0;
 
 	state.frequency = frequency;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
+
 	if (tuner_ops->set_state) {
 		if (frontend_ops->i2c_gate_ctrl)
 			frontend_ops->i2c_gate_ctrl(fe, 1);
@@ -79,15 +72,11 @@ static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
 
 static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	struct tuner_state	state;
 	int err = 0;
 
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
 	if (tuner_ops->get_state) {
 		if (frontend_ops->i2c_gate_ctrl)
 			frontend_ops->i2c_gate_ctrl(fe, 1);
@@ -109,16 +98,13 @@ static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
 
 static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	struct tuner_state	state;
 	int err = 0;
 
 	state.bandwidth = bandwidth;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
+
 	if (tuner_ops->set_state) {
 		if (frontend_ops->i2c_gate_ctrl)
 			frontend_ops->i2c_gate_ctrl(fe, 1);

+ 2 - 7
drivers/media/dvb-frontends/stv0367.c

@@ -922,18 +922,13 @@ static int stv0367ter_gate_ctrl(struct dvb_frontend *fe, int enable)
 
 static u32 stv0367_get_tuner_freq(struct dvb_frontend *fe)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	u32 freq = 0;
 	int err = 0;
 
 	dprintk("%s:\n", __func__);
 
-
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
 	if (tuner_ops->get_frequency) {
 		err = tuner_ops->get_frequency(fe, &freq);
 		if (err < 0) {

+ 1 - 1
drivers/media/dvb-frontends/tda18271c2dd.c

@@ -1030,7 +1030,7 @@ static int ChannelConfiguration(struct tda_state *state,
 			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital;
 
 		if ((Standard == HF_FM_Radio) && state->m_bFMInput)
-			state->m_Regs[EP4] |= 80;
+			state->m_Regs[EP4] |= 0x80;
 
 		state->m_Regs[MPD] &= ~0x80;
 		if (Standard > HF_AnalogMax)

+ 4 - 4
drivers/media/dvb-frontends/tda18271c2dd_maps.h

@@ -5,7 +5,7 @@ enum HF_S {
 	HF_DVBC_8MHZ, HF_DVBC
 };
 
-struct SStandardParam m_StandardTable[] = {
+static struct SStandardParam m_StandardTable[] = {
 	{       0,        0, 0x00, 0x00 },    /* HF_None */
 	{ 6000000,  7000000, 0x1D, 0x2C },    /* HF_B, */
 	{ 6900000,  8000000, 0x1E, 0x2C },    /* HF_DK, */
@@ -27,7 +27,7 @@ struct SStandardParam m_StandardTable[] = {
 	{       0,        0, 0x00, 0x00 },    /* HF_DVBC (Unused) */
 };
 
-struct SMap  m_BP_Filter_Map[] = {
+static struct SMap  m_BP_Filter_Map[] = {
 	{   62000000,  0x00 },
 	{   84000000,  0x01 },
 	{  100000000,  0x02 },
@@ -799,14 +799,14 @@ static struct SRFBandMap  m_RF_Band_Map[7] = {
 	{  865000000,  489500000,   697500000,  842000000},
 };
 
-u8 m_Thermometer_Map_1[16] = {
+static u8 m_Thermometer_Map_1[16] = {
 	60, 62, 66, 64,
 	74, 72, 68, 70,
 	90, 88, 84, 86,
 	76, 78, 82, 80,
 };
 
-u8 m_Thermometer_Map_2[16] = {
+static u8 m_Thermometer_Map_2[16] = {
 	92, 94, 98, 96,
 	106, 104, 100, 102,
 	122, 120, 116, 118,

+ 11 - 19
drivers/media/dvb-frontends/tda8261_cfg.h

@@ -19,17 +19,14 @@
 
 static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	struct tuner_state	t_state;
 	int err = 0;
 
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
 	if (tuner_ops->get_state) {
-		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+		err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+		if (err < 0) {
 			printk("%s: Invalid parameter\n", __func__);
 			return err;
 		}
@@ -41,18 +38,16 @@ static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 
 static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency)
 {
-	struct dvb_frontend_ops	*frontend_ops = NULL;
-	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct dvb_frontend_ops	*frontend_ops = &fe->ops;
+	struct dvb_tuner_ops	*tuner_ops = &frontend_ops->tuner_ops;
 	struct tuner_state	t_state;
 	int err = 0;
 
 	t_state.frequency = frequency;
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
+
 	if (tuner_ops->set_state) {
-		if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+		err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+		if (err < 0) {
 			printk("%s: Invalid parameter\n", __func__);
 			return err;
 		}
@@ -68,12 +63,9 @@ static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 	struct tuner_state	t_state;
 	int err = 0;
 
-	if (&fe->ops)
-		frontend_ops = &fe->ops;
-	if (&frontend_ops->tuner_ops)
-		tuner_ops = &frontend_ops->tuner_ops;
 	if (tuner_ops->get_state) {
-		if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+		err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+		if (err < 0) {
 			printk("%s: Invalid parameter\n", __func__);
 			return err;
 		}

+ 1 - 0
drivers/media/i2c/Kconfig

@@ -551,6 +551,7 @@ config VIDEO_MT9V032
 	tristate "Micron MT9V032 sensor support"
 	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
 	depends on MEDIA_CAMERA_SUPPORT
+	select REGMAP_I2C
 	---help---
 	  This is a Video4Linux2 sensor-level driver for the Micron
 	  MT9V032 752x480 CMOS sensor.

+ 0 - 1
drivers/media/i2c/adv7180.c

@@ -663,7 +663,6 @@ static int adv7180_remove(struct i2c_client *client)
 	if (state->irq > 0)
 		free_irq(client->irq, state);
 
-	v4l2_device_unregister_subdev(sd);
 	adv7180_exit_controls(state);
 	mutex_destroy(&state->mutex);
 	return 0;

+ 4 - 1
drivers/media/i2c/adv7604.c

@@ -2588,8 +2588,11 @@ static const struct adv7604_reg_seq adv7604_recommended_settings_hdmi[] = {
 };
 
 static const struct adv7604_reg_seq adv7611_recommended_settings_hdmi[] = {
+	/* ADV7611 Register Settings Recommendations Rev 1.5, May 2014 */
 	{ ADV7604_REG(ADV7604_PAGE_CP, 0x6c), 0x00 },
-	{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x0c },
+	{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x9b), 0x03 },
+	{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x08 },
+	{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x85), 0x1f },
 	{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x87), 0x70 },
 	{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xda },
 	{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x01 },

+ 48 - 47
drivers/media/i2c/ir-kbd-i2c.c

@@ -62,8 +62,8 @@ module_param(debug, int, 0644);    /* debug level (0,1,2) */
 
 /* ----------------------------------------------------------------------- */
 
-static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
-			       int size, int offset)
+static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol,
+			       u32 *scancode, u8 *ptoggle, int size, int offset)
 {
 	unsigned char buf[6];
 	int start, range, toggle, dev, code, ircode;
@@ -86,19 +86,10 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
 	if (!start)
 		/* no key pressed */
 		return 0;
-	/*
-	 * Hauppauge remotes (black/silver) always use
-	 * specific device ids. If we do not filter the
-	 * device ids then messages destined for devices
-	 * such as TVs (id=0) will get through causing
-	 * mis-fired events.
-	 *
-	 * We also filter out invalid key presses which
-	 * produce annoying debug log entries.
-	 */
-	ircode= (start << 12) | (toggle << 11) | (dev << 6) | code;
-	if ((ircode & 0x1fff)==0x1fff)
-		/* invalid key press */
+
+	/* filter out invalid key presses */
+	ircode = (start << 12) | (toggle << 11) | (dev << 6) | code;
+	if ((ircode & 0x1fff) == 0x1fff)
 		return 0;
 
 	if (!range)
@@ -107,18 +98,20 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
 	dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n",
 		start, range, toggle, dev, code);
 
-	/* return key */
-	*ir_key = (dev << 8) | code;
-	*ir_raw = ircode;
+	*protocol = RC_TYPE_RC5;
+	*scancode = RC_SCANCODE_RC5(dev, code);
+	*ptoggle = toggle;
 	return 1;
 }
 
-static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, enum rc_type *protocol,
+			u32 *scancode, u8 *toggle)
 {
-	return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+	return get_key_haup_common (ir, protocol, scancode, toggle, 3, 0);
 }
 
-static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_type *protocol,
+			    u32 *scancode, u8 *toggle)
 {
 	int ret;
 	unsigned char buf[1] = { 0 };
@@ -133,10 +126,11 @@ static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	if (ret != 1)
 		return (ret < 0) ? ret : -EINVAL;
 
-	return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+	return get_key_haup_common(ir, protocol, scancode, toggle, 6, 3);
 }
 
-static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pixelview(struct IR_i2c *ir, enum rc_type *protocol,
+			     u32 *scancode, u8 *toggle)
 {
 	unsigned char b;
 
@@ -145,12 +139,15 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 		dprintk(1,"read error\n");
 		return -EIO;
 	}
-	*ir_key = b;
-	*ir_raw = b;
+
+	*protocol = RC_TYPE_OTHER;
+	*scancode = b;
+	*toggle = 0;
 	return 1;
 }
 
-static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_type *protocol,
+			      u32 *scancode, u8 *toggle)
 {
 	unsigned char buf[4];
 
@@ -168,13 +165,14 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	if(buf[0] != 0x1 ||  buf[1] != 0xfe)
 		return 0;
 
-	*ir_key = buf[2];
-	*ir_raw = (buf[2] << 8) | buf[3];
-
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = buf[2];
+	*toggle = 0;
 	return 1;
 }
 
-static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_knc1(struct IR_i2c *ir, enum rc_type *protocol,
+			u32 *scancode, u8 *toggle)
 {
 	unsigned char b;
 
@@ -197,13 +195,14 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 		/* keep old data */
 		return 1;
 
-	*ir_key = b;
-	*ir_raw = b;
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = b;
+	*toggle = 0;
 	return 1;
 }
 
-static int get_key_avermedia_cardbus(struct IR_i2c *ir,
-				     u32 *ir_key, u32 *ir_raw)
+static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_type *protocol,
+				     u32 *scancode, u8 *toggle)
 {
 	unsigned char subaddr, key, keygroup;
 	struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0,
@@ -237,12 +236,11 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
 	}
 	key |= (keygroup & 1) << 6;
 
-	*ir_key = key;
-	*ir_raw = key;
-	if (!strcmp(ir->ir_codes, RC_MAP_AVERMEDIA_M733A_RM_K6)) {
-		*ir_key |= keygroup << 8;
-		*ir_raw |= keygroup << 8;
-	}
+	*protocol = RC_TYPE_UNKNOWN;
+	*scancode = key;
+	if (ir->c->addr == 0x41) /* AVerMedia EM78P153 */
+		*scancode |= keygroup << 8;
+	*toggle = 0;
 	return 1;
 }
 
@@ -250,19 +248,22 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
 
 static int ir_key_poll(struct IR_i2c *ir)
 {
-	static u32 ir_key, ir_raw;
+	enum rc_type protocol;
+	u32 scancode;
+	u8 toggle;
 	int rc;
 
 	dprintk(3, "%s\n", __func__);
-	rc = ir->get_key(ir, &ir_key, &ir_raw);
+	rc = ir->get_key(ir, &protocol, &scancode, &toggle);
 	if (rc < 0) {
 		dprintk(2,"error\n");
 		return rc;
 	}
 
 	if (rc) {
-		dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
-		rc_keydown(ir->rc, ir_key, 0);
+		dprintk(1, "%s: proto = 0x%04x, scancode = 0x%08x\n",
+			__func__, protocol, scancode);
+		rc_keydown(ir->rc, protocol, scancode, toggle);
 	}
 	return 0;
 }
@@ -327,7 +328,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	case 0x6b:
 		name        = "FusionHDTV";
 		ir->get_key = get_key_fusionhdtv;
-		rc_type     = RC_BIT_RC5;
+		rc_type     = RC_BIT_UNKNOWN;
 		ir_codes    = RC_MAP_FUSIONHDTV_MCE;
 		break;
 	case 0x40:
@@ -431,8 +432,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	 * Initialize the other fields of rc_dev
 	 */
 	rc->map_name       = ir->ir_codes;
-	rc_set_allowed_protocols(rc, rc_type);
-	rc_set_enabled_protocols(rc, rc_type);
+	rc->allowed_protocols = rc_type;
+	rc->enabled_protocols = rc_type;
 	if (!rc->driver_name)
 		rc->driver_name = MODULE_NAME;
 

+ 94 - 76
drivers/media/i2c/mt9v032.c

@@ -1,5 +1,5 @@
 /*
- * Driver for MT9V032 CMOS Image Sensor from Micron
+ * Driver for MT9V022, MT9V024, MT9V032, and MT9V034 CMOS Image Sensors
  *
  * Copyright (C) 2010, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  *
@@ -17,6 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/log2.h>
 #include <linux/mutex.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/v4l2-mediabus.h>
@@ -87,6 +88,7 @@
 #define		MT9V032_READ_MODE_COLUMN_FLIP		(1 << 5)
 #define		MT9V032_READ_MODE_DARK_COLUMNS		(1 << 6)
 #define		MT9V032_READ_MODE_DARK_ROWS		(1 << 7)
+#define		MT9V032_READ_MODE_RESERVED		0x0300
 #define MT9V032_PIXEL_OPERATION_MODE			0x0f
 #define		MT9V034_PIXEL_OPERATION_MODE_HDR	(1 << 0)
 #define		MT9V034_PIXEL_OPERATION_MODE_COLOR	(1 << 1)
@@ -133,8 +135,12 @@
 #define MT9V032_THERMAL_INFO				0xc1
 
 enum mt9v032_model {
-	MT9V032_MODEL_V032_COLOR,
-	MT9V032_MODEL_V032_MONO,
+	MT9V032_MODEL_V022_COLOR,	/* MT9V022IX7ATC */
+	MT9V032_MODEL_V022_MONO,	/* MT9V022IX7ATM */
+	MT9V032_MODEL_V024_COLOR,	/* MT9V024IA7XTC */
+	MT9V032_MODEL_V024_MONO,	/* MT9V024IA7XTM */
+	MT9V032_MODEL_V032_COLOR,	/* MT9V032C12STM */
+	MT9V032_MODEL_V032_MONO,	/* MT9V032C12STC */
 	MT9V032_MODEL_V034_COLOR,
 	MT9V032_MODEL_V034_MONO,
 };
@@ -160,14 +166,14 @@ struct mt9v032_model_info {
 };
 
 static const struct mt9v032_model_version mt9v032_versions[] = {
-	{ MT9V032_CHIP_ID_REV1, "MT9V032 rev1/2" },
-	{ MT9V032_CHIP_ID_REV3, "MT9V032 rev3" },
-	{ MT9V034_CHIP_ID_REV1, "MT9V034 rev1" },
+	{ MT9V032_CHIP_ID_REV1, "MT9V022/MT9V032 rev1/2" },
+	{ MT9V032_CHIP_ID_REV3, "MT9V022/MT9V032 rev3" },
+	{ MT9V034_CHIP_ID_REV1, "MT9V024/MT9V034 rev1" },
 };
 
 static const struct mt9v032_model_data mt9v032_model_data[] = {
 	{
-		/* MT9V032 revisions 1/2/3 */
+		/* MT9V022, MT9V032 revisions 1/2/3 */
 		.min_row_time = 660,
 		.min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN,
 		.min_vblank = MT9V032_VERTICAL_BLANKING_MIN,
@@ -176,7 +182,7 @@ static const struct mt9v032_model_data mt9v032_model_data[] = {
 		.max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX,
 		.pclk_reg = MT9V032_PIXEL_CLOCK,
 	}, {
-		/* MT9V034 */
+		/* MT9V024, MT9V034 */
 		.min_row_time = 690,
 		.min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN,
 		.min_vblank = MT9V034_VERTICAL_BLANKING_MIN,
@@ -188,6 +194,22 @@ static const struct mt9v032_model_data mt9v032_model_data[] = {
 };
 
 static const struct mt9v032_model_info mt9v032_models[] = {
+	[MT9V032_MODEL_V022_COLOR] = {
+		.data = &mt9v032_model_data[0],
+		.color = true,
+	},
+	[MT9V032_MODEL_V022_MONO] = {
+		.data = &mt9v032_model_data[0],
+		.color = false,
+	},
+	[MT9V032_MODEL_V024_COLOR] = {
+		.data = &mt9v032_model_data[1],
+		.color = true,
+	},
+	[MT9V032_MODEL_V024_MONO] = {
+		.data = &mt9v032_model_data[1],
+		.color = false,
+	},
 	[MT9V032_MODEL_V032_COLOR] = {
 		.data = &mt9v032_model_data[0],
 		.color = true,
@@ -224,6 +246,7 @@ struct mt9v032 {
 	struct mutex power_lock;
 	int power_count;
 
+	struct regmap *regmap;
 	struct clk *clk;
 
 	struct mt9v032_platform_data *pdata;
@@ -231,7 +254,6 @@ struct mt9v032 {
 	const struct mt9v032_model_version *version;
 
 	u32 sysclk;
-	u16 chip_control;
 	u16 aec_agc;
 	u16 hblank;
 	struct {
@@ -245,40 +267,10 @@ static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
 	return container_of(sd, struct mt9v032, subdev);
 }
 
-static int mt9v032_read(struct i2c_client *client, const u8 reg)
-{
-	s32 data = i2c_smbus_read_word_swapped(client, reg);
-	dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
-		data, reg);
-	return data;
-}
-
-static int mt9v032_write(struct i2c_client *client, const u8 reg,
-			 const u16 data)
-{
-	dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
-		data, reg);
-	return i2c_smbus_write_word_swapped(client, reg, data);
-}
-
-static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
-{
-	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
-	u16 value = (mt9v032->chip_control & ~clear) | set;
-	int ret;
-
-	ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value);
-	if (ret < 0)
-		return ret;
-
-	mt9v032->chip_control = value;
-	return 0;
-}
-
 static int
 mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
 {
-	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+	struct regmap *map = mt9v032->regmap;
 	u16 value = mt9v032->aec_agc;
 	int ret;
 
@@ -287,7 +279,7 @@ mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
 	else
 		value &= ~which;
 
-	ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value);
+	ret = regmap_write(map, MT9V032_AEC_AGC_ENABLE, value);
 	if (ret < 0)
 		return ret;
 
@@ -298,23 +290,23 @@ mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
 static int
 mt9v032_update_hblank(struct mt9v032 *mt9v032)
 {
-	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
 	struct v4l2_rect *crop = &mt9v032->crop;
 	unsigned int min_hblank = mt9v032->model->data->min_hblank;
 	unsigned int hblank;
 
 	if (mt9v032->version->version == MT9V034_CHIP_ID_REV1)
 		min_hblank += (mt9v032->hratio - 1) * 10;
-	min_hblank = max_t(unsigned int, (int)mt9v032->model->data->min_row_time - crop->width,
-			   (int)min_hblank);
+	min_hblank = max_t(int, mt9v032->model->data->min_row_time - crop->width,
+			   min_hblank);
 	hblank = max_t(unsigned int, mt9v032->hblank, min_hblank);
 
-	return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, hblank);
+	return regmap_write(mt9v032->regmap, MT9V032_HORIZONTAL_BLANKING,
+			    hblank);
 }
 
 static int mt9v032_power_on(struct mt9v032 *mt9v032)
 {
-	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+	struct regmap *map = mt9v032->regmap;
 	int ret;
 
 	ret = clk_set_rate(mt9v032->clk, mt9v032->sysclk);
@@ -328,15 +320,15 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
 	udelay(1);
 
 	/* Reset the chip and stop data read out */
-	ret = mt9v032_write(client, MT9V032_RESET, 1);
+	ret = regmap_write(map, MT9V032_RESET, 1);
 	if (ret < 0)
 		return ret;
 
-	ret = mt9v032_write(client, MT9V032_RESET, 0);
+	ret = regmap_write(map, MT9V032_RESET, 0);
 	if (ret < 0)
 		return ret;
 
-	return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0);
+	return regmap_write(map, MT9V032_CHIP_CONTROL, 0);
 }
 
 static void mt9v032_power_off(struct mt9v032 *mt9v032)
@@ -346,7 +338,7 @@ static void mt9v032_power_off(struct mt9v032 *mt9v032)
 
 static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
 {
-	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+	struct regmap *map = mt9v032->regmap;
 	int ret;
 
 	if (!on) {
@@ -360,14 +352,14 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
 
 	/* Configure the pixel clock polarity */
 	if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
-		ret = mt9v032_write(client, mt9v032->model->data->pclk_reg,
+		ret = regmap_write(map, mt9v032->model->data->pclk_reg,
 				MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
 		if (ret < 0)
 			return ret;
 	}
 
 	/* Disable the noise correction algorithm and restore the controls. */
-	ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
+	ret = regmap_write(map, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
 	if (ret < 0)
 		return ret;
 
@@ -411,38 +403,39 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
 	const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
 		       | MT9V032_CHIP_CONTROL_DOUT_ENABLE
 		       | MT9V032_CHIP_CONTROL_SEQUENTIAL;
-	struct i2c_client *client = v4l2_get_subdevdata(subdev);
 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
 	struct v4l2_rect *crop = &mt9v032->crop;
+	struct regmap *map = mt9v032->regmap;
 	unsigned int hbin;
 	unsigned int vbin;
 	int ret;
 
 	if (!enable)
-		return mt9v032_set_chip_control(mt9v032, mode, 0);
+		return regmap_update_bits(map, MT9V032_CHIP_CONTROL, mode, 0);
 
 	/* Configure the window size and row/column bin */
 	hbin = fls(mt9v032->hratio) - 1;
 	vbin = fls(mt9v032->vratio) - 1;
-	ret = mt9v032_write(client, MT9V032_READ_MODE,
-			    hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT |
-			    vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT);
+	ret = regmap_update_bits(map, MT9V032_READ_MODE,
+				 ~MT9V032_READ_MODE_RESERVED,
+				 hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT |
+				 vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT);
 	if (ret < 0)
 		return ret;
 
-	ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left);
+	ret = regmap_write(map, MT9V032_COLUMN_START, crop->left);
 	if (ret < 0)
 		return ret;
 
-	ret = mt9v032_write(client, MT9V032_ROW_START, crop->top);
+	ret = regmap_write(map, MT9V032_ROW_START, crop->top);
 	if (ret < 0)
 		return ret;
 
-	ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width);
+	ret = regmap_write(map, MT9V032_WINDOW_WIDTH, crop->width);
 	if (ret < 0)
 		return ret;
 
-	ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height);
+	ret = regmap_write(map, MT9V032_WINDOW_HEIGHT, crop->height);
 	if (ret < 0)
 		return ret;
 
@@ -451,7 +444,7 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
 		return ret;
 
 	/* Switch to master "normal" mode */
-	return mt9v032_set_chip_control(mt9v032, 0, mode);
+	return regmap_update_bits(map, MT9V032_CHIP_CONTROL, mode, mode);
 }
 
 static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -633,7 +626,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct mt9v032 *mt9v032 =
 			container_of(ctrl->handler, struct mt9v032, ctrls);
-	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+	struct regmap *map = mt9v032->regmap;
 	u32 freq;
 	u16 data;
 
@@ -643,23 +636,23 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
 					      ctrl->val);
 
 	case V4L2_CID_GAIN:
-		return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val);
+		return regmap_write(map, MT9V032_ANALOG_GAIN, ctrl->val);
 
 	case V4L2_CID_EXPOSURE_AUTO:
 		return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
 					      !ctrl->val);
 
 	case V4L2_CID_EXPOSURE:
-		return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
-				     ctrl->val);
+		return regmap_write(map, MT9V032_TOTAL_SHUTTER_WIDTH,
+				    ctrl->val);
 
 	case V4L2_CID_HBLANK:
 		mt9v032->hblank = ctrl->val;
 		return mt9v032_update_hblank(mt9v032);
 
 	case V4L2_CID_VBLANK:
-		return mt9v032_write(client, MT9V032_VERTICAL_BLANKING,
-				     ctrl->val);
+		return regmap_write(map, MT9V032_VERTICAL_BLANKING,
+				    ctrl->val);
 
 	case V4L2_CID_PIXEL_RATE:
 	case V4L2_CID_LINK_FREQ:
@@ -667,7 +660,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
 			break;
 
 		freq = mt9v032->pdata->link_freqs[mt9v032->link_freq->val];
-		mt9v032->pixel_rate->val64 = freq;
+		*mt9v032->pixel_rate->p_new.p_s64 = freq;
 		mt9v032->sysclk = freq;
 		break;
 
@@ -696,7 +689,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
 			     | MT9V032_TEST_PATTERN_FLIP;
 			break;
 		}
-		return mt9v032_write(client, MT9V032_TEST_PATTERN, data);
+		return regmap_write(map, MT9V032_TEST_PATTERN, data);
 	}
 
 	return 0;
@@ -764,7 +757,7 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
 	struct i2c_client *client = v4l2_get_subdevdata(subdev);
 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
 	unsigned int i;
-	s32 version;
+	u32 version;
 	int ret;
 
 	dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
@@ -777,10 +770,10 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
 	}
 
 	/* Read and check the sensor version */
-	version = mt9v032_read(client, MT9V032_CHIP_VERSION);
-	if (version < 0) {
+	ret = regmap_read(mt9v032->regmap, MT9V032_CHIP_VERSION, &version);
+	if (ret < 0) {
 		dev_err(&client->dev, "Failed reading chip version\n");
-		return version;
+		return ret;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(mt9v032_versions); ++i) {
@@ -867,6 +860,13 @@ static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
 	.close = mt9v032_close,
 };
 
+static const struct regmap_config mt9v032_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+};
+
 /* -----------------------------------------------------------------------------
  * Driver initialization and probing
  */
@@ -890,6 +890,10 @@ static int mt9v032_probe(struct i2c_client *client,
 	if (!mt9v032)
 		return -ENOMEM;
 
+	mt9v032->regmap = devm_regmap_init_i2c(client, &mt9v032_regmap_config);
+	if (IS_ERR(mt9v032->regmap))
+		return PTR_ERR(mt9v032->regmap);
+
 	mt9v032->clk = devm_clk_get(&client->dev, NULL);
 	if (IS_ERR(mt9v032->clk))
 		return PTR_ERR(mt9v032->clk);
@@ -931,7 +935,7 @@ static int mt9v032_probe(struct i2c_client *client,
 
 	mt9v032->pixel_rate =
 		v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
-				  V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+				  V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
 
 	if (pdata && pdata->link_freqs) {
 		unsigned int def = 0;
@@ -984,10 +988,19 @@ static int mt9v032_probe(struct i2c_client *client,
 
 	mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
 	ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
+	if (ret < 0)
+		goto err;
 
+	mt9v032->subdev.dev = &client->dev;
+	ret = v4l2_async_register_subdev(&mt9v032->subdev);
 	if (ret < 0)
-		v4l2_ctrl_handler_free(&mt9v032->ctrls);
+		goto err;
 
+	return 0;
+
+err:
+	media_entity_cleanup(&mt9v032->subdev.entity);
+	v4l2_ctrl_handler_free(&mt9v032->ctrls);
 	return ret;
 }
 
@@ -996,6 +1009,7 @@ static int mt9v032_remove(struct i2c_client *client)
 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
 
+	v4l2_async_unregister_subdev(subdev);
 	v4l2_ctrl_handler_free(&mt9v032->ctrls);
 	v4l2_device_unregister_subdev(subdev);
 	media_entity_cleanup(&subdev->entity);
@@ -1004,6 +1018,10 @@ static int mt9v032_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mt9v032_id[] = {
+	{ "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] },
+	{ "mt9v022m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_MONO] },
+	{ "mt9v024", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_COLOR] },
+	{ "mt9v024m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_MONO] },
 	{ "mt9v032", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_COLOR] },
 	{ "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] },
 	{ "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] },

+ 1 - 0
drivers/media/i2c/noon010pc30.c

@@ -554,6 +554,7 @@ static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 	nf = noon010_try_fmt(sd, &fmt->format);
 	noon010_try_frame_size(&fmt->format, &size);
 	fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
+	fmt->format.field = V4L2_FIELD_NONE;
 
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 		if (fh) {

+ 1 - 0
drivers/media/i2c/s5k4ecgx.c

@@ -594,6 +594,7 @@ static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 	pf = s5k4ecgx_try_fmt(sd, &fmt->format);
 	s5k4ecgx_try_frame_size(&fmt->format, &fsize);
 	fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
+	fmt->format.field = V4L2_FIELD_NONE;
 
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 		if (fh) {

+ 2 - 0
drivers/media/i2c/s5k5baf.c

@@ -1313,6 +1313,8 @@ static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 	const struct s5k5baf_pixfmt *pixfmt;
 	int ret = 0;
 
+	mf->field = V4L2_FIELD_NONE;
+
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 		*v4l2_subdev_get_try_format(fh, fmt->pad) = *mf;
 		return 0;

+ 1 - 0
drivers/media/i2c/s5k6a3.c

@@ -115,6 +115,7 @@ static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf)
 
 	fmt = find_sensor_format(mf);
 	mf->code = fmt->code;
+	mf->field = V4L2_FIELD_NONE;
 	v4l_bound_align_image(&mf->width, S5K6A3_SENSOR_MIN_WIDTH,
 			      S5K6A3_SENSOR_MAX_WIDTH, 0,
 			      &mf->height, S5K6A3_SENSOR_MIN_HEIGHT,

+ 10 - 7
drivers/media/i2c/smiapp/smiapp-core.c

@@ -297,8 +297,8 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor)
 	if (rval < 0)
 		return rval;
 
-	sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz;
-	sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi;
+	*sensor->pixel_rate_parray->p_cur.p_s64 = pll->vt_pix_clk_freq_hz;
+	*sensor->pixel_rate_csi->p_cur.p_s64 = pll->pixel_rate_csi;
 
 	return 0;
 }
@@ -533,7 +533,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
 
 	sensor->pixel_rate_parray = v4l2_ctrl_new_std(
 		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
-		V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+		V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
 
 	if (sensor->pixel_array->ctrl_handler.error) {
 		dev_err(&client->dev,
@@ -562,7 +562,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
 
 	sensor->pixel_rate_csi = v4l2_ctrl_new_std(
 		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
-		V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+		V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
 
 	if (sensor->src->ctrl_handler.error) {
 		dev_err(&client->dev,
@@ -1554,6 +1554,7 @@ static int __smiapp_get_format(struct v4l2_subdev *subdev,
 		fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
 		fmt->format.width = r->width;
 		fmt->format.height = r->height;
+		fmt->format.field = V4L2_FIELD_NONE;
 	}
 
 	return 0;
@@ -1687,6 +1688,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev,
 	fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
 	fmt->format.width &= ~1;
 	fmt->format.height &= ~1;
+	fmt->format.field = V4L2_FIELD_NONE;
 
 	fmt->format.width =
 		clamp(fmt->format.width,
@@ -2544,9 +2546,9 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
 		}
 
 		snprintf(this->sd.name,
-			 sizeof(this->sd.name), "%s %d-%4.4x %s",
-			 sensor->minfo.name, i2c_adapter_id(client->adapter),
-			 client->addr, _this->name);
+			 sizeof(this->sd.name), "%s %s %d-%4.4x",
+			 sensor->minfo.name, _this->name,
+			 i2c_adapter_id(client->adapter), client->addr);
 
 		this->sink_fmt.width =
 			sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
@@ -2674,6 +2676,7 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 		try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
 		try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
 		try_fmt->code = mbus_code;
+		try_fmt->field = V4L2_FIELD_NONE;
 
 		try_crop->top = 0;
 		try_crop->left = 0;

+ 3 - 3
drivers/media/i2c/soc_camera/mt9m001.c

@@ -403,7 +403,7 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
 		if (ctrl->val <= ctrl->default_value) {
 			/* Pack it into 0..1 step 0.125, register values 0..8 */
 			unsigned long range = ctrl->default_value - ctrl->minimum;
-			data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
+			data = ((ctrl->val - (s32)ctrl->minimum) * 8 + range / 2) / range;
 
 			dev_dbg(&client->dev, "Setting gain %d\n", data);
 			data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
@@ -413,7 +413,7 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
 			/* Pack it into 1.125..15 variable step, register values 9..67 */
 			/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
 			unsigned long range = ctrl->maximum - ctrl->default_value - 1;
-			unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
+			unsigned long gain = ((ctrl->val - (s32)ctrl->default_value - 1) *
 					       111 + range / 2) / range + 9;
 
 			if (gain <= 32)
@@ -434,7 +434,7 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_EXPOSURE_AUTO:
 		if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
 			unsigned long range = exp->maximum - exp->minimum;
-			unsigned long shutter = ((exp->val - exp->minimum) * 1048 +
+			unsigned long shutter = ((exp->val - (s32)exp->minimum) * 1048 +
 						 range / 2) / range + 1;
 
 			dev_dbg(&client->dev,

+ 12 - 0
drivers/media/i2c/soc_camera/mt9m111.c

@@ -931,6 +931,12 @@ static int mt9m111_probe(struct i2c_client *client,
 	struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
 	int ret;
 
+	if (client->dev.of_node) {
+		ssdd = devm_kzalloc(&client->dev, sizeof(*ssdd), GFP_KERNEL);
+		if (!ssdd)
+			return -ENOMEM;
+		client->dev.platform_data = ssdd;
+	}
 	if (!ssdd) {
 		dev_err(&client->dev, "mt9m111: driver needs platform data\n");
 		return -EINVAL;
@@ -1015,6 +1021,11 @@ static int mt9m111_remove(struct i2c_client *client)
 
 	return 0;
 }
+static const struct of_device_id mt9m111_of_match[] = {
+	{ .compatible = "micron,mt9m111", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt9m111_of_match);
 
 static const struct i2c_device_id mt9m111_id[] = {
 	{ "mt9m111", 0 },
@@ -1025,6 +1036,7 @@ MODULE_DEVICE_TABLE(i2c, mt9m111_id);
 static struct i2c_driver mt9m111_i2c_driver = {
 	.driver = {
 		.name = "mt9m111",
+		.of_match_table = of_match_ptr(mt9m111_of_match),
 	},
 	.probe		= mt9m111_probe,
 	.remove		= mt9m111_remove,

+ 3 - 3
drivers/media/i2c/soc_camera/mt9t031.c

@@ -474,7 +474,7 @@ static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
 		if (ctrl->val <= ctrl->default_value) {
 			/* Pack it into 0..1 step 0.125, register values 0..8 */
 			unsigned long range = ctrl->default_value - ctrl->minimum;
-			data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
+			data = ((ctrl->val - (s32)ctrl->minimum) * 8 + range / 2) / range;
 
 			dev_dbg(&client->dev, "Setting gain %d\n", data);
 			data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
@@ -485,7 +485,7 @@ static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
 			/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
 			unsigned long range = ctrl->maximum - ctrl->default_value - 1;
 			/* calculated gain: map 65..127 to 9..1024 step 0.125 */
-			unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
+			unsigned long gain = ((ctrl->val - (s32)ctrl->default_value - 1) *
 					       1015 + range / 2) / range + 9;
 
 			if (gain <= 32)		/* calculated gain 9..32 -> 9..32 */
@@ -507,7 +507,7 @@ static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_EXPOSURE_AUTO:
 		if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
 			unsigned int range = exp->maximum - exp->minimum;
-			unsigned int shutter = ((exp->val - exp->minimum) * 1048 +
+			unsigned int shutter = ((exp->val - (s32)exp->minimum) * 1048 +
 						 range / 2) / range + 1;
 			u32 old;
 

+ 2 - 2
drivers/media/i2c/soc_camera/mt9v022.c

@@ -583,7 +583,7 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
 			/* mt9v022 has minimum == default */
 			unsigned long range = gain->maximum - gain->minimum;
 			/* Valid values 16 to 64, 32 to 64 must be even. */
-			unsigned long gain_val = ((gain->val - gain->minimum) *
+			unsigned long gain_val = ((gain->val - (s32)gain->minimum) *
 					      48 + range / 2) / range + 16;
 
 			if (gain_val >= 32)
@@ -608,7 +608,7 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
 		} else {
 			struct v4l2_ctrl *exp = mt9v022->exposure;
 			unsigned long range = exp->maximum - exp->minimum;
-			unsigned long shutter = ((exp->val - exp->minimum) *
+			unsigned long shutter = ((exp->val - (s32)exp->minimum) *
 					479 + range / 2) / range + 1;
 
 			/*

+ 13 - 22
drivers/media/i2c/tvp5150.c

@@ -56,38 +56,29 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
 static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
 {
 	struct i2c_client *c = v4l2_get_subdevdata(sd);
-	unsigned char buffer[1];
 	int rc;
-	struct i2c_msg msg[] = {
-		{ .addr = c->addr, .flags = 0,
-		  .buf = &addr, .len = 1 },
-		{ .addr = c->addr, .flags = I2C_M_RD,
-		  .buf = buffer, .len = 1 }
-	};
-
-	rc = i2c_transfer(c->adapter, msg, 2);
-	if (rc < 0 || rc != 2) {
-		v4l2_err(sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
-		return rc < 0 ? rc : -EIO;
+
+	rc = i2c_smbus_read_byte_data(c, addr);
+	if (rc < 0) {
+		v4l2_err(sd, "i2c i/o error: rc == %d\n", rc);
+		return rc;
 	}
 
-	v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
+	v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, rc);
 
-	return (buffer[0]);
+	return rc;
 }
 
 static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
 				 unsigned char value)
 {
 	struct i2c_client *c = v4l2_get_subdevdata(sd);
-	unsigned char buffer[2];
 	int rc;
 
-	buffer[0] = addr;
-	buffer[1] = value;
-	v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
-	if (2 != (rc = i2c_master_send(c, buffer, 2)))
-		v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
+	v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value);
+	rc = i2c_smbus_write_byte_data(c, addr, value);
+	if (rc < 0)
+		v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d\n", rc);
 }
 
 static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
@@ -1148,10 +1139,10 @@ static int tvp5150_probe(struct i2c_client *c,
 		/* Is TVP5150A */
 		if (tvp5150_id[2] == 3 || tvp5150_id[3] == 0x21) {
 			v4l2_info(sd, "tvp%02x%02xa detected.\n",
-				  tvp5150_id[2], tvp5150_id[3]);
+				  tvp5150_id[0], tvp5150_id[1]);
 		} else {
 			v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
-				  tvp5150_id[2], tvp5150_id[3]);
+				  tvp5150_id[0], tvp5150_id[1]);
 			v4l2_info(sd, "*** Rom ver is %d.%d\n",
 				  tvp5150_id[2], tvp5150_id[3]);
 		}

+ 0 - 2
drivers/media/media-device.c

@@ -106,8 +106,6 @@ static long media_device_enum_entities(struct media_device *mdev,
 	if (ent->name) {
 		strncpy(u_ent.name, ent->name, sizeof(u_ent.name));
 		u_ent.name[sizeof(u_ent.name) - 1] = '\0';
-	} else {
-		memset(u_ent.name, 0, sizeof(u_ent.name));
 	}
 	u_ent.type = ent->type;
 	u_ent.revision = ent->revision;

+ 0 - 3
drivers/media/parport/bw-qcam.c

@@ -759,7 +759,6 @@ static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
 	pix->sizeimage = pix->width * pix->height;
 	/* Just a guess */
 	pix->colorspace = V4L2_COLORSPACE_SRGB;
-	pix->priv = 0;
 	return 0;
 }
 
@@ -785,7 +784,6 @@ static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format
 	pix->sizeimage = pix->width * pix->height;
 	/* Just a guess */
 	pix->colorspace = V4L2_COLORSPACE_SRGB;
-	pix->priv = 0;
 	return 0;
 }
 
@@ -990,7 +988,6 @@ static struct qcam *qcam_init(struct parport *port)
 	qcam->vdev.fops = &qcam_fops;
 	qcam->vdev.lock = &qcam->lock;
 	qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
-	set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
 	qcam->vdev.release = video_device_release_empty;
 	video_set_drvdata(&qcam->vdev, qcam);
 

+ 0 - 1
drivers/media/parport/c-qcam.c

@@ -761,7 +761,6 @@ static struct qcam *qcam_init(struct parport *port)
 	qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
 	qcam->vdev.release = video_device_release_empty;
 	qcam->vdev.ctrl_handler = &qcam->hdl;
-	set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
 	video_set_drvdata(&qcam->vdev, qcam);
 
 	mutex_init(&qcam->lock);

+ 0 - 1
drivers/media/parport/pms.c

@@ -1091,7 +1091,6 @@ static int pms_probe(struct device *pdev, unsigned int card)
 	dev->vdev.release = video_device_release_empty;
 	dev->vdev.lock = &dev->lock;
 	dev->vdev.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
-	set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
 	video_set_drvdata(&dev->vdev, dev);
 	dev->std = V4L2_STD_NTSC_M;
 	dev->height = 240;

+ 0 - 1
drivers/media/parport/w9966.c

@@ -883,7 +883,6 @@ static int w9966_init(struct w9966 *cam, struct parport *port)
 	cam->vdev.ioctl_ops = &w9966_ioctl_ops;
 	cam->vdev.release = video_device_release_empty;
 	cam->vdev.ctrl_handler = &cam->hdl;
-	set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
 	video_set_drvdata(&cam->vdev, cam);
 
 	mutex_init(&cam->lock);

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません