浏览代码

Merge tag 'media/v3.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:

 - Some documentation updates and a few new pixel formats

 - Stop btcx-risc abuse by cx88 and move it to bt8xx driver

 - New platform driver: am437x

 - New webcam driver: toptek

 - New remote controller hardware protocols added to img-ir driver

 - Removal of a few very old drivers that relies on old kABIs and are
   for very hard to find hardware: parallel port webcam drivers
   (bw-qcam, c-cam, pms and w9966), tlg2300, Video In/Out for SGI (vino)

 - Removal of the USB Telegent driver (tlg2300).  The company that
   developed this driver has long gone and the hardware is hard to find.
   As it relies on a legacy set of kABI symbols and nobody seems to care
   about it, remove it.

 - several improvements at rtl2832 driver

 - conversion on cx28521 and au0828 to use videobuf2 (VB2)

 - several improvements, fixups and board additions

* tag 'media/v3.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (321 commits)
  [media] dvb_net: Convert local hex dump to print_hex_dump_debug
  [media] dvb_net: Use standard debugging facilities
  [media] dvb_net: Use vsprintf %pM extension to print Ethernet addresses
  [media] staging: lirc_serial: adjust boolean assignments
  [media] stb0899: use sign_extend32() for sign extension
  [media] si2168: add support for 1.7MHz bandwidth
  [media] si2168: return error if set_frontend is called with invalid parameters
  [media] lirc_dev: avoid potential null-dereference
  [media] mn88472: simplify bandwidth registers setting code
  [media] dvb: tc90522: re-add symbol-rate report
  [media] lmedm04: add read snr, signal strength and ber call backs
  [media] lmedm04: Create frontend call back for read status
  [media] lmedm04: create frontend callbacks for signal/snr/ber/ucblocks
  [media] lmedm04: Fix usb_submit_urb BOGUS urb xfer, pipe 1 != type 3 in interrupt urb
  [media] lmedm04: Increase Interupt due time to 200 msec
  [media] cx88-dvb: whitespace cleanup
  [media] rtl28xxu: properly initialize pdata
  [media] rtl2832: declare functions as static
  [media] rtl2830: declare functions as static
  [media] rtl2832_sdr: add kernel-doc comments for platform_data
  ...
Linus Torvalds 10 年之前
父节点
当前提交
3e63430a5c
共有 100 个文件被更改,包括 4260 次插入3704 次删除
  1. 5 6
      Documentation/DocBook/media/v4l/controls.xml
  2. 1 1
      Documentation/DocBook/media/v4l/pixfmt-srggb10.xml
  3. 1 1
      Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml
  4. 1 1
      Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
  5. 99 0
      Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml
  6. 1 1
      Documentation/DocBook/media/v4l/pixfmt-srggb12.xml
  7. 1 0
      Documentation/DocBook/media/v4l/pixfmt.xml
  8. 0 8
      Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml
  9. 0 8
      Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml
  10. 63 0
      Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
  11. 3 1
      Documentation/devicetree/bindings/media/sunxi-ir.txt
  12. 61 0
      Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt
  13. 3 0
      Documentation/devicetree/bindings/media/video-interfaces.txt
  14. 0 205
      Documentation/video4linux/CQcam.txt
  15. 0 47
      Documentation/video4linux/README.tlg2300
  16. 23 2
      Documentation/video4linux/v4l2-framework.txt
  17. 0 33
      Documentation/video4linux/w9966.txt
  18. 19 22
      MAINTAINERS
  19. 0 4
      drivers/media/common/Kconfig
  20. 0 1
      drivers/media/common/Makefile
  21. 0 6
      drivers/media/common/btcx-risc.h
  22. 26 62
      drivers/media/dvb-core/dvb_net.c
  23. 3 1
      drivers/media/dvb-frontends/Kconfig
  24. 0 5
      drivers/media/dvb-frontends/au8522.h
  25. 2 1
      drivers/media/dvb-frontends/dib8000.c
  26. 7 3
      drivers/media/dvb-frontends/hd29l2.c
  27. 0 6
      drivers/media/dvb-frontends/lg2160.c
  28. 8 15
      drivers/media/dvb-frontends/lgdt3305.c
  29. 6 0
      drivers/media/dvb-frontends/lgdt3305.h
  30. 0 6
      drivers/media/dvb-frontends/lgdt330x.c
  31. 0 6
      drivers/media/dvb-frontends/lgdt330x.h
  32. 0 6
      drivers/media/dvb-frontends/lgdt330x_priv.h
  33. 0 4
      drivers/media/dvb-frontends/mb86a20s.c
  34. 6 0
      drivers/media/dvb-frontends/mn88472.h
  35. 0 6
      drivers/media/dvb-frontends/nxt200x.h
  36. 0 6
      drivers/media/dvb-frontends/or51132.c
  37. 0 6
      drivers/media/dvb-frontends/or51132.h
  38. 551 393
      drivers/media/dvb-frontends/rtl2830.c
  39. 19 60
      drivers/media/dvb-frontends/rtl2830.h
  40. 14 10
      drivers/media/dvb-frontends/rtl2830_priv.h
  41. 737 599
      drivers/media/dvb-frontends/rtl2832.c
  42. 28 71
      drivers/media/dvb-frontends/rtl2832.h
  43. 19 13
      drivers/media/dvb-frontends/rtl2832_priv.h
  44. 557 632
      drivers/media/dvb-frontends/rtl2832_sdr.c
  45. 35 22
      drivers/media/dvb-frontends/rtl2832_sdr.h
  46. 0 6
      drivers/media/dvb-frontends/s5h1409.c
  47. 0 5
      drivers/media/dvb-frontends/s5h1409.h
  48. 0 5
      drivers/media/dvb-frontends/s5h1411.c
  49. 0 5
      drivers/media/dvb-frontends/s5h1411.h
  50. 152 165
      drivers/media/dvb-frontends/si2168.c
  51. 2 4
      drivers/media/dvb-frontends/si2168.h
  52. 1 2
      drivers/media/dvb-frontends/si2168_priv.h
  53. 2 3
      drivers/media/dvb-frontends/stb0899_algo.c
  54. 4 3
      drivers/media/dvb-frontends/stb0899_drv.c
  55. 1 0
      drivers/media/dvb-frontends/tc90522.c
  56. 5 4
      drivers/media/i2c/Kconfig
  57. 812 198
      drivers/media/i2c/adv7180.c
  58. 0 76
      drivers/media/i2c/adv7604.c
  59. 46 138
      drivers/media/i2c/adv7842.c
  60. 2 7
      drivers/media/i2c/m5mols/m5mols_core.c
  61. 0 8
      drivers/media/i2c/msp3400-driver.c
  62. 24 18
      drivers/media/i2c/mt9m032.c
  63. 23 18
      drivers/media/i2c/mt9p031.c
  64. 23 18
      drivers/media/i2c/mt9t001.c
  65. 24 19
      drivers/media/i2c/mt9v032.c
  66. 5 6
      drivers/media/i2c/s5k4ecgx.c
  67. 7 6
      drivers/media/i2c/s5k5baf.c
  68. 27 19
      drivers/media/i2c/s5k6aa.c
  69. 1 6
      drivers/media/i2c/smiapp-pll.c
  70. 0 8
      drivers/media/i2c/smiapp-pll.h
  71. 280 106
      drivers/media/i2c/smiapp/smiapp-core.c
  72. 0 6
      drivers/media/i2c/smiapp/smiapp-limits.c
  73. 0 6
      drivers/media/i2c/smiapp/smiapp-limits.h
  74. 5 9
      drivers/media/i2c/smiapp/smiapp-quirk.c
  75. 11 13
      drivers/media/i2c/smiapp/smiapp-quirk.h
  76. 0 6
      drivers/media/i2c/smiapp/smiapp-reg-defs.h
  77. 0 6
      drivers/media/i2c/smiapp/smiapp-reg.h
  78. 0 6
      drivers/media/i2c/smiapp/smiapp-regs.c
  79. 0 6
      drivers/media/i2c/smiapp/smiapp-regs.h
  80. 0 7
      drivers/media/i2c/smiapp/smiapp.h
  81. 30 52
      drivers/media/i2c/soc_camera/ov2640.c
  82. 0 10
      drivers/media/i2c/ths8200.c
  83. 2 0
      drivers/media/mmc/siano/Kconfig
  84. 3 1
      drivers/media/pci/bt8xx/Kconfig
  85. 1 1
      drivers/media/pci/bt8xx/Makefile
  86. 0 6
      drivers/media/pci/bt8xx/bt878.c
  87. 8 28
      drivers/media/pci/bt8xx/btcx-risc.c
  88. 26 0
      drivers/media/pci/bt8xx/btcx-risc.h
  89. 110 214
      drivers/media/pci/bt8xx/bttv-cards.c
  90. 35 9
      drivers/media/pci/bt8xx/bttv-driver.c
  91. 0 6
      drivers/media/pci/bt8xx/bttv-gpio.c
  92. 0 6
      drivers/media/pci/bt8xx/bttv-if.c
  93. 0 6
      drivers/media/pci/bt8xx/bttv-risc.c
  94. 0 7
      drivers/media/pci/bt8xx/bttv-vbi.c
  95. 0 5
      drivers/media/pci/bt8xx/bttv.h
  96. 8 12
      drivers/media/pci/bt8xx/bttvp.h
  97. 1 0
      drivers/media/pci/cx23885/Kconfig
  98. 43 0
      drivers/media/pci/cx23885/cx23885-cards.c
  99. 235 141
      drivers/media/pci/cx23885/cx23885-dvb.c
  100. 2 2
      drivers/media/pci/cx23885/cx23885-i2c.c

+ 5 - 6
Documentation/DocBook/media/v4l/controls.xml

@@ -2692,12 +2692,11 @@ in the S5P family of SoCs by Samsung.
 	      <row><entry></entry></row>
 	      <row><entry></entry></row>
 	      <row>
 	      <row>
 		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE</constant>&nbsp;</entry>
 		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE</constant>&nbsp;</entry>
-		<entry>integer</entry>
-	      </row><row><entry spanname="descr">If the display delay is enabled then the decoder has to return a
-CAPTURE buffer after processing a certain number of OUTPUT buffers. If this number is low, then it may result in
-buffers not being dequeued in display order. In addition hardware may still use those buffers as reference, thus
-application should not write to those buffers. This feature can be used for example for generating thumbnails of videos.
-Applicable to the H264 decoder.
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">If the display delay is enabled then the decoder is forced to return a
+CAPTURE buffer (decoded frame) after processing a certain number of OUTPUT buffers. The delay can be set through
+<constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY</constant>. This feature can be used for example
+for generating thumbnails of videos. Applicable to the H264 decoder.
 	      </entry>
 	      </entry>
 	      </row>
 	      </row>
 	      <row><entry></entry></row>
 	      <row><entry></entry></row>

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

@@ -17,7 +17,7 @@
       <refsect1>
       <refsect1>
 	<title>Description</title>
 	<title>Description</title>
 
 
-	<para>The following four pixel formats are raw sRGB / Bayer formats with
+	<para>These four pixel formats are raw sRGB / Bayer formats with
 10 bits per colour. Each colour component is stored in a 16-bit word, with 6
 10 bits per colour. Each colour component is stored in a 16-bit word, with 6
 unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
 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
 and n/2 blue or red samples, with alternating red and blue rows. Bytes are

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

@@ -25,7 +25,7 @@
 	  </refnamediv>
 	  </refnamediv>
 	  <refsect1>
 	  <refsect1>
 	    <title>Description</title>
 	    <title>Description</title>
-	    <para>The following four pixel formats are raw sRGB / Bayer
+	    <para>These four pixel formats are raw sRGB / Bayer
 	    formats with 10 bits per color compressed to 8 bits each,
 	    formats with 10 bits per color compressed to 8 bits each,
 	    using the A-LAW algorithm. Each color component consumes 8
 	    using the A-LAW algorithm. Each color component consumes 8
 	    bits of memory. In other respects this format is similar to
 	    bits of memory. In other respects this format is similar to

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

@@ -18,7 +18,7 @@
       <refsect1>
       <refsect1>
 	<title>Description</title>
 	<title>Description</title>
 
 
-	<para>The following four pixel formats are raw sRGB / Bayer formats
+	<para>These four pixel formats are raw sRGB / Bayer formats
 	with 10 bits per colour compressed to 8 bits each, using DPCM
 	with 10 bits per colour compressed to 8 bits each, using DPCM
 	compression. DPCM, differential pulse-code modulation, is lossy.
 	compression. DPCM, differential pulse-code modulation, is lossy.
 	Each colour component consumes 8 bits of memory. In other respects
 	Each colour component consumes 8 bits of memory. In other respects

+ 99 - 0
Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml

@@ -0,0 +1,99 @@
+    <refentry id="pixfmt-srggb10p">
+      <refmeta>
+	<refentrytitle>V4L2_PIX_FMT_SRGGB10P ('pRAA'),
+	 V4L2_PIX_FMT_SGRBG10P ('pgAA'),
+	 V4L2_PIX_FMT_SGBRG10P ('pGAA'),
+	 V4L2_PIX_FMT_SBGGR10P ('pBAA'),
+	 </refentrytitle>
+	&manvol;
+      </refmeta>
+      <refnamediv>
+	<refname id="V4L2-PIX-FMT-SRGGB10P"><constant>V4L2_PIX_FMT_SRGGB10P</constant></refname>
+	<refname id="V4L2-PIX-FMT-SGRBG10P"><constant>V4L2_PIX_FMT_SGRBG10P</constant></refname>
+	<refname id="V4L2-PIX-FMT-SGBRG10P"><constant>V4L2_PIX_FMT_SGBRG10P</constant></refname>
+	<refname id="V4L2-PIX-FMT-SBGGR10P"><constant>V4L2_PIX_FMT_SBGGR10P</constant></refname>
+	<refpurpose>10-bit packed Bayer formats</refpurpose>
+      </refnamediv>
+      <refsect1>
+	<title>Description</title>
+
+	<para>These four pixel formats are packed raw sRGB /
+	Bayer formats with 10 bits per colour. Every four consecutive
+	colour components are packed into 5 bytes. Each of the first 4
+	bytes contain the 8 high order bits of the pixels, and the
+	fifth byte contains the two least significants bits of each
+	pixel, in the same order.</para>
+
+	<para>Each n-pixel row contains n/2 green samples and n/2 blue
+	or red samples, with alternating green-red and green-blue
+	rows. They are conventionally described as GRGR... BGBG...,
+	RGRG... GBGB..., etc. Below is an example of one of these
+	formats:</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_SBGGR10P</constant> 4 &times; 4
+      pixel image</title>
+
+      <formalpara>
+	<title>Byte Order.</title>
+	<para>Each cell is one byte.
+	  <informaltable frame="topbot" colsep="1" rowsep="1">
+	    <tgroup cols="5" align="center" border="1">
+	      <colspec align="left" colwidth="2*" />
+	      <tbody valign="top">
+		<row>
+		  <entry>start&nbsp;+&nbsp;0:</entry>
+		  <entry>B<subscript>00high</subscript></entry>
+		  <entry>G<subscript>01high</subscript></entry>
+		  <entry>B<subscript>02high</subscript></entry>
+		  <entry>G<subscript>03high</subscript></entry>
+		  <entry>B<subscript>00low</subscript>(bits 7--6)
+			 G<subscript>01low</subscript>(bits 5--4)
+			 B<subscript>02low</subscript>(bits 3--2)
+			 G<subscript>03low</subscript>(bits 1--0)
+		  </entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;5:</entry>
+		  <entry>G<subscript>10high</subscript></entry>
+		  <entry>R<subscript>11high</subscript></entry>
+		  <entry>G<subscript>12high</subscript></entry>
+		  <entry>R<subscript>13high</subscript></entry>
+		  <entry>G<subscript>10low</subscript>(bits 7--6)
+			 R<subscript>11low</subscript>(bits 5--4)
+			 G<subscript>12low</subscript>(bits 3--2)
+			 R<subscript>13low</subscript>(bits 1--0)
+		  </entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;10:</entry>
+		  <entry>B<subscript>20high</subscript></entry>
+		  <entry>G<subscript>21high</subscript></entry>
+		  <entry>B<subscript>22high</subscript></entry>
+		  <entry>G<subscript>23high</subscript></entry>
+		  <entry>B<subscript>20low</subscript>(bits 7--6)
+			 G<subscript>21low</subscript>(bits 5--4)
+			 B<subscript>22low</subscript>(bits 3--2)
+			 G<subscript>23low</subscript>(bits 1--0)
+		  </entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;15:</entry>
+		  <entry>G<subscript>30high</subscript></entry>
+		  <entry>R<subscript>31high</subscript></entry>
+		  <entry>G<subscript>32high</subscript></entry>
+		  <entry>R<subscript>33high</subscript></entry>
+		  <entry>G<subscript>30low</subscript>(bits 7--6)
+			 R<subscript>31low</subscript>(bits 5--4)
+			 G<subscript>32low</subscript>(bits 3--2)
+			 R<subscript>33low</subscript>(bits 1--0)
+		  </entry>
+		</row>
+	      </tbody>
+	    </tgroup>
+	  </informaltable>
+	</para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>

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

@@ -17,7 +17,7 @@
       <refsect1>
       <refsect1>
 	<title>Description</title>
 	<title>Description</title>
 
 
-	<para>The following four pixel formats are raw sRGB / Bayer formats with
+	<para>These four pixel formats are raw sRGB / Bayer formats with
 12 bits per colour. Each colour component is stored in a 16-bit word, with 4
 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
 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
 and n/2 blue or red samples, with alternating red and blue rows. Bytes are

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

@@ -1405,6 +1405,7 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.<
     &sub-srggb8;
     &sub-srggb8;
     &sub-sbggr16;
     &sub-sbggr16;
     &sub-srggb10;
     &sub-srggb10;
+    &sub-srggb10p;
     &sub-srggb10alaw8;
     &sub-srggb10alaw8;
     &sub-srggb10dpcm8;
     &sub-srggb10dpcm8;
     &sub-srggb12;
     &sub-srggb12;

+ 0 - 8
Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml

@@ -212,11 +212,3 @@ standards set in the <structfield>standards</structfield> field.
     &return-value;
     &return-value;
   </refsect1>
   </refsect1>
 </refentry>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->

+ 0 - 8
Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml

@@ -131,11 +131,3 @@ is out of bounds or the <structfield>pad</structfield> number is invalid.</para>
     </variablelist>
     </variablelist>
   </refsect1>
   </refsect1>
 </refentry>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->

+ 63 - 0
Documentation/devicetree/bindings/media/i2c/nokia,smia.txt

@@ -0,0 +1,63 @@
+SMIA/SMIA++ sensor
+
+SMIA (Standard Mobile Imaging Architecture) is an image sensor standard
+defined jointly by Nokia and ST. SMIA++, defined by Nokia, is an extension
+of that. These definitions are valid for both types of sensors.
+
+More detailed documentation can be found in
+Documentation/devicetree/bindings/media/video-interfaces.txt .
+
+
+Mandatory properties
+--------------------
+
+- compatible: "nokia,smia"
+- reg: I2C address (0x10, or an alternative address)
+- vana-supply: Analogue voltage supply (VANA), typically 2,8 volts (sensor
+  dependent).
+- clocks: External clock to the sensor
+- clock-frequency: Frequency of the external clock to the sensor
+- link-frequencies: List of allowed data link frequencies. An array of
+  64-bit elements.
+
+
+Optional properties
+-------------------
+
+- nokia,nvm-size: The size of the NVM, in bytes. If the size is not given,
+  the NVM contents will not be read.
+- reset-gpios: XSHUTDOWN GPIO
+
+
+Endpoint node mandatory properties
+----------------------------------
+
+- clock-lanes: <0>
+- data-lanes: <1..n>
+- remote-endpoint: A phandle to the bus receiver's endpoint node.
+
+
+Example
+-------
+
+&i2c2 {
+	clock-frequency = <400000>;
+
+	smiapp_1: camera@10 {
+		compatible = "nokia,smia";
+		reg = <0x10>;
+		reset-gpios = <&gpio3 20 0>;
+		vana-supply = <&vaux3>;
+		clocks = <&omap3_isp 0>;
+		clock-frequency = <9600000>;
+		nokia,nvm-size = <512>; /* 8 * 64 */
+		link-frequencies = /bits/ 64 <199200000 210000000 499200000>;
+		port {
+			smiapp_1_1: endpoint {
+				clock-lanes = <0>;
+				data-lanes = <1 2>;
+				remote-endpoint = <&csi2a_ep>;
+			};
+		};
+	};
+};

+ 3 - 1
Documentation/devicetree/bindings/media/sunxi-ir.txt

@@ -1,7 +1,7 @@
 Device-Tree bindings for SUNXI IR controller found in sunXi SoC family
 Device-Tree bindings for SUNXI IR controller found in sunXi SoC family
 
 
 Required properties:
 Required properties:
-- compatible	    : should be "allwinner,sun4i-a10-ir";
+- compatible	    : "allwinner,sun4i-a10-ir" or "allwinner,sun5i-a13-ir"
 - clocks	    : list of clock specifiers, corresponding to
 - clocks	    : list of clock specifiers, corresponding to
 		      entries in clock-names property;
 		      entries in clock-names property;
 - clock-names	    : should contain "apb" and "ir" entries;
 - clock-names	    : should contain "apb" and "ir" entries;
@@ -10,6 +10,7 @@ Required properties:
 
 
 Optional properties:
 Optional properties:
 - linux,rc-map-name : Remote control map name.
 - linux,rc-map-name : Remote control map name.
+- resets : phandle + reset specifier pair
 
 
 Example:
 Example:
 
 
@@ -17,6 +18,7 @@ ir0: ir@01c21800 {
 	compatible = "allwinner,sun4i-a10-ir";
 	compatible = "allwinner,sun4i-a10-ir";
 	clocks = <&apb0_gates 6>, <&ir0_clk>;
 	clocks = <&apb0_gates 6>, <&ir0_clk>;
 	clock-names = "apb", "ir";
 	clock-names = "apb", "ir";
+	resets = <&apb0_rst 1>;
 	interrupts = <0 5 1>;
 	interrupts = <0 5 1>;
 	reg = <0x01C21800 0x40>;
 	reg = <0x01C21800 0x40>;
 	linux,rc-map-name = "rc-rc6-mce";
 	linux,rc-map-name = "rc-rc6-mce";

+ 61 - 0
Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt

@@ -0,0 +1,61 @@
+Texas Instruments AM437x CAMERA (VPFE)
+--------------------------------------
+
+The Video Processing Front End (VPFE) is a key component for image capture
+applications. The capture module provides the system interface and the
+processing capability to connect RAW image-sensor modules and video decoders
+to the AM437x device.
+
+Required properties:
+- compatible: must be "ti,am437x-vpfe"
+- reg: physical base address and length of the registers set for the device;
+- interrupts: should contain IRQ line for the VPFE;
+- ti,am437x-vpfe-interface: can be one of the following,
+	0 - Raw Bayer Interface.
+	1 - 8 Bit BT656 Interface.
+	2 - 10 Bit BT656 Interface.
+	3 - YCbCr 8 Bit Interface.
+	4 - YCbCr 16 Bit Interface.
+
+VPFE 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:
+	vpfe: vpfe@f0034000 {
+		compatible = "ti,am437x-vpfe";
+		reg = <0x48328000 0x2000>;
+		interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&vpfe_pins_default>;
+		pinctrl-1 = <&vpfe_pins_sleep>;
+
+		port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			vpfe0_ep: endpoint {
+				remote-endpoint = <&ov2659_1>;
+				ti,am437x-vpfe-interface = <0>;
+				bus-width = <8>;
+				hsync-active = <0>;
+				vsync-active = <0>;
+			};
+		};
+	};
+
+	i2c1: i2c@4802a000 {
+
+		ov2659@30 {
+			compatible = "ti,ov2659";
+			reg = <0x30>;
+
+			port {
+				ov2659_1: endpoint {
+					remote-endpoint = <&vpfe0_ep>;
+					bus-width = <8>;
+					mclk-frequency = <12000000>;
+				};
+			};
+	};

+ 3 - 0
Documentation/devicetree/bindings/media/video-interfaces.txt

@@ -103,6 +103,9 @@ Optional endpoint properties
   array contains only one entry.
   array contains only one entry.
 - clock-noncontinuous: a boolean property to allow MIPI CSI-2 non-continuous
 - clock-noncontinuous: a boolean property to allow MIPI CSI-2 non-continuous
   clock mode.
   clock mode.
+- link-frequencies: Allowed data bus frequencies. For MIPI CSI-2, for
+  instance, this is the actual frequency of the bus, not bits per clock per
+  lane value. An array of 64-bit unsigned integers.
 
 
 
 
 Example
 Example

+ 0 - 205
Documentation/video4linux/CQcam.txt

@@ -1,205 +0,0 @@
-c-qcam - Connectix Color QuickCam video4linux kernel driver
-
-Copyright (C) 1999  Dave Forrest  <drf5n@virginia.edu>
-		    released under GNU GPL.
-
-1999-12-08 Dave Forrest, written with kernel version 2.2.12 in mind
-
-
-Table of Contents
-
-1.0 Introduction
-2.0 Compilation, Installation, and Configuration
-3.0 Troubleshooting
-4.0 Future Work / current work arounds
-9.0 Sample Program, v4lgrab
-10.0 Other Information
-
-
-1.0 Introduction
-
-  The file ../../drivers/media/parport/c-qcam.c is a device driver for
-the Logitech (nee Connectix) parallel port interface color CCD camera.
-This is a fairly inexpensive device for capturing images.  Logitech
-does not currently provide information for developers, but many people
-have engineered several solutions for non-Microsoft use of the Color
-Quickcam.
-
-1.1 Motivation
-
-  I spent a number of hours trying to get my camera to work, and I
-hope this document saves you some time.  My camera will not work with
-the 2.2.13 kernel as distributed, but with a few patches to the
-module, I was able to grab some frames. See 4.0, Future Work.
-
-
-
-2.0 Compilation, Installation, and Configuration
-
-  The c-qcam depends on parallel port support, video4linux, and the
-Color Quickcam.  It is also nice to have the parallel port readback
-support enabled. I enabled these as modules during the kernel
-configuration.  The appropriate flags are:
-
-    CONFIG_PRINTER       M    for lp.o, parport.o parport_pc.o modules
-    CONFIG_PNP_PARPORT   M for autoprobe.o IEEE1284 readback module
-    CONFIG_PRINTER_READBACK M for parport_probe.o IEEE1284 readback module
-    CONFIG_VIDEO_DEV     M    for videodev.o video4linux module
-    CONFIG_VIDEO_CQCAM   M    for c-qcam.o  Color Quickcam module
-
-  With these flags, the kernel should compile and install the modules.
-To record and monitor the compilation, I use:
-
- (make zlilo ; \
-  make modules; \
-  make modules_install ;
-  depmod -a ) &>log &
- less log  # then a capital 'F' to watch the progress
-
-But that is my personal preference.
-
-2.2 Configuration
-
-  The configuration requires module configuration and device
-configuration.  The following sections detail these procedures.
-
-
-2.1 Module Configuration
-
-  Using modules requires a bit of work to install and pass the
-parameters.  Understand that entries in /etc/modprobe.d/*.conf of:
-
-   alias parport_lowlevel parport_pc
-   options parport_pc io=0x378 irq=none
-   alias char-major-81 videodev
-   alias char-major-81-0 c-qcam
-
-2.2 Device Configuration
-
-  At this point, we need to ensure that the device files exist.
-Video4linux used the /dev/video* files, and we want to attach the
-Quickcam to one of these.
-
-   ls -lad /dev/video*  # should produce a list of the video devices
-
-If the video devices do not exist, you can create them with:
-
-  su
-  cd /dev
-  for ii in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
-    mknod video$ii c 81 $ii   # char-major-81-[0-16]
-    chown root.root video$ii  # owned by root
-    chmod 600 video$ii        # read/writable by root only
-  done
-
-  Lots of people connect video0 to video and bttv, but you might want
-your c-qcam to mean something more:
-
-   ln -s video0 c-qcam  # make /dev/c-qcam a working file
-   ln -s c-qcam video   # make /dev/c-qcam your default video source
-
-  But these are conveniences.  The important part is to make the proper
-special character files with the right major and minor numbers.  All
-of the special device files are listed in ../devices.txt.  If you
-would like the c-qcam readable by non-root users, you will need to
-change the permissions.
-
-3.0 Troubleshooting
-
-  If the sample program below, v4lgrab, gives you output then
-everything is working.
-
-    v4lgrab | wc # should give you a count of characters
-
-  Otherwise, you have some problem.
-
-  The c-qcam is IEEE1284 compatible, so if you are using the proc file
-system (CONFIG_PROC_FS), the parallel printer support
-(CONFIG_PRINTER), the IEEE 1284 system,(CONFIG_PRINTER_READBACK), you
-should be able to read some identification from your quickcam with
-
-	 modprobe -v parport
-	 modprobe -v parport_probe
-	 cat /proc/parport/PORTNUMBER/autoprobe
-Returns:
-  CLASS:MEDIA;
-  MODEL:Color QuickCam 2.0;
-  MANUFACTURER:Connectix;
-
-  A good response to this indicates that your color quickcam is alive
-and well.  A common problem is that the current driver does not
-reliably detect a c-qcam, even though one is attached.  In this case,
-
-     modprobe -v c-qcam
-or
-     insmod -v c-qcam
-
-  Returns a message saying "Device or resource busy"  Development is
-currently underway, but a workaround is to patch the module to skip
-the detection code and attach to a defined port.  Check the
-video4linux mailing list and archive for more current information.
-
-3.1 Checklist:
-
-  Can you get an image?
-	    v4lgrab >qcam.ppm ; wc qcam.ppm ; xv qcam.ppm
-
-  Is a working c-qcam connected to the port?
-	    grep ^ /proc/parport/?/autoprobe
-
-  Do the /dev/video* files exist?
-	    ls -lad /dev/video
-
-  Is the c-qcam module loaded?
-	    modprobe -v c-qcam ; lsmod
-
-  Does the camera work with alternate programs? cqcam, etc?
-
-
-
-
-4.0 Future Work / current workarounds
-
-  It is hoped that this section will soon become obsolete, but if it
-isn't, you might try patching the c-qcam module to add a parport=xxx
-option as in the bw-qcam module so you can specify the parallel port:
-
-       insmod -v c-qcam parport=0
-
-And bypass the detection code, see ../../drivers/char/c-qcam.c and
-look for the 'qc_detect' code and call.
-
-  Note that there is work in progress to change the video4linux API,
-this work is documented at the video4linux2 site listed below.
-
-
-9.0 --- A sample program using v4lgrabber,
-
-v4lgrab is a simple image grabber that will copy a frame from the
-first video device, /dev/video0 to standard output in portable pixmap
-format (.ppm)  To produce .jpg output, you can use it like this:
-'v4lgrab | convert - c-qcam.jpg'
-
-
-10.0 --- Other Information
-
-Use the ../../Maintainers file, particularly the  VIDEO FOR LINUX and PARALLEL
-PORT SUPPORT sections
-
-The video4linux page:
-  http://linuxtv.org
-
-The V4L2 API spec:
-  http://v4l2spec.bytesex.org/
-
-Some web pages about the quickcams:
-   http://www.pingouin-land.com/howto/QuickCam-HOWTO.html
-
-   http://www.crynwr.com/qcpc/            QuickCam Third-Party Drivers
-   http://www.crynwr.com/qcpc/re.html     Some Reverse Engineering
-   http://www.wirelesscouch.net/software/gqcam/   v4l client
-   http://phobos.illtel.denver.co.us/pub/qcread/ doesn't use v4l
-   ftp://ftp.cs.unm.edu/pub/chris/quickcam/   Has lots of drivers
-   http://www.cs.duke.edu/~reynolds/quickcam/ Has lots of information
-
-

+ 0 - 47
Documentation/video4linux/README.tlg2300

@@ -1,47 +0,0 @@
-tlg2300 release notes
-====================
-
-This is a v4l2/dvb device driver for the tlg2300 chip.
-
-
-current status
-==============
-
-video
-	- support mmap and read().(no overlay)
-
-audio
-	- The driver will register a ALSA card for the audio input.
-
-vbi
-	- Works for almost TV norms.
-
-dvb-t
-	- works for DVB-T
-
-FM
-	- Works for radio.
-
----------------------------------------------------------------------------
-TESTED APPLICATIONS:
-
--VLC1.0.4 test the video and dvb. The GUI is friendly to use.
-
--Mplayer test the video.
-
--Mplayer test the FM. The mplayer should be compiled with --enable-radio and
-	 --enable-radio-capture.
-	The command runs as this(The alsa audio registers to card 1):
-	#mplayer radio://103.7/capture/ -radio adevice=hw=1,0:arate=48000 \
-		-rawaudio rate=48000:channels=2
-
----------------------------------------------------------------------------
-KNOWN PROBLEMS:
-about preemphasis:
-	You can set the preemphasis for radio by the following command:
-	#v4l2-ctl -d /dev/radio0 --set-ctrl=pre_emphasis_settings=1
-
-	"pre_emphasis_settings=1" means that you select the 50us. If you want
-	to select the 75us, please use "pre_emphasis_settings=2"
-
-

+ 23 - 2
Documentation/video4linux/v4l2-framework.txt

@@ -793,8 +793,10 @@ video_register_device_no_warn() instead.
 
 
 Whenever a device node is created some attributes are also created for you.
 Whenever a device node is created some attributes are also created for you.
 If you look in /sys/class/video4linux you see the devices. Go into e.g.
 If you look in /sys/class/video4linux you see the devices. Go into e.g.
-video0 and you will see 'name' and 'index' attributes. The 'name' attribute
-is the 'name' field of the video_device struct.
+video0 and you will see 'name', 'debug' and 'index' attributes. The 'name'
+attribute is the 'name' field of the video_device struct. The 'debug' attribute
+can be used to enable core debugging. See the next section for more detailed
+information on this.
 
 
 The 'index' attribute is the index of the device node: for each call to
 The 'index' attribute is the index of the device node: for each call to
 video_register_device() the index is just increased by 1. The first video
 video_register_device() the index is just increased by 1. The first video
@@ -816,6 +818,25 @@ video_device was embedded in it. The vdev->release() callback will never
 be called if the registration failed, nor should you ever attempt to
 be called if the registration failed, nor should you ever attempt to
 unregister the device if the registration failed.
 unregister the device if the registration failed.
 
 
+video device debugging
+----------------------
+
+The 'debug' attribute that is created for each video, vbi, radio or swradio
+device in /sys/class/video4linux/<devX>/ allows you to enable logging of
+file operations.
+
+It is a bitmask and the following bits can be set:
+
+0x01: Log the ioctl name and error code. VIDIOC_(D)QBUF ioctls are only logged
+      if bit 0x08 is also set.
+0x02: Log the ioctl name arguments and error code. VIDIOC_(D)QBUF ioctls are
+      only logged if bit 0x08 is also set.
+0x04: Log the file operations open, release, read, write, mmap and
+      get_unmapped_area. The read and write operations are only logged if
+      bit 0x08 is also set.
+0x08: Log the read and write file operations and the VIDIOC_QBUF and
+      VIDIOC_DQBUF ioctls.
+0x10: Log the poll file operation.
 
 
 video_device cleanup
 video_device cleanup
 --------------------
 --------------------

+ 0 - 33
Documentation/video4linux/w9966.txt

@@ -1,33 +0,0 @@
-W9966 Camera driver, written by Jakob Kemi (jakob.kemi@telia.com)
-
-After a lot of work in softice & wdasm, reading .pdf-files and tiresome
-trial-and-error work I've finally got everything to work. I needed vision for a
-robotics project so I borrowed this camera from a friend and started hacking.
-Anyway I've converted my original code from the AVR 8bit RISC C/ASM code into
-a working Linux driver.
-
-To get it working simply configure your kernel to support
-parport, ieee1284, video4linux and w9966
-
-If w9966 is statically linked it will always perform aggressive probing for
-the camera. If built as a module you'll have more configuration options.
-
-Options:
- modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
-voila!
-
-you can also type 'modinfo -p w9966.o' for option usage
-(or checkout w9966.c)
-
-The only thing to keep in mind is that the image format is in Y-U-Y-V format
-where every two pixels take 4 bytes. In SDL (www.libsdl.org) this format
-is called VIDEO_PALETTE_YUV422 (16 bpp).
-
-A minimal test application (with source) is available from:
-  http://www.slackwaresupport.com/howtos/Webcam-HOWTO
-
-The slow framerate is due to missing DMA ECP read support in the
-parport drivers. I might add working EPP support later.
-
-Good luck!
-    /Jakob Kemi

+ 19 - 22
MAINTAINERS

@@ -659,6 +659,13 @@ L:	linux-media@vger.kernel.org
 S:	Maintained
 S:	Maintained
 F:	drivers/media/i2c/ad9389b*
 F:	drivers/media/i2c/ad9389b*
 
 
+ANALOG DEVICES INC ADV7180 DRIVER
+M:	Lars-Peter Clausen <lars@metafoo.de>
+L:	linux-media@vger.kernel.org
+W:	http://ez.analog.com/community/linux-device-drivers
+S:	Supported
+F:	drivers/media/i2c/adv7180.c
+
 ANALOG DEVICES INC ADV7511 DRIVER
 ANALOG DEVICES INC ADV7511 DRIVER
 M:	Hans Verkuil <hans.verkuil@cisco.com>
 M:	Hans Verkuil <hans.verkuil@cisco.com>
 L:	linux-media@vger.kernel.org
 L:	linux-media@vger.kernel.org
@@ -6202,14 +6209,6 @@ F:	include/uapi/linux/meye.h
 F:	include/uapi/linux/ivtv*
 F:	include/uapi/linux/ivtv*
 F:	include/uapi/linux/uvcvideo.h
 F:	include/uapi/linux/uvcvideo.h
 
 
-MEDIAVISION PRO MOVIE STUDIO DRIVER
-M:	Hans Verkuil <hverkuil@xs4all.nl>
-L:	linux-media@vger.kernel.org
-T:	git git://linuxtv.org/media_tree.git
-W:	http://linuxtv.org
-S:	Odd Fixes
-F:	drivers/media/parport/pms*
-
 MEGARAID SCSI/SAS DRIVERS
 MEGARAID SCSI/SAS DRIVERS
 M:	Kashyap Desai <kashyap.desai@avagotech.com>
 M:	Kashyap Desai <kashyap.desai@avagotech.com>
 M:	Sumit Saxena <sumit.saxena@avagotech.com>
 M:	Sumit Saxena <sumit.saxena@avagotech.com>
@@ -7909,14 +7908,6 @@ T:	git git://github.com/KrasnikovEugene/wcn36xx.git
 S:	Supported
 S:	Supported
 F:	drivers/net/wireless/ath/wcn36xx/
 F:	drivers/net/wireless/ath/wcn36xx/
 
 
-QUICKCAM PARALLEL PORT WEBCAMS
-M:	Hans Verkuil <hverkuil@xs4all.nl>
-L:	linux-media@vger.kernel.org
-T:	git git://linuxtv.org/media_tree.git
-W:	http://linuxtv.org
-S:	Odd Fixes
-F:	drivers/media/parport/*-qcam*
-
 RADOS BLOCK DEVICE (RBD)
 RADOS BLOCK DEVICE (RBD)
 M:	Yehuda Sadeh <yehuda@inktank.com>
 M:	Yehuda Sadeh <yehuda@inktank.com>
 M:	Sage Weil <sage@inktank.com>
 M:	Sage Weil <sage@inktank.com>
@@ -8454,12 +8445,6 @@ F:	kernel/time/clocksource.c
 F:	kernel/time/time*.c
 F:	kernel/time/time*.c
 F:	kernel/time/ntp.c
 F:	kernel/time/ntp.c
 
 
-TLG2300 VIDEO4LINUX-2 DRIVER
-M:	Huang Shijie <shijie8@gmail.com>
-M:	Hans Verkuil <hverkuil@xs4all.nl>
-S:	Odd Fixes
-F:	drivers/media/usb/tlg2300/
-
 SC1200 WDT DRIVER
 SC1200 WDT DRIVER
 M:	Zwane Mwaikambo <zwanem@gmail.com>
 M:	Zwane Mwaikambo <zwanem@gmail.com>
 S:	Maintained
 S:	Maintained
@@ -8825,6 +8810,15 @@ S:	Maintained
 F:	drivers/media/platform/davinci/
 F:	drivers/media/platform/davinci/
 F:	include/media/davinci/
 F:	include/media/davinci/
 
 
+TI AM437X VPFE DRIVER
+M:	Lad, Prabhakar <prabhakar.csengg@gmail.com>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+Q:	http://patchwork.linuxtv.org/project/linux-media/list/
+T:	git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
+S:	Maintained
+F:	drivers/media/platform/am437x/
+
 SIS 190 ETHERNET DRIVER
 SIS 190 ETHERNET DRIVER
 M:	Francois Romieu <romieu@fr.zoreil.com>
 M:	Francois Romieu <romieu@fr.zoreil.com>
 L:	netdev@vger.kernel.org
 L:	netdev@vger.kernel.org
@@ -8906,6 +8900,8 @@ F:	drivers/media/i2c/smiapp/
 F:	include/media/smiapp.h
 F:	include/media/smiapp.h
 F:	drivers/media/i2c/smiapp-pll.c
 F:	drivers/media/i2c/smiapp-pll.c
 F:	drivers/media/i2c/smiapp-pll.h
 F:	drivers/media/i2c/smiapp-pll.h
+F:	include/uapi/linux/smiapp.h
+F:	Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
 
 
 SMM665 HARDWARE MONITOR DRIVER
 SMM665 HARDWARE MONITOR DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
 M:	Guenter Roeck <linux@roeck-us.net>
@@ -8972,6 +8968,7 @@ SOFTLOGIC 6x10 MPEG CODEC
 M:	Bluecherry Maintainers <maintainers@bluecherrydvr.com>
 M:	Bluecherry Maintainers <maintainers@bluecherrydvr.com>
 M:	Andrey Utkin <andrey.utkin@corp.bluecherry.net>
 M:	Andrey Utkin <andrey.utkin@corp.bluecherry.net>
 M:	Andrey Utkin <andrey.krieger.utkin@gmail.com>
 M:	Andrey Utkin <andrey.krieger.utkin@gmail.com>
+M:	Ismael Luceno <ismael@iodev.co.uk>
 L:	linux-media@vger.kernel.org
 L:	linux-media@vger.kernel.org
 S:	Supported
 S:	Supported
 F:	drivers/media/pci/solo6x10/
 F:	drivers/media/pci/solo6x10/

+ 0 - 4
drivers/media/common/Kconfig

@@ -8,10 +8,6 @@ comment "common driver options"
 config VIDEO_CX2341X
 config VIDEO_CX2341X
 	tristate
 	tristate
 
 
-config VIDEO_BTCX
-	depends on PCI
-	tristate
-
 config VIDEO_TVEEPROM
 config VIDEO_TVEEPROM
 	tristate
 	tristate
 	depends on I2C
 	depends on I2C

+ 0 - 1
drivers/media/common/Makefile

@@ -1,5 +1,4 @@
 obj-y += b2c2/ saa7146/ siano/
 obj-y += b2c2/ saa7146/ siano/
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
-obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
 obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o

+ 0 - 6
drivers/media/common/btcx-risc.h

@@ -26,9 +26,3 @@ void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
 void btcx_calc_skips(int line, int width, int *maxy,
 void btcx_calc_skips(int line, int width, int *maxy,
 		     struct btcx_skiplist *skips, unsigned int *nskips,
 		     struct btcx_skiplist *skips, unsigned int *nskips,
 		     const struct v4l2_clip *clips, unsigned int nclips);
 		     const struct v4l2_clip *clips, unsigned int nclips);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 26 - 62
drivers/media/dvb-core/dvb_net.c

@@ -68,13 +68,6 @@
 #include "dvb_demux.h"
 #include "dvb_demux.h"
 #include "dvb_net.h"
 #include "dvb_net.h"
 
 
-static int dvb_net_debug;
-module_param(dvb_net_debug, int, 0444);
-MODULE_PARM_DESC(dvb_net_debug, "enable debug messages");
-
-#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0)
-
-
 static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
 static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
 {
 {
 	unsigned int j;
 	unsigned int j;
@@ -90,36 +83,9 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
 
 
 #ifdef ULE_DEBUG
 #ifdef ULE_DEBUG
 
 
-#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
-#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
-
-#define isprint(c)	((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
-
-static void hexdump( const unsigned char *buf, unsigned short len )
+static void hexdump(const unsigned char *buf, unsigned short len)
 {
 {
-	char str[80], octet[10];
-	int ofs, i, l;
-
-	for (ofs = 0; ofs < len; ofs += 16) {
-		sprintf( str, "%03d: ", ofs );
-
-		for (i = 0; i < 16; i++) {
-			if ((i + ofs) < len)
-				sprintf( octet, "%02x ", buf[ofs + i] );
-			else
-				strcpy( octet, "   " );
-
-			strcat( str, octet );
-		}
-		strcat( str, "  " );
-		l = strlen( str );
-
-		for (i = 0; (i < 16) && ((i + ofs) < len); i++)
-			str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.';
-
-		str[l] = '\0';
-		printk( KERN_WARNING "%s\n", str );
-	}
+	print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true);
 }
 }
 
 
 #endif
 #endif
@@ -315,9 +281,9 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
 			return l;	/* Stop extension header processing and discard SNDU. */
 			return l;	/* Stop extension header processing and discard SNDU. */
 		total_ext_len += l;
 		total_ext_len += l;
 #ifdef ULE_DEBUG
 #ifdef ULE_DEBUG
-		dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
-			"l=%i, total_ext_len=%i\n", p->ule_next_hdr,
-			(int) p->ule_sndu_type, l, total_ext_len);
+		pr_debug("ule_next_hdr=%p, ule_sndu_type=%i, l=%i, total_ext_len=%i\n",
+			 p->ule_next_hdr, (int)p->ule_sndu_type,
+			 l, total_ext_len);
 #endif
 #endif
 
 
 	} while (p->ule_sndu_type < ETH_P_802_3_MIN);
 	} while (p->ule_sndu_type < ETH_P_802_3_MIN);
@@ -700,8 +666,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 
 
 					if (drop) {
 					if (drop) {
 #ifdef ULE_DEBUG
 #ifdef ULE_DEBUG
-						dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
-							MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+						netdev_dbg(dev, "Dropping SNDU: MAC destination address does not match: dest addr: %pM, dev addr: %pM\n",
+							   priv->ule_skb->data, dev->dev_addr);
 #endif
 #endif
 						dev_kfree_skb(priv->ule_skb);
 						dev_kfree_skb(priv->ule_skb);
 						goto sndu_done;
 						goto sndu_done;
@@ -964,8 +930,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev,
 	(*secfilter)->filter_mask[10] = mac_mask[1];
 	(*secfilter)->filter_mask[10] = mac_mask[1];
 	(*secfilter)->filter_mask[11]=mac_mask[0];
 	(*secfilter)->filter_mask[11]=mac_mask[0];
 
 
-	dprintk("%s: filter mac=%pM\n", dev->name, mac);
-	dprintk("%s: filter mask=%pM\n", dev->name, mac_mask);
+	netdev_dbg(dev, "filter mac=%pM mask=%pM\n", mac, mac_mask);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -977,7 +942,7 @@ static int dvb_net_feed_start(struct net_device *dev)
 	struct dmx_demux *demux = priv->demux;
 	struct dmx_demux *demux = priv->demux;
 	unsigned char *mac = (unsigned char *) dev->dev_addr;
 	unsigned char *mac = (unsigned char *) dev->dev_addr;
 
 
-	dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode);
+	netdev_dbg(dev, "rx_mode %i\n", priv->rx_mode);
 	mutex_lock(&priv->mutex);
 	mutex_lock(&priv->mutex);
 	if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
 	if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
 		printk("%s: BUG %d\n", __func__, __LINE__);
 		printk("%s: BUG %d\n", __func__, __LINE__);
@@ -987,7 +952,7 @@ static int dvb_net_feed_start(struct net_device *dev)
 	priv->tsfeed = NULL;
 	priv->tsfeed = NULL;
 
 
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
-		dprintk("%s: alloc secfeed\n", __func__);
+		netdev_dbg(dev, "alloc secfeed\n");
 		ret=demux->allocate_section_feed(demux, &priv->secfeed,
 		ret=demux->allocate_section_feed(demux, &priv->secfeed,
 					 dvb_net_sec_callback);
 					 dvb_net_sec_callback);
 		if (ret<0) {
 		if (ret<0) {
@@ -1005,38 +970,38 @@ static int dvb_net_feed_start(struct net_device *dev)
 		}
 		}
 
 
 		if (priv->rx_mode != RX_MODE_PROMISC) {
 		if (priv->rx_mode != RX_MODE_PROMISC) {
-			dprintk("%s: set secfilter\n", __func__);
+			netdev_dbg(dev, "set secfilter\n");
 			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
 			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
 		}
 		}
 
 
 		switch (priv->rx_mode) {
 		switch (priv->rx_mode) {
 		case RX_MODE_MULTI:
 		case RX_MODE_MULTI:
 			for (i = 0; i < priv->multi_num; i++) {
 			for (i = 0; i < priv->multi_num; i++) {
-				dprintk("%s: set multi_secfilter[%d]\n", __func__, i);
+				netdev_dbg(dev, "set multi_secfilter[%d]\n", i);
 				dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
 				dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
 						       priv->multi_macs[i], mask_normal);
 						       priv->multi_macs[i], mask_normal);
 			}
 			}
 			break;
 			break;
 		case RX_MODE_ALL_MULTI:
 		case RX_MODE_ALL_MULTI:
 			priv->multi_num=1;
 			priv->multi_num=1;
-			dprintk("%s: set multi_secfilter[0]\n", __func__);
+			netdev_dbg(dev, "set multi_secfilter[0]\n");
 			dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
 			dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
 					       mac_allmulti, mask_allmulti);
 					       mac_allmulti, mask_allmulti);
 			break;
 			break;
 		case RX_MODE_PROMISC:
 		case RX_MODE_PROMISC:
 			priv->multi_num=0;
 			priv->multi_num=0;
-			dprintk("%s: set secfilter\n", __func__);
+			netdev_dbg(dev, "set secfilter\n");
 			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
 			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
 			break;
 			break;
 		}
 		}
 
 
-		dprintk("%s: start filtering\n", __func__);
+		netdev_dbg(dev, "start filtering\n");
 		priv->secfeed->start_filtering(priv->secfeed);
 		priv->secfeed->start_filtering(priv->secfeed);
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
 		struct timespec timeout = { 0, 10000000 }; // 10 msec
 		struct timespec timeout = { 0, 10000000 }; // 10 msec
 
 
 		/* we have payloads encapsulated in TS */
 		/* we have payloads encapsulated in TS */
-		dprintk("%s: alloc tsfeed\n", __func__);
+		netdev_dbg(dev, "alloc tsfeed\n");
 		ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
 		ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
 		if (ret < 0) {
 		if (ret < 0) {
 			printk("%s: could not allocate ts feed\n", dev->name);
 			printk("%s: could not allocate ts feed\n", dev->name);
@@ -1060,7 +1025,7 @@ static int dvb_net_feed_start(struct net_device *dev)
 			goto error;
 			goto error;
 		}
 		}
 
 
-		dprintk("%s: start filtering\n", __func__);
+		netdev_dbg(dev, "start filtering\n");
 		priv->tsfeed->start_filtering(priv->tsfeed);
 		priv->tsfeed->start_filtering(priv->tsfeed);
 	} else
 	} else
 		ret = -EINVAL;
 		ret = -EINVAL;
@@ -1075,17 +1040,16 @@ static int dvb_net_feed_stop(struct net_device *dev)
 	struct dvb_net_priv *priv = netdev_priv(dev);
 	struct dvb_net_priv *priv = netdev_priv(dev);
 	int i, ret = 0;
 	int i, ret = 0;
 
 
-	dprintk("%s\n", __func__);
 	mutex_lock(&priv->mutex);
 	mutex_lock(&priv->mutex);
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
 		if (priv->secfeed) {
 		if (priv->secfeed) {
 			if (priv->secfeed->is_filtering) {
 			if (priv->secfeed->is_filtering) {
-				dprintk("%s: stop secfeed\n", __func__);
+				netdev_dbg(dev, "stop secfeed\n");
 				priv->secfeed->stop_filtering(priv->secfeed);
 				priv->secfeed->stop_filtering(priv->secfeed);
 			}
 			}
 
 
 			if (priv->secfilter) {
 			if (priv->secfilter) {
-				dprintk("%s: release secfilter\n", __func__);
+				netdev_dbg(dev, "release secfilter\n");
 				priv->secfeed->release_filter(priv->secfeed,
 				priv->secfeed->release_filter(priv->secfeed,
 							      priv->secfilter);
 							      priv->secfilter);
 				priv->secfilter=NULL;
 				priv->secfilter=NULL;
@@ -1093,8 +1057,8 @@ static int dvb_net_feed_stop(struct net_device *dev)
 
 
 			for (i=0; i<priv->multi_num; i++) {
 			for (i=0; i<priv->multi_num; i++) {
 				if (priv->multi_secfilter[i]) {
 				if (priv->multi_secfilter[i]) {
-					dprintk("%s: release multi_filter[%d]\n",
-						__func__, i);
+					netdev_dbg(dev, "release multi_filter[%d]\n",
+						   i);
 					priv->secfeed->release_filter(priv->secfeed,
 					priv->secfeed->release_filter(priv->secfeed,
 								      priv->multi_secfilter[i]);
 								      priv->multi_secfilter[i]);
 					priv->multi_secfilter[i] = NULL;
 					priv->multi_secfilter[i] = NULL;
@@ -1108,7 +1072,7 @@ static int dvb_net_feed_stop(struct net_device *dev)
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
 		if (priv->tsfeed) {
 		if (priv->tsfeed) {
 			if (priv->tsfeed->is_filtering) {
 			if (priv->tsfeed->is_filtering) {
-				dprintk("%s: stop tsfeed\n", __func__);
+				netdev_dbg(dev, "stop tsfeed\n");
 				priv->tsfeed->stop_filtering(priv->tsfeed);
 				priv->tsfeed->stop_filtering(priv->tsfeed);
 			}
 			}
 			priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
 			priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
@@ -1148,16 +1112,16 @@ static void wq_set_multicast_list (struct work_struct *work)
 	netif_addr_lock_bh(dev);
 	netif_addr_lock_bh(dev);
 
 
 	if (dev->flags & IFF_PROMISC) {
 	if (dev->flags & IFF_PROMISC) {
-		dprintk("%s: promiscuous mode\n", dev->name);
+		netdev_dbg(dev, "promiscuous mode\n");
 		priv->rx_mode = RX_MODE_PROMISC;
 		priv->rx_mode = RX_MODE_PROMISC;
 	} else if ((dev->flags & IFF_ALLMULTI)) {
 	} else if ((dev->flags & IFF_ALLMULTI)) {
-		dprintk("%s: allmulti mode\n", dev->name);
+		netdev_dbg(dev, "allmulti mode\n");
 		priv->rx_mode = RX_MODE_ALL_MULTI;
 		priv->rx_mode = RX_MODE_ALL_MULTI;
 	} else if (!netdev_mc_empty(dev)) {
 	} else if (!netdev_mc_empty(dev)) {
 		struct netdev_hw_addr *ha;
 		struct netdev_hw_addr *ha;
 
 
-		dprintk("%s: set_mc_list, %d entries\n",
-			dev->name, netdev_mc_count(dev));
+		netdev_dbg(dev, "set_mc_list, %d entries\n",
+			   netdev_mc_count(dev));
 
 
 		priv->rx_mode = RX_MODE_MULTI;
 		priv->rx_mode = RX_MODE_MULTI;
 		priv->multi_num = 0;
 		priv->multi_num = 0;

+ 3 - 1
drivers/media/dvb-frontends/Kconfig

@@ -443,7 +443,8 @@ config DVB_CXD2820R
 
 
 config DVB_RTL2830
 config DVB_RTL2830
 	tristate "Realtek RTL2830 DVB-T"
 	tristate "Realtek RTL2830 DVB-T"
-	depends on DVB_CORE && I2C
+	depends on DVB_CORE && I2C && I2C_MUX
+	select REGMAP
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
 	help
 	  Say Y when you want to support this frontend.
 	  Say Y when you want to support this frontend.
@@ -451,6 +452,7 @@ config DVB_RTL2830
 config DVB_RTL2832
 config DVB_RTL2832
 	tristate "Realtek RTL2832 DVB-T"
 	tristate "Realtek RTL2832 DVB-T"
 	depends on DVB_CORE && I2C && I2C_MUX
 	depends on DVB_CORE && I2C && I2C_MUX
+	select REGMAP
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
 	help
 	  Say Y when you want to support this frontend.
 	  Say Y when you want to support this frontend.

+ 0 - 5
drivers/media/dvb-frontends/au8522.h

@@ -91,8 +91,3 @@ enum au8522_audio_input {
 };
 };
 
 
 #endif /* __AU8522_H__ */
 #endif /* __AU8522_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */

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

@@ -1263,7 +1263,8 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
 	struct dib8000_state *state = fe->demodulator_priv;
 	struct dib8000_state *state = fe->demodulator_priv;
 	enum frontend_tune_state *tune_state = &state->tune_state;
 	enum frontend_tune_state *tune_state = &state->tune_state;
 	int ret = 0;
 	int ret = 0;
-	u16 reg, upd_demod_gain_period = 0x8000;
+	u16 reg;
+	u32 upd_demod_gain_period = 0x8000;
 
 
 	switch (*tune_state) {
 	switch (*tune_state) {
 	case CT_AGC_START:
 	case CT_AGC_START:

+ 7 - 3
drivers/media/dvb-frontends/hd29l2.c

@@ -22,20 +22,24 @@
 
 
 #include "hd29l2_priv.h"
 #include "hd29l2_priv.h"
 
 
+#define HD29L2_MAX_LEN (3)
+
 /* write multiple registers */
 /* write multiple registers */
 static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
 static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
 {
 {
 	int ret;
 	int ret;
-	u8 buf[2 + len];
+	u8 buf[2 + HD29L2_MAX_LEN];
 	struct i2c_msg msg[1] = {
 	struct i2c_msg msg[1] = {
 		{
 		{
 			.addr = priv->cfg.i2c_addr,
 			.addr = priv->cfg.i2c_addr,
 			.flags = 0,
 			.flags = 0,
-			.len = sizeof(buf),
+			.len = 2 + len,
 			.buf = buf,
 			.buf = buf,
 		}
 		}
 	};
 	};
 
 
+	if (len > HD29L2_MAX_LEN)
+		return -EINVAL;
 	buf[0] = 0x00;
 	buf[0] = 0x00;
 	buf[1] = reg;
 	buf[1] = reg;
 	memcpy(&buf[2], val, len);
 	memcpy(&buf[2], val, len);
@@ -118,7 +122,7 @@ static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask)
 }
 }
 
 
 /* read single register with mask */
 /* read single register with mask */
-int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask)
+static int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask)
 {
 {
 	int ret, i;
 	int ret, i;
 	u8 tmp;
 	u8 tmp;

+ 0 - 6
drivers/media/dvb-frontends/lg2160.c

@@ -1456,9 +1456,3 @@ MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_VERSION("0.3");
 MODULE_VERSION("0.3");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 8 - 15
drivers/media/dvb-frontends/lgdt3305.c

@@ -236,12 +236,13 @@ static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state,
 	return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode);
 	return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode);
 }
 }
 
 
-static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state,
-				       enum lgdt3305_tp_clock_edge edge,
-				       enum lgdt3305_tp_valid_polarity valid)
+static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state)
 {
 {
 	u8 val;
 	u8 val;
 	int ret;
 	int ret;
+	enum lgdt3305_tp_clock_edge edge = state->cfg->tpclk_edge;
+	enum lgdt3305_tp_clock_mode mode = state->cfg->tpclk_mode;
+	enum lgdt3305_tp_valid_polarity valid = state->cfg->tpvalid_polarity;
 
 
 	lg_dbg("edge = %d, valid = %d\n", edge, valid);
 	lg_dbg("edge = %d, valid = %d\n", edge, valid);
 
 
@@ -253,6 +254,8 @@ static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state,
 
 
 	if (edge)
 	if (edge)
 		val |= 0x08;
 		val |= 0x08;
+	if (mode)
+		val |= 0x40;
 	if (valid)
 	if (valid)
 		val |= 0x01;
 		val |= 0x01;
 
 
@@ -740,9 +743,7 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe)
 		goto fail;
 		goto fail;
 
 
 	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
 	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
-	ret = lgdt3305_mpeg_mode_polarity(state,
-					  state->cfg->tpclk_edge,
-					  state->cfg->tpvalid_polarity);
+	ret = lgdt3305_mpeg_mode_polarity(state);
 fail:
 fail:
 	return ret;
 	return ret;
 }
 }
@@ -806,9 +807,7 @@ static int lgdt3305_set_parameters(struct dvb_frontend *fe)
 		goto fail;
 		goto fail;
 
 
 	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
 	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
-	ret = lgdt3305_mpeg_mode_polarity(state,
-					  state->cfg->tpclk_edge,
-					  state->cfg->tpvalid_polarity);
+	ret = lgdt3305_mpeg_mode_polarity(state);
 fail:
 fail:
 	return ret;
 	return ret;
 }
 }
@@ -1215,9 +1214,3 @@ MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_VERSION("0.2");
 MODULE_VERSION("0.2");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

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

@@ -37,6 +37,11 @@ enum lgdt3305_tp_clock_edge {
 	LGDT3305_TPCLK_FALLING_EDGE = 1,
 	LGDT3305_TPCLK_FALLING_EDGE = 1,
 };
 };
 
 
+enum lgdt3305_tp_clock_mode {
+	LGDT3305_TPCLK_GATED = 0,
+	LGDT3305_TPCLK_FIXED = 1,
+};
+
 enum lgdt3305_tp_valid_polarity {
 enum lgdt3305_tp_valid_polarity {
 	LGDT3305_TP_VALID_LOW = 0,
 	LGDT3305_TP_VALID_LOW = 0,
 	LGDT3305_TP_VALID_HIGH = 1,
 	LGDT3305_TP_VALID_HIGH = 1,
@@ -70,6 +75,7 @@ struct lgdt3305_config {
 
 
 	enum lgdt3305_mpeg_mode mpeg_mode;
 	enum lgdt3305_mpeg_mode mpeg_mode;
 	enum lgdt3305_tp_clock_edge tpclk_edge;
 	enum lgdt3305_tp_clock_edge tpclk_edge;
+	enum lgdt3305_tp_clock_mode tpclk_mode;
 	enum lgdt3305_tp_valid_polarity tpvalid_polarity;
 	enum lgdt3305_tp_valid_polarity tpvalid_polarity;
 	enum lgdt_demod_chip_type demod_chip;
 	enum lgdt_demod_chip_type demod_chip;
 };
 };

+ 0 - 6
drivers/media/dvb-frontends/lgdt330x.c

@@ -823,9 +823,3 @@ MODULE_AUTHOR("Wilson Michaels");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 
 
 EXPORT_SYMBOL(lgdt330x_attach);
 EXPORT_SYMBOL(lgdt330x_attach);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

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

@@ -65,9 +65,3 @@ static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config*
 #endif // CONFIG_DVB_LGDT330X
 #endif // CONFIG_DVB_LGDT330X
 
 
 #endif /* LGDT330X_H */
 #endif /* LGDT330X_H */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

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

@@ -69,9 +69,3 @@ enum I2C_REG {
 };
 };
 
 
 #endif /* _LGDT330X_PRIV_ */
 #endif /* _LGDT330X_PRIV_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 0 - 4
drivers/media/dvb-frontends/mb86a20s.c

@@ -22,10 +22,6 @@
 
 
 #define NUM_LAYERS 3
 #define NUM_LAYERS 3
 
 
-static int debug = 1;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
 enum mb86a20s_bandwidth {
 enum mb86a20s_bandwidth {
 	MB86A20S_13SEG = 0,
 	MB86A20S_13SEG = 0,
 	MB86A20S_13SEG_PARTIAL = 1,
 	MB86A20S_13SEG_PARTIAL = 1,

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

@@ -33,6 +33,12 @@ struct mn88472_config {
 	 * DVB frontend.
 	 * DVB frontend.
 	 */
 	 */
 	struct dvb_frontend **fe;
 	struct dvb_frontend **fe;
+
+	/*
+	 * Xtal frequency.
+	 * Hz
+	 */
+	u32 xtal;
 };
 };
 
 
 #endif
 #endif

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

@@ -55,9 +55,3 @@ static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* c
 #endif // CONFIG_DVB_NXT200X
 #endif // CONFIG_DVB_NXT200X
 
 
 #endif /* NXT200X_H */
 #endif /* NXT200X_H */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 0 - 6
drivers/media/dvb-frontends/or51132.c

@@ -623,9 +623,3 @@ MODULE_AUTHOR("Trent Piepho");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 
 
 EXPORT_SYMBOL(or51132_attach);
 EXPORT_SYMBOL(or51132_attach);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

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

@@ -47,9 +47,3 @@ static inline struct dvb_frontend* or51132_attach(const struct or51132_config* c
 #endif // CONFIG_DVB_OR51132
 #endif // CONFIG_DVB_OR51132
 
 
 #endif // OR51132_H
 #endif // OR51132_H
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 551 - 393
drivers/media/dvb-frontends/rtl2830.c

@@ -13,261 +13,154 @@
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    GNU General Public License for more details.
  *    GNU General Public License for more details.
  *
  *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-
-/*
- * Driver implements own I2C-adapter for tuner I2C access. That's since chip
- * have unusual I2C-gate control which closes gate automatically after each
- * I2C transfer. Using own I2C adapter we can workaround that.
  */
  */
 
 
 #include "rtl2830_priv.h"
 #include "rtl2830_priv.h"
 
 
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  64
-
-/* write multiple hardware registers */
-static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, const u8 *val, int len)
+/* Our regmap is bypassing I2C adapter lock, thus we do it! */
+static int rtl2830_bulk_write(struct i2c_client *client, unsigned int reg,
+			      const void *val, size_t val_count)
 {
 {
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
-	u8 buf[MAX_XFER_SIZE];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = 1 + len,
-			.buf = buf,
-		}
-	};
-
-	if (1 + len > sizeof(buf)) {
-		dev_warn(&priv->i2c->dev,
-			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
-			 KBUILD_MODNAME, reg, len);
-		return -EINVAL;
-	}
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
 
 
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
-				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
+	i2c_lock_adapter(client->adapter);
+	ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
+	i2c_unlock_adapter(client->adapter);
 	return ret;
 	return ret;
 }
 }
 
 
-/* read multiple hardware registers */
-static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
+static int rtl2830_update_bits(struct i2c_client *client, unsigned int reg,
+			       unsigned int mask, unsigned int val)
 {
 {
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = priv->cfg.i2c_addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = val,
-		}
-	};
 
 
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
-				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
+	i2c_lock_adapter(client->adapter);
+	ret = regmap_update_bits(dev->regmap, reg, mask, val);
+	i2c_unlock_adapter(client->adapter);
 	return ret;
 	return ret;
 }
 }
 
 
-/* write multiple registers */
-static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, const u8 *val,
-		int len)
+static int rtl2830_bulk_read(struct i2c_client *client, unsigned int reg,
+			     void *val, size_t val_count)
 {
 {
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
-	u8 reg2 = (reg >> 0) & 0xff;
-	u8 page = (reg >> 8) & 0xff;
-
-	/* switch bank if needed */
-	if (page != priv->page) {
-		ret = rtl2830_wr(priv, 0x00, &page, 1);
-		if (ret)
-			return ret;
-
-		priv->page = page;
-	}
-
-	return rtl2830_wr(priv, reg2, val, len);
-}
-
-/* read multiple registers */
-static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
-{
-	int ret;
-	u8 reg2 = (reg >> 0) & 0xff;
-	u8 page = (reg >> 8) & 0xff;
-
-	/* switch bank if needed */
-	if (page != priv->page) {
-		ret = rtl2830_wr(priv, 0x00, &page, 1);
-		if (ret)
-			return ret;
-
-		priv->page = page;
-	}
 
 
-	return rtl2830_rd(priv, reg2, val, len);
-}
-
-/* read single register */
-static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val)
-{
-	return rtl2830_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-static int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask)
-{
-	int ret;
-	u8 tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return rtl2830_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register with mask */
-static int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask)
-{
-	int ret, i;
-	u8 tmp;
-
-	ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
-	if (ret)
-		return ret;
-
-	tmp &= mask;
-
-	/* find position of the first bit */
-	for (i = 0; i < 8; i++) {
-		if ((mask >> i) & 0x01)
-			break;
-	}
-	*val = tmp >> i;
-
-	return 0;
+	i2c_lock_adapter(client->adapter);
+	ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
+	i2c_unlock_adapter(client->adapter);
+	return ret;
 }
 }
 
 
 static int rtl2830_init(struct dvb_frontend *fe)
 static int rtl2830_init(struct dvb_frontend *fe)
 {
 {
-	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
+	struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
 	int ret, i;
 	int ret, i;
 	struct rtl2830_reg_val_mask tab[] = {
 	struct rtl2830_reg_val_mask tab[] = {
-		{ 0x00d, 0x01, 0x03 },
-		{ 0x00d, 0x10, 0x10 },
-		{ 0x104, 0x00, 0x1e },
-		{ 0x105, 0x80, 0x80 },
-		{ 0x110, 0x02, 0x03 },
-		{ 0x110, 0x08, 0x0c },
-		{ 0x17b, 0x00, 0x40 },
-		{ 0x17d, 0x05, 0x0f },
-		{ 0x17d, 0x50, 0xf0 },
-		{ 0x18c, 0x08, 0x0f },
-		{ 0x18d, 0x00, 0xc0 },
-		{ 0x188, 0x05, 0x0f },
-		{ 0x189, 0x00, 0xfc },
-		{ 0x2d5, 0x02, 0x02 },
-		{ 0x2f1, 0x02, 0x06 },
-		{ 0x2f1, 0x20, 0xf8 },
-		{ 0x16d, 0x00, 0x01 },
-		{ 0x1a6, 0x00, 0x80 },
-		{ 0x106, priv->cfg.vtop, 0x3f },
-		{ 0x107, priv->cfg.krf, 0x3f },
-		{ 0x112, 0x28, 0xff },
-		{ 0x103, priv->cfg.agc_targ_val, 0xff },
-		{ 0x00a, 0x02, 0x07 },
-		{ 0x140, 0x0c, 0x3c },
-		{ 0x140, 0x40, 0xc0 },
-		{ 0x15b, 0x05, 0x07 },
-		{ 0x15b, 0x28, 0x38 },
-		{ 0x15c, 0x05, 0x07 },
-		{ 0x15c, 0x28, 0x38 },
-		{ 0x115, priv->cfg.spec_inv, 0x01 },
-		{ 0x16f, 0x01, 0x07 },
-		{ 0x170, 0x18, 0x38 },
-		{ 0x172, 0x0f, 0x0f },
-		{ 0x173, 0x08, 0x38 },
-		{ 0x175, 0x01, 0x07 },
-		{ 0x176, 0x00, 0xc0 },
+		{0x00d, 0x01, 0x03},
+		{0x00d, 0x10, 0x10},
+		{0x104, 0x00, 0x1e},
+		{0x105, 0x80, 0x80},
+		{0x110, 0x02, 0x03},
+		{0x110, 0x08, 0x0c},
+		{0x17b, 0x00, 0x40},
+		{0x17d, 0x05, 0x0f},
+		{0x17d, 0x50, 0xf0},
+		{0x18c, 0x08, 0x0f},
+		{0x18d, 0x00, 0xc0},
+		{0x188, 0x05, 0x0f},
+		{0x189, 0x00, 0xfc},
+		{0x2d5, 0x02, 0x02},
+		{0x2f1, 0x02, 0x06},
+		{0x2f1, 0x20, 0xf8},
+		{0x16d, 0x00, 0x01},
+		{0x1a6, 0x00, 0x80},
+		{0x106, dev->pdata->vtop, 0x3f},
+		{0x107, dev->pdata->krf, 0x3f},
+		{0x112, 0x28, 0xff},
+		{0x103, dev->pdata->agc_targ_val, 0xff},
+		{0x00a, 0x02, 0x07},
+		{0x140, 0x0c, 0x3c},
+		{0x140, 0x40, 0xc0},
+		{0x15b, 0x05, 0x07},
+		{0x15b, 0x28, 0x38},
+		{0x15c, 0x05, 0x07},
+		{0x15c, 0x28, 0x38},
+		{0x115, dev->pdata->spec_inv, 0x01},
+		{0x16f, 0x01, 0x07},
+		{0x170, 0x18, 0x38},
+		{0x172, 0x0f, 0x0f},
+		{0x173, 0x08, 0x38},
+		{0x175, 0x01, 0x07},
+		{0x176, 0x00, 0xc0},
 	};
 	};
 
 
 	for (i = 0; i < ARRAY_SIZE(tab); i++) {
 	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val,
-			tab[i].mask);
+		ret = rtl2830_update_bits(client, tab[i].reg, tab[i].mask,
+					  tab[i].val);
 		if (ret)
 		if (ret)
 			goto err;
 			goto err;
 	}
 	}
 
 
-	ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2);
+	ret = rtl2830_bulk_write(client, 0x18f, "\x28\x00", 2);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2830_wr_regs(priv, 0x195,
-		"\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
+	ret = rtl2830_bulk_write(client, 0x195,
+				 "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* TODO: spec init */
 	/* TODO: spec init */
 
 
 	/* soft reset */
 	/* soft reset */
-	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04);
+	ret = rtl2830_update_bits(client, 0x101, 0x04, 0x04);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04);
+	ret = rtl2830_update_bits(client, 0x101, 0x04, 0x00);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	priv->sleeping = false;
+	/* init stats here in order signal app which stats are supported */
+	c->strength.len = 1;
+	c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->cnr.len = 1;
+	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_error.len = 1;
+	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_count.len = 1;
+	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	/* start statistics polling */
+	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+
+	dev->sleeping = false;
 
 
 	return ret;
 	return ret;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int rtl2830_sleep(struct dvb_frontend *fe)
 static int rtl2830_sleep(struct dvb_frontend *fe)
 {
 {
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	priv->sleeping = true;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
+
+	dev->sleeping = true;
+	/* stop statistics polling */
+	cancel_delayed_work_sync(&dev->stat_work);
+	dev->fe_status = 0;
+
 	return 0;
 	return 0;
 }
 }
 
 
 static int rtl2830_get_tune_settings(struct dvb_frontend *fe,
 static int rtl2830_get_tune_settings(struct dvb_frontend *fe,
-	struct dvb_frontend_tune_settings *s)
+				     struct dvb_frontend_tune_settings *s)
 {
 {
 	s->min_delay_ms = 500;
 	s->min_delay_ms = 500;
 	s->step_size = fe->ops.info.frequency_stepsize * 2;
 	s->step_size = fe->ops.info.frequency_stepsize * 2;
@@ -278,11 +171,12 @@ static int rtl2830_get_tune_settings(struct dvb_frontend *fe,
 
 
 static int rtl2830_set_frontend(struct dvb_frontend *fe)
 static int rtl2830_set_frontend(struct dvb_frontend *fe)
 {
 {
-	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret, i;
 	int ret, i;
 	u64 num;
 	u64 num;
-	u8 buf[3], tmp;
+	u8 buf[3], u8tmp;
 	u32 if_ctl, if_frequency;
 	u32 if_ctl, if_frequency;
 	static const u8 bw_params1[3][34] = {
 	static const u8 bw_params1[3][34] = {
 		{
 		{
@@ -308,9 +202,8 @@ static int rtl2830_set_frontend(struct dvb_frontend *fe)
 		{0xae, 0xba, 0xf3, 0x26, 0x66, 0x64}, /* 8 MHz */
 		{0xae, 0xba, 0xf3, 0x26, 0x66, 0x64}, /* 8 MHz */
 	};
 	};
 
 
-	dev_dbg(&priv->i2c->dev,
-			"%s: frequency=%d bandwidth_hz=%d inversion=%d\n",
-			__func__, c->frequency, c->bandwidth_hz, c->inversion);
+	dev_dbg(&client->dev, "frequency=%u bandwidth_hz=%u inversion=%u\n",
+		c->frequency, c->bandwidth_hz, c->inversion);
 
 
 	/* program tuner */
 	/* program tuner */
 	if (fe->ops.tuner_ops.set_params)
 	if (fe->ops.tuner_ops.set_params)
@@ -327,11 +220,12 @@ static int rtl2830_set_frontend(struct dvb_frontend *fe)
 		i = 2;
 		i = 2;
 		break;
 		break;
 	default:
 	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid bandwidth\n", __func__);
+		dev_err(&client->dev, "invalid bandwidth_hz %u\n",
+			c->bandwidth_hz);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06);
+	ret = rtl2830_update_bits(client, 0x008, 0x06, i << 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -340,70 +234,71 @@ static int rtl2830_set_frontend(struct dvb_frontend *fe)
 		ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
 		ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
 	else
 	else
 		ret = -EINVAL;
 		ret = -EINVAL;
-
-	if (ret < 0)
+	if (ret)
 		goto err;
 		goto err;
 
 
-	num = if_frequency % priv->cfg.xtal;
+	num = if_frequency % dev->pdata->clk;
 	num *= 0x400000;
 	num *= 0x400000;
-	num = div_u64(num, priv->cfg.xtal);
+	num = div_u64(num, dev->pdata->clk);
 	num = -num;
 	num = -num;
 	if_ctl = num & 0x3fffff;
 	if_ctl = num & 0x3fffff;
-	dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d if_ctl=%08x\n",
-			__func__, if_frequency, if_ctl);
+	dev_dbg(&client->dev, "if_frequency=%d if_ctl=%08x\n",
+		if_frequency, if_ctl);
 
 
-	ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */
+	buf[0] = (if_ctl >> 16) & 0x3f;
+	buf[1] = (if_ctl >>  8) & 0xff;
+	buf[2] = (if_ctl >>  0) & 0xff;
+
+	ret = rtl2830_bulk_read(client, 0x119, &u8tmp, 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	buf[0] = tmp << 6;
-	buf[0] |= (if_ctl >> 16) & 0x3f;
-	buf[1] = (if_ctl >>  8) & 0xff;
-	buf[2] = (if_ctl >>  0) & 0xff;
+	buf[0] |= u8tmp & 0xc0;  /* [7:6] */
 
 
-	ret = rtl2830_wr_regs(priv, 0x119, buf, 3);
+	ret = rtl2830_bulk_write(client, 0x119, buf, 3);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* 1/2 split I2C write */
 	/* 1/2 split I2C write */
-	ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17);
+	ret = rtl2830_bulk_write(client, 0x11c, &bw_params1[i][0], 17);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* 2/2 split I2C write */
 	/* 2/2 split I2C write */
-	ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17);
+	ret = rtl2830_bulk_write(client, 0x12d, &bw_params1[i][17], 17);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6);
+	ret = rtl2830_bulk_write(client, 0x19d, bw_params2[i], 6);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	return ret;
 	return ret;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int rtl2830_get_frontend(struct dvb_frontend *fe)
 static int rtl2830_get_frontend(struct dvb_frontend *fe)
 {
 {
-	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
 	int ret;
 	u8 buf[3];
 	u8 buf[3];
 
 
-	if (priv->sleeping)
+	if (dev->sleeping)
 		return 0;
 		return 0;
 
 
-	ret = rtl2830_rd_regs(priv, 0x33c, buf, 2);
+	ret = rtl2830_bulk_read(client, 0x33c, buf, 2);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2830_rd_reg(priv, 0x351, &buf[2]);
+	ret = rtl2830_bulk_read(client, 0x351, &buf[2], 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	dev_dbg(&priv->i2c->dev, "%s: TPS=%*ph\n", __func__, 3, buf);
+	dev_dbg(&client->dev, "TPS=%*ph\n", 3, buf);
 
 
 	switch ((buf[0] >> 2) & 3) {
 	switch ((buf[0] >> 2) & 3) {
 	case 0:
 	case 0:
@@ -493,280 +388,543 @@ static int rtl2830_get_frontend(struct dvb_frontend *fe)
 
 
 	return 0;
 	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
 static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
 {
-	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
-	u8 tmp;
+	u8 u8tmp;
+
 	*status = 0;
 	*status = 0;
 
 
-	if (priv->sleeping)
+	if (dev->sleeping)
 		return 0;
 		return 0;
 
 
-	ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */
+	ret = rtl2830_bulk_read(client, 0x351, &u8tmp, 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	if (tmp == 11) {
+	u8tmp = (u8tmp >> 3) & 0x0f; /* [6:3] */
+	if (u8tmp == 11) {
 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
 			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-	} else if (tmp == 10) {
+	} else if (u8tmp == 10) {
 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
 			FE_HAS_VITERBI;
 			FE_HAS_VITERBI;
 	}
 	}
 
 
+	dev->fe_status = *status;
+
 	return ret;
 	return ret;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
 static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
 {
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	int ret, hierarchy, constellation;
-	u8 buf[2], tmp;
-	u16 tmp16;
-#define CONSTELLATION_NUM 3
-#define HIERARCHY_NUM 4
-	static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
-		{ 70705899, 70705899, 70705899, 70705899 },
-		{ 82433173, 82433173, 87483115, 94445660 },
-		{ 92888734, 92888734, 95487525, 99770748 },
-	};
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
 
-	if (priv->sleeping)
-		return 0;
+	if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
+		*snr = div_s64(c->cnr.stat[0].svalue, 100);
+	else
+		*snr = 0;
 
 
-	/* reports SNR in resolution of 0.1 dB */
+	return 0;
+}
 
 
-	ret = rtl2830_rd_reg(priv, 0x33c, &tmp);
-	if (ret)
-		goto err;
+static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct i2c_client *client = fe->demodulator_priv;
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 
 
-	constellation = (tmp >> 2) & 0x03; /* [3:2] */
-	if (constellation > CONSTELLATION_NUM - 1)
-		goto err;
+	*ber = (dev->post_bit_error - dev->post_bit_error_prev);
+	dev->post_bit_error_prev = dev->post_bit_error;
 
 
-	hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
-	if (hierarchy > HIERARCHY_NUM - 1)
-		goto err;
+	return 0;
+}
 
 
-	ret = rtl2830_rd_regs(priv, 0x40c, buf, 2);
-	if (ret)
-		goto err;
+static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
 
 
-	tmp16 = buf[0] << 8 | buf[1];
+	return 0;
+}
+
+static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
 
-	if (tmp16)
-		*snr = (snr_constant[constellation][hierarchy] -
-				intlog10(tmp16)) / ((1 << 24) / 100);
+	if (c->strength.stat[0].scale == FE_SCALE_RELATIVE)
+		*strength = c->strength.stat[0].uvalue;
 	else
 	else
-		*snr = 0;
+		*strength = 0;
 
 
 	return 0;
 	return 0;
+}
+
+static struct dvb_frontend_ops rtl2830_ops = {
+	.delsys = {SYS_DVBT},
+	.info = {
+		.name = "Realtek RTL2830 (DVB-T)",
+		.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_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.init = rtl2830_init,
+	.sleep = rtl2830_sleep,
+
+	.get_tune_settings = rtl2830_get_tune_settings,
+
+	.set_frontend = rtl2830_set_frontend,
+	.get_frontend = rtl2830_get_frontend,
+
+	.read_status = rtl2830_read_status,
+	.read_snr = rtl2830_read_snr,
+	.read_ber = rtl2830_read_ber,
+	.read_ucblocks = rtl2830_read_ucblocks,
+	.read_signal_strength = rtl2830_read_signal_strength,
+};
+
+static void rtl2830_stat_work(struct work_struct *work)
+{
+	struct rtl2830_dev *dev = container_of(work, struct rtl2830_dev, stat_work.work);
+	struct i2c_client *client = dev->client;
+	struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+	int ret, tmp;
+	u8 u8tmp, buf[2];
+	u16 u16tmp;
+
+	dev_dbg(&client->dev, "\n");
+
+	/* signal strength */
+	if (dev->fe_status & FE_HAS_SIGNAL) {
+		struct {signed int x:14; } s;
+
+		/* read IF AGC */
+		ret = rtl2830_bulk_read(client, 0x359, buf, 2);
+		if (ret)
+			goto err;
+
+		u16tmp = buf[0] << 8 | buf[1] << 0;
+		u16tmp &= 0x3fff; /* [13:0] */
+		tmp = s.x = u16tmp; /* 14-bit bin to 2 complement */
+		u16tmp = clamp_val(-4 * tmp + 32767, 0x0000, 0xffff);
+
+		dev_dbg(&client->dev, "IF AGC=%d\n", tmp);
+
+		c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+		c->strength.stat[0].uvalue = u16tmp;
+	} else {
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
+
+	/* CNR */
+	if (dev->fe_status & FE_HAS_VITERBI) {
+		unsigned hierarchy, constellation;
+		#define CONSTELLATION_NUM 3
+		#define HIERARCHY_NUM 4
+		static const u32 constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
+			{70705899, 70705899, 70705899, 70705899},
+			{82433173, 82433173, 87483115, 94445660},
+			{92888734, 92888734, 95487525, 99770748},
+		};
+
+		ret = rtl2830_bulk_read(client, 0x33c, &u8tmp, 1);
+		if (ret)
+			goto err;
+
+		constellation = (u8tmp >> 2) & 0x03; /* [3:2] */
+		if (constellation > CONSTELLATION_NUM - 1)
+			goto err_schedule_delayed_work;
+
+		hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */
+		if (hierarchy > HIERARCHY_NUM - 1)
+			goto err_schedule_delayed_work;
+
+		ret = rtl2830_bulk_read(client, 0x40c, buf, 2);
+		if (ret)
+			goto err;
+
+		u16tmp = buf[0] << 8 | buf[1] << 0;
+		if (u16tmp)
+			tmp = (constant[constellation][hierarchy] -
+			       intlog10(u16tmp)) / ((1 << 24) / 10000);
+		else
+			tmp = 0;
+
+		dev_dbg(&client->dev, "CNR raw=%u\n", u16tmp);
+
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = tmp;
+	} else {
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
+
+	/* BER */
+	if (dev->fe_status & FE_HAS_LOCK) {
+		ret = rtl2830_bulk_read(client, 0x34e, buf, 2);
+		if (ret)
+			goto err;
+
+		u16tmp = buf[0] << 8 | buf[1] << 0;
+		dev->post_bit_error += u16tmp;
+		dev->post_bit_count += 1000000;
+
+		dev_dbg(&client->dev, "BER errors=%u total=1000000\n", u16tmp);
+
+		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
+		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_count.stat[0].uvalue = dev->post_bit_count;
+	} else {
+		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
+
+err_schedule_delayed_work:
+	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+	return;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 }
 }
 
 
-static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
+static int rtl2830_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
 {
 {
-	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
 	int ret;
 	int ret;
-	u8 buf[2];
+	u8 u8tmp;
 
 
-	if (priv->sleeping)
-		return 0;
+	dev_dbg(&client->dev, "onoff=%d\n", onoff);
+
+	/* enable / disable PID filter */
+	if (onoff)
+		u8tmp = 0x80;
+	else
+		u8tmp = 0x00;
 
 
-	ret = rtl2830_rd_regs(priv, 0x34e, buf, 2);
+	ret = rtl2830_update_bits(client, 0x061, 0x80, u8tmp);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	*ber = buf[0] << 8 | buf[1];
-
 	return 0;
 	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
-static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+static int rtl2830_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, int onoff)
 {
 {
-	*ucblocks = 0;
-	return 0;
-}
-
-static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
-	u8 buf[2];
-	u16 if_agc_raw, if_agc;
+	u8 buf[4];
 
 
-	if (priv->sleeping)
+	dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n",
+		index, pid, onoff);
+
+	/* skip invalid PIDs (0x2000) */
+	if (pid > 0x1fff || index > 32)
 		return 0;
 		return 0;
 
 
-	ret = rtl2830_rd_regs(priv, 0x359, buf, 2);
+	if (onoff)
+		set_bit(index, &dev->filters);
+	else
+		clear_bit(index, &dev->filters);
+
+	/* enable / disable PIDs */
+	buf[0] = (dev->filters >>  0) & 0xff;
+	buf[1] = (dev->filters >>  8) & 0xff;
+	buf[2] = (dev->filters >> 16) & 0xff;
+	buf[3] = (dev->filters >> 24) & 0xff;
+	ret = rtl2830_bulk_write(client, 0x062, buf, 4);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff;
-
-	if (if_agc_raw & (1 << 9))
-		if_agc = -(~(if_agc_raw - 1) & 0x1ff);
-	else
-		if_agc = if_agc_raw;
-
-	*strength = (u8) (55 - if_agc / 182);
-	*strength |= *strength << 8;
+	/* add PID */
+	buf[0] = (pid >> 8) & 0xff;
+	buf[1] = (pid >> 0) & 0xff;
+	ret = rtl2830_bulk_write(client, 0x066 + 2 * index, buf, 2);
+	if (ret)
+		goto err;
 
 
 	return 0;
 	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
-static struct dvb_frontend_ops rtl2830_ops;
-
-static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C;
-}
-
-static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
-	struct i2c_msg msg[], int num)
+/*
+ * I2C gate/mux/repeater logic
+ * We must use unlocked __i2c_transfer() here (through regmap) because of I2C
+ * adapter lock is already taken by tuner driver.
+ * Gate is closed automatically after single I2C transfer.
+ */
+static int rtl2830_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
 {
 {
-	struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap);
+	struct i2c_client *client = mux_priv;
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
 
 
-	/* open i2c-gate */
-	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08);
+	dev_dbg(&client->dev, "\n");
+
+	/* open I2C repeater for 1 transfer, closes automatically */
+	/* XXX: regmap_update_bits() does not lock I2C adapter */
+	ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = i2c_transfer(priv->i2c, msg, num);
-	if (ret < 0)
-		dev_warn(&priv->i2c->dev, "%s: tuner i2c failed=%d\n",
-			KBUILD_MODNAME, ret);
-
-	return ret;
+	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
-static struct i2c_algorithm rtl2830_tuner_i2c_algo = {
-	.master_xfer   = rtl2830_tuner_i2c_xfer,
-	.functionality = rtl2830_tuner_i2c_func,
-};
+static struct dvb_frontend *rtl2830_get_dvb_frontend(struct i2c_client *client)
+{
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 
 
-struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+	dev_dbg(&client->dev, "\n");
+
+	return &dev->fe;
+}
+
+static struct i2c_adapter *rtl2830_get_i2c_adapter(struct i2c_client *client)
 {
 {
-	struct rtl2830_priv *priv = fe->demodulator_priv;
-	return &priv->tuner_i2c_adapter;
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "\n");
+
+	return dev->adapter;
 }
 }
-EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter);
 
 
-static void rtl2830_release(struct dvb_frontend *fe)
+/*
+ * We implement own I2C access routines for regmap in order to get manual access
+ * to I2C adapter lock, which is needed for I2C mux adapter.
+ */
+static int rtl2830_regmap_read(void *context, const void *reg_buf,
+			       size_t reg_size, void *val_buf, size_t val_size)
 {
 {
-	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct i2c_client *client = context;
+	int ret;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = reg_size,
+			.buf = (u8 *)reg_buf,
+		}, {
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = val_size,
+			.buf = val_buf,
+		}
+	};
 
 
-	i2c_del_adapter(&priv->tuner_i2c_adapter);
-	kfree(priv);
+	ret = __i2c_transfer(client->adapter, msg, 2);
+	if (ret != 2) {
+		dev_warn(&client->dev, "i2c reg read failed %d\n", ret);
+		if (ret >= 0)
+			ret = -EREMOTEIO;
+		return ret;
+	}
+	return 0;
 }
 }
 
 
-struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg,
-	struct i2c_adapter *i2c)
+static int rtl2830_regmap_write(void *context, const void *data, size_t count)
 {
 {
-	struct rtl2830_priv *priv = NULL;
-	int ret = 0;
-	u8 tmp;
+	struct i2c_client *client = context;
+	int ret;
+	struct i2c_msg msg[1] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = count,
+			.buf = (u8 *)data,
+		}
+	};
+
+	ret = __i2c_transfer(client->adapter, msg, 1);
+	if (ret != 1) {
+		dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+		if (ret >= 0)
+			ret = -EREMOTEIO;
+		return ret;
+	}
+	return 0;
+}
+
+static int rtl2830_regmap_gather_write(void *context, const void *reg,
+				       size_t reg_len, const void *val,
+				       size_t val_len)
+{
+	struct i2c_client *client = context;
+	int ret;
+	u8 buf[256];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1 + val_len,
+			.buf = buf,
+		}
+	};
+
+	buf[0] = *(u8 const *)reg;
+	memcpy(&buf[1], val, val_len);
+
+	ret = __i2c_transfer(client->adapter, msg, 1);
+	if (ret != 1) {
+		dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+		if (ret >= 0)
+			ret = -EREMOTEIO;
+		return ret;
+	}
+	return 0;
+}
+
+static int rtl2830_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct rtl2830_platform_data *pdata = client->dev.platform_data;
+	struct rtl2830_dev *dev;
+	int ret;
+	u8 u8tmp;
+	static const struct regmap_bus regmap_bus = {
+		.read = rtl2830_regmap_read,
+		.write = rtl2830_regmap_write,
+		.gather_write = rtl2830_regmap_gather_write,
+		.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	};
+	static const struct regmap_range_cfg regmap_range_cfg[] = {
+		{
+			.selector_reg     = 0x00,
+			.selector_mask    = 0xff,
+			.selector_shift   = 0,
+			.window_start     = 0,
+			.window_len       = 0x100,
+			.range_min        = 0 * 0x100,
+			.range_max        = 5 * 0x100,
+		},
+	};
+	static const struct regmap_config regmap_config = {
+		.reg_bits    =  8,
+		.val_bits    =  8,
+		.max_register = 5 * 0x100,
+		.ranges = regmap_range_cfg,
+		.num_ranges = ARRAY_SIZE(regmap_range_cfg),
+	};
+
+	dev_dbg(&client->dev, "\n");
+
+	if (pdata == NULL) {
+		ret = -EINVAL;
+		goto err;
+	}
 
 
 	/* allocate memory for the internal state */
 	/* allocate memory for the internal state */
-	priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL);
-	if (priv == NULL)
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		ret = -ENOMEM;
 		goto err;
 		goto err;
+	}
 
 
-	/* setup the priv */
-	priv->i2c = i2c;
-	memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config));
+	/* setup the state */
+	i2c_set_clientdata(client, dev);
+	dev->client = client;
+	dev->pdata = client->dev.platform_data;
+	dev->sleeping = true;
+	INIT_DELAYED_WORK(&dev->stat_work, rtl2830_stat_work);
+	dev->regmap = regmap_init(&client->dev, &regmap_bus, client,
+				  &regmap_config);
+	if (IS_ERR(dev->regmap)) {
+		ret = PTR_ERR(dev->regmap);
+		goto err_kfree;
+	}
 
 
 	/* check if the demod is there */
 	/* check if the demod is there */
-	ret = rtl2830_rd_reg(priv, 0x000, &tmp);
+	ret = rtl2830_bulk_read(client, 0x000, &u8tmp, 1);
 	if (ret)
 	if (ret)
-		goto err;
-
-	/* create dvb_frontend */
-	memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops));
-	priv->fe.demodulator_priv = priv;
-
-	/* create tuner i2c adapter */
-	strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter",
-		sizeof(priv->tuner_i2c_adapter.name));
-	priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo;
-	priv->tuner_i2c_adapter.algo_data = NULL;
-	priv->tuner_i2c_adapter.dev.parent = &i2c->dev;
-	i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
-	if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
-		dev_err(&i2c->dev,
-				"%s: tuner i2c bus could not be initialized\n",
-				KBUILD_MODNAME);
-		goto err;
+		goto err_regmap_exit;
+
+	/* create muxed i2c adapter for tuner */
+	dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+			client, 0, 0, 0, rtl2830_select, NULL);
+	if (dev->adapter == NULL) {
+		ret = -ENODEV;
+		goto err_regmap_exit;
 	}
 	}
 
 
-	priv->sleeping = true;
+	/* create dvb frontend */
+	memcpy(&dev->fe.ops, &rtl2830_ops, sizeof(dev->fe.ops));
+	dev->fe.demodulator_priv = client;
+
+	/* setup callbacks */
+	pdata->get_dvb_frontend = rtl2830_get_dvb_frontend;
+	pdata->get_i2c_adapter = rtl2830_get_i2c_adapter;
+	pdata->pid_filter = rtl2830_pid_filter;
+	pdata->pid_filter_ctrl = rtl2830_pid_filter_ctrl;
 
 
-	return &priv->fe;
+	dev_info(&client->dev, "Realtek RTL2830 successfully attached\n");
+
+	return 0;
+err_regmap_exit:
+	regmap_exit(dev->regmap);
+err_kfree:
+	kfree(dev);
 err:
 err:
-	dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
-	kfree(priv);
-	return NULL;
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+	return ret;
 }
 }
-EXPORT_SYMBOL(rtl2830_attach);
 
 
-static struct dvb_frontend_ops rtl2830_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "Realtek RTL2830 (DVB-T)",
-		.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_64 |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO |
-			FE_CAN_RECOVER |
-			FE_CAN_MUTE_TS
-	},
+static int rtl2830_remove(struct i2c_client *client)
+{
+	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 
 
-	.release = rtl2830_release,
+	dev_dbg(&client->dev, "\n");
 
 
-	.init = rtl2830_init,
-	.sleep = rtl2830_sleep,
+	i2c_del_mux_adapter(dev->adapter);
+	regmap_exit(dev->regmap);
+	kfree(dev);
 
 
-	.get_tune_settings = rtl2830_get_tune_settings,
+	return 0;
+}
 
 
-	.set_frontend = rtl2830_set_frontend,
-	.get_frontend = rtl2830_get_frontend,
+static const struct i2c_device_id rtl2830_id_table[] = {
+	{"rtl2830", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rtl2830_id_table);
 
 
-	.read_status = rtl2830_read_status,
-	.read_snr = rtl2830_read_snr,
-	.read_ber = rtl2830_read_ber,
-	.read_ucblocks = rtl2830_read_ucblocks,
-	.read_signal_strength = rtl2830_read_signal_strength,
+static struct i2c_driver rtl2830_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "rtl2830",
+	},
+	.probe		= rtl2830_probe,
+	.remove		= rtl2830_remove,
+	.id_table	= rtl2830_id_table,
 };
 };
 
 
+module_i2c_driver(rtl2830_driver);
+
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
 MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 19 - 60
drivers/media/dvb-frontends/rtl2830.h

@@ -13,78 +13,37 @@
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    GNU General Public License for more details.
  *    GNU General Public License for more details.
  *
  *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
  */
 
 
 #ifndef RTL2830_H
 #ifndef RTL2830_H
 #define RTL2830_H
 #define RTL2830_H
 
 
-#include <linux/kconfig.h>
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/frontend.h>
 
 
-struct rtl2830_config {
-	/*
-	 * Demodulator I2C address.
-	 */
-	u8 i2c_addr;
-
-	/*
-	 * Xtal frequency.
-	 * Hz
-	 * 4000000, 16000000, 25000000, 28800000
-	 */
-	u32 xtal;
-
-	/*
-	 * TS output mode.
-	 */
-	u8 ts_mode;
+/**
+ * struct rtl2830_platform_data - Platform data for the rtl2830 driver
+ * @clk: Clock frequency (4000000, 16000000, 25000000, 28800000).
+ * @spec_inv: Spectrum inversion.
+ * @vtop: AGC take-over point.
+ * @krf: AGC ratio.
+ * @agc_targ_val: AGC.
+ * @get_dvb_frontend: Get DVB frontend.
+ * @get_i2c_adapter: Get I2C adapter.
+ * @pid_filter: Set PID to PID filter.
+ * @pid_filter_ctrl: Control PID filter.
+ */
 
 
-	/*
-	 * Spectrum inversion.
-	 */
+struct rtl2830_platform_data {
+	u32 clk;
 	bool spec_inv;
 	bool spec_inv;
-
-	/*
-	 */
 	u8 vtop;
 	u8 vtop;
-
-	/*
-	 */
 	u8 krf;
 	u8 krf;
-
-	/*
-	 */
 	u8 agc_targ_val;
 	u8 agc_targ_val;
-};
-
-#if IS_ENABLED(CONFIG_DVB_RTL2830)
-extern struct dvb_frontend *rtl2830_attach(
-	const struct rtl2830_config *config,
-	struct i2c_adapter *i2c
-);
 
 
-extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
-	struct dvb_frontend *fe
-);
-#else
-static inline struct dvb_frontend *rtl2830_attach(
-	const struct rtl2830_config *config,
-	struct i2c_adapter *i2c
-)
-{
-	pr_warn("%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
-	struct dvb_frontend *fe
-)
-{
-	return NULL;
-}
-#endif
+	struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
+	struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *);
+	int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
+	int (*pid_filter_ctrl)(struct dvb_frontend *, int);
+};
 
 
 #endif /* RTL2830_H */
 #endif /* RTL2830_H */

+ 14 - 10
drivers/media/dvb-frontends/rtl2830_priv.h

@@ -13,9 +13,6 @@
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    GNU General Public License for more details.
  *    GNU General Public License for more details.
  *
  *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
  */
 
 
 #ifndef RTL2830_PRIV_H
 #ifndef RTL2830_PRIV_H
@@ -24,16 +21,23 @@
 #include "dvb_frontend.h"
 #include "dvb_frontend.h"
 #include "dvb_math.h"
 #include "dvb_math.h"
 #include "rtl2830.h"
 #include "rtl2830.h"
+#include <linux/i2c-mux.h>
+#include <linux/math64.h>
+#include <linux/regmap.h>
 
 
-struct rtl2830_priv {
-	struct i2c_adapter *i2c;
+struct rtl2830_dev {
+	struct rtl2830_platform_data *pdata;
+	struct i2c_client *client;
+	struct regmap *regmap;
+	struct i2c_adapter *adapter;
 	struct dvb_frontend fe;
 	struct dvb_frontend fe;
-	struct rtl2830_config cfg;
-	struct i2c_adapter tuner_i2c_adapter;
-
 	bool sleeping;
 	bool sleeping;
-
-	u8 page; /* active register page */
+	unsigned long filters;
+	struct delayed_work stat_work;
+	fe_status_t fe_status;
+	u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */
+	u64 post_bit_error;
+	u64 post_bit_count;
 };
 };
 
 
 struct rtl2830_reg_val_mask {
 struct rtl2830_reg_val_mask {

+ 737 - 599
drivers/media/dvb-frontends/rtl2832.c

@@ -2,6 +2,7 @@
  * Realtek RTL2832 DVB-T demodulator driver
  * Realtek RTL2832 DVB-T demodulator driver
  *
  *
  * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
  * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ * Copyright (C) 2012-2014 Antti Palosaari <crope@iki.fi>
  *
  *
  *	This program is free software; you can redistribute it and/or modify
  *	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
  *	it under the terms of the GNU General Public License as published by
@@ -19,280 +20,191 @@
  */
  */
 
 
 #include "rtl2832_priv.h"
 #include "rtl2832_priv.h"
-#include "dvb_math.h"
-#include <linux/bitops.h>
 
 
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  64
 #define REG_MASK(b) (BIT(b + 1) - 1)
 #define REG_MASK(b) (BIT(b + 1) - 1)
 
 
 static const struct rtl2832_reg_entry registers[] = {
 static const struct rtl2832_reg_entry registers[] = {
-	[DVBT_SOFT_RST]		= {0x1, 0x1,   2, 2},
-	[DVBT_IIC_REPEAT]	= {0x1, 0x1,   3, 3},
-	[DVBT_TR_WAIT_MIN_8K]	= {0x1, 0x88, 11, 2},
-	[DVBT_RSD_BER_FAIL_VAL]	= {0x1, 0x8f, 15, 0},
-	[DVBT_EN_BK_TRK]	= {0x1, 0xa6,  7, 7},
-	[DVBT_AD_EN_REG]	= {0x0, 0x8,   7, 7},
-	[DVBT_AD_EN_REG1]	= {0x0, 0x8,   6, 6},
-	[DVBT_EN_BBIN]		= {0x1, 0xb1,  0, 0},
-	[DVBT_MGD_THD0]		= {0x1, 0x95,  7, 0},
-	[DVBT_MGD_THD1]		= {0x1, 0x96,  7, 0},
-	[DVBT_MGD_THD2]		= {0x1, 0x97,  7, 0},
-	[DVBT_MGD_THD3]		= {0x1, 0x98,  7, 0},
-	[DVBT_MGD_THD4]		= {0x1, 0x99,  7, 0},
-	[DVBT_MGD_THD5]		= {0x1, 0x9a,  7, 0},
-	[DVBT_MGD_THD6]		= {0x1, 0x9b,  7, 0},
-	[DVBT_MGD_THD7]		= {0x1, 0x9c,  7, 0},
-	[DVBT_EN_CACQ_NOTCH]	= {0x1, 0x61,  4, 4},
-	[DVBT_AD_AV_REF]	= {0x0, 0x9,   6, 0},
-	[DVBT_REG_PI]		= {0x0, 0xa,   2, 0},
-	[DVBT_PIP_ON]		= {0x0, 0x21,  3, 3},
-	[DVBT_SCALE1_B92]	= {0x2, 0x92,  7, 0},
-	[DVBT_SCALE1_B93]	= {0x2, 0x93,  7, 0},
-	[DVBT_SCALE1_BA7]	= {0x2, 0xa7,  7, 0},
-	[DVBT_SCALE1_BA9]	= {0x2, 0xa9,  7, 0},
-	[DVBT_SCALE1_BAA]	= {0x2, 0xaa,  7, 0},
-	[DVBT_SCALE1_BAB]	= {0x2, 0xab,  7, 0},
-	[DVBT_SCALE1_BAC]	= {0x2, 0xac,  7, 0},
-	[DVBT_SCALE1_BB0]	= {0x2, 0xb0,  7, 0},
-	[DVBT_SCALE1_BB1]	= {0x2, 0xb1,  7, 0},
-	[DVBT_KB_P1]		= {0x1, 0x64,  3, 1},
-	[DVBT_KB_P2]		= {0x1, 0x64,  6, 4},
-	[DVBT_KB_P3]		= {0x1, 0x65,  2, 0},
-	[DVBT_OPT_ADC_IQ]	= {0x0, 0x6,   5, 4},
-	[DVBT_AD_AVI]		= {0x0, 0x9,   1, 0},
-	[DVBT_AD_AVQ]		= {0x0, 0x9,   3, 2},
-	[DVBT_K1_CR_STEP12]	= {0x2, 0xad,  9, 4},
-	[DVBT_TRK_KS_P2]	= {0x1, 0x6f,  2, 0},
-	[DVBT_TRK_KS_I2]	= {0x1, 0x70,  5, 3},
-	[DVBT_TR_THD_SET2]	= {0x1, 0x72,  3, 0},
-	[DVBT_TRK_KC_P2]	= {0x1, 0x73,  5, 3},
-	[DVBT_TRK_KC_I2]	= {0x1, 0x75,  2, 0},
-	[DVBT_CR_THD_SET2]	= {0x1, 0x76,  7, 6},
-	[DVBT_PSET_IFFREQ]	= {0x1, 0x19, 21, 0},
-	[DVBT_SPEC_INV]		= {0x1, 0x15,  0, 0},
-	[DVBT_RSAMP_RATIO]	= {0x1, 0x9f, 27, 2},
-	[DVBT_CFREQ_OFF_RATIO]	= {0x1, 0x9d, 23, 4},
-	[DVBT_FSM_STAGE]	= {0x3, 0x51,  6, 3},
-	[DVBT_RX_CONSTEL]	= {0x3, 0x3c,  3, 2},
-	[DVBT_RX_HIER]		= {0x3, 0x3c,  6, 4},
-	[DVBT_RX_C_RATE_LP]	= {0x3, 0x3d,  2, 0},
-	[DVBT_RX_C_RATE_HP]	= {0x3, 0x3d,  5, 3},
-	[DVBT_GI_IDX]		= {0x3, 0x51,  1, 0},
-	[DVBT_FFT_MODE_IDX]	= {0x3, 0x51,  2, 2},
-	[DVBT_RSD_BER_EST]	= {0x3, 0x4e, 15, 0},
-	[DVBT_CE_EST_EVM]	= {0x4, 0xc,  15, 0},
-	[DVBT_RF_AGC_VAL]	= {0x3, 0x5b, 13, 0},
-	[DVBT_IF_AGC_VAL]	= {0x3, 0x59, 13, 0},
-	[DVBT_DAGC_VAL]		= {0x3, 0x5,   7, 0},
-	[DVBT_SFREQ_OFF]	= {0x3, 0x18, 13, 0},
-	[DVBT_CFREQ_OFF]	= {0x3, 0x5f, 17, 0},
-	[DVBT_POLAR_RF_AGC]	= {0x0, 0xe,   1, 1},
-	[DVBT_POLAR_IF_AGC]	= {0x0, 0xe,   0, 0},
-	[DVBT_AAGC_HOLD]	= {0x1, 0x4,   5, 5},
-	[DVBT_EN_RF_AGC]	= {0x1, 0x4,   6, 6},
-	[DVBT_EN_IF_AGC]	= {0x1, 0x4,   7, 7},
-	[DVBT_IF_AGC_MIN]	= {0x1, 0x8,   7, 0},
-	[DVBT_IF_AGC_MAX]	= {0x1, 0x9,   7, 0},
-	[DVBT_RF_AGC_MIN]	= {0x1, 0xa,   7, 0},
-	[DVBT_RF_AGC_MAX]	= {0x1, 0xb,   7, 0},
-	[DVBT_IF_AGC_MAN]	= {0x1, 0xc,   6, 6},
-	[DVBT_IF_AGC_MAN_VAL]	= {0x1, 0xc,  13, 0},
-	[DVBT_RF_AGC_MAN]	= {0x1, 0xe,   6, 6},
-	[DVBT_RF_AGC_MAN_VAL]	= {0x1, 0xe,  13, 0},
-	[DVBT_DAGC_TRG_VAL]	= {0x1, 0x12,  7, 0},
-	[DVBT_AGC_TARG_VAL_0]	= {0x1, 0x2,   0, 0},
-	[DVBT_AGC_TARG_VAL_8_1]	= {0x1, 0x3,   7, 0},
-	[DVBT_AAGC_LOOP_GAIN]	= {0x1, 0xc7,  5, 1},
-	[DVBT_LOOP_GAIN2_3_0]	= {0x1, 0x4,   4, 1},
-	[DVBT_LOOP_GAIN2_4]	= {0x1, 0x5,   7, 7},
-	[DVBT_LOOP_GAIN3]	= {0x1, 0xc8,  4, 0},
-	[DVBT_VTOP1]		= {0x1, 0x6,   5, 0},
-	[DVBT_VTOP2]		= {0x1, 0xc9,  5, 0},
-	[DVBT_VTOP3]		= {0x1, 0xca,  5, 0},
-	[DVBT_KRF1]		= {0x1, 0xcb,  7, 0},
-	[DVBT_KRF2]		= {0x1, 0x7,   7, 0},
-	[DVBT_KRF3]		= {0x1, 0xcd,  7, 0},
-	[DVBT_KRF4]		= {0x1, 0xce,  7, 0},
-	[DVBT_EN_GI_PGA]	= {0x1, 0xe5,  0, 0},
-	[DVBT_THD_LOCK_UP]	= {0x1, 0xd9,  8, 0},
-	[DVBT_THD_LOCK_DW]	= {0x1, 0xdb,  8, 0},
-	[DVBT_THD_UP1]		= {0x1, 0xdd,  7, 0},
-	[DVBT_THD_DW1]		= {0x1, 0xde,  7, 0},
-	[DVBT_INTER_CNT_LEN]	= {0x1, 0xd8,  3, 0},
-	[DVBT_GI_PGA_STATE]	= {0x1, 0xe6,  3, 3},
-	[DVBT_EN_AGC_PGA]	= {0x1, 0xd7,  0, 0},
-	[DVBT_CKOUTPAR]		= {0x1, 0x7b,  5, 5},
-	[DVBT_CKOUT_PWR]	= {0x1, 0x7b,  6, 6},
-	[DVBT_SYNC_DUR]		= {0x1, 0x7b,  7, 7},
-	[DVBT_ERR_DUR]		= {0x1, 0x7c,  0, 0},
-	[DVBT_SYNC_LVL]		= {0x1, 0x7c,  1, 1},
-	[DVBT_ERR_LVL]		= {0x1, 0x7c,  2, 2},
-	[DVBT_VAL_LVL]		= {0x1, 0x7c,  3, 3},
-	[DVBT_SERIAL]		= {0x1, 0x7c,  4, 4},
-	[DVBT_SER_LSB]		= {0x1, 0x7c,  5, 5},
-	[DVBT_CDIV_PH0]		= {0x1, 0x7d,  3, 0},
-	[DVBT_CDIV_PH1]		= {0x1, 0x7d,  7, 4},
-	[DVBT_MPEG_IO_OPT_2_2]	= {0x0, 0x6,   7, 7},
-	[DVBT_MPEG_IO_OPT_1_0]	= {0x0, 0x7,   7, 6},
-	[DVBT_CKOUTPAR_PIP]	= {0x0, 0xb7,  4, 4},
-	[DVBT_CKOUT_PWR_PIP]	= {0x0, 0xb7,  3, 3},
-	[DVBT_SYNC_LVL_PIP]	= {0x0, 0xb7,  2, 2},
-	[DVBT_ERR_LVL_PIP]	= {0x0, 0xb7,  1, 1},
-	[DVBT_VAL_LVL_PIP]	= {0x0, 0xb7,  0, 0},
-	[DVBT_CKOUTPAR_PID]	= {0x0, 0xb9,  4, 4},
-	[DVBT_CKOUT_PWR_PID]	= {0x0, 0xb9,  3, 3},
-	[DVBT_SYNC_LVL_PID]	= {0x0, 0xb9,  2, 2},
-	[DVBT_ERR_LVL_PID]	= {0x0, 0xb9,  1, 1},
-	[DVBT_VAL_LVL_PID]	= {0x0, 0xb9,  0, 0},
-	[DVBT_SM_PASS]		= {0x1, 0x93, 11, 0},
-	[DVBT_AD7_SETTING]	= {0x0, 0x11, 15, 0},
-	[DVBT_RSSI_R]		= {0x3, 0x1,   6, 0},
-	[DVBT_ACI_DET_IND]	= {0x3, 0x12,  0, 0},
-	[DVBT_REG_MON]		= {0x0, 0xd,   1, 0},
-	[DVBT_REG_MONSEL]	= {0x0, 0xd,   2, 2},
-	[DVBT_REG_GPE]		= {0x0, 0xd,   7, 7},
-	[DVBT_REG_GPO]		= {0x0, 0x10,  0, 0},
-	[DVBT_REG_4MSEL]	= {0x0, 0x13,  0, 0},
+	[DVBT_SOFT_RST]		= {0x101,  2, 2},
+	[DVBT_IIC_REPEAT]	= {0x101,  3, 3},
+	[DVBT_TR_WAIT_MIN_8K]	= {0x188, 11, 2},
+	[DVBT_RSD_BER_FAIL_VAL]	= {0x18f, 15, 0},
+	[DVBT_EN_BK_TRK]	= {0x1a6,  7, 7},
+	[DVBT_AD_EN_REG]	= {0x008,  7, 7},
+	[DVBT_AD_EN_REG1]	= {0x008,  6, 6},
+	[DVBT_EN_BBIN]		= {0x1b1,  0, 0},
+	[DVBT_MGD_THD0]		= {0x195,  7, 0},
+	[DVBT_MGD_THD1]		= {0x196,  7, 0},
+	[DVBT_MGD_THD2]		= {0x197,  7, 0},
+	[DVBT_MGD_THD3]		= {0x198,  7, 0},
+	[DVBT_MGD_THD4]		= {0x199,  7, 0},
+	[DVBT_MGD_THD5]		= {0x19a,  7, 0},
+	[DVBT_MGD_THD6]		= {0x19b,  7, 0},
+	[DVBT_MGD_THD7]		= {0x19c,  7, 0},
+	[DVBT_EN_CACQ_NOTCH]	= {0x161,  4, 4},
+	[DVBT_AD_AV_REF]	= {0x009,  6, 0},
+	[DVBT_REG_PI]		= {0x00a,  2, 0},
+	[DVBT_PIP_ON]		= {0x021,  3, 3},
+	[DVBT_SCALE1_B92]	= {0x292,  7, 0},
+	[DVBT_SCALE1_B93]	= {0x293,  7, 0},
+	[DVBT_SCALE1_BA7]	= {0x2a7,  7, 0},
+	[DVBT_SCALE1_BA9]	= {0x2a9,  7, 0},
+	[DVBT_SCALE1_BAA]	= {0x2aa,  7, 0},
+	[DVBT_SCALE1_BAB]	= {0x2ab,  7, 0},
+	[DVBT_SCALE1_BAC]	= {0x2ac,  7, 0},
+	[DVBT_SCALE1_BB0]	= {0x2b0,  7, 0},
+	[DVBT_SCALE1_BB1]	= {0x2b1,  7, 0},
+	[DVBT_KB_P1]		= {0x164,  3, 1},
+	[DVBT_KB_P2]		= {0x164,  6, 4},
+	[DVBT_KB_P3]		= {0x165,  2, 0},
+	[DVBT_OPT_ADC_IQ]	= {0x006,  5, 4},
+	[DVBT_AD_AVI]		= {0x009,  1, 0},
+	[DVBT_AD_AVQ]		= {0x009,  3, 2},
+	[DVBT_K1_CR_STEP12]	= {0x2ad,  9, 4},
+	[DVBT_TRK_KS_P2]	= {0x16f,  2, 0},
+	[DVBT_TRK_KS_I2]	= {0x170,  5, 3},
+	[DVBT_TR_THD_SET2]	= {0x172,  3, 0},
+	[DVBT_TRK_KC_P2]	= {0x173,  5, 3},
+	[DVBT_TRK_KC_I2]	= {0x175,  2, 0},
+	[DVBT_CR_THD_SET2]	= {0x176,  7, 6},
+	[DVBT_PSET_IFFREQ]	= {0x119, 21, 0},
+	[DVBT_SPEC_INV]		= {0x115,  0, 0},
+	[DVBT_RSAMP_RATIO]	= {0x19f, 27, 2},
+	[DVBT_CFREQ_OFF_RATIO]	= {0x19d, 23, 4},
+	[DVBT_FSM_STAGE]	= {0x351,  6, 3},
+	[DVBT_RX_CONSTEL]	= {0x33c,  3, 2},
+	[DVBT_RX_HIER]		= {0x33c,  6, 4},
+	[DVBT_RX_C_RATE_LP]	= {0x33d,  2, 0},
+	[DVBT_RX_C_RATE_HP]	= {0x33d,  5, 3},
+	[DVBT_GI_IDX]		= {0x351,  1, 0},
+	[DVBT_FFT_MODE_IDX]	= {0x351,  2, 2},
+	[DVBT_RSD_BER_EST]	= {0x34e, 15, 0},
+	[DVBT_CE_EST_EVM]	= {0x40c, 15, 0},
+	[DVBT_RF_AGC_VAL]	= {0x35b, 13, 0},
+	[DVBT_IF_AGC_VAL]	= {0x359, 13, 0},
+	[DVBT_DAGC_VAL]		= {0x305,  7, 0},
+	[DVBT_SFREQ_OFF]	= {0x318, 13, 0},
+	[DVBT_CFREQ_OFF]	= {0x35f, 17, 0},
+	[DVBT_POLAR_RF_AGC]	= {0x00e,  1, 1},
+	[DVBT_POLAR_IF_AGC]	= {0x00e,  0, 0},
+	[DVBT_AAGC_HOLD]	= {0x104,  5, 5},
+	[DVBT_EN_RF_AGC]	= {0x104,  6, 6},
+	[DVBT_EN_IF_AGC]	= {0x104,  7, 7},
+	[DVBT_IF_AGC_MIN]	= {0x108,  7, 0},
+	[DVBT_IF_AGC_MAX]	= {0x109,  7, 0},
+	[DVBT_RF_AGC_MIN]	= {0x10a,  7, 0},
+	[DVBT_RF_AGC_MAX]	= {0x10b,  7, 0},
+	[DVBT_IF_AGC_MAN]	= {0x10c,  6, 6},
+	[DVBT_IF_AGC_MAN_VAL]	= {0x10c, 13, 0},
+	[DVBT_RF_AGC_MAN]	= {0x10e,  6, 6},
+	[DVBT_RF_AGC_MAN_VAL]	= {0x10e, 13, 0},
+	[DVBT_DAGC_TRG_VAL]	= {0x112,  7, 0},
+	[DVBT_AGC_TARG_VAL_0]	= {0x102,  0, 0},
+	[DVBT_AGC_TARG_VAL_8_1]	= {0x103,  7, 0},
+	[DVBT_AAGC_LOOP_GAIN]	= {0x1c7,  5, 1},
+	[DVBT_LOOP_GAIN2_3_0]	= {0x104,  4, 1},
+	[DVBT_LOOP_GAIN2_4]	= {0x105,  7, 7},
+	[DVBT_LOOP_GAIN3]	= {0x1c8,  4, 0},
+	[DVBT_VTOP1]		= {0x106,  5, 0},
+	[DVBT_VTOP2]		= {0x1c9,  5, 0},
+	[DVBT_VTOP3]		= {0x1ca,  5, 0},
+	[DVBT_KRF1]		= {0x1cb,  7, 0},
+	[DVBT_KRF2]		= {0x107,  7, 0},
+	[DVBT_KRF3]		= {0x1cd,  7, 0},
+	[DVBT_KRF4]		= {0x1ce,  7, 0},
+	[DVBT_EN_GI_PGA]	= {0x1e5,  0, 0},
+	[DVBT_THD_LOCK_UP]	= {0x1d9,  8, 0},
+	[DVBT_THD_LOCK_DW]	= {0x1db,  8, 0},
+	[DVBT_THD_UP1]		= {0x1dd,  7, 0},
+	[DVBT_THD_DW1]		= {0x1de,  7, 0},
+	[DVBT_INTER_CNT_LEN]	= {0x1d8,  3, 0},
+	[DVBT_GI_PGA_STATE]	= {0x1e6,  3, 3},
+	[DVBT_EN_AGC_PGA]	= {0x1d7,  0, 0},
+	[DVBT_CKOUTPAR]		= {0x17b,  5, 5},
+	[DVBT_CKOUT_PWR]	= {0x17b,  6, 6},
+	[DVBT_SYNC_DUR]		= {0x17b,  7, 7},
+	[DVBT_ERR_DUR]		= {0x17c,  0, 0},
+	[DVBT_SYNC_LVL]		= {0x17c,  1, 1},
+	[DVBT_ERR_LVL]		= {0x17c,  2, 2},
+	[DVBT_VAL_LVL]		= {0x17c,  3, 3},
+	[DVBT_SERIAL]		= {0x17c,  4, 4},
+	[DVBT_SER_LSB]		= {0x17c,  5, 5},
+	[DVBT_CDIV_PH0]		= {0x17d,  3, 0},
+	[DVBT_CDIV_PH1]		= {0x17d,  7, 4},
+	[DVBT_MPEG_IO_OPT_2_2]	= {0x006,  7, 7},
+	[DVBT_MPEG_IO_OPT_1_0]	= {0x007,  7, 6},
+	[DVBT_CKOUTPAR_PIP]	= {0x0b7,  4, 4},
+	[DVBT_CKOUT_PWR_PIP]	= {0x0b7,  3, 3},
+	[DVBT_SYNC_LVL_PIP]	= {0x0b7,  2, 2},
+	[DVBT_ERR_LVL_PIP]	= {0x0b7,  1, 1},
+	[DVBT_VAL_LVL_PIP]	= {0x0b7,  0, 0},
+	[DVBT_CKOUTPAR_PID]	= {0x0b9,  4, 4},
+	[DVBT_CKOUT_PWR_PID]	= {0x0b9,  3, 3},
+	[DVBT_SYNC_LVL_PID]	= {0x0b9,  2, 2},
+	[DVBT_ERR_LVL_PID]	= {0x0b9,  1, 1},
+	[DVBT_VAL_LVL_PID]	= {0x0b9,  0, 0},
+	[DVBT_SM_PASS]		= {0x193, 11, 0},
+	[DVBT_AD7_SETTING]	= {0x011, 15, 0},
+	[DVBT_RSSI_R]		= {0x301,  6, 0},
+	[DVBT_ACI_DET_IND]	= {0x312,  0, 0},
+	[DVBT_REG_MON]		= {0x00d,  1, 0},
+	[DVBT_REG_MONSEL]	= {0x00d,  2, 2},
+	[DVBT_REG_GPE]		= {0x00d,  7, 7},
+	[DVBT_REG_GPO]		= {0x010,  0, 0},
+	[DVBT_REG_4MSEL]	= {0x013,  0, 0},
 };
 };
 
 
-/* write multiple hardware registers */
-static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+/* Our regmap is bypassing I2C adapter lock, thus we do it! */
+static int rtl2832_bulk_write(struct i2c_client *client, unsigned int reg,
+			      const void *val, size_t val_count)
 {
 {
+	struct rtl2832_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
-	u8 buf[MAX_XFER_SIZE];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = 1 + len,
-			.buf = buf,
-		}
-	};
 
 
-	if (1 + len > sizeof(buf)) {
-		dev_warn(&priv->i2c->dev,
-			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
-			 KBUILD_MODNAME, reg, len);
-		return -EINVAL;
-	}
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
-
-	ret = i2c_transfer(priv->i2c_adapter, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev,
-				"%s: i2c wr failed=%d reg=%02x len=%d\n",
-				KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
+	i2c_lock_adapter(client->adapter);
+	ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
+	i2c_unlock_adapter(client->adapter);
 	return ret;
 	return ret;
 }
 }
 
 
-/* read multiple hardware registers */
-static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+static int rtl2832_update_bits(struct i2c_client *client, unsigned int reg,
+			       unsigned int mask, unsigned int val)
 {
 {
+	struct rtl2832_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg.i2c_addr,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = priv->cfg.i2c_addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = val,
-		}
-	};
 
 
-	ret = i2c_transfer(priv->i2c_adapter, msg, 2);
-	if (ret == 2) {
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev,
-				"%s: i2c rd failed=%d reg=%02x len=%d\n",
-				KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
+	i2c_lock_adapter(client->adapter);
+	ret = regmap_update_bits(dev->regmap, reg, mask, val);
+	i2c_unlock_adapter(client->adapter);
 	return ret;
 	return ret;
 }
 }
 
 
-/* write multiple registers */
-static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
-	int len)
-{
-	int ret;
-
-	/* switch bank if needed */
-	if (page != priv->page) {
-		ret = rtl2832_wr(priv, 0x00, &page, 1);
-		if (ret)
-			return ret;
-
-		priv->page = page;
-}
-
-return rtl2832_wr(priv, reg, val, len);
-}
-
-/* read multiple registers */
-static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
-	int len)
+static int rtl2832_bulk_read(struct i2c_client *client, unsigned int reg,
+			     void *val, size_t val_count)
 {
 {
+	struct rtl2832_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
 
 
-	/* switch bank if needed */
-	if (page != priv->page) {
-		ret = rtl2832_wr(priv, 0x00, &page, 1);
-		if (ret)
-			return ret;
-
-		priv->page = page;
-	}
-
-	return rtl2832_rd(priv, reg, val, len);
-}
-
-/* write single register */
-static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
-{
-	return rtl2832_wr_regs(priv, reg, page, &val, 1);
-}
-
-/* read single register */
-static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
-{
-	return rtl2832_rd_regs(priv, reg, page, val, 1);
+	i2c_lock_adapter(client->adapter);
+	ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
+	i2c_unlock_adapter(client->adapter);
+	return ret;
 }
 }
 
 
-static int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val)
+static int rtl2832_rd_demod_reg(struct rtl2832_dev *dev, int reg, u32 *val)
 {
 {
-	int ret;
-
-	u8 reg_start_addr;
-	u8 msb, lsb;
-	u8 page;
-	u8 reading[4];
-	u32 reading_tmp;
-	int i;
-
-	u8 len;
-	u32 mask;
+	struct i2c_client *client = dev->client;
+	int ret, i;
+	u16 reg_start_addr;
+	u8 msb, lsb, reading[4], len;
+	u32 reading_tmp, mask;
 
 
 	reg_start_addr = registers[reg].start_address;
 	reg_start_addr = registers[reg].start_address;
 	msb = registers[reg].msb;
 	msb = registers[reg].msb;
 	lsb = registers[reg].lsb;
 	lsb = registers[reg].lsb;
-	page = registers[reg].page;
-
 	len = (msb >> 3) + 1;
 	len = (msb >> 3) + 1;
 	mask = REG_MASK(msb - lsb);
 	mask = REG_MASK(msb - lsb);
 
 
-	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+	ret = rtl2832_bulk_read(client, reg_start_addr, reading, len);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -302,40 +214,27 @@ static int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val)
 
 
 	*val = (reading_tmp >> lsb) & mask;
 	*val = (reading_tmp >> lsb) & mask;
 
 
-	return ret;
-
+	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
-
 }
 }
 
 
-static int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
+static int rtl2832_wr_demod_reg(struct rtl2832_dev *dev, int reg, u32 val)
 {
 {
+	struct i2c_client *client = dev->client;
 	int ret, i;
 	int ret, i;
-	u8 len;
-	u8 reg_start_addr;
-	u8 msb, lsb;
-	u8 page;
-	u32 mask;
-
-
-	u8 reading[4];
-	u8 writing[4];
-	u32 reading_tmp;
-	u32 writing_tmp;
-
+	u16 reg_start_addr;
+	u8 msb, lsb, reading[4], writing[4], len;
+	u32 reading_tmp, writing_tmp, mask;
 
 
 	reg_start_addr = registers[reg].start_address;
 	reg_start_addr = registers[reg].start_address;
 	msb = registers[reg].msb;
 	msb = registers[reg].msb;
 	lsb = registers[reg].lsb;
 	lsb = registers[reg].lsb;
-	page = registers[reg].page;
-
 	len = (msb >> 3) + 1;
 	len = (msb >> 3) + 1;
 	mask = REG_MASK(msb - lsb);
 	mask = REG_MASK(msb - lsb);
 
 
-
-	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+	ret = rtl2832_bulk_read(client, reg_start_addr, reading, len);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -346,49 +245,23 @@ static int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
 	writing_tmp = reading_tmp & ~(mask << lsb);
 	writing_tmp = reading_tmp & ~(mask << lsb);
 	writing_tmp |= ((val & mask) << lsb);
 	writing_tmp |= ((val & mask) << lsb);
 
 
-
 	for (i = 0; i < len; i++)
 	for (i = 0; i < len; i++)
 		writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff;
 		writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff;
 
 
-	ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
-	if (ret)
-		goto err;
-
-	return ret;
-
-err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-
-}
-
-static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-	int ret;
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-
-	dev_dbg(&priv->i2c->dev, "%s: enable=%d\n", __func__, enable);
-
-	/* gate already open or close */
-	if (priv->i2c_gate_state == enable)
-		return 0;
-
-	ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable ? 0x1 : 0x0));
+	ret = rtl2832_bulk_write(client, reg_start_addr, writing, len);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	priv->i2c_gate_state = enable;
-
-	return ret;
+	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
-
 static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
 static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct rtl2832_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	int ret;
 	int ret;
 	u64 pset_iffreq;
 	u64 pset_iffreq;
 	u8 en_bbin = (if_freq == 0 ? 0x1 : 0x0);
 	u8 en_bbin = (if_freq == 0 ? 0x1 : 0x0);
@@ -397,30 +270,35 @@ static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
 	* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
 	* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
 	*		/ CrystalFreqHz)
 	*		/ CrystalFreqHz)
 	*/
 	*/
-
-	pset_iffreq = if_freq % priv->cfg.xtal;
+	pset_iffreq = if_freq % dev->pdata->clk;
 	pset_iffreq *= 0x400000;
 	pset_iffreq *= 0x400000;
-	pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
+	pset_iffreq = div_u64(pset_iffreq, dev->pdata->clk);
 	pset_iffreq = -pset_iffreq;
 	pset_iffreq = -pset_iffreq;
 	pset_iffreq = pset_iffreq & 0x3fffff;
 	pset_iffreq = pset_iffreq & 0x3fffff;
-	dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d pset_iffreq=%08x\n",
-			__func__, if_freq, (unsigned)pset_iffreq);
+	dev_dbg(&client->dev, "if_frequency=%d pset_iffreq=%08x\n",
+		if_freq, (unsigned)pset_iffreq);
 
 
-	ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+	ret = rtl2832_wr_demod_reg(dev, DVBT_EN_BBIN, en_bbin);
 	if (ret)
 	if (ret)
-		return ret;
+		goto err;
 
 
-	ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
+	ret = rtl2832_wr_demod_reg(dev, DVBT_PSET_IFFREQ, pset_iffreq);
+	if (ret)
+		goto err;
 
 
+	return 0;
+err:
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int rtl2832_init(struct dvb_frontend *fe)
 static int rtl2832_init(struct dvb_frontend *fe)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct rtl2832_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
+	struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
 	const struct rtl2832_reg_value *init;
 	const struct rtl2832_reg_value *init;
 	int i, ret, len;
 	int i, ret, len;
-
 	/* initialization values for the demodulator registers */
 	/* initialization values for the demodulator registers */
 	struct rtl2832_reg_value rtl2832_initial_regs[] = {
 	struct rtl2832_reg_value rtl2832_initial_regs[] = {
 		{DVBT_AD_EN_REG,		0x1},
 		{DVBT_AD_EN_REG,		0x1},
@@ -467,19 +345,19 @@ static int rtl2832_init(struct dvb_frontend *fe)
 		{DVBT_CR_THD_SET2,		0x1},
 		{DVBT_CR_THD_SET2,		0x1},
 	};
 	};
 
 
-	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+	dev_dbg(&client->dev, "\n");
 
 
 	for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
 	for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
-		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg,
+		ret = rtl2832_wr_demod_reg(dev, rtl2832_initial_regs[i].reg,
 			rtl2832_initial_regs[i].value);
 			rtl2832_initial_regs[i].value);
 		if (ret)
 		if (ret)
 			goto err;
 			goto err;
 	}
 	}
 
 
 	/* load tuner specific settings */
 	/* load tuner specific settings */
-	dev_dbg(&priv->i2c->dev, "%s: load settings for tuner=%02x\n",
-			__func__, priv->cfg.tuner);
-	switch (priv->cfg.tuner) {
+	dev_dbg(&client->dev, "load settings for tuner=%02x\n",
+		dev->pdata->tuner);
+	switch (dev->pdata->tuner) {
 	case RTL2832_TUNER_FC0012:
 	case RTL2832_TUNER_FC0012:
 	case RTL2832_TUNER_FC0013:
 	case RTL2832_TUNER_FC0013:
 		len = ARRAY_SIZE(rtl2832_tuner_init_fc0012);
 		len = ARRAY_SIZE(rtl2832_tuner_init_fc0012);
@@ -504,51 +382,60 @@ static int rtl2832_init(struct dvb_frontend *fe)
 	}
 	}
 
 
 	for (i = 0; i < len; i++) {
 	for (i = 0; i < len; i++) {
-		ret = rtl2832_wr_demod_reg(priv, init[i].reg, init[i].value);
+		ret = rtl2832_wr_demod_reg(dev, init[i].reg, init[i].value);
 		if (ret)
 		if (ret)
 			goto err;
 			goto err;
 	}
 	}
 
 
-	/*
-	 * r820t NIM code does a software reset here at the demod -
-	 * may not be needed, as there's already a software reset at
-	 * set_params()
-	 */
-#if 1
-	/* soft reset */
-	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
-	if (ret)
-		goto err;
-
-	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
-	if (ret)
-		goto err;
-#endif
-
-	priv->sleeping = false;
-
-	return ret;
+	/* init stats here in order signal app which stats are supported */
+	c->strength.len = 1;
+	c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->cnr.len = 1;
+	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_error.len = 1;
+	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_count.len = 1;
+	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	/* start statistics polling */
+	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+	dev->sleeping = false;
 
 
+	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int rtl2832_sleep(struct dvb_frontend *fe)
 static int rtl2832_sleep(struct dvb_frontend *fe)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct rtl2832_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
+	int ret;
+
+	dev_dbg(&client->dev, "\n");
+
+	dev->sleeping = true;
+	/* stop statistics polling */
+	cancel_delayed_work_sync(&dev->stat_work);
+	dev->fe_status = 0;
+
+	ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
+	if (ret)
+		goto err;
 
 
-	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
-	priv->sleeping = true;
 	return 0;
 	return 0;
+err:
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+	return ret;
 }
 }
 
 
 static int rtl2832_get_tune_settings(struct dvb_frontend *fe,
 static int rtl2832_get_tune_settings(struct dvb_frontend *fe,
 	struct dvb_frontend_tune_settings *s)
 	struct dvb_frontend_tune_settings *s)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct rtl2832_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 
 
-	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+	dev_dbg(&client->dev, "\n");
 	s->min_delay_ms = 1000;
 	s->min_delay_ms = 1000;
 	s->step_size = fe->ops.info.frequency_stepsize * 2;
 	s->step_size = fe->ops.info.frequency_stepsize * 2;
 	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
 	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
@@ -557,7 +444,8 @@ static int rtl2832_get_tune_settings(struct dvb_frontend *fe,
 
 
 static int rtl2832_set_frontend(struct dvb_frontend *fe)
 static int rtl2832_set_frontend(struct dvb_frontend *fe)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct rtl2832_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret, i, j;
 	int ret, i, j;
 	u64 bw_mode, num, num2;
 	u64 bw_mode, num, num2;
@@ -588,17 +476,15 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
 		},
 		},
 	};
 	};
 
 
-
-	dev_dbg(&priv->i2c->dev,
-			"%s: frequency=%d bandwidth_hz=%d inversion=%d\n",
-			__func__, c->frequency, c->bandwidth_hz, c->inversion);
+	dev_dbg(&client->dev, "frequency=%u bandwidth_hz=%u inversion=%u\n",
+		c->frequency, c->bandwidth_hz, c->inversion);
 
 
 	/* program tuner */
 	/* program tuner */
 	if (fe->ops.tuner_ops.set_params)
 	if (fe->ops.tuner_ops.set_params)
 		fe->ops.tuner_ops.set_params(fe);
 		fe->ops.tuner_ops.set_params(fe);
 
 
 	/* PIP mode related */
 	/* PIP mode related */
-	ret = rtl2832_wr_regs(priv, 0x92, 1, "\x00\x0f\xff", 3);
+	ret = rtl2832_bulk_write(client, 0x192, "\x00\x0f\xff", 3);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -629,12 +515,14 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
 		bw_mode = 64000000;
 		bw_mode = 64000000;
 		break;
 		break;
 	default:
 	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid bandwidth\n", __func__);
-		return -EINVAL;
+		dev_err(&client->dev, "invalid bandwidth_hz %u\n",
+			c->bandwidth_hz);
+		ret = -EINVAL;
+		goto err;
 	}
 	}
 
 
 	for (j = 0; j < sizeof(bw_params[0]); j++) {
 	for (j = 0; j < sizeof(bw_params[0]); j++) {
-		ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
+		ret = rtl2832_bulk_write(client, 0x11c + j, &bw_params[i][j], 1);
 		if (ret)
 		if (ret)
 			goto err;
 			goto err;
 	}
 	}
@@ -643,11 +531,11 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
 	* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22)
 	* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22)
 	*	/ ConstWithBandwidthMode)
 	*	/ ConstWithBandwidthMode)
 	*/
 	*/
-	num = priv->cfg.xtal * 7;
+	num = dev->pdata->clk * 7;
 	num *= 0x400000;
 	num *= 0x400000;
 	num = div_u64(num, bw_mode);
 	num = div_u64(num, bw_mode);
 	resamp_ratio =  num & 0x3ffffff;
 	resamp_ratio =  num & 0x3ffffff;
-	ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
+	ret = rtl2832_wr_demod_reg(dev, DVBT_RSAMP_RATIO, resamp_ratio);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -656,48 +544,49 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
 	*	/ (CrystalFreqHz * 7))
 	*	/ (CrystalFreqHz * 7))
 	*/
 	*/
 	num = bw_mode << 20;
 	num = bw_mode << 20;
-	num2 = priv->cfg.xtal * 7;
+	num2 = dev->pdata->clk * 7;
 	num = div_u64(num, num2);
 	num = div_u64(num, num2);
 	num = -num;
 	num = -num;
 	cfreq_off_ratio = num & 0xfffff;
 	cfreq_off_ratio = num & 0xfffff;
-	ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
+	ret = rtl2832_wr_demod_reg(dev, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* soft reset */
 	/* soft reset */
-	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+	ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+	ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	return ret;
+	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int rtl2832_get_frontend(struct dvb_frontend *fe)
 static int rtl2832_get_frontend(struct dvb_frontend *fe)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct rtl2832_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
 	int ret;
 	u8 buf[3];
 	u8 buf[3];
 
 
-	if (priv->sleeping)
+	if (dev->sleeping)
 		return 0;
 		return 0;
 
 
-	ret = rtl2832_rd_regs(priv, 0x3c, 3, buf, 2);
+	ret = rtl2832_bulk_read(client, 0x33c, buf, 2);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_rd_reg(priv, 0x51, 3, &buf[2]);
+	ret = rtl2832_bulk_read(client, 0x351, &buf[2], 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	dev_dbg(&priv->i2c->dev, "%s: TPS=%*ph\n", __func__, 3, buf);
+	dev_dbg(&client->dev, "TPS=%*ph\n", 3, buf);
 
 
 	switch ((buf[0] >> 2) & 3) {
 	switch ((buf[0] >> 2) & 3) {
 	case 0:
 	case 0:
@@ -787,403 +676,652 @@ static int rtl2832_get_frontend(struct dvb_frontend *fe)
 
 
 	return 0;
 	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
 static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct rtl2832_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	int ret;
 	int ret;
 	u32 tmp;
 	u32 tmp;
-	*status = 0;
 
 
-	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
-	if (priv->sleeping)
+	dev_dbg(&client->dev, "\n");
+
+	*status = 0;
+	if (dev->sleeping)
 		return 0;
 		return 0;
 
 
-	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
+	ret = rtl2832_rd_demod_reg(dev, DVBT_FSM_STAGE, &tmp);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	if (tmp == 11) {
 	if (tmp == 11) {
 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
 				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
-	}
-	/* TODO find out if this is also true for rtl2832? */
-	/*else if (tmp == 10) {
+	} else if (tmp == 10) {
 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
 				FE_HAS_VITERBI;
 				FE_HAS_VITERBI;
-	}*/
+	}
 
 
-	return ret;
+	dev->fe_status = *status;
+	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
 static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-	int ret, hierarchy, constellation;
-	u8 buf[2], tmp;
-	u16 tmp16;
-#define CONSTELLATION_NUM 3
-#define HIERARCHY_NUM 4
-	static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
-		{ 85387325, 85387325, 85387325, 85387325 },
-		{ 86676178, 86676178, 87167949, 87795660 },
-		{ 87659938, 87659938, 87885178, 88241743 },
-	};
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
 
-	/* reports SNR in resolution of 0.1 dB */
+	/* report SNR in resolution of 0.1 dB */
+	if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
+		*snr = div_s64(c->cnr.stat[0].svalue, 100);
+	else
+		*snr = 0;
 
 
-	ret = rtl2832_rd_reg(priv, 0x3c, 3, &tmp);
-	if (ret)
-		goto err;
+	return 0;
+}
 
 
-	constellation = (tmp >> 2) & 0x03; /* [3:2] */
-	if (constellation > CONSTELLATION_NUM - 1)
-		goto err;
+static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct rtl2832_dev *dev = fe->demodulator_priv;
 
 
-	hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
-	if (hierarchy > HIERARCHY_NUM - 1)
-		goto err;
+	*ber = (dev->post_bit_error - dev->post_bit_error_prev);
+	dev->post_bit_error_prev = dev->post_bit_error;
 
 
-	ret = rtl2832_rd_regs(priv, 0x0c, 4, buf, 2);
-	if (ret)
-		goto err;
+	return 0;
+}
 
 
-	tmp16 = buf[0] << 8 | buf[1];
+static void rtl2832_stat_work(struct work_struct *work)
+{
+	struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, stat_work.work);
+	struct i2c_client *client = dev->client;
+	struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+	int ret, tmp;
+	u8 u8tmp, buf[2];
+	u16 u16tmp;
+
+	dev_dbg(&client->dev, "\n");
+
+	/* signal strength */
+	if (dev->fe_status & FE_HAS_SIGNAL) {
+		/* read digital AGC */
+		ret = rtl2832_bulk_read(client, 0x305, &u8tmp, 1);
+		if (ret)
+			goto err;
 
 
-	if (tmp16)
-		*snr = (snr_constant[constellation][hierarchy] -
-				intlog10(tmp16)) / ((1 << 24) / 100);
-	else
-		*snr = 0;
+		dev_dbg(&client->dev, "digital agc=%02x", u8tmp);
 
 
-	return 0;
+		u8tmp = ~u8tmp;
+		u16tmp = u8tmp << 8 | u8tmp << 0;
+
+		c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+		c->strength.stat[0].uvalue = u16tmp;
+	} else {
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
+
+	/* CNR */
+	if (dev->fe_status & FE_HAS_VITERBI) {
+		unsigned hierarchy, constellation;
+		#define CONSTELLATION_NUM 3
+		#define HIERARCHY_NUM 4
+		static const u32 constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
+			{85387325, 85387325, 85387325, 85387325},
+			{86676178, 86676178, 87167949, 87795660},
+			{87659938, 87659938, 87885178, 88241743},
+		};
+
+		ret = rtl2832_bulk_read(client, 0x33c, &u8tmp, 1);
+		if (ret)
+			goto err;
+
+		constellation = (u8tmp >> 2) & 0x03; /* [3:2] */
+		if (constellation > CONSTELLATION_NUM - 1)
+			goto err_schedule_delayed_work;
+
+		hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */
+		if (hierarchy > HIERARCHY_NUM - 1)
+			goto err_schedule_delayed_work;
+
+		ret = rtl2832_bulk_read(client, 0x40c, buf, 2);
+		if (ret)
+			goto err;
+
+		u16tmp = buf[0] << 8 | buf[1] << 0;
+		if (u16tmp)
+			tmp = (constant[constellation][hierarchy] -
+			       intlog10(u16tmp)) / ((1 << 24) / 10000);
+		else
+			tmp = 0;
+
+		dev_dbg(&client->dev, "cnr raw=%u\n", u16tmp);
+
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = tmp;
+	} else {
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
+
+	/* BER */
+	if (dev->fe_status & FE_HAS_LOCK) {
+		ret = rtl2832_bulk_read(client, 0x34e, buf, 2);
+		if (ret)
+			goto err;
+
+		u16tmp = buf[0] << 8 | buf[1] << 0;
+		dev->post_bit_error += u16tmp;
+		dev->post_bit_count += 1000000;
+
+		dev_dbg(&client->dev, "ber errors=%u total=1000000\n", u16tmp);
+
+		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
+		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_count.stat[0].uvalue = dev->post_bit_count;
+	} else {
+		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
+
+err_schedule_delayed_work:
+	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+	return;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 }
 }
 
 
-static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
+/*
+ * I2C gate/mux/repeater logic
+ * We must use unlocked __i2c_transfer() here (through regmap) because of I2C
+ * adapter lock is already taken by tuner driver.
+ * There is delay mechanism to avoid unneeded I2C gate open / close. Gate close
+ * is delayed here a little bit in order to see if there is sequence of I2C
+ * messages sent to same I2C bus.
+ */
+static void rtl2832_i2c_gate_work(struct work_struct *work)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, i2c_gate_work.work);
+	struct i2c_client *client = dev->client;
 	int ret;
 	int ret;
-	u8 buf[2];
 
 
-	ret = rtl2832_rd_regs(priv, 0x4e, 3, buf, 2);
+	/* close gate */
+	ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	*ber = buf[0] << 8 | buf[1];
+	return;
+err:
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+}
+
+static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+{
+	struct rtl2832_dev *dev = mux_priv;
+	struct i2c_client *client = dev->client;
+	int ret;
+
+	/* terminate possible gate closing */
+	cancel_delayed_work(&dev->i2c_gate_work);
+
+	/*
+	 * I2C adapter lock is already taken and due to that we will use
+	 * regmap_update_bits() which does not lock again I2C adapter.
+	 */
+	ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08);
+	if (ret)
+		goto err;
 
 
 	return 0;
 	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
-static struct dvb_frontend_ops rtl2832_ops;
+static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
+			    u32 chan_id)
+{
+	struct rtl2832_dev *dev = mux_priv;
+
+	schedule_delayed_work(&dev->i2c_gate_work, usecs_to_jiffies(100));
+	return 0;
+}
+
+static struct dvb_frontend_ops rtl2832_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Realtek RTL2832 (DVB-T)",
+		.frequency_min	  = 174000000,
+		.frequency_max	  = 862000000,
+		.frequency_stepsize = 166667,
+		.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_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	 },
 
 
-static void rtl2832_release(struct dvb_frontend *fe)
+	.init = rtl2832_init,
+	.sleep = rtl2832_sleep,
+
+	.get_tune_settings = rtl2832_get_tune_settings,
+
+	.set_frontend = rtl2832_set_frontend,
+	.get_frontend = rtl2832_get_frontend,
+
+	.read_status = rtl2832_read_status,
+	.read_snr = rtl2832_read_snr,
+	.read_ber = rtl2832_read_ber,
+};
+
+static bool rtl2832_volatile_reg(struct device *dev, unsigned int reg)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	switch (reg) {
+	case 0x305:
+	case 0x33c:
+	case 0x34e:
+	case 0x351:
+	case 0x40c ... 0x40d:
+		return true;
+	default:
+		break;
+	}
 
 
-	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
-	cancel_delayed_work_sync(&priv->i2c_gate_work);
-	i2c_del_mux_adapter(priv->i2c_adapter_tuner);
-	i2c_del_mux_adapter(priv->i2c_adapter);
-	kfree(priv);
+	return false;
 }
 }
 
 
 /*
 /*
- * Delay mechanism to avoid unneeded I2C gate open / close. Gate close is
- * delayed here a little bit in order to see if there is sequence of I2C
- * messages sent to same I2C bus.
- * We must use unlocked version of __i2c_transfer() in order to avoid deadlock
- * as lock is already taken by calling muxed i2c_transfer().
+ * We implement own I2C access routines for regmap in order to get manual access
+ * to I2C adapter lock, which is needed for I2C mux adapter.
  */
  */
-static void rtl2832_i2c_gate_work(struct work_struct *work)
+static int rtl2832_regmap_read(void *context, const void *reg_buf,
+			       size_t reg_size, void *val_buf, size_t val_size)
 {
 {
-	struct rtl2832_priv *priv = container_of(work,
-			struct rtl2832_priv, i2c_gate_work.work);
-	struct i2c_adapter *adap = priv->i2c;
+	struct i2c_client *client = context;
 	int ret;
 	int ret;
-	u8 buf[2];
-	struct i2c_msg msg[1] = {
+	struct i2c_msg msg[2] = {
 		{
 		{
-			.addr = priv->cfg.i2c_addr,
+			.addr = client->addr,
 			.flags = 0,
 			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
+			.len = reg_size,
+			.buf = (u8 *)reg_buf,
+		}, {
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = val_size,
+			.buf = val_buf,
 		}
 		}
 	};
 	};
 
 
-	/* select reg bank 1 */
-	buf[0] = 0x00;
-	buf[1] = 0x01;
-	ret = __i2c_transfer(adap, msg, 1);
-	if (ret != 1)
-		goto err;
-
-	priv->page = 1;
-
-	/* close I2C repeater gate */
-	buf[0] = 0x01;
-	buf[1] = 0x10;
-	ret = __i2c_transfer(adap, msg, 1);
-	if (ret != 1)
-		goto err;
-
-	priv->i2c_gate_state = false;
-
-	return;
-err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-
-	return;
+	ret = __i2c_transfer(client->adapter, msg, 2);
+	if (ret != 2) {
+		dev_warn(&client->dev, "i2c reg read failed %d\n", ret);
+		if (ret >= 0)
+			ret = -EREMOTEIO;
+		return ret;
+	}
+	return 0;
 }
 }
 
 
-static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+static int rtl2832_regmap_write(void *context, const void *data, size_t count)
 {
 {
-	struct rtl2832_priv *priv = mux_priv;
+	struct i2c_client *client = context;
 	int ret;
 	int ret;
-	u8 buf[2], val;
 	struct i2c_msg msg[1] = {
 	struct i2c_msg msg[1] = {
 		{
 		{
-			.addr = priv->cfg.i2c_addr,
+			.addr = client->addr,
 			.flags = 0,
 			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
+			.len = count,
+			.buf = (u8 *)data,
 		}
 		}
 	};
 	};
-	struct i2c_msg msg_rd[2] = {
+
+	ret = __i2c_transfer(client->adapter, msg, 1);
+	if (ret != 1) {
+		dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+		if (ret >= 0)
+			ret = -EREMOTEIO;
+		return ret;
+	}
+	return 0;
+}
+
+static int rtl2832_regmap_gather_write(void *context, const void *reg,
+				       size_t reg_len, const void *val,
+				       size_t val_len)
+{
+	struct i2c_client *client = context;
+	int ret;
+	u8 buf[256];
+	struct i2c_msg msg[1] = {
 		{
 		{
-			.addr = priv->cfg.i2c_addr,
+			.addr = client->addr,
 			.flags = 0,
 			.flags = 0,
-			.len = 1,
-			.buf = "\x01",
-		}, {
-			.addr = priv->cfg.i2c_addr,
-			.flags = I2C_M_RD,
-			.len = 1,
-			.buf = &val,
+			.len = 1 + val_len,
+			.buf = buf,
 		}
 		}
 	};
 	};
 
 
-	/* terminate possible gate closing */
-	cancel_delayed_work_sync(&priv->i2c_gate_work);
+	buf[0] = *(u8 const *)reg;
+	memcpy(&buf[1], val, val_len);
 
 
-	if (priv->i2c_gate_state == chan_id)
-		return 0;
-
-	/* select reg bank 1 */
-	buf[0] = 0x00;
-	buf[1] = 0x01;
-	ret = __i2c_transfer(adap, msg, 1);
-	if (ret != 1)
-		goto err;
-
-	priv->page = 1;
+	ret = __i2c_transfer(client->adapter, msg, 1);
+	if (ret != 1) {
+		dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+		if (ret >= 0)
+			ret = -EREMOTEIO;
+		return ret;
+	}
+	return 0;
+}
 
 
-	/* we must read that register, otherwise there will be errors */
-	ret = __i2c_transfer(adap, msg_rd, 2);
-	if (ret != 2)
-		goto err;
+/*
+ * FIXME: Hack. Implement own regmap locking in order to silence lockdep
+ * recursive lock warning. That happens when regmap I2C client calls I2C mux
+ * adapter, which leads demod I2C repeater enable via demod regmap. Operation
+ * takes two regmap locks recursively - but those are different regmap instances
+ * in a two different I2C drivers, so it is not deadlock. Proper fix is to make
+ * regmap aware of lockdep.
+ */
+static void rtl2832_regmap_lock(void *__dev)
+{
+	struct rtl2832_dev *dev = __dev;
+	struct i2c_client *client = dev->client;
 
 
-	/* open or close I2C repeater gate */
-	buf[0] = 0x01;
-	if (chan_id == 1)
-		buf[1] = 0x18; /* open */
-	else
-		buf[1] = 0x10; /* close */
+	dev_dbg(&client->dev, "\n");
+	mutex_lock(&dev->regmap_mutex);
+}
 
 
-	ret = __i2c_transfer(adap, msg, 1);
-	if (ret != 1)
-		goto err;
+static void rtl2832_regmap_unlock(void *__dev)
+{
+	struct rtl2832_dev *dev = __dev;
+	struct i2c_client *client = dev->client;
 
 
-	priv->i2c_gate_state = chan_id;
+	dev_dbg(&client->dev, "\n");
+	mutex_unlock(&dev->regmap_mutex);
+}
 
 
-	return 0;
-err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+static struct dvb_frontend *rtl2832_get_dvb_frontend(struct i2c_client *client)
+{
+	struct rtl2832_dev *dev = i2c_get_clientdata(client);
 
 
-	return -EREMOTEIO;
+	dev_dbg(&client->dev, "\n");
+	return &dev->fe;
 }
 }
 
 
-static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
-		u32 chan_id)
+static struct i2c_adapter *rtl2832_get_i2c_adapter(struct i2c_client *client)
 {
 {
-	struct rtl2832_priv *priv = mux_priv;
-	schedule_delayed_work(&priv->i2c_gate_work, usecs_to_jiffies(100));
-	return 0;
+	struct rtl2832_dev *dev = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "\n");
+	return dev->i2c_adapter_tuner;
 }
 }
 
 
-int rtl2832_enable_external_ts_if(struct dvb_frontend *fe)
+static int rtl2832_enable_slave_ts(struct i2c_client *client)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct rtl2832_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
 
 
-	dev_dbg(&priv->i2c->dev, "%s: setting PIP mode\n", __func__);
+	dev_dbg(&client->dev, "\n");
 
 
-	ret = rtl2832_wr_regs(priv, 0x0c, 1, "\x5f\xff", 2);
+	ret = rtl2832_bulk_write(client, 0x10c, "\x5f\xff", 2);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_wr_demod_reg(priv, DVBT_PIP_ON, 0x1);
+	ret = rtl2832_wr_demod_reg(dev, DVBT_PIP_ON, 0x1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_wr_reg(priv, 0xbc, 0, 0x18);
+	ret = rtl2832_bulk_write(client, 0x0bc, "\x18", 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_wr_reg(priv, 0x22, 0, 0x01);
+	ret = rtl2832_bulk_write(client, 0x022, "\x01", 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_wr_reg(priv, 0x26, 0, 0x1f);
+	ret = rtl2832_bulk_write(client, 0x026, "\x1f", 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_wr_reg(priv, 0x27, 0, 0xff);
+	ret = rtl2832_bulk_write(client, 0x027, "\xff", 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_wr_regs(priv, 0x92, 1, "\x7f\xf7\xff", 3);
+	ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* soft reset */
 	/* soft reset */
-	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+	ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+	ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	return 0;
 	return 0;
 err:
 err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
-
 }
 }
-EXPORT_SYMBOL(rtl2832_enable_external_ts_if);
 
 
-struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe)
+static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-	return priv->i2c_adapter_tuner;
+	struct rtl2832_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
+	int ret;
+	u8 u8tmp;
+
+	dev_dbg(&client->dev, "onoff=%d\n", onoff);
+
+	/* enable / disable PID filter */
+	if (onoff)
+		u8tmp = 0x80;
+	else
+		u8tmp = 0x00;
+
+	ret = rtl2832_update_bits(client, 0x061, 0xc0, u8tmp);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+	return ret;
 }
 }
-EXPORT_SYMBOL(rtl2832_get_i2c_adapter);
 
 
-struct i2c_adapter *rtl2832_get_private_i2c_adapter(struct dvb_frontend *fe)
+static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid,
+			      int onoff)
 {
 {
-	struct rtl2832_priv *priv = fe->demodulator_priv;
-	return priv->i2c_adapter;
+	struct rtl2832_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
+	int ret;
+	u8 buf[4];
+
+	dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n",
+		index, pid, onoff);
+
+	/* skip invalid PIDs (0x2000) */
+	if (pid > 0x1fff || index > 32)
+		return 0;
+
+	if (onoff)
+		set_bit(index, &dev->filters);
+	else
+		clear_bit(index, &dev->filters);
+
+	/* enable / disable PIDs */
+	buf[0] = (dev->filters >>  0) & 0xff;
+	buf[1] = (dev->filters >>  8) & 0xff;
+	buf[2] = (dev->filters >> 16) & 0xff;
+	buf[3] = (dev->filters >> 24) & 0xff;
+	ret = rtl2832_bulk_write(client, 0x062, buf, 4);
+	if (ret)
+		goto err;
+
+	/* add PID */
+	buf[0] = (pid >> 8) & 0xff;
+	buf[1] = (pid >> 0) & 0xff;
+	ret = rtl2832_bulk_write(client, 0x066 + 2 * index, buf, 2);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+	return ret;
 }
 }
-EXPORT_SYMBOL(rtl2832_get_private_i2c_adapter);
 
 
-struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
-	struct i2c_adapter *i2c)
+static int rtl2832_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
 {
 {
-	struct rtl2832_priv *priv = NULL;
-	int ret = 0;
+	struct rtl2832_platform_data *pdata = client->dev.platform_data;
+	struct i2c_adapter *i2c = client->adapter;
+	struct rtl2832_dev *dev;
+	int ret;
 	u8 tmp;
 	u8 tmp;
+	static const struct regmap_bus regmap_bus = {
+		.read = rtl2832_regmap_read,
+		.write = rtl2832_regmap_write,
+		.gather_write = rtl2832_regmap_gather_write,
+		.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	};
+	static const struct regmap_range_cfg regmap_range_cfg[] = {
+		{
+			.selector_reg     = 0x00,
+			.selector_mask    = 0xff,
+			.selector_shift   = 0,
+			.window_start     = 0,
+			.window_len       = 0x100,
+			.range_min        = 0 * 0x100,
+			.range_max        = 5 * 0x100,
+		},
+	};
 
 
-	dev_dbg(&i2c->dev, "%s:\n", __func__);
+	dev_dbg(&client->dev, "\n");
 
 
 	/* allocate memory for the internal state */
 	/* allocate memory for the internal state */
-	priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
-	if (priv == NULL)
+	dev = kzalloc(sizeof(struct rtl2832_dev), GFP_KERNEL);
+	if (dev == NULL) {
+		ret = -ENOMEM;
 		goto err;
 		goto err;
+	}
 
 
-	/* setup the priv */
-	priv->i2c = i2c;
-	priv->tuner = cfg->tuner;
-	memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
-	INIT_DELAYED_WORK(&priv->i2c_gate_work, rtl2832_i2c_gate_work);
-
-	/* create muxed i2c adapter for demod itself */
-	priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0,
-			rtl2832_select, NULL);
-	if (priv->i2c_adapter == NULL)
-		goto err;
+	/* setup the state */
+	i2c_set_clientdata(client, dev);
+	dev->client = client;
+	dev->pdata = client->dev.platform_data;
+	dev->sleeping = true;
+	INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work);
+	INIT_DELAYED_WORK(&dev->stat_work, rtl2832_stat_work);
+	/* create regmap */
+	mutex_init(&dev->regmap_mutex);
+	dev->regmap_config.reg_bits =  8,
+	dev->regmap_config.val_bits =  8,
+	dev->regmap_config.lock = rtl2832_regmap_lock,
+	dev->regmap_config.unlock = rtl2832_regmap_unlock,
+	dev->regmap_config.lock_arg = dev,
+	dev->regmap_config.volatile_reg = rtl2832_volatile_reg,
+	dev->regmap_config.max_register = 5 * 0x100,
+	dev->regmap_config.ranges = regmap_range_cfg,
+	dev->regmap_config.num_ranges = ARRAY_SIZE(regmap_range_cfg),
+	dev->regmap_config.cache_type = REGCACHE_RBTREE,
+	dev->regmap = regmap_init(&client->dev, &regmap_bus, client,
+				  &dev->regmap_config);
+	if (IS_ERR(dev->regmap)) {
+		ret = PTR_ERR(dev->regmap);
+		goto err_kfree;
+	}
 
 
 	/* check if the demod is there */
 	/* check if the demod is there */
-	ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
+	ret = rtl2832_bulk_read(client, 0x000, &tmp, 1);
 	if (ret)
 	if (ret)
-		goto err;
+		goto err_regmap_exit;
 
 
 	/* create muxed i2c adapter for demod tuner bus */
 	/* create muxed i2c adapter for demod tuner bus */
-	priv->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, priv,
-			0, 1, 0, rtl2832_select, rtl2832_deselect);
-	if (priv->i2c_adapter_tuner == NULL)
-		goto err;
+	dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev,
+			0, 0, 0, rtl2832_select, rtl2832_deselect);
+	if (dev->i2c_adapter_tuner == NULL) {
+		ret = -ENODEV;
+		goto err_regmap_exit;
+	}
 
 
 	/* create dvb_frontend */
 	/* create dvb_frontend */
-	memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
-	priv->fe.demodulator_priv = priv;
-
-	/* TODO implement sleep mode */
-	priv->sleeping = true;
-
-	return &priv->fe;
+	memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
+	dev->fe.demodulator_priv = dev;
+
+	/* setup callbacks */
+	pdata->get_dvb_frontend = rtl2832_get_dvb_frontend;
+	pdata->get_i2c_adapter = rtl2832_get_i2c_adapter;
+	pdata->enable_slave_ts = rtl2832_enable_slave_ts;
+	pdata->pid_filter = rtl2832_pid_filter;
+	pdata->pid_filter_ctrl = rtl2832_pid_filter_ctrl;
+	pdata->bulk_read = rtl2832_bulk_read;
+	pdata->bulk_write = rtl2832_bulk_write;
+	pdata->update_bits = rtl2832_update_bits;
+
+	dev_info(&client->dev, "Realtek RTL2832 successfully attached\n");
+	return 0;
+err_regmap_exit:
+	regmap_exit(dev->regmap);
+err_kfree:
+	kfree(dev);
 err:
 err:
-	dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
-	if (priv && priv->i2c_adapter)
-		i2c_del_mux_adapter(priv->i2c_adapter);
-	kfree(priv);
-	return NULL;
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+	return ret;
 }
 }
-EXPORT_SYMBOL(rtl2832_attach);
 
 
-static struct dvb_frontend_ops rtl2832_ops = {
-	.delsys = { SYS_DVBT },
-	.info = {
-		.name = "Realtek RTL2832 (DVB-T)",
-		.frequency_min	  = 174000000,
-		.frequency_max	  = 862000000,
-		.frequency_stepsize = 166667,
-		.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_64 |
-			FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO |
-			FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO |
-			FE_CAN_RECOVER |
-			FE_CAN_MUTE_TS
-	 },
+static int rtl2832_remove(struct i2c_client *client)
+{
+	struct rtl2832_dev *dev = i2c_get_clientdata(client);
 
 
-	.release = rtl2832_release,
+	dev_dbg(&client->dev, "\n");
 
 
-	.init = rtl2832_init,
-	.sleep = rtl2832_sleep,
+	cancel_delayed_work_sync(&dev->i2c_gate_work);
 
 
-	.get_tune_settings = rtl2832_get_tune_settings,
+	i2c_del_mux_adapter(dev->i2c_adapter_tuner);
 
 
-	.set_frontend = rtl2832_set_frontend,
-	.get_frontend = rtl2832_get_frontend,
+	regmap_exit(dev->regmap);
 
 
-	.read_status = rtl2832_read_status,
-	.read_snr = rtl2832_read_snr,
-	.read_ber = rtl2832_read_ber,
+	kfree(dev);
 
 
-	.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
+	return 0;
+}
+
+static const struct i2c_device_id rtl2832_id_table[] = {
+	{"rtl2832", 0},
+	{}
 };
 };
+MODULE_DEVICE_TABLE(i2c, rtl2832_id_table);
+
+static struct i2c_driver rtl2832_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "rtl2832",
+	},
+	.probe		= rtl2832_probe,
+	.remove		= rtl2832_remove,
+	.id_table	= rtl2832_id_table,
+};
+
+module_i2c_driver(rtl2832_driver);
 
 
 MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
 MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
 MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.5");

+ 28 - 71
drivers/media/dvb-frontends/rtl2832.h

@@ -2,6 +2,7 @@
  * Realtek RTL2832 DVB-T demodulator driver
  * Realtek RTL2832 DVB-T demodulator driver
  *
  *
  * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
  * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ * Copyright (C) 2012-2014 Antti Palosaari <crope@iki.fi>
  *
  *
  *	This program is free software; you can redistribute it and/or modify
  *	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
  *	it under the terms of the GNU General Public License as published by
@@ -21,86 +22,42 @@
 #ifndef RTL2832_H
 #ifndef RTL2832_H
 #define RTL2832_H
 #define RTL2832_H
 
 
-#include <linux/kconfig.h>
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/frontend.h>
+#include <linux/i2c-mux.h>
+
+/**
+ * struct rtl2832_platform_data - Platform data for the rtl2832 driver
+ * @clk: Clock frequency (4000000, 16000000, 25000000, 28800000).
+ * @tuner: Used tuner model.
+ * @get_dvb_frontend: Get DVB frontend.
+ * @get_i2c_adapter: Get I2C adapter.
+ * @enable_slave_ts: Enable slave TS IF.
+ * @pid_filter: Set PID to PID filter.
+ * @pid_filter_ctrl: Control PID filter.
+ */
 
 
-struct rtl2832_config {
-	/*
-	 * Demodulator I2C address.
-	 */
-	u8 i2c_addr;
-
-	/*
-	 * Xtal frequency.
-	 * Hz
-	 * 4000000, 16000000, 25000000, 28800000
-	 */
-	u32 xtal;
-
+struct rtl2832_platform_data {
+	u32 clk;
 	/*
 	/*
-	 * tuner
-	 * XXX: This must be keep sync with dvb_usb_rtl28xxu demod driver.
+	 * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver.
 	 */
 	 */
 #define RTL2832_TUNER_TUA9001   0x24
 #define RTL2832_TUNER_TUA9001   0x24
 #define RTL2832_TUNER_FC0012    0x26
 #define RTL2832_TUNER_FC0012    0x26
 #define RTL2832_TUNER_E4000     0x27
 #define RTL2832_TUNER_E4000     0x27
 #define RTL2832_TUNER_FC0013    0x29
 #define RTL2832_TUNER_FC0013    0x29
-#define RTL2832_TUNER_R820T	0x2a
-#define RTL2832_TUNER_R828D	0x2b
+#define RTL2832_TUNER_R820T     0x2a
+#define RTL2832_TUNER_R828D     0x2b
 	u8 tuner;
 	u8 tuner;
-};
-
-#if IS_ENABLED(CONFIG_DVB_RTL2832)
-struct dvb_frontend *rtl2832_attach(
-	const struct rtl2832_config *cfg,
-	struct i2c_adapter *i2c
-);
-
-extern struct i2c_adapter *rtl2832_get_i2c_adapter(
-	struct dvb_frontend *fe
-);
-
-extern struct i2c_adapter *rtl2832_get_private_i2c_adapter(
-	struct dvb_frontend *fe
-);
-
-extern int rtl2832_enable_external_ts_if(
-	struct dvb_frontend *fe
-);
-
-#else
-
-static inline struct dvb_frontend *rtl2832_attach(
-	const struct rtl2832_config *config,
-	struct i2c_adapter *i2c
-)
-{
-	pr_warn("%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline struct i2c_adapter *rtl2832_get_i2c_adapter(
-	struct dvb_frontend *fe
-)
-{
-	return NULL;
-}
-
-static inline struct i2c_adapter *rtl2832_get_private_i2c_adapter(
-	struct dvb_frontend *fe
-)
-{
-	return NULL;
-}
-
-static inline int rtl2832_enable_external_ts_if(
-	struct dvb_frontend *fe
-)
-{
-	return -ENODEV;
-}
-
-#endif
 
 
+	struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
+	struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *);
+	int (*enable_slave_ts)(struct i2c_client *);
+	int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
+	int (*pid_filter_ctrl)(struct dvb_frontend *, int);
+/* private: Register access for SDR module use only */
+	int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t);
+	int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t);
+	int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int);
+};
 
 
 #endif /* RTL2832_H */
 #endif /* RTL2832_H */

+ 19 - 13
drivers/media/dvb-frontends/rtl2832_priv.h

@@ -2,6 +2,7 @@
  * Realtek RTL2832 DVB-T demodulator driver
  * Realtek RTL2832 DVB-T demodulator driver
  *
  *
  * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
  * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ * Copyright (C) 2012-2014 Antti Palosaari <crope@iki.fi>
  *
  *
  *	This program is free software; you can redistribute it and/or modify
  *	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
  *	it under the terms of the GNU General Public License as published by
@@ -21,28 +22,34 @@
 #ifndef RTL2832_PRIV_H
 #ifndef RTL2832_PRIV_H
 #define RTL2832_PRIV_H
 #define RTL2832_PRIV_H
 
 
+#include <linux/regmap.h>
+#include <linux/math64.h>
+#include <linux/bitops.h>
+
 #include "dvb_frontend.h"
 #include "dvb_frontend.h"
+#include "dvb_math.h"
 #include "rtl2832.h"
 #include "rtl2832.h"
-#include <linux/i2c-mux.h>
 
 
-struct rtl2832_priv {
-	struct i2c_adapter *i2c;
-	struct i2c_adapter *i2c_adapter;
+struct rtl2832_dev {
+	struct rtl2832_platform_data *pdata;
+	struct i2c_client *client;
+	struct mutex regmap_mutex;
+	struct regmap_config regmap_config;
+	struct regmap *regmap;
 	struct i2c_adapter *i2c_adapter_tuner;
 	struct i2c_adapter *i2c_adapter_tuner;
 	struct dvb_frontend fe;
 	struct dvb_frontend fe;
-	struct rtl2832_config cfg;
-
-	bool i2c_gate_state;
+	struct delayed_work stat_work;
+	fe_status_t fe_status;
+	u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */
+	u64 post_bit_error;
+	u64 post_bit_count;
 	bool sleeping;
 	bool sleeping;
-
-	u8 tuner;
-	u8 page; /* active register page */
 	struct delayed_work i2c_gate_work;
 	struct delayed_work i2c_gate_work;
+	unsigned long filters; /* PID filter */
 };
 };
 
 
 struct rtl2832_reg_entry {
 struct rtl2832_reg_entry {
-	u8 page;
-	u8 start_address;
+	u16 start_address;
 	u8 msb;
 	u8 msb;
 	u8 lsb;
 	u8 lsb;
 };
 };
@@ -52,7 +59,6 @@ struct rtl2832_reg_value {
 	u32 value;
 	u32 value;
 };
 };
 
 
-
 /* Demod register bit names */
 /* Demod register bit names */
 enum DVBT_REG_BIT_NAME {
 enum DVBT_REG_BIT_NAME {
 	DVBT_SOFT_RST,
 	DVBT_SOFT_RST,

+ 557 - 632
drivers/media/dvb-frontends/rtl2832_sdr.c

@@ -22,7 +22,6 @@
  *
  *
  */
  */
 
 
-#include "dvb_frontend.h"
 #include "rtl2832_sdr.h"
 #include "rtl2832_sdr.h"
 #include "dvb_usb.h"
 #include "dvb_usb.h"
 
 
@@ -32,6 +31,7 @@
 #include <media/v4l2-event.h>
 #include <media/v4l2-event.h>
 #include <media/videobuf2-vmalloc.h>
 #include <media/videobuf2-vmalloc.h>
 
 
+#include <linux/platform_device.h>
 #include <linux/jiffies.h>
 #include <linux/jiffies.h>
 #include <linux/math64.h>
 #include <linux/math64.h>
 
 
@@ -107,16 +107,12 @@ struct rtl2832_sdr_frame_buf {
 	struct list_head list;
 	struct list_head list;
 };
 };
 
 
-struct rtl2832_sdr_state {
+struct rtl2832_sdr_dev {
 #define POWER_ON           (1 << 1)
 #define POWER_ON           (1 << 1)
 #define URB_BUF            (1 << 2)
 #define URB_BUF            (1 << 2)
 	unsigned long flags;
 	unsigned long flags;
 
 
-	const struct rtl2832_config *cfg;
-	struct dvb_frontend *fe;
-	struct dvb_usb_device *d;
-	struct i2c_adapter *i2c;
-	u8 bank;
+	struct platform_device *pdev;
 
 
 	struct video_device vdev;
 	struct video_device vdev;
 	struct v4l2_device v4l2_dev;
 	struct v4l2_device v4l2_dev;
@@ -160,200 +156,77 @@ struct rtl2832_sdr_state {
 	unsigned long jiffies_next;
 	unsigned long jiffies_next;
 };
 };
 
 
-/* write multiple hardware registers */
-static int rtl2832_sdr_wr(struct rtl2832_sdr_state *s, u8 reg, const u8 *val,
-		int len)
-{
-	int ret;
-#define MAX_WR_LEN 24
-#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1)
-	u8 buf[MAX_WR_XFER_LEN];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = s->cfg->i2c_addr,
-			.flags = 0,
-			.len = 1 + len,
-			.buf = buf,
-		}
-	};
-
-	if (WARN_ON(len > MAX_WR_LEN))
-		return -EINVAL;
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
-
-	ret = i2c_transfer(s->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		dev_err(&s->i2c->dev,
-			"%s: I2C wr failed=%d reg=%02x len=%d\n",
-			KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* read multiple hardware registers */
-static int rtl2832_sdr_rd(struct rtl2832_sdr_state *s, u8 reg, u8 *val, int len)
-{
-	int ret;
-	struct i2c_msg msg[2] = {
-		{
-			.addr = s->cfg->i2c_addr,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = s->cfg->i2c_addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = val,
-		}
-	};
-
-	ret = i2c_transfer(s->i2c, msg, 2);
-	if (ret == 2) {
-		ret = 0;
-	} else {
-		dev_err(&s->i2c->dev,
-				"%s: I2C rd failed=%d reg=%02x len=%d\n",
-				KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
 /* write multiple registers */
 /* write multiple registers */
-static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_state *s, u16 reg,
+static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_dev *dev, u16 reg,
 		const u8 *val, int len)
 		const u8 *val, int len)
 {
 {
-	int ret;
-	u8 reg2 = (reg >> 0) & 0xff;
-	u8 bank = (reg >> 8) & 0xff;
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct i2c_client *client = pdata->i2c_client;
 
 
-	/* switch bank if needed */
-	if (bank != s->bank) {
-		ret = rtl2832_sdr_wr(s, 0x00, &bank, 1);
-		if (ret)
-			return ret;
-
-		s->bank = bank;
-	}
-
-	return rtl2832_sdr_wr(s, reg2, val, len);
+	return pdata->bulk_write(client, reg, val, len);
 }
 }
 
 
+#if 0
 /* read multiple registers */
 /* read multiple registers */
-static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_state *s, u16 reg, u8 *val,
+static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_dev *dev, u16 reg, u8 *val,
 		int len)
 		int len)
 {
 {
-	int ret;
-	u8 reg2 = (reg >> 0) & 0xff;
-	u8 bank = (reg >> 8) & 0xff;
-
-	/* switch bank if needed */
-	if (bank != s->bank) {
-		ret = rtl2832_sdr_wr(s, 0x00, &bank, 1);
-		if (ret)
-			return ret;
-
-		s->bank = bank;
-	}
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct i2c_client *client = pdata->i2c_client;
 
 
-	return rtl2832_sdr_rd(s, reg2, val, len);
+	return pdata->bulk_read(client, reg, val, len);
 }
 }
+#endif
 
 
 /* write single register */
 /* write single register */
-static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_state *s, u16 reg, u8 val)
+static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_dev *dev, u16 reg, u8 val)
 {
 {
-	return rtl2832_sdr_wr_regs(s, reg, &val, 1);
+	return rtl2832_sdr_wr_regs(dev, reg, &val, 1);
 }
 }
 
 
-#if 0
-/* read single register */
-static int rtl2832_sdr_rd_reg(struct rtl2832_sdr_state *s, u16 reg, u8 *val)
-{
-	return rtl2832_sdr_rd_regs(s, reg, val, 1);
-}
-#endif
-
 /* write single register with mask */
 /* write single register with mask */
-static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_state *s, u16 reg,
+static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_dev *dev, u16 reg,
 		u8 val, u8 mask)
 		u8 val, u8 mask)
 {
 {
-	int ret;
-	u8 tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		tmp &= ~mask;
-		val |= tmp;
-	}
-
-	return rtl2832_sdr_wr_regs(s, reg, &val, 1);
-}
-
-#if 0
-/* read single register with mask */
-static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_state *s, u16 reg,
-		u8 *val, u8 mask)
-{
-	int ret, i;
-	u8 tmp;
-
-	ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1);
-	if (ret)
-		return ret;
-
-	tmp &= mask;
-
-	/* find position of the first bit */
-	for (i = 0; i < 8; i++) {
-		if ((mask >> i) & 0x01)
-			break;
-	}
-	*val = tmp >> i;
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct i2c_client *client = pdata->i2c_client;
 
 
-	return 0;
+	return pdata->update_bits(client, reg, mask, val);
 }
 }
-#endif
 
 
 /* Private functions */
 /* Private functions */
 static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf(
 static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf(
-		struct rtl2832_sdr_state *s)
+		struct rtl2832_sdr_dev *dev)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 	struct rtl2832_sdr_frame_buf *buf = NULL;
 	struct rtl2832_sdr_frame_buf *buf = NULL;
 
 
-	spin_lock_irqsave(&s->queued_bufs_lock, flags);
-	if (list_empty(&s->queued_bufs))
+	spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+	if (list_empty(&dev->queued_bufs))
 		goto leave;
 		goto leave;
 
 
-	buf = list_entry(s->queued_bufs.next,
+	buf = list_entry(dev->queued_bufs.next,
 			struct rtl2832_sdr_frame_buf, list);
 			struct rtl2832_sdr_frame_buf, list);
 	list_del(&buf->list);
 	list_del(&buf->list);
 leave:
 leave:
-	spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
 	return buf;
 	return buf;
 }
 }
 
 
-static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
+static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_dev *dev,
 		void *dst, const u8 *src, unsigned int src_len)
 		void *dst, const u8 *src, unsigned int src_len)
 {
 {
+	struct platform_device *pdev = dev->pdev;
 	unsigned int dst_len;
 	unsigned int dst_len;
 
 
-	if (s->pixelformat ==  V4L2_SDR_FMT_CU8) {
+	if (dev->pixelformat ==  V4L2_SDR_FMT_CU8) {
 		/* native stream, no need to convert */
 		/* native stream, no need to convert */
 		memcpy(dst, src, src_len);
 		memcpy(dst, src, src_len);
 		dst_len = src_len;
 		dst_len = src_len;
-	} else if (s->pixelformat == V4L2_SDR_FMT_CU16LE) {
+	} else if (dev->pixelformat == V4L2_SDR_FMT_CU16LE) {
 		/* convert u8 to u16 */
 		/* convert u8 to u16 */
 		unsigned int i;
 		unsigned int i;
 		u16 *u16dst = dst;
 		u16 *u16dst = dst;
@@ -366,22 +239,21 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
 	}
 	}
 
 
 	/* calculate sample rate and output it in 10 seconds intervals */
 	/* calculate sample rate and output it in 10 seconds intervals */
-	if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
+	if (unlikely(time_is_before_jiffies(dev->jiffies_next))) {
 		#define MSECS 10000UL
 		#define MSECS 10000UL
 		unsigned int msecs = jiffies_to_msecs(jiffies -
 		unsigned int msecs = jiffies_to_msecs(jiffies -
-				s->jiffies_next + msecs_to_jiffies(MSECS));
-		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,
-				"slen=%u samples=%u msecs=%u sample rate=%lu\n",
-				src_len, samples, msecs,
-				samples * 1000UL / msecs);
+				dev->jiffies_next + msecs_to_jiffies(MSECS));
+		unsigned int samples = dev->sample - dev->sample_measured;
+
+		dev->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
+		dev->sample_measured = dev->sample;
+		dev_dbg(&pdev->dev,
+			"slen=%u samples=%u msecs=%u sample rate=%lu\n",
+			src_len, samples, msecs, samples * 1000UL / msecs);
 	}
 	}
 
 
 	/* total number of I+Q pairs */
 	/* total number of I+Q pairs */
-	s->sample += src_len / 2;
+	dev->sample += src_len / 2;
 
 
 	return dst_len;
 	return dst_len;
 }
 }
@@ -392,13 +264,13 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
  */
  */
 static void rtl2832_sdr_urb_complete(struct urb *urb)
 static void rtl2832_sdr_urb_complete(struct urb *urb)
 {
 {
-	struct rtl2832_sdr_state *s = urb->context;
+	struct rtl2832_sdr_dev *dev = urb->context;
+	struct platform_device *pdev = dev->pdev;
 	struct rtl2832_sdr_frame_buf *fbuf;
 	struct rtl2832_sdr_frame_buf *fbuf;
 
 
-	dev_dbg_ratelimited(&s->udev->dev,
-			"status=%d length=%d/%d errors=%d\n",
-			urb->status, urb->actual_length,
-			urb->transfer_buffer_length, urb->error_count);
+	dev_dbg_ratelimited(&pdev->dev, "status=%d length=%d/%d errors=%d\n",
+			    urb->status, urb->actual_length,
+			    urb->transfer_buffer_length, urb->error_count);
 
 
 	switch (urb->status) {
 	switch (urb->status) {
 	case 0:             /* success */
 	case 0:             /* success */
@@ -409,8 +281,7 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
 	case -ESHUTDOWN:
 	case -ESHUTDOWN:
 		return;
 		return;
 	default:            /* error */
 	default:            /* error */
-		dev_err_ratelimited(&s->udev->dev, "urb failed=%d\n",
-				urb->status);
+		dev_err_ratelimited(&pdev->dev, "urb failed=%d\n", urb->status);
 		break;
 		break;
 	}
 	}
 
 
@@ -418,204 +289,192 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
 		void *ptr;
 		void *ptr;
 		unsigned int len;
 		unsigned int len;
 		/* get free framebuffer */
 		/* get free framebuffer */
-		fbuf = rtl2832_sdr_get_next_fill_buf(s);
+		fbuf = rtl2832_sdr_get_next_fill_buf(dev);
 		if (unlikely(fbuf == NULL)) {
 		if (unlikely(fbuf == NULL)) {
-			s->vb_full++;
-			dev_notice_ratelimited(&s->udev->dev,
-					"videobuf is full, %d packets dropped\n",
-					s->vb_full);
+			dev->vb_full++;
+			dev_notice_ratelimited(&pdev->dev,
+					       "videobuf is full, %d packets dropped\n",
+					       dev->vb_full);
 			goto skip;
 			goto skip;
 		}
 		}
 
 
 		/* fill framebuffer */
 		/* fill framebuffer */
 		ptr = vb2_plane_vaddr(&fbuf->vb, 0);
 		ptr = vb2_plane_vaddr(&fbuf->vb, 0);
-		len = rtl2832_sdr_convert_stream(s, ptr, urb->transfer_buffer,
+		len = rtl2832_sdr_convert_stream(dev, ptr, urb->transfer_buffer,
 				urb->actual_length);
 				urb->actual_length);
 		vb2_set_plane_payload(&fbuf->vb, 0, len);
 		vb2_set_plane_payload(&fbuf->vb, 0, len);
 		v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp);
 		v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp);
-		fbuf->vb.v4l2_buf.sequence = s->sequence++;
+		fbuf->vb.v4l2_buf.sequence = dev->sequence++;
 		vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
 		vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
 	}
 	}
 skip:
 skip:
 	usb_submit_urb(urb, GFP_ATOMIC);
 	usb_submit_urb(urb, GFP_ATOMIC);
 }
 }
 
 
-static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_dev *dev)
 {
 {
+	struct platform_device *pdev = dev->pdev;
 	int i;
 	int i;
 
 
-	for (i = s->urbs_submitted - 1; i >= 0; i--) {
-		dev_dbg(&s->udev->dev, "kill urb=%d\n", i);
+	for (i = dev->urbs_submitted - 1; i >= 0; i--) {
+		dev_dbg(&pdev->dev, "kill urb=%d\n", i);
 		/* stop the URB */
 		/* stop the URB */
-		usb_kill_urb(s->urb_list[i]);
+		usb_kill_urb(dev->urb_list[i]);
 	}
 	}
-	s->urbs_submitted = 0;
+	dev->urbs_submitted = 0;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_dev *dev)
 {
 {
+	struct platform_device *pdev = dev->pdev;
 	int i, ret;
 	int i, ret;
 
 
-	for (i = 0; i < s->urbs_initialized; i++) {
-		dev_dbg(&s->udev->dev, "submit urb=%d\n", i);
-		ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
+	for (i = 0; i < dev->urbs_initialized; i++) {
+		dev_dbg(&pdev->dev, "submit urb=%d\n", i);
+		ret = usb_submit_urb(dev->urb_list[i], GFP_ATOMIC);
 		if (ret) {
 		if (ret) {
-			dev_err(&s->udev->dev,
-					"Could not submit urb no. %d - get them all back\n",
-					i);
-			rtl2832_sdr_kill_urbs(s);
+			dev_err(&pdev->dev,
+				"Could not submit urb no. %d - get them all back\n",
+				i);
+			rtl2832_sdr_kill_urbs(dev);
 			return ret;
 			return ret;
 		}
 		}
-		s->urbs_submitted++;
+		dev->urbs_submitted++;
 	}
 	}
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_dev *dev)
 {
 {
-	if (s->flags & USB_STATE_URB_BUF) {
-		while (s->buf_num) {
-			s->buf_num--;
-			dev_dbg(&s->udev->dev, "free buf=%d\n", s->buf_num);
-			usb_free_coherent(s->udev, s->buf_size,
-					  s->buf_list[s->buf_num],
-					  s->dma_addr[s->buf_num]);
+	struct platform_device *pdev = dev->pdev;
+
+	if (dev->flags & USB_STATE_URB_BUF) {
+		while (dev->buf_num) {
+			dev->buf_num--;
+			dev_dbg(&pdev->dev, "free buf=%d\n", dev->buf_num);
+			usb_free_coherent(dev->udev, dev->buf_size,
+					  dev->buf_list[dev->buf_num],
+					  dev->dma_addr[dev->buf_num]);
 		}
 		}
 	}
 	}
-	s->flags &= ~USB_STATE_URB_BUF;
+	dev->flags &= ~USB_STATE_URB_BUF;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_dev *dev)
 {
 {
-	s->buf_num = 0;
-	s->buf_size = BULK_BUFFER_SIZE;
+	struct platform_device *pdev = dev->pdev;
 
 
-	dev_dbg(&s->udev->dev, "all in all I will use %u bytes for streaming\n",
-			MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+	dev->buf_num = 0;
+	dev->buf_size = BULK_BUFFER_SIZE;
 
 
-	for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
-		s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
+	dev_dbg(&pdev->dev, "all in all I will use %u bytes for streaming\n",
+		MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+
+	for (dev->buf_num = 0; dev->buf_num < MAX_BULK_BUFS; dev->buf_num++) {
+		dev->buf_list[dev->buf_num] = usb_alloc_coherent(dev->udev,
 				BULK_BUFFER_SIZE, GFP_ATOMIC,
 				BULK_BUFFER_SIZE, GFP_ATOMIC,
-				&s->dma_addr[s->buf_num]);
-		if (!s->buf_list[s->buf_num]) {
-			dev_dbg(&s->udev->dev, "alloc buf=%d failed\n",
-					s->buf_num);
-			rtl2832_sdr_free_stream_bufs(s);
+				&dev->dma_addr[dev->buf_num]);
+		if (!dev->buf_list[dev->buf_num]) {
+			dev_dbg(&pdev->dev, "alloc buf=%d failed\n",
+				dev->buf_num);
+			rtl2832_sdr_free_stream_bufs(dev);
 			return -ENOMEM;
 			return -ENOMEM;
 		}
 		}
 
 
-		dev_dbg(&s->udev->dev, "alloc buf=%d %p (dma %llu)\n",
-				s->buf_num, s->buf_list[s->buf_num],
-				(long long)s->dma_addr[s->buf_num]);
-		s->flags |= USB_STATE_URB_BUF;
+		dev_dbg(&pdev->dev, "alloc buf=%d %p (dma %llu)\n",
+			dev->buf_num, dev->buf_list[dev->buf_num],
+			(long long)dev->dma_addr[dev->buf_num]);
+		dev->flags |= USB_STATE_URB_BUF;
 	}
 	}
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_dev *dev)
 {
 {
+	struct platform_device *pdev = dev->pdev;
 	int i;
 	int i;
 
 
-	rtl2832_sdr_kill_urbs(s);
+	rtl2832_sdr_kill_urbs(dev);
 
 
-	for (i = s->urbs_initialized - 1; i >= 0; i--) {
-		if (s->urb_list[i]) {
-			dev_dbg(&s->udev->dev, "free urb=%d\n", i);
+	for (i = dev->urbs_initialized - 1; i >= 0; i--) {
+		if (dev->urb_list[i]) {
+			dev_dbg(&pdev->dev, "free urb=%d\n", i);
 			/* free the URBs */
 			/* free the URBs */
-			usb_free_urb(s->urb_list[i]);
+			usb_free_urb(dev->urb_list[i]);
 		}
 		}
 	}
 	}
-	s->urbs_initialized = 0;
+	dev->urbs_initialized = 0;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_dev *dev)
 {
 {
+	struct platform_device *pdev = dev->pdev;
 	int i, j;
 	int i, j;
 
 
 	/* allocate the URBs */
 	/* allocate the URBs */
 	for (i = 0; i < MAX_BULK_BUFS; i++) {
 	for (i = 0; i < MAX_BULK_BUFS; i++) {
-		dev_dbg(&s->udev->dev, "alloc urb=%d\n", i);
-		s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
-		if (!s->urb_list[i]) {
-			dev_dbg(&s->udev->dev, "failed\n");
+		dev_dbg(&pdev->dev, "alloc urb=%d\n", i);
+		dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+		if (!dev->urb_list[i]) {
+			dev_dbg(&pdev->dev, "failed\n");
 			for (j = 0; j < i; j++)
 			for (j = 0; j < i; j++)
-				usb_free_urb(s->urb_list[j]);
+				usb_free_urb(dev->urb_list[j]);
 			return -ENOMEM;
 			return -ENOMEM;
 		}
 		}
-		usb_fill_bulk_urb(s->urb_list[i],
-				s->udev,
-				usb_rcvbulkpipe(s->udev, 0x81),
-				s->buf_list[i],
+		usb_fill_bulk_urb(dev->urb_list[i],
+				dev->udev,
+				usb_rcvbulkpipe(dev->udev, 0x81),
+				dev->buf_list[i],
 				BULK_BUFFER_SIZE,
 				BULK_BUFFER_SIZE,
-				rtl2832_sdr_urb_complete, s);
+				rtl2832_sdr_urb_complete, dev);
 
 
-		s->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
-		s->urb_list[i]->transfer_dma = s->dma_addr[i];
-		s->urbs_initialized++;
+		dev->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+		dev->urb_list[i]->transfer_dma = dev->dma_addr[i];
+		dev->urbs_initialized++;
 	}
 	}
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 /* Must be called with vb_queue_lock hold */
 /* Must be called with vb_queue_lock hold */
-static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
+static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev)
 {
 {
+	struct platform_device *pdev = dev->pdev;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
-	spin_lock_irqsave(&s->queued_bufs_lock, flags);
-	while (!list_empty(&s->queued_bufs)) {
+	spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+	while (!list_empty(&dev->queued_bufs)) {
 		struct rtl2832_sdr_frame_buf *buf;
 		struct rtl2832_sdr_frame_buf *buf;
 
 
-		buf = list_entry(s->queued_bufs.next,
+		buf = list_entry(dev->queued_bufs.next,
 				struct rtl2832_sdr_frame_buf, list);
 				struct rtl2832_sdr_frame_buf, list);
 		list_del(&buf->list);
 		list_del(&buf->list);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
 	}
 	}
-	spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
-}
-
-/* The user yanked out the cable... */
-static void rtl2832_sdr_release_sec(struct dvb_frontend *fe)
-{
-	struct rtl2832_sdr_state *s = fe->sec_priv;
-
-	dev_dbg(&s->udev->dev, "\n");
-
-	mutex_lock(&s->vb_queue_lock);
-	mutex_lock(&s->v4l2_lock);
-	/* No need to keep the urbs around after disconnection */
-	s->udev = NULL;
-
-	v4l2_device_disconnect(&s->v4l2_dev);
-	video_unregister_device(&s->vdev);
-	mutex_unlock(&s->v4l2_lock);
-	mutex_unlock(&s->vb_queue_lock);
-
-	v4l2_device_put(&s->v4l2_dev);
-
-	fe->sec_priv = NULL;
+	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
 }
 }
 
 
 static int rtl2832_sdr_querycap(struct file *file, void *fh,
 static int rtl2832_sdr_querycap(struct file *file, void *fh,
 		struct v4l2_capability *cap)
 		struct v4l2_capability *cap)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
 	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
 	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
-	strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
-	usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
+	strlcpy(cap->card, dev->vdev.name, sizeof(cap->card));
+	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 	cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
 	cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
 			V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
 			V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -627,26 +486,26 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
 		const struct v4l2_format *fmt, unsigned int *nbuffers,
 		const struct v4l2_format *fmt, unsigned int *nbuffers,
 		unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
 		unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
 {
 {
-	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+	struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq);
+	struct platform_device *pdev = dev->pdev;
 
 
-	dev_dbg(&s->udev->dev, "nbuffers=%d\n", *nbuffers);
+	dev_dbg(&pdev->dev, "nbuffers=%d\n", *nbuffers);
 
 
 	/* Need at least 8 buffers */
 	/* Need at least 8 buffers */
 	if (vq->num_buffers + *nbuffers < 8)
 	if (vq->num_buffers + *nbuffers < 8)
 		*nbuffers = 8 - vq->num_buffers;
 		*nbuffers = 8 - vq->num_buffers;
 	*nplanes = 1;
 	*nplanes = 1;
-	sizes[0] = PAGE_ALIGN(s->buffersize);
-	dev_dbg(&s->udev->dev, "nbuffers=%d sizes[0]=%d\n",
-			*nbuffers, sizes[0]);
+	sizes[0] = PAGE_ALIGN(dev->buffersize);
+	dev_dbg(&pdev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
 	return 0;
 	return 0;
 }
 }
 
 
 static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb)
 static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb)
 {
 {
-	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue);
+	struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
 
 
 	/* Don't allow queing new buffers after device disconnection */
 	/* Don't allow queing new buffers after device disconnection */
-	if (!s->udev)
+	if (!dev->udev)
 		return -ENODEV;
 		return -ENODEV;
 
 
 	return 0;
 	return 0;
@@ -654,46 +513,48 @@ static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb)
 
 
 static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb)
 static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb)
 {
 {
-	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue);
+	struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
 	struct rtl2832_sdr_frame_buf *buf =
 	struct rtl2832_sdr_frame_buf *buf =
 			container_of(vb, struct rtl2832_sdr_frame_buf, vb);
 			container_of(vb, struct rtl2832_sdr_frame_buf, vb);
 	unsigned long flags;
 	unsigned long flags;
 
 
 	/* Check the device has not disconnected between prep and queuing */
 	/* Check the device has not disconnected between prep and queuing */
-	if (!s->udev) {
+	if (!dev->udev) {
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
 		return;
 		return;
 	}
 	}
 
 
-	spin_lock_irqsave(&s->queued_bufs_lock, flags);
-	list_add_tail(&buf->list, &s->queued_bufs);
-	spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+	spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+	list_add_tail(&buf->list, &dev->queued_bufs);
+	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
 }
 }
 
 
-static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
 {
 {
-	struct dvb_frontend *fe = s->fe;
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct dvb_frontend *fe = pdata->dvb_frontend;
 	int ret;
 	int ret;
 	unsigned int f_sr, f_if;
 	unsigned int f_sr, f_if;
 	u8 buf[4], u8tmp1, u8tmp2;
 	u8 buf[4], u8tmp1, u8tmp2;
 	u64 u64tmp;
 	u64 u64tmp;
 	u32 u32tmp;
 	u32 u32tmp;
 
 
-	dev_dbg(&s->udev->dev, "f_adc=%u\n", s->f_adc);
+	dev_dbg(&pdev->dev, "f_adc=%u\n", dev->f_adc);
 
 
-	if (!test_bit(POWER_ON, &s->flags))
+	if (!test_bit(POWER_ON, &dev->flags))
 		return 0;
 		return 0;
 
 
-	if (s->f_adc == 0)
+	if (dev->f_adc == 0)
 		return 0;
 		return 0;
 
 
-	f_sr = s->f_adc;
+	f_sr = dev->f_adc;
 
 
-	ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x00\x00", 2);
+	ret = rtl2832_sdr_wr_regs(dev, 0x13e, "\x00\x00", 2);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_wr_regs(s, 0x115, "\x00\x00\x00\x00", 4);
+	ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x00\x00\x00\x00", 4);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -707,19 +568,19 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
 		goto err;
 		goto err;
 
 
 	/* program IF */
 	/* program IF */
-	u64tmp = f_if % s->cfg->xtal;
+	u64tmp = f_if % pdata->clk;
 	u64tmp *= 0x400000;
 	u64tmp *= 0x400000;
-	u64tmp = div_u64(u64tmp, s->cfg->xtal);
+	u64tmp = div_u64(u64tmp, pdata->clk);
 	u64tmp = -u64tmp;
 	u64tmp = -u64tmp;
 	u32tmp = u64tmp & 0x3fffff;
 	u32tmp = u64tmp & 0x3fffff;
 
 
-	dev_dbg(&s->udev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp);
+	dev_dbg(&pdev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp);
 
 
 	buf[0] = (u32tmp >> 16) & 0xff;
 	buf[0] = (u32tmp >> 16) & 0xff;
 	buf[1] = (u32tmp >>  8) & 0xff;
 	buf[1] = (u32tmp >>  8) & 0xff;
 	buf[2] = (u32tmp >>  0) & 0xff;
 	buf[2] = (u32tmp >>  0) & 0xff;
 
 
-	ret = rtl2832_sdr_wr_regs(s, 0x119, buf, 3);
+	ret = rtl2832_sdr_wr_regs(dev, 0x119, buf, 3);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -733,208 +594,212 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
 		u8tmp2 = 0xcd; /* enable ADC I, ADC Q */
 		u8tmp2 = 0xcd; /* enable ADC I, ADC Q */
 	}
 	}
 
 
-	ret = rtl2832_sdr_wr_reg(s, 0x1b1, u8tmp1);
+	ret = rtl2832_sdr_wr_reg(dev, 0x1b1, u8tmp1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_wr_reg(s, 0x008, u8tmp2);
+	ret = rtl2832_sdr_wr_reg(dev, 0x008, u8tmp2);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_wr_reg(s, 0x006, 0x80);
+	ret = rtl2832_sdr_wr_reg(dev, 0x006, 0x80);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* program sampling rate (resampling down) */
 	/* program sampling rate (resampling down) */
-	u32tmp = div_u64(s->cfg->xtal * 0x400000ULL, f_sr * 4U);
+	u32tmp = div_u64(pdata->clk * 0x400000ULL, f_sr * 4U);
 	u32tmp <<= 2;
 	u32tmp <<= 2;
 	buf[0] = (u32tmp >> 24) & 0xff;
 	buf[0] = (u32tmp >> 24) & 0xff;
 	buf[1] = (u32tmp >> 16) & 0xff;
 	buf[1] = (u32tmp >> 16) & 0xff;
 	buf[2] = (u32tmp >>  8) & 0xff;
 	buf[2] = (u32tmp >>  8) & 0xff;
 	buf[3] = (u32tmp >>  0) & 0xff;
 	buf[3] = (u32tmp >>  0) & 0xff;
-	ret = rtl2832_sdr_wr_regs(s, 0x19f, buf, 4);
+	ret = rtl2832_sdr_wr_regs(dev, 0x19f, buf, 4);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* low-pass filter */
 	/* low-pass filter */
-	ret = rtl2832_sdr_wr_regs(s, 0x11c,
+	ret = rtl2832_sdr_wr_regs(dev, 0x11c,
 			"\xca\xdc\xd7\xd8\xe0\xf2\x0e\x35\x06\x50\x9c\x0d\x71\x11\x14\x71\x74\x19\x41\xa5",
 			"\xca\xdc\xd7\xd8\xe0\xf2\x0e\x35\x06\x50\x9c\x0d\x71\x11\x14\x71\x74\x19\x41\xa5",
 			20);
 			20);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2);
+	ret = rtl2832_sdr_wr_regs(dev, 0x017, "\x11\x10", 2);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* mode */
 	/* mode */
-	ret = rtl2832_sdr_wr_regs(s, 0x019, "\x05", 1);
+	ret = rtl2832_sdr_wr_regs(dev, 0x019, "\x05", 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_wr_regs(s, 0x01a, "\x1b\x16\x0d\x06\x01\xff", 6);
+	ret = rtl2832_sdr_wr_regs(dev, 0x01a, "\x1b\x16\x0d\x06\x01\xff", 6);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* FSM */
 	/* FSM */
-	ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\xf0\x0f", 3);
+	ret = rtl2832_sdr_wr_regs(dev, 0x192, "\x00\xf0\x0f", 3);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* PID filter */
 	/* PID filter */
-	ret = rtl2832_sdr_wr_regs(s, 0x061, "\x60", 1);
+	ret = rtl2832_sdr_wr_regs(dev, 0x061, "\x60", 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* used RF tuner based settings */
 	/* used RF tuner based settings */
-	switch (s->cfg->tuner) {
-	case RTL2832_TUNER_E4000:
-		ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x30", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x104, "\xd0", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x18", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x011, "\xd4", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x14", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xec", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x83", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x010, "\x49", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x87", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x85", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x013, "\x02", 1);
+	switch (pdata->tuner) {
+	case RTL2832_SDR_TUNER_E4000:
+		ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x30", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xd0", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x18", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xd4", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1e5, "\xf0", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1d9, "\x00", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1db, "\x00", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1dd, "\x14", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1de, "\xec", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1d8, "\x0c", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1e6, "\x02", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1d7, "\x09", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x83", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x010, "\x49", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x87", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x85", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x013, "\x02", 1);
 		break;
 		break;
-	case RTL2832_TUNER_FC0012:
-	case RTL2832_TUNER_FC0013:
-		ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x2c", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x16", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x011, "\xe9\xbf", 2);
-		ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x11", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xef", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1);
+	case RTL2832_SDR_TUNER_FC0012:
+	case RTL2832_SDR_TUNER_FC0013:
+		ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x2c", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x16", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xe9\xbf", 2);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1e5, "\xf0", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1d9, "\x00", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1db, "\x00", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1dd, "\x11", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1de, "\xef", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1d8, "\x0c", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1e6, "\x02", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1d7, "\x09", 1);
 		break;
 		break;
-	case RTL2832_TUNER_R820T:
-		ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x115, "\x01", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x103, "\x80", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x24", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x14", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
-		ret = rtl2832_sdr_wr_regs(s, 0x011, "\xf4", 1);
+	case RTL2832_SDR_TUNER_R820T:
+	case RTL2832_SDR_TUNER_R828D:
+		ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x01", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x80", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x24", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x14", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+		ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xf4", 1);
 		break;
 		break;
 	default:
 	default:
-		dev_notice(&s->udev->dev, "Unsupported tuner\n");
+		dev_notice(&pdev->dev, "Unsupported tuner\n");
 	}
 	}
 
 
 	/* software reset */
 	/* software reset */
-	ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x04, 0x04);
+	ret = rtl2832_sdr_wr_reg_mask(dev, 0x101, 0x04, 0x04);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x00, 0x04);
+	ret = rtl2832_sdr_wr_reg_mask(dev, 0x101, 0x00, 0x04);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 err:
 err:
 	return ret;
 	return ret;
 };
 };
 
 
-static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_state *s)
+static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_dev *dev)
 {
 {
+	struct platform_device *pdev = dev->pdev;
 	int ret;
 	int ret;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
 	/* PID filter */
 	/* PID filter */
-	ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1);
+	ret = rtl2832_sdr_wr_regs(dev, 0x061, "\xe0", 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* mode */
 	/* mode */
-	ret = rtl2832_sdr_wr_regs(s, 0x019, "\x20", 1);
+	ret = rtl2832_sdr_wr_regs(dev, 0x019, "\x20", 1);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2);
+	ret = rtl2832_sdr_wr_regs(dev, 0x017, "\x11\x10", 2);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* FSM */
 	/* FSM */
-	ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\x0f\xff", 3);
+	ret = rtl2832_sdr_wr_regs(dev, 0x192, "\x00\x0f\xff", 3);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x40\x00", 2);
+	ret = rtl2832_sdr_wr_regs(dev, 0x13e, "\x40\x00", 2);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_wr_regs(s, 0x115, "\x06\x3f\xce\xcc", 4);
+	ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x06\x3f\xce\xcc", 4);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 err:
 err:
 	return;
 	return;
 };
 };
 
 
-static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_dev *dev)
 {
 {
-	struct dvb_frontend *fe = s->fe;
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct dvb_frontend *fe = pdata->dvb_frontend;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct v4l2_ctrl *bandwidth_auto;
 	struct v4l2_ctrl *bandwidth_auto;
 	struct v4l2_ctrl *bandwidth;
 	struct v4l2_ctrl *bandwidth;
@@ -942,29 +807,29 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
 	/*
 	/*
 	 * tuner RF (Hz)
 	 * tuner RF (Hz)
 	 */
 	 */
-	if (s->f_tuner == 0)
+	if (dev->f_tuner == 0)
 		return 0;
 		return 0;
 
 
 	/*
 	/*
 	 * bandwidth (Hz)
 	 * bandwidth (Hz)
 	 */
 	 */
-	bandwidth_auto = v4l2_ctrl_find(&s->hdl,
+	bandwidth_auto = v4l2_ctrl_find(&dev->hdl,
 					V4L2_CID_RF_TUNER_BANDWIDTH_AUTO);
 					V4L2_CID_RF_TUNER_BANDWIDTH_AUTO);
-	bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH);
+	bandwidth = v4l2_ctrl_find(&dev->hdl, V4L2_CID_RF_TUNER_BANDWIDTH);
 	if (v4l2_ctrl_g_ctrl(bandwidth_auto)) {
 	if (v4l2_ctrl_g_ctrl(bandwidth_auto)) {
-		c->bandwidth_hz = s->f_adc;
-		v4l2_ctrl_s_ctrl(bandwidth, s->f_adc);
+		c->bandwidth_hz = dev->f_adc;
+		v4l2_ctrl_s_ctrl(bandwidth, dev->f_adc);
 	} else {
 	} else {
 		c->bandwidth_hz = v4l2_ctrl_g_ctrl(bandwidth);
 		c->bandwidth_hz = v4l2_ctrl_g_ctrl(bandwidth);
 	}
 	}
 
 
-	c->frequency = s->f_tuner;
+	c->frequency = dev->f_tuner;
 	c->delivery_system = SYS_DVBT;
 	c->delivery_system = SYS_DVBT;
 
 
-	dev_dbg(&s->udev->dev, "frequency=%u bandwidth=%d\n",
-			c->frequency, c->bandwidth_hz);
+	dev_dbg(&pdev->dev, "frequency=%u bandwidth=%d\n",
+		c->frequency, c->bandwidth_hz);
 
 
-	if (!test_bit(POWER_ON, &s->flags))
+	if (!test_bit(POWER_ON, &dev->flags))
 		return 0;
 		return 0;
 
 
 	if (fe->ops.tuner_ops.set_params)
 	if (fe->ops.tuner_ops.set_params)
@@ -973,11 +838,13 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
 	return 0;
 	return 0;
 };
 };
 
 
-static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_dev *dev)
 {
 {
-	struct dvb_frontend *fe = s->fe;
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct dvb_frontend *fe = pdata->dvb_frontend;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
 	if (fe->ops.tuner_ops.init)
 	if (fe->ops.tuner_ops.init)
 		fe->ops.tuner_ops.init(fe);
 		fe->ops.tuner_ops.init(fe);
@@ -985,11 +852,13 @@ static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s)
 	return 0;
 	return 0;
 };
 };
 
 
-static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s)
+static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_dev *dev)
 {
 {
-	struct dvb_frontend *fe = s->fe;
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct dvb_frontend *fe = pdata->dvb_frontend;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
 	if (fe->ops.tuner_ops.sleep)
 	if (fe->ops.tuner_ops.sleep)
 		fe->ops.tuner_ops.sleep(fe);
 		fe->ops.tuner_ops.sleep(fe);
@@ -999,83 +868,89 @@ static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s)
 
 
 static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
 static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
 {
-	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+	struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq);
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct dvb_usb_device *d = pdata->dvb_usb_device;
 	int ret;
 	int ret;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
-	if (!s->udev)
+	if (!dev->udev)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (mutex_lock_interruptible(&s->v4l2_lock))
+	if (mutex_lock_interruptible(&dev->v4l2_lock))
 		return -ERESTARTSYS;
 		return -ERESTARTSYS;
 
 
-	if (s->d->props->power_ctrl)
-		s->d->props->power_ctrl(s->d, 1);
+	if (d->props->power_ctrl)
+		d->props->power_ctrl(d, 1);
 
 
 	/* enable ADC */
 	/* enable ADC */
-	if (s->d->props->frontend_ctrl)
-		s->d->props->frontend_ctrl(s->fe, 1);
+	if (d->props->frontend_ctrl)
+		d->props->frontend_ctrl(pdata->dvb_frontend, 1);
 
 
-	set_bit(POWER_ON, &s->flags);
+	set_bit(POWER_ON, &dev->flags);
 
 
-	ret = rtl2832_sdr_set_tuner(s);
+	ret = rtl2832_sdr_set_tuner(dev);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_set_tuner_freq(s);
+	ret = rtl2832_sdr_set_tuner_freq(dev);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_set_adc(s);
+	ret = rtl2832_sdr_set_adc(dev);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_alloc_stream_bufs(s);
+	ret = rtl2832_sdr_alloc_stream_bufs(dev);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	ret = rtl2832_sdr_alloc_urbs(s);
+	ret = rtl2832_sdr_alloc_urbs(dev);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	s->sequence = 0;
+	dev->sequence = 0;
 
 
-	ret = rtl2832_sdr_submit_urbs(s);
+	ret = rtl2832_sdr_submit_urbs(dev);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 err:
 err:
-	mutex_unlock(&s->v4l2_lock);
+	mutex_unlock(&dev->v4l2_lock);
 
 
 	return ret;
 	return ret;
 }
 }
 
 
 static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
 static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
 {
 {
-	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+	struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq);
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct dvb_usb_device *d = pdata->dvb_usb_device;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
-	mutex_lock(&s->v4l2_lock);
+	mutex_lock(&dev->v4l2_lock);
 
 
-	rtl2832_sdr_kill_urbs(s);
-	rtl2832_sdr_free_urbs(s);
-	rtl2832_sdr_free_stream_bufs(s);
-	rtl2832_sdr_cleanup_queued_bufs(s);
-	rtl2832_sdr_unset_adc(s);
-	rtl2832_sdr_unset_tuner(s);
+	rtl2832_sdr_kill_urbs(dev);
+	rtl2832_sdr_free_urbs(dev);
+	rtl2832_sdr_free_stream_bufs(dev);
+	rtl2832_sdr_cleanup_queued_bufs(dev);
+	rtl2832_sdr_unset_adc(dev);
+	rtl2832_sdr_unset_tuner(dev);
 
 
-	clear_bit(POWER_ON, &s->flags);
+	clear_bit(POWER_ON, &dev->flags);
 
 
 	/* disable ADC */
 	/* disable ADC */
-	if (s->d->props->frontend_ctrl)
-		s->d->props->frontend_ctrl(s->fe, 0);
+	if (d->props->frontend_ctrl)
+		d->props->frontend_ctrl(pdata->dvb_frontend, 0);
 
 
-	if (s->d->props->power_ctrl)
-		s->d->props->power_ctrl(s->d, 0);
+	if (d->props->power_ctrl)
+		d->props->power_ctrl(d, 0);
 
 
-	mutex_unlock(&s->v4l2_lock);
+	mutex_unlock(&dev->v4l2_lock);
 }
 }
 
 
 static struct vb2_ops rtl2832_sdr_vb2_ops = {
 static struct vb2_ops rtl2832_sdr_vb2_ops = {
@@ -1091,9 +966,10 @@ static struct vb2_ops rtl2832_sdr_vb2_ops = {
 static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
 static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
 		struct v4l2_tuner *v)
 		struct v4l2_tuner *v)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
 
 
-	dev_dbg(&s->udev->dev, "index=%d type=%d\n", v->index, v->type);
+	dev_dbg(&pdev->dev, "index=%d type=%d\n", v->index, v->type);
 
 
 	if (v->index == 0) {
 	if (v->index == 0) {
 		strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
 		strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
@@ -1117,9 +993,10 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
 static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
 static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
 		const struct v4l2_tuner *v)
 		const struct v4l2_tuner *v)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
 	if (v->index > 1)
 	if (v->index > 1)
 		return -EINVAL;
 		return -EINVAL;
@@ -1129,10 +1006,11 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
 static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
 static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
 		struct v4l2_frequency_band *band)
 		struct v4l2_frequency_band *band)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
 
 
-	dev_dbg(&s->udev->dev, "tuner=%d type=%d index=%d\n",
-			band->tuner, band->type, band->index);
+	dev_dbg(&pdev->dev, "tuner=%d type=%d index=%d\n",
+		band->tuner, band->type, band->index);
 
 
 	if (band->tuner == 0) {
 	if (band->tuner == 0) {
 		if (band->index >= ARRAY_SIZE(bands_adc))
 		if (band->index >= ARRAY_SIZE(bands_adc))
@@ -1154,17 +1032,17 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
 static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
 static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
 		struct v4l2_frequency *f)
 		struct v4l2_frequency *f)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
 	int ret  = 0;
 	int ret  = 0;
 
 
-	dev_dbg(&s->udev->dev, "tuner=%d type=%d\n",
-			f->tuner, f->type);
+	dev_dbg(&pdev->dev, "tuner=%d type=%d\n", f->tuner, f->type);
 
 
 	if (f->tuner == 0) {
 	if (f->tuner == 0) {
-		f->frequency = s->f_adc;
+		f->frequency = dev->f_adc;
 		f->type = V4L2_TUNER_ADC;
 		f->type = V4L2_TUNER_ADC;
 	} else if (f->tuner == 1) {
 	} else if (f->tuner == 1) {
-		f->frequency = s->f_tuner;
+		f->frequency = dev->f_tuner;
 		f->type = V4L2_TUNER_RF;
 		f->type = V4L2_TUNER_RF;
 	} else {
 	} else {
 		return -EINVAL;
 		return -EINVAL;
@@ -1176,11 +1054,12 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
 static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
 static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
 		const struct v4l2_frequency *f)
 		const struct v4l2_frequency *f)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
 	int ret, band;
 	int ret, band;
 
 
-	dev_dbg(&s->udev->dev, "tuner=%d type=%d frequency=%u\n",
-			f->tuner, f->type, f->frequency);
+	dev_dbg(&pdev->dev, "tuner=%d type=%d frequency=%u\n",
+		f->tuner, f->type, f->frequency);
 
 
 	/* ADC band midpoints */
 	/* ADC band midpoints */
 	#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
 	#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
@@ -1194,19 +1073,19 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
 		else
 		else
 			band = 2;
 			band = 2;
 
 
-		s->f_adc = clamp_t(unsigned int, f->frequency,
+		dev->f_adc = clamp_t(unsigned int, f->frequency,
 				bands_adc[band].rangelow,
 				bands_adc[band].rangelow,
 				bands_adc[band].rangehigh);
 				bands_adc[band].rangehigh);
 
 
-		dev_dbg(&s->udev->dev, "ADC frequency=%u Hz\n", s->f_adc);
-		ret = rtl2832_sdr_set_adc(s);
+		dev_dbg(&pdev->dev, "ADC frequency=%u Hz\n", dev->f_adc);
+		ret = rtl2832_sdr_set_adc(dev);
 	} else if (f->tuner == 1) {
 	} else if (f->tuner == 1) {
-		s->f_tuner = clamp_t(unsigned int, f->frequency,
+		dev->f_tuner = clamp_t(unsigned int, f->frequency,
 				bands_fm[0].rangelow,
 				bands_fm[0].rangelow,
 				bands_fm[0].rangehigh);
 				bands_fm[0].rangehigh);
-		dev_dbg(&s->udev->dev, "RF frequency=%u Hz\n", f->frequency);
+		dev_dbg(&pdev->dev, "RF frequency=%u Hz\n", f->frequency);
 
 
-		ret = rtl2832_sdr_set_tuner_freq(s);
+		ret = rtl2832_sdr_set_tuner_freq(dev);
 	} else {
 	} else {
 		ret = -EINVAL;
 		ret = -EINVAL;
 	}
 	}
@@ -1217,11 +1096,12 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
 static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
 static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
 		struct v4l2_fmtdesc *f)
 		struct v4l2_fmtdesc *f)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
-	if (f->index >= s->num_formats)
+	if (f->index >= dev->num_formats)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	strlcpy(f->description, formats[f->index].name, sizeof(f->description));
 	strlcpy(f->description, formats[f->index].name, sizeof(f->description));
@@ -1233,12 +1113,13 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
 static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
 static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
 		struct v4l2_format *f)
 		struct v4l2_format *f)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
 
 
-	dev_dbg(&s->udev->dev, "\n");
+	dev_dbg(&pdev->dev, "\n");
 
 
-	f->fmt.sdr.pixelformat = s->pixelformat;
-	f->fmt.sdr.buffersize = s->buffersize;
+	f->fmt.sdr.pixelformat = dev->pixelformat;
+	f->fmt.sdr.buffersize = dev->buffersize;
 
 
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
 
 
@@ -1248,28 +1129,29 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
 static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
 static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
 		struct v4l2_format *f)
 		struct v4l2_format *f)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
-	struct vb2_queue *q = &s->vb_queue;
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
+	struct vb2_queue *q = &dev->vb_queue;
 	int i;
 	int i;
 
 
-	dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
-			(char *)&f->fmt.sdr.pixelformat);
+	dev_dbg(&pdev->dev, "pixelformat fourcc %4.4s\n",
+		(char *)&f->fmt.sdr.pixelformat);
 
 
 	if (vb2_is_busy(q))
 	if (vb2_is_busy(q))
 		return -EBUSY;
 		return -EBUSY;
 
 
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
-	for (i = 0; i < s->num_formats; i++) {
+	for (i = 0; i < dev->num_formats; i++) {
 		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
 		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
-			s->pixelformat = formats[i].pixelformat;
-			s->buffersize = formats[i].buffersize;
+			dev->pixelformat = formats[i].pixelformat;
+			dev->buffersize = formats[i].buffersize;
 			f->fmt.sdr.buffersize = formats[i].buffersize;
 			f->fmt.sdr.buffersize = formats[i].buffersize;
 			return 0;
 			return 0;
 		}
 		}
 	}
 	}
 
 
-	s->pixelformat = formats[0].pixelformat;
-	s->buffersize = formats[0].buffersize;
+	dev->pixelformat = formats[0].pixelformat;
+	dev->buffersize = formats[0].buffersize;
 	f->fmt.sdr.pixelformat = formats[0].pixelformat;
 	f->fmt.sdr.pixelformat = formats[0].pixelformat;
 	f->fmt.sdr.buffersize = formats[0].buffersize;
 	f->fmt.sdr.buffersize = formats[0].buffersize;
 
 
@@ -1279,14 +1161,15 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
 static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
 static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
 		struct v4l2_format *f)
 		struct v4l2_format *f)
 {
 {
-	struct rtl2832_sdr_state *s = video_drvdata(file);
+	struct rtl2832_sdr_dev *dev = video_drvdata(file);
+	struct platform_device *pdev = dev->pdev;
 	int i;
 	int i;
 
 
-	dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
-			(char *)&f->fmt.sdr.pixelformat);
+	dev_dbg(&pdev->dev, "pixelformat fourcc %4.4s\n",
+		(char *)&f->fmt.sdr.pixelformat);
 
 
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
-	for (i = 0; i < s->num_formats; i++) {
+	for (i = 0; i < dev->num_formats; i++) {
 		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
 		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
 			f->fmt.sdr.buffersize = formats[i].buffersize;
 			f->fmt.sdr.buffersize = formats[i].buffersize;
 			return 0;
 			return 0;
@@ -1348,37 +1231,38 @@ static struct video_device rtl2832_sdr_template = {
 
 
 static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
 static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 {
-	struct rtl2832_sdr_state *s =
-			container_of(ctrl->handler, struct rtl2832_sdr_state,
+	struct rtl2832_sdr_dev *dev =
+			container_of(ctrl->handler, struct rtl2832_sdr_dev,
 					hdl);
 					hdl);
-	struct dvb_frontend *fe = s->fe;
+	struct platform_device *pdev = dev->pdev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+	struct dvb_frontend *fe = pdata->dvb_frontend;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
 	int ret;
 
 
-	dev_dbg(&s->udev->dev,
-			"id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
-			ctrl->id, ctrl->name, ctrl->val,
-			ctrl->minimum, ctrl->maximum, ctrl->step);
+	dev_dbg(&pdev->dev, "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
+		ctrl->id, ctrl->name, ctrl->val, ctrl->minimum, ctrl->maximum,
+		ctrl->step);
 
 
 	switch (ctrl->id) {
 	switch (ctrl->id) {
 	case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
 	case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
 	case V4L2_CID_RF_TUNER_BANDWIDTH:
 	case V4L2_CID_RF_TUNER_BANDWIDTH:
 		/* TODO: these controls should be moved to tuner drivers */
 		/* TODO: these controls should be moved to tuner drivers */
-		if (s->bandwidth_auto->val) {
+		if (dev->bandwidth_auto->val) {
 			/* Round towards the closest legal value */
 			/* Round towards the closest legal value */
-			s32 val = s->f_adc + div_u64(s->bandwidth->step, 2);
+			s32 val = dev->f_adc + div_u64(dev->bandwidth->step, 2);
 			u32 offset;
 			u32 offset;
 
 
-			val = clamp_t(s32, val, s->bandwidth->minimum,
-				      s->bandwidth->maximum);
-			offset = val - s->bandwidth->minimum;
-			offset = s->bandwidth->step *
-				div_u64(offset, s->bandwidth->step);
-			s->bandwidth->val = s->bandwidth->minimum + offset;
+			val = clamp_t(s32, val, dev->bandwidth->minimum,
+				      dev->bandwidth->maximum);
+			offset = val - dev->bandwidth->minimum;
+			offset = dev->bandwidth->step *
+				div_u64(offset, dev->bandwidth->step);
+			dev->bandwidth->val = dev->bandwidth->minimum + offset;
 		}
 		}
-		c->bandwidth_hz = s->bandwidth->val;
+		c->bandwidth_hz = dev->bandwidth->val;
 
 
-		if (!test_bit(POWER_ON, &s->flags))
+		if (!test_bit(POWER_ON, &dev->flags))
 			return 0;
 			return 0;
 
 
 		if (fe->ops.tuner_ops.set_params)
 		if (fe->ops.tuner_ops.set_params)
@@ -1399,154 +1283,195 @@ static const struct v4l2_ctrl_ops rtl2832_sdr_ctrl_ops = {
 
 
 static void rtl2832_sdr_video_release(struct v4l2_device *v)
 static void rtl2832_sdr_video_release(struct v4l2_device *v)
 {
 {
-	struct rtl2832_sdr_state *s =
-			container_of(v, struct rtl2832_sdr_state, v4l2_dev);
+	struct rtl2832_sdr_dev *dev =
+			container_of(v, struct rtl2832_sdr_dev, v4l2_dev);
+	struct platform_device *pdev = dev->pdev;
+
+	dev_dbg(&pdev->dev, "\n");
 
 
-	v4l2_ctrl_handler_free(&s->hdl);
-	v4l2_device_unregister(&s->v4l2_dev);
-	kfree(s);
+	v4l2_ctrl_handler_free(&dev->hdl);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	kfree(dev);
 }
 }
 
 
-struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
-		struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
-		struct v4l2_subdev *sd)
+/* Platform driver interface */
+static int rtl2832_sdr_probe(struct platform_device *pdev)
 {
 {
-	int ret;
-	struct rtl2832_sdr_state *s;
+	struct rtl2832_sdr_dev *dev;
+	struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
 	const struct v4l2_ctrl_ops *ops = &rtl2832_sdr_ctrl_ops;
 	const struct v4l2_ctrl_ops *ops = &rtl2832_sdr_ctrl_ops;
-	struct dvb_usb_device *d = i2c_get_adapdata(i2c);
+	struct v4l2_subdev *subdev;
+	int ret;
+
+	dev_dbg(&pdev->dev, "\n");
 
 
-	s = kzalloc(sizeof(struct rtl2832_sdr_state), GFP_KERNEL);
-	if (s == NULL) {
-		dev_err(&d->udev->dev,
-				"Could not allocate memory for rtl2832_sdr_state\n");
-		return NULL;
+	if (!pdata) {
+		dev_err(&pdev->dev, "Cannot proceed without platform data\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	if (!pdev->dev.parent->driver) {
+		dev_dbg(&pdev->dev, "No parent device\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	/* try to refcount host drv since we are the consumer */
+	if (!try_module_get(pdev->dev.parent->driver->owner)) {
+		dev_err(&pdev->dev, "Refcount fail");
+		ret = -EINVAL;
+		goto err;
+	}
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		ret = -ENOMEM;
+		goto err_module_put;
 	}
 	}
 
 
 	/* setup the state */
 	/* setup the state */
-	s->fe = fe;
-	s->d = d;
-	s->udev = d->udev;
-	s->i2c = i2c;
-	s->cfg = cfg;
-	s->f_adc = bands_adc[0].rangelow;
-	s->f_tuner = bands_fm[0].rangelow;
-	s->pixelformat = formats[0].pixelformat;
-	s->buffersize = formats[0].buffersize;
-	s->num_formats = NUM_FORMATS;
+	subdev = pdata->v4l2_subdev;
+	dev->pdev = pdev;
+	dev->udev = pdata->dvb_usb_device->udev;
+	dev->f_adc = bands_adc[0].rangelow;
+	dev->f_tuner = bands_fm[0].rangelow;
+	dev->pixelformat = formats[0].pixelformat;
+	dev->buffersize = formats[0].buffersize;
+	dev->num_formats = NUM_FORMATS;
 	if (!rtl2832_sdr_emulated_fmt)
 	if (!rtl2832_sdr_emulated_fmt)
-		s->num_formats -= 1;
+		dev->num_formats -= 1;
 
 
-	mutex_init(&s->v4l2_lock);
-	mutex_init(&s->vb_queue_lock);
-	spin_lock_init(&s->queued_bufs_lock);
-	INIT_LIST_HEAD(&s->queued_bufs);
+	mutex_init(&dev->v4l2_lock);
+	mutex_init(&dev->vb_queue_lock);
+	spin_lock_init(&dev->queued_bufs_lock);
+	INIT_LIST_HEAD(&dev->queued_bufs);
 
 
 	/* Init videobuf2 queue structure */
 	/* Init videobuf2 queue structure */
-	s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
-	s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
-	s->vb_queue.drv_priv = s;
-	s->vb_queue.buf_struct_size = sizeof(struct rtl2832_sdr_frame_buf);
-	s->vb_queue.ops = &rtl2832_sdr_vb2_ops;
-	s->vb_queue.mem_ops = &vb2_vmalloc_memops;
-	s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-	ret = vb2_queue_init(&s->vb_queue);
+	dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
+	dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+	dev->vb_queue.drv_priv = dev;
+	dev->vb_queue.buf_struct_size = sizeof(struct rtl2832_sdr_frame_buf);
+	dev->vb_queue.ops = &rtl2832_sdr_vb2_ops;
+	dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
+	dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	ret = vb2_queue_init(&dev->vb_queue);
 	if (ret) {
 	if (ret) {
-		dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
-		goto err_free_mem;
+		dev_err(&pdev->dev, "Could not initialize vb2 queue\n");
+		goto err_kfree;
 	}
 	}
 
 
 	/* Register controls */
 	/* Register controls */
-	switch (s->cfg->tuner) {
-	case RTL2832_TUNER_E4000:
-		v4l2_ctrl_handler_init(&s->hdl, 9);
-		if (sd)
-			v4l2_ctrl_add_handler(&s->hdl, sd->ctrl_handler, NULL);
+	switch (pdata->tuner) {
+	case RTL2832_SDR_TUNER_E4000:
+		v4l2_ctrl_handler_init(&dev->hdl, 9);
+		if (subdev)
+			v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler, NULL);
 		break;
 		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);
-		v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+	case RTL2832_SDR_TUNER_R820T:
+	case RTL2832_SDR_TUNER_R828D:
+		v4l2_ctrl_handler_init(&dev->hdl, 2);
+		dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, ops,
+							V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+							0, 1, 1, 1);
+		dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, ops,
+						   V4L2_CID_RF_TUNER_BANDWIDTH,
+						   0, 8000000, 100000, 0);
+		v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
 		break;
 		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);
-		v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+	case RTL2832_SDR_TUNER_FC0012:
+	case RTL2832_SDR_TUNER_FC0013:
+		v4l2_ctrl_handler_init(&dev->hdl, 2);
+		dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, ops,
+							V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+							0, 1, 1, 1);
+		dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, ops,
+						   V4L2_CID_RF_TUNER_BANDWIDTH,
+						   6000000, 8000000, 1000000,
+						   6000000);
+		v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
 		break;
 		break;
 	default:
 	default:
-		v4l2_ctrl_handler_init(&s->hdl, 0);
-		dev_notice(&s->udev->dev, "%s: Unsupported tuner\n",
-				KBUILD_MODNAME);
-		goto err_free_controls;
+		v4l2_ctrl_handler_init(&dev->hdl, 0);
+		dev_err(&pdev->dev, "Unsupported tuner\n");
+		goto err_v4l2_ctrl_handler_free;
 	}
 	}
-
-	if (s->hdl.error) {
-		ret = s->hdl.error;
-		dev_err(&s->udev->dev, "Could not initialize controls\n");
-		goto err_free_controls;
+	if (dev->hdl.error) {
+		ret = dev->hdl.error;
+		dev_err(&pdev->dev, "Could not initialize controls\n");
+		goto err_v4l2_ctrl_handler_free;
 	}
 	}
 
 
 	/* Init video_device structure */
 	/* Init video_device structure */
-	s->vdev = rtl2832_sdr_template;
-	s->vdev.queue = &s->vb_queue;
-	s->vdev.queue->lock = &s->vb_queue_lock;
-	video_set_drvdata(&s->vdev, s);
+	dev->vdev = rtl2832_sdr_template;
+	dev->vdev.queue = &dev->vb_queue;
+	dev->vdev.queue->lock = &dev->vb_queue_lock;
+	video_set_drvdata(&dev->vdev, dev);
 
 
 	/* Register the v4l2_device structure */
 	/* Register the v4l2_device structure */
-	s->v4l2_dev.release = rtl2832_sdr_video_release;
-	ret = v4l2_device_register(&s->udev->dev, &s->v4l2_dev);
+	dev->v4l2_dev.release = rtl2832_sdr_video_release;
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
 	if (ret) {
 	if (ret) {
-		dev_err(&s->udev->dev,
-				"Failed to register v4l2-device (%d)\n", ret);
-		goto err_free_controls;
+		dev_err(&pdev->dev, "Failed to register v4l2-device %d\n", ret);
+		goto err_v4l2_ctrl_handler_free;
 	}
 	}
 
 
-	s->v4l2_dev.ctrl_handler = &s->hdl;
-	s->vdev.v4l2_dev = &s->v4l2_dev;
-	s->vdev.lock = &s->v4l2_lock;
-	s->vdev.vfl_dir = VFL_DIR_RX;
+	dev->v4l2_dev.ctrl_handler = &dev->hdl;
+	dev->vdev.v4l2_dev = &dev->v4l2_dev;
+	dev->vdev.lock = &dev->v4l2_lock;
+	dev->vdev.vfl_dir = VFL_DIR_RX;
 
 
-	ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
+	ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
 	if (ret) {
 	if (ret) {
-		dev_err(&s->udev->dev,
-				"Failed to register as video device (%d)\n",
-				ret);
-		goto err_unregister_v4l2_dev;
+		dev_err(&pdev->dev, "Failed to register as video device %d\n",
+			ret);
+		goto err_v4l2_device_unregister;
 	}
 	}
-	dev_info(&s->udev->dev, "Registered as %s\n",
-			video_device_node_name(&s->vdev));
-
-	fe->sec_priv = s;
-	fe->ops.release_sec = rtl2832_sdr_release_sec;
-
-	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:
-	v4l2_device_unregister(&s->v4l2_dev);
-err_free_controls:
-	v4l2_ctrl_handler_free(&s->hdl);
-err_free_mem:
-	kfree(s);
-	return NULL;
+	dev_info(&pdev->dev, "Registered as %s\n",
+		 video_device_node_name(&dev->vdev));
+	dev_info(&pdev->dev, "Realtek RTL2832 SDR attached\n");
+	dev_notice(&pdev->dev,
+		   "SDR API is still slightly experimental and functionality changes may follow\n");
+	platform_set_drvdata(pdev, dev);
+	return 0;
+err_v4l2_device_unregister:
+	v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2_ctrl_handler_free:
+	v4l2_ctrl_handler_free(&dev->hdl);
+err_kfree:
+	kfree(dev);
+err_module_put:
+	module_put(pdev->dev.parent->driver->owner);
+err:
+	return ret;
 }
 }
-EXPORT_SYMBOL(rtl2832_sdr_attach);
+
+static int rtl2832_sdr_remove(struct platform_device *pdev)
+{
+	struct rtl2832_sdr_dev *dev = platform_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "\n");
+
+	mutex_lock(&dev->vb_queue_lock);
+	mutex_lock(&dev->v4l2_lock);
+	/* No need to keep the urbs around after disconnection */
+	dev->udev = NULL;
+	v4l2_device_disconnect(&dev->v4l2_dev);
+	video_unregister_device(&dev->vdev);
+	mutex_unlock(&dev->v4l2_lock);
+	mutex_unlock(&dev->vb_queue_lock);
+	v4l2_device_put(&dev->v4l2_dev);
+	module_put(pdev->dev.parent->driver->owner);
+
+	return 0;
+}
+
+static struct platform_driver rtl2832_sdr_driver = {
+	.driver = {
+		.name   = "rtl2832_sdr",
+		.owner  = THIS_MODULE,
+	},
+	.probe          = rtl2832_sdr_probe,
+	.remove         = rtl2832_sdr_remove,
+};
+module_platform_driver(rtl2832_sdr_driver);
 
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Realtek RTL2832 SDR driver");
 MODULE_DESCRIPTION("Realtek RTL2832 SDR driver");

+ 35 - 22
drivers/media/dvb-frontends/rtl2832_sdr.h

@@ -20,35 +20,48 @@
  * GNU Radio plugin "gr-kernel" for device usage will be on:
  * GNU Radio plugin "gr-kernel" for device usage will be on:
  * http://git.linuxtv.org/anttip/gr-kernel.git
  * http://git.linuxtv.org/anttip/gr-kernel.git
  *
  *
- * TODO:
- * Help is very highly welcome for these + all the others you could imagine:
- * - move controls to V4L2 API
- * - use libv4l2 for stream format conversions
- * - gr-kernel: switch to v4l2_mmap (current read eats a lot of cpu)
- * - SDRSharp support
  */
  */
 
 
 #ifndef RTL2832_SDR_H
 #ifndef RTL2832_SDR_H
 #define RTL2832_SDR_H
 #define RTL2832_SDR_H
 
 
-#include <linux/kconfig.h>
+#include <linux/i2c.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-subdev.h>
+#include "dvb_frontend.h"
 
 
-/* for config struct */
-#include "rtl2832.h"
+/**
+ * struct rtl2832_sdr_platform_data - Platform data for the rtl2832_sdr driver
+ * @clk: Clock frequency (4000000, 16000000, 25000000, 28800000).
+ * @tuner: Used tuner model.
+ * @i2c_client: rtl2832 demod driver I2C client.
+ * @bulk_read: rtl2832 driver private I/O interface.
+ * @bulk_write: rtl2832 driver private I/O interface.
+ * @update_bits: rtl2832 driver private I/O interface.
+ * @dvb_frontend: rtl2832 DVB frontend.
+ * @v4l2_subdev: Tuner v4l2 controls.
+ * @dvb_usb_device: DVB USB interface for USB streaming.
+ */
+
+struct rtl2832_sdr_platform_data {
+	u32 clk;
+	/*
+	 * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver.
+	 */
+#define RTL2832_SDR_TUNER_TUA9001   0x24
+#define RTL2832_SDR_TUNER_FC0012    0x26
+#define RTL2832_SDR_TUNER_E4000     0x27
+#define RTL2832_SDR_TUNER_FC0013    0x29
+#define RTL2832_SDR_TUNER_R820T     0x2a
+#define RTL2832_SDR_TUNER_R828D     0x2b
+	u8 tuner;
 
 
-#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR)
-extern struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
-	struct v4l2_subdev *sd);
-#else
-static inline struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
-	struct v4l2_subdev *sd)
-{
-	dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
+	struct i2c_client *i2c_client;
+	int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t);
+	int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t);
+	int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int);
+	struct dvb_frontend *dvb_frontend;
+	struct v4l2_subdev *v4l2_subdev;
+	struct dvb_usb_device *dvb_usb_device;
+};
 
 
 #endif /* RTL2832_SDR_H */
 #endif /* RTL2832_SDR_H */

+ 0 - 6
drivers/media/dvb-frontends/s5h1409.c

@@ -1021,9 +1021,3 @@ static struct dvb_frontend_ops s5h1409_ops = {
 MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
 MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
 MODULE_AUTHOR("Steven Toth");
 MODULE_AUTHOR("Steven Toth");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */

+ 0 - 5
drivers/media/dvb-frontends/s5h1409.h

@@ -81,8 +81,3 @@ static inline struct dvb_frontend *s5h1409_attach(
 #endif /* CONFIG_DVB_S5H1409 */
 #endif /* CONFIG_DVB_S5H1409 */
 
 
 #endif /* __S5H1409_H__ */
 #endif /* __S5H1409_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */

+ 0 - 5
drivers/media/dvb-frontends/s5h1411.c

@@ -944,8 +944,3 @@ MODULE_PARM_DESC(debug, "Enable verbose debug messages");
 MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver");
 MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver");
 MODULE_AUTHOR("Steven Toth");
 MODULE_AUTHOR("Steven Toth");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */

+ 0 - 5
drivers/media/dvb-frontends/s5h1411.h

@@ -83,8 +83,3 @@ static inline struct dvb_frontend *s5h1411_attach(
 #endif /* CONFIG_DVB_S5H1411 */
 #endif /* CONFIG_DVB_S5H1411 */
 
 
 #endif /* __S5H1411_H__ */
 #endif /* __S5H1411_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */

+ 152 - 165
drivers/media/dvb-frontends/si2168.c

@@ -19,16 +19,17 @@
 static const struct dvb_frontend_ops si2168_ops;
 static const struct dvb_frontend_ops si2168_ops;
 
 
 /* execute firmware command */
 /* execute firmware command */
-static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
+static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
 {
 {
+	struct si2168_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
 	unsigned long timeout;
 	unsigned long timeout;
 
 
-	mutex_lock(&s->i2c_mutex);
+	mutex_lock(&dev->i2c_mutex);
 
 
 	if (cmd->wlen) {
 	if (cmd->wlen) {
 		/* write cmd and args for firmware */
 		/* write cmd and args for firmware */
-		ret = i2c_master_send(s->client, cmd->args, cmd->wlen);
+		ret = i2c_master_send(client, cmd->args, cmd->wlen);
 		if (ret < 0) {
 		if (ret < 0) {
 			goto err_mutex_unlock;
 			goto err_mutex_unlock;
 		} else if (ret != cmd->wlen) {
 		} else if (ret != cmd->wlen) {
@@ -39,10 +40,10 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
 
 
 	if (cmd->rlen) {
 	if (cmd->rlen) {
 		/* wait cmd execution terminate */
 		/* wait cmd execution terminate */
-		#define TIMEOUT 50
+		#define TIMEOUT 70
 		timeout = jiffies + msecs_to_jiffies(TIMEOUT);
 		timeout = jiffies + msecs_to_jiffies(TIMEOUT);
 		while (!time_after(jiffies, timeout)) {
 		while (!time_after(jiffies, timeout)) {
-			ret = i2c_master_recv(s->client, cmd->args, cmd->rlen);
+			ret = i2c_master_recv(client, cmd->args, cmd->rlen);
 			if (ret < 0) {
 			if (ret < 0) {
 				goto err_mutex_unlock;
 				goto err_mutex_unlock;
 			} else if (ret != cmd->rlen) {
 			} else if (ret != cmd->rlen) {
@@ -55,7 +56,7 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
 				break;
 				break;
 		}
 		}
 
 
-		dev_dbg(&s->client->dev, "cmd execution took %d ms\n",
+		dev_dbg(&client->dev, "cmd execution took %d ms\n",
 				jiffies_to_msecs(jiffies) -
 				jiffies_to_msecs(jiffies) -
 				(jiffies_to_msecs(timeout) - TIMEOUT));
 				(jiffies_to_msecs(timeout) - TIMEOUT));
 
 
@@ -65,29 +66,26 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
 		}
 		}
 	}
 	}
 
 
-	ret = 0;
+	mutex_unlock(&dev->i2c_mutex);
+	return 0;
 
 
 err_mutex_unlock:
 err_mutex_unlock:
-	mutex_unlock(&s->i2c_mutex);
-	if (ret)
-		goto err;
-
-	return 0;
-err:
-	dev_dbg(&s->client->dev, "failed=%d\n", ret);
+	mutex_unlock(&dev->i2c_mutex);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
 static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
 {
-	struct si2168 *s = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct si2168_dev *dev = i2c_get_clientdata(client);
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
 	int ret;
 	struct si2168_cmd cmd;
 	struct si2168_cmd cmd;
 
 
 	*status = 0;
 	*status = 0;
 
 
-	if (!s->active) {
+	if (!dev->active) {
 		ret = -EAGAIN;
 		ret = -EAGAIN;
 		goto err;
 		goto err;
 	}
 	}
@@ -113,21 +111,10 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
 		goto err;
 		goto err;
 	}
 	}
 
 
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	/*
-	 * Possible values seen, in order from strong signal to weak:
-	 * 16 0001 0110 full lock
-	 * 1e 0001 1110 partial lock
-	 * 1a 0001 1010 partial lock
-	 * 18 0001 1000 no lock
-	 *
-	 * [b3:b1] lock bits
-	 * [b4] statistics ready? Set in a few secs after lock is gained.
-	 */
-
 	switch ((cmd.args[2] >> 1) & 0x03) {
 	switch ((cmd.args[2] >> 1) & 0x03) {
 	case 0x01:
 	case 0x01:
 		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
 		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
@@ -138,7 +125,7 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
 		break;
 		break;
 	}
 	}
 
 
-	s->fe_status = *status;
+	dev->fe_status = *status;
 
 
 	if (*status & FE_HAS_LOCK) {
 	if (*status & FE_HAS_LOCK) {
 		c->cnr.len = 1;
 		c->cnr.len = 1;
@@ -149,30 +136,31 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 	}
 	}
 
 
-	dev_dbg(&s->client->dev, "status=%02x args=%*ph\n",
+	dev_dbg(&client->dev, "status=%02x args=%*ph\n",
 			*status, cmd.rlen, cmd.args);
 			*status, cmd.rlen, cmd.args);
 
 
 	return 0;
 	return 0;
 err:
 err:
-	dev_dbg(&s->client->dev, "failed=%d\n", ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int si2168_set_frontend(struct dvb_frontend *fe)
 static int si2168_set_frontend(struct dvb_frontend *fe)
 {
 {
-	struct si2168 *s = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct si2168_dev *dev = i2c_get_clientdata(client);
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
 	int ret;
 	struct si2168_cmd cmd;
 	struct si2168_cmd cmd;
 	u8 bandwidth, delivery_system;
 	u8 bandwidth, delivery_system;
 
 
-	dev_dbg(&s->client->dev,
-			"delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u, stream_id=%d\n",
-			c->delivery_system, c->modulation,
-			c->frequency, c->bandwidth_hz, c->symbol_rate,
-			c->inversion, c->stream_id);
+	dev_dbg(&client->dev,
+			"delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u stream_id=%u\n",
+			c->delivery_system, c->modulation, c->frequency,
+			c->bandwidth_hz, c->symbol_rate, c->inversion,
+			c->stream_id);
 
 
-	if (!s->active) {
+	if (!dev->active) {
 		ret = -EAGAIN;
 		ret = -EAGAIN;
 		goto err;
 		goto err;
 	}
 	}
@@ -192,7 +180,12 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 		goto err;
 		goto err;
 	}
 	}
 
 
-	if (c->bandwidth_hz <= 5000000)
+	if (c->bandwidth_hz == 0) {
+		ret = -EINVAL;
+		goto err;
+	} else if (c->bandwidth_hz <= 2000000)
+		bandwidth = 0x02;
+	else if (c->bandwidth_hz <= 5000000)
 		bandwidth = 0x05;
 		bandwidth = 0x05;
 	else if (c->bandwidth_hz <= 6000000)
 	else if (c->bandwidth_hz <= 6000000)
 		bandwidth = 0x06;
 		bandwidth = 0x06;
@@ -217,7 +210,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 	memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5);
 	memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5);
 	cmd.wlen = 5;
 	cmd.wlen = 5;
 	cmd.rlen = 5;
 	cmd.rlen = 5;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -230,7 +223,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 		memcpy(cmd.args, "\x89\x21\x06\x11\x89\x20", 6);
 		memcpy(cmd.args, "\x89\x21\x06\x11\x89\x20", 6);
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 3;
 	cmd.rlen = 3;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -241,7 +234,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 		cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1;
 		cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1;
 		cmd.wlen = 3;
 		cmd.wlen = 3;
 		cmd.rlen = 1;
 		cmd.rlen = 1;
-		ret = si2168_cmd_execute(s, &cmd);
+		ret = si2168_cmd_execute(client, &cmd);
 		if (ret)
 		if (ret)
 			goto err;
 			goto err;
 	}
 	}
@@ -249,35 +242,35 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 	memcpy(cmd.args, "\x51\x03", 2);
 	memcpy(cmd.args, "\x51\x03", 2);
 	cmd.wlen = 2;
 	cmd.wlen = 2;
 	cmd.rlen = 12;
 	cmd.rlen = 12;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	memcpy(cmd.args, "\x12\x08\x04", 3);
 	memcpy(cmd.args, "\x12\x08\x04", 3);
 	cmd.wlen = 3;
 	cmd.wlen = 3;
 	cmd.rlen = 3;
 	cmd.rlen = 3;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6);
 	memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6);
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6);
 	memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6);
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6);
 	memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6);
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -285,18 +278,18 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 	cmd.args[4] = delivery_system | bandwidth;
 	cmd.args[4] = delivery_system | bandwidth;
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	/* set DVB-C symbol rate */
 	/* set DVB-C symbol rate */
 	if (c->delivery_system == SYS_DVBC_ANNEX_A) {
 	if (c->delivery_system == SYS_DVBC_ANNEX_A) {
 		memcpy(cmd.args, "\x14\x00\x02\x11", 4);
 		memcpy(cmd.args, "\x14\x00\x02\x11", 4);
-		cmd.args[4] = (c->symbol_rate / 1000) & 0xff;
+		cmd.args[4] = ((c->symbol_rate / 1000) >> 0) & 0xff;
 		cmd.args[5] = ((c->symbol_rate / 1000) >> 8) & 0xff;
 		cmd.args[5] = ((c->symbol_rate / 1000) >> 8) & 0xff;
 		cmd.wlen = 6;
 		cmd.wlen = 6;
 		cmd.rlen = 4;
 		cmd.rlen = 4;
-		ret = si2168_cmd_execute(s, &cmd);
+		ret = si2168_cmd_execute(client, &cmd);
 		if (ret)
 		if (ret)
 			goto err;
 			goto err;
 	}
 	}
@@ -304,88 +297,88 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 	memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6);
 	memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6);
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x08", 6);
 	memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x08", 6);
-	cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10;
+	cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10;
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x05", 6);
 	memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x05", 6);
-	cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10;
+	cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10;
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6);
 	memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6);
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x00", 6);
 	memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x00", 6);
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	memcpy(cmd.args, "\x85", 1);
 	memcpy(cmd.args, "\x85", 1);
 	cmd.wlen = 1;
 	cmd.wlen = 1;
 	cmd.rlen = 1;
 	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	s->delivery_system = c->delivery_system;
+	dev->delivery_system = c->delivery_system;
 
 
 	return 0;
 	return 0;
 err:
 err:
-	dev_dbg(&s->client->dev, "failed=%d\n", ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int si2168_init(struct dvb_frontend *fe)
 static int si2168_init(struct dvb_frontend *fe)
 {
 {
-	struct si2168 *s = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct si2168_dev *dev = i2c_get_clientdata(client);
 	int ret, len, remaining;
 	int ret, len, remaining;
-	const struct firmware *fw = NULL;
-	u8 *fw_file;
-	const unsigned int i2c_wr_max = 8;
+	const struct firmware *fw;
+	const char *fw_name;
 	struct si2168_cmd cmd;
 	struct si2168_cmd cmd;
 	unsigned int chip_id;
 	unsigned int chip_id;
 
 
-	dev_dbg(&s->client->dev, "\n");
+	dev_dbg(&client->dev, "\n");
 
 
 	/* initialize */
 	/* initialize */
 	memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13);
 	memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13);
 	cmd.wlen = 13;
 	cmd.wlen = 13;
 	cmd.rlen = 0;
 	cmd.rlen = 0;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	if (s->fw_loaded) {
+	if (dev->fw_loaded) {
 		/* resume */
 		/* resume */
 		memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8);
 		memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8);
 		cmd.wlen = 8;
 		cmd.wlen = 8;
 		cmd.rlen = 1;
 		cmd.rlen = 1;
-		ret = si2168_cmd_execute(s, &cmd);
+		ret = si2168_cmd_execute(client, &cmd);
 		if (ret)
 		if (ret)
 			goto err;
 			goto err;
 
 
 		memcpy(cmd.args, "\x85", 1);
 		memcpy(cmd.args, "\x85", 1);
 		cmd.wlen = 1;
 		cmd.wlen = 1;
 		cmd.rlen = 1;
 		cmd.rlen = 1;
-		ret = si2168_cmd_execute(s, &cmd);
+		ret = si2168_cmd_execute(client, &cmd);
 		if (ret)
 		if (ret)
 			goto err;
 			goto err;
 
 
@@ -396,7 +389,7 @@ static int si2168_init(struct dvb_frontend *fe)
 	memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8);
 	memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8);
 	cmd.wlen = 8;
 	cmd.wlen = 8;
 	cmd.rlen = 1;
 	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -404,7 +397,7 @@ static int si2168_init(struct dvb_frontend *fe)
 	memcpy(cmd.args, "\x02", 1);
 	memcpy(cmd.args, "\x02", 1);
 	cmd.wlen = 1;
 	cmd.wlen = 1;
 	cmd.rlen = 13;
 	cmd.rlen = 13;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -417,50 +410,48 @@ static int si2168_init(struct dvb_frontend *fe)
 
 
 	switch (chip_id) {
 	switch (chip_id) {
 	case SI2168_A20:
 	case SI2168_A20:
-		fw_file = SI2168_A20_FIRMWARE;
+		fw_name = SI2168_A20_FIRMWARE;
 		break;
 		break;
 	case SI2168_A30:
 	case SI2168_A30:
-		fw_file = SI2168_A30_FIRMWARE;
+		fw_name = SI2168_A30_FIRMWARE;
 		break;
 		break;
 	case SI2168_B40:
 	case SI2168_B40:
-		fw_file = SI2168_B40_FIRMWARE;
+		fw_name = SI2168_B40_FIRMWARE;
 		break;
 		break;
 	default:
 	default:
-		dev_err(&s->client->dev,
-				"unknown chip version Si21%d-%c%c%c\n",
+		dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
 				cmd.args[2], cmd.args[1],
 				cmd.args[2], cmd.args[1],
 				cmd.args[3], cmd.args[4]);
 				cmd.args[3], cmd.args[4]);
 		ret = -EINVAL;
 		ret = -EINVAL;
 		goto err;
 		goto err;
 	}
 	}
 
 
-	/* cold state - try to download firmware */
-	dev_info(&s->client->dev, "found a '%s' in cold state\n",
-			si2168_ops.info.name);
+	dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n",
+			cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);
 
 
 	/* request the firmware, this will block and timeout */
 	/* request the firmware, this will block and timeout */
-	ret = request_firmware(&fw, fw_file, &s->client->dev);
+	ret = request_firmware(&fw, fw_name, &client->dev);
 	if (ret) {
 	if (ret) {
 		/* fallback mechanism to handle old name for Si2168 B40 fw */
 		/* fallback mechanism to handle old name for Si2168 B40 fw */
 		if (chip_id == SI2168_B40) {
 		if (chip_id == SI2168_B40) {
-			fw_file = SI2168_B40_FIRMWARE_FALLBACK;
-			ret = request_firmware(&fw, fw_file, &s->client->dev);
+			fw_name = SI2168_B40_FIRMWARE_FALLBACK;
+			ret = request_firmware(&fw, fw_name, &client->dev);
 		}
 		}
 
 
 		if (ret == 0) {
 		if (ret == 0) {
-			dev_notice(&s->client->dev,
+			dev_notice(&client->dev,
 					"please install firmware file '%s'\n",
 					"please install firmware file '%s'\n",
 					SI2168_B40_FIRMWARE);
 					SI2168_B40_FIRMWARE);
 		} else {
 		} else {
-			dev_err(&s->client->dev,
+			dev_err(&client->dev,
 					"firmware file '%s' not found\n",
 					"firmware file '%s' not found\n",
-					fw_file);
-			goto error_fw_release;
+					fw_name);
+			goto err_release_firmware;
 		}
 		}
 	}
 	}
 
 
-	dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
-			fw_file);
+	dev_info(&client->dev, "downloading firmware from file '%s'\n",
+			fw_name);
 
 
 	if ((fw->size % 17 == 0) && (fw->data[0] > 5)) {
 	if ((fw->size % 17 == 0) && (fw->data[0] > 5)) {
 		/* firmware is in the new format */
 		/* firmware is in the new format */
@@ -469,41 +460,37 @@ static int si2168_init(struct dvb_frontend *fe)
 			memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
 			memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
 			cmd.wlen = len;
 			cmd.wlen = len;
 			cmd.rlen = 1;
 			cmd.rlen = 1;
-			ret = si2168_cmd_execute(s, &cmd);
-			if (ret) {
-				dev_err(&s->client->dev,
-						"firmware download failed=%d\n",
-						ret);
-				goto error_fw_release;
-			}
+			ret = si2168_cmd_execute(client, &cmd);
+			if (ret)
+				break;
 		}
 		}
-	} else {
+	} else if (fw->size % 8 == 0) {
 		/* firmware is in the old format */
 		/* firmware is in the old format */
-		for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) {
-			len = remaining;
-			if (len > i2c_wr_max)
-				len = i2c_wr_max;
-
+		for (remaining = fw->size; remaining > 0; remaining -= 8) {
+			len = 8;
 			memcpy(cmd.args, &fw->data[fw->size - remaining], len);
 			memcpy(cmd.args, &fw->data[fw->size - remaining], len);
 			cmd.wlen = len;
 			cmd.wlen = len;
 			cmd.rlen = 1;
 			cmd.rlen = 1;
-			ret = si2168_cmd_execute(s, &cmd);
-			if (ret) {
-				dev_err(&s->client->dev,
-						"firmware download failed=%d\n",
-						ret);
-				goto error_fw_release;
-			}
+			ret = si2168_cmd_execute(client, &cmd);
+			if (ret)
+				break;
 		}
 		}
+	} else {
+		/* bad or unknown firmware format */
+		ret = -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&client->dev, "firmware download failed %d\n", ret);
+		goto err_release_firmware;
 	}
 	}
 
 
 	release_firmware(fw);
 	release_firmware(fw);
-	fw = NULL;
 
 
 	memcpy(cmd.args, "\x01\x01", 2);
 	memcpy(cmd.args, "\x01\x01", 2);
 	cmd.wlen = 2;
 	cmd.wlen = 2;
 	cmd.rlen = 1;
 	cmd.rlen = 1;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
@@ -511,58 +498,56 @@ static int si2168_init(struct dvb_frontend *fe)
 	memcpy(cmd.args, "\x11", 1);
 	memcpy(cmd.args, "\x11", 1);
 	cmd.wlen = 1;
 	cmd.wlen = 1;
 	cmd.rlen = 10;
 	cmd.rlen = 10;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	dev_dbg(&s->client->dev, "firmware version: %c.%c.%d\n",
+	dev_info(&client->dev, "firmware version: %c.%c.%d\n",
 			cmd.args[6], cmd.args[7], cmd.args[8]);
 			cmd.args[6], cmd.args[7], cmd.args[8]);
 
 
 	/* set ts mode */
 	/* set ts mode */
 	memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
 	memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
-	cmd.args[4] |= s->ts_mode;
+	cmd.args[4] |= dev->ts_mode;
 	cmd.wlen = 6;
 	cmd.wlen = 6;
 	cmd.rlen = 4;
 	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
-	s->fw_loaded = true;
-
-	dev_info(&s->client->dev, "found a '%s' in warm state\n",
-			si2168_ops.info.name);
+	dev->fw_loaded = true;
 warm:
 warm:
-	s->active = true;
+	dev->active = true;
 
 
 	return 0;
 	return 0;
 
 
-error_fw_release:
+err_release_firmware:
 	release_firmware(fw);
 	release_firmware(fw);
 err:
 err:
-	dev_dbg(&s->client->dev, "failed=%d\n", ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int si2168_sleep(struct dvb_frontend *fe)
 static int si2168_sleep(struct dvb_frontend *fe)
 {
 {
-	struct si2168 *s = fe->demodulator_priv;
+	struct i2c_client *client = fe->demodulator_priv;
+	struct si2168_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
 	struct si2168_cmd cmd;
 	struct si2168_cmd cmd;
 
 
-	dev_dbg(&s->client->dev, "\n");
+	dev_dbg(&client->dev, "\n");
 
 
-	s->active = false;
+	dev->active = false;
 
 
 	memcpy(cmd.args, "\x13", 1);
 	memcpy(cmd.args, "\x13", 1);
 	cmd.wlen = 1;
 	cmd.wlen = 1;
 	cmd.rlen = 0;
 	cmd.rlen = 0;
-	ret = si2168_cmd_execute(s, &cmd);
+	ret = si2168_cmd_execute(client, &cmd);
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
 	return 0;
 	return 0;
 err:
 err:
-	dev_dbg(&s->client->dev, "failed=%d\n", ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -581,21 +566,22 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe,
  */
  */
 static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
 static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
 {
 {
-	struct si2168 *s = mux_priv;
+	struct i2c_client *client = mux_priv;
+	struct si2168_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
 	struct i2c_msg gate_open_msg = {
 	struct i2c_msg gate_open_msg = {
-		.addr = s->client->addr,
+		.addr = client->addr,
 		.flags = 0,
 		.flags = 0,
 		.len = 3,
 		.len = 3,
 		.buf = "\xc0\x0d\x01",
 		.buf = "\xc0\x0d\x01",
 	};
 	};
 
 
-	mutex_lock(&s->i2c_mutex);
+	mutex_lock(&dev->i2c_mutex);
 
 
 	/* open tuner I2C gate */
 	/* open tuner I2C gate */
-	ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1);
+	ret = __i2c_transfer(client->adapter, &gate_open_msg, 1);
 	if (ret != 1) {
 	if (ret != 1) {
-		dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
+		dev_warn(&client->dev, "i2c write failed=%d\n", ret);
 		if (ret >= 0)
 		if (ret >= 0)
 			ret = -EREMOTEIO;
 			ret = -EREMOTEIO;
 	} else {
 	} else {
@@ -607,26 +593,27 @@ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
 
 
 static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
 static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
 {
 {
-	struct si2168 *s = mux_priv;
+	struct i2c_client *client = mux_priv;
+	struct si2168_dev *dev = i2c_get_clientdata(client);
 	int ret;
 	int ret;
 	struct i2c_msg gate_close_msg = {
 	struct i2c_msg gate_close_msg = {
-		.addr = s->client->addr,
+		.addr = client->addr,
 		.flags = 0,
 		.flags = 0,
 		.len = 3,
 		.len = 3,
 		.buf = "\xc0\x0d\x00",
 		.buf = "\xc0\x0d\x00",
 	};
 	};
 
 
 	/* close tuner I2C gate */
 	/* close tuner I2C gate */
-	ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1);
+	ret = __i2c_transfer(client->adapter, &gate_close_msg, 1);
 	if (ret != 1) {
 	if (ret != 1) {
-		dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
+		dev_warn(&client->dev, "i2c write failed=%d\n", ret);
 		if (ret >= 0)
 		if (ret >= 0)
 			ret = -EREMOTEIO;
 			ret = -EREMOTEIO;
 	} else {
 	} else {
 		ret = 0;
 		ret = 0;
 	}
 	}
 
 
-	mutex_unlock(&s->i2c_mutex);
+	mutex_unlock(&dev->i2c_mutex);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -635,6 +622,8 @@ static const struct dvb_frontend_ops si2168_ops = {
 	.delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
 	.delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
 	.info = {
 	.info = {
 		.name = "Silicon Labs Si2168",
 		.name = "Silicon Labs Si2168",
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 7200000,
 		.caps =	FE_CAN_FEC_1_2 |
 		.caps =	FE_CAN_FEC_1_2 |
 			FE_CAN_FEC_2_3 |
 			FE_CAN_FEC_2_3 |
 			FE_CAN_FEC_3_4 |
 			FE_CAN_FEC_3_4 |
@@ -670,71 +659,69 @@ static int si2168_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 		const struct i2c_device_id *id)
 {
 {
 	struct si2168_config *config = client->dev.platform_data;
 	struct si2168_config *config = client->dev.platform_data;
-	struct si2168 *s;
+	struct si2168_dev *dev;
 	int ret;
 	int ret;
 
 
 	dev_dbg(&client->dev, "\n");
 	dev_dbg(&client->dev, "\n");
 
 
-	s = kzalloc(sizeof(struct si2168), GFP_KERNEL);
-	if (!s) {
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		dev_err(&client->dev, "kzalloc() failed\n");
 		dev_err(&client->dev, "kzalloc() failed\n");
 		goto err;
 		goto err;
 	}
 	}
 
 
-	s->client = client;
-	mutex_init(&s->i2c_mutex);
+	mutex_init(&dev->i2c_mutex);
 
 
 	/* create mux i2c adapter for tuner */
 	/* 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) {
+	dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+			client, 0, 0, 0, si2168_select, si2168_deselect);
+	if (dev->adapter == NULL) {
 		ret = -ENODEV;
 		ret = -ENODEV;
-		goto err;
+		goto err_kfree;
 	}
 	}
 
 
 	/* create dvb_frontend */
 	/* create dvb_frontend */
-	memcpy(&s->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
-	s->fe.demodulator_priv = s;
-
-	*config->i2c_adapter = s->adapter;
-	*config->fe = &s->fe;
-	s->ts_mode = config->ts_mode;
-	s->ts_clock_inv = config->ts_clock_inv;
-	s->fw_loaded = false;
+	memcpy(&dev->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
+	dev->fe.demodulator_priv = client;
+	*config->i2c_adapter = dev->adapter;
+	*config->fe = &dev->fe;
+	dev->ts_mode = config->ts_mode;
+	dev->ts_clock_inv = config->ts_clock_inv;
+	dev->fw_loaded = false;
 
 
-	i2c_set_clientdata(client, s);
+	i2c_set_clientdata(client, dev);
 
 
-	dev_info(&s->client->dev,
-			"Silicon Labs Si2168 successfully attached\n");
+	dev_info(&client->dev, "Silicon Labs Si2168 successfully attached\n");
 	return 0;
 	return 0;
+err_kfree:
+	kfree(dev);
 err:
 err:
-	kfree(s);
 	dev_dbg(&client->dev, "failed=%d\n", ret);
 	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static int si2168_remove(struct i2c_client *client)
 static int si2168_remove(struct i2c_client *client)
 {
 {
-	struct si2168 *s = i2c_get_clientdata(client);
+	struct si2168_dev *dev = i2c_get_clientdata(client);
 
 
 	dev_dbg(&client->dev, "\n");
 	dev_dbg(&client->dev, "\n");
 
 
-	i2c_del_mux_adapter(s->adapter);
+	i2c_del_mux_adapter(dev->adapter);
 
 
-	s->fe.ops.release = NULL;
-	s->fe.demodulator_priv = NULL;
+	dev->fe.ops.release = NULL;
+	dev->fe.demodulator_priv = NULL;
 
 
-	kfree(s);
+	kfree(dev);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static const struct i2c_device_id si2168_id[] = {
+static const struct i2c_device_id si2168_id_table[] = {
 	{"si2168", 0},
 	{"si2168", 0},
 	{}
 	{}
 };
 };
-MODULE_DEVICE_TABLE(i2c, si2168_id);
+MODULE_DEVICE_TABLE(i2c, si2168_id_table);
 
 
 static struct i2c_driver si2168_driver = {
 static struct i2c_driver si2168_driver = {
 	.driver = {
 	.driver = {
@@ -743,7 +730,7 @@ static struct i2c_driver si2168_driver = {
 	},
 	},
 	.probe		= si2168_probe,
 	.probe		= si2168_probe,
 	.remove		= si2168_remove,
 	.remove		= si2168_remove,
-	.id_table	= si2168_id,
+	.id_table	= si2168_id_table,
 };
 };
 
 
 module_i2c_driver(si2168_driver);
 module_i2c_driver(si2168_driver);

+ 2 - 4
drivers/media/dvb-frontends/si2168.h

@@ -36,14 +36,12 @@ struct si2168_config {
 	struct i2c_adapter **i2c_adapter;
 	struct i2c_adapter **i2c_adapter;
 
 
 	/* TS mode */
 	/* TS mode */
+#define SI2168_TS_PARALLEL	0x06
+#define SI2168_TS_SERIAL	0x03
 	u8 ts_mode;
 	u8 ts_mode;
 
 
 	/* TS clock inverted */
 	/* TS clock inverted */
 	bool ts_clock_inv;
 	bool ts_clock_inv;
-
 };
 };
 
 
-#define SI2168_TS_PARALLEL	0x06
-#define SI2168_TS_SERIAL	0x03
-
 #endif
 #endif

+ 1 - 2
drivers/media/dvb-frontends/si2168_priv.h

@@ -28,8 +28,7 @@
 #define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw"
 #define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw"
 
 
 /* state struct */
 /* state struct */
-struct si2168 {
-	struct i2c_client *client;
+struct si2168_dev {
 	struct i2c_adapter *adapter;
 	struct i2c_adapter *adapter;
 	struct mutex i2c_mutex;
 	struct mutex i2c_mutex;
 	struct dvb_frontend fe;
 	struct dvb_frontend fe;

+ 2 - 3
drivers/media/dvb-frontends/stb0899_algo.c

@@ -19,6 +19,7 @@
 	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 */
 
 
+#include <linux/bitops.h>
 #include "stb0899_drv.h"
 #include "stb0899_drv.h"
 #include "stb0899_priv.h"
 #include "stb0899_priv.h"
 #include "stb0899_reg.h"
 #include "stb0899_reg.h"
@@ -1490,9 +1491,7 @@ enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
 		/* Store signal parameters	*/
 		/* Store signal parameters	*/
 		offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
 		offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
 
 
-		/* sign extend 30 bit value before using it in calculations */
-		if (offsetfreq & (1 << 29))
-			offsetfreq |= -1 << 30;
+		offsetfreq = sign_extend32(offsetfreq, 29);
 
 
 		offsetfreq = offsetfreq / ((1 << 30) / 1000);
 		offsetfreq = offsetfreq / ((1 << 30) / 1000);
 		offsetfreq *= (internal->master_clk / 1000000);
 		offsetfreq *= (internal->master_clk / 1000000);

+ 4 - 3
drivers/media/dvb-frontends/stb0899_drv.c

@@ -20,6 +20,7 @@
 */
 */
 
 
 #include <linux/init.h>
 #include <linux/init.h>
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
@@ -691,7 +692,7 @@ static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeo
 		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
 		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
 		if (!STB0899_GETFIELD(FIFOFULL, reg))
 		if (!STB0899_GETFIELD(FIFOFULL, reg))
 			break;
 			break;
-		if ((jiffies - start) > timeout) {
+		if (time_after(jiffies, start + timeout)) {
 			dprintk(state->verbose, FE_ERROR, 1, "timed out !!");
 			dprintk(state->verbose, FE_ERROR, 1, "timed out !!");
 			return -ETIMEDOUT;
 			return -ETIMEDOUT;
 		}
 		}
@@ -733,7 +734,7 @@ static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout)
 
 
 	while (!STB0899_GETFIELD(RXEND, reg)) {
 	while (!STB0899_GETFIELD(RXEND, reg)) {
 		reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
 		reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
-		if (jiffies - start > timeout) {
+		if (time_after(jiffies, start + timeout)) {
 			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
 			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
 			return -ETIMEDOUT;
 			return -ETIMEDOUT;
 		}
 		}
@@ -782,7 +783,7 @@ static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout)
 
 
 	while (!STB0899_GETFIELD(TXIDLE, reg)) {
 	while (!STB0899_GETFIELD(TXIDLE, reg)) {
 		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
 		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
-		if (jiffies - start > timeout) {
+		if (time_after(jiffies, start + timeout)) {
 			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
 			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
 			return -ETIMEDOUT;
 			return -ETIMEDOUT;
 		}
 		}

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

@@ -214,6 +214,7 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe)
 	state = fe->demodulator_priv;
 	state = fe->demodulator_priv;
 	c = &fe->dtv_property_cache;
 	c = &fe->dtv_property_cache;
 	c->delivery_system = SYS_ISDBS;
 	c->delivery_system = SYS_ISDBS;
+	c->symbol_rate = 28860000;
 
 
 	layers = 0;
 	layers = 0;
 	ret = reg_read(state, 0xe6, val, 5);
 	ret = reg_read(state, 0xe6, val, 5);

+ 5 - 4
drivers/media/i2c/Kconfig

@@ -177,7 +177,7 @@ comment "Video decoders"
 
 
 config VIDEO_ADV7180
 config VIDEO_ADV7180
 	tristate "Analog Devices ADV7180 decoder"
 	tristate "Analog Devices ADV7180 decoder"
-	depends on VIDEO_V4L2 && I2C
+	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
 	---help---
 	---help---
 	  Support for the Analog Devices ADV7180 video decoder.
 	  Support for the Analog Devices ADV7180 video decoder.
 
 
@@ -196,7 +196,7 @@ config VIDEO_ADV7183
 
 
 config VIDEO_ADV7604
 config VIDEO_ADV7604
 	tristate "Analog Devices ADV7604 decoder"
 	tristate "Analog Devices ADV7604 decoder"
-	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
+	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
 	---help---
 	---help---
 	  Support for the Analog Devices ADV7604 video decoder.
 	  Support for the Analog Devices ADV7604 video decoder.
 
 
@@ -208,7 +208,8 @@ config VIDEO_ADV7604
 
 
 config VIDEO_ADV7842
 config VIDEO_ADV7842
 	tristate "Analog Devices ADV7842 decoder"
 	tristate "Analog Devices ADV7842 decoder"
-	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
+	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+	select HDMI
 	---help---
 	---help---
 	  Support for the Analog Devices ADV7842 video decoder.
 	  Support for the Analog Devices ADV7842 video decoder.
 
 
@@ -422,7 +423,7 @@ config VIDEO_ADV7393
 
 
 config VIDEO_ADV7511
 config VIDEO_ADV7511
 	tristate "Analog Devices ADV7511 encoder"
 	tristate "Analog Devices ADV7511 encoder"
-	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
+	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
 	---help---
 	---help---
 	  Support for the Analog Devices ADV7511 video encoder.
 	  Support for the Analog Devices ADV7511 video encoder.
 
 

+ 812 - 198
drivers/media/i2c/adv7180.c

@@ -30,56 +30,60 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-ctrls.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
-
-#define ADV7180_INPUT_CONTROL_REG			0x00
-#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM	0x00
-#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
-#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM	0x20
-#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM	0x30
-#define ADV7180_INPUT_CONTROL_NTSC_J			0x40
-#define ADV7180_INPUT_CONTROL_NTSC_M			0x50
-#define ADV7180_INPUT_CONTROL_PAL60			0x60
-#define ADV7180_INPUT_CONTROL_NTSC_443			0x70
-#define ADV7180_INPUT_CONTROL_PAL_BG			0x80
-#define ADV7180_INPUT_CONTROL_PAL_N			0x90
-#define ADV7180_INPUT_CONTROL_PAL_M			0xa0
-#define ADV7180_INPUT_CONTROL_PAL_M_PED			0xb0
-#define ADV7180_INPUT_CONTROL_PAL_COMB_N		0xc0
-#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED		0xd0
-#define ADV7180_INPUT_CONTROL_PAL_SECAM			0xe0
-#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED		0xf0
+#include <linux/delay.h>
+
+#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM		0x0
+#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED		0x1
+#define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM		0x2
+#define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM		0x3
+#define ADV7180_STD_NTSC_J				0x4
+#define ADV7180_STD_NTSC_M				0x5
+#define ADV7180_STD_PAL60				0x6
+#define ADV7180_STD_NTSC_443				0x7
+#define ADV7180_STD_PAL_BG				0x8
+#define ADV7180_STD_PAL_N				0x9
+#define ADV7180_STD_PAL_M				0xa
+#define ADV7180_STD_PAL_M_PED				0xb
+#define ADV7180_STD_PAL_COMB_N				0xc
+#define ADV7180_STD_PAL_COMB_N_PED			0xd
+#define ADV7180_STD_PAL_SECAM				0xe
+#define ADV7180_STD_PAL_SECAM_PED			0xf
+
+#define ADV7180_REG_INPUT_CONTROL			0x0000
 #define ADV7180_INPUT_CONTROL_INSEL_MASK		0x0f
 #define ADV7180_INPUT_CONTROL_INSEL_MASK		0x0f
 
 
-#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG		0x04
+#define ADV7182_REG_INPUT_VIDSEL			0x0002
+
+#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL		0x0004
 #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
 #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
 
 
-#define ADV7180_AUTODETECT_ENABLE_REG			0x07
+#define ADV7180_REG_AUTODETECT_ENABLE			0x07
 #define ADV7180_AUTODETECT_DEFAULT			0x7f
 #define ADV7180_AUTODETECT_DEFAULT			0x7f
 /* Contrast */
 /* Contrast */
-#define ADV7180_CON_REG		0x08	/*Unsigned */
+#define ADV7180_REG_CON		0x0008	/*Unsigned */
 #define ADV7180_CON_MIN		0
 #define ADV7180_CON_MIN		0
 #define ADV7180_CON_DEF		128
 #define ADV7180_CON_DEF		128
 #define ADV7180_CON_MAX		255
 #define ADV7180_CON_MAX		255
 /* Brightness*/
 /* Brightness*/
-#define ADV7180_BRI_REG		0x0a	/*Signed */
+#define ADV7180_REG_BRI		0x000a	/*Signed */
 #define ADV7180_BRI_MIN		-128
 #define ADV7180_BRI_MIN		-128
 #define ADV7180_BRI_DEF		0
 #define ADV7180_BRI_DEF		0
 #define ADV7180_BRI_MAX		127
 #define ADV7180_BRI_MAX		127
 /* Hue */
 /* Hue */
-#define ADV7180_HUE_REG		0x0b	/*Signed, inverted */
+#define ADV7180_REG_HUE		0x000b	/*Signed, inverted */
 #define ADV7180_HUE_MIN		-127
 #define ADV7180_HUE_MIN		-127
 #define ADV7180_HUE_DEF		0
 #define ADV7180_HUE_DEF		0
 #define ADV7180_HUE_MAX		128
 #define ADV7180_HUE_MAX		128
 
 
-#define ADV7180_ADI_CTRL_REG				0x0e
-#define ADV7180_ADI_CTRL_IRQ_SPACE			0x20
+#define ADV7180_REG_CTRL		0x000e
+#define ADV7180_CTRL_IRQ_SPACE		0x20
 
 
-#define ADV7180_PWR_MAN_REG		0x0f
+#define ADV7180_REG_PWR_MAN		0x0f
 #define ADV7180_PWR_MAN_ON		0x04
 #define ADV7180_PWR_MAN_ON		0x04
 #define ADV7180_PWR_MAN_OFF		0x24
 #define ADV7180_PWR_MAN_OFF		0x24
 #define ADV7180_PWR_MAN_RES		0x80
 #define ADV7180_PWR_MAN_RES		0x80
 
 
-#define ADV7180_STATUS1_REG				0x10
+#define ADV7180_REG_STATUS1		0x0010
 #define ADV7180_STATUS1_IN_LOCK		0x01
 #define ADV7180_STATUS1_IN_LOCK		0x01
 #define ADV7180_STATUS1_AUTOD_MASK	0x70
 #define ADV7180_STATUS1_AUTOD_MASK	0x70
 #define ADV7180_STATUS1_AUTOD_NTSM_M_J	0x00
 #define ADV7180_STATUS1_AUTOD_NTSM_M_J	0x00
@@ -91,49 +95,161 @@
 #define ADV7180_STATUS1_AUTOD_PAL_COMB	0x60
 #define ADV7180_STATUS1_AUTOD_PAL_COMB	0x60
 #define ADV7180_STATUS1_AUTOD_SECAM_525	0x70
 #define ADV7180_STATUS1_AUTOD_SECAM_525	0x70
 
 
-#define ADV7180_IDENT_REG 0x11
+#define ADV7180_REG_IDENT 0x0011
 #define ADV7180_ID_7180 0x18
 #define ADV7180_ID_7180 0x18
 
 
-#define ADV7180_ICONF1_ADI		0x40
+#define ADV7180_REG_ICONF1		0x0040
 #define ADV7180_ICONF1_ACTIVE_LOW	0x01
 #define ADV7180_ICONF1_ACTIVE_LOW	0x01
 #define ADV7180_ICONF1_PSYNC_ONLY	0x10
 #define ADV7180_ICONF1_PSYNC_ONLY	0x10
 #define ADV7180_ICONF1_ACTIVE_TO_CLR	0xC0
 #define ADV7180_ICONF1_ACTIVE_TO_CLR	0xC0
 /* Saturation */
 /* Saturation */
-#define ADV7180_SD_SAT_CB_REG	0xe3	/*Unsigned */
-#define ADV7180_SD_SAT_CR_REG	0xe4	/*Unsigned */
+#define ADV7180_REG_SD_SAT_CB	0x00e3	/*Unsigned */
+#define ADV7180_REG_SD_SAT_CR	0x00e4	/*Unsigned */
 #define ADV7180_SAT_MIN		0
 #define ADV7180_SAT_MIN		0
 #define ADV7180_SAT_DEF		128
 #define ADV7180_SAT_DEF		128
 #define ADV7180_SAT_MAX		255
 #define ADV7180_SAT_MAX		255
 
 
 #define ADV7180_IRQ1_LOCK	0x01
 #define ADV7180_IRQ1_LOCK	0x01
 #define ADV7180_IRQ1_UNLOCK	0x02
 #define ADV7180_IRQ1_UNLOCK	0x02
-#define ADV7180_ISR1_ADI	0x42
-#define ADV7180_ICR1_ADI	0x43
-#define ADV7180_IMR1_ADI	0x44
-#define ADV7180_IMR2_ADI	0x48
+#define ADV7180_REG_ISR1	0x0042
+#define ADV7180_REG_ICR1	0x0043
+#define ADV7180_REG_IMR1	0x0044
+#define ADV7180_REG_IMR2	0x0048
 #define ADV7180_IRQ3_AD_CHANGE	0x08
 #define ADV7180_IRQ3_AD_CHANGE	0x08
-#define ADV7180_ISR3_ADI	0x4A
-#define ADV7180_ICR3_ADI	0x4B
-#define ADV7180_IMR3_ADI	0x4C
-#define ADV7180_IMR4_ADI	0x50
+#define ADV7180_REG_ISR3	0x004A
+#define ADV7180_REG_ICR3	0x004B
+#define ADV7180_REG_IMR3	0x004C
+#define ADV7180_REG_IMR4	0x50
 
 
-#define ADV7180_NTSC_V_BIT_END_REG	0xE6
+#define ADV7180_REG_NTSC_V_BIT_END	0x00E6
 #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
 #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
 
 
+#define ADV7180_REG_VPP_SLAVE_ADDR	0xFD
+#define ADV7180_REG_CSI_SLAVE_ADDR	0xFE
+
+#define ADV7180_REG_FLCONTROL 0x40e0
+#define ADV7180_FLCONTROL_FL_ENABLE 0x1
+
+#define ADV7180_CSI_REG_PWRDN	0x00
+#define ADV7180_CSI_PWRDN	0x80
+
+#define ADV7180_INPUT_CVBS_AIN1 0x00
+#define ADV7180_INPUT_CVBS_AIN2 0x01
+#define ADV7180_INPUT_CVBS_AIN3 0x02
+#define ADV7180_INPUT_CVBS_AIN4 0x03
+#define ADV7180_INPUT_CVBS_AIN5 0x04
+#define ADV7180_INPUT_CVBS_AIN6 0x05
+#define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06
+#define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07
+#define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08
+#define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09
+#define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a
+
+#define ADV7182_INPUT_CVBS_AIN1 0x00
+#define ADV7182_INPUT_CVBS_AIN2 0x01
+#define ADV7182_INPUT_CVBS_AIN3 0x02
+#define ADV7182_INPUT_CVBS_AIN4 0x03
+#define ADV7182_INPUT_CVBS_AIN5 0x04
+#define ADV7182_INPUT_CVBS_AIN6 0x05
+#define ADV7182_INPUT_CVBS_AIN7 0x06
+#define ADV7182_INPUT_CVBS_AIN8 0x07
+#define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08
+#define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09
+#define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a
+#define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b
+#define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c
+#define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d
+#define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e
+#define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f
+#define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10
+#define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11
+
+#define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44
+#define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42
+
+#define V4L2_CID_ADV_FAST_SWITCH	(V4L2_CID_USER_ADV7180_BASE + 0x00)
+
+struct adv7180_state;
+
+#define ADV7180_FLAG_RESET_POWERED	BIT(0)
+#define ADV7180_FLAG_V2			BIT(1)
+#define ADV7180_FLAG_MIPI_CSI2		BIT(2)
+#define ADV7180_FLAG_I2P		BIT(3)
+
+struct adv7180_chip_info {
+	unsigned int flags;
+	unsigned int valid_input_mask;
+	int (*set_std)(struct adv7180_state *st, unsigned int std);
+	int (*select_input)(struct adv7180_state *st, unsigned int input);
+	int (*init)(struct adv7180_state *state);
+};
+
 struct adv7180_state {
 struct adv7180_state {
 	struct v4l2_ctrl_handler ctrl_hdl;
 	struct v4l2_ctrl_handler ctrl_hdl;
 	struct v4l2_subdev	sd;
 	struct v4l2_subdev	sd;
+	struct media_pad	pad;
 	struct mutex		mutex; /* mutual excl. when accessing chip */
 	struct mutex		mutex; /* mutual excl. when accessing chip */
 	int			irq;
 	int			irq;
 	v4l2_std_id		curr_norm;
 	v4l2_std_id		curr_norm;
 	bool			autodetect;
 	bool			autodetect;
 	bool			powered;
 	bool			powered;
 	u8			input;
 	u8			input;
+
+	struct i2c_client	*client;
+	unsigned int		register_page;
+	struct i2c_client	*csi_client;
+	struct i2c_client	*vpp_client;
+	const struct adv7180_chip_info *chip_info;
+	enum v4l2_field		field;
 };
 };
 #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler,		\
 #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler,		\
 					    struct adv7180_state,	\
 					    struct adv7180_state,	\
 					    ctrl_hdl)->sd)
 					    ctrl_hdl)->sd)
 
 
+static int adv7180_select_page(struct adv7180_state *state, unsigned int page)
+{
+	if (state->register_page != page) {
+		i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL,
+			page);
+		state->register_page = page;
+	}
+
+	return 0;
+}
+
+static int adv7180_write(struct adv7180_state *state, unsigned int reg,
+	unsigned int value)
+{
+	lockdep_assert_held(&state->mutex);
+	adv7180_select_page(state, reg >> 8);
+	return i2c_smbus_write_byte_data(state->client, reg & 0xff, value);
+}
+
+static int adv7180_read(struct adv7180_state *state, unsigned int reg)
+{
+	lockdep_assert_held(&state->mutex);
+	adv7180_select_page(state, reg >> 8);
+	return i2c_smbus_read_byte_data(state->client, reg & 0xff);
+}
+
+static int adv7180_csi_write(struct adv7180_state *state, unsigned int reg,
+	unsigned int value)
+{
+	return i2c_smbus_write_byte_data(state->csi_client, reg, value);
+}
+
+static int adv7180_set_video_standard(struct adv7180_state *state,
+	unsigned int std)
+{
+	return state->chip_info->set_std(state, std);
+}
+
+static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg,
+	unsigned int value)
+{
+	return i2c_smbus_write_byte_data(state->vpp_client, reg, value);
+}
+
 static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
 static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
 {
 {
 	/* in case V4L2_IN_ST_NO_SIGNAL */
 	/* in case V4L2_IN_ST_NO_SIGNAL */
@@ -165,22 +281,22 @@ static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
 static int v4l2_std_to_adv7180(v4l2_std_id std)
 static int v4l2_std_to_adv7180(v4l2_std_id std)
 {
 {
 	if (std == V4L2_STD_PAL_60)
 	if (std == V4L2_STD_PAL_60)
-		return ADV7180_INPUT_CONTROL_PAL60;
+		return ADV7180_STD_PAL60;
 	if (std == V4L2_STD_NTSC_443)
 	if (std == V4L2_STD_NTSC_443)
-		return ADV7180_INPUT_CONTROL_NTSC_443;
+		return ADV7180_STD_NTSC_443;
 	if (std == V4L2_STD_PAL_N)
 	if (std == V4L2_STD_PAL_N)
-		return ADV7180_INPUT_CONTROL_PAL_N;
+		return ADV7180_STD_PAL_N;
 	if (std == V4L2_STD_PAL_M)
 	if (std == V4L2_STD_PAL_M)
-		return ADV7180_INPUT_CONTROL_PAL_M;
+		return ADV7180_STD_PAL_M;
 	if (std == V4L2_STD_PAL_Nc)
 	if (std == V4L2_STD_PAL_Nc)
-		return ADV7180_INPUT_CONTROL_PAL_COMB_N;
+		return ADV7180_STD_PAL_COMB_N;
 
 
 	if (std & V4L2_STD_PAL)
 	if (std & V4L2_STD_PAL)
-		return ADV7180_INPUT_CONTROL_PAL_BG;
+		return ADV7180_STD_PAL_BG;
 	if (std & V4L2_STD_NTSC)
 	if (std & V4L2_STD_NTSC)
-		return ADV7180_INPUT_CONTROL_NTSC_M;
+		return ADV7180_STD_NTSC_M;
 	if (std & V4L2_STD_SECAM)
 	if (std & V4L2_STD_SECAM)
-		return ADV7180_INPUT_CONTROL_PAL_SECAM;
+		return ADV7180_STD_PAL_SECAM;
 
 
 	return -EINVAL;
 	return -EINVAL;
 }
 }
@@ -193,10 +309,10 @@ static u32 adv7180_status_to_v4l2(u8 status1)
 	return 0;
 	return 0;
 }
 }
 
 
-static int __adv7180_status(struct i2c_client *client, u32 *status,
+static int __adv7180_status(struct adv7180_state *state, u32 *status,
 			    v4l2_std_id *std)
 			    v4l2_std_id *std)
 {
 {
-	int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
+	int status1 = adv7180_read(state, ADV7180_REG_STATUS1);
 
 
 	if (status1 < 0)
 	if (status1 < 0)
 		return status1;
 		return status1;
@@ -225,7 +341,7 @@ static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
 	if (!state->autodetect || state->irq > 0)
 	if (!state->autodetect || state->irq > 0)
 		*std = state->curr_norm;
 		*std = state->curr_norm;
 	else
 	else
-		err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
+		err = __adv7180_status(state, NULL, std);
 
 
 	mutex_unlock(&state->mutex);
 	mutex_unlock(&state->mutex);
 	return err;
 	return err;
@@ -236,26 +352,19 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
 {
 {
 	struct adv7180_state *state = to_state(sd);
 	struct adv7180_state *state = to_state(sd);
 	int ret = mutex_lock_interruptible(&state->mutex);
 	int ret = mutex_lock_interruptible(&state->mutex);
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
 
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	/* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
-	 * all inputs and let the card driver take care of validation
-	 */
-	if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
+	if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) {
+		ret = -EINVAL;
 		goto out;
 		goto out;
+	}
 
 
-	ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
-
-	if (ret < 0)
-		goto out;
+	ret = state->chip_info->select_input(state, input);
 
 
-	ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
-	ret = i2c_smbus_write_byte_data(client,
-					ADV7180_INPUT_CONTROL_REG, ret | input);
-	state->input = input;
+	if (ret == 0)
+		state->input = input;
 out:
 out:
 	mutex_unlock(&state->mutex);
 	mutex_unlock(&state->mutex);
 	return ret;
 	return ret;
@@ -268,74 +377,104 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
+	ret = __adv7180_status(state, status, NULL);
 	mutex_unlock(&state->mutex);
 	mutex_unlock(&state->mutex);
 	return ret;
 	return ret;
 }
 }
 
 
+static int adv7180_program_std(struct adv7180_state *state)
+{
+	int ret;
+
+	if (state->autodetect) {
+		ret = adv7180_set_video_standard(state,
+			ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
+		if (ret < 0)
+			return ret;
+
+		__adv7180_status(state, NULL, &state->curr_norm);
+	} else {
+		ret = v4l2_std_to_adv7180(state->curr_norm);
+		if (ret < 0)
+			return ret;
+
+		ret = adv7180_set_video_standard(state, ret);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
 {
 	struct adv7180_state *state = to_state(sd);
 	struct adv7180_state *state = to_state(sd);
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	int ret = mutex_lock_interruptible(&state->mutex);
 	int ret = mutex_lock_interruptible(&state->mutex);
+
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
 	/* all standards -> autodetect */
 	/* all standards -> autodetect */
 	if (std == V4L2_STD_ALL) {
 	if (std == V4L2_STD_ALL) {
-		ret =
-		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
-				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
-					      | state->input);
-		if (ret < 0)
-			goto out;
-
-		__adv7180_status(client, NULL, &state->curr_norm);
 		state->autodetect = true;
 		state->autodetect = true;
 	} else {
 	} else {
+		/* Make sure we can support this std */
 		ret = v4l2_std_to_adv7180(std);
 		ret = v4l2_std_to_adv7180(std);
 		if (ret < 0)
 		if (ret < 0)
 			goto out;
 			goto out;
 
 
-		ret = i2c_smbus_write_byte_data(client,
-						ADV7180_INPUT_CONTROL_REG,
-						ret | state->input);
-		if (ret < 0)
-			goto out;
-
 		state->curr_norm = std;
 		state->curr_norm = std;
 		state->autodetect = false;
 		state->autodetect = false;
 	}
 	}
-	ret = 0;
+
+	ret = adv7180_program_std(state);
 out:
 out:
 	mutex_unlock(&state->mutex);
 	mutex_unlock(&state->mutex);
 	return ret;
 	return ret;
 }
 }
 
 
-static int adv7180_set_power(struct adv7180_state *state,
-	struct i2c_client *client, bool on)
+static int adv7180_set_power(struct adv7180_state *state, bool on)
 {
 {
 	u8 val;
 	u8 val;
+	int ret;
 
 
 	if (on)
 	if (on)
 		val = ADV7180_PWR_MAN_ON;
 		val = ADV7180_PWR_MAN_ON;
 	else
 	else
 		val = ADV7180_PWR_MAN_OFF;
 		val = ADV7180_PWR_MAN_OFF;
 
 
-	return i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, val);
+	ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val);
+	if (ret)
+		return ret;
+
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+		if (on) {
+			adv7180_csi_write(state, 0xDE, 0x02);
+			adv7180_csi_write(state, 0xD2, 0xF7);
+			adv7180_csi_write(state, 0xD8, 0x65);
+			adv7180_csi_write(state, 0xE0, 0x09);
+			adv7180_csi_write(state, 0x2C, 0x00);
+			if (state->field == V4L2_FIELD_NONE)
+				adv7180_csi_write(state, 0x1D, 0x80);
+			adv7180_csi_write(state, 0x00, 0x00);
+		} else {
+			adv7180_csi_write(state, 0x00, 0x80);
+		}
+	}
+
+	return 0;
 }
 }
 
 
 static int adv7180_s_power(struct v4l2_subdev *sd, int on)
 static int adv7180_s_power(struct v4l2_subdev *sd, int on)
 {
 {
 	struct adv7180_state *state = to_state(sd);
 	struct adv7180_state *state = to_state(sd);
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	int ret;
 	int ret;
 
 
 	ret = mutex_lock_interruptible(&state->mutex);
 	ret = mutex_lock_interruptible(&state->mutex);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	ret = adv7180_set_power(state, client, on);
+	ret = adv7180_set_power(state, on);
 	if (ret == 0)
 	if (ret == 0)
 		state->powered = on;
 		state->powered = on;
 
 
@@ -347,7 +486,6 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 {
 	struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
 	struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
 	struct adv7180_state *state = to_state(sd);
 	struct adv7180_state *state = to_state(sd);
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	int ret = mutex_lock_interruptible(&state->mutex);
 	int ret = mutex_lock_interruptible(&state->mutex);
 	int val;
 	int val;
 
 
@@ -356,26 +494,36 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
 	val = ctrl->val;
 	val = ctrl->val;
 	switch (ctrl->id) {
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
 	case V4L2_CID_BRIGHTNESS:
-		ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val);
+		ret = adv7180_write(state, ADV7180_REG_BRI, val);
 		break;
 		break;
 	case V4L2_CID_HUE:
 	case V4L2_CID_HUE:
 		/*Hue is inverted according to HSL chart */
 		/*Hue is inverted according to HSL chart */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val);
+		ret = adv7180_write(state, ADV7180_REG_HUE, -val);
 		break;
 		break;
 	case V4L2_CID_CONTRAST:
 	case V4L2_CID_CONTRAST:
-		ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val);
+		ret = adv7180_write(state, ADV7180_REG_CON, val);
 		break;
 		break;
 	case V4L2_CID_SATURATION:
 	case V4L2_CID_SATURATION:
 		/*
 		/*
 		 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
 		 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
 		 *Let's not confuse the user, everybody understands saturation
 		 *Let's not confuse the user, everybody understands saturation
 		 */
 		 */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
-						val);
+		ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val);
 		if (ret < 0)
 		if (ret < 0)
 			break;
 			break;
-		ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
-						val);
+		ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val);
+		break;
+	case V4L2_CID_ADV_FAST_SWITCH:
+		if (ctrl->val) {
+			/* ADI required write */
+			adv7180_write(state, 0x80d9, 0x44);
+			adv7180_write(state, ADV7180_REG_FLCONTROL,
+				ADV7180_FLCONTROL_FL_ENABLE);
+		} else {
+			/* ADI required write */
+			adv7180_write(state, 0x80d9, 0xc4);
+			adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00);
+		}
 		break;
 		break;
 	default:
 	default:
 		ret = -EINVAL;
 		ret = -EINVAL;
@@ -389,6 +537,16 @@ static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
 	.s_ctrl = adv7180_s_ctrl,
 	.s_ctrl = adv7180_s_ctrl,
 };
 };
 
 
+static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = {
+	.ops = &adv7180_ctrl_ops,
+	.id = V4L2_CID_ADV_FAST_SWITCH,
+	.name = "Fast Switching",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+};
+
 static int adv7180_init_controls(struct adv7180_state *state)
 static int adv7180_init_controls(struct adv7180_state *state)
 {
 {
 	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
 	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
@@ -405,6 +563,8 @@ static int adv7180_init_controls(struct adv7180_state *state)
 	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
 	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
 			  V4L2_CID_HUE, ADV7180_HUE_MIN,
 			  V4L2_CID_HUE, ADV7180_HUE_MIN,
 			  ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
 			  ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
+	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
+
 	state->sd.ctrl_handler = &state->ctrl_hdl;
 	state->sd.ctrl_handler = &state->ctrl_hdl;
 	if (state->ctrl_hdl.error) {
 	if (state->ctrl_hdl.error) {
 		int err = state->ctrl_hdl.error;
 		int err = state->ctrl_hdl.error;
@@ -421,13 +581,14 @@ static void adv7180_exit_controls(struct adv7180_state *state)
 	v4l2_ctrl_handler_free(&state->ctrl_hdl);
 	v4l2_ctrl_handler_free(&state->ctrl_hdl);
 }
 }
 
 
-static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
-				 u32 *code)
+static int adv7180_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
 {
 {
-	if (index > 0)
+	if (code->index != 0)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	*code = MEDIA_BUS_FMT_YUYV8_2X8;
+	code->code = MEDIA_BUS_FMT_YUYV8_2X8;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -439,23 +600,118 @@ static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
 
 
 	fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
 	fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
 	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
 	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
-	fmt->field = V4L2_FIELD_INTERLACED;
 	fmt->width = 720;
 	fmt->width = 720;
 	fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
 	fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
+static int adv7180_set_field_mode(struct adv7180_state *state)
+{
+	if (!(state->chip_info->flags & ADV7180_FLAG_I2P))
+		return 0;
+
+	if (state->field == V4L2_FIELD_NONE) {
+		if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+			adv7180_csi_write(state, 0x01, 0x20);
+			adv7180_csi_write(state, 0x02, 0x28);
+			adv7180_csi_write(state, 0x03, 0x38);
+			adv7180_csi_write(state, 0x04, 0x30);
+			adv7180_csi_write(state, 0x05, 0x30);
+			adv7180_csi_write(state, 0x06, 0x80);
+			adv7180_csi_write(state, 0x07, 0x70);
+			adv7180_csi_write(state, 0x08, 0x50);
+		}
+		adv7180_vpp_write(state, 0xa3, 0x00);
+		adv7180_vpp_write(state, 0x5b, 0x00);
+		adv7180_vpp_write(state, 0x55, 0x80);
+	} else {
+		if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+			adv7180_csi_write(state, 0x01, 0x18);
+			adv7180_csi_write(state, 0x02, 0x18);
+			adv7180_csi_write(state, 0x03, 0x30);
+			adv7180_csi_write(state, 0x04, 0x20);
+			adv7180_csi_write(state, 0x05, 0x28);
+			adv7180_csi_write(state, 0x06, 0x40);
+			adv7180_csi_write(state, 0x07, 0x58);
+			adv7180_csi_write(state, 0x08, 0x30);
+		}
+		adv7180_vpp_write(state, 0xa3, 0x70);
+		adv7180_vpp_write(state, 0x5b, 0x80);
+		adv7180_vpp_write(state, 0x55, 0x00);
+	}
+
+	return 0;
+}
+
+static int adv7180_get_pad_format(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *format)
+{
+	struct adv7180_state *state = to_state(sd);
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		format->format = *v4l2_subdev_get_try_format(fh, 0);
+	} else {
+		adv7180_mbus_fmt(sd, &format->format);
+		format->format.field = state->field;
+	}
+
+	return 0;
+}
+
+static int adv7180_set_pad_format(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *format)
+{
+	struct adv7180_state *state = to_state(sd);
+	struct v4l2_mbus_framefmt *framefmt;
+
+	switch (format->format.field) {
+	case V4L2_FIELD_NONE:
+		if (!(state->chip_info->flags & ADV7180_FLAG_I2P))
+			format->format.field = V4L2_FIELD_INTERLACED;
+		break;
+	default:
+		format->format.field = V4L2_FIELD_INTERLACED;
+		break;
+	}
+
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		framefmt = &format->format;
+		if (state->field != format->format.field) {
+			state->field = format->format.field;
+			adv7180_set_power(state, false);
+			adv7180_set_field_mode(state);
+			adv7180_set_power(state, true);
+		}
+	} else {
+		framefmt = v4l2_subdev_get_try_format(fh, 0);
+		*framefmt = format->format;
+	}
+
+	return adv7180_mbus_fmt(sd, framefmt);
+}
+
 static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
 static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
 				 struct v4l2_mbus_config *cfg)
 				 struct v4l2_mbus_config *cfg)
 {
 {
-	/*
-	 * The ADV7180 sensor supports BT.601/656 output modes.
-	 * The BT.656 is default and not yet configurable by s/w.
-	 */
-	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
-		     V4L2_MBUS_DATA_ACTIVE_HIGH;
-	cfg->type = V4L2_MBUS_BT656;
+	struct adv7180_state *state = to_state(sd);
+
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+		cfg->type = V4L2_MBUS_CSI2;
+		cfg->flags = V4L2_MBUS_CSI2_1_LANE |
+				V4L2_MBUS_CSI2_CHANNEL_0 |
+				V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+	} else {
+		/*
+		 * The ADV7180 sensor supports BT.601/656 output modes.
+		 * The BT.656 is default and not yet configurable by s/w.
+		 */
+		cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+				 V4L2_MBUS_DATA_ACTIVE_HIGH;
+		cfg->type = V4L2_MBUS_BT656;
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -465,139 +721,439 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
 	.querystd = adv7180_querystd,
 	.querystd = adv7180_querystd,
 	.g_input_status = adv7180_g_input_status,
 	.g_input_status = adv7180_g_input_status,
 	.s_routing = adv7180_s_routing,
 	.s_routing = adv7180_s_routing,
-	.enum_mbus_fmt = adv7180_enum_mbus_fmt,
-	.try_mbus_fmt = adv7180_mbus_fmt,
-	.g_mbus_fmt = adv7180_mbus_fmt,
-	.s_mbus_fmt = adv7180_mbus_fmt,
 	.g_mbus_config = adv7180_g_mbus_config,
 	.g_mbus_config = adv7180_g_mbus_config,
 };
 };
 
 
+
 static const struct v4l2_subdev_core_ops adv7180_core_ops = {
 static const struct v4l2_subdev_core_ops adv7180_core_ops = {
 	.s_power = adv7180_s_power,
 	.s_power = adv7180_s_power,
 };
 };
 
 
+static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
+	.enum_mbus_code = adv7180_enum_mbus_code,
+	.set_fmt = adv7180_set_pad_format,
+	.get_fmt = adv7180_get_pad_format,
+};
+
 static const struct v4l2_subdev_ops adv7180_ops = {
 static const struct v4l2_subdev_ops adv7180_ops = {
 	.core = &adv7180_core_ops,
 	.core = &adv7180_core_ops,
 	.video = &adv7180_video_ops,
 	.video = &adv7180_video_ops,
+	.pad = &adv7180_pad_ops,
 };
 };
 
 
 static irqreturn_t adv7180_irq(int irq, void *devid)
 static irqreturn_t adv7180_irq(int irq, void *devid)
 {
 {
 	struct adv7180_state *state = devid;
 	struct adv7180_state *state = devid;
-	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
 	u8 isr3;
 	u8 isr3;
 
 
 	mutex_lock(&state->mutex);
 	mutex_lock(&state->mutex);
-	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
-				  ADV7180_ADI_CTRL_IRQ_SPACE);
-	isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
+	isr3 = adv7180_read(state, ADV7180_REG_ISR3);
 	/* clear */
 	/* clear */
-	i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
-	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
+	adv7180_write(state, ADV7180_REG_ICR3, isr3);
 
 
 	if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
 	if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
-		__adv7180_status(client, NULL, &state->curr_norm);
+		__adv7180_status(state, NULL, &state->curr_norm);
 	mutex_unlock(&state->mutex);
 	mutex_unlock(&state->mutex);
 
 
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
-static int init_device(struct i2c_client *client, struct adv7180_state *state)
+static int adv7180_init(struct adv7180_state *state)
 {
 {
 	int ret;
 	int ret;
 
 
-	/* Initialize adv7180 */
-	/* Enable autodetection */
-	if (state->autodetect) {
-		ret =
-		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
-				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
-					      | state->input);
-		if (ret < 0)
-			return ret;
-
-		ret =
-		    i2c_smbus_write_byte_data(client,
-					      ADV7180_AUTODETECT_ENABLE_REG,
-					      ADV7180_AUTODETECT_DEFAULT);
-		if (ret < 0)
-			return ret;
-	} else {
-		ret = v4l2_std_to_adv7180(state->curr_norm);
-		if (ret < 0)
-			return ret;
-
-		ret =
-		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
-					      ret | state->input);
-		if (ret < 0)
-			return ret;
-
-	}
 	/* ITU-R BT.656-4 compatible */
 	/* ITU-R BT.656-4 compatible */
-	ret = i2c_smbus_write_byte_data(client,
-			ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
+	ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
 			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
 			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
 	/* Manually set V bit end position in NTSC mode */
 	/* Manually set V bit end position in NTSC mode */
-	ret = i2c_smbus_write_byte_data(client,
-					ADV7180_NTSC_V_BIT_END_REG,
+	return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END,
 					ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
 					ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
+}
+
+static int adv7180_set_std(struct adv7180_state *state, unsigned int std)
+{
+	return adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
+		(std << 4) | state->input);
+}
+
+static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
+{
+	int ret;
+
+	ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	/* read current norm */
-	__adv7180_status(client, NULL, &state->curr_norm);
+	ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
+	ret |= input;
+	return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret);
+}
 
 
-	/* register for interrupts */
-	if (state->irq > 0) {
-		ret = request_threaded_irq(state->irq, NULL, adv7180_irq,
-					   IRQF_ONESHOT, KBUILD_MODNAME, state);
-		if (ret)
-			return ret;
+static int adv7182_init(struct adv7180_state *state)
+{
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
+		adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR,
+			ADV7180_DEFAULT_CSI_I2C_ADDR << 1);
+
+	if (state->chip_info->flags & ADV7180_FLAG_I2P)
+		adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR,
+			ADV7180_DEFAULT_VPP_I2C_ADDR << 1);
+
+	if (state->chip_info->flags & ADV7180_FLAG_V2) {
+		/* ADI recommended writes for improved video quality */
+		adv7180_write(state, 0x0080, 0x51);
+		adv7180_write(state, 0x0081, 0x51);
+		adv7180_write(state, 0x0082, 0x68);
+	}
 
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
-						ADV7180_ADI_CTRL_IRQ_SPACE);
-		if (ret < 0)
-			goto err;
+	/* ADI required writes */
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+		adv7180_write(state, 0x0003, 0x4e);
+		adv7180_write(state, 0x0004, 0x57);
+		adv7180_write(state, 0x001d, 0xc0);
+	} else {
+		if (state->chip_info->flags & ADV7180_FLAG_V2)
+			adv7180_write(state, 0x0004, 0x17);
+		else
+			adv7180_write(state, 0x0004, 0x07);
+		adv7180_write(state, 0x0003, 0x0c);
+		adv7180_write(state, 0x001d, 0x40);
+	}
+
+	adv7180_write(state, 0x0013, 0x00);
+
+	return 0;
+}
+
+static int adv7182_set_std(struct adv7180_state *state, unsigned int std)
+{
+	return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4);
+}
+
+enum adv7182_input_type {
+	ADV7182_INPUT_TYPE_CVBS,
+	ADV7182_INPUT_TYPE_DIFF_CVBS,
+	ADV7182_INPUT_TYPE_SVIDEO,
+	ADV7182_INPUT_TYPE_YPBPR,
+};
+
+static enum adv7182_input_type adv7182_get_input_type(unsigned int input)
+{
+	switch (input) {
+	case ADV7182_INPUT_CVBS_AIN1:
+	case ADV7182_INPUT_CVBS_AIN2:
+	case ADV7182_INPUT_CVBS_AIN3:
+	case ADV7182_INPUT_CVBS_AIN4:
+	case ADV7182_INPUT_CVBS_AIN5:
+	case ADV7182_INPUT_CVBS_AIN6:
+	case ADV7182_INPUT_CVBS_AIN7:
+	case ADV7182_INPUT_CVBS_AIN8:
+		return ADV7182_INPUT_TYPE_CVBS;
+	case ADV7182_INPUT_SVIDEO_AIN1_AIN2:
+	case ADV7182_INPUT_SVIDEO_AIN3_AIN4:
+	case ADV7182_INPUT_SVIDEO_AIN5_AIN6:
+	case ADV7182_INPUT_SVIDEO_AIN7_AIN8:
+		return ADV7182_INPUT_TYPE_SVIDEO;
+	case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3:
+	case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6:
+		return ADV7182_INPUT_TYPE_YPBPR;
+	case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2:
+	case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4:
+	case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6:
+	case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8:
+		return ADV7182_INPUT_TYPE_DIFF_CVBS;
+	default: /* Will never happen */
+		return 0;
+	}
+}
+
+/* ADI recommended writes to registers 0x52, 0x53, 0x54 */
+static unsigned int adv7182_lbias_settings[][3] = {
+	[ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 },
+	[ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 },
+	[ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 },
+	[ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
+};
+
+static unsigned int adv7280_lbias_settings[][3] = {
+	[ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 },
+	[ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 },
+	[ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 },
+	[ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
+};
+
+static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
+{
+	enum adv7182_input_type input_type;
+	unsigned int *lbias;
+	unsigned int i;
+	int ret;
+
+	ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input);
+	if (ret)
+		return ret;
+
+	/* Reset clamp circuitry - ADI recommended writes */
+	adv7180_write(state, 0x809c, 0x00);
+	adv7180_write(state, 0x809c, 0xff);
+
+	input_type = adv7182_get_input_type(input);
+
+	switch (input_type) {
+	case ADV7182_INPUT_TYPE_CVBS:
+	case ADV7182_INPUT_TYPE_DIFF_CVBS:
+		/* ADI recommends to use the SH1 filter */
+		adv7180_write(state, 0x0017, 0x41);
+		break;
+	default:
+		adv7180_write(state, 0x0017, 0x01);
+		break;
+	}
+
+	if (state->chip_info->flags & ADV7180_FLAG_V2)
+		lbias = adv7280_lbias_settings[input_type];
+	else
+		lbias = adv7182_lbias_settings[input_type];
+
+	for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++)
+		adv7180_write(state, 0x0052 + i, lbias[i]);
+
+	if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) {
+		/* ADI required writes to make differential CVBS work */
+		adv7180_write(state, 0x005f, 0xa8);
+		adv7180_write(state, 0x005a, 0x90);
+		adv7180_write(state, 0x0060, 0xb0);
+		adv7180_write(state, 0x80b6, 0x08);
+		adv7180_write(state, 0x80c0, 0xa0);
+	} else {
+		adv7180_write(state, 0x005f, 0xf0);
+		adv7180_write(state, 0x005a, 0xd0);
+		adv7180_write(state, 0x0060, 0x10);
+		adv7180_write(state, 0x80b6, 0x9c);
+		adv7180_write(state, 0x80c0, 0x00);
+	}
+
+	return 0;
+}
+
+static const struct adv7180_chip_info adv7180_info = {
+	.flags = ADV7180_FLAG_RESET_POWERED,
+	/* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
+	 * all inputs and let the card driver take care of validation
+	 */
+	.valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) |
+		BIT(ADV7180_INPUT_CVBS_AIN2) |
+		BIT(ADV7180_INPUT_CVBS_AIN3) |
+		BIT(ADV7180_INPUT_CVBS_AIN4) |
+		BIT(ADV7180_INPUT_CVBS_AIN5) |
+		BIT(ADV7180_INPUT_CVBS_AIN6) |
+		BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) |
+		BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6),
+	.init = adv7180_init,
+	.set_std = adv7180_set_std,
+	.select_input = adv7180_select_input,
+};
+
+static const struct adv7180_chip_info adv7182_info = {
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7280_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7280_m_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_CVBS_AIN5) |
+		BIT(ADV7182_INPUT_CVBS_AIN6) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7281_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7281_m_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
 
 
+static const struct adv7180_chip_info adv7281_ma_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_CVBS_AIN5) |
+		BIT(ADV7182_INPUT_CVBS_AIN6) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7282_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7282_m_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static int init_device(struct adv7180_state *state)
+{
+	int ret;
+
+	mutex_lock(&state->mutex);
+
+	adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
+	usleep_range(2000, 10000);
+
+	ret = state->chip_info->init(state);
+	if (ret)
+		goto out_unlock;
+
+	ret = adv7180_program_std(state);
+	if (ret)
+		goto out_unlock;
+
+	adv7180_set_field_mode(state);
+
+	/* register for interrupts */
+	if (state->irq > 0) {
 		/* config the Interrupt pin to be active low */
 		/* config the Interrupt pin to be active low */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
+		ret = adv7180_write(state, ADV7180_REG_ICONF1,
 						ADV7180_ICONF1_ACTIVE_LOW |
 						ADV7180_ICONF1_ACTIVE_LOW |
 						ADV7180_ICONF1_PSYNC_ONLY);
 						ADV7180_ICONF1_PSYNC_ONLY);
 		if (ret < 0)
 		if (ret < 0)
-			goto err;
+			goto out_unlock;
 
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
+		ret = adv7180_write(state, ADV7180_REG_IMR1, 0);
 		if (ret < 0)
 		if (ret < 0)
-			goto err;
+			goto out_unlock;
 
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
+		ret = adv7180_write(state, ADV7180_REG_IMR2, 0);
 		if (ret < 0)
 		if (ret < 0)
-			goto err;
+			goto out_unlock;
 
 
 		/* enable AD change interrupts interrupts */
 		/* enable AD change interrupts interrupts */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
+		ret = adv7180_write(state, ADV7180_REG_IMR3,
 						ADV7180_IRQ3_AD_CHANGE);
 						ADV7180_IRQ3_AD_CHANGE);
 		if (ret < 0)
 		if (ret < 0)
-			goto err;
+			goto out_unlock;
 
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
+		ret = adv7180_write(state, ADV7180_REG_IMR4, 0);
 		if (ret < 0)
 		if (ret < 0)
-			goto err;
-
-		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
-						0);
-		if (ret < 0)
-			goto err;
+			goto out_unlock;
 	}
 	}
 
 
-	return 0;
+out_unlock:
+	mutex_unlock(&state->mutex);
 
 
-err:
-	free_irq(state->irq, state);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -616,26 +1172,63 @@ static int adv7180_probe(struct i2c_client *client,
 		 client->addr, client->adapter->name);
 		 client->addr, client->adapter->name);
 
 
 	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
 	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
-	if (state == NULL) {
-		ret = -ENOMEM;
-		goto err;
+	if (state == NULL)
+		return -ENOMEM;
+
+	state->client = client;
+	state->field = V4L2_FIELD_INTERLACED;
+	state->chip_info = (struct adv7180_chip_info *)id->driver_data;
+
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+		state->csi_client = i2c_new_dummy(client->adapter,
+				ADV7180_DEFAULT_CSI_I2C_ADDR);
+		if (!state->csi_client)
+			return -ENOMEM;
+	}
+
+	if (state->chip_info->flags & ADV7180_FLAG_I2P) {
+		state->vpp_client = i2c_new_dummy(client->adapter,
+				ADV7180_DEFAULT_VPP_I2C_ADDR);
+		if (!state->vpp_client) {
+			ret = -ENOMEM;
+			goto err_unregister_csi_client;
+		}
 	}
 	}
 
 
 	state->irq = client->irq;
 	state->irq = client->irq;
 	mutex_init(&state->mutex);
 	mutex_init(&state->mutex);
 	state->autodetect = true;
 	state->autodetect = true;
-	state->powered = true;
+	if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
+		state->powered = true;
+	else
+		state->powered = false;
 	state->input = 0;
 	state->input = 0;
 	sd = &state->sd;
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
 	v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 
 	ret = adv7180_init_controls(state);
 	ret = adv7180_init_controls(state);
 	if (ret)
 	if (ret)
-		goto err_unreg_subdev;
-	ret = init_device(client, state);
+		goto err_unregister_vpp_client;
+
+	state->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+	ret = media_entity_init(&sd->entity, 1, &state->pad, 0);
 	if (ret)
 	if (ret)
 		goto err_free_ctrl;
 		goto err_free_ctrl;
 
 
+	ret = init_device(state);
+	if (ret)
+		goto err_media_entity_cleanup;
+
+	if (state->irq) {
+		ret = request_threaded_irq(client->irq, NULL, adv7180_irq,
+					   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+					   KBUILD_MODNAME, state);
+		if (ret)
+			goto err_media_entity_cleanup;
+	}
+
 	ret = v4l2_async_register_subdev(sd);
 	ret = v4l2_async_register_subdev(sd);
 	if (ret)
 	if (ret)
 		goto err_free_irq;
 		goto err_free_irq;
@@ -645,11 +1238,17 @@ static int adv7180_probe(struct i2c_client *client,
 err_free_irq:
 err_free_irq:
 	if (state->irq > 0)
 	if (state->irq > 0)
 		free_irq(client->irq, state);
 		free_irq(client->irq, state);
+err_media_entity_cleanup:
+	media_entity_cleanup(&sd->entity);
 err_free_ctrl:
 err_free_ctrl:
 	adv7180_exit_controls(state);
 	adv7180_exit_controls(state);
-err_unreg_subdev:
+err_unregister_vpp_client:
+	if (state->chip_info->flags & ADV7180_FLAG_I2P)
+		i2c_unregister_device(state->vpp_client);
+err_unregister_csi_client:
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
+		i2c_unregister_device(state->csi_client);
 	mutex_destroy(&state->mutex);
 	mutex_destroy(&state->mutex);
-err:
 	return ret;
 	return ret;
 }
 }
 
 
@@ -663,15 +1262,32 @@ static int adv7180_remove(struct i2c_client *client)
 	if (state->irq > 0)
 	if (state->irq > 0)
 		free_irq(client->irq, state);
 		free_irq(client->irq, state);
 
 
+	media_entity_cleanup(&sd->entity);
 	adv7180_exit_controls(state);
 	adv7180_exit_controls(state);
+
+	if (state->chip_info->flags & ADV7180_FLAG_I2P)
+		i2c_unregister_device(state->vpp_client);
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
+		i2c_unregister_device(state->csi_client);
+
 	mutex_destroy(&state->mutex);
 	mutex_destroy(&state->mutex);
+
 	return 0;
 	return 0;
 }
 }
 
 
 static const struct i2c_device_id adv7180_id[] = {
 static const struct i2c_device_id adv7180_id[] = {
-	{KBUILD_MODNAME, 0},
+	{ "adv7180", (kernel_ulong_t)&adv7180_info },
+	{ "adv7182", (kernel_ulong_t)&adv7182_info },
+	{ "adv7280", (kernel_ulong_t)&adv7280_info },
+	{ "adv7280-m", (kernel_ulong_t)&adv7280_m_info },
+	{ "adv7281", (kernel_ulong_t)&adv7281_info },
+	{ "adv7281-m", (kernel_ulong_t)&adv7281_m_info },
+	{ "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info },
+	{ "adv7282", (kernel_ulong_t)&adv7282_info },
+	{ "adv7282-m", (kernel_ulong_t)&adv7282_m_info },
 	{},
 	{},
 };
 };
+MODULE_DEVICE_TABLE(i2c, adv7180_id);
 
 
 #ifdef CONFIG_PM_SLEEP
 #ifdef CONFIG_PM_SLEEP
 static int adv7180_suspend(struct device *dev)
 static int adv7180_suspend(struct device *dev)
@@ -680,7 +1296,7 @@ static int adv7180_suspend(struct device *dev)
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
 	struct adv7180_state *state = to_state(sd);
 	struct adv7180_state *state = to_state(sd);
 
 
-	return adv7180_set_power(state, client, false);
+	return adv7180_set_power(state, false);
 }
 }
 
 
 static int adv7180_resume(struct device *dev)
 static int adv7180_resume(struct device *dev)
@@ -690,14 +1306,14 @@ static int adv7180_resume(struct device *dev)
 	struct adv7180_state *state = to_state(sd);
 	struct adv7180_state *state = to_state(sd);
 	int ret;
 	int ret;
 
 
-	if (state->powered) {
-		ret = adv7180_set_power(state, client, true);
-		if (ret)
-			return ret;
-	}
-	ret = init_device(client, state);
+	ret = init_device(state);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
+
+	ret = adv7180_set_power(state, state->powered);
+	if (ret)
+		return ret;
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -708,8 +1324,6 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
 #define ADV7180_PM_OPS NULL
 #define ADV7180_PM_OPS NULL
 #endif
 #endif
 
 
-MODULE_DEVICE_TABLE(i2c, adv7180_id);
-
 static struct i2c_driver adv7180_driver = {
 static struct i2c_driver adv7180_driver = {
 	.driver = {
 	.driver = {
 		   .owner = THIS_MODULE,
 		   .owner = THIS_MODULE,

+ 0 - 76
drivers/media/i2c/adv7604.c

@@ -333,21 +333,11 @@ static inline struct adv7604_state *to_state(struct v4l2_subdev *sd)
 	return container_of(sd, struct adv7604_state, sd);
 	return container_of(sd, struct adv7604_state, sd);
 }
 }
 
 
-static inline unsigned hblanking(const struct v4l2_bt_timings *t)
-{
-	return V4L2_DV_BT_BLANKING_WIDTH(t);
-}
-
 static inline unsigned htotal(const struct v4l2_bt_timings *t)
 static inline unsigned htotal(const struct v4l2_bt_timings *t)
 {
 {
 	return V4L2_DV_BT_FRAME_WIDTH(t);
 	return V4L2_DV_BT_FRAME_WIDTH(t);
 }
 }
 
 
-static inline unsigned vblanking(const struct v4l2_bt_timings *t)
-{
-	return V4L2_DV_BT_BLANKING_HEIGHT(t);
-}
-
 static inline unsigned vtotal(const struct v4l2_bt_timings *t)
 static inline unsigned vtotal(const struct v4l2_bt_timings *t)
 {
 {
 	return V4L2_DV_BT_FRAME_HEIGHT(t);
 	return V4L2_DV_BT_FRAME_HEIGHT(t);
@@ -466,11 +456,6 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 	return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val);
 	return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val);
 }
 }
 
 
-static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
-{
-	return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val);
-}
-
 static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg)
 static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg)
 {
 {
 	struct adv7604_state *state = to_state(sd);
 	struct adv7604_state *state = to_state(sd);
@@ -486,34 +471,6 @@ static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 					 reg, val);
 					 reg, val);
 }
 }
 
 
-static inline int esdp_read(struct v4l2_subdev *sd, u8 reg)
-{
-	struct adv7604_state *state = to_state(sd);
-
-	return adv_smbus_read_byte_data(state, ADV7604_PAGE_ESDP, reg);
-}
-
-static inline int esdp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
-{
-	struct adv7604_state *state = to_state(sd);
-
-	return adv_smbus_write_byte_data(state, ADV7604_PAGE_ESDP, reg, val);
-}
-
-static inline int dpp_read(struct v4l2_subdev *sd, u8 reg)
-{
-	struct adv7604_state *state = to_state(sd);
-
-	return adv_smbus_read_byte_data(state, ADV7604_PAGE_DPP, reg);
-}
-
-static inline int dpp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
-{
-	struct adv7604_state *state = to_state(sd);
-
-	return adv_smbus_write_byte_data(state, ADV7604_PAGE_DPP, reg, val);
-}
-
 static inline int afe_read(struct v4l2_subdev *sd, u8 reg)
 static inline int afe_read(struct v4l2_subdev *sd, u8 reg)
 {
 {
 	struct adv7604_state *state = to_state(sd);
 	struct adv7604_state *state = to_state(sd);
@@ -561,32 +518,6 @@ static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 	return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val);
 	return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val);
 }
 }
 
 
-static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val)
-{
-	struct adv7604_state *state = to_state(sd);
-	struct i2c_client *client = state->i2c_clients[ADV7604_PAGE_EDID];
-	u8 msgbuf0[1] = { 0 };
-	u8 msgbuf1[256];
-	struct i2c_msg msg[2] = {
-		{
-			.addr = client->addr,
-			.len = 1,
-			.buf = msgbuf0
-		},
-		{
-			.addr = client->addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = msgbuf1
-		},
-	};
-
-	if (i2c_transfer(client->adapter, msg, 2) < 0)
-		return -EIO;
-	memcpy(val, msgbuf1, len);
-	return 0;
-}
-
 static inline int edid_write_block(struct v4l2_subdev *sd,
 static inline int edid_write_block(struct v4l2_subdev *sd,
 					unsigned len, const u8 *val)
 					unsigned len, const u8 *val)
 {
 {
@@ -652,13 +583,6 @@ static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8
 	return hdmi_write(sd, reg, (hdmi_read(sd, reg) & ~mask) | val);
 	return hdmi_write(sd, reg, (hdmi_read(sd, reg) & ~mask) | val);
 }
 }
 
 
-static inline int test_read(struct v4l2_subdev *sd, u8 reg)
-{
-	struct adv7604_state *state = to_state(sd);
-
-	return adv_smbus_read_byte_data(state, ADV7604_PAGE_TEST, reg);
-}
-
 static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 {
 	struct adv7604_state *state = to_state(sd);
 	struct adv7604_state *state = to_state(sd);

+ 46 - 138
drivers/media/i2c/adv7842.c

@@ -38,6 +38,7 @@
 #include <linux/videodev2.h>
 #include <linux/videodev2.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/v4l2-dv-timings.h>
 #include <linux/v4l2-dv-timings.h>
+#include <linux/hdmi.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-dv-timings.h>
 #include <media/v4l2-dv-timings.h>
@@ -220,21 +221,11 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
 	return &container_of(ctrl->handler, struct adv7842_state, hdl)->sd;
 	return &container_of(ctrl->handler, struct adv7842_state, hdl)->sd;
 }
 }
 
 
-static inline unsigned hblanking(const struct v4l2_bt_timings *t)
-{
-	return V4L2_DV_BT_BLANKING_WIDTH(t);
-}
-
 static inline unsigned htotal(const struct v4l2_bt_timings *t)
 static inline unsigned htotal(const struct v4l2_bt_timings *t)
 {
 {
 	return V4L2_DV_BT_FRAME_WIDTH(t);
 	return V4L2_DV_BT_FRAME_WIDTH(t);
 }
 }
 
 
-static inline unsigned vblanking(const struct v4l2_bt_timings *t)
-{
-	return V4L2_DV_BT_BLANKING_HEIGHT(t);
-}
-
 static inline unsigned vtotal(const struct v4l2_bt_timings *t)
 static inline unsigned vtotal(const struct v4l2_bt_timings *t)
 {
 {
 	return V4L2_DV_BT_FRAME_HEIGHT(t);
 	return V4L2_DV_BT_FRAME_HEIGHT(t);
@@ -2108,149 +2099,65 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
 	return err;
 	return err;
 }
 }
 
 
-/*********** avi info frame CEA-861-E **************/
-/* TODO move to common library */
-
-struct avi_info_frame {
-	uint8_t f17;
-	uint8_t y10;
-	uint8_t a0;
-	uint8_t b10;
-	uint8_t s10;
-	uint8_t c10;
-	uint8_t m10;
-	uint8_t r3210;
-	uint8_t itc;
-	uint8_t ec210;
-	uint8_t q10;
-	uint8_t sc10;
-	uint8_t f47;
-	uint8_t vic;
-	uint8_t yq10;
-	uint8_t cn10;
-	uint8_t pr3210;
-	uint16_t etb;
-	uint16_t sbb;
-	uint16_t elb;
-	uint16_t srb;
-};
-
-static const char *y10_txt[4] = {
-	"RGB",
-	"YCbCr 4:2:2",
-	"YCbCr 4:4:4",
-	"Future",
-};
-
-static const char *c10_txt[4] = {
-	"No Data",
-	"SMPTE 170M",
-	"ITU-R 709",
-	"Extended Colorimetry information valied",
-};
-
-static const char *itc_txt[2] = {
-	"No Data",
-	"IT content",
-};
-
-static const char *ec210_txt[8] = {
-	"xvYCC601",
-	"xvYCC709",
-	"sYCC601",
-	"AdobeYCC601",
-	"AdobeRGB",
-	"5 reserved",
-	"6 reserved",
-	"7 reserved",
+struct adv7842_cfg_read_infoframe {
+	const char *desc;
+	u8 present_mask;
+	u8 head_addr;
+	u8 payload_addr;
 };
 };
 
 
-static const char *q10_txt[4] = {
-	"Default",
-	"Limited Range",
-	"Full Range",
-	"Reserved",
-};
-
-static void parse_avi_infoframe(struct v4l2_subdev *sd, uint8_t *buf,
-				struct avi_info_frame *avi)
-{
-	avi->f17 = (buf[1] >> 7) & 0x1;
-	avi->y10 = (buf[1] >> 5) & 0x3;
-	avi->a0 = (buf[1] >> 4) & 0x1;
-	avi->b10 = (buf[1] >> 2) & 0x3;
-	avi->s10 = buf[1] & 0x3;
-	avi->c10 = (buf[2] >> 6) & 0x3;
-	avi->m10 = (buf[2] >> 4) & 0x3;
-	avi->r3210 = buf[2] & 0xf;
-	avi->itc = (buf[3] >> 7) & 0x1;
-	avi->ec210 = (buf[3] >> 4) & 0x7;
-	avi->q10 = (buf[3] >> 2) & 0x3;
-	avi->sc10 = buf[3] & 0x3;
-	avi->f47 = (buf[4] >> 7) & 0x1;
-	avi->vic = buf[4] & 0x7f;
-	avi->yq10 = (buf[5] >> 6) & 0x3;
-	avi->cn10 = (buf[5] >> 4) & 0x3;
-	avi->pr3210 = buf[5] & 0xf;
-	avi->etb = buf[6] + 256*buf[7];
-	avi->sbb = buf[8] + 256*buf[9];
-	avi->elb = buf[10] + 256*buf[11];
-	avi->srb = buf[12] + 256*buf[13];
-}
-
-static void print_avi_infoframe(struct v4l2_subdev *sd)
+static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infoframe *cri)
 {
 {
 	int i;
 	int i;
-	uint8_t buf[14];
-	u8 avi_len;
-	u8 avi_ver;
-	struct avi_info_frame avi;
+	uint8_t buffer[32];
+	union hdmi_infoframe frame;
+	u8 len;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct device *dev = &client->dev;
 
 
-	if (!(hdmi_read(sd, 0x05) & 0x80)) {
-		v4l2_info(sd, "receive DVI-D signal (AVI infoframe not supported)\n");
-		return;
-	}
-	if (!(io_read(sd, 0x60) & 0x01)) {
-		v4l2_info(sd, "AVI infoframe not received\n");
+	if (!(io_read(sd, 0x60) & cri->present_mask)) {
+		v4l2_info(sd, "%s infoframe not received\n", cri->desc);
 		return;
 		return;
 	}
 	}
 
 
-	if (io_read(sd, 0x88) & 0x10) {
-		v4l2_info(sd, "AVI infoframe checksum error has occurred earlier\n");
-		io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */
-		if (io_read(sd, 0x88) & 0x10) {
-			v4l2_info(sd, "AVI infoframe checksum error still present\n");
-			io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */
-		}
-	}
+	for (i = 0; i < 3; i++)
+		buffer[i] = infoframe_read(sd, cri->head_addr + i);
 
 
-	avi_len = infoframe_read(sd, 0xe2);
-	avi_ver = infoframe_read(sd, 0xe1);
-	v4l2_info(sd, "AVI infoframe version %d (%d byte)\n",
-		  avi_ver, avi_len);
+	len = buffer[2] + 1;
 
 
-	if (avi_ver != 0x02)
+	if (len + 3 > sizeof(buffer)) {
+		v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len);
 		return;
 		return;
+	}
+
+	for (i = 0; i < len; i++)
+		buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
 
 
-	for (i = 0; i < 14; i++)
-		buf[i] = infoframe_read(sd, i);
+	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
+		return;
+	}
 
 
-	v4l2_info(sd, "\t%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-		  buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
-		  buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]);
+	hdmi_infoframe_log(KERN_INFO, dev, &frame);
+}
 
 
-	parse_avi_infoframe(sd, buf, &avi);
+static void adv7842_log_infoframes(struct v4l2_subdev *sd)
+{
+	int i;
+	struct adv7842_cfg_read_infoframe cri[] = {
+		{ "AVI", 0x01, 0xe0, 0x00 },
+		{ "Audio", 0x02, 0xe3, 0x1c },
+		{ "SDP", 0x04, 0xe6, 0x2a },
+		{ "Vendor", 0x10, 0xec, 0x54 }
+	};
 
 
-	if (avi.vic)
-		v4l2_info(sd, "\tVIC: %d\n", avi.vic);
-	if (avi.itc)
-		v4l2_info(sd, "\t%s\n", itc_txt[avi.itc]);
+	if (!(hdmi_read(sd, 0x05) & 0x80)) {
+		v4l2_info(sd, "receive DVI-D signal, no infoframes\n");
+		return;
+	}
 
 
-	if (avi.y10)
-		v4l2_info(sd, "\t%s %s\n", y10_txt[avi.y10], !avi.c10 ? "" :
-			(avi.c10 == 0x3 ? ec210_txt[avi.ec210] : c10_txt[avi.c10]));
-	else
-		v4l2_info(sd, "\t%s %s\n", y10_txt[avi.y10], q10_txt[avi.q10]);
+	for (i = 0; i < ARRAY_SIZE(cri); i++)
+		log_infoframe(sd, &cri[i]);
 }
 }
 
 
 static const char * const prim_mode_txt[] = {
 static const char * const prim_mode_txt[] = {
@@ -2464,7 +2371,8 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd)
 	v4l2_info(sd, "Deep color mode: %s\n",
 	v4l2_info(sd, "Deep color mode: %s\n",
 			deep_color_mode_txt[hdmi_read(sd, 0x0b) >> 6]);
 			deep_color_mode_txt[hdmi_read(sd, 0x0b) >> 6]);
 
 
-	print_avi_infoframe(sd);
+	adv7842_log_infoframes(sd);
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 2 - 7
drivers/media/i2c/m5mols/m5mols_core.c

@@ -125,9 +125,9 @@ static u32 m5mols_swap_byte(u8 *data, u8 length)
 	if (length == 1)
 	if (length == 1)
 		return *data;
 		return *data;
 	else if (length == 2)
 	else if (length == 2)
-		return be16_to_cpu(*((u16 *)data));
+		return be16_to_cpu(*((__be16 *)data));
 	else
 	else
-		return be32_to_cpu(*((u32 *)data));
+		return be32_to_cpu(*((__be32 *)data));
 }
 }
 
 
 /**
 /**
@@ -454,11 +454,6 @@ static int m5mols_get_version(struct v4l2_subdev *sd)
 			return ret;
 			return ret;
 	}
 	}
 
 
-	ver->fw = be16_to_cpu(ver->fw);
-	ver->hw = be16_to_cpu(ver->hw);
-	ver->param = be16_to_cpu(ver->param);
-	ver->awb = be16_to_cpu(ver->awb);
-
 	v4l2_info(sd, "Manufacturer\t[%s]\n",
 	v4l2_info(sd, "Manufacturer\t[%s]\n",
 			is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
 			is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
 			"Samsung Electro-Machanics" :
 			"Samsung Electro-Machanics" :

+ 0 - 8
drivers/media/i2c/msp3400-driver.c

@@ -904,11 +904,3 @@ static struct i2c_driver msp_driver = {
 };
 };
 
 
 module_i2c_driver(msp_driver);
 module_i2c_driver(msp_driver);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 24 - 18
drivers/media/i2c/mt9m032.c

@@ -422,22 +422,25 @@ done:
 	return ret;
 	return ret;
 }
 }
 
 
-static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev,
-				struct v4l2_subdev_fh *fh,
-				struct v4l2_subdev_crop *crop)
+static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_fh *fh,
+				     struct v4l2_subdev_selection *sel)
 {
 {
 	struct mt9m032 *sensor = to_mt9m032(subdev);
 	struct mt9m032 *sensor = to_mt9m032(subdev);
 
 
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
 	mutex_lock(&sensor->lock);
 	mutex_lock(&sensor->lock);
-	crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which);
+	sel->r = *__mt9m032_get_pad_crop(sensor, fh, sel->which);
 	mutex_unlock(&sensor->lock);
 	mutex_unlock(&sensor->lock);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
-				struct v4l2_subdev_fh *fh,
-				struct v4l2_subdev_crop *crop)
+static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_fh *fh,
+				     struct v4l2_subdev_selection *sel)
 {
 {
 	struct mt9m032 *sensor = to_mt9m032(subdev);
 	struct mt9m032 *sensor = to_mt9m032(subdev);
 	struct v4l2_mbus_framefmt *format;
 	struct v4l2_mbus_framefmt *format;
@@ -445,9 +448,12 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
 	struct v4l2_rect rect;
 	struct v4l2_rect rect;
 	int ret = 0;
 	int ret = 0;
 
 
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
 	mutex_lock(&sensor->lock);
 	mutex_lock(&sensor->lock);
 
 
-	if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+	if (sensor->streaming && sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
 		ret = -EBUSY;
 		ret = -EBUSY;
 		goto done;
 		goto done;
 	}
 	}
@@ -455,13 +461,13 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
 	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
 	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
 	 * pixels to ensure a GRBG Bayer pattern.
 	 * pixels to ensure a GRBG Bayer pattern.
 	 */
 	 */
-	rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN,
+	rect.left = clamp(ALIGN(sel->r.left, 2), MT9M032_COLUMN_START_MIN,
 			  MT9M032_COLUMN_START_MAX);
 			  MT9M032_COLUMN_START_MAX);
-	rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN,
+	rect.top = clamp(ALIGN(sel->r.top, 2), MT9M032_ROW_START_MIN,
 			 MT9M032_ROW_START_MAX);
 			 MT9M032_ROW_START_MAX);
-	rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+	rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
 			     MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX);
 			     MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX);
-	rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+	rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
 			      MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX);
 			      MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX);
 
 
 	rect.width = min_t(unsigned int, rect.width,
 	rect.width = min_t(unsigned int, rect.width,
@@ -469,21 +475,21 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
 	rect.height = min_t(unsigned int, rect.height,
 	rect.height = min_t(unsigned int, rect.height,
 			    MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
 			    MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
 
 
-	__crop = __mt9m032_get_pad_crop(sensor, fh, crop->which);
+	__crop = __mt9m032_get_pad_crop(sensor, fh, sel->which);
 
 
 	if (rect.width != __crop->width || rect.height != __crop->height) {
 	if (rect.width != __crop->width || rect.height != __crop->height) {
 		/* Reset the output image size if the crop rectangle size has
 		/* Reset the output image size if the crop rectangle size has
 		 * been modified.
 		 * been modified.
 		 */
 		 */
-		format = __mt9m032_get_pad_format(sensor, fh, crop->which);
+		format = __mt9m032_get_pad_format(sensor, fh, sel->which);
 		format->width = rect.width;
 		format->width = rect.width;
 		format->height = rect.height;
 		format->height = rect.height;
 	}
 	}
 
 
 	*__crop = rect;
 	*__crop = rect;
-	crop->rect = rect;
+	sel->r = rect;
 
 
-	if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 		ret = mt9m032_update_geom_timing(sensor);
 		ret = mt9m032_update_geom_timing(sensor);
 
 
 done:
 done:
@@ -690,8 +696,8 @@ static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = {
 	.enum_frame_size = mt9m032_enum_frame_size,
 	.enum_frame_size = mt9m032_enum_frame_size,
 	.get_fmt = mt9m032_get_pad_format,
 	.get_fmt = mt9m032_get_pad_format,
 	.set_fmt = mt9m032_set_pad_format,
 	.set_fmt = mt9m032_set_pad_format,
-	.set_crop = mt9m032_set_pad_crop,
-	.get_crop = mt9m032_get_pad_crop,
+	.set_selection = mt9m032_set_pad_selection,
+	.get_selection = mt9m032_get_pad_selection,
 };
 };
 
 
 static const struct v4l2_subdev_ops mt9m032_ops = {
 static const struct v4l2_subdev_ops mt9m032_ops = {

+ 23 - 18
drivers/media/i2c/mt9p031.c

@@ -581,37 +581,42 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
 	return 0;
 	return 0;
 }
 }
 
 
-static int mt9p031_get_crop(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_fh *fh,
-			    struct v4l2_subdev_crop *crop)
+static int mt9p031_get_selection(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
 {
 {
 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
 
 
-	crop->rect = *__mt9p031_get_pad_crop(mt9p031, fh, crop->pad,
-					     crop->which);
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
+	sel->r = *__mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which);
 	return 0;
 	return 0;
 }
 }
 
 
-static int mt9p031_set_crop(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_fh *fh,
-			    struct v4l2_subdev_crop *crop)
+static int mt9p031_set_selection(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
 {
 {
 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
 	struct v4l2_mbus_framefmt *__format;
 	struct v4l2_mbus_framefmt *__format;
 	struct v4l2_rect *__crop;
 	struct v4l2_rect *__crop;
 	struct v4l2_rect rect;
 	struct v4l2_rect rect;
 
 
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
 	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
 	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
 	 * pixels to ensure a GRBG Bayer pattern.
 	 * pixels to ensure a GRBG Bayer pattern.
 	 */
 	 */
-	rect.left = clamp(ALIGN(crop->rect.left, 2), MT9P031_COLUMN_START_MIN,
+	rect.left = clamp(ALIGN(sel->r.left, 2), MT9P031_COLUMN_START_MIN,
 			  MT9P031_COLUMN_START_MAX);
 			  MT9P031_COLUMN_START_MAX);
-	rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN,
+	rect.top = clamp(ALIGN(sel->r.top, 2), MT9P031_ROW_START_MIN,
 			 MT9P031_ROW_START_MAX);
 			 MT9P031_ROW_START_MAX);
-	rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+	rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
 			     MT9P031_WINDOW_WIDTH_MIN,
 			     MT9P031_WINDOW_WIDTH_MIN,
 			     MT9P031_WINDOW_WIDTH_MAX);
 			     MT9P031_WINDOW_WIDTH_MAX);
-	rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+	rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
 			      MT9P031_WINDOW_HEIGHT_MIN,
 			      MT9P031_WINDOW_HEIGHT_MIN,
 			      MT9P031_WINDOW_HEIGHT_MAX);
 			      MT9P031_WINDOW_HEIGHT_MAX);
 
 
@@ -620,20 +625,20 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev,
 	rect.height = min_t(unsigned int, rect.height,
 	rect.height = min_t(unsigned int, rect.height,
 			    MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
 			    MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
 
 
-	__crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which);
+	__crop = __mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which);
 
 
 	if (rect.width != __crop->width || rect.height != __crop->height) {
 	if (rect.width != __crop->width || rect.height != __crop->height) {
 		/* Reset the output image size if the crop rectangle size has
 		/* Reset the output image size if the crop rectangle size has
 		 * been modified.
 		 * been modified.
 		 */
 		 */
-		__format = __mt9p031_get_pad_format(mt9p031, fh, crop->pad,
-						    crop->which);
+		__format = __mt9p031_get_pad_format(mt9p031, fh, sel->pad,
+						    sel->which);
 		__format->width = rect.width;
 		__format->width = rect.width;
 		__format->height = rect.height;
 		__format->height = rect.height;
 	}
 	}
 
 
 	*__crop = rect;
 	*__crop = rect;
-	crop->rect = rect;
+	sel->r = rect;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -980,8 +985,8 @@ static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
 	.enum_frame_size = mt9p031_enum_frame_size,
 	.enum_frame_size = mt9p031_enum_frame_size,
 	.get_fmt = mt9p031_get_format,
 	.get_fmt = mt9p031_get_format,
 	.set_fmt = mt9p031_set_format,
 	.set_fmt = mt9p031_set_format,
-	.get_crop = mt9p031_get_crop,
-	.set_crop = mt9p031_set_crop,
+	.get_selection = mt9p031_get_selection,
+	.set_selection = mt9p031_set_selection,
 };
 };
 
 
 static struct v4l2_subdev_ops mt9p031_subdev_ops = {
 static struct v4l2_subdev_ops mt9p031_subdev_ops = {

+ 23 - 18
drivers/media/i2c/mt9t001.c

@@ -401,39 +401,44 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
 	return 0;
 	return 0;
 }
 }
 
 
-static int mt9t001_get_crop(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_fh *fh,
-			    struct v4l2_subdev_crop *crop)
+static int mt9t001_get_selection(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
 {
 {
 	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
 	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
 
 
-	crop->rect = *__mt9t001_get_pad_crop(mt9t001, fh, crop->pad,
-					     crop->which);
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
+	sel->r = *__mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which);
 	return 0;
 	return 0;
 }
 }
 
 
-static int mt9t001_set_crop(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_fh *fh,
-			    struct v4l2_subdev_crop *crop)
+static int mt9t001_set_selection(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
 {
 {
 	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
 	struct mt9t001 *mt9t001 = to_mt9t001(subdev);
 	struct v4l2_mbus_framefmt *__format;
 	struct v4l2_mbus_framefmt *__format;
 	struct v4l2_rect *__crop;
 	struct v4l2_rect *__crop;
 	struct v4l2_rect rect;
 	struct v4l2_rect rect;
 
 
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
 	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
 	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
 	 * pixels.
 	 * pixels.
 	 */
 	 */
-	rect.left = clamp(ALIGN(crop->rect.left, 2),
+	rect.left = clamp(ALIGN(sel->r.left, 2),
 			  MT9T001_COLUMN_START_MIN,
 			  MT9T001_COLUMN_START_MIN,
 			  MT9T001_COLUMN_START_MAX);
 			  MT9T001_COLUMN_START_MAX);
-	rect.top = clamp(ALIGN(crop->rect.top, 2),
+	rect.top = clamp(ALIGN(sel->r.top, 2),
 			 MT9T001_ROW_START_MIN,
 			 MT9T001_ROW_START_MIN,
 			 MT9T001_ROW_START_MAX);
 			 MT9T001_ROW_START_MAX);
-	rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+	rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
 			     MT9T001_WINDOW_WIDTH_MIN + 1,
 			     MT9T001_WINDOW_WIDTH_MIN + 1,
 			     MT9T001_WINDOW_WIDTH_MAX + 1);
 			     MT9T001_WINDOW_WIDTH_MAX + 1);
-	rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+	rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
 			      MT9T001_WINDOW_HEIGHT_MIN + 1,
 			      MT9T001_WINDOW_HEIGHT_MIN + 1,
 			      MT9T001_WINDOW_HEIGHT_MAX + 1);
 			      MT9T001_WINDOW_HEIGHT_MAX + 1);
 
 
@@ -442,20 +447,20 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev,
 	rect.height = min_t(unsigned int, rect.height,
 	rect.height = min_t(unsigned int, rect.height,
 			    MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
 			    MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
 
 
-	__crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which);
+	__crop = __mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which);
 
 
 	if (rect.width != __crop->width || rect.height != __crop->height) {
 	if (rect.width != __crop->width || rect.height != __crop->height) {
 		/* Reset the output image size if the crop rectangle size has
 		/* Reset the output image size if the crop rectangle size has
 		 * been modified.
 		 * been modified.
 		 */
 		 */
-		__format = __mt9t001_get_pad_format(mt9t001, fh, crop->pad,
-						    crop->which);
+		__format = __mt9t001_get_pad_format(mt9t001, fh, sel->pad,
+						    sel->which);
 		__format->width = rect.width;
 		__format->width = rect.width;
 		__format->height = rect.height;
 		__format->height = rect.height;
 	}
 	}
 
 
 	*__crop = rect;
 	*__crop = rect;
-	crop->rect = rect;
+	sel->r = rect;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -819,8 +824,8 @@ static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = {
 	.enum_frame_size = mt9t001_enum_frame_size,
 	.enum_frame_size = mt9t001_enum_frame_size,
 	.get_fmt = mt9t001_get_format,
 	.get_fmt = mt9t001_get_format,
 	.set_fmt = mt9t001_set_format,
 	.set_fmt = mt9t001_set_format,
-	.get_crop = mt9t001_get_crop,
-	.set_crop = mt9t001_set_crop,
+	.get_selection = mt9t001_get_selection,
+	.set_selection = mt9t001_set_selection,
 };
 };
 
 
 static struct v4l2_subdev_ops mt9t001_subdev_ops = {
 static struct v4l2_subdev_ops mt9t001_subdev_ops = {

+ 24 - 19
drivers/media/i2c/mt9v032.c

@@ -552,39 +552,44 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
 	return 0;
 	return 0;
 }
 }
 
 
-static int mt9v032_get_crop(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_fh *fh,
-			    struct v4l2_subdev_crop *crop)
+static int mt9v032_get_selection(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
 {
 {
 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
 
 
-	crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad,
-					     crop->which);
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
+	sel->r = *__mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which);
 	return 0;
 	return 0;
 }
 }
 
 
-static int mt9v032_set_crop(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_fh *fh,
-			    struct v4l2_subdev_crop *crop)
+static int mt9v032_set_selection(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_selection *sel)
 {
 {
 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
 	struct v4l2_mbus_framefmt *__format;
 	struct v4l2_mbus_framefmt *__format;
 	struct v4l2_rect *__crop;
 	struct v4l2_rect *__crop;
 	struct v4l2_rect rect;
 	struct v4l2_rect rect;
 
 
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
 	/* Clamp the crop rectangle boundaries and align them to a non multiple
 	/* Clamp the crop rectangle boundaries and align them to a non multiple
 	 * of 2 pixels to ensure a GRBG Bayer pattern.
 	 * of 2 pixels to ensure a GRBG Bayer pattern.
 	 */
 	 */
-	rect.left = clamp(ALIGN(crop->rect.left + 1, 2) - 1,
+	rect.left = clamp(ALIGN(sel->r.left + 1, 2) - 1,
 			  MT9V032_COLUMN_START_MIN,
 			  MT9V032_COLUMN_START_MIN,
 			  MT9V032_COLUMN_START_MAX);
 			  MT9V032_COLUMN_START_MAX);
-	rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1,
+	rect.top = clamp(ALIGN(sel->r.top + 1, 2) - 1,
 			 MT9V032_ROW_START_MIN,
 			 MT9V032_ROW_START_MIN,
 			 MT9V032_ROW_START_MAX);
 			 MT9V032_ROW_START_MAX);
-	rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+	rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
 			     MT9V032_WINDOW_WIDTH_MIN,
 			     MT9V032_WINDOW_WIDTH_MIN,
 			     MT9V032_WINDOW_WIDTH_MAX);
 			     MT9V032_WINDOW_WIDTH_MAX);
-	rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+	rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
 			      MT9V032_WINDOW_HEIGHT_MIN,
 			      MT9V032_WINDOW_HEIGHT_MIN,
 			      MT9V032_WINDOW_HEIGHT_MAX);
 			      MT9V032_WINDOW_HEIGHT_MAX);
 
 
@@ -593,17 +598,17 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
 	rect.height = min_t(unsigned int,
 	rect.height = min_t(unsigned int,
 			    rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
 			    rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
 
 
-	__crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
+	__crop = __mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which);
 
 
 	if (rect.width != __crop->width || rect.height != __crop->height) {
 	if (rect.width != __crop->width || rect.height != __crop->height) {
 		/* Reset the output image size if the crop rectangle size has
 		/* Reset the output image size if the crop rectangle size has
 		 * been modified.
 		 * been modified.
 		 */
 		 */
-		__format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad,
-						    crop->which);
+		__format = __mt9v032_get_pad_format(mt9v032, fh, sel->pad,
+						    sel->which);
 		__format->width = rect.width;
 		__format->width = rect.width;
 		__format->height = rect.height;
 		__format->height = rect.height;
-		if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
 			mt9v032->hratio = 1;
 			mt9v032->hratio = 1;
 			mt9v032->vratio = 1;
 			mt9v032->vratio = 1;
 			mt9v032_configure_pixel_rate(mt9v032);
 			mt9v032_configure_pixel_rate(mt9v032);
@@ -611,7 +616,7 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
 	}
 	}
 
 
 	*__crop = rect;
 	*__crop = rect;
-	crop->rect = rect;
+	sel->r = rect;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -844,8 +849,8 @@ static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
 	.enum_frame_size = mt9v032_enum_frame_size,
 	.enum_frame_size = mt9v032_enum_frame_size,
 	.get_fmt = mt9v032_get_format,
 	.get_fmt = mt9v032_get_format,
 	.set_fmt = mt9v032_set_format,
 	.set_fmt = mt9v032_set_format,
-	.get_crop = mt9v032_get_crop,
-	.set_crop = mt9v032_set_crop,
+	.get_selection = mt9v032_get_selection,
+	.set_selection = mt9v032_set_selection,
 };
 };
 
 
 static struct v4l2_subdev_ops mt9v032_subdev_ops = {
 static struct v4l2_subdev_ops mt9v032_subdev_ops = {

+ 5 - 6
drivers/media/i2c/s5k4ecgx.c

@@ -220,7 +220,7 @@ static int s5k4ecgx_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
 	msg[1].buf = rbuf;
 	msg[1].buf = rbuf;
 
 
 	ret = i2c_transfer(client->adapter, msg, 2);
 	ret = i2c_transfer(client->adapter, msg, 2);
-	*val = be16_to_cpu(*((u16 *)rbuf));
+	*val = be16_to_cpu(*((__be16 *)rbuf));
 
 
 	v4l2_dbg(4, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
 	v4l2_dbg(4, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
 
 
@@ -341,7 +341,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd)
 		v4l2_err(sd, "Failed to read firmware %s\n", S5K4ECGX_FIRMWARE);
 		v4l2_err(sd, "Failed to read firmware %s\n", S5K4ECGX_FIRMWARE);
 		return err;
 		return err;
 	}
 	}
-	regs_num = le32_to_cpu(get_unaligned_le32(fw->data));
+	regs_num = get_unaligned_le32(fw->data);
 
 
 	v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n",
 	v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n",
 		 S5K4ECGX_FIRMWARE, fw->size, regs_num);
 		 S5K4ECGX_FIRMWARE, fw->size, regs_num);
@@ -351,8 +351,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd)
 		err = -EINVAL;
 		err = -EINVAL;
 		goto fw_out;
 		goto fw_out;
 	}
 	}
-	crc_file = le32_to_cpu(get_unaligned_le32(fw->data +
-						  regs_num * FW_RECORD_SIZE));
+	crc_file = get_unaligned_le32(fw->data + regs_num * FW_RECORD_SIZE);
 	crc = crc32_le(~0, fw->data, regs_num * FW_RECORD_SIZE);
 	crc = crc32_le(~0, fw->data, regs_num * FW_RECORD_SIZE);
 	if (crc != crc_file) {
 	if (crc != crc_file) {
 		v4l2_err(sd, "FW: invalid crc (%#x:%#x)\n", crc, crc_file);
 		v4l2_err(sd, "FW: invalid crc (%#x:%#x)\n", crc, crc_file);
@@ -361,9 +360,9 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd)
 	}
 	}
 	ptr = fw->data + FW_RECORD_SIZE;
 	ptr = fw->data + FW_RECORD_SIZE;
 	for (i = 1; i < regs_num; i++) {
 	for (i = 1; i < regs_num; i++) {
-		addr = le32_to_cpu(get_unaligned_le32(ptr));
+		addr = get_unaligned_le32(ptr);
 		ptr += sizeof(u32);
 		ptr += sizeof(u32);
-		val = le16_to_cpu(get_unaligned_le16(ptr));
+		val = get_unaligned_le16(ptr);
 		ptr += sizeof(u16);
 		ptr += sizeof(u16);
 		if (addr - addr_inc != 2)
 		if (addr - addr_inc != 2)
 			err = s5k4ecgx_write(client, addr, val);
 			err = s5k4ecgx_write(client, addr, val);

+ 7 - 6
drivers/media/i2c/s5k5baf.c

@@ -353,7 +353,7 @@ static struct v4l2_rect s5k5baf_cis_rect = {
  *
  *
  */
  */
 static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw,
 static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw,
-			    size_t count, const u16 *data)
+			    size_t count, const __le16 *data)
 {
 {
 	struct s5k5baf_fw *f;
 	struct s5k5baf_fw *f;
 	u16 *d, i, *end;
 	u16 *d, i, *end;
@@ -421,6 +421,7 @@ static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr)
 {
 {
 	struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
 	struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
 	__be16 w, r;
 	__be16 w, r;
+	u16 res;
 	struct i2c_msg msg[] = {
 	struct i2c_msg msg[] = {
 		{ .addr = c->addr, .flags = 0,
 		{ .addr = c->addr, .flags = 0,
 		  .len = 2, .buf = (u8 *)&w },
 		  .len = 2, .buf = (u8 *)&w },
@@ -434,15 +435,15 @@ static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr)
 
 
 	w = cpu_to_be16(addr);
 	w = cpu_to_be16(addr);
 	ret = i2c_transfer(c->adapter, msg, 2);
 	ret = i2c_transfer(c->adapter, msg, 2);
-	r = be16_to_cpu(r);
+	res = be16_to_cpu(r);
 
 
-	v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, r);
+	v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, res);
 
 
 	if (ret != 2) {
 	if (ret != 2) {
 		v4l2_err(c, "i2c_read: error during transfer (%d)\n", ret);
 		v4l2_err(c, "i2c_read: error during transfer (%d)\n", ret);
 		state->error = ret;
 		state->error = ret;
 	}
 	}
-	return r;
+	return res;
 }
 }
 
 
 static void s5k5baf_i2c_write(struct s5k5baf *state, u16 addr, u16 val)
 static void s5k5baf_i2c_write(struct s5k5baf *state, u16 addr, u16 val)
@@ -1037,7 +1038,7 @@ static int s5k5baf_load_setfile(struct s5k5baf *state)
 	}
 	}
 
 
 	ret = s5k5baf_fw_parse(&c->dev, &state->fw, fw->size / 2,
 	ret = s5k5baf_fw_parse(&c->dev, &state->fw, fw->size / 2,
-			       (u16 *)fw->data);
+			       (__le16 *)fw->data);
 
 
 	release_firmware(fw);
 	release_firmware(fw);
 
 
@@ -1793,7 +1794,7 @@ static const struct v4l2_subdev_ops s5k5baf_subdev_ops = {
 
 
 static int s5k5baf_configure_gpios(struct s5k5baf *state)
 static int s5k5baf_configure_gpios(struct s5k5baf *state)
 {
 {
-	static const char const *name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" };
+	static const char * const name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" };
 	struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
 	struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
 	struct s5k5baf_gpio *g = state->gpios;
 	struct s5k5baf_gpio *g = state->gpios;
 	int ret, i;
 	int ret, i;

+ 27 - 19
drivers/media/i2c/s5k6aa.c

@@ -348,7 +348,7 @@ static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
 	msg[1].buf = rbuf;
 	msg[1].buf = rbuf;
 
 
 	ret = i2c_transfer(client->adapter, msg, 2);
 	ret = i2c_transfer(client->adapter, msg, 2);
-	*val = be16_to_cpu(*((u16 *)rbuf));
+	*val = be16_to_cpu(*((__be16 *)rbuf));
 
 
 	v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
 	v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
 
 
@@ -1161,17 +1161,21 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 	return ret;
 	return ret;
 }
 }
 
 
-static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
-			   struct v4l2_subdev_crop *crop)
+static int s5k6aa_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
 {
 {
 	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
 	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
 	struct v4l2_rect *rect;
 	struct v4l2_rect *rect;
 
 
-	memset(crop->reserved, 0, sizeof(crop->reserved));
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
+	memset(sel->reserved, 0, sizeof(sel->reserved));
 
 
 	mutex_lock(&s5k6aa->lock);
 	mutex_lock(&s5k6aa->lock);
-	rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
-	crop->rect = *rect;
+	rect = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which);
+	sel->r = *rect;
 	mutex_unlock(&s5k6aa->lock);
 	mutex_unlock(&s5k6aa->lock);
 
 
 	v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n",
 	v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n",
@@ -1180,35 +1184,39 @@ static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 	return 0;
 	return 0;
 }
 }
 
 
-static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
-			   struct v4l2_subdev_crop *crop)
+static int s5k6aa_set_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
 {
 {
 	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
 	struct s5k6aa *s5k6aa = to_s5k6aa(sd);
 	struct v4l2_mbus_framefmt *mf;
 	struct v4l2_mbus_framefmt *mf;
 	unsigned int max_x, max_y;
 	unsigned int max_x, max_y;
 	struct v4l2_rect *crop_r;
 	struct v4l2_rect *crop_r;
 
 
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
 	mutex_lock(&s5k6aa->lock);
 	mutex_lock(&s5k6aa->lock);
-	crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
+	crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which);
 
 
-	if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
 		mf = &s5k6aa->preset->mbus_fmt;
 		mf = &s5k6aa->preset->mbus_fmt;
 		s5k6aa->apply_crop = 1;
 		s5k6aa->apply_crop = 1;
 	} else {
 	} else {
 		mf = v4l2_subdev_get_try_format(fh, 0);
 		mf = v4l2_subdev_get_try_format(fh, 0);
 	}
 	}
-	v4l_bound_align_image(&crop->rect.width, mf->width,
+	v4l_bound_align_image(&sel->r.width, mf->width,
 			      S5K6AA_WIN_WIDTH_MAX, 1,
 			      S5K6AA_WIN_WIDTH_MAX, 1,
-			      &crop->rect.height, mf->height,
+			      &sel->r.height, mf->height,
 			      S5K6AA_WIN_HEIGHT_MAX, 1, 0);
 			      S5K6AA_WIN_HEIGHT_MAX, 1, 0);
 
 
-	max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1;
-	max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1;
+	max_x = (S5K6AA_WIN_WIDTH_MAX - sel->r.width) & ~1;
+	max_y = (S5K6AA_WIN_HEIGHT_MAX - sel->r.height) & ~1;
 
 
-	crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x);
-	crop->rect.top  = clamp_t(unsigned int, crop->rect.top, 0, max_y);
+	sel->r.left = clamp_t(unsigned int, sel->r.left, 0, max_x);
+	sel->r.top  = clamp_t(unsigned int, sel->r.top, 0, max_y);
 
 
-	*crop_r = crop->rect;
+	*crop_r = sel->r;
 
 
 	mutex_unlock(&s5k6aa->lock);
 	mutex_unlock(&s5k6aa->lock);
 
 
@@ -1224,8 +1232,8 @@ static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = {
 	.enum_frame_interval	= s5k6aa_enum_frame_interval,
 	.enum_frame_interval	= s5k6aa_enum_frame_interval,
 	.get_fmt		= s5k6aa_get_fmt,
 	.get_fmt		= s5k6aa_get_fmt,
 	.set_fmt		= s5k6aa_set_fmt,
 	.set_fmt		= s5k6aa_set_fmt,
-	.get_crop		= s5k6aa_get_crop,
-	.set_crop		= s5k6aa_set_crop,
+	.get_selection		= s5k6aa_get_selection,
+	.set_selection		= s5k6aa_set_selection,
 };
 };
 
 
 static const struct v4l2_subdev_video_ops s5k6aa_video_ops = {
 static const struct v4l2_subdev_video_ops s5k6aa_video_ops = {

+ 1 - 6
drivers/media/i2c/smiapp-pll.c

@@ -14,14 +14,9 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
+#include <linux/device.h>
 #include <linux/gcd.h>
 #include <linux/gcd.h>
 #include <linux/lcm.h>
 #include <linux/lcm.h>
 #include <linux/module.h>
 #include <linux/module.h>

+ 0 - 8
drivers/media/i2c/smiapp-pll.h

@@ -14,19 +14,11 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #ifndef SMIAPP_PLL_H
 #ifndef SMIAPP_PLL_H
 #define SMIAPP_PLL_H
 #define SMIAPP_PLL_H
 
 
-#include <linux/device.h>
-
 /* CSI-2 or CCP-2 */
 /* CSI-2 or CCP-2 */
 #define SMIAPP_PLL_BUS_TYPE_CSI2				0x00
 #define SMIAPP_PLL_BUS_TYPE_CSI2				0x00
 #define SMIAPP_PLL_BUS_TYPE_PARALLEL				0x01
 #define SMIAPP_PLL_BUS_TYPE_PARALLEL				0x01

+ 280 - 106
drivers/media/i2c/smiapp/smiapp-core.c

@@ -18,12 +18,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #include <linux/clk.h>
 #include <linux/clk.h>
@@ -31,11 +25,13 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/of_gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/smiapp.h>
 #include <linux/smiapp.h>
 #include <linux/v4l2-mediabus.h>
 #include <linux/v4l2-mediabus.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
 
 
 #include "smiapp.h"
 #include "smiapp.h"
 
 
@@ -523,14 +519,12 @@ static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
 static int smiapp_init_controls(struct smiapp_sensor *sensor)
 static int smiapp_init_controls(struct smiapp_sensor *sensor)
 {
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
-	unsigned long *valid_link_freqs = &sensor->valid_link_freqs[
-		sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE];
-	unsigned int max, i;
 	int rval;
 	int rval;
 
 
 	rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12);
 	rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12);
 	if (rval)
 	if (rval)
 		return rval;
 		return rval;
+
 	sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
 	sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
 
 
 	sensor->analog_gain = v4l2_ctrl_new_std(
 	sensor->analog_gain = v4l2_ctrl_new_std(
@@ -576,21 +570,11 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
 				     ARRAY_SIZE(smiapp_test_patterns) - 1,
 				     ARRAY_SIZE(smiapp_test_patterns) - 1,
 				     0, 0, smiapp_test_patterns);
 				     0, 0, smiapp_test_patterns);
 
 
-	for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) {
-		int max_value = (1 << sensor->csi_format->width) - 1;
-		sensor->test_data[i] =
-			v4l2_ctrl_new_std(
-				&sensor->pixel_array->ctrl_handler,
-				&smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i,
-				0, max_value, 1, max_value);
-	}
-
 	if (sensor->pixel_array->ctrl_handler.error) {
 	if (sensor->pixel_array->ctrl_handler.error) {
 		dev_err(&client->dev,
 		dev_err(&client->dev,
 			"pixel array controls initialization failed (%d)\n",
 			"pixel array controls initialization failed (%d)\n",
 			sensor->pixel_array->ctrl_handler.error);
 			sensor->pixel_array->ctrl_handler.error);
-		rval = sensor->pixel_array->ctrl_handler.error;
-		goto error;
+		return sensor->pixel_array->ctrl_handler.error;
 	}
 	}
 
 
 	sensor->pixel_array->sd.ctrl_handler =
 	sensor->pixel_array->sd.ctrl_handler =
@@ -600,15 +584,9 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
 
 
 	rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0);
 	rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0);
 	if (rval)
 	if (rval)
-		goto error;
-	sensor->src->ctrl_handler.lock = &sensor->mutex;
-
-	for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++);
+		return rval;
 
 
-	sensor->link_freq = v4l2_ctrl_new_int_menu(
-		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
-		V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs),
-		__ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock);
+	sensor->src->ctrl_handler.lock = &sensor->mutex;
 
 
 	sensor->pixel_rate_csi = v4l2_ctrl_new_std(
 	sensor->pixel_rate_csi = v4l2_ctrl_new_std(
 		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
 		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
@@ -618,20 +596,41 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
 		dev_err(&client->dev,
 		dev_err(&client->dev,
 			"src controls initialization failed (%d)\n",
 			"src controls initialization failed (%d)\n",
 			sensor->src->ctrl_handler.error);
 			sensor->src->ctrl_handler.error);
-		rval = sensor->src->ctrl_handler.error;
-		goto error;
+		return sensor->src->ctrl_handler.error;
 	}
 	}
 
 
-	sensor->src->sd.ctrl_handler =
-		&sensor->src->ctrl_handler;
+	sensor->src->sd.ctrl_handler = &sensor->src->ctrl_handler;
 
 
 	return 0;
 	return 0;
+}
+
+/*
+ * For controls that require information on available media bus codes
+ * and linke frequencies.
+ */
+static int smiapp_init_late_controls(struct smiapp_sensor *sensor)
+{
+	unsigned long *valid_link_freqs = &sensor->valid_link_freqs[
+		sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE];
+	unsigned int max, i;
 
 
-error:
-	v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler);
-	v4l2_ctrl_handler_free(&sensor->src->ctrl_handler);
+	for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) {
+		int max_value = (1 << sensor->csi_format->width) - 1;
 
 
-	return rval;
+		sensor->test_data[i] = v4l2_ctrl_new_std(
+				&sensor->pixel_array->ctrl_handler,
+				&smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i,
+				0, max_value, 1, max_value);
+	}
+
+	for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++);
+
+	sensor->link_freq = v4l2_ctrl_new_int_menu(
+		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+		V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs),
+		__ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock);
+
+	return sensor->src->ctrl_handler.error;
 }
 }
 
 
 static void smiapp_free_controls(struct smiapp_sensor *sensor)
 static void smiapp_free_controls(struct smiapp_sensor *sensor)
@@ -1487,7 +1486,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor)
 	if (rval < 0)
 	if (rval < 0)
 		goto out;
 		goto out;
 
 
-	if ((sensor->flash_capability &
+	if ((sensor->limits[SMIAPP_LIMIT_FLASH_MODE_CAPABILITY] &
 	     (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
 	     (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
 	      SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
 	      SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
 	    sensor->platform_data->strobe_setup != NULL &&
 	    sensor->platform_data->strobe_setup != NULL &&
@@ -2338,10 +2337,9 @@ static DEVICE_ATTR(ident, S_IRUGO, smiapp_sysfs_ident_read, NULL);
  * V4L2 subdev core operations
  * V4L2 subdev core operations
  */
  */
 
 
-static int smiapp_identify_module(struct v4l2_subdev *subdev)
+static int smiapp_identify_module(struct smiapp_sensor *sensor)
 {
 {
-	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
-	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
 	struct smiapp_module_info *minfo = &sensor->minfo;
 	struct smiapp_module_info *minfo = &sensor->minfo;
 	unsigned int i;
 	unsigned int i;
 	int rval = 0;
 	int rval = 0;
@@ -2464,8 +2462,6 @@ static int smiapp_identify_module(struct v4l2_subdev *subdev)
 		minfo->name, minfo->manufacturer_id, minfo->model_id,
 		minfo->name, minfo->manufacturer_id, minfo->model_id,
 		minfo->revision_number_major);
 		minfo->revision_number_major);
 
 
-	strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name));
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2473,13 +2469,71 @@ static const struct v4l2_subdev_ops smiapp_ops;
 static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
 static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
 static const struct media_entity_operations smiapp_entity_ops;
 static const struct media_entity_operations smiapp_entity_ops;
 
 
-static int smiapp_registered(struct v4l2_subdev *subdev)
+static int smiapp_register_subdevs(struct smiapp_sensor *sensor)
 {
 {
-	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
-	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+	struct smiapp_subdev *ssds[] = {
+		sensor->scaler,
+		sensor->binner,
+		sensor->pixel_array,
+	};
+	unsigned int i;
+	int rval;
+
+	for (i = 0; i < SMIAPP_SUBDEVS - 1; i++) {
+		struct smiapp_subdev *this = ssds[i + 1];
+		struct smiapp_subdev *last = ssds[i];
+
+		if (!last)
+			continue;
+
+		rval = media_entity_init(&this->sd.entity,
+					 this->npads, this->pads, 0);
+		if (rval) {
+			dev_err(&client->dev,
+				"media_entity_init failed\n");
+			return rval;
+		}
+
+		rval = media_entity_create_link(&this->sd.entity,
+						this->source_pad,
+						&last->sd.entity,
+						last->sink_pad,
+						MEDIA_LNK_FL_ENABLED |
+						MEDIA_LNK_FL_IMMUTABLE);
+		if (rval) {
+			dev_err(&client->dev,
+				"media_entity_create_link failed\n");
+			return rval;
+		}
+
+		rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
+						   &this->sd);
+		if (rval) {
+			dev_err(&client->dev,
+				"v4l2_device_register_subdev failed\n");
+			return rval;
+		}
+	}
+
+	return 0;
+}
+
+static void smiapp_cleanup(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+	device_remove_file(&client->dev, &dev_attr_nvm);
+	device_remove_file(&client->dev, &dev_attr_ident);
+
+	smiapp_free_controls(sensor);
+}
+
+static int smiapp_init(struct smiapp_sensor *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
 	struct smiapp_pll *pll = &sensor->pll;
 	struct smiapp_pll *pll = &sensor->pll;
 	struct smiapp_subdev *last = NULL;
 	struct smiapp_subdev *last = NULL;
-	u32 tmp;
 	unsigned int i;
 	unsigned int i;
 	int rval;
 	int rval;
 
 
@@ -2490,7 +2544,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
 	}
 	}
 
 
 	if (!sensor->platform_data->set_xclk) {
 	if (!sensor->platform_data->set_xclk) {
-		sensor->ext_clk = devm_clk_get(&client->dev, "ext_clk");
+		sensor->ext_clk = devm_clk_get(&client->dev, NULL);
 		if (IS_ERR(sensor->ext_clk)) {
 		if (IS_ERR(sensor->ext_clk)) {
 			dev_err(&client->dev, "could not get clock\n");
 			dev_err(&client->dev, "could not get clock\n");
 			return PTR_ERR(sensor->ext_clk);
 			return PTR_ERR(sensor->ext_clk);
@@ -2522,7 +2576,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
 	if (rval)
 	if (rval)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	rval = smiapp_identify_module(subdev);
+	rval = smiapp_identify_module(sensor);
 	if (rval) {
 	if (rval) {
 		rval = -ENODEV;
 		rval = -ENODEV;
 		goto out_power_off;
 		goto out_power_off;
@@ -2602,13 +2656,13 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
 		if (sensor->nvm == NULL) {
 		if (sensor->nvm == NULL) {
 			dev_err(&client->dev, "nvm buf allocation failed\n");
 			dev_err(&client->dev, "nvm buf allocation failed\n");
 			rval = -ENOMEM;
 			rval = -ENOMEM;
-			goto out_ident_release;
+			goto out_cleanup;
 		}
 		}
 
 
 		if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
 		if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
 			dev_err(&client->dev, "sysfs nvm entry failed\n");
 			dev_err(&client->dev, "sysfs nvm entry failed\n");
 			rval = -EBUSY;
 			rval = -EBUSY;
-			goto out_ident_release;
+			goto out_cleanup;
 		}
 		}
 	}
 	}
 
 
@@ -2643,18 +2697,11 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
 	pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
 	pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
 	pll->csi2.lanes = sensor->platform_data->lanes;
 	pll->csi2.lanes = sensor->platform_data->lanes;
 	pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
 	pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
-	pll->flags = smiapp_call_quirk(sensor, pll_flags);
 	pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
 	pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
 	/* Profile 0 sensors have no separate OP clock branch. */
 	/* Profile 0 sensors have no separate OP clock branch. */
 	if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
 	if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
 		pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
 		pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
 
 
-	rval = smiapp_get_mbus_formats(sensor);
-	if (rval) {
-		rval = -ENODEV;
-		goto out_nvm_release;
-	}
-
 	for (i = 0; i < SMIAPP_SUBDEVS; i++) {
 	for (i = 0; i < SMIAPP_SUBDEVS; i++) {
 		struct {
 		struct {
 			struct smiapp_subdev *ssd;
 			struct smiapp_subdev *ssd;
@@ -2711,34 +2758,6 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
 		this->sd.owner = THIS_MODULE;
 		this->sd.owner = THIS_MODULE;
 		v4l2_set_subdevdata(&this->sd, client);
 		v4l2_set_subdevdata(&this->sd, client);
 
 
-		rval = media_entity_init(&this->sd.entity,
-					 this->npads, this->pads, 0);
-		if (rval) {
-			dev_err(&client->dev,
-				"media_entity_init failed\n");
-			goto out_nvm_release;
-		}
-
-		rval = media_entity_create_link(&this->sd.entity,
-						this->source_pad,
-						&last->sd.entity,
-						last->sink_pad,
-						MEDIA_LNK_FL_ENABLED |
-						MEDIA_LNK_FL_IMMUTABLE);
-		if (rval) {
-			dev_err(&client->dev,
-				"media_entity_create_link failed\n");
-			goto out_nvm_release;
-		}
-
-		rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
-						   &this->sd);
-		if (rval) {
-			dev_err(&client->dev,
-				"v4l2_device_register_subdev failed\n");
-			goto out_nvm_release;
-		}
-
 		last = this;
 		last = this;
 	}
 	}
 
 
@@ -2750,40 +2769,66 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
 	smiapp_read_frame_fmt(sensor);
 	smiapp_read_frame_fmt(sensor);
 	rval = smiapp_init_controls(sensor);
 	rval = smiapp_init_controls(sensor);
 	if (rval < 0)
 	if (rval < 0)
-		goto out_nvm_release;
+		goto out_cleanup;
+
+	rval = smiapp_call_quirk(sensor, init);
+	if (rval)
+		goto out_cleanup;
+
+	rval = smiapp_get_mbus_formats(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_cleanup;
+	}
+
+	rval = smiapp_init_late_controls(sensor);
+	if (rval) {
+		rval = -ENODEV;
+		goto out_cleanup;
+	}
 
 
 	mutex_lock(&sensor->mutex);
 	mutex_lock(&sensor->mutex);
 	rval = smiapp_update_mode(sensor);
 	rval = smiapp_update_mode(sensor);
 	mutex_unlock(&sensor->mutex);
 	mutex_unlock(&sensor->mutex);
 	if (rval) {
 	if (rval) {
 		dev_err(&client->dev, "update mode failed\n");
 		dev_err(&client->dev, "update mode failed\n");
-		goto out_nvm_release;
+		goto out_cleanup;
 	}
 	}
 
 
 	sensor->streaming = false;
 	sensor->streaming = false;
 	sensor->dev_init_done = true;
 	sensor->dev_init_done = true;
 
 
-	/* check flash capability */
-	rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp);
-	sensor->flash_capability = tmp;
-	if (rval)
-		goto out_nvm_release;
-
 	smiapp_power_off(sensor);
 	smiapp_power_off(sensor);
 
 
 	return 0;
 	return 0;
 
 
-out_nvm_release:
-	device_remove_file(&client->dev, &dev_attr_nvm);
-
-out_ident_release:
-	device_remove_file(&client->dev, &dev_attr_ident);
+out_cleanup:
+	smiapp_cleanup(sensor);
 
 
 out_power_off:
 out_power_off:
 	smiapp_power_off(sensor);
 	smiapp_power_off(sensor);
 	return rval;
 	return rval;
 }
 }
 
 
+static int smiapp_registered(struct v4l2_subdev *subdev)
+{
+	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	int rval;
+
+	if (!client->dev.of_node) {
+		rval = smiapp_init(sensor);
+		if (rval)
+			return rval;
+	}
+
+	rval = smiapp_register_subdevs(sensor);
+	if (rval)
+		smiapp_cleanup(sensor);
+
+	return rval;
+}
+
 static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
 {
 	struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
 	struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
@@ -2927,19 +2972,125 @@ static int smiapp_resume(struct device *dev)
 
 
 #endif /* CONFIG_PM */
 #endif /* CONFIG_PM */
 
 
+static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev)
+{
+	struct smiapp_platform_data *pdata;
+	struct v4l2_of_endpoint bus_cfg;
+	struct device_node *ep;
+	struct property *prop;
+	__be32 *val;
+	uint32_t asize;
+#ifdef CONFIG_OF
+	unsigned int i;
+#endif
+	int rval;
+
+	if (!dev->of_node)
+		return dev->platform_data;
+
+	ep = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (!ep)
+		return NULL;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		rval = -ENOMEM;
+		goto out_err;
+	}
+
+	v4l2_of_parse_endpoint(ep, &bus_cfg);
+
+	switch (bus_cfg.bus_type) {
+	case V4L2_MBUS_CSI2:
+		pdata->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2;
+		break;
+		/* FIXME: add CCP2 support. */
+	default:
+		rval = -EINVAL;
+		goto out_err;
+	}
+
+	pdata->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+	dev_dbg(dev, "lanes %u\n", pdata->lanes);
+
+	/* xshutdown GPIO is optional */
+	pdata->xshutdown = of_get_named_gpio(dev->of_node, "reset-gpios", 0);
+
+	/* NVM size is not mandatory */
+	of_property_read_u32(dev->of_node, "nokia,nvm-size",
+				    &pdata->nvm_size);
+
+	rval = of_property_read_u32(dev->of_node, "clock-frequency",
+				    &pdata->ext_clk);
+	if (rval) {
+		dev_warn(dev, "can't get clock-frequency\n");
+		goto out_err;
+	}
+
+	dev_dbg(dev, "reset %d, nvm %d, clk %d, csi %d\n", pdata->xshutdown,
+		pdata->nvm_size, pdata->ext_clk, pdata->csi_signalling_mode);
+
+	rval = of_get_property(
+		dev->of_node, "link-frequencies", &asize) ? 0 : -ENOENT;
+	if (rval) {
+		dev_warn(dev, "can't get link-frequencies array size\n");
+		goto out_err;
+	}
+
+	pdata->op_sys_clock = devm_kzalloc(dev, asize, GFP_KERNEL);
+	if (!pdata->op_sys_clock) {
+		rval = -ENOMEM;
+		goto out_err;
+	}
+
+	asize /= sizeof(*pdata->op_sys_clock);
+	/*
+	 * Read a 64-bit array --- this will be replaced with a
+	 * of_property_read_u64_array() once it's merged.
+	 */
+	prop = of_find_property(dev->of_node, "link-frequencies", NULL);
+	if (!prop)
+		goto out_err;
+	if (!prop->value)
+		goto out_err;
+	if (asize * sizeof(*pdata->op_sys_clock) > prop->length)
+		goto out_err;
+	val = prop->value;
+	if (IS_ERR(val))
+		goto out_err;
+
+#ifdef CONFIG_OF
+	for (i = 0; i < asize; i++)
+		pdata->op_sys_clock[i] = of_read_number(val + i * 2, 2);
+#endif
+
+	for (; asize > 0; asize--)
+		dev_dbg(dev, "freq %d: %lld\n", asize - 1,
+			pdata->op_sys_clock[asize - 1]);
+
+	of_node_put(ep);
+	return pdata;
+
+out_err:
+	of_node_put(ep);
+	return NULL;
+}
+
 static int smiapp_probe(struct i2c_client *client,
 static int smiapp_probe(struct i2c_client *client,
 			const struct i2c_device_id *devid)
 			const struct i2c_device_id *devid)
 {
 {
 	struct smiapp_sensor *sensor;
 	struct smiapp_sensor *sensor;
+	struct smiapp_platform_data *pdata = smiapp_get_pdata(&client->dev);
+	int rval;
 
 
-	if (client->dev.platform_data == NULL)
+	if (pdata == NULL)
 		return -ENODEV;
 		return -ENODEV;
 
 
 	sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
 	sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
 	if (sensor == NULL)
 	if (sensor == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	sensor->platform_data = client->dev.platform_data;
+	sensor->platform_data = pdata;
 	mutex_init(&sensor->mutex);
 	mutex_init(&sensor->mutex);
 	mutex_init(&sensor->power_mutex);
 	mutex_init(&sensor->power_mutex);
 	sensor->src = &sensor->ssds[sensor->ssds_used];
 	sensor->src = &sensor->ssds[sensor->ssds_used];
@@ -2950,8 +3101,27 @@ static int smiapp_probe(struct i2c_client *client,
 	sensor->src->sensor = sensor;
 	sensor->src->sensor = sensor;
 
 
 	sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
 	sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
-	return media_entity_init(&sensor->src->sd.entity, 2,
+	rval = media_entity_init(&sensor->src->sd.entity, 2,
 				 sensor->src->pads, 0);
 				 sensor->src->pads, 0);
+	if (rval < 0)
+		return rval;
+
+	if (client->dev.of_node) {
+		rval = smiapp_init(sensor);
+		if (rval)
+			goto out_media_entity_cleanup;
+	}
+
+	rval = v4l2_async_register_subdev(&sensor->src->sd);
+	if (rval < 0)
+		goto out_media_entity_cleanup;
+
+	return 0;
+
+out_media_entity_cleanup:
+	media_entity_cleanup(&sensor->src->sd.entity);
+
+	return rval;
 }
 }
 
 
 static int smiapp_remove(struct i2c_client *client)
 static int smiapp_remove(struct i2c_client *client)
@@ -2960,6 +3130,8 @@ static int smiapp_remove(struct i2c_client *client)
 	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
 	struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
 	unsigned int i;
 	unsigned int i;
 
 
+	v4l2_async_unregister_subdev(subdev);
+
 	if (sensor->power_count) {
 	if (sensor->power_count) {
 		if (gpio_is_valid(sensor->platform_data->xshutdown))
 		if (gpio_is_valid(sensor->platform_data->xshutdown))
 			gpio_set_value(sensor->platform_data->xshutdown, 0);
 			gpio_set_value(sensor->platform_data->xshutdown, 0);
@@ -2970,19 +3142,20 @@ static int smiapp_remove(struct i2c_client *client)
 		sensor->power_count = 0;
 		sensor->power_count = 0;
 	}
 	}
 
 
-	device_remove_file(&client->dev, &dev_attr_ident);
-	if (sensor->nvm)
-		device_remove_file(&client->dev, &dev_attr_nvm);
-
 	for (i = 0; i < sensor->ssds_used; i++) {
 	for (i = 0; i < sensor->ssds_used; i++) {
 		v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
 		v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
 		media_entity_cleanup(&sensor->ssds[i].sd.entity);
 		media_entity_cleanup(&sensor->ssds[i].sd.entity);
 	}
 	}
-	smiapp_free_controls(sensor);
+	smiapp_cleanup(sensor);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
+static const struct of_device_id smiapp_of_table[] = {
+	{ .compatible = "nokia,smia" },
+	{ },
+};
+
 static const struct i2c_device_id smiapp_id_table[] = {
 static const struct i2c_device_id smiapp_id_table[] = {
 	{ SMIAPP_NAME, 0 },
 	{ SMIAPP_NAME, 0 },
 	{ },
 	{ },
@@ -2996,6 +3169,7 @@ static const struct dev_pm_ops smiapp_pm_ops = {
 
 
 static struct i2c_driver smiapp_i2c_driver = {
 static struct i2c_driver smiapp_i2c_driver = {
 	.driver	= {
 	.driver	= {
+		.of_match_table = smiapp_of_table,
 		.name = SMIAPP_NAME,
 		.name = SMIAPP_NAME,
 		.pm = &smiapp_pm_ops,
 		.pm = &smiapp_pm_ops,
 	},
 	},

+ 0 - 6
drivers/media/i2c/smiapp/smiapp-limits.c

@@ -14,12 +14,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #include "smiapp.h"
 #include "smiapp.h"

+ 0 - 6
drivers/media/i2c/smiapp/smiapp-limits.h

@@ -14,12 +14,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY			0
 #define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY			0

+ 5 - 9
drivers/media/i2c/smiapp/smiapp-quirk.c

@@ -14,12 +14,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #include <linux/delay.h>
 #include <linux/delay.h>
@@ -220,9 +214,11 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
 	return smiapp_write_8(sensor, 0x3328, 0x80);
 	return smiapp_write_8(sensor, 0x3328, 0x80);
 }
 }
 
 
-static unsigned long jt8ev1_pll_flags(struct smiapp_sensor *sensor)
+static int jt8ev1_init(struct smiapp_sensor *sensor)
 {
 {
-	return SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+	sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+
+	return 0;
 }
 }
 
 
 const struct smiapp_quirk smiapp_jt8ev1_quirk = {
 const struct smiapp_quirk smiapp_jt8ev1_quirk = {
@@ -230,7 +226,7 @@ const struct smiapp_quirk smiapp_jt8ev1_quirk = {
 	.post_poweron = jt8ev1_post_poweron,
 	.post_poweron = jt8ev1_post_poweron,
 	.pre_streamon = jt8ev1_pre_streamon,
 	.pre_streamon = jt8ev1_pre_streamon,
 	.post_streamoff = jt8ev1_post_streamoff,
 	.post_streamoff = jt8ev1_post_streamoff,
-	.pll_flags = jt8ev1_pll_flags,
+	.init = jt8ev1_init,
 };
 };
 
 
 static int tcm8500md_limits(struct smiapp_sensor *sensor)
 static int tcm8500md_limits(struct smiapp_sensor *sensor)

+ 11 - 13
drivers/media/i2c/smiapp/smiapp-quirk.h

@@ -14,12 +14,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #ifndef __SMIAPP_QUIRK__
 #ifndef __SMIAPP_QUIRK__
@@ -35,6 +29,9 @@ struct smiapp_sensor;
  * @post_poweron: Called always after the sensor has been fully powered on.
  * @post_poweron: Called always after the sensor has been fully powered on.
  * @pre_streamon: Called just before streaming is enabled.
  * @pre_streamon: Called just before streaming is enabled.
  * @post_streamon: Called right after stopping streaming.
  * @post_streamon: Called right after stopping streaming.
+ * @pll_flags: Return flags for the PLL calculator.
+ * @init: Quirk initialisation, called the last in probe(). This is
+ *	  also appropriate for adding sensor specific controls, for instance.
  * @reg_access: Register access quirk. The quirk may divert the access
  * @reg_access: Register access quirk. The quirk may divert the access
  *		to another register, or no register at all.
  *		to another register, or no register at all.
  *
  *
@@ -53,6 +50,7 @@ struct smiapp_quirk {
 	int (*pre_streamon)(struct smiapp_sensor *sensor);
 	int (*pre_streamon)(struct smiapp_sensor *sensor);
 	int (*post_streamoff)(struct smiapp_sensor *sensor);
 	int (*post_streamoff)(struct smiapp_sensor *sensor);
 	unsigned long (*pll_flags)(struct smiapp_sensor *sensor);
 	unsigned long (*pll_flags)(struct smiapp_sensor *sensor);
+	int (*init)(struct smiapp_sensor *sensor);
 	int (*reg_access)(struct smiapp_sensor *sensor, bool write, u32 *reg,
 	int (*reg_access)(struct smiapp_sensor *sensor, bool write, u32 *reg,
 			  u32 *val);
 			  u32 *val);
 	unsigned long flags;
 	unsigned long flags;
@@ -74,14 +72,14 @@ void smiapp_replace_limit(struct smiapp_sensor *sensor,
 		.val = _val,		\
 		.val = _val,		\
 	}
 	}
 
 
-#define smiapp_call_quirk(_sensor, _quirk, ...)				\
-	(_sensor->minfo.quirk &&					\
-	 _sensor->minfo.quirk->_quirk ?					\
-	 _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0)
+#define smiapp_call_quirk(sensor, _quirk, ...)				\
+	((sensor)->minfo.quirk &&					\
+	 (sensor)->minfo.quirk->_quirk ?				\
+	 (sensor)->minfo.quirk->_quirk(sensor, ##__VA_ARGS__) : 0)
 
 
-#define smiapp_needs_quirk(_sensor, _quirk)		\
-	(_sensor->minfo.quirk ?				\
-	 _sensor->minfo.quirk->flags & _quirk : 0)
+#define smiapp_needs_quirk(sensor, _quirk)		\
+	((sensor)->minfo.quirk ?			\
+	 (sensor)->minfo.quirk->flags & _quirk : 0)
 
 
 extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
 extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
 extern const struct smiapp_quirk smiapp_imx125es_quirk;
 extern const struct smiapp_quirk smiapp_imx125es_quirk;

+ 0 - 6
drivers/media/i2c/smiapp/smiapp-reg-defs.h

@@ -14,12 +14,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 #define SMIAPP_REG_MK_U8(r) ((SMIAPP_REG_8BIT << 16) | (r))
 #define SMIAPP_REG_MK_U8(r) ((SMIAPP_REG_8BIT << 16) | (r))
 #define SMIAPP_REG_MK_U16(r) ((SMIAPP_REG_16BIT << 16) | (r))
 #define SMIAPP_REG_MK_U16(r) ((SMIAPP_REG_16BIT << 16) | (r))

+ 0 - 6
drivers/media/i2c/smiapp/smiapp-reg.h

@@ -14,12 +14,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #ifndef __SMIAPP_REG_H_
 #ifndef __SMIAPP_REG_H_

+ 0 - 6
drivers/media/i2c/smiapp/smiapp-regs.c

@@ -14,12 +14,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #include <linux/delay.h>
 #include <linux/delay.h>

+ 0 - 6
drivers/media/i2c/smiapp/smiapp-regs.h

@@ -14,12 +14,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #ifndef SMIAPP_REGS_H
 #ifndef SMIAPP_REGS_H

+ 0 - 7
drivers/media/i2c/smiapp/smiapp.h

@@ -14,12 +14,6 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
  */
 
 
 #ifndef __SMIAPP_PRIV_H_
 #ifndef __SMIAPP_PRIV_H_
@@ -222,7 +216,6 @@ struct smiapp_sensor {
 	u8 scaling_mode;
 	u8 scaling_mode;
 
 
 	u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
 	u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
-	u8 flash_capability;
 	u8 frame_skip;
 	u8 frame_skip;
 
 
 	int power_count;
 	int power_count;

+ 30 - 52
drivers/media/i2c/soc_camera/ov2640.c

@@ -25,6 +25,7 @@
 #include <media/v4l2-clk.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-image-sizes.h>
 
 
 #define VAL_SET(x, mask, rshift, lshift)  \
 #define VAL_SET(x, mask, rshift, lshift)  \
 		((((x) >> rshift) & mask) << lshift)
 		((((x) >> rshift) & mask) << lshift)
@@ -268,33 +269,10 @@ struct regval_list {
 	u8 value;
 	u8 value;
 };
 };
 
 
-/* Supported resolutions */
-enum ov2640_width {
-	W_QCIF	= 176,
-	W_QVGA	= 320,
-	W_CIF	= 352,
-	W_VGA	= 640,
-	W_SVGA	= 800,
-	W_XGA	= 1024,
-	W_SXGA	= 1280,
-	W_UXGA	= 1600,
-};
-
-enum ov2640_height {
-	H_QCIF	= 144,
-	H_QVGA	= 240,
-	H_CIF	= 288,
-	H_VGA	= 480,
-	H_SVGA	= 600,
-	H_XGA	= 768,
-	H_SXGA	= 1024,
-	H_UXGA	= 1200,
-};
-
 struct ov2640_win_size {
 struct ov2640_win_size {
 	char				*name;
 	char				*name;
-	enum ov2640_width		width;
-	enum ov2640_height		height;
+	u32				width;
+	u32				height;
 	const struct regval_list	*regs;
 	const struct regval_list	*regs;
 };
 };
 
 
@@ -495,17 +473,17 @@ static const struct regval_list ov2640_init_regs[] = {
 static const struct regval_list ov2640_size_change_preamble_regs[] = {
 static const struct regval_list ov2640_size_change_preamble_regs[] = {
 	{ BANK_SEL, BANK_SEL_DSP },
 	{ BANK_SEL, BANK_SEL_DSP },
 	{ RESET, RESET_DVP },
 	{ RESET, RESET_DVP },
-	{ HSIZE8, HSIZE8_SET(W_UXGA) },
-	{ VSIZE8, VSIZE8_SET(H_UXGA) },
+	{ HSIZE8, HSIZE8_SET(UXGA_WIDTH) },
+	{ VSIZE8, VSIZE8_SET(UXGA_HEIGHT) },
 	{ CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
 	{ CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
 		 CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
 		 CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
-	{ HSIZE, HSIZE_SET(W_UXGA) },
-	{ VSIZE, VSIZE_SET(H_UXGA) },
+	{ HSIZE, HSIZE_SET(UXGA_WIDTH) },
+	{ VSIZE, VSIZE_SET(UXGA_HEIGHT) },
 	{ XOFFL, XOFFL_SET(0) },
 	{ XOFFL, XOFFL_SET(0) },
 	{ YOFFL, YOFFL_SET(0) },
 	{ YOFFL, YOFFL_SET(0) },
-	{ VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) |
+	{ VHYX, VHYX_HSIZE_SET(UXGA_WIDTH) | VHYX_VSIZE_SET(UXGA_HEIGHT) |
 		VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)},
 		VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)},
-	{ TEST, TEST_HSIZE_SET(W_UXGA) },
+	{ TEST, TEST_HSIZE_SET(UXGA_WIDTH) },
 	ENDMARKER,
 	ENDMARKER,
 };
 };
 
 
@@ -519,45 +497,45 @@ static const struct regval_list ov2640_size_change_preamble_regs[] = {
 	{ RESET, 0x00}
 	{ RESET, 0x00}
 
 
 static const struct regval_list ov2640_qcif_regs[] = {
 static const struct regval_list ov2640_qcif_regs[] = {
-	PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4),
+	PER_SIZE_REG_SEQ(QCIF_WIDTH, QCIF_HEIGHT, 3, 3, 4),
 	ENDMARKER,
 	ENDMARKER,
 };
 };
 
 
 static const struct regval_list ov2640_qvga_regs[] = {
 static const struct regval_list ov2640_qvga_regs[] = {
-	PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4),
+	PER_SIZE_REG_SEQ(QVGA_WIDTH, QVGA_HEIGHT, 2, 2, 4),
 	ENDMARKER,
 	ENDMARKER,
 };
 };
 
 
 static const struct regval_list ov2640_cif_regs[] = {
 static const struct regval_list ov2640_cif_regs[] = {
-	PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8),
+	PER_SIZE_REG_SEQ(CIF_WIDTH, CIF_HEIGHT, 2, 2, 8),
 	ENDMARKER,
 	ENDMARKER,
 };
 };
 
 
 static const struct regval_list ov2640_vga_regs[] = {
 static const struct regval_list ov2640_vga_regs[] = {
-	PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2),
+	PER_SIZE_REG_SEQ(VGA_WIDTH, VGA_HEIGHT, 0, 0, 2),
 	ENDMARKER,
 	ENDMARKER,
 };
 };
 
 
 static const struct regval_list ov2640_svga_regs[] = {
 static const struct regval_list ov2640_svga_regs[] = {
-	PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2),
+	PER_SIZE_REG_SEQ(SVGA_WIDTH, SVGA_HEIGHT, 1, 1, 2),
 	ENDMARKER,
 	ENDMARKER,
 };
 };
 
 
 static const struct regval_list ov2640_xga_regs[] = {
 static const struct regval_list ov2640_xga_regs[] = {
-	PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2),
+	PER_SIZE_REG_SEQ(XGA_WIDTH, XGA_HEIGHT, 0, 0, 2),
 	{ CTRLI,    0x00},
 	{ CTRLI,    0x00},
 	ENDMARKER,
 	ENDMARKER,
 };
 };
 
 
 static const struct regval_list ov2640_sxga_regs[] = {
 static const struct regval_list ov2640_sxga_regs[] = {
-	PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2),
+	PER_SIZE_REG_SEQ(SXGA_WIDTH, SXGA_HEIGHT, 0, 0, 2),
 	{ CTRLI,    0x00},
 	{ CTRLI,    0x00},
 	{ R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE },
 	{ R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE },
 	ENDMARKER,
 	ENDMARKER,
 };
 };
 
 
 static const struct regval_list ov2640_uxga_regs[] = {
 static const struct regval_list ov2640_uxga_regs[] = {
-	PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0),
+	PER_SIZE_REG_SEQ(UXGA_WIDTH, UXGA_HEIGHT, 0, 0, 0),
 	{ CTRLI,    0x00},
 	{ CTRLI,    0x00},
 	{ R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE },
 	{ R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE },
 	ENDMARKER,
 	ENDMARKER,
@@ -567,14 +545,14 @@ static const struct regval_list ov2640_uxga_regs[] = {
 	{.name = n, .width = w , .height = h, .regs = r }
 	{.name = n, .width = w , .height = h, .regs = r }
 
 
 static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
 static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
-	OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs),
-	OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs),
-	OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs),
-	OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs),
-	OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs),
-	OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs),
-	OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs),
-	OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs),
+	OV2640_SIZE("QCIF", QCIF_WIDTH, QCIF_HEIGHT, ov2640_qcif_regs),
+	OV2640_SIZE("QVGA", QVGA_WIDTH, QVGA_HEIGHT, ov2640_qvga_regs),
+	OV2640_SIZE("CIF", CIF_WIDTH, CIF_HEIGHT, ov2640_cif_regs),
+	OV2640_SIZE("VGA", VGA_WIDTH, VGA_HEIGHT, ov2640_vga_regs),
+	OV2640_SIZE("SVGA", SVGA_WIDTH, SVGA_HEIGHT, ov2640_svga_regs),
+	OV2640_SIZE("XGA", XGA_WIDTH, XGA_HEIGHT, ov2640_xga_regs),
+	OV2640_SIZE("SXGA", SXGA_WIDTH, SXGA_HEIGHT, ov2640_sxga_regs),
+	OV2640_SIZE("UXGA", UXGA_WIDTH, UXGA_HEIGHT, ov2640_uxga_regs),
 };
 };
 
 
 /*
 /*
@@ -867,7 +845,7 @@ static int ov2640_g_fmt(struct v4l2_subdev *sd,
 	struct ov2640_priv *priv = to_ov2640(client);
 	struct ov2640_priv *priv = to_ov2640(client);
 
 
 	if (!priv->win) {
 	if (!priv->win) {
-		u32 width = W_SVGA, height = H_SVGA;
+		u32 width = SVGA_WIDTH, height = SVGA_HEIGHT;
 		priv->win = ov2640_select_win(&width, &height);
 		priv->win = ov2640_select_win(&width, &height);
 		priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8;
 		priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8;
 	}
 	}
@@ -954,8 +932,8 @@ static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
 {
 	a->c.left	= 0;
 	a->c.left	= 0;
 	a->c.top	= 0;
 	a->c.top	= 0;
-	a->c.width	= W_UXGA;
-	a->c.height	= H_UXGA;
+	a->c.width	= UXGA_WIDTH;
+	a->c.height	= UXGA_HEIGHT;
 	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
 
 	return 0;
 	return 0;
@@ -965,8 +943,8 @@ static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 {
 {
 	a->bounds.left			= 0;
 	a->bounds.left			= 0;
 	a->bounds.top			= 0;
 	a->bounds.top			= 0;
-	a->bounds.width			= W_UXGA;
-	a->bounds.height		= H_UXGA;
+	a->bounds.width			= UXGA_WIDTH;
+	a->bounds.height		= UXGA_HEIGHT;
 	a->defrect			= a->bounds;
 	a->defrect			= a->bounds;
 	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	a->pixelaspect.numerator	= 1;
 	a->pixelaspect.numerator	= 1;

+ 0 - 10
drivers/media/i2c/ths8200.c

@@ -58,21 +58,11 @@ static inline struct ths8200_state *to_state(struct v4l2_subdev *sd)
 	return container_of(sd, struct ths8200_state, sd);
 	return container_of(sd, struct ths8200_state, sd);
 }
 }
 
 
-static inline unsigned hblanking(const struct v4l2_bt_timings *t)
-{
-	return V4L2_DV_BT_BLANKING_WIDTH(t);
-}
-
 static inline unsigned htotal(const struct v4l2_bt_timings *t)
 static inline unsigned htotal(const struct v4l2_bt_timings *t)
 {
 {
 	return V4L2_DV_BT_FRAME_WIDTH(t);
 	return V4L2_DV_BT_FRAME_WIDTH(t);
 }
 }
 
 
-static inline unsigned vblanking(const struct v4l2_bt_timings *t)
-{
-	return V4L2_DV_BT_BLANKING_HEIGHT(t);
-}
-
 static inline unsigned vtotal(const struct v4l2_bt_timings *t)
 static inline unsigned vtotal(const struct v4l2_bt_timings *t)
 {
 {
 	return V4L2_DV_BT_FRAME_HEIGHT(t);
 	return V4L2_DV_BT_FRAME_HEIGHT(t);

+ 2 - 0
drivers/media/mmc/siano/Kconfig

@@ -6,6 +6,8 @@ config SMS_SDIO_DRV
 	tristate "Siano SMS1xxx based MDTV via SDIO interface"
 	tristate "Siano SMS1xxx based MDTV via SDIO interface"
 	depends on DVB_CORE && HAS_DMA
 	depends on DVB_CORE && HAS_DMA
 	depends on MMC
 	depends on MMC
+	depends on !RC_CORE || RC_CORE
 	select MEDIA_COMMON_OPTIONS
 	select MEDIA_COMMON_OPTIONS
+	select SMS_SIANO_MDTV
 	---help---
 	---help---
 	  Choose if you would like to have Siano's support for SDIO interface
 	  Choose if you would like to have Siano's support for SDIO interface

+ 3 - 1
drivers/media/pci/bt8xx/Kconfig

@@ -2,15 +2,17 @@ config VIDEO_BT848
 	tristate "BT848 Video For Linux"
 	tristate "BT848 Video For Linux"
 	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
 	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
 	select I2C_ALGOBIT
 	select I2C_ALGOBIT
-	select VIDEO_BTCX
 	select VIDEOBUF_DMA_SG
 	select VIDEOBUF_DMA_SG
 	depends on RC_CORE
 	depends on RC_CORE
+	depends on MEDIA_RADIO_SUPPORT
 	select VIDEO_TUNER
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_TVEEPROM
 	select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TVAUDIO if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TVAUDIO if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TDA7432 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TDA7432 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT
+	select RADIO_ADAPTERS
+	select RADIO_TEA575X
 	---help---
 	---help---
 	  Support for BT848 based frame grabber/overlay boards. This includes
 	  Support for BT848 based frame grabber/overlay boards. This includes
 	  the Miro, Hauppauge and STB boards. Please read the material in
 	  the Miro, Hauppauge and STB boards. Please read the material in

+ 1 - 1
drivers/media/pci/bt8xx/Makefile

@@ -1,6 +1,6 @@
 bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
 bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
 		       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
 		       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
-		       bttv-input.o bttv-audio-hook.o
+		       bttv-input.o bttv-audio-hook.o btcx-risc.o
 
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o
 obj-$(CONFIG_VIDEO_BT848) += bttv.o
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o

+ 0 - 6
drivers/media/pci/bt8xx/bt878.c

@@ -590,9 +590,3 @@ module_init(bt878_init_module);
 module_exit(bt878_cleanup_module);
 module_exit(bt878_cleanup_module);
 
 
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 8 - 28
drivers/media/common/btcx-risc.c → drivers/media/pci/bt8xx/btcx-risc.c

@@ -32,13 +32,9 @@
 
 
 #include "btcx-risc.h"
 #include "btcx-risc.h"
 
 
-MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)");
+static unsigned int btcx_debug;
+module_param(btcx_debug, int, 0644);
+MODULE_PARM_DESC(btcx_debug,"debug messages, default is 0 (no)");
 
 
 /* ---------------------------------------------------------- */
 /* ---------------------------------------------------------- */
 /* allocate/free risc memory                                  */
 /* allocate/free risc memory                                  */
@@ -50,7 +46,7 @@ void btcx_riscmem_free(struct pci_dev *pci,
 {
 {
 	if (NULL == risc->cpu)
 	if (NULL == risc->cpu)
 		return;
 		return;
-	if (debug) {
+	if (btcx_debug) {
 		memcnt--;
 		memcnt--;
 		printk("btcx: riscmem free [%d] dma=%lx\n",
 		printk("btcx: riscmem free [%d] dma=%lx\n",
 		       memcnt, (unsigned long)risc->dma);
 		       memcnt, (unsigned long)risc->dma);
@@ -75,7 +71,7 @@ int btcx_riscmem_alloc(struct pci_dev *pci,
 		risc->cpu  = cpu;
 		risc->cpu  = cpu;
 		risc->dma  = dma;
 		risc->dma  = dma;
 		risc->size = size;
 		risc->size = size;
-		if (debug) {
+		if (btcx_debug) {
 			memcnt++;
 			memcnt++;
 			printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n",
 			printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n",
 			       memcnt, (unsigned long)dma, cpu, size);
 			       memcnt, (unsigned long)dma, cpu, size);
@@ -141,7 +137,7 @@ btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int m
 	dx = nx - win->left;
 	dx = nx - win->left;
 	win->left  = nx;
 	win->left  = nx;
 	win->width = nw;
 	win->width = nw;
-	if (debug)
+	if (btcx_debug)
 		printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n",
 		printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n",
 		       win->width, win->height, win->left, win->top, dx);
 		       win->width, win->height, win->left, win->top, dx);
 
 
@@ -153,7 +149,7 @@ btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int m
 			nw += mask+1;
 			nw += mask+1;
 		clips[i].c.left  = nx;
 		clips[i].c.left  = nx;
 		clips[i].c.width = nw;
 		clips[i].c.width = nw;
-		if (debug)
+		if (btcx_debug)
 			printk(KERN_DEBUG "btcx:   clip align %dx%d+%d+%d\n",
 			printk(KERN_DEBUG "btcx:   clip align %dx%d+%d+%d\n",
 			       clips[i].c.width, clips[i].c.height,
 			       clips[i].c.width, clips[i].c.height,
 			       clips[i].c.left, clips[i].c.top);
 			       clips[i].c.left, clips[i].c.top);
@@ -234,7 +230,7 @@ btcx_calc_skips(int line, int width, int *maxy,
 	*nskips = skip;
 	*nskips = skip;
 	*maxy = maxline;
 	*maxy = maxline;
 
 
-	if (debug) {
+	if (btcx_debug) {
 		printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline);
 		printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline);
 		for (skip = 0; skip < *nskips; skip++) {
 		for (skip = 0; skip < *nskips; skip++) {
 			printk(" %d-%d",skips[skip].start,skips[skip].end);
 			printk(" %d-%d",skips[skip].start,skips[skip].end);
@@ -242,19 +238,3 @@ btcx_calc_skips(int line, int width, int *maxy,
 		printk("\n");
 		printk("\n");
 	}
 	}
 }
 }
-
-/* ---------------------------------------------------------- */
-
-EXPORT_SYMBOL(btcx_riscmem_alloc);
-EXPORT_SYMBOL(btcx_riscmem_free);
-
-EXPORT_SYMBOL(btcx_screen_clips);
-EXPORT_SYMBOL(btcx_align);
-EXPORT_SYMBOL(btcx_sort_clips);
-EXPORT_SYMBOL(btcx_calc_skips);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 26 - 0
drivers/media/pci/bt8xx/btcx-risc.h

@@ -0,0 +1,26 @@
+struct btcx_riscmem {
+	unsigned int   size;
+	__le32         *cpu;
+	__le32         *jmp;
+	dma_addr_t     dma;
+};
+
+struct btcx_skiplist {
+	int start;
+	int end;
+};
+
+int  btcx_riscmem_alloc(struct pci_dev *pci,
+			struct btcx_riscmem *risc,
+			unsigned int size);
+void btcx_riscmem_free(struct pci_dev *pci,
+		       struct btcx_riscmem *risc);
+
+int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
+		      struct v4l2_clip *clips, unsigned int n);
+int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
+	       unsigned int n, int mask);
+void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
+void btcx_calc_skips(int line, int width, int *maxy,
+		     struct btcx_skiplist *skips, unsigned int *nskips,
+		     const struct v4l2_clip *clips, unsigned int nclips);

+ 110 - 214
drivers/media/pci/bt8xx/bttv-cards.c

@@ -84,8 +84,7 @@ static void gv800s_init(struct bttv *btv);
 static void td3116_muxsel(struct bttv *btv, unsigned int input);
 static void td3116_muxsel(struct bttv *btv, unsigned int input);
 
 
 static int terratec_active_radio_upgrade(struct bttv *btv);
 static int terratec_active_radio_upgrade(struct bttv *btv);
-static int tea5757_read(struct bttv *btv);
-static int tea5757_write(struct bttv *btv, int value);
+static int tea575x_init(struct bttv *btv);
 static void identify_by_eeprom(struct bttv *btv,
 static void identify_by_eeprom(struct bttv *btv,
 			       unsigned char eeprom_data[256]);
 			       unsigned char eeprom_data[256]);
 static int pvr_boot(struct bttv *btv);
 static int pvr_boot(struct bttv *btv);
@@ -3085,12 +3084,12 @@ static void miro_pinnacle_gpio(struct bttv *btv)
 		if (0 == (gpio & 0x20)) {
 		if (0 == (gpio & 0x20)) {
 			btv->has_radio = 1;
 			btv->has_radio = 1;
 			if (!miro_fmtuner[id]) {
 			if (!miro_fmtuner[id]) {
-				btv->has_matchbox = 1;
-				btv->mbox_we    = (1<<6);
-				btv->mbox_most  = (1<<7);
-				btv->mbox_clk   = (1<<8);
-				btv->mbox_data  = (1<<9);
-				btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+				btv->has_tea575x = 1;
+				btv->tea_gpio.wren = 6;
+				btv->tea_gpio.most = 7;
+				btv->tea_gpio.clk  = 8;
+				btv->tea_gpio.data = 9;
+				tea575x_init(btv);
 			}
 			}
 		} else {
 		} else {
 			btv->has_radio = 0;
 			btv->has_radio = 0;
@@ -3104,7 +3103,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
 		pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
 		pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
 			btv->c.nr, id+1, btv->tuner_type,
 			btv->c.nr, id+1, btv->tuner_type,
 			!btv->has_radio ? "no" :
 			!btv->has_radio ? "no" :
-			(btv->has_matchbox ? "matchbox" : "fmtuner"),
+			(btv->has_tea575x ? "tea575x" : "fmtuner"),
 			(-1 == msp) ? "no" : "yes");
 			(-1 == msp) ? "no" : "yes");
 	} else {
 	} else {
 		/* new cards with microtune tuner */
 		/* new cards with microtune tuner */
@@ -3382,12 +3381,12 @@ void bttv_init_card2(struct bttv *btv)
 		break;
 		break;
 	case BTTV_BOARD_VHX:
 	case BTTV_BOARD_VHX:
 		btv->has_radio    = 1;
 		btv->has_radio    = 1;
-		btv->has_matchbox = 1;
-		btv->mbox_we      = 0x20;
-		btv->mbox_most    = 0;
-		btv->mbox_clk     = 0x08;
-		btv->mbox_data    = 0x10;
-		btv->mbox_mask    = 0x38;
+		btv->has_tea575x  = 1;
+		btv->tea_gpio.wren = 5;
+		btv->tea_gpio.most = 6;
+		btv->tea_gpio.clk  = 3;
+		btv->tea_gpio.data = 4;
+		tea575x_init(btv);
 		break;
 		break;
 	case BTTV_BOARD_VOBIS_BOOSTAR:
 	case BTTV_BOARD_VOBIS_BOOSTAR:
 	case BTTV_BOARD_TERRATV:
 	case BTTV_BOARD_TERRATV:
@@ -3745,33 +3744,112 @@ static void hauppauge_eeprom(struct bttv *btv)
 		btv->radio_uses_msp_demodulator = 1;
 		btv->radio_uses_msp_demodulator = 1;
 }
 }
 
 
-static int terratec_active_radio_upgrade(struct bttv *btv)
+/* ----------------------------------------------------------------------- */
+
+static void bttv_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
+{
+	struct bttv *btv = tea->private_data;
+	struct bttv_tea575x_gpio gpio = btv->tea_gpio;
+	u16 val = 0;
+
+	val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0;
+	val |= (pins & TEA575X_CLK)  ? (1 << gpio.clk)  : 0;
+	val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0;
+
+	gpio_bits((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren), val);
+	if (btv->mbox_ior) {
+		/* IOW and CSEL active */
+		gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
+		udelay(5);
+		/* all inactive */
+		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+	}
+}
+
+static u8 bttv_tea575x_get_pins(struct snd_tea575x *tea)
+{
+	struct bttv *btv = tea->private_data;
+	struct bttv_tea575x_gpio gpio = btv->tea_gpio;
+	u8 ret = 0;
+	u16 val;
+
+	if (btv->mbox_ior) {
+		/* IOR and CSEL active */
+		gpio_bits(btv->mbox_ior | btv->mbox_csel, 0);
+		udelay(5);
+	}
+	val = gpio_read();
+	if (btv->mbox_ior) {
+		/* all inactive */
+		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+	}
+
+	if (val & (1 << gpio.data))
+		ret |= TEA575X_DATA;
+	if (val & (1 << gpio.most))
+		ret |= TEA575X_MOST;
+
+	return ret;
+}
+
+static void bttv_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
 {
-	int freq;
+	struct bttv *btv = tea->private_data;
+	struct bttv_tea575x_gpio gpio = btv->tea_gpio;
+	u32 mask = (1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) |
+		   (1 << gpio.most);
+
+	if (output)
+		gpio_inout(mask, (1 << gpio.data) | (1 << gpio.clk) |
+				 (1 << gpio.wren));
+	else
+		gpio_inout(mask, (1 << gpio.clk) | (1 << gpio.wren));
+}
+
+static struct snd_tea575x_ops bttv_tea_ops = {
+	.set_pins = bttv_tea575x_set_pins,
+	.get_pins = bttv_tea575x_get_pins,
+	.set_direction = bttv_tea575x_set_direction,
+};
+
+static int tea575x_init(struct bttv *btv)
+{
+	btv->tea.private_data = btv;
+	btv->tea.ops = &bttv_tea_ops;
+	if (!snd_tea575x_hw_init(&btv->tea)) {
+		pr_info("%d: detected TEA575x radio\n", btv->c.nr);
+		btv->tea.mute = false;
+		return 0;
+	}
+
+	btv->has_tea575x = 0;
+	btv->has_radio = 0;
 
 
+	return -ENODEV;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int terratec_active_radio_upgrade(struct bttv *btv)
+{
 	btv->has_radio    = 1;
 	btv->has_radio    = 1;
-	btv->has_matchbox = 1;
-	btv->mbox_we      = 0x10;
-	btv->mbox_most    = 0x20;
-	btv->mbox_clk     = 0x08;
-	btv->mbox_data    = 0x04;
-	btv->mbox_mask    = 0x3c;
+	btv->has_tea575x  = 1;
+	btv->tea_gpio.wren = 4;
+	btv->tea_gpio.most = 5;
+	btv->tea_gpio.clk  = 3;
+	btv->tea_gpio.data = 2;
 
 
 	btv->mbox_iow     = 1 <<  8;
 	btv->mbox_iow     = 1 <<  8;
 	btv->mbox_ior     = 1 <<  9;
 	btv->mbox_ior     = 1 <<  9;
 	btv->mbox_csel    = 1 << 10;
 	btv->mbox_csel    = 1 << 10;
 
 
-	freq=88000/62.5;
-	tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */
-	if (0x1ed8 == tea5757_read(btv)) {
+	if (!tea575x_init(btv)) {
 		pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr);
 		pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr);
-		btv->has_radio    = 1;
-		btv->has_saa6588  = 1;
-		btv->has_matchbox = 1;
-	} else {
-		btv->has_radio    = 0;
-		btv->has_matchbox = 0;
+		btv->has_saa6588 = 1;
 	}
 	}
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -4292,181 +4370,6 @@ init_PCI8604PW(struct bttv *btv)
 	}
 	}
 }
 }
 
 
-
-
-/* ----------------------------------------------------------------------- */
-/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports     */
-/*
- * Copyright (c) 1999 Csaba Halasz <qgehali@uni-miskolc.hu>
- * This code is placed under the terms of the GNU General Public License
- *
- * Brutally hacked by Dan Sheridan <dan.sheridan@contact.org.uk> djs52 8/3/00
- */
-
-static void bus_low(struct bttv *btv, int bit)
-{
-	if (btv->mbox_ior) {
-		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-		udelay(5);
-	}
-
-	gpio_bits(bit,0);
-	udelay(5);
-
-	if (btv->mbox_ior) {
-		gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
-		udelay(5);
-	}
-}
-
-static void bus_high(struct bttv *btv, int bit)
-{
-	if (btv->mbox_ior) {
-		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-		udelay(5);
-	}
-
-	gpio_bits(bit,bit);
-	udelay(5);
-
-	if (btv->mbox_ior) {
-		gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
-		udelay(5);
-	}
-}
-
-static int bus_in(struct bttv *btv, int bit)
-{
-	if (btv->mbox_ior) {
-		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-		udelay(5);
-
-		gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
-		udelay(5);
-	}
-	return gpio_read() & (bit);
-}
-
-/* TEA5757 register bits */
-#define TEA_FREQ		0:14
-#define TEA_BUFFER		15:15
-
-#define TEA_SIGNAL_STRENGTH	16:17
-
-#define TEA_PORT1		18:18
-#define TEA_PORT0		19:19
-
-#define TEA_BAND		20:21
-#define TEA_BAND_FM		0
-#define TEA_BAND_MW		1
-#define TEA_BAND_LW		2
-#define TEA_BAND_SW		3
-
-#define TEA_MONO		22:22
-#define TEA_ALLOW_STEREO	0
-#define TEA_FORCE_MONO		1
-
-#define TEA_SEARCH_DIRECTION	23:23
-#define TEA_SEARCH_DOWN		0
-#define TEA_SEARCH_UP		1
-
-#define TEA_STATUS		24:24
-#define TEA_STATUS_TUNED	0
-#define TEA_STATUS_SEARCHING	1
-
-/* Low-level stuff */
-static int tea5757_read(struct bttv *btv)
-{
-	unsigned long timeout;
-	int value = 0;
-	int i;
-
-	/* better safe than sorry */
-	gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we);
-
-	if (btv->mbox_ior) {
-		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-		udelay(5);
-	}
-
-	if (bttv_gpio)
-		bttv_gpio_tracking(btv,"tea5757 read");
-
-	bus_low(btv,btv->mbox_we);
-	bus_low(btv,btv->mbox_clk);
-
-	udelay(10);
-	timeout= jiffies + msecs_to_jiffies(1000);
-
-	/* wait for DATA line to go low; error if it doesn't */
-	while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
-		schedule();
-	if (bus_in(btv,btv->mbox_data)) {
-		pr_warn("%d: tea5757: read timeout\n", btv->c.nr);
-		return -1;
-	}
-
-	dprintk("%d: tea5757:", btv->c.nr);
-	for (i = 0; i < 24; i++) {
-		udelay(5);
-		bus_high(btv,btv->mbox_clk);
-		udelay(5);
-		dprintk_cont("%c",
-			     bus_in(btv, btv->mbox_most) == 0 ? 'T' : '-');
-		bus_low(btv,btv->mbox_clk);
-		value <<= 1;
-		value |= (bus_in(btv,btv->mbox_data) == 0)?0:1;  /* MSB first */
-		dprintk_cont("%c",
-			     bus_in(btv, btv->mbox_most) == 0 ? 'S' : 'M');
-	}
-	dprintk_cont("\n");
-	dprintk("%d: tea5757: read 0x%X\n", btv->c.nr, value);
-	return value;
-}
-
-static int tea5757_write(struct bttv *btv, int value)
-{
-	int i;
-	int reg = value;
-
-	gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data);
-
-	if (btv->mbox_ior) {
-		gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-			  btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-		udelay(5);
-	}
-	if (bttv_gpio)
-		bttv_gpio_tracking(btv,"tea5757 write");
-
-	dprintk("%d: tea5757: write 0x%X\n", btv->c.nr, value);
-	bus_low(btv,btv->mbox_clk);
-	bus_high(btv,btv->mbox_we);
-	for (i = 0; i < 25; i++) {
-		if (reg & 0x1000000)
-			bus_high(btv,btv->mbox_data);
-		else
-			bus_low(btv,btv->mbox_data);
-		reg <<= 1;
-		bus_high(btv,btv->mbox_clk);
-		udelay(10);
-		bus_low(btv,btv->mbox_clk);
-		udelay(10);
-	}
-	bus_low(btv,btv->mbox_we);  /* unmute !!! */
-	return 0;
-}
-
-void tea5757_set_freq(struct bttv *btv, unsigned short freq)
-{
-	dprintk("tea5757_set_freq %d\n",freq);
-	tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
-}
-
 /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
 /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
  *
  *
  * This is needed because rv605 don't use a normal multiplex, but a crosspoint
  * This is needed because rv605 don't use a normal multiplex, but a crosspoint
@@ -5048,10 +4951,3 @@ int bttv_handle_chipset(struct bttv *btv)
 		pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
 		pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
 	return 0;
 	return 0;
 }
 }
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 35 - 9
drivers/media/pci/bt8xx/bttv-driver.c

@@ -1874,8 +1874,10 @@ static void bttv_set_frequency(struct bttv *btv, const struct v4l2_frequency *f)
 	if (new_freq.type == V4L2_TUNER_RADIO) {
 	if (new_freq.type == V4L2_TUNER_RADIO) {
 		radio_enable(btv);
 		radio_enable(btv);
 		btv->radio_freq = new_freq.frequency;
 		btv->radio_freq = new_freq.frequency;
-		if (btv->has_matchbox)
-			tea5757_set_freq(btv, btv->radio_freq);
+		if (btv->has_tea575x) {
+			btv->tea.freq = btv->radio_freq;
+			snd_tea575x_set_freq(&btv->tea);
+		}
 	} else {
 	} else {
 		btv->tv_freq = new_freq.frequency;
 		btv->tv_freq = new_freq.frequency;
 	}
 	}
@@ -2513,6 +2515,8 @@ static int bttv_querycap(struct file *file, void  *priv,
 		if (btv->has_saa6588)
 		if (btv->has_saa6588)
 			cap->device_caps |= V4L2_CAP_READWRITE |
 			cap->device_caps |= V4L2_CAP_READWRITE |
 						V4L2_CAP_RDS_CAPTURE;
 						V4L2_CAP_RDS_CAPTURE;
+		if (btv->has_tea575x)
+			cap->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -3242,6 +3246,9 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
 	if (btv->audio_mode_gpio)
 	if (btv->audio_mode_gpio)
 		btv->audio_mode_gpio(btv, t, 0);
 		btv->audio_mode_gpio(btv, t, 0);
 
 
+	if (btv->has_tea575x)
+		return snd_tea575x_g_tuner(&btv->tea, t);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3259,6 +3266,30 @@ static int radio_s_tuner(struct file *file, void *priv,
 	return 0;
 	return 0;
 }
 }
 
 
+static int radio_s_hw_freq_seek(struct file *file, void *priv,
+					const struct v4l2_hw_freq_seek *a)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (btv->has_tea575x)
+		return snd_tea575x_s_hw_freq_seek(file, &btv->tea, a);
+
+	return -ENOTTY;
+}
+
+static int radio_enum_freq_bands(struct file *file, void *priv,
+					 struct v4l2_frequency_band *band)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (btv->has_tea575x)
+		return snd_tea575x_enum_freq_bands(&btv->tea, band);
+
+	return -ENOTTY;
+}
+
 static ssize_t radio_read(struct file *file, char __user *data,
 static ssize_t radio_read(struct file *file, char __user *data,
 			 size_t count, loff_t *ppos)
 			 size_t count, loff_t *ppos)
 {
 {
@@ -3316,6 +3347,8 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
 	.vidioc_s_tuner         = radio_s_tuner,
 	.vidioc_s_tuner         = radio_s_tuner,
 	.vidioc_g_frequency     = bttv_g_frequency,
 	.vidioc_g_frequency     = bttv_g_frequency,
 	.vidioc_s_frequency     = bttv_s_frequency,
 	.vidioc_s_frequency     = bttv_s_frequency,
+	.vidioc_s_hw_freq_seek	= radio_s_hw_freq_seek,
+	.vidioc_enum_freq_bands	= radio_enum_freq_bands,
 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 };
@@ -3884,7 +3917,6 @@ static struct video_device *vdev_init(struct bttv *btv,
 	*vfd = *template;
 	*vfd = *template;
 	vfd->v4l2_dev = &btv->c.v4l2_dev;
 	vfd->v4l2_dev = &btv->c.v4l2_dev;
 	vfd->release = video_device_release;
 	vfd->release = video_device_release;
-	vfd->debug   = bttv_debug;
 	video_set_drvdata(vfd, btv);
 	video_set_drvdata(vfd, btv);
 	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
 	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
 		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
 		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
@@ -4429,9 +4461,3 @@ static void __exit bttv_cleanup_module(void)
 
 
 module_init(bttv_init_module);
 module_init(bttv_init_module);
 module_exit(bttv_cleanup_module);
 module_exit(bttv_cleanup_module);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 0 - 6
drivers/media/pci/bt8xx/bttv-gpio.c

@@ -181,9 +181,3 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
 	btwrite(data,BT848_GPIO_DATA);
 	btwrite(data,BT848_GPIO_DATA);
 	spin_unlock_irqrestore(&btv->gpio_lock,flags);
 	spin_unlock_irqrestore(&btv->gpio_lock,flags);
 }
 }
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 0 - 6
drivers/media/pci/bt8xx/bttv-if.c

@@ -113,9 +113,3 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
 		bttv_gpio_tracking(btv,"extern write");
 		bttv_gpio_tracking(btv,"extern write");
 	return 0;
 	return 0;
 }
 }
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 0 - 6
drivers/media/pci/bt8xx/bttv-risc.c

@@ -901,9 +901,3 @@ bttv_overlay_risc(struct bttv *btv,
 	buf->vb.field = ov->field;
 	buf->vb.field = ov->field;
 	return 0;
 	return 0;
 }
 }
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 0 - 7
drivers/media/pci/bt8xx/bttv-vbi.c

@@ -450,10 +450,3 @@ void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm)
 	/* See bttv_vbi_fmt_set(). */
 	/* See bttv_vbi_fmt_set(). */
 	f->end                  = tvnorm->vbistart[0] * 2 + 2;
 	f->end                  = tvnorm->vbistart[0] * 2 + 2;
 }
 }
-
-/* ----------------------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 0 - 5
drivers/media/pci/bt8xx/bttv.h

@@ -378,8 +378,3 @@ extern void bttv_input_fini(struct bttv *dev);
 extern void bttv_input_irq(struct bttv *dev);
 extern void bttv_input_irq(struct bttv *dev);
 
 
 #endif /* _BTTV_H_ */
 #endif /* _BTTV_H_ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 8 - 12
drivers/media/pci/bt8xx/bttvp.h

@@ -42,6 +42,7 @@
 #include <media/tveeprom.h>
 #include <media/tveeprom.h>
 #include <media/rc-core.h>
 #include <media/rc-core.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/ir-kbd-i2c.h>
+#include <media/tea575x.h>
 
 
 #include "bt848.h"
 #include "bt848.h"
 #include "bttv.h"
 #include "bttv.h"
@@ -359,6 +360,10 @@ struct bttv_suspend_state {
 	struct bttv_buffer     *vbi;
 	struct bttv_buffer     *vbi;
 };
 };
 
 
+struct bttv_tea575x_gpio {
+	u8 data, clk, wren, most;
+};
+
 struct bttv {
 struct bttv {
 	struct bttv_core c;
 	struct bttv_core c;
 
 
@@ -445,12 +450,9 @@ struct bttv {
 
 
 	/* miro/pinnacle + Aimslab VHX
 	/* miro/pinnacle + Aimslab VHX
 	   philips matchbox (tea5757 radio tuner) support */
 	   philips matchbox (tea5757 radio tuner) support */
-	int has_matchbox;
-	int mbox_we;
-	int mbox_data;
-	int mbox_clk;
-	int mbox_most;
-	int mbox_mask;
+	int has_tea575x;
+	struct bttv_tea575x_gpio tea_gpio;
+	struct snd_tea575x tea;
 
 
 	/* ISA stuff (Terratec Active Radio Upgrade) */
 	/* ISA stuff (Terratec Active Radio Upgrade) */
 	int mbox_ior;
 	int mbox_ior;
@@ -531,9 +533,3 @@ static inline unsigned int bttv_muxsel(const struct bttv *btv,
 #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
 #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
 
 
 #endif /* _BTTVP_H_ */
 #endif /* _BTTVP_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 1 - 0
drivers/media/pci/cx23885/Kconfig

@@ -41,6 +41,7 @@ config VIDEO_CX23885
 	select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+	select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
 	---help---
 	---help---
 	  This is a video4linux driver for Conexant 23885 based
 	  This is a video4linux driver for Conexant 23885 based

+ 43 - 0
drivers/media/pci/cx23885/cx23885-cards.c

@@ -710,6 +710,11 @@ struct cx23885_board cx23885_boards[] = {
 		.portb		= CX23885_MPEG_DVB,
 		.portb		= CX23885_MPEG_DVB,
 		.portc		= CX23885_MPEG_DVB,
 		.portc		= CX23885_MPEG_DVB,
 	},
 	},
+	[CX23885_BOARD_HAUPPAUGE_HVR5525] = {
+		.name		= "Hauppauge WinTV-HVR5525",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+	},
 };
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
 
@@ -993,6 +998,10 @@ struct cx23885_subid cx23885_subids[] = {
 		.subvendor = 0x4254,
 		.subvendor = 0x4254,
 		.subdevice = 0x0982,
 		.subdevice = 0x0982,
 		.card      = CX23885_BOARD_DVBSKY_T982,
 		.card      = CX23885_BOARD_DVBSKY_T982,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0xf038,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR5525,
 	},
 	},
 };
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1165,6 +1174,8 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
 	case 85721:
 	case 85721:
 		/* WinTV-HVR1290 (PCIe, OEM, RCA in, IR,
 		/* WinTV-HVR1290 (PCIe, OEM, RCA in, IR,
 			Dual channel ATSC and Basic analog */
 			Dual channel ATSC and Basic analog */
+	case 150329:
+		/* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */
 		break;
 		break;
 	default:
 	default:
 		printk(KERN_WARNING "%s: warning: "
 		printk(KERN_WARNING "%s: warning: "
@@ -1637,6 +1648,29 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
 		msleep(100);
 		msleep(100);
 		cx23885_gpio_set(dev, GPIO_2);
 		cx23885_gpio_set(dev, GPIO_2);
 		break;
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR5525:
+		/*
+		 * GPIO-00 IR_WIDE
+		 * GPIO-02 wake#
+		 * GPIO-03 VAUX Pres.
+		 * GPIO-07 PROG#
+		 * GPIO-08 SAT_RESN
+		 * GPIO-09 TER_RESN
+		 * GPIO-10 B2_SENSE
+		 * GPIO-11 B1_SENSE
+		 * GPIO-15 IR_LED_STATUS
+		 * GPIO-19 IR_NARROW
+		 * GPIO-20 Blauster1
+		 * ALTGPIO VAUX_SWITCH
+		 * AUX_PLL_CLK : Blaster2
+		 */
+		/* Put the parts into reset and back */
+		cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1);
+		cx23885_gpio_clear(dev, GPIO_8 | GPIO_9);
+		msleep(100);
+		cx23885_gpio_set(dev, GPIO_8 | GPIO_9);
+		msleep(100);
+		break;
 	}
 	}
 }
 }
 
 
@@ -1879,6 +1913,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 	case CX23885_BOARD_HAUPPAUGE_HVR4400:
 	case CX23885_BOARD_HAUPPAUGE_HVR4400:
 	case CX23885_BOARD_HAUPPAUGE_STARBURST:
 	case CX23885_BOARD_HAUPPAUGE_STARBURST:
 	case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
 	case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
+	case CX23885_BOARD_HAUPPAUGE_HVR5525:
 		if (dev->i2c_bus[0].i2c_rc == 0)
 		if (dev->i2c_bus[0].i2c_rc == 0)
 			hauppauge_eeprom(dev, eeprom+0xc0);
 			hauppauge_eeprom(dev, eeprom+0xc0);
 		break;
 		break;
@@ -2008,6 +2043,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR5525:
+		ts1->gen_ctrl_val  = 0x5; /* Parallel */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:

+ 235 - 141
drivers/media/pci/cx23885/cx23885-dvb.c

@@ -74,6 +74,7 @@
 #include "sp2.h"
 #include "sp2.h"
 #include "m88ds3103.h"
 #include "m88ds3103.h"
 #include "m88ts2022.h"
 #include "m88ts2022.h"
+#include "m88rs6000t.h"
 
 
 static unsigned int debug;
 static unsigned int debug;
 
 
@@ -915,6 +916,16 @@ static const struct m88ds3103_config dvbsky_s952_portc_m88ds3103_config = {
 	.agc = 0x99,
 	.agc = 0x99,
 };
 };
 
 
+static const struct m88ds3103_config hauppauge_hvr5525_m88ds3103_config = {
+	.i2c_addr = 0x69,
+	.clock = 27000000,
+	.i2c_wr_max = 33,
+	.ts_mode = M88DS3103_TS_PARALLEL,
+	.ts_clk = 16000,
+	.ts_clk_pol = 1,
+	.agc = 0x99,
+};
+
 static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
 static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
 {
 {
 	struct cx23885_dev *dev = (struct cx23885_dev *)device;
 	struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -1058,6 +1069,116 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
 	.hostbus_diversity = 1,
 	.hostbus_diversity = 1,
 };
 };
 
 
+static int dvb_register_ci_mac(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct i2c_client *client_ci = NULL;
+	struct vb2_dvb_frontend *fe0;
+
+	fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
+	if (!fe0)
+		return -EINVAL;
+
+	switch (dev->board) {
+	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
+		static struct netup_card_info cinfo;
+
+		netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+		memcpy(port->frontends.adapter.proposed_mac,
+				cinfo.port[port->nr - 1].mac, 6);
+		printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n",
+			port->nr, port->frontends.adapter.proposed_mac);
+
+		netup_ci_init(port);
+		return 0;
+		}
+	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
+		struct altera_ci_config netup_ci_cfg = {
+			.dev = dev,/* magic number to identify*/
+			.adapter = &port->frontends.adapter,/* for CI */
+			.demux = &fe0->dvb.demux,/* for hw pid filter */
+			.fpga_rw = netup_altera_fpga_rw,
+		};
+
+		altera_ci_init(&netup_ci_cfg, port->nr);
+		return 0;
+		}
+	case CX23885_BOARD_TEVII_S470: {
+		u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+		if (port->nr != 1)
+			return 0;
+
+		/* Read entire EEPROM */
+		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
+		printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
+		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
+		return 0;
+		}
+	case CX23885_BOARD_DVBSKY_T9580:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
+	case CX23885_BOARD_DVBSKY_T982: {
+		u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+		if (port->nr > 2)
+			return 0;
+
+		/* Read entire EEPROM */
+		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
+				sizeof(eeprom));
+		printk(KERN_INFO "%s port %d MAC address: %pM\n",
+			cx23885_boards[dev->board].name, port->nr,
+			eeprom + 0xc0 + (port->nr-1) * 8);
+		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +
+			(port->nr-1) * 8, 6);
+		return 0;
+		}
+	case CX23885_BOARD_DVBSKY_S950C:
+	case CX23885_BOARD_DVBSKY_T980C:
+	case CX23885_BOARD_TT_CT2_4500_CI: {
+		u8 eeprom[256]; /* 24C02 i2c eeprom */
+		struct sp2_config sp2_config;
+		struct i2c_board_info info;
+		struct cx23885_i2c *i2c_bus2 = &dev->i2c_bus[1];
+
+		/* attach CI */
+		memset(&sp2_config, 0, sizeof(sp2_config));
+		sp2_config.dvb_adap = &port->frontends.adapter;
+		sp2_config.priv = port;
+		sp2_config.ci_control = cx23885_sp2_ci_ctrl;
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		strlcpy(info.type, "sp2", I2C_NAME_SIZE);
+		info.addr = 0x40;
+		info.platform_data = &sp2_config;
+		request_module(info.type);
+		client_ci = i2c_new_device(&i2c_bus2->i2c_adap, &info);
+		if (client_ci == NULL || client_ci->dev.driver == NULL)
+			return -ENODEV;
+		if (!try_module_get(client_ci->dev.driver->owner)) {
+			i2c_unregister_device(client_ci);
+			return -ENODEV;
+		}
+		port->i2c_client_ci = client_ci;
+
+		if (port->nr != 1)
+			return 0;
+
+		/* Read entire EEPROM */
+		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
+				sizeof(eeprom));
+		printk(KERN_INFO "%s MAC address: %pM\n",
+			cx23885_boards[dev->board].name, eeprom + 0xc0);
+		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0, 6);
+		return 0;
+		}
+	}
+	return 0;
+}
+
 static int dvb_register(struct cx23885_tsport *port)
 static int dvb_register(struct cx23885_tsport *port)
 {
 {
 	struct dib7000p_ops dib7000p_ops;
 	struct dib7000p_ops dib7000p_ops;
@@ -1066,11 +1187,10 @@ static int dvb_register(struct cx23885_tsport *port)
 	struct vb2_dvb_frontend *fe0, *fe1 = NULL;
 	struct vb2_dvb_frontend *fe0, *fe1 = NULL;
 	struct si2168_config si2168_config;
 	struct si2168_config si2168_config;
 	struct si2157_config si2157_config;
 	struct si2157_config si2157_config;
-	struct sp2_config sp2_config;
 	struct m88ts2022_config m88ts2022_config;
 	struct m88ts2022_config m88ts2022_config;
 	struct i2c_board_info info;
 	struct i2c_board_info info;
 	struct i2c_adapter *adapter;
 	struct i2c_adapter *adapter;
-	struct i2c_client *client_demod = NULL, *client_tuner = NULL, *client_ci = NULL;
+	struct i2c_client *client_demod = NULL, *client_tuner = NULL;
 	const struct m88ds3103_config *p_m88ds3103_config = NULL;
 	const struct m88ds3103_config *p_m88ds3103_config = NULL;
 	int (*p_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage) = NULL;
 	int (*p_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage) = NULL;
 	int mfe_shared = 0; /* bus not shared by default */
 	int mfe_shared = 0; /* bus not shared by default */
@@ -1801,15 +1921,11 @@ static int dvb_register(struct cx23885_tsport *port)
 			request_module(info.type);
 			request_module(info.type);
 			client_tuner = i2c_new_device(adapter, &info);
 			client_tuner = i2c_new_device(adapter, &info);
 			if (client_tuner == NULL ||
 			if (client_tuner == NULL ||
-					client_tuner->dev.driver == NULL) {
-				module_put(client_demod->dev.driver->owner);
-				i2c_unregister_device(client_demod);
+					client_tuner->dev.driver == NULL)
 				goto frontend_detach;
 				goto frontend_detach;
-			}
+
 			if (!try_module_get(client_tuner->dev.driver->owner)) {
 			if (!try_module_get(client_tuner->dev.driver->owner)) {
 				i2c_unregister_device(client_tuner);
 				i2c_unregister_device(client_tuner);
-				module_put(client_demod->dev.driver->owner);
-				i2c_unregister_device(client_demod);
 				goto frontend_detach;
 				goto frontend_detach;
 			}
 			}
 			port->i2c_client_tuner = client_tuner;
 			port->i2c_client_tuner = client_tuner;
@@ -1832,8 +1948,7 @@ static int dvb_register(struct cx23885_tsport *port)
 		info.platform_data = &si2168_config;
 		info.platform_data = &si2168_config;
 		request_module(info.type);
 		request_module(info.type);
 		client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
 		client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
-		if (client_demod == NULL ||
-				client_demod->dev.driver == NULL)
+		if (client_demod == NULL || client_demod->dev.driver == NULL)
 			goto frontend_detach;
 			goto frontend_detach;
 		if (!try_module_get(client_demod->dev.driver->owner)) {
 		if (!try_module_get(client_demod->dev.driver->owner)) {
 			i2c_unregister_device(client_demod);
 			i2c_unregister_device(client_demod);
@@ -1851,15 +1966,10 @@ static int dvb_register(struct cx23885_tsport *port)
 		request_module(info.type);
 		request_module(info.type);
 		client_tuner = i2c_new_device(adapter, &info);
 		client_tuner = i2c_new_device(adapter, &info);
 		if (client_tuner == NULL ||
 		if (client_tuner == NULL ||
-				client_tuner->dev.driver == NULL) {
-			module_put(client_demod->dev.driver->owner);
-			i2c_unregister_device(client_demod);
+				client_tuner->dev.driver == NULL)
 			goto frontend_detach;
 			goto frontend_detach;
-		}
 		if (!try_module_get(client_tuner->dev.driver->owner)) {
 		if (!try_module_get(client_tuner->dev.driver->owner)) {
 			i2c_unregister_device(client_tuner);
 			i2c_unregister_device(client_tuner);
-			module_put(client_demod->dev.driver->owner);
-			i2c_unregister_device(client_demod);
 			goto frontend_detach;
 			goto frontend_detach;
 		}
 		}
 		port->i2c_client_tuner = client_tuner;
 		port->i2c_client_tuner = client_tuner;
@@ -1885,8 +1995,7 @@ static int dvb_register(struct cx23885_tsport *port)
 		info.platform_data = &m88ts2022_config;
 		info.platform_data = &m88ts2022_config;
 		request_module(info.type);
 		request_module(info.type);
 		client_tuner = i2c_new_device(adapter, &info);
 		client_tuner = i2c_new_device(adapter, &info);
-		if (client_tuner == NULL ||
-				client_tuner->dev.driver == NULL)
+		if (client_tuner == NULL || client_tuner->dev.driver == NULL)
 			goto frontend_detach;
 			goto frontend_detach;
 		if (!try_module_get(client_tuner->dev.driver->owner)) {
 		if (!try_module_get(client_tuner->dev.driver->owner)) {
 			i2c_unregister_device(client_tuner);
 			i2c_unregister_device(client_tuner);
@@ -1932,8 +2041,7 @@ static int dvb_register(struct cx23885_tsport *port)
 		info.platform_data = &m88ts2022_config;
 		info.platform_data = &m88ts2022_config;
 		request_module(info.type);
 		request_module(info.type);
 		client_tuner = i2c_new_device(adapter, &info);
 		client_tuner = i2c_new_device(adapter, &info);
-		if (client_tuner == NULL ||
-				client_tuner->dev.driver == NULL)
+		if (client_tuner == NULL || client_tuner->dev.driver == NULL)
 			goto frontend_detach;
 			goto frontend_detach;
 		if (!try_module_get(client_tuner->dev.driver->owner)) {
 		if (!try_module_get(client_tuner->dev.driver->owner)) {
 			i2c_unregister_device(client_tuner);
 			i2c_unregister_device(client_tuner);
@@ -1978,8 +2086,7 @@ static int dvb_register(struct cx23885_tsport *port)
 		info.platform_data = &si2168_config;
 		info.platform_data = &si2168_config;
 		request_module(info.type);
 		request_module(info.type);
 		client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
 		client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
-		if (client_demod == NULL ||
-				client_demod->dev.driver == NULL)
+		if (client_demod == NULL || client_demod->dev.driver == NULL)
 			goto frontend_detach;
 			goto frontend_detach;
 		if (!try_module_get(client_demod->dev.driver->owner)) {
 		if (!try_module_get(client_demod->dev.driver->owner)) {
 			i2c_unregister_device(client_demod);
 			i2c_unregister_device(client_demod);
@@ -1997,20 +2104,101 @@ static int dvb_register(struct cx23885_tsport *port)
 		request_module(info.type);
 		request_module(info.type);
 		client_tuner = i2c_new_device(adapter, &info);
 		client_tuner = i2c_new_device(adapter, &info);
 		if (client_tuner == NULL ||
 		if (client_tuner == NULL ||
-				client_tuner->dev.driver == NULL) {
-			module_put(client_demod->dev.driver->owner);
-			i2c_unregister_device(client_demod);
+				client_tuner->dev.driver == NULL)
 			goto frontend_detach;
 			goto frontend_detach;
-		}
 		if (!try_module_get(client_tuner->dev.driver->owner)) {
 		if (!try_module_get(client_tuner->dev.driver->owner)) {
 			i2c_unregister_device(client_tuner);
 			i2c_unregister_device(client_tuner);
-			module_put(client_demod->dev.driver->owner);
-			i2c_unregister_device(client_demod);
-			port->i2c_client_demod = NULL;
 			goto frontend_detach;
 			goto frontend_detach;
 		}
 		}
 		port->i2c_client_tuner = client_tuner;
 		port->i2c_client_tuner = client_tuner;
 		break;
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR5525:
+		switch (port->nr) {
+		struct m88rs6000t_config m88rs6000t_config;
+
+		/* port b - satellite */
+		case 1:
+			/* attach frontend */
+			fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+					&hauppauge_hvr5525_m88ds3103_config,
+					&dev->i2c_bus[0].i2c_adap, &adapter);
+			if (fe0->dvb.frontend == NULL)
+				break;
+
+			/* attach SEC */
+			if (!dvb_attach(a8293_attach, fe0->dvb.frontend,
+					&dev->i2c_bus[0].i2c_adap,
+					&hauppauge_a8293_config))
+				goto frontend_detach;
+
+			/* attach tuner */
+			memset(&m88rs6000t_config, 0, sizeof(m88rs6000t_config));
+			m88rs6000t_config.fe = fe0->dvb.frontend;
+			memset(&info, 0, sizeof(struct i2c_board_info));
+			strlcpy(info.type, "m88rs6000t", I2C_NAME_SIZE);
+			info.addr = 0x21;
+			info.platform_data = &m88rs6000t_config;
+			request_module("%s", info.type);
+			client_tuner = i2c_new_device(adapter, &info);
+			if (!client_tuner || !client_tuner->dev.driver)
+				goto frontend_detach;
+			if (!try_module_get(client_tuner->dev.driver->owner)) {
+				i2c_unregister_device(client_tuner);
+				goto frontend_detach;
+			}
+			port->i2c_client_tuner = client_tuner;
+
+			/* delegate signal strength measurement to tuner */
+			fe0->dvb.frontend->ops.read_signal_strength =
+				fe0->dvb.frontend->ops.tuner_ops.get_rf_strength;
+			break;
+		/* port c - terrestrial/cable */
+		case 2:
+			/* attach frontend */
+			memset(&si2168_config, 0, sizeof(si2168_config));
+			si2168_config.i2c_adapter = &adapter;
+			si2168_config.fe = &fe0->dvb.frontend;
+			si2168_config.ts_mode = SI2168_TS_SERIAL;
+			memset(&info, 0, sizeof(struct i2c_board_info));
+			strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+			info.addr = 0x64;
+			info.platform_data = &si2168_config;
+			request_module("%s", info.type);
+			client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info);
+			if (!client_demod || !client_demod->dev.driver)
+				goto frontend_detach;
+			if (!try_module_get(client_demod->dev.driver->owner)) {
+				i2c_unregister_device(client_demod);
+				goto frontend_detach;
+			}
+			port->i2c_client_demod = client_demod;
+
+			/* attach tuner */
+			memset(&si2157_config, 0, sizeof(si2157_config));
+			si2157_config.fe = fe0->dvb.frontend;
+			memset(&info, 0, sizeof(struct i2c_board_info));
+			strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+			info.addr = 0x60;
+			info.platform_data = &si2157_config;
+			request_module("%s", info.type);
+			client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info);
+			if (!client_tuner || !client_tuner->dev.driver) {
+				module_put(client_demod->dev.driver->owner);
+				i2c_unregister_device(client_demod);
+				port->i2c_client_demod = NULL;
+				goto frontend_detach;
+			}
+			if (!try_module_get(client_tuner->dev.driver->owner)) {
+				i2c_unregister_device(client_tuner);
+				module_put(client_demod->dev.driver->owner);
+				i2c_unregister_device(client_demod);
+				port->i2c_client_demod = NULL;
+				goto frontend_detach;
+			}
+			port->i2c_client_tuner = client_tuner;
+			break;
+		}
+		break;
 	default:
 	default:
 		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
 		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
 			" isn't supported yet\n",
 			" isn't supported yet\n",
@@ -2047,123 +2235,29 @@ static int dvb_register(struct cx23885_tsport *port)
 	if (ret)
 	if (ret)
 		goto frontend_detach;
 		goto frontend_detach;
 
 
-	/* init CI & MAC */
-	switch (dev->board) {
-	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
-		static struct netup_card_info cinfo;
-
-		netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
-		memcpy(port->frontends.adapter.proposed_mac,
-				cinfo.port[port->nr - 1].mac, 6);
-		printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n",
-			port->nr, port->frontends.adapter.proposed_mac);
-
-		netup_ci_init(port);
-		break;
-		}
-	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
-		struct altera_ci_config netup_ci_cfg = {
-			.dev = dev,/* magic number to identify*/
-			.adapter = &port->frontends.adapter,/* for CI */
-			.demux = &fe0->dvb.demux,/* for hw pid filter */
-			.fpga_rw = netup_altera_fpga_rw,
-		};
-
-		altera_ci_init(&netup_ci_cfg, port->nr);
-		break;
-		}
-	case CX23885_BOARD_TEVII_S470: {
-		u8 eeprom[256]; /* 24C02 i2c eeprom */
-
-		if (port->nr != 1)
-			break;
-
-		/* Read entire EEPROM */
-		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
-		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
-		printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
-		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
-		break;
-		}
-	case CX23885_BOARD_DVBSKY_T9580:
-	case CX23885_BOARD_DVBSKY_S950:
-	case CX23885_BOARD_DVBSKY_S952:
-	case CX23885_BOARD_DVBSKY_T982: {
-		u8 eeprom[256]; /* 24C02 i2c eeprom */
-
-		if (port->nr > 2)
-			break;
-
-		/* Read entire EEPROM */
-		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
-		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
-				sizeof(eeprom));
-		printk(KERN_INFO "%s port %d MAC address: %pM\n",
-			cx23885_boards[dev->board].name, port->nr,
-			eeprom + 0xc0 + (port->nr-1) * 8);
-		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +
-			(port->nr-1) * 8, 6);
-		break;
-		}
-	case CX23885_BOARD_DVBSKY_S950C:
-	case CX23885_BOARD_DVBSKY_T980C:
-	case CX23885_BOARD_TT_CT2_4500_CI: {
-		u8 eeprom[256]; /* 24C02 i2c eeprom */
-
-		/* attach CI */
-		memset(&sp2_config, 0, sizeof(sp2_config));
-		sp2_config.dvb_adap = &port->frontends.adapter;
-		sp2_config.priv = port;
-		sp2_config.ci_control = cx23885_sp2_ci_ctrl;
-		memset(&info, 0, sizeof(struct i2c_board_info));
-		strlcpy(info.type, "sp2", I2C_NAME_SIZE);
-		info.addr = 0x40;
-		info.platform_data = &sp2_config;
-		request_module(info.type);
-		client_ci = i2c_new_device(&i2c_bus2->i2c_adap, &info);
-		if (client_ci == NULL ||
-				client_ci->dev.driver == NULL) {
-			if (client_tuner) {
-				module_put(client_tuner->dev.driver->owner);
-				i2c_unregister_device(client_tuner);
-			}
-			if (client_demod) {
-				module_put(client_demod->dev.driver->owner);
-				i2c_unregister_device(client_demod);
-			}
-			goto frontend_detach;
-		}
-		if (!try_module_get(client_ci->dev.driver->owner)) {
-			i2c_unregister_device(client_ci);
-			if (client_tuner) {
-				module_put(client_tuner->dev.driver->owner);
-				i2c_unregister_device(client_tuner);
-			}
-			if (client_demod) {
-				module_put(client_demod->dev.driver->owner);
-				i2c_unregister_device(client_demod);
-			}
-			goto frontend_detach;
-		}
-		port->i2c_client_ci = client_ci;
+	ret = dvb_register_ci_mac(port);
+	if (ret)
+		goto frontend_detach;
 
 
-		if (port->nr != 1)
-			break;
+	return 0;
 
 
-		/* Read entire EEPROM */
-		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
-		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
-				sizeof(eeprom));
-		printk(KERN_INFO "%s MAC address: %pM\n",
-			cx23885_boards[dev->board].name, eeprom + 0xc0);
-		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0, 6);
-		break;
-		}
+frontend_detach:
+	/* remove I2C client for tuner */
+	client_tuner = port->i2c_client_tuner;
+	if (client_tuner) {
+		module_put(client_tuner->dev.driver->owner);
+		i2c_unregister_device(client_tuner);
+		port->i2c_client_tuner = NULL;
 	}
 	}
 
 
-	return ret;
+	/* remove I2C client for demodulator */
+	client_demod = port->i2c_client_demod;
+	if (client_demod) {
+		module_put(client_demod->dev.driver->owner);
+		i2c_unregister_device(client_demod);
+		port->i2c_client_demod = NULL;
+	}
 
 
-frontend_detach:
 	port->gate_ctrl = NULL;
 	port->gate_ctrl = NULL;
 	vb2_dvb_dealloc_frontends(&port->frontends);
 	vb2_dvb_dealloc_frontends(&port->frontends);
 	return -EINVAL;
 	return -EINVAL;

+ 2 - 2
drivers/media/pci/cx23885/cx23885-i2c.c

@@ -300,8 +300,8 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
 		rc = i2c_master_recv(c, &buf, 0);
 		rc = i2c_master_recv(c, &buf, 0);
 		if (rc < 0)
 		if (rc < 0)
 			continue;
 			continue;
-		printk(KERN_INFO "%s: i2c scan: found device @ 0x%x  [%s]\n",
-		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+		printk(KERN_INFO "%s: i2c scan: found device @ 0x%04x  [%s]\n",
+		       name, i, i2c_devs[i] ? i2c_devs[i] : "???");
 	}
 	}
 }
 }
 
 

部分文件因为文件数量过多而无法显示