浏览代码

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

Pull media updates from Mauro Carvalho Chehab:
 - new DVB frontend drivers: ascot2e, cxd2841er, horus3a, lnbh25
 - new HDMI capture driver: tc358743
 - new driver for NetUP DVB new boards (netup_unidvb)
 - IR support for DVBSky cards (smipcie-ir)
 - Coda driver has gain macroblock tiling support
 - Renesas R-Car gains JPEG codec driver
 - new DVB platform driver for STi boards: c8sectpfe
 - added documentation for the media core kABI to device-drivers DocBook
 - lots of driver fixups, cleanups and improvements

* tag 'media/v4.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (297 commits)
  [media] c8sectpfe: Remove select on undefined LIBELF_32
  [media] i2c: fix platform_no_drv_owner.cocci warnings
  [media] cx231xx: Use wake_up_interruptible() instead of wake_up_interruptible_nr()
  [media] tc358743: only queue subdev notifications if devnode is set
  [media] tc358743: add missing Kconfig dependency/select
  [media] c8sectpfe: Use %pad to print 'dma_addr_t'
  [media] DocBook media: Fix typo "the the" in xml files
  [media] tc358743: make reset gpio optional
  [media] tc358743: set direction of reset gpio using devm_gpiod_get
  [media] dvbdev: document most of the functions/data structs
  [media] dvb_frontend.h: document the struct dvb_frontend
  [media] dvb-frontend.h: document struct dtv_frontend_properties
  [media] dvb-frontend.h: document struct dvb_frontend_ops
  [media] dvb: Use DVBFE_ALGO_HW where applicable
  [media] dvb_frontend.h: document struct analog_demod_ops
  [media] dvb_frontend.h: Document struct dvb_tuner_ops
  [media] Docbook: Document struct analog_parameters
  [media] dvb_frontend.h: get rid of dvbfe_modcod
  [media] add documentation for struct dvb_tuner_info
  [media] dvb_frontend: document dvb_frontend_tune_settings
  ...
Linus Torvalds 10 年之前
父节点
当前提交
9cfcc658da
共有 100 个文件被更改,包括 8680 次插入1316 次删除
  1. 34 0
      Documentation/DocBook/device-drivers.tmpl
  2. 2 1
      Documentation/DocBook/media/Makefile
  3. 2 3
      Documentation/DocBook/media/dvb/intro.xml
  4. 1 1
      Documentation/DocBook/media/v4l/controls.xml
  5. 1 1
      Documentation/DocBook/media/v4l/media-ioc-device-info.xml
  6. 19 19
      Documentation/DocBook/media/v4l/vidioc-expbuf.xml
  7. 1 1
      Documentation/DocBook/media/v4l/vidioc-g-parm.xml
  8. 1 1
      Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
  9. 13 8
      Documentation/devicetree/bindings/media/i2c/adv7604.txt
  10. 48 0
      Documentation/devicetree/bindings/media/i2c/tc358743.txt
  11. 24 0
      Documentation/devicetree/bindings/media/renesas,jpu.txt
  12. 89 0
      Documentation/devicetree/bindings/media/stih407-c8sectpfe.txt
  13. 59 0
      MAINTAINERS
  14. 1 1
      arch/sh/kernel/cpu/sh4a/clock-sh7724.c
  15. 3 6
      drivers/media/common/saa7146/saa7146_hlp.c
  16. 84 83
      drivers/media/dvb-core/dvb_ca_en50221.c
  17. 17 17
      drivers/media/dvb-core/dvb_ca_en50221.h
  18. 0 1
      drivers/media/dvb-core/dvb_frontend.c
  19. 331 79
      drivers/media/dvb-core/dvb_frontend.h
  20. 15 10
      drivers/media/dvb-core/dvb_math.h
  21. 1 1
      drivers/media/dvb-core/dvb_net.c
  22. 75 60
      drivers/media/dvb-core/dvb_ringbuffer.h
  23. 99 17
      drivers/media/dvb-core/dvbdev.h
  24. 31 1
      drivers/media/dvb-frontends/Kconfig
  25. 4 0
      drivers/media/dvb-frontends/Makefile
  26. 29 139
      drivers/media/dvb-frontends/a8293.c
  27. 0 22
      drivers/media/dvb-frontends/a8293.h
  28. 0 1
      drivers/media/dvb-frontends/af9033.c
  29. 548 0
      drivers/media/dvb-frontends/ascot2e.c
  30. 58 0
      drivers/media/dvb-frontends/ascot2e.h
  31. 0 1
      drivers/media/dvb-frontends/au8522_decoder.c
  32. 1 1
      drivers/media/dvb-frontends/cx24123.c
  33. 2727 0
      drivers/media/dvb-frontends/cxd2841er.c
  34. 65 0
      drivers/media/dvb-frontends/cxd2841er.h
  35. 43 0
      drivers/media/dvb-frontends/cxd2841er_priv.h
  36. 25 25
      drivers/media/dvb-frontends/dvb-pll.c
  37. 430 0
      drivers/media/dvb-frontends/horus3a.c
  38. 58 0
      drivers/media/dvb-frontends/horus3a.h
  39. 189 0
      drivers/media/dvb-frontends/lnbh25.c
  40. 56 0
      drivers/media/dvb-frontends/lnbh25.h
  41. 0 1
      drivers/media/dvb-frontends/m88ds3103.c
  42. 0 1
      drivers/media/dvb-frontends/rtl2830.c
  43. 0 1
      drivers/media/dvb-frontends/rtl2832.c
  44. 0 1
      drivers/media/dvb-frontends/rtl2832_sdr.c
  45. 1 1
      drivers/media/dvb-frontends/s921.c
  46. 0 1
      drivers/media/dvb-frontends/si2168.c
  47. 0 1
      drivers/media/dvb-frontends/sp2.c
  48. 13 4
      drivers/media/dvb-frontends/stv0367.c
  49. 333 492
      drivers/media/dvb-frontends/tda10071.c
  50. 1 62
      drivers/media/dvb-frontends/tda10071.h
  51. 14 6
      drivers/media/dvb-frontends/tda10071_priv.h
  52. 0 1
      drivers/media/dvb-frontends/ts2020.c
  53. 13 2
      drivers/media/i2c/Kconfig
  54. 1 0
      drivers/media/i2c/Makefile
  55. 0 1
      drivers/media/i2c/adv7170.c
  56. 0 1
      drivers/media/i2c/adv7175.c
  57. 11 1
      drivers/media/i2c/adv7180.c
  58. 0 8
      drivers/media/i2c/adv7343.c
  59. 0 7
      drivers/media/i2c/adv7393.c
  60. 1 2
      drivers/media/i2c/adv7511.c
  61. 381 105
      drivers/media/i2c/adv7604.c
  62. 21 7
      drivers/media/i2c/adv7842.c
  63. 4 4
      drivers/media/i2c/ak881x.c
  64. 0 12
      drivers/media/i2c/bt819.c
  65. 0 1
      drivers/media/i2c/bt856.c
  66. 0 1
      drivers/media/i2c/bt866.c
  67. 0 8
      drivers/media/i2c/cs5345.c
  68. 0 1
      drivers/media/i2c/cs53l32a.c
  69. 0 1
      drivers/media/i2c/cx25840/cx25840-core.c
  70. 1 0
      drivers/media/i2c/ir-kbd-i2c.c
  71. 0 1
      drivers/media/i2c/ks0127.c
  72. 0 1
      drivers/media/i2c/m52790.c
  73. 0 1
      drivers/media/i2c/msp3400-driver.c
  74. 0 1
      drivers/media/i2c/mt9v011.c
  75. 1 1
      drivers/media/i2c/mt9v032.c
  76. 0 4
      drivers/media/i2c/ov2659.c
  77. 0 1
      drivers/media/i2c/ov7640.c
  78. 0 1
      drivers/media/i2c/ov7670.c
  79. 1 1
      drivers/media/i2c/ov9650.c
  80. 0 1
      drivers/media/i2c/s5c73m3/s5c73m3-spi.c
  81. 1 0
      drivers/media/i2c/s5k6a3.c
  82. 1 4
      drivers/media/i2c/saa6588.c
  83. 0 1
      drivers/media/i2c/saa6752hs.c
  84. 0 12
      drivers/media/i2c/saa7110.c
  85. 0 1
      drivers/media/i2c/saa7115.c
  86. 0 1
      drivers/media/i2c/saa7127.c
  87. 0 8
      drivers/media/i2c/saa717x.c
  88. 0 1
      drivers/media/i2c/saa7185.c
  89. 4 4
      drivers/media/i2c/soc_camera/mt9t112.c
  90. 31 4
      drivers/media/i2c/soc_camera/tw9910.c
  91. 0 1
      drivers/media/i2c/sony-btf-mpx.c
  92. 2 13
      drivers/media/i2c/sr030pc30.c
  93. 1979 0
      drivers/media/i2c/tc358743.c
  94. 681 0
      drivers/media/i2c/tc358743_regs.h
  95. 0 8
      drivers/media/i2c/tda7432.c
  96. 0 1
      drivers/media/i2c/tda9840.c
  97. 0 1
      drivers/media/i2c/tea6415c.c
  98. 0 1
      drivers/media/i2c/tea6420.c
  99. 0 1
      drivers/media/i2c/ths7303.c
  100. 0 7
      drivers/media/i2c/tlv320aic23b.c

+ 34 - 0
Documentation/DocBook/device-drivers.tmpl

@@ -217,6 +217,40 @@ X!Isound/sound_firmware.c
 -->
   </chapter>
 
+  <chapter id="mediadev">
+     <title>Media Devices</title>
+
+     <sect1><title>Video2Linux devices</title>
+!Iinclude/media/v4l2-async.h
+!Iinclude/media/v4l2-ctrls.h
+!Iinclude/media/v4l2-dv-timings.h
+!Iinclude/media/v4l2-event.h
+!Iinclude/media/v4l2-flash-led-class.h
+!Iinclude/media/v4l2-mediabus.h
+!Iinclude/media/v4l2-mem2mem.h
+!Iinclude/media/v4l2-of.h
+!Iinclude/media/v4l2-subdev.h
+!Iinclude/media/videobuf2-core.h
+!Iinclude/media/videobuf2-memops.h
+     </sect1>
+     <sect1><title>Digital TV (DVB) devices</title>
+!Idrivers/media/dvb-core/dvb_ca_en50221.h
+!Idrivers/media/dvb-core/dvb_frontend.h
+!Idrivers/media/dvb-core/dvb_math.h
+!Idrivers/media/dvb-core/dvb_ringbuffer.h
+!Idrivers/media/dvb-core/dvbdev.h
+     </sect1>
+     <sect1><title>Remote Controller devices</title>
+!Iinclude/media/rc-core.h
+     </sect1>
+     <sect1><title>Media Controller devices</title>
+!Iinclude/media/media-device.h
+!Iinclude/media/media-devnode.h
+!Iinclude/media/media-entity.h
+     </sect1>
+
+  </chapter>
+
   <chapter id="uart16x50">
      <title>16x50 UART Driver</title>
 !Edrivers/tty/serial/serial_core.c

+ 2 - 1
Documentation/DocBook/media/Makefile

@@ -199,7 +199,8 @@ DVB_DOCUMENTED = \
 #
 
 install_media_images = \
-	$(Q)-cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/*.svg $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api
+	$(Q)-mkdir $(MEDIA_OBJ_DIR)/media_api; \
+	cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/*.svg $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api
 
 $(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64
 	$(Q)base64 -d $< >$@

+ 2 - 3
Documentation/DocBook/media/dvb/intro.xml

@@ -163,9 +163,8 @@ are called:</para>
 <para>where N enumerates the DVB PCI cards in a system starting
 from&#x00A0;0, and M enumerates the devices of each type within each
 adapter, starting from&#x00A0;0, too. We will omit the &#8220;
-<constant>/dev/dvb/adapterN/</constant>&#8221; in the further dicussion
-of these devices. The naming scheme for the devices is the same wheter
-devfs is used or not.</para>
+<constant>/dev/dvb/adapterN/</constant>&#8221; in the further discussion
+of these devices.</para>
 
 <para>More details about the data structures and function calls of all
 the devices are described in the following chapters.</para>

+ 1 - 1
Documentation/DocBook/media/v4l/controls.xml

@@ -3414,7 +3414,7 @@ giving priority to the center of the metered area.</entry>
 		<row>
 		  <entry><constant>V4L2_EXPOSURE_METERING_MATRIX</constant>&nbsp;</entry>
 		  <entry>A multi-zone metering. The light intensity is measured
-in several points of the frame and the the results are combined. The
+in several points of the frame and the results are combined. The
 algorithm of the zones selection and their significance in calculating the
 final value is device dependent.</entry>
 		</row>

+ 1 - 1
Documentation/DocBook/media/v4l/media-ioc-device-info.xml

@@ -102,7 +102,7 @@
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>media_version</structfield></entry>
+	    <entry><structfield>driver_version</structfield></entry>
 	    <entry>Media device driver version, formatted with the
 	    <constant>KERNEL_VERSION()</constant> macro. Together with the
 	    <structfield>driver</structfield> field this identifies a particular

+ 19 - 19
Documentation/DocBook/media/v4l/vidioc-expbuf.xml

@@ -62,28 +62,28 @@ buffer as a DMABUF file at any time after buffers have been allocated with the
 &VIDIOC-REQBUFS; ioctl.</para>
 
 <para> To export a buffer, applications fill &v4l2-exportbuffer;.  The
-<structfield> type </structfield> field is set to the same buffer type as was
-previously used with  &v4l2-requestbuffers;<structfield> type </structfield>.
-Applications must also set the <structfield> index </structfield> field. Valid
+<structfield>type</structfield> field is set to the same buffer type as was
+previously used with &v4l2-requestbuffers; <structfield>type</structfield>.
+Applications must also set the <structfield>index</structfield> field. Valid
 index numbers range from zero to the number of buffers allocated with
-&VIDIOC-REQBUFS; (&v4l2-requestbuffers;<structfield> count </structfield>)
-minus one.  For the multi-planar API, applications set the <structfield> plane
-</structfield> field to the index of the plane to be exported. Valid planes
+&VIDIOC-REQBUFS; (&v4l2-requestbuffers; <structfield>count</structfield>)
+minus one.  For the multi-planar API, applications set the <structfield>plane</structfield>
+field to the index of the plane to be exported. Valid planes
 range from zero to the maximal number of valid planes for the currently active
-format. For the single-planar API, applications must set <structfield> plane
-</structfield> to zero.  Additional flags may be posted in the <structfield>
-flags </structfield> field.  Refer to a manual for open() for details.
+format. For the single-planar API, applications must set <structfield>plane</structfield>
+to zero.  Additional flags may be posted in the <structfield>flags</structfield>
+field.  Refer to a manual for open() for details.
 Currently only O_CLOEXEC, O_RDONLY, O_WRONLY, and O_RDWR are supported.  All
 other fields must be set to zero.
 In the case of multi-planar API, every plane is exported separately using
-multiple <constant> VIDIOC_EXPBUF </constant> calls. </para>
+multiple <constant>VIDIOC_EXPBUF</constant> calls.</para>
 
-<para> After calling <constant>VIDIOC_EXPBUF</constant> the <structfield> fd
-</structfield> field will be set by a driver.  This is a DMABUF file
+<para>After calling <constant>VIDIOC_EXPBUF</constant> the <structfield>fd</structfield>
+field will be set by a driver.  This is a DMABUF file
 descriptor. The application may pass it to other DMABUF-aware devices. Refer to
 <link linkend="dmabuf">DMABUF importing</link> for details about importing
 DMABUF files into V4L2 nodes. It is recommended to close a DMABUF file when it
-is no longer used to allow the associated memory to be reclaimed. </para>
+is no longer used to allow the associated memory to be reclaimed.</para>
   </refsect1>
 
   <refsect1>
@@ -170,9 +170,9 @@ multi-planar API. Otherwise this value must be set to zero. </entry>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>flags</structfield></entry>
-	    <entry>Flags for the newly created file, currently only <constant>
-O_CLOEXEC </constant>, <constant>O_RDONLY</constant>, <constant>O_WRONLY
-</constant>, and <constant>O_RDWR</constant> are supported, refer to the manual
+	    <entry>Flags for the newly created file, currently only
+<constant>O_CLOEXEC</constant>, <constant>O_RDONLY</constant>, <constant>O_WRONLY</constant>,
+and <constant>O_RDWR</constant> are supported, refer to the manual
 of open() for more details.</entry>
 	  </row>
 	  <row>
@@ -200,9 +200,9 @@ set the array to zero.</entry>
 	<term><errorcode>EINVAL</errorcode></term>
 	<listitem>
 	  <para>A queue is not in MMAP mode or DMABUF exporting is not
-supported or <structfield> flags </structfield> or <structfield> type
-</structfield> or <structfield> index </structfield> or <structfield> plane
-</structfield> fields are invalid.</para>
+supported or <structfield>flags</structfield> or <structfield>type</structfield>
+or <structfield>index</structfield> or <structfield>plane</structfield> fields
+are invalid.</para>
 	</listitem>
       </varlistentry>
     </variablelist>

+ 1 - 1
Documentation/DocBook/media/v4l/vidioc-g-parm.xml

@@ -267,7 +267,7 @@ is intended for still imaging applications. The idea is to get the
 best possible image quality that the hardware can deliver. It is not
 defined how the driver writer may achieve that; it will depend on the
 hardware and the ingenuity of the driver writer. High quality mode is
-a different mode from the the regular motion video capture modes. In
+a different mode from the regular motion video capture modes. In
 high quality mode:<itemizedlist>
 		  <listitem>
 		    <para>The driver may be able to capture higher

+ 1 - 1
Documentation/DocBook/media/v4l/vidioc-queryctrl.xml

@@ -616,7 +616,7 @@ pointer to memory containing the payload of the control.</entry>
 	    <entry><constant>V4L2_CTRL_FLAG_EXECUTE_ON_WRITE</constant></entry>
 	    <entry>0x0200</entry>
 	    <entry>The value provided to the control will be propagated to the driver
-even if remains constant. This is required when the control represents an action
+even if it remains constant. This is required when the control represents an action
 on the hardware. For example: clearing an error flag or triggering the flash. All the
 controls of the type <constant>V4L2_CTRL_TYPE_BUTTON</constant> have this flag set.</entry>
 	  </row>

+ 13 - 8
Documentation/devicetree/bindings/media/i2c/adv7604.txt

@@ -1,15 +1,17 @@
-* Analog Devices ADV7604/11 video decoder with HDMI receiver
+* Analog Devices ADV7604/11/12 video decoder with HDMI receiver
 
-The ADV7604 and ADV7611 are multiformat video decoders with an integrated HDMI
-receiver. The ADV7604 has four multiplexed HDMI inputs and one analog input,
-and the ADV7611 has one HDMI input and no analog input.
+The ADV7604 and ADV7611/12 are multiformat video decoders with an integrated
+HDMI receiver. The ADV7604 has four multiplexed HDMI inputs and one analog
+input, and the ADV7611 has one HDMI input and no analog input. The 7612 is
+similar to the 7611 but has 2 HDMI inputs.
 
-These device tree bindings support the ADV7611 only at the moment.
+These device tree bindings support the ADV7611/12 only at the moment.
 
 Required Properties:
 
   - compatible: Must contain one of the following
     - "adi,adv7611" for the ADV7611
+    - "adi,adv7612" for the ADV7612
 
   - reg: I2C slave address
 
@@ -22,10 +24,10 @@ port, in accordance with the video interface bindings defined in
 Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes
 are numbered as follows.
 
-  Port			ADV7611
+  Port			ADV7611    ADV7612
 ------------------------------------------------------------
-  HDMI			0
-  Digital output	1
+  HDMI			0             0, 1
+  Digital output	1                2
 
 The digital output port node must contain at least one endpoint.
 
@@ -45,6 +47,7 @@ Optional Endpoint Properties:
   If none of hsync-active, vsync-active and pclk-sample is specified the
   endpoint will use embedded BT.656 synchronization.
 
+  - default-input: Select which input is selected after reset.
 
 Example:
 
@@ -58,6 +61,8 @@ Example:
 		#address-cells = <1>;
 		#size-cells = <0>;
 
+		default-input = <0>;
+
 		port@0 {
 			reg = <0>;
 		};

+ 48 - 0
Documentation/devicetree/bindings/media/i2c/tc358743.txt

@@ -0,0 +1,48 @@
+* Toshiba TC358743 HDMI-RX to MIPI CSI2-TX Bridge
+
+The Toshiba TC358743 HDMI-RX to MIPI CSI2-TX (H2C) is a bridge that converts
+a HDMI stream to MIPI CSI-2 TX. It is programmable through I2C.
+
+Required Properties:
+
+- compatible: value should be "toshiba,tc358743"
+- clocks, clock-names: should contain a phandle link to the reference clock
+		       source, the clock input is named "refclk".
+
+Optional Properties:
+
+- reset-gpios: gpio phandle GPIO connected to the reset pin
+- interrupts, interrupt-parent: GPIO connected to the interrupt pin
+- data-lanes: should be <1 2 3 4> for four-lane operation,
+	      or <1 2> for two-lane operation
+- clock-lanes: should be <0>
+- clock-noncontinuous: Presence of this boolean property decides whether the
+		       MIPI CSI-2 clock is continuous or non-continuous.
+- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
+		    expressed as a 64-bit big-endian integer. The frequency
+		    is half of the bps per lane due to DDR transmission.
+
+For further information on the MIPI CSI-2 endpoint node properties, see
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example:
+
+	tc358743@0f {
+		compatible = "toshiba,tc358743";
+		reg = <0x0f>;
+		clocks = <&hdmi_osc>;
+		clock-names = "refclk";
+		reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
+
+		port {
+			tc358743_out: endpoint {
+				remote-endpoint = <&mipi_csi2_in>;
+				data-lanes = <1 2 3 4>;
+				clock-lanes = <0>;
+				clock-noncontinuous;
+				link-frequencies = /bits/ 64 <297000000>;
+			};
+		};
+	};

+ 24 - 0
Documentation/devicetree/bindings/media/renesas,jpu.txt

@@ -0,0 +1,24 @@
+* Renesas JPEG Processing Unit
+
+The JPEG processing unit (JPU) incorporates the JPEG codec with an encoding
+and decoding function conforming to the JPEG baseline process, so that the JPU
+can encode image data and decode JPEG data quickly.
+
+Required properties:
+  - compatible: should containg one of the following:
+			- "renesas,jpu-r8a7790" for R-Car H2
+			- "renesas,jpu-r8a7791" for R-Car M2-W
+			- "renesas,jpu-r8a7792" for R-Car V2H
+			- "renesas,jpu-r8a7793" for R-Car M2-N
+
+  - reg: Base address and length of the registers block for the JPU.
+  - interrupts: JPU interrupt specifier.
+  - clocks: A phandle + clock-specifier pair for the JPU functional clock.
+
+Example: R8A7790 (R-Car H2) JPU node
+	jpeg-codec@fe980000 {
+		compatible = "renesas,jpu-r8a7790";
+		reg = <0 0xfe980000 0 0x10300>;
+		interrupts = <0 272 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp1_clks R8A7790_CLK_JPU>;
+	};

+ 89 - 0
Documentation/devicetree/bindings/media/stih407-c8sectpfe.txt

@@ -0,0 +1,89 @@
+STMicroelectronics STi c8sectpfe binding
+============================================
+
+This document describes the c8sectpfe device bindings that is used to get transport
+stream data into the SoC on the TS pins, and into DDR for further processing.
+
+It is typically used in conjunction with one or more demodulator and tuner devices
+which converts from the RF to digital domain. Demodulators and tuners are usually
+located on an external DVB frontend card connected to SoC TS input pins.
+
+Currently 7 TS input (tsin) channels are supported on the stih407 family SoC.
+
+Required properties (controller (parent) node):
+- compatible	: Should be "stih407-c8sectpfe"
+
+- reg		: Address and length of register sets for each device in
+		  "reg-names"
+
+- reg-names	: The names of the register addresses corresponding to the
+		  registers filled in "reg":
+			- c8sectpfe: c8sectpfe registers
+			- c8sectpfe-ram: c8sectpfe internal sram
+
+- clocks	: phandle list of c8sectpfe clocks
+- clock-names	: should be "c8sectpfe"
+See: Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+- pinctrl-names	: a pinctrl state named tsin%d-serial or tsin%d-parallel (where %d is tsin-num)
+		   must be defined for each tsin child node.
+- pinctrl-0	: phandle referencing pin configuration for this tsin configuration
+See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
+
+
+Required properties (tsin (child) node):
+
+- tsin-num	: tsin id of the InputBlock (must be between 0 to 6)
+- i2c-bus	: phandle to the I2C bus DT node which the demodulators & tuners on this tsin channel are connected.
+- rst-gpio	: reset gpio for this tsin channel.
+
+Optional properties (tsin (child) node):
+
+- invert-ts-clk		: Bool property to control sense of ts input clock (data stored on falling edge of clk).
+- serial-not-parallel	: Bool property to configure input bus width (serial on ts_data<7>).
+- async-not-sync	: Bool property to control if data is received in asynchronous mode
+			   (all bits/bytes with ts_valid or ts_packet asserted are valid).
+
+- dvb-card		: Describes the NIM card connected to this tsin channel.
+
+Example:
+
+/* stih410 SoC b2120 + b2004a + stv0367-pll(NIMB) + stv0367-tda18212 (NIMA) DT example) */
+
+	c8sectpfe@08a20000 {
+		compatible = "st,stih407-c8sectpfe";
+		status = "okay";
+		reg = <0x08a20000 0x10000>, <0x08a00000 0x4000>;
+		reg-names = "stfe", "stfe-ram";
+		interrupts = <0 34 0>, <0 35 0>;
+		interrupt-names = "stfe-error-irq", "stfe-idle-irq";
+
+		pinctrl-names	= "tsin0-serial", "tsin0-parallel", "tsin3-serial",
+				"tsin4-serial", "tsin5-serial";
+
+		pinctrl-0	= <&pinctrl_tsin0_serial>;
+		pinctrl-1	= <&pinctrl_tsin0_parallel>;
+		pinctrl-2	= <&pinctrl_tsin3_serial>;
+		pinctrl-3	= <&pinctrl_tsin4_serial_alt3>;
+		pinctrl-4	= <&pinctrl_tsin5_serial_alt1>;
+
+		clocks = <&clk_s_c0_flexgen CLK_PROC_STFE>;
+		clock-names = "stfe";
+
+		/* tsin0 is TSA on NIMA */
+		tsin0: port@0 {
+			tsin-num		= <0>;
+			serial-not-parallel;
+			i2c-bus			= <&ssc2>;
+			rst-gpio		= <&pio15 4 0>;
+			dvb-card		= <STV0367_TDA18212_NIMA_1>;
+		};
+
+		tsin3: port@3 {
+			tsin-num		= <3>;
+			serial-not-parallel;
+			i2c-bus			= <&ssc3>;
+			rst-gpio		= <&pio15 7 0>;
+			dvb-card		= <STV0367_TDA18212_NIMB_1>;
+		};
+	};

+ 59 - 0
MAINTAINERS

@@ -1525,6 +1525,7 @@ F:	drivers/clocksource/arm_global_timer.c
 F:	drivers/clocksource/clksrc_st_lpc.c
 F:	drivers/i2c/busses/i2c-st.c
 F:	drivers/media/rc/st_rc.c
+F:	drivers/media/platform/sti/c8sectpfe/
 F:	drivers/mmc/host/sdhci-st.c
 F:	drivers/phy/phy-miphy28lp.c
 F:	drivers/phy/phy-miphy365x.c
@@ -5819,6 +5820,12 @@ S:	Maintained
 F:	fs/jbd2/
 F:	include/linux/jbd2.h
 
+JPU V4L2 MEM2MEM DRIVER FOR RENESAS
+M:	Mikhail Ulyanov <mikhail.ulyanov@cogentembedded.com>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	drivers/media/platform/rcar_jpu.c
+
 JSM Neo PCI based serial card
 M:	Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
 L:	linux-serial@vger.kernel.org
@@ -6662,6 +6669,51 @@ S:	Supported
 F:	Documentation/devicetree/bindings/media/renesas,vsp1.txt
 F:	drivers/media/platform/vsp1/
 
+MEDIA DRIVERS FOR ASCOT2E
+M:	Sergey Kozlov <serjk@netup.ru>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org
+W:	http://netup.tv/
+T:	git git://linuxtv.org/media_tree.git
+S:	Supported
+F:	drivers/media/dvb-frontends/ascot2e*
+
+MEDIA DRIVERS FOR CXD2841ER
+M:	Sergey Kozlov <serjk@netup.ru>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+W:	http://netup.tv/
+T:	git git://linuxtv.org/media_tree.git
+S:	Supported
+F:	drivers/media/dvb-frontends/cxd2841er*
+
+MEDIA DRIVERS FOR HORUS3A
+M:	Sergey Kozlov <serjk@netup.ru>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+W:	http://netup.tv/
+T:	git git://linuxtv.org/media_tree.git
+S:	Supported
+F:	drivers/media/dvb-frontends/horus3a*
+
+MEDIA DRIVERS FOR LNBH25
+M:	Sergey Kozlov <serjk@netup.ru>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+W:	http://netup.tv/
+T:	git git://linuxtv.org/media_tree.git
+S:	Supported
+F:	drivers/media/dvb-frontends/lnbh25*
+
+MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices
+M:	Sergey Kozlov <serjk@netup.ru>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+W:	http://netup.tv/
+T:	git git://linuxtv.org/media_tree.git
+S:	Supported
+F:	drivers/media/pci/netup_unidvb/*
+
 MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
 M:	Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 P:	LinuxTV.org Project
@@ -10428,6 +10480,13 @@ F:	drivers/char/toshiba.c
 F:	include/linux/toshiba.h
 F:	include/uapi/linux/toshiba.h
 
+TOSHIBA TC358743 DRIVER
+M:	Mats Randgaard <matrandg@cisco.com>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	drivers/media/i2c/tc358743*
+F:	include/media/tc358743.h
+
 TMIO MMC DRIVER
 M:	Ian Molton <ian@mnementh.co.uk>
 L:	linux-mmc@vger.kernel.org

+ 1 - 1
arch/sh/kernel/cpu/sh4a/clock-sh7724.c

@@ -343,7 +343,7 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_CON_ID("2ddmac0", &mstp_clks[HWBLK_2DDMAC]),
 	CLKDEV_DEV_ID("sh_fsi.0", &mstp_clks[HWBLK_SPU]),
 	CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),
-	CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
+	CLKDEV_DEV_ID("sh-vou", &mstp_clks[HWBLK_VOU]),
 	CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU0]),
 	CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU0]),
 	CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU0]),

+ 3 - 6
drivers/media/common/saa7146/saa7146_hlp.c

@@ -307,7 +307,7 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field
 /* simple bubble-sort algorithm with duplicate elimination */
 static int sort_and_eliminate(u32* values, int* count)
 {
-	int low = 0, high = 0, top = 0, temp = 0;
+	int low = 0, high = 0, top = 0;
 	int cur = 0, next = 0;
 
 	/* sanity checks */
@@ -318,11 +318,8 @@ static int sort_and_eliminate(u32* values, int* count)
 	/* bubble sort the first @count items of the array @values */
 	for( top = *count; top > 0; top--) {
 		for( low = 0, high = 1; high < top; low++, high++) {
-			if( values[low] > values[high] ) {
-				temp = values[low];
-				values[low] = values[high];
-				values[high] = temp;
-			}
+			if( values[low] > values[high] )
+				swap(values[low], values[high]);
 		}
 	}
 

+ 84 - 83
drivers/media/dvb-core/dvb_ca_en50221.c

@@ -169,10 +169,10 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * e
 /**
  * Safely find needle in haystack.
  *
- * @param haystack Buffer to look in.
- * @param hlen Number of bytes in haystack.
- * @param needle Buffer to find.
- * @param nlen Number of bytes in needle.
+ * @haystack: Buffer to look in.
+ * @hlen: Number of bytes in haystack.
+ * @needle: Buffer to find.
+ * @nlen: Number of bytes in needle.
  * @return Pointer into haystack needle was found at, or NULL if not found.
  */
 static char *findstr(char * haystack, int hlen, char * needle, int nlen)
@@ -197,7 +197,7 @@ static char *findstr(char * haystack, int hlen, char * needle, int nlen)
 
 
 /**
- * Check CAM status.
+ * dvb_ca_en50221_check_camstatus - Check CAM status.
  */
 static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
 {
@@ -240,13 +240,13 @@ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
 
 
 /**
- * Wait for flags to become set on the STATUS register on a CAM interface,
- * checking for errors and timeout.
+ * dvb_ca_en50221_wait_if_status - Wait for flags to become set on the STATUS
+ *	 register on a CAM interface, checking for errors and timeout.
  *
- * @param ca CA instance.
- * @param slot Slot on interface.
- * @param waitfor Flags to wait for.
- * @param timeout_ms Timeout in milliseconds.
+ * @ca: CA instance.
+ * @slot: Slot on interface.
+ * @waitfor: Flags to wait for.
+ * @timeout_ms: Timeout in milliseconds.
  *
  * @return 0 on success, nonzero on error.
  */
@@ -290,10 +290,10 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
 
 
 /**
- * Initialise the link layer connection to a CAM.
+ * dvb_ca_en50221_link_init - Initialise the link layer connection to a CAM.
  *
- * @param ca CA instance.
- * @param slot Slot id.
+ * @ca: CA instance.
+ * @slot: Slot id.
  *
  * @return 0 on success, nonzero on failure.
  */
@@ -346,14 +346,14 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
 }
 
 /**
- * Read a tuple from attribute memory.
+ * dvb_ca_en50221_read_tuple - Read a tuple from attribute memory.
  *
- * @param ca CA instance.
- * @param slot Slot id.
- * @param address Address to read from. Updated.
- * @param tupleType Tuple id byte. Updated.
- * @param tupleLength Tuple length. Updated.
- * @param tuple Dest buffer for tuple (must be 256 bytes). Updated.
+ * @ca: CA instance.
+ * @slot: Slot id.
+ * @address: Address to read from. Updated.
+ * @tupleType: Tuple id byte. Updated.
+ * @tupleLength: Tuple length. Updated.
+ * @tuple: Dest buffer for tuple (must be 256 bytes). Updated.
  *
  * @return 0 on success, nonzero on error.
  */
@@ -399,11 +399,11 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
 
 
 /**
- * Parse attribute memory of a CAM module, extracting Config register, and checking
- * it is a DVB CAM module.
+ * dvb_ca_en50221_parse_attributes - Parse attribute memory of a CAM module,
+ *	extracting Config register, and checking it is a DVB CAM module.
  *
- * @param ca CA instance.
- * @param slot Slot id.
+ * @ca: CA instance.
+ * @slot: Slot id.
  *
  * @return 0 on success, <0 on failure.
  */
@@ -546,10 +546,10 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
 
 
 /**
- * Set CAM's configoption correctly.
+ * dvb_ca_en50221_set_configoption - Set CAM's configoption correctly.
  *
- * @param ca CA instance.
- * @param slot Slot containing the CAM.
+ * @ca: CA instance.
+ * @slot: Slot containing the CAM.
  */
 static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
 {
@@ -574,15 +574,16 @@ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
 
 
 /**
- * This function talks to an EN50221 CAM control interface. It reads a buffer of
- * data from the CAM. The data can either be stored in a supplied buffer, or
- * automatically be added to the slot's rx_buffer.
+ * dvb_ca_en50221_read_data - This function talks to an EN50221 CAM control
+ *	interface. It reads a buffer of data from the CAM. The data can either
+ *	be stored in a supplied buffer, or automatically be added to the slot's
+ *	rx_buffer.
  *
- * @param ca CA instance.
- * @param slot Slot to read from.
- * @param ebuf If non-NULL, the data will be written to this buffer. If NULL,
+ * @ca: CA instance.
+ * @slot: Slot to read from.
+ * @ebuf: If non-NULL, the data will be written to this buffer. If NULL,
  * the data will be added into the buffering system as a normal fragment.
- * @param ecount Size of ebuf. Ignored if ebuf is NULL.
+ * @ecount: Size of ebuf. Ignored if ebuf is NULL.
  *
  * @return Number of bytes read, or < 0 on error
  */
@@ -698,14 +699,14 @@ exit:
 
 
 /**
- * This function talks to an EN50221 CAM control interface. It writes a buffer of data
- * to a CAM.
+ * dvb_ca_en50221_write_data - This function talks to an EN50221 CAM control
+ *				interface. It writes a buffer of data to a CAM.
  *
- * @param ca CA instance.
- * @param slot Slot to write to.
- * @param ebuf The data in this buffer is treated as a complete link-level packet to
+ * @ca: CA instance.
+ * @slot: Slot to write to.
+ * @ebuf: The data in this buffer is treated as a complete link-level packet to
  * be written.
- * @param count Size of ebuf.
+ * @count: Size of ebuf.
  *
  * @return Number of bytes written, or < 0 on error.
  */
@@ -790,10 +791,10 @@ EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
 
 
 /**
- * A CAM has been removed => shut it down.
+ * dvb_ca_en50221_camready_irq - A CAM has been removed => shut it down.
  *
- * @param ca CA instance.
- * @param slot Slot to shut down.
+ * @ca: CA instance.
+ * @slot: Slot to shut down.
  */
 static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
 {
@@ -815,11 +816,11 @@ EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
 
 
 /**
- * A CAMCHANGE IRQ has occurred.
+ * dvb_ca_en50221_camready_irq - A CAMCHANGE IRQ has occurred.
  *
- * @param ca CA instance.
- * @param slot Slot concerned.
- * @param change_type One of the DVB_CA_CAMCHANGE_* values.
+ * @ca: CA instance.
+ * @slot: Slot concerned.
+ * @change_type: One of the DVB_CA_CAMCHANGE_* values.
  */
 void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type)
 {
@@ -844,10 +845,10 @@ EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
 
 
 /**
- * A CAMREADY IRQ has occurred.
+ * dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred.
  *
- * @param ca CA instance.
- * @param slot Slot concerned.
+ * @ca: CA instance.
+ * @slot: Slot concerned.
  */
 void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
 {
@@ -865,8 +866,8 @@ void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
 /**
  * An FR or DA IRQ has occurred.
  *
- * @param ca CA instance.
- * @param slot Slot concerned.
+ * @ca: CA instance.
+ * @slot: Slot concerned.
  */
 void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
 {
@@ -899,7 +900,7 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
 /**
  * Wake up the DVB CA thread
  *
- * @param ca CA instance.
+ * @ca: CA instance.
  */
 static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
 {
@@ -914,7 +915,7 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
 /**
  * Update the delay used by the thread.
  *
- * @param ca CA instance.
+ * @ca: CA instance.
  */
 static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
 {
@@ -1177,10 +1178,10 @@ static int dvb_ca_en50221_thread(void *data)
  * Real ioctl implementation.
  * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
  *
- * @param inode Inode concerned.
- * @param file File concerned.
- * @param cmd IOCTL command.
- * @param arg Associated argument.
+ * @inode: Inode concerned.
+ * @file: File concerned.
+ * @cmd: IOCTL command.
+ * @arg: Associated argument.
  *
  * @return 0 on success, <0 on error.
  */
@@ -1258,10 +1259,10 @@ out_unlock:
 /**
  * Wrapper for ioctl implementation.
  *
- * @param inode Inode concerned.
- * @param file File concerned.
- * @param cmd IOCTL command.
- * @param arg Associated argument.
+ * @inode: Inode concerned.
+ * @file: File concerned.
+ * @cmd: IOCTL command.
+ * @arg: Associated argument.
  *
  * @return 0 on success, <0 on error.
  */
@@ -1275,10 +1276,10 @@ static long dvb_ca_en50221_io_ioctl(struct file *file,
 /**
  * Implementation of write() syscall.
  *
- * @param file File structure.
- * @param buf Source buffer.
- * @param count Size of source buffer.
- * @param ppos Position in file (ignored).
+ * @file: File structure.
+ * @buf: Source buffer.
+ * @count: Size of source buffer.
+ * @ppos: Position in file (ignored).
  *
  * @return Number of bytes read, or <0 on error.
  */
@@ -1416,10 +1417,10 @@ nextslot:
 /**
  * Implementation of read() syscall.
  *
- * @param file File structure.
- * @param buf Destination buffer.
- * @param count Size of destination buffer.
- * @param ppos Position in file (ignored).
+ * @file: File structure.
+ * @buf: Destination buffer.
+ * @count: Size of destination buffer.
+ * @ppos: Position in file (ignored).
  *
  * @return Number of bytes read, or <0 on error.
  */
@@ -1519,8 +1520,8 @@ exit:
 /**
  * Implementation of file open syscall.
  *
- * @param inode Inode concerned.
- * @param file File concerned.
+ * @inode: Inode concerned.
+ * @file: File concerned.
  *
  * @return 0 on success, <0 on failure.
  */
@@ -1564,8 +1565,8 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
 /**
  * Implementation of file close syscall.
  *
- * @param inode Inode concerned.
- * @param file File concerned.
+ * @inode: Inode concerned.
+ * @file: File concerned.
  *
  * @return 0 on success, <0 on failure.
  */
@@ -1592,8 +1593,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
 /**
  * Implementation of poll() syscall.
  *
- * @param file File concerned.
- * @param wait poll wait table.
+ * @file: File concerned.
+ * @wait: poll wait table.
  *
  * @return Standard poll mask.
  */
@@ -1656,10 +1657,10 @@ static const struct dvb_device dvbdev_ca = {
 /**
  * Initialise a new DVB CA EN50221 interface device.
  *
- * @param dvb_adapter DVB adapter to attach the new CA device to.
- * @param ca The dvb_ca instance.
- * @param flags Flags describing the CA device (DVB_CA_FLAG_*).
- * @param slot_count Number of slots supported.
+ * @dvb_adapter: DVB adapter to attach the new CA device to.
+ * @ca: The dvb_ca instance.
+ * @flags: Flags describing the CA device (DVB_CA_FLAG_*).
+ * @slot_count: Number of slots supported.
  *
  * @return 0 on success, nonzero on failure
  */
@@ -1743,8 +1744,8 @@ EXPORT_SYMBOL(dvb_ca_en50221_release);
 /**
  * Release a DVB CA EN50221 interface device.
  *
- * @param ca_dev The dvb_device_t instance for the CA device.
- * @param ca The associated dvb_ca instance.
+ * @ca_dev: The dvb_device_t instance for the CA device.
+ * @ca: The associated dvb_ca instance.
  */
 void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
 {

+ 17 - 17
drivers/media/dvb-core/dvb_ca_en50221.h

@@ -83,27 +83,27 @@ struct dvb_ca_en50221 {
 /* Functions for reporting IRQ events */
 
 /**
- * A CAMCHANGE IRQ has occurred.
+ * dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred.
  *
- * @param ca CA instance.
- * @param slot Slot concerned.
- * @param change_type One of the DVB_CA_CAMCHANGE_* values
+ * @pubca: CA instance.
+ * @slot: Slot concerned.
+ * @change_type: One of the DVB_CA_CAMCHANGE_* values
  */
 void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
 
 /**
- * A CAMREADY IRQ has occurred.
+ * dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred.
  *
- * @param ca CA instance.
- * @param slot Slot concerned.
+ * @pubca: CA instance.
+ * @slot: Slot concerned.
  */
 void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
 
 /**
- * An FR or a DA IRQ has occurred.
+ * dvb_ca_en50221_frda_irq - An FR or a DA IRQ has occurred.
  *
- * @param ca CA instance.
- * @param slot Slot concerned.
+ * @ca: CA instance.
+ * @slot: Slot concerned.
  */
 void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
 
@@ -113,21 +113,21 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
 /* Initialisation/shutdown functions */
 
 /**
- * Initialise a new DVB CA device.
+ * dvb_ca_en50221_init - Initialise a new DVB CA device.
  *
- * @param dvb_adapter DVB adapter to attach the new CA device to.
- * @param ca The dvb_ca instance.
- * @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
- * @param slot_count Number of slots supported.
+ * @dvb_adapter: DVB adapter to attach the new CA device to.
+ * @ca: The dvb_ca instance.
+ * @flags: Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
+ * @slot_count: Number of slots supported.
  *
  * @return 0 on success, nonzero on failure
  */
 extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count);
 
 /**
- * Release a DVB CA device.
+ * dvb_ca_en50221_release - Release a DVB CA device.
  *
- * @param ca The associated dvb_ca instance.
+ * @ca: The associated dvb_ca instance.
  */
 extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
 

+ 0 - 1
drivers/media/dvb-core/dvb_frontend.c

@@ -81,7 +81,6 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
 #define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
 #define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
 
-#define FE_ALGO_HW		1
 /*
  * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
  * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.

+ 331 - 79
drivers/media/dvb-core/dvb_frontend.h

@@ -48,6 +48,15 @@
  */
 #define MAX_DELSYS	8
 
+/**
+ * struct dvb_frontend_tune_settings - parameters to adjust frontend tuning
+ *
+ * @min_delay_ms:	minimum delay for tuning, in ms
+ * @step_size:		step size between two consecutive frequencies
+ * @max_drift:		maximum drift
+ *
+ * NOTE: step_size is in Hz, for terrestrial/cable or kHz for satellite
+ */
 struct dvb_frontend_tune_settings {
 	int min_delay_ms;
 	int step_size;
@@ -56,6 +65,20 @@ struct dvb_frontend_tune_settings {
 
 struct dvb_frontend;
 
+/**
+ * struct dvb_tuner_info - Frontend name and min/max ranges/bandwidths
+ *
+ * @name:		name of the Frontend
+ * @frequency_min:	minimal frequency supported
+ * @frequency_max:	maximum frequency supported
+ * @frequency_step:	frequency step
+ * @bandwidth_min:	minimal frontend bandwidth supported
+ * @bandwidth_max:	maximum frontend bandwidth supported
+ * @bandwidth_step:	frontend bandwidth step
+ *
+ * NOTE: frequency parameters are in Hz, for terrestrial/cable or kHz for
+ * satellite.
+ */
 struct dvb_tuner_info {
 	char name[128];
 
@@ -68,6 +91,20 @@ struct dvb_tuner_info {
 	u32 bandwidth_step;
 };
 
+/**
+ * struct analog_parameters - Parameters to tune into an analog/radio channel
+ *
+ * @frequency:	Frequency used by analog TV tuner (either in 62.5 kHz step,
+ * 		for TV, or 62.5 Hz for radio)
+ * @mode:	Tuner mode, as defined on enum v4l2_tuner_type
+ * @audmode:	Audio mode as defined for the rxsubchans field at videodev2.h,
+ * 		e. g. V4L2_TUNER_MODE_*
+ * @std:	TV standard bitmap as defined at videodev2.h, e. g. V4L2_STD_*
+ *
+ * Hybrid tuners should be supported by both V4L2 and DVB APIs. This
+ * struct contains the data that are used by the V4L2 side. To avoid
+ * dependencies from V4L2 headers, all enums here are declared as integers.
+ */
 struct analog_parameters {
 	unsigned int frequency;
 	unsigned int mode;
@@ -75,42 +112,6 @@ struct analog_parameters {
 	u64 std;
 };
 
-enum dvbfe_modcod {
-	DVBFE_MODCOD_DUMMY_PLFRAME	= 0,
-	DVBFE_MODCOD_QPSK_1_4,
-	DVBFE_MODCOD_QPSK_1_3,
-	DVBFE_MODCOD_QPSK_2_5,
-	DVBFE_MODCOD_QPSK_1_2,
-	DVBFE_MODCOD_QPSK_3_5,
-	DVBFE_MODCOD_QPSK_2_3,
-	DVBFE_MODCOD_QPSK_3_4,
-	DVBFE_MODCOD_QPSK_4_5,
-	DVBFE_MODCOD_QPSK_5_6,
-	DVBFE_MODCOD_QPSK_8_9,
-	DVBFE_MODCOD_QPSK_9_10,
-	DVBFE_MODCOD_8PSK_3_5,
-	DVBFE_MODCOD_8PSK_2_3,
-	DVBFE_MODCOD_8PSK_3_4,
-	DVBFE_MODCOD_8PSK_5_6,
-	DVBFE_MODCOD_8PSK_8_9,
-	DVBFE_MODCOD_8PSK_9_10,
-	DVBFE_MODCOD_16APSK_2_3,
-	DVBFE_MODCOD_16APSK_3_4,
-	DVBFE_MODCOD_16APSK_4_5,
-	DVBFE_MODCOD_16APSK_5_6,
-	DVBFE_MODCOD_16APSK_8_9,
-	DVBFE_MODCOD_16APSK_9_10,
-	DVBFE_MODCOD_32APSK_3_4,
-	DVBFE_MODCOD_32APSK_4_5,
-	DVBFE_MODCOD_32APSK_5_6,
-	DVBFE_MODCOD_32APSK_8_9,
-	DVBFE_MODCOD_32APSK_9_10,
-	DVBFE_MODCOD_RESERVED_1,
-	DVBFE_MODCOD_BPSK_1_3,
-	DVBFE_MODCOD_BPSK_1_4,
-	DVBFE_MODCOD_RESERVED_2
-};
-
 enum tuner_param {
 	DVBFE_TUNER_FREQUENCY		= (1 <<  0),
 	DVBFE_TUNER_TUNERSTEP		= (1 <<  1),
@@ -121,30 +122,28 @@ enum tuner_param {
 	DVBFE_TUNER_DUMMY		= (1 << 31)
 };
 
-/*
- * ALGO_HW: (Hardware Algorithm)
- * ----------------------------------------------------------------
- * Devices that support this algorithm do everything in hardware
- * and no software support is needed to handle them.
- * Requesting these devices to LOCK is the only thing required,
- * device is supposed to do everything in the hardware.
- *
- * ALGO_SW: (Software Algorithm)
- * ----------------------------------------------------------------
+/**
+ * enum dvbfe_algo - defines the algorithm used to tune into a channel
+ *
+ * @DVBFE_ALGO_HW: Hardware Algorithm -
+ *	Devices that support this algorithm do everything in hardware
+ *	and no software support is needed to handle them.
+ *	Requesting these devices to LOCK is the only thing required,
+ *	device is supposed to do everything in the hardware.
+ *
+ * @DVBFE_ALGO_SW: Software Algorithm -
  * These are dumb devices, that require software to do everything
  *
- * ALGO_CUSTOM: (Customizable Agorithm)
- * ----------------------------------------------------------------
- * Devices having this algorithm can be customized to have specific
- * algorithms in the frontend driver, rather than simply doing a
- * software zig-zag. In this case the zigzag maybe hardware assisted
- * or it maybe completely done in hardware. In all cases, usage of
- * this algorithm, in conjunction with the search and track
- * callbacks, utilizes the driver specific algorithm.
- *
- * ALGO_RECOVERY: (Recovery Algorithm)
- * ----------------------------------------------------------------
- * These devices have AUTO recovery capabilities from LOCK failure
+ * @DVBFE_ALGO_CUSTOM: Customizable Agorithm -
+ *	Devices having this algorithm can be customized to have specific
+ *	algorithms in the frontend driver, rather than simply doing a
+ *	software zig-zag. In this case the zigzag maybe hardware assisted
+ *	or it maybe completely done in hardware. In all cases, usage of
+ *	this algorithm, in conjunction with the search and track
+ *	callbacks, utilizes the driver specific algorithm.
+ *
+ * @DVBFE_ALGO_RECOVERY: Recovery Algorithm -
+ *	These devices have AUTO recovery capabilities from LOCK failure
  */
 enum dvbfe_algo {
 	DVBFE_ALGO_HW			= (1 <<  0),
@@ -162,27 +161,27 @@ struct tuner_state {
 	u32 refclock;
 };
 
-/*
- * search callback possible return status
+/**
+ * enum dvbfe_search - search callback possible return status
  *
- * DVBFE_ALGO_SEARCH_SUCCESS
- * The frontend search algorithm completed and returned successfully
+ * @DVBFE_ALGO_SEARCH_SUCCESS:
+ *	The frontend search algorithm completed and returned successfully
  *
- * DVBFE_ALGO_SEARCH_ASLEEP
- * The frontend search algorithm is sleeping
+ * @DVBFE_ALGO_SEARCH_ASLEEP:
+ *	The frontend search algorithm is sleeping
  *
- * DVBFE_ALGO_SEARCH_FAILED
- * The frontend search for a signal failed
+ * @DVBFE_ALGO_SEARCH_FAILED:
+ *	The frontend search for a signal failed
  *
- * DVBFE_ALGO_SEARCH_INVALID
- * The frontend search algorith was probably supplied with invalid
- * parameters and the search is an invalid one
+ * @DVBFE_ALGO_SEARCH_INVALID:
+ *	The frontend search algorith was probably supplied with invalid
+ *	parameters and the search is an invalid one
  *
- * DVBFE_ALGO_SEARCH_ERROR
- * The frontend search algorithm failed due to some error
+ * @DVBFE_ALGO_SEARCH_ERROR:
+ *	The frontend search algorithm failed due to some error
  *
- * DVBFE_ALGO_SEARCH_AGAIN
- * The frontend search algorithm was requested to search again
+ * @DVBFE_ALGO_SEARCH_AGAIN:
+ *	The frontend search algorithm was requested to search again
  */
 enum dvbfe_search {
 	DVBFE_ALGO_SEARCH_SUCCESS	= (1 <<  0),
@@ -193,7 +192,56 @@ enum dvbfe_search {
 	DVBFE_ALGO_SEARCH_ERROR		= (1 << 31),
 };
 
-
+/**
+ * struct dvb_tuner_ops - Tuner information and callbacks
+ *
+ * @info:		embedded struct dvb_tuner_info with tuner properties
+ * @release:		callback function called when frontend is dettached.
+ *			drivers should free any allocated memory.
+ * @init:		callback function used to initialize the tuner device.
+ * @sleep:		callback function used to put the tuner to sleep.
+ * @suspend:		callback function used to inform that the Kernel will
+ *			suspend.
+ * @resume:		callback function used to inform that the Kernel is
+ *			resuming from suspend.
+ * @set_params:		callback function used to inform the tuner to tune
+ *			into a digital TV channel. The properties to be used
+ *			are stored at @dvb_frontend.dtv_property_cache;. The
+ *			tuner demod can change the parameters to reflect the
+ *			changes needed for the channel to be tuned, and
+ *			update statistics.
+ * @set_analog_params:	callback function used to tune into an analog TV
+ *			channel on hybrid tuners. It passes @analog_parameters;
+ *			to the driver.
+ * @calc_regs:		callback function used to pass register data settings
+ *			for simple tuners.
+ * @set_config:		callback function used to send some tuner-specific
+ *			parameters.
+ * @get_frequency:	get the actual tuned frequency
+ * @get_bandwidth:	get the bandwitdh used by the low pass filters
+ * @get_if_frequency:	get the Intermediate Frequency, in Hz. For baseband,
+ * 			should return 0.
+ * @get_status:		returns the frontend lock status
+ * @get_rf_strength:	returns the RF signal strengh. Used mostly to support
+ *			analog TV and radio. Digital TV should report, instead,
+ *			via DVBv5 API (@dvb_frontend.dtv_property_cache;).
+ * @get_afc:		Used only by analog TV core. Reports the frequency
+ *			drift due to AFC.
+ * @set_frequency:	Set a new frequency. Please notice that using
+ *			set_params is preferred.
+ * @set_bandwidth:	Set a new frequency. Please notice that using
+ *			set_params is preferred.
+ * @set_state:		callback function used on some legacy drivers that
+ * 			don't implement set_params in order to set properties.
+ * 			Shouldn't be used on new drivers.
+ * @get_state:		callback function used to get properties by some
+ * 			legacy drivers that don't implement set_params.
+ * 			Shouldn't be used on new drivers.
+ *
+ * NOTE: frequencies used on get_frequency and set_frequency are in Hz for
+ * terrestrial/cable or kHz for satellite.
+ *
+ */
 struct dvb_tuner_ops {
 
 	struct dvb_tuner_info info;
@@ -237,10 +285,37 @@ struct dvb_tuner_ops {
 	int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
 };
 
+/**
+ * struct analog_demod_info - Information struct for analog TV part of the demod
+ *
+ * @name:	Name of the analog TV demodulator
+ */
 struct analog_demod_info {
 	char *name;
 };
 
+/**
+ * struct analog_demod_ops  - Demodulation information and callbacks for
+ *			      analog TV and radio
+ *
+ * @info:		pointer to struct analog_demod_info
+ * @set_params:		callback function used to inform the demod to set the
+ *			demodulator parameters needed to decode an analog or
+ *			radio channel. The properties are passed via
+ *			struct @analog_params;.
+ * @has_signal:		returns 0xffff if has signal, or 0 if it doesn't.
+ * @get_afc:		Used only by analog TV core. Reports the frequency
+ *			drift due to AFC.
+ * @tuner_status:	callback function that returns tuner status bits, e. g.
+ *			TUNER_STATUS_LOCKED and TUNER_STATUS_STEREO.
+ * @standby:		set the tuner to standby mode.
+ * @release:		callback function called when frontend is dettached.
+ *			drivers should free any allocated memory.
+ * @i2c_gate_ctrl:	controls the I2C gate. Newer drivers should use I2C
+ *			mux support instead.
+ * @set_config:		callback function used to send some tuner-specific
+ *			parameters.
+ */
 struct analog_demod_ops {
 
 	struct analog_demod_info info;
@@ -260,6 +335,87 @@ struct analog_demod_ops {
 
 struct dtv_frontend_properties;
 
+
+/**
+ * struct dvb_frontend_ops - Demodulation information and callbacks for
+ *			      ditialt TV
+ *
+ * @info:		embedded struct dvb_tuner_info with tuner properties
+ * @delsys:		Delivery systems supported by the frontend
+ * @release:		callback function called when frontend is dettached.
+ *			drivers should free any allocated memory.
+ * @release_sec:	callback function requesting that the Satelite Equipment
+ *			Control (SEC) driver to release and free any memory
+ *			allocated by the driver.
+ * @init:		callback function used to initialize the tuner device.
+ * @sleep:		callback function used to put the tuner to sleep.
+ * @write:		callback function used by some demod legacy drivers to
+ *			allow other drivers to write data into their registers.
+ *			Should not be used on new drivers.
+ * @tune:		callback function used by demod drivers that use
+ *			@DVBFE_ALGO_HW; to tune into a frequency.
+ * @get_frontend_algo:	returns the desired hardware algorithm.
+ * @set_frontend:	callback function used to inform the demod to set the
+ *			parameters for demodulating a digital TV channel.
+ *			The properties to be used are stored at
+ *			@dvb_frontend.dtv_property_cache;. The demod can change
+ *			the parameters to reflect the changes needed for the
+ *			channel to be decoded, and update statistics.
+ * @get_tune_settings:	callback function
+ * @get_frontend:	callback function used to inform the parameters
+ *			actuall in use. The properties to be used are stored at
+ *			@dvb_frontend.dtv_property_cache; and update
+ *			statistics. Please notice that it should not return
+ *			an error code if the statistics are not available
+ *			because the demog is not locked.
+ * @read_status:	returns the locking status of the frontend.
+ * @read_ber:		legacy callback function to return the bit error rate.
+ *			Newer drivers should provide such info via DVBv5 API,
+ *			e. g. @set_frontend;/@get_frontend;, implementing this
+ *			callback only if DVBv3 API compatibility is wanted.
+ * @read_signal_strength: legacy callback function to return the signal
+ *			strength. Newer drivers should provide such info via
+ *			DVBv5 API, e. g. @set_frontend;/@get_frontend;,
+ *			implementing this callback only if DVBv3 API
+ *			compatibility is wanted.
+ * @read_snr:		legacy callback function to return the Signal/Noise
+ * 			rate. Newer drivers should provide such info via
+ *			DVBv5 API, e. g. @set_frontend;/@get_frontend;,
+ *			implementing this callback only if DVBv3 API
+ *			compatibility is wanted.
+ * @read_ucblocks:	legacy callback function to return the Uncorrected Error
+ *			Blocks. Newer drivers should provide such info via
+ *			DVBv5 API, e. g. @set_frontend;/@get_frontend;,
+ *			implementing this callback only if DVBv3 API
+ *			compatibility is wanted.
+ * @diseqc_reset_overload: callback function to implement the
+ *			FE_DISEQC_RESET_OVERLOAD ioctl (only Satellite)
+ * @diseqc_send_master_cmd: callback function to implement the
+ *			FE_DISEQC_SEND_MASTER_CMD ioctl (only Satellite).
+ * @diseqc_recv_slave_reply: callback function to implement the
+ *			FE_DISEQC_RECV_SLAVE_REPLY ioctl (only Satellite)
+ * @diseqc_send_burst:	callback function to implement the
+ *			FE_DISEQC_SEND_BURST ioctl (only Satellite).
+ * @set_tone:		callback function to implement the
+ *			FE_SET_TONE ioctl (only Satellite).
+ * @set_voltage:	callback function to implement the
+ *			FE_SET_VOLTAGE ioctl (only Satellite).
+ * @enable_high_lnb_voltage: callback function to implement the
+ *			FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite).
+ * @dishnetwork_send_legacy_command: callback function to implement the
+ *			FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite).
+ * @i2c_gate_ctrl:	controls the I2C gate. Newer drivers should use I2C
+ *			mux support instead.
+ * @ts_bus_ctrl:	callback function used to take control of the TS bus.
+ * @set_lna:		callback function to power on/off/auto the LNA.
+ * @search:		callback function used on some custom algo search algos.
+ * @tuner_ops:		pointer to struct dvb_tuner_ops
+ * @analog_ops:		pointer to struct analog_demod_ops
+ * @set_property:	callback function to allow the frontend to validade
+ *			incoming properties. Should not be used on new drivers.
+ * @get_property:	callback function to allow the frontend to override
+ *			outcoming properties. Should not be used on new drivers.
+ */
 struct dvb_frontend_ops {
 
 	struct dvb_frontend_info info;
@@ -280,6 +436,7 @@ struct dvb_frontend_ops {
 		    unsigned int mode_flags,
 		    unsigned int *delay,
 		    enum fe_status *status);
+
 	/* get frontend tuning algorithm from the module */
 	enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
 
@@ -324,6 +481,7 @@ struct dvb_frontend_ops {
 #ifdef __DVB_CORE__
 #define MAX_EVENT 8
 
+/* Used only internally at dvb_frontend.c */
 struct dvb_fe_events {
 	struct dvb_frontend_event events[MAX_EVENT];
 	int			  eventw;
@@ -334,13 +492,83 @@ struct dvb_fe_events {
 };
 #endif
 
+/**
+ * struct dtv_frontend_properties - contains a list of properties that are
+ *				    specific to a digital TV standard.
+ *
+ * @frequency:		frequency in Hz for terrestrial/cable or in kHz for
+ *			Satellite
+ * @modulation:		Frontend modulation type
+ * @voltage:		SEC voltage (only Satellite)
+ * @sectone:		SEC tone mode (only Satellite)
+ * @inversion:		Spectral inversion
+ * @fec_inner:		Forward error correction inner Code Rate
+ * @transmission_mode:	Transmission Mode
+ * @bandwidth_hz:	Bandwidth, in Hz. A zero value means that userspace
+ * 			wants to autodetect.
+ * @guard_interval:	Guard Interval
+ * @hierarchy:		Hierarchy
+ * @symbol_rate:	Symbol Rate
+ * @code_rate_HP:	high priority stream code rate
+ * @code_rate_LP:	low priority stream code rate
+ * @pilot:		Enable/disable/autodetect pilot tones
+ * @rolloff:		Rolloff factor (alpha)
+ * @delivery_system:	FE delivery system (e. g. digital TV standard)
+ * @interleaving:	interleaving
+ * @isdbt_partial_reception: ISDB-T partial reception (only ISDB standard)
+ * @isdbt_sb_mode:	ISDB-T Sound Broadcast (SB) mode (only ISDB standard)
+ * @isdbt_sb_subchannel:	ISDB-T SB subchannel (only ISDB standard)
+ * @isdbt_sb_segment_idx:	ISDB-T SB segment index (only ISDB standard)
+ * @isdbt_sb_segment_count:	ISDB-T SB segment count (only ISDB standard)
+ * @isdbt_layer_enabled:	ISDB Layer enabled (only ISDB standard)
+ * @layer:		ISDB per-layer data (only ISDB standard)
+ * @layer.segment_count: Segment Count;
+ * @layer.fec:		per layer code rate;
+ * @layer.modulation:	per layer modulation;
+ * @layer.interleaving:	 per layer interleaving.
+ * @stream_id:		If different than zero, enable substream filtering, if
+ *			hardware supports (DVB-S2 and DVB-T2).
+ * @atscmh_fic_ver:	Version number of the FIC (Fast Information Channel)
+ *			signaling data (only ATSC-M/H)
+ * @atscmh_parade_id:	Parade identification number (only ATSC-M/H)
+ * @atscmh_nog:		Number of MH groups per MH subframe for a designated
+ *			parade (only ATSC-M/H)
+ * @atscmh_tnog:	Total number of MH groups including all MH groups
+ *			belonging to all MH parades in one MH subframe
+ *			(only ATSC-M/H)
+ * @atscmh_sgn:		Start group number (only ATSC-M/H)
+ * @atscmh_prc:		Parade repetition cycle (only ATSC-M/H)
+ * @atscmh_rs_frame_mode:	Reed Solomon (RS) frame mode (only ATSC-M/H)
+ * @atscmh_rs_frame_ensemble:	RS frame ensemble (only ATSC-M/H)
+ * @atscmh_rs_code_mode_pri:	RS code mode pri (only ATSC-M/H)
+ * @atscmh_rs_code_mode_sec:	RS code mode sec (only ATSC-M/H)
+ * @atscmh_sccc_block_mode:	Series Concatenated Convolutional Code (SCCC)
+ *				Block Mode (only ATSC-M/H)
+ * @atscmh_sccc_code_mode_a:	SCCC code mode A (only ATSC-M/H)
+ * @atscmh_sccc_code_mode_b:	SCCC code mode B (only ATSC-M/H)
+ * @atscmh_sccc_code_mode_c:	SCCC code mode C (only ATSC-M/H)
+ * @atscmh_sccc_code_mode_d:	SCCC code mode D (only ATSC-M/H)
+ * @lna:		Power ON/OFF/AUTO the Linear Now-noise Amplifier (LNA)
+ * @strength:		DVBv5 API statistics: Signal Strength
+ * @cnr:		DVBv5 API statistics: Signal to Noise ratio of the
+ * 			(main) carrier
+ * @pre_bit_error:	DVBv5 API statistics: pre-Viterbi bit error count
+ * @pre_bit_count:	DVBv5 API statistics: pre-Viterbi bit count
+ * @post_bit_error:	DVBv5 API statistics: post-Viterbi bit error count
+ * @post_bit_count:	DVBv5 API statistics: post-Viterbi bit count
+ * @block_error:	DVBv5 API statistics: block error count
+ * @block_count:	DVBv5 API statistics: block count
+ *
+ * NOTE: derivated statistics like Uncorrected Error blocks (UCE) are
+ * calculated on userspace.
+ *
+ * Only a subset of the properties are needed for a given delivery system.
+ * For more info, consult the media_api.html with the documentation of the
+ * Userspace API.
+ */
 struct dtv_frontend_properties {
-
-	/* Cache State */
-	u32			state;
-
 	u32			frequency;
-	enum fe_modulation		modulation;
+	enum fe_modulation	modulation;
 
 	enum fe_sec_voltage	voltage;
 	enum fe_sec_tone_mode	sectone;
@@ -407,6 +635,11 @@ struct dtv_frontend_properties {
 	struct dtv_fe_stats	post_bit_count;
 	struct dtv_fe_stats	block_error;
 	struct dtv_fe_stats	block_count;
+
+	/* private: */
+	/* Cache State */
+	u32			state;
+
 };
 
 #define DVB_FE_NO_EXIT  0
@@ -414,6 +647,25 @@ struct dtv_frontend_properties {
 #define DVB_FE_DEVICE_REMOVED   2
 #define DVB_FE_DEVICE_RESUME    3
 
+/**
+ * struct dvb_frontend - Frontend structure to be used on drivers.
+ *
+ * @ops:		embedded struct dvb_frontend_ops
+ * @dvb:		pointer to struct dvb_adapter
+ * @demodulator_priv:	demod private data
+ * @tuner_priv:		tuner private data
+ * @frontend_priv:	frontend private data
+ * @sec_priv:		SEC private data
+ * @analog_demod_priv:	Analog demod private data
+ * @dtv_property_cache:	embedded struct dtv_frontend_properties
+ * @callback:		callback function used on some drivers to call
+ *			either the tuner or the demodulator.
+ * @id:			Frontend ID
+ * @exit:		Used to inform the DVB core that the frontend
+ *			thread should exit (usually, means that the hardware
+ *			got disconnected.
+ */
+
 struct dvb_frontend {
 	struct dvb_frontend_ops ops;
 	struct dvb_adapter *dvb;

+ 15 - 10
drivers/media/dvb-core/dvb_math.h

@@ -25,33 +25,38 @@
 #include <linux/types.h>
 
 /**
- * computes log2 of a value; the result is shifted left by 24 bits
+ * cintlog2 - computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * @value: The value (must be != 0)
  *
  * to use rational values you can use the following method:
  *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
  *
- * example: intlog2(8) will give 3 << 24 = 3 * 2^24
- * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
- * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ * Some usecase examples:
+ *	intlog2(8) will give 3 << 24 = 3 * 2^24
+ *	intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ *	intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
  *
- * @param value The value (must be != 0)
- * @return log2(value) * 2^24
+ * return: log2(value) * 2^24
  */
 extern unsigned int intlog2(u32 value);
 
 /**
- * computes log10 of a value; the result is shifted left by 24 bits
+ * intlog10 - computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * @value: The value (must be != 0)
  *
  * to use rational values you can use the following method:
  *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
  *
- * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
+ * An usecase example:
+ *	intlog10(1000) will give 3 << 24 = 3 * 2^24
  *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
  *
  * look at intlog2 for similar examples
  *
- * @param value The value (must be != 0)
- * @return log10(value) * 2^24
+ * return: log10(value) * 2^24
  */
 extern unsigned int intlog10(u32 value);
 

+ 1 - 1
drivers/media/dvb-core/dvb_net.c

@@ -709,7 +709,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 					if (!priv->ule_dbit) {
 						 /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
 						memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
-						memset(ethh->h_source, 0, ETH_ALEN);
+						eth_zero_addr(ethh->h_source);
 					}
 					else /* zeroize source and dest */
 						memset( ethh, 0, ETH_ALEN*2 );

+ 75 - 60
drivers/media/dvb-core/dvb_ringbuffer.h

@@ -45,33 +45,33 @@ struct dvb_ringbuffer {
 
 
 /*
-** Notes:
-** ------
-** (1) For performance reasons read and write routines don't check buffer sizes
-**     and/or number of bytes free/available. This has to be done before these
-**     routines are called. For example:
-**
-**     *** write <buflen> bytes ***
-**     free = dvb_ringbuffer_free(rbuf);
-**     if (free >= buflen)
-**         count = dvb_ringbuffer_write(rbuf, buffer, buflen);
-**     else
-**         ...
-**
-**     *** read min. 1000, max. <bufsize> bytes ***
-**     avail = dvb_ringbuffer_avail(rbuf);
-**     if (avail >= 1000)
-**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
-**     else
-**         ...
-**
-** (2) If there is exactly one reader and one writer, there is no need
-**     to lock read or write operations.
-**     Two or more readers must be locked against each other.
-**     Flushing the buffer counts as a read operation.
-**     Resetting the buffer counts as a read and write operation.
-**     Two or more writers must be locked against each other.
-*/
+ * Notes:
+ * ------
+ * (1) For performance reasons read and write routines don't check buffer sizes
+ *     and/or number of bytes free/available. This has to be done before these
+ *     routines are called. For example:
+ *
+ *     *** write @buflen: bytes ***
+ *     free = dvb_ringbuffer_free(rbuf);
+ *     if (free >= buflen)
+ *         count = dvb_ringbuffer_write(rbuf, buffer, buflen);
+ *     else
+ *         ...
+ *
+ *     *** read min. 1000, max. @bufsize: bytes ***
+ *     avail = dvb_ringbuffer_avail(rbuf);
+ *     if (avail >= 1000)
+ *         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
+ *     else
+ *         ...
+ *
+ * (2) If there is exactly one reader and one writer, there is no need
+ *     to lock read or write operations.
+ *     Two or more readers must be locked against each other.
+ *     Flushing the buffer counts as a read operation.
+ *     Resetting the buffer counts as a read and write operation.
+ *     Two or more writers must be locked against each other.
+ */
 
 /* initialize ring buffer, lock and queue */
 extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len);
@@ -87,9 +87,9 @@ extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
 
 
 /*
-** Reset the read and write pointers to zero and flush the buffer
-** This counts as a read and write operation
-*/
+ * Reset the read and write pointers to zero and flush the buffer
+ * This counts as a read and write operation
+ */
 extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
 
 
@@ -101,19 +101,19 @@ extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
 /* flush buffer protected by spinlock and wake-up waiting task(s) */
 extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
 
-/* peek at byte <offs> in the buffer */
+/* peek at byte @offs: in the buffer */
 #define DVB_RINGBUFFER_PEEK(rbuf,offs)	\
 			(rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
 
-/* advance read ptr by <num> bytes */
+/* advance read ptr by @num: bytes */
 #define DVB_RINGBUFFER_SKIP(rbuf,num)	\
 			(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
 
 /*
-** read <len> bytes from ring buffer into <buf>
-** <usermem> specifies whether <buf> resides in user space
-** returns number of bytes transferred or -EFAULT
-*/
+ * read @len: bytes from ring buffer into @buf:
+ * @usermem: specifies whether @buf: resides in user space
+ * returns number of bytes transferred or -EFAULT
+ */
 extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
 				   u8 __user *buf, size_t len);
 extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
@@ -127,9 +127,9 @@ extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
 			{ (rbuf)->data[(rbuf)->pwrite]=(byte); \
 			(rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
 /*
-** write <len> bytes to ring buffer
-** <usermem> specifies whether <buf> resides in user space
-** returns number of bytes transferred or -EFAULT
+ * write @len: bytes to ring buffer
+ * @usermem: specifies whether @buf: resides in user space
+ * returns number of bytes transferred or -EFAULT
 */
 extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
 				    size_t len);
@@ -138,48 +138,63 @@ extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
 
 
 /**
- * Write a packet into the ringbuffer.
+ * dvb_ringbuffer_pkt_write - Write a packet into the ringbuffer.
  *
- * <rbuf> Ringbuffer to write to.
- * <buf> Buffer to write.
- * <len> Length of buffer (currently limited to 65535 bytes max).
+ * @rbuf: Ringbuffer to write to.
+ * @buf: Buffer to write.
+ * @len: Length of buffer (currently limited to 65535 bytes max).
  * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
  */
 extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
 					size_t len);
 
 /**
- * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
- * does NOT update the read pointer in the ringbuffer. You must use
- * dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
- *
- * <rbuf> Ringbuffer concerned.
- * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
- * <offset> Offset into packet to read from.
- * <buf> Destination buffer for data.
- * <len> Size of destination buffer.
- * <usermem> Set to 1 if <buf> is in userspace.
+ * dvb_ringbuffer_pkt_read_user - Read from a packet in the ringbuffer.
+ * Note: unlike dvb_ringbuffer_read(), this does NOT update the read pointer
+ * in the ringbuffer. You must use dvb_ringbuffer_pkt_dispose() to mark a
+ * packet as no longer required.
+ *
+ * @rbuf: Ringbuffer concerned.
+ * @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
+ * @offset: Offset into packet to read from.
+ * @buf: Destination buffer for data.
+ * @len: Size of destination buffer.
+ *
  * returns Number of bytes read, or -EFAULT.
  */
 extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
 				       int offset, u8 __user *buf, size_t len);
+
+/**
+ * dvb_ringbuffer_pkt_read - Read from a packet in the ringbuffer.
+ * Note: unlike dvb_ringbuffer_read_user(), this DOES update the read pointer
+ * in the ringbuffer.
+ *
+ * @rbuf: Ringbuffer concerned.
+ * @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
+ * @offset: Offset into packet to read from.
+ * @buf: Destination buffer for data.
+ * @len: Size of destination buffer.
+ *
+ * returns Number of bytes read, or -EFAULT.
+ */
 extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
 				       int offset, u8 *buf, size_t len);
 
 /**
- * Dispose of a packet in the ring buffer.
+ * dvb_ringbuffer_pkt_dispose - Dispose of a packet in the ring buffer.
  *
- * <rbuf> Ring buffer concerned.
- * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
+ * @rbuf: Ring buffer concerned.
+ * @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
  */
 extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
 
 /**
- * Get the index of the next packet in a ringbuffer.
+ * dvb_ringbuffer_pkt_next - Get the index of the next packet in a ringbuffer.
  *
- * <rbuf> Ringbuffer concerned.
- * <idx> Previous packet index, or -1 to return the first packet index.
- * <pktlen> On success, will be updated to contain the length of the packet in bytes.
+ * @rbuf: Ringbuffer concerned.
+ * @idx: Previous packet index, or -1 to return the first packet index.
+ * @pktlen: On success, will be updated to contain the length of the packet in bytes.
  * returns Packet index (if >=0), or -1 if no packets available.
  */
 extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);

+ 99 - 17
drivers/media/dvb-core/dvbdev.h

@@ -57,6 +57,25 @@
 
 struct dvb_frontend;
 
+/**
+ * struct dvb_adapter - represents a Digital TV adapter using Linux DVB API
+ *
+ * @num:		Number of the adapter
+ * @list_head:		List with the DVB adapters
+ * @device_list:	List with the DVB devices
+ * @name:		Name of the adapter
+ * @proposed_mac:	proposed MAC address for the adapter
+ * @priv:		private data
+ * @device:		pointer to struct device
+ * @module:		pointer to struct module
+ * @mfe_shared:		mfe shared: indicates mutually exclusive frontends
+ *			Thie usage of this flag is currently deprecated
+ * @mfe_dvbdev:		Frontend device in use, in the case of MFE
+ * @mfe_lock:		Lock to prevent using the other frontends when MFE is
+ *			used.
+ * @mdev:		pointer to struct media_device, used when the media
+ *			controller is used.
+ */
 struct dvb_adapter {
 	int num;
 	struct list_head list_head;
@@ -78,7 +97,34 @@ struct dvb_adapter {
 #endif
 };
 
-
+/**
+ * struct dvb_device - represents a DVB device node
+ *
+ * @list_head:	List head with all DVB devices
+ * @fops:	pointer to struct file_operations
+ * @adapter:	pointer to the adapter that holds this device node
+ * @type:	type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND,
+ *		DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
+ * @minor:	devnode minor number. Major number is always DVB_MAJOR.
+ * @id:		device ID number, inside the adapter
+ * @readers:	Initialized by the caller. Each call to open() in Read Only mode
+ *		decreases this counter by one.
+ * @writers:	Initialized by the caller. Each call to open() in Read/Write
+ *		mode decreases this counter by one.
+ * @users:	Initialized by the caller. Each call to open() in any mode
+ *		decreases this counter by one.
+ * @wait_queue:	wait queue, used to wait for certain events inside one of
+ *		the DVB API callers
+ * @kernel_ioctl: callback function used to handle ioctl calls from userspace.
+ * @name:	Name to be used for the device at the Media Controller
+ * @entity:	pointer to struct media_entity associated with the device node
+ * @pads:	pointer to struct media_pad associated with @entity;
+ * @priv:	private data
+ *
+ * This structure is used by the DVB core (frontend, CA, net, demux) in
+ * order to create the device nodes. Usually, driver should not initialize
+ * this struct diretly.
+ */
 struct dvb_device {
 	struct list_head list_head;
 	const struct file_operations *fops;
@@ -109,19 +155,55 @@ struct dvb_device {
 	void *priv;
 };
 
+/**
+ * dvb_register_adapter - Registers a new DVB adapter
+ *
+ * @adap:	pointer to struct dvb_adapter
+ * @name:	Adapter's name
+ * @module:	initialized with THIS_MODULE at the caller
+ * @device:	pointer to struct device that corresponds to the device driver
+ * @adapter_nums: Array with a list of the numbers for @dvb_register_adapter;
+ * 		to select among them. Typically, initialized with:
+ *		DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums)
+ */
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+			 struct module *module, struct device *device,
+			 short *adapter_nums);
 
-extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
-				struct module *module, struct device *device,
-				short *adapter_nums);
-extern int dvb_unregister_adapter (struct dvb_adapter *adap);
-
-extern int dvb_register_device (struct dvb_adapter *adap,
-				struct dvb_device **pdvbdev,
-				const struct dvb_device *template,
-				void *priv,
-				int type);
+/**
+ * dvb_unregister_adapter - Unregisters a DVB adapter
+ *
+ * @adap:	pointer to struct dvb_adapter
+ */
+int dvb_unregister_adapter(struct dvb_adapter *adap);
 
-extern void dvb_unregister_device (struct dvb_device *dvbdev);
+/**
+ * dvb_register_device - Registers a new DVB device
+ *
+ * @adap:	pointer to struct dvb_adapter
+ * @pdvbdev:	pointer to the place where the new struct dvb_device will be
+ *		stored
+ * @template:	Template used to create &pdvbdev;
+ * @device:	pointer to struct device that corresponds to the device driver
+ * @adapter_nums: Array with a list of the numbers for @dvb_register_adapter;
+ * 		to select among them. Typically, initialized with:
+ *		DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums)
+ * @priv:	private data
+ * @type:	type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND,
+ *		DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
+ */
+int dvb_register_device(struct dvb_adapter *adap,
+			struct dvb_device **pdvbdev,
+			const struct dvb_device *template,
+			void *priv,
+			int type);
+
+/**
+ * dvb_unregister_device - Unregisters a DVB device
+ *
+ * @dvbdev:	pointer to struct dvb_device
+ */
+void dvb_unregister_device(struct dvb_device *dvbdev);
 
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 void dvb_create_media_graph(struct dvb_adapter *adap);
@@ -136,17 +218,17 @@ static inline void dvb_create_media_graph(struct dvb_adapter *adap) {}
 #define dvb_register_media_controller(a, b) {}
 #endif
 
-extern int dvb_generic_open (struct inode *inode, struct file *file);
-extern int dvb_generic_release (struct inode *inode, struct file *file);
-extern long dvb_generic_ioctl (struct file *file,
+int dvb_generic_open (struct inode *inode, struct file *file);
+int dvb_generic_release (struct inode *inode, struct file *file);
+long dvb_generic_ioctl (struct file *file,
 			      unsigned int cmd, unsigned long arg);
 
 /* we don't mess with video_usercopy() any more,
 we simply define out own dvb_usercopy(), which will hopefully become
 generic_usercopy()  someday... */
 
-extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
-			    int (*func)(struct file *file, unsigned int cmd, void *arg));
+int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+		 int (*func)(struct file *file, unsigned int cmd, void *arg));
 
 /** generic DVB attach function. */
 #ifdef CONFIG_MEDIA_ATTACH

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

@@ -1,5 +1,5 @@
 menu "Customise DVB Frontends"
-	visible if !MEDIA_SUBDRV_AUTOSELECT
+	visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST
 
 comment "Multistandard (satellite) frontends"
 	depends on DVB_CORE
@@ -264,6 +264,7 @@ config DVB_MB86A16
 config DVB_TDA10071
 	tristate "NXP TDA10071"
 	depends on DVB_CORE && I2C
+	select REGMAP
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
 	  Say Y when you want to support this frontend.
@@ -450,6 +451,13 @@ config DVB_CXD2820R
 	help
 	  Say Y when you want to support this frontend.
 
+config DVB_CXD2841ER
+	tristate "Sony CXD2841ER"
+	depends on DVB_CORE && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Say Y when you want to support this frontend.
+
 config DVB_RTL2830
 	tristate "Realtek RTL2830 DVB-T"
 	depends on DVB_CORE && I2C && I2C_MUX
@@ -712,6 +720,14 @@ comment "SEC control devices for DVB-S"
 
 source "drivers/media/dvb-frontends/drx39xyj/Kconfig"
 
+config DVB_LNBH25
+	tristate "LNBH25 SEC controller"
+	depends on DVB_CORE && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  An SEC control chip.
+	  Say Y when you want to support this chip.
+
 config DVB_LNBP21
 	tristate "LNBP21/LNBH24 SEC controllers"
 	depends on DVB_CORE && I2C
@@ -815,6 +831,20 @@ config DVB_AF9033
 	depends on DVB_CORE && I2C
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 
+config DVB_HORUS3A
+	tristate "Sony Horus3A tuner"
+	depends on DVB_CORE && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Say Y when you want to support this frontend.
+
+config DVB_ASCOT2E
+	tristate "Sony Ascot2E tuner"
+	depends on DVB_CORE && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Say Y when you want to support this frontend.
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE

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

@@ -57,6 +57,7 @@ obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
 obj-$(CONFIG_DVB_LGDT3306A) += lgdt3306a.o
 obj-$(CONFIG_DVB_LG2160) += lg2160.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBH25) += lnbh25.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
 obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
 obj-$(CONFIG_DVB_ISL6405) += isl6405.o
@@ -105,6 +106,7 @@ obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
 obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
 obj-$(CONFIG_DVB_STV0367) += stv0367.o
 obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
+obj-$(CONFIG_DVB_CXD2841ER) += cxd2841er.o
 obj-$(CONFIG_DVB_DRXK) += drxk.o
 obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
 obj-$(CONFIG_DVB_SI2165) += si2165.o
@@ -118,3 +120,5 @@ obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
 obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o
 obj-$(CONFIG_DVB_TC90522) += tc90522.o
+obj-$(CONFIG_DVB_HORUS3A) += horus3a.o
+obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o

+ 29 - 139
drivers/media/dvb-frontends/a8293.c

@@ -12,163 +12,69 @@
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "dvb_frontend.h"
 #include "a8293.h"
 
-struct a8293_priv {
-	u8 i2c_addr;
-	struct i2c_adapter *i2c;
+struct a8293_dev {
 	struct i2c_client *client;
 	u8 reg[2];
 };
 
-static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd)
-{
-	int ret;
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->i2c_addr,
-			.len = len,
-			.buf = val,
-		}
-	};
-
-	if (rd)
-		msg[0].flags = I2C_M_RD;
-	else
-		msg[0].flags = 0;
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev, "%s: i2c failed=%d rd=%d\n",
-				KBUILD_MODNAME, ret, rd);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-static int a8293_wr(struct a8293_priv *priv, u8 *val, int len)
-{
-	return a8293_i2c(priv, val, len, 0);
-}
-
-static int a8293_rd(struct a8293_priv *priv, u8 *val, int len)
-{
-	return a8293_i2c(priv, val, len, 1);
-}
-
 static int a8293_set_voltage(struct dvb_frontend *fe,
-	enum fe_sec_voltage fe_sec_voltage)
+			     enum fe_sec_voltage fe_sec_voltage)
 {
-	struct a8293_priv *priv = fe->sec_priv;
+	struct a8293_dev *dev = fe->sec_priv;
+	struct i2c_client *client = dev->client;
 	int ret;
+	u8 reg0, reg1;
 
-	dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__,
-			fe_sec_voltage);
+	dev_dbg(&client->dev, "fe_sec_voltage=%d\n", fe_sec_voltage);
 
 	switch (fe_sec_voltage) {
 	case SEC_VOLTAGE_OFF:
 		/* ENB=0 */
-		priv->reg[0] = 0x10;
+		reg0 = 0x10;
 		break;
 	case SEC_VOLTAGE_13:
 		/* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/
-		priv->reg[0] = 0x31;
+		reg0 = 0x31;
 		break;
 	case SEC_VOLTAGE_18:
 		/* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/
-		priv->reg[0] = 0x38;
+		reg0 = 0x38;
 		break;
 	default:
 		ret = -EINVAL;
 		goto err;
 	}
-
-	ret = a8293_wr(priv, &priv->reg[0], 1);
-	if (ret)
-		goto err;
-
-	usleep_range(1500, 50000);
-
-	return ret;
-err:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
-
-static void a8293_release_sec(struct dvb_frontend *fe)
-{
-	a8293_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-	kfree(fe->sec_priv);
-	fe->sec_priv = NULL;
-}
-
-struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, const struct a8293_config *cfg)
-{
-	int ret;
-	struct a8293_priv *priv = NULL;
-	u8 buf[2];
-
-	/* allocate memory for the internal priv */
-	priv = kzalloc(sizeof(struct a8293_priv), GFP_KERNEL);
-	if (priv == NULL) {
-		ret = -ENOMEM;
-		goto err;
+	if (reg0 != dev->reg[0]) {
+		ret = i2c_master_send(client, &reg0, 1);
+		if (ret < 0)
+			goto err;
+		dev->reg[0] = reg0;
 	}
 
-	/* setup the priv */
-	priv->i2c = i2c;
-	priv->i2c_addr = cfg->i2c_addr;
-	fe->sec_priv = priv;
-
-	/* check if the SEC is there */
-	ret = a8293_rd(priv, buf, 2);
-	if (ret)
-		goto err;
-
-	/* ENB=0 */
-	priv->reg[0] = 0x10;
-	ret = a8293_wr(priv, &priv->reg[0], 1);
-	if (ret)
-		goto err;
-
 	/* TMODE=0, TGATE=1 */
-	priv->reg[1] = 0x82;
-	ret = a8293_wr(priv, &priv->reg[1], 1);
-	if (ret)
-		goto err;
-
-	fe->ops.release_sec = a8293_release_sec;
-
-	/* override frontend ops */
-	fe->ops.set_voltage = a8293_set_voltage;
-
-	dev_info(&priv->i2c->dev, "%s: Allegro A8293 SEC attached\n",
-			KBUILD_MODNAME);
+	reg1 = 0x82;
+	if (reg1 != dev->reg[1]) {
+		ret = i2c_master_send(client, &reg1, 1);
+		if (ret < 0)
+			goto err;
+		dev->reg[1] = reg1;
+	}
 
-	return fe;
+	usleep_range(1500, 50000);
+	return 0;
 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(a8293_attach);
 
 static int a8293_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
+		       const struct i2c_device_id *id)
 {
-	struct a8293_priv *dev;
+	struct a8293_dev *dev;
 	struct a8293_platform_data *pdata = client->dev.platform_data;
 	struct dvb_frontend *fe = pdata->dvb_frontend;
 	int ret;
@@ -181,29 +87,14 @@ static int a8293_probe(struct i2c_client *client,
 	}
 
 	dev->client = client;
-	dev->i2c = client->adapter;
-	dev->i2c_addr = client->addr;
 
 	/* check if the SEC is there */
-	ret = a8293_rd(dev, buf, 2);
-	if (ret)
-		goto err_kfree;
-
-	/* ENB=0 */
-	dev->reg[0] = 0x10;
-	ret = a8293_wr(dev, &dev->reg[0], 1);
-	if (ret)
-		goto err_kfree;
-
-	/* TMODE=0, TGATE=1 */
-	dev->reg[1] = 0x82;
-	ret = a8293_wr(dev, &dev->reg[1], 1);
-	if (ret)
+	ret = i2c_master_recv(client, buf, 2);
+	if (ret < 0)
 		goto err_kfree;
 
 	/* override frontend ops */
 	fe->ops.set_voltage = a8293_set_voltage;
-
 	fe->sec_priv = dev;
 	i2c_set_clientdata(client, dev);
 
@@ -234,7 +125,6 @@ MODULE_DEVICE_TABLE(i2c, a8293_id_table);
 
 static struct i2c_driver a8293_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "a8293",
 		.suppress_bind_attrs = true,
 	},

+ 0 - 22
drivers/media/dvb-frontends/a8293.h

@@ -12,17 +12,12 @@
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License along
- *    with this program; if not, write to the Free Software Foundation, Inc.,
- *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 #ifndef A8293_H
 #define A8293_H
 
 #include "dvb_frontend.h"
-#include <linux/kconfig.h>
 
 /*
  * I2C address
@@ -37,21 +32,4 @@ struct a8293_platform_data {
 	struct dvb_frontend *dvb_frontend;
 };
 
-
-struct a8293_config {
-	u8 i2c_addr;
-};
-
-#if IS_REACHABLE(CONFIG_DVB_A8293)
-extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, const struct a8293_config *cfg);
-#else
-static inline struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, const struct a8293_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
 #endif /* A8293_H */

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

@@ -1387,7 +1387,6 @@ MODULE_DEVICE_TABLE(i2c, af9033_id_table);
 
 static struct i2c_driver af9033_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "af9033",
 	},
 	.probe		= af9033_probe,

+ 548 - 0
drivers/media/dvb-frontends/ascot2e.c

@@ -0,0 +1,548 @@
+/*
+ * ascot2e.c
+ *
+ * Sony Ascot3E DVB-T/T2/C/C2 tuner driver
+ *
+ * Copyright 2012 Sony Corporation
+ * Copyright (C) 2014 NetUP Inc.
+ * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
+ * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+  */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <linux/types.h>
+#include "ascot2e.h"
+#include "dvb_frontend.h"
+
+#define MAX_WRITE_REGSIZE 10
+
+enum ascot2e_state {
+	STATE_UNKNOWN,
+	STATE_SLEEP,
+	STATE_ACTIVE
+};
+
+struct ascot2e_priv {
+	u32			frequency;
+	u8			i2c_address;
+	struct i2c_adapter	*i2c;
+	enum ascot2e_state	state;
+	void			*set_tuner_data;
+	int			(*set_tuner)(void *, int);
+};
+
+enum ascot2e_tv_system_t {
+	ASCOT2E_DTV_DVBT_5,
+	ASCOT2E_DTV_DVBT_6,
+	ASCOT2E_DTV_DVBT_7,
+	ASCOT2E_DTV_DVBT_8,
+	ASCOT2E_DTV_DVBT2_1_7,
+	ASCOT2E_DTV_DVBT2_5,
+	ASCOT2E_DTV_DVBT2_6,
+	ASCOT2E_DTV_DVBT2_7,
+	ASCOT2E_DTV_DVBT2_8,
+	ASCOT2E_DTV_DVBC_6,
+	ASCOT2E_DTV_DVBC_8,
+	ASCOT2E_DTV_DVBC2_6,
+	ASCOT2E_DTV_DVBC2_8,
+	ASCOT2E_DTV_UNKNOWN
+};
+
+struct ascot2e_band_sett {
+	u8	if_out_sel;
+	u8	agc_sel;
+	u8	mix_oll;
+	u8	rf_gain;
+	u8	if_bpf_gc;
+	u8	fif_offset;
+	u8	bw_offset;
+	u8	bw;
+	u8	rf_oldet;
+	u8	if_bpf_f0;
+};
+
+#define ASCOT2E_AUTO		0xff
+#define ASCOT2E_OFFSET(ofs)	((u8)(ofs) & 0x1F)
+#define ASCOT2E_BW_6		0x00
+#define ASCOT2E_BW_7		0x01
+#define ASCOT2E_BW_8		0x02
+#define ASCOT2E_BW_1_7		0x03
+
+static struct ascot2e_band_sett ascot2e_sett[] = {
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06,
+	  ASCOT2E_OFFSET(-8), ASCOT2E_OFFSET(-6), ASCOT2E_BW_6,  0x0B, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06,
+	  ASCOT2E_OFFSET(-8), ASCOT2E_OFFSET(-6), ASCOT2E_BW_6,  0x0B, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06,
+	  ASCOT2E_OFFSET(-6), ASCOT2E_OFFSET(-4), ASCOT2E_BW_7,  0x0B, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06,
+	  ASCOT2E_OFFSET(-4), ASCOT2E_OFFSET(-2), ASCOT2E_BW_8,  0x0B, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06,
+	ASCOT2E_OFFSET(-10), ASCOT2E_OFFSET(-16), ASCOT2E_BW_1_7, 0x0B, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06,
+	  ASCOT2E_OFFSET(-8), ASCOT2E_OFFSET(-6), ASCOT2E_BW_6,  0x0B, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06,
+	  ASCOT2E_OFFSET(-8), ASCOT2E_OFFSET(-6), ASCOT2E_BW_6,  0x0B, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06,
+	  ASCOT2E_OFFSET(-6), ASCOT2E_OFFSET(-4), ASCOT2E_BW_7,  0x0B, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x06,
+	  ASCOT2E_OFFSET(-4), ASCOT2E_OFFSET(-2), ASCOT2E_BW_8,  0x0B, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x02, ASCOT2E_AUTO, 0x03,
+	  ASCOT2E_OFFSET(-6), ASCOT2E_OFFSET(-8), ASCOT2E_BW_6,  0x09, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x02, ASCOT2E_AUTO, 0x03,
+	  ASCOT2E_OFFSET(-2), ASCOT2E_OFFSET(-1), ASCOT2E_BW_8,  0x09, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x01,
+	  ASCOT2E_OFFSET(-6), ASCOT2E_OFFSET(-4), ASCOT2E_BW_6,  0x09, 0x00 },
+	{ ASCOT2E_AUTO, ASCOT2E_AUTO, 0x03, ASCOT2E_AUTO, 0x01,
+	  ASCOT2E_OFFSET(-2), ASCOT2E_OFFSET(2),  ASCOT2E_BW_8,  0x09, 0x00 }
+};
+
+static void ascot2e_i2c_debug(struct ascot2e_priv *priv,
+			      u8 reg, u8 write, const u8 *data, u32 len)
+{
+	dev_dbg(&priv->i2c->dev, "ascot2e: I2C %s reg 0x%02x size %d\n",
+		(write == 0 ? "read" : "write"), reg, len);
+	print_hex_dump_bytes("ascot2e: I2C data: ",
+		DUMP_PREFIX_OFFSET, data, len);
+}
+
+static int ascot2e_write_regs(struct ascot2e_priv *priv,
+			      u8 reg, const u8 *data, u32 len)
+{
+	int ret;
+	u8 buf[MAX_WRITE_REGSIZE + 1];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->i2c_address,
+			.flags = 0,
+			.len = len + 1,
+			.buf = buf,
+		}
+	};
+
+	if (len + 1 >= sizeof(buf)) {
+		dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n",
+			 reg, len + 1);
+		return -E2BIG;
+	}
+
+	ascot2e_i2c_debug(priv, reg, 1, data, len);
+	buf[0] = reg;
+	memcpy(&buf[1], data, len);
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret >= 0 && ret != 1)
+		ret = -EREMOTEIO;
+	if (ret < 0) {
+		dev_warn(&priv->i2c->dev,
+			"%s: i2c wr failed=%d reg=%02x len=%d\n",
+			KBUILD_MODNAME, ret, reg, len);
+		return ret;
+	}
+	return 0;
+}
+
+static int ascot2e_write_reg(struct ascot2e_priv *priv, u8 reg, u8 val)
+{
+	return ascot2e_write_regs(priv, reg, &val, 1);
+}
+
+static int ascot2e_read_regs(struct ascot2e_priv *priv,
+			     u8 reg, u8 *val, u32 len)
+{
+	int ret;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->i2c_address,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = priv->i2c_address,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, &msg[0], 1);
+	if (ret >= 0 && ret != 1)
+		ret = -EREMOTEIO;
+	if (ret < 0) {
+		dev_warn(&priv->i2c->dev,
+			"%s: I2C rw failed=%d addr=%02x reg=%02x\n",
+			KBUILD_MODNAME, ret, priv->i2c_address, reg);
+		return ret;
+	}
+	ret = i2c_transfer(priv->i2c, &msg[1], 1);
+	if (ret >= 0 && ret != 1)
+		ret = -EREMOTEIO;
+	if (ret < 0) {
+		dev_warn(&priv->i2c->dev,
+			"%s: i2c rd failed=%d addr=%02x reg=%02x\n",
+			KBUILD_MODNAME, ret, priv->i2c_address, reg);
+		return ret;
+	}
+	ascot2e_i2c_debug(priv, reg, 0, val, len);
+	return 0;
+}
+
+static int ascot2e_read_reg(struct ascot2e_priv *priv, u8 reg, u8 *val)
+{
+	return ascot2e_read_regs(priv, reg, val, 1);
+}
+
+static int ascot2e_set_reg_bits(struct ascot2e_priv *priv,
+				u8 reg, u8 data, u8 mask)
+{
+	int res;
+	u8 rdata;
+
+	if (mask != 0xff) {
+		res = ascot2e_read_reg(priv, reg, &rdata);
+		if (res != 0)
+			return res;
+		data = ((data & mask) | (rdata & (mask ^ 0xFF)));
+	}
+	return ascot2e_write_reg(priv, reg, data);
+}
+
+static int ascot2e_enter_power_save(struct ascot2e_priv *priv)
+{
+	u8 data[2];
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state == STATE_SLEEP)
+		return 0;
+	data[0] = 0x00;
+	data[1] = 0x04;
+	ascot2e_write_regs(priv, 0x14, data, 2);
+	ascot2e_write_reg(priv, 0x50, 0x01);
+	priv->state = STATE_SLEEP;
+	return 0;
+}
+
+static int ascot2e_leave_power_save(struct ascot2e_priv *priv)
+{
+	u8 data[2] = { 0xFB, 0x0F };
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state == STATE_ACTIVE)
+		return 0;
+	ascot2e_write_regs(priv, 0x14, data, 2);
+	ascot2e_write_reg(priv, 0x50, 0x00);
+	priv->state = STATE_ACTIVE;
+	return 0;
+}
+
+static int ascot2e_init(struct dvb_frontend *fe)
+{
+	struct ascot2e_priv *priv = fe->tuner_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	return ascot2e_leave_power_save(priv);
+}
+
+static int ascot2e_release(struct dvb_frontend *fe)
+{
+	struct ascot2e_priv *priv = fe->tuner_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int ascot2e_sleep(struct dvb_frontend *fe)
+{
+	struct ascot2e_priv *priv = fe->tuner_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	ascot2e_enter_power_save(priv);
+	return 0;
+}
+
+static enum ascot2e_tv_system_t ascot2e_get_tv_system(struct dvb_frontend *fe)
+{
+	enum ascot2e_tv_system_t system = ASCOT2E_DTV_UNKNOWN;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct ascot2e_priv *priv = fe->tuner_priv;
+
+	if (p->delivery_system == SYS_DVBT) {
+		if (p->bandwidth_hz <= 5000000)
+			system = ASCOT2E_DTV_DVBT_5;
+		else if (p->bandwidth_hz <= 6000000)
+			system = ASCOT2E_DTV_DVBT_6;
+		else if (p->bandwidth_hz <= 7000000)
+			system = ASCOT2E_DTV_DVBT_7;
+		else if (p->bandwidth_hz <= 8000000)
+			system = ASCOT2E_DTV_DVBT_8;
+		else {
+			system = ASCOT2E_DTV_DVBT_8;
+			p->bandwidth_hz = 8000000;
+		}
+	} else if (p->delivery_system == SYS_DVBT2) {
+		if (p->bandwidth_hz <= 5000000)
+			system = ASCOT2E_DTV_DVBT2_5;
+		else if (p->bandwidth_hz <= 6000000)
+			system = ASCOT2E_DTV_DVBT2_6;
+		else if (p->bandwidth_hz <= 7000000)
+			system = ASCOT2E_DTV_DVBT2_7;
+		else if (p->bandwidth_hz <= 8000000)
+			system = ASCOT2E_DTV_DVBT2_8;
+		else {
+			system = ASCOT2E_DTV_DVBT2_8;
+			p->bandwidth_hz = 8000000;
+		}
+	} else if (p->delivery_system == SYS_DVBC_ANNEX_A) {
+		if (p->bandwidth_hz <= 6000000)
+			system = ASCOT2E_DTV_DVBC_6;
+		else if (p->bandwidth_hz <= 8000000)
+			system = ASCOT2E_DTV_DVBC_8;
+	}
+	dev_dbg(&priv->i2c->dev,
+		"%s(): ASCOT2E DTV system %d (delsys %d, bandwidth %d)\n",
+		__func__, (int)system, p->delivery_system, p->bandwidth_hz);
+	return system;
+}
+
+static int ascot2e_set_params(struct dvb_frontend *fe)
+{
+	u8 data[10];
+	u32 frequency;
+	enum ascot2e_tv_system_t tv_system;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct ascot2e_priv *priv = fe->tuner_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s(): tune frequency %dkHz\n",
+		__func__, p->frequency / 1000);
+	tv_system = ascot2e_get_tv_system(fe);
+
+	if (tv_system == ASCOT2E_DTV_UNKNOWN) {
+		dev_dbg(&priv->i2c->dev, "%s(): unknown DTV system\n",
+			__func__);
+		return -EINVAL;
+	}
+	if (priv->set_tuner)
+		priv->set_tuner(priv->set_tuner_data, 1);
+	frequency = roundup(p->frequency / 1000, 25);
+	if (priv->state == STATE_SLEEP)
+		ascot2e_leave_power_save(priv);
+
+	/* IF_OUT_SEL / AGC_SEL setting */
+	data[0] = 0x00;
+	if (ascot2e_sett[tv_system].agc_sel != ASCOT2E_AUTO) {
+		/* AGC pin setting from parameter table */
+		data[0] |= (u8)(
+			(ascot2e_sett[tv_system].agc_sel & 0x03) << 3);
+	}
+	if (ascot2e_sett[tv_system].if_out_sel != ASCOT2E_AUTO) {
+		/* IFOUT pin setting from parameter table */
+		data[0] |= (u8)(
+			(ascot2e_sett[tv_system].if_out_sel & 0x01) << 2);
+	}
+	/* Set bit[4:2] only */
+	ascot2e_set_reg_bits(priv, 0x05, data[0], 0x1c);
+	/* 0x06 - 0x0F */
+	/* REF_R setting (0x06) */
+	if (tv_system == ASCOT2E_DTV_DVBC_6 ||
+			tv_system == ASCOT2E_DTV_DVBC_8) {
+		/* xtal, xtal*2 */
+		data[0] = (frequency > 500000) ? 16 : 32;
+	} else {
+		/* xtal/8, xtal/4 */
+		data[0] = (frequency > 500000) ? 2 : 4;
+	}
+	/* XOSC_SEL=100uA */
+	data[1] = 0x04;
+	/* KBW setting (0x08), KC0 setting (0x09), KC1 setting (0x0A) */
+	if (tv_system == ASCOT2E_DTV_DVBC_6 ||
+			tv_system == ASCOT2E_DTV_DVBC_8) {
+		data[2] = 18;
+		data[3] = 120;
+		data[4] = 20;
+	} else {
+		data[2] = 48;
+		data[3] = 10;
+		data[4] = 30;
+	}
+	/* ORDER/R2_RANGE/R2_BANK/C2_BANK setting (0x0B) */
+	if (tv_system == ASCOT2E_DTV_DVBC_6 ||
+			tv_system == ASCOT2E_DTV_DVBC_8)
+		data[5] = (frequency > 500000) ? 0x08 : 0x0c;
+	else
+		data[5] = (frequency > 500000) ? 0x30 : 0x38;
+	/* Set MIX_OLL (0x0C) value from parameter table */
+	data[6] = ascot2e_sett[tv_system].mix_oll;
+	/* Set RF_GAIN (0x0D) setting from parameter table */
+	if (ascot2e_sett[tv_system].rf_gain == ASCOT2E_AUTO) {
+		/* RF_GAIN auto control enable */
+		ascot2e_write_reg(priv, 0x4E, 0x01);
+		/* RF_GAIN Default value */
+		data[7] = 0x00;
+	} else {
+		/* RF_GAIN auto control disable */
+		ascot2e_write_reg(priv, 0x4E, 0x00);
+		data[7] = ascot2e_sett[tv_system].rf_gain;
+	}
+	/* Set IF_BPF_GC/FIF_OFFSET (0x0E) value from parameter table */
+	data[8] = (u8)((ascot2e_sett[tv_system].fif_offset << 3) |
+		(ascot2e_sett[tv_system].if_bpf_gc & 0x07));
+	/* Set BW_OFFSET (0x0F) value from parameter table */
+	data[9] = ascot2e_sett[tv_system].bw_offset;
+	ascot2e_write_regs(priv, 0x06, data, 10);
+	/*
+	 * 0x45 - 0x47
+	 * LNA optimization setting
+	 * RF_LNA_DIST1-5, RF_LNA_CM
+	 */
+	if (tv_system == ASCOT2E_DTV_DVBC_6 ||
+			tv_system == ASCOT2E_DTV_DVBC_8) {
+		data[0] = 0x0F;
+		data[1] = 0x00;
+		data[2] = 0x01;
+	} else {
+		data[0] = 0x0F;
+		data[1] = 0x00;
+		data[2] = 0x03;
+	}
+	ascot2e_write_regs(priv, 0x45, data, 3);
+	/* 0x49 - 0x4A
+	 Set RF_OLDET_ENX/RF_OLDET_OLL value from parameter table */
+	data[0] = ascot2e_sett[tv_system].rf_oldet;
+	/* Set IF_BPF_F0 value from parameter table */
+	data[1] = ascot2e_sett[tv_system].if_bpf_f0;
+	ascot2e_write_regs(priv, 0x49, data, 2);
+	/*
+	 * Tune now
+	 * RFAGC fast mode / RFAGC auto control enable
+	 * (set bit[7], bit[5:4] only)
+	 * vco_cal = 1, set MIX_OL_CPU_EN
+	 */
+	ascot2e_set_reg_bits(priv, 0x0c, 0x90, 0xb0);
+	/* Logic wake up, CPU wake up */
+	data[0] = 0xc4;
+	data[1] = 0x40;
+	ascot2e_write_regs(priv, 0x03, data, 2);
+	/* 0x10 - 0x14 */
+	data[0] = (u8)(frequency & 0xFF);         /* 0x10: FRF_L */
+	data[1] = (u8)((frequency >> 8) & 0xFF);  /* 0x11: FRF_M */
+	data[2] = (u8)((frequency >> 16) & 0x0F); /* 0x12: FRF_H (bit[3:0]) */
+	/* 0x12: BW (bit[5:4]) */
+	data[2] |= (u8)(ascot2e_sett[tv_system].bw << 4);
+	data[3] = 0xFF; /* 0x13: VCO calibration enable */
+	data[4] = 0xFF; /* 0x14: Analog block enable */
+	/* Tune (Burst write) */
+	ascot2e_write_regs(priv, 0x10, data, 5);
+	msleep(50);
+	/* CPU deep sleep */
+	ascot2e_write_reg(priv, 0x04, 0x00);
+	/* Logic sleep */
+	ascot2e_write_reg(priv, 0x03, 0xC0);
+	/* RFAGC normal mode (set bit[5:4] only) */
+	ascot2e_set_reg_bits(priv, 0x0C, 0x00, 0x30);
+	priv->frequency = frequency;
+	return 0;
+}
+
+static int ascot2e_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct ascot2e_priv *priv = fe->tuner_priv;
+
+	*frequency = priv->frequency * 1000;
+	return 0;
+}
+
+static struct dvb_tuner_ops ascot2e_tuner_ops = {
+	.info = {
+		.name = "Sony ASCOT2E",
+		.frequency_min = 1000000,
+		.frequency_max = 1200000000,
+		.frequency_step = 25000,
+	},
+	.init = ascot2e_init,
+	.release = ascot2e_release,
+	.sleep = ascot2e_sleep,
+	.set_params = ascot2e_set_params,
+	.get_frequency = ascot2e_get_frequency,
+};
+
+struct dvb_frontend *ascot2e_attach(struct dvb_frontend *fe,
+				    const struct ascot2e_config *config,
+				    struct i2c_adapter *i2c)
+{
+	u8 data[4];
+	struct ascot2e_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct ascot2e_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	priv->i2c_address = (config->i2c_address >> 1);
+	priv->i2c = i2c;
+	priv->set_tuner_data = config->set_tuner_priv;
+	priv->set_tuner = config->set_tuner_callback;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* 16 MHz xTal frequency */
+	data[0] = 16;
+	/* VCO current setting */
+	data[1] = 0x06;
+	/* Logic wake up, CPU boot */
+	data[2] = 0xC4;
+	data[3] = 0x40;
+	ascot2e_write_regs(priv, 0x01, data, 4);
+	/* RFVGA optimization setting (RF_DIST0 - RF_DIST2) */
+	data[0] = 0x10;
+	data[1] = 0x3F;
+	data[2] = 0x25;
+	ascot2e_write_regs(priv, 0x22, data, 3);
+	/* PLL mode setting */
+	ascot2e_write_reg(priv, 0x28, 0x1e);
+	/* RSSI setting */
+	ascot2e_write_reg(priv, 0x59, 0x04);
+	/* TODO check CPU HW error state here */
+	msleep(80);
+	/* Xtal oscillator current control setting */
+	ascot2e_write_reg(priv, 0x4c, 0x01);
+	/* XOSC_SEL=100uA */
+	ascot2e_write_reg(priv, 0x07, 0x04);
+	/* CPU deep sleep */
+	ascot2e_write_reg(priv, 0x04, 0x00);
+	/* Logic sleep */
+	ascot2e_write_reg(priv, 0x03, 0xc0);
+	/* Power save setting */
+	data[0] = 0x00;
+	data[1] = 0x04;
+	ascot2e_write_regs(priv, 0x14, data, 2);
+	ascot2e_write_reg(priv, 0x50, 0x01);
+	priv->state = STATE_SLEEP;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	memcpy(&fe->ops.tuner_ops, &ascot2e_tuner_ops,
+				sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = priv;
+	dev_info(&priv->i2c->dev,
+		"Sony ASCOT2E attached on addr=%x at I2C adapter %p\n",
+		priv->i2c_address, priv->i2c);
+	return fe;
+}
+EXPORT_SYMBOL(ascot2e_attach);
+
+MODULE_DESCRIPTION("Sony ASCOT2E terr/cab tuner driver");
+MODULE_AUTHOR("info@netup.ru");
+MODULE_LICENSE("GPL");

+ 58 - 0
drivers/media/dvb-frontends/ascot2e.h

@@ -0,0 +1,58 @@
+/*
+ * ascot2e.h
+ *
+ * Sony Ascot3E DVB-T/T2/C/C2 tuner driver
+ *
+ * Copyright 2012 Sony Corporation
+ * Copyright (C) 2014 NetUP Inc.
+ * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
+ * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+  */
+
+#ifndef __DVB_ASCOT2E_H__
+#define __DVB_ASCOT2E_H__
+
+#include <linux/kconfig.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+/**
+ * struct ascot2e_config - the configuration of Ascot2E tuner driver
+ * @i2c_address:	I2C address of the tuner
+ * @xtal_freq_mhz:	Oscillator frequency, MHz
+ * @set_tuner_priv:	Callback function private context
+ * @set_tuner_callback:	Callback function that notifies the parent driver
+ *			which tuner is active now
+ */
+struct ascot2e_config {
+	u8	i2c_address;
+	u8	xtal_freq_mhz;
+	void	*set_tuner_priv;
+	int	(*set_tuner_callback)(void *, int);
+};
+
+#if IS_REACHABLE(CONFIG_DVB_ASCOT2E)
+extern struct dvb_frontend *ascot2e_attach(struct dvb_frontend *fe,
+					const struct ascot2e_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ascot2e_attach(struct dvb_frontend *fe,
+					const struct ascot2e_config *config,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif

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

@@ -820,7 +820,6 @@ MODULE_DEVICE_TABLE(i2c, au8522_id);
 
 static struct i2c_driver au8522_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "au8522",
 	},
 	.probe		= au8522_probe,

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

@@ -1011,7 +1011,7 @@ static int cx24123_tune(struct dvb_frontend *fe,
 
 static int cx24123_get_algo(struct dvb_frontend *fe)
 {
-	return 1; /* FE_ALGO_HW */
+	return DVBFE_ALGO_HW;
 }
 
 static void cx24123_release(struct dvb_frontend *fe)

+ 2727 - 0
drivers/media/dvb-frontends/cxd2841er.c

@@ -0,0 +1,2727 @@
+/*
+ * cxd2841er.c
+ *
+ * Sony CXD2441ER digital demodulator driver
+ *
+ * Copyright 2012 Sony Corporation
+ * Copyright (C) 2014 NetUP Inc.
+ * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
+ * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+  */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/math64.h>
+#include <linux/log2.h>
+#include <linux/dynamic_debug.h>
+
+#include "dvb_math.h"
+#include "dvb_frontend.h"
+#include "cxd2841er.h"
+#include "cxd2841er_priv.h"
+
+#define MAX_WRITE_REGSIZE	16
+
+enum cxd2841er_state {
+	STATE_SHUTDOWN = 0,
+	STATE_SLEEP_S,
+	STATE_ACTIVE_S,
+	STATE_SLEEP_TC,
+	STATE_ACTIVE_TC
+};
+
+struct cxd2841er_priv {
+	struct dvb_frontend		frontend;
+	struct i2c_adapter		*i2c;
+	u8				i2c_addr_slvx;
+	u8				i2c_addr_slvt;
+	const struct cxd2841er_config	*config;
+	enum cxd2841er_state		state;
+	u8				system;
+};
+
+static const struct cxd2841er_cnr_data s_cn_data[] = {
+	{ 0x033e, 0 }, { 0x0339, 100 }, { 0x0333, 200 },
+	{ 0x032e, 300 }, { 0x0329, 400 }, { 0x0324, 500 },
+	{ 0x031e, 600 }, { 0x0319, 700 }, { 0x0314, 800 },
+	{ 0x030f, 900 }, { 0x030a, 1000 }, { 0x02ff, 1100 },
+	{ 0x02f4, 1200 }, { 0x02e9, 1300 }, { 0x02de, 1400 },
+	{ 0x02d4, 1500 }, { 0x02c9, 1600 }, { 0x02bf, 1700 },
+	{ 0x02b5, 1800 }, { 0x02ab, 1900 }, { 0x02a1, 2000 },
+	{ 0x029b, 2100 }, { 0x0295, 2200 }, { 0x0290, 2300 },
+	{ 0x028a, 2400 }, { 0x0284, 2500 }, { 0x027f, 2600 },
+	{ 0x0279, 2700 }, { 0x0274, 2800 }, { 0x026e, 2900 },
+	{ 0x0269, 3000 }, { 0x0262, 3100 }, { 0x025c, 3200 },
+	{ 0x0255, 3300 }, { 0x024f, 3400 }, { 0x0249, 3500 },
+	{ 0x0242, 3600 }, { 0x023c, 3700 }, { 0x0236, 3800 },
+	{ 0x0230, 3900 }, { 0x022a, 4000 }, { 0x0223, 4100 },
+	{ 0x021c, 4200 }, { 0x0215, 4300 }, { 0x020e, 4400 },
+	{ 0x0207, 4500 }, { 0x0201, 4600 }, { 0x01fa, 4700 },
+	{ 0x01f4, 4800 }, { 0x01ed, 4900 }, { 0x01e7, 5000 },
+	{ 0x01e0, 5100 }, { 0x01d9, 5200 }, { 0x01d2, 5300 },
+	{ 0x01cb, 5400 }, { 0x01c4, 5500 }, { 0x01be, 5600 },
+	{ 0x01b7, 5700 }, { 0x01b1, 5800 }, { 0x01aa, 5900 },
+	{ 0x01a4, 6000 }, { 0x019d, 6100 }, { 0x0196, 6200 },
+	{ 0x018f, 6300 }, { 0x0189, 6400 }, { 0x0182, 6500 },
+	{ 0x017c, 6600 }, { 0x0175, 6700 }, { 0x016f, 6800 },
+	{ 0x0169, 6900 }, { 0x0163, 7000 }, { 0x015c, 7100 },
+	{ 0x0156, 7200 }, { 0x0150, 7300 }, { 0x014a, 7400 },
+	{ 0x0144, 7500 }, { 0x013e, 7600 }, { 0x0138, 7700 },
+	{ 0x0132, 7800 }, { 0x012d, 7900 }, { 0x0127, 8000 },
+	{ 0x0121, 8100 }, { 0x011c, 8200 }, { 0x0116, 8300 },
+	{ 0x0111, 8400 }, { 0x010b, 8500 }, { 0x0106, 8600 },
+	{ 0x0101, 8700 }, { 0x00fc, 8800 }, { 0x00f7, 8900 },
+	{ 0x00f2, 9000 }, { 0x00ee, 9100 }, { 0x00ea, 9200 },
+	{ 0x00e6, 9300 }, { 0x00e2, 9400 }, { 0x00de, 9500 },
+	{ 0x00da, 9600 }, { 0x00d7, 9700 }, { 0x00d3, 9800 },
+	{ 0x00d0, 9900 }, { 0x00cc, 10000 }, { 0x00c7, 10100 },
+	{ 0x00c3, 10200 }, { 0x00bf, 10300 }, { 0x00ba, 10400 },
+	{ 0x00b6, 10500 }, { 0x00b2, 10600 }, { 0x00ae, 10700 },
+	{ 0x00aa, 10800 }, { 0x00a7, 10900 }, { 0x00a3, 11000 },
+	{ 0x009f, 11100 }, { 0x009c, 11200 }, { 0x0098, 11300 },
+	{ 0x0094, 11400 }, { 0x0091, 11500 }, { 0x008e, 11600 },
+	{ 0x008a, 11700 }, { 0x0087, 11800 }, { 0x0084, 11900 },
+	{ 0x0081, 12000 }, { 0x007e, 12100 }, { 0x007b, 12200 },
+	{ 0x0079, 12300 }, { 0x0076, 12400 }, { 0x0073, 12500 },
+	{ 0x0071, 12600 }, { 0x006e, 12700 }, { 0x006c, 12800 },
+	{ 0x0069, 12900 }, { 0x0067, 13000 }, { 0x0065, 13100 },
+	{ 0x0062, 13200 }, { 0x0060, 13300 }, { 0x005e, 13400 },
+	{ 0x005c, 13500 }, { 0x005a, 13600 }, { 0x0058, 13700 },
+	{ 0x0056, 13800 }, { 0x0054, 13900 }, { 0x0052, 14000 },
+	{ 0x0050, 14100 }, { 0x004e, 14200 }, { 0x004c, 14300 },
+	{ 0x004b, 14400 }, { 0x0049, 14500 }, { 0x0047, 14600 },
+	{ 0x0046, 14700 }, { 0x0044, 14800 }, { 0x0043, 14900 },
+	{ 0x0041, 15000 }, { 0x003f, 15100 }, { 0x003e, 15200 },
+	{ 0x003c, 15300 }, { 0x003b, 15400 }, { 0x003a, 15500 },
+	{ 0x0037, 15700 }, { 0x0036, 15800 }, { 0x0034, 15900 },
+	{ 0x0033, 16000 }, { 0x0032, 16100 }, { 0x0031, 16200 },
+	{ 0x0030, 16300 }, { 0x002f, 16400 }, { 0x002e, 16500 },
+	{ 0x002d, 16600 }, { 0x002c, 16700 }, { 0x002b, 16800 },
+	{ 0x002a, 16900 }, { 0x0029, 17000 }, { 0x0028, 17100 },
+	{ 0x0027, 17200 }, { 0x0026, 17300 }, { 0x0025, 17400 },
+	{ 0x0024, 17500 }, { 0x0023, 17600 }, { 0x0022, 17800 },
+	{ 0x0021, 17900 }, { 0x0020, 18000 }, { 0x001f, 18200 },
+	{ 0x001e, 18300 }, { 0x001d, 18500 }, { 0x001c, 18700 },
+	{ 0x001b, 18900 }, { 0x001a, 19000 }, { 0x0019, 19200 },
+	{ 0x0018, 19300 }, { 0x0017, 19500 }, { 0x0016, 19700 },
+	{ 0x0015, 19900 }, { 0x0014, 20000 },
+};
+
+static const struct cxd2841er_cnr_data s2_cn_data[] = {
+	{ 0x05af, 0 }, { 0x0597, 100 }, { 0x057e, 200 },
+	{ 0x0567, 300 }, { 0x0550, 400 }, { 0x0539, 500 },
+	{ 0x0522, 600 }, { 0x050c, 700 }, { 0x04f6, 800 },
+	{ 0x04e1, 900 }, { 0x04cc, 1000 }, { 0x04b6, 1100 },
+	{ 0x04a1, 1200 }, { 0x048c, 1300 }, { 0x0477, 1400 },
+	{ 0x0463, 1500 }, { 0x044f, 1600 }, { 0x043c, 1700 },
+	{ 0x0428, 1800 }, { 0x0416, 1900 }, { 0x0403, 2000 },
+	{ 0x03ef, 2100 }, { 0x03dc, 2200 }, { 0x03c9, 2300 },
+	{ 0x03b6, 2400 }, { 0x03a4, 2500 }, { 0x0392, 2600 },
+	{ 0x0381, 2700 }, { 0x036f, 2800 }, { 0x035f, 2900 },
+	{ 0x034e, 3000 }, { 0x033d, 3100 }, { 0x032d, 3200 },
+	{ 0x031d, 3300 }, { 0x030d, 3400 }, { 0x02fd, 3500 },
+	{ 0x02ee, 3600 }, { 0x02df, 3700 }, { 0x02d0, 3800 },
+	{ 0x02c2, 3900 }, { 0x02b4, 4000 }, { 0x02a6, 4100 },
+	{ 0x0299, 4200 }, { 0x028c, 4300 }, { 0x027f, 4400 },
+	{ 0x0272, 4500 }, { 0x0265, 4600 }, { 0x0259, 4700 },
+	{ 0x024d, 4800 }, { 0x0241, 4900 }, { 0x0236, 5000 },
+	{ 0x022b, 5100 }, { 0x0220, 5200 }, { 0x0215, 5300 },
+	{ 0x020a, 5400 }, { 0x0200, 5500 }, { 0x01f6, 5600 },
+	{ 0x01ec, 5700 }, { 0x01e2, 5800 }, { 0x01d8, 5900 },
+	{ 0x01cf, 6000 }, { 0x01c6, 6100 }, { 0x01bc, 6200 },
+	{ 0x01b3, 6300 }, { 0x01aa, 6400 }, { 0x01a2, 6500 },
+	{ 0x0199, 6600 }, { 0x0191, 6700 }, { 0x0189, 6800 },
+	{ 0x0181, 6900 }, { 0x0179, 7000 }, { 0x0171, 7100 },
+	{ 0x0169, 7200 }, { 0x0161, 7300 }, { 0x015a, 7400 },
+	{ 0x0153, 7500 }, { 0x014b, 7600 }, { 0x0144, 7700 },
+	{ 0x013d, 7800 }, { 0x0137, 7900 }, { 0x0130, 8000 },
+	{ 0x012a, 8100 }, { 0x0124, 8200 }, { 0x011e, 8300 },
+	{ 0x0118, 8400 }, { 0x0112, 8500 }, { 0x010c, 8600 },
+	{ 0x0107, 8700 }, { 0x0101, 8800 }, { 0x00fc, 8900 },
+	{ 0x00f7, 9000 }, { 0x00f2, 9100 }, { 0x00ec, 9200 },
+	{ 0x00e7, 9300 }, { 0x00e2, 9400 }, { 0x00dd, 9500 },
+	{ 0x00d8, 9600 }, { 0x00d4, 9700 }, { 0x00cf, 9800 },
+	{ 0x00ca, 9900 }, { 0x00c6, 10000 }, { 0x00c2, 10100 },
+	{ 0x00be, 10200 }, { 0x00b9, 10300 }, { 0x00b5, 10400 },
+	{ 0x00b1, 10500 }, { 0x00ae, 10600 }, { 0x00aa, 10700 },
+	{ 0x00a6, 10800 }, { 0x00a3, 10900 }, { 0x009f, 11000 },
+	{ 0x009b, 11100 }, { 0x0098, 11200 }, { 0x0095, 11300 },
+	{ 0x0091, 11400 }, { 0x008e, 11500 }, { 0x008b, 11600 },
+	{ 0x0088, 11700 }, { 0x0085, 11800 }, { 0x0082, 11900 },
+	{ 0x007f, 12000 }, { 0x007c, 12100 }, { 0x007a, 12200 },
+	{ 0x0077, 12300 }, { 0x0074, 12400 }, { 0x0072, 12500 },
+	{ 0x006f, 12600 }, { 0x006d, 12700 }, { 0x006b, 12800 },
+	{ 0x0068, 12900 }, { 0x0066, 13000 }, { 0x0064, 13100 },
+	{ 0x0061, 13200 }, { 0x005f, 13300 }, { 0x005d, 13400 },
+	{ 0x005b, 13500 }, { 0x0059, 13600 }, { 0x0057, 13700 },
+	{ 0x0055, 13800 }, { 0x0053, 13900 }, { 0x0051, 14000 },
+	{ 0x004f, 14100 }, { 0x004e, 14200 }, { 0x004c, 14300 },
+	{ 0x004a, 14400 }, { 0x0049, 14500 }, { 0x0047, 14600 },
+	{ 0x0045, 14700 }, { 0x0044, 14800 }, { 0x0042, 14900 },
+	{ 0x0041, 15000 }, { 0x003f, 15100 }, { 0x003e, 15200 },
+	{ 0x003c, 15300 }, { 0x003b, 15400 }, { 0x003a, 15500 },
+	{ 0x0038, 15600 }, { 0x0037, 15700 }, { 0x0036, 15800 },
+	{ 0x0034, 15900 }, { 0x0033, 16000 }, { 0x0032, 16100 },
+	{ 0x0031, 16200 }, { 0x0030, 16300 }, { 0x002f, 16400 },
+	{ 0x002e, 16500 }, { 0x002d, 16600 }, { 0x002c, 16700 },
+	{ 0x002b, 16800 }, { 0x002a, 16900 }, { 0x0029, 17000 },
+	{ 0x0028, 17100 }, { 0x0027, 17200 }, { 0x0026, 17300 },
+	{ 0x0025, 17400 }, { 0x0024, 17500 }, { 0x0023, 17600 },
+	{ 0x0022, 17800 }, { 0x0021, 17900 }, { 0x0020, 18000 },
+	{ 0x001f, 18200 }, { 0x001e, 18300 }, { 0x001d, 18500 },
+	{ 0x001c, 18700 }, { 0x001b, 18900 }, { 0x001a, 19000 },
+	{ 0x0019, 19200 }, { 0x0018, 19300 }, { 0x0017, 19500 },
+	{ 0x0016, 19700 }, { 0x0015, 19900 }, { 0x0014, 20000 },
+};
+
+#define MAKE_IFFREQ_CONFIG(iffreq) ((u32)(((iffreq)/41.0)*16777216.0 + 0.5))
+
+static void cxd2841er_i2c_debug(struct cxd2841er_priv *priv,
+				u8 addr, u8 reg, u8 write,
+				const u8 *data, u32 len)
+{
+	dev_dbg(&priv->i2c->dev,
+		"cxd2841er: I2C %s addr %02x reg 0x%02x size %d\n",
+		(write == 0 ? "read" : "write"), addr, reg, len);
+	print_hex_dump_bytes("cxd2841er: I2C data: ",
+		DUMP_PREFIX_OFFSET, data, len);
+}
+
+static int cxd2841er_write_regs(struct cxd2841er_priv *priv,
+				u8 addr, u8 reg, const u8 *data, u32 len)
+{
+	int ret;
+	u8 buf[MAX_WRITE_REGSIZE + 1];
+	u8 i2c_addr = (addr == I2C_SLVX ?
+		priv->i2c_addr_slvx : priv->i2c_addr_slvt);
+	struct i2c_msg msg[1] = {
+		{
+			.addr = i2c_addr,
+			.flags = 0,
+			.len = len + 1,
+			.buf = buf,
+		}
+	};
+
+	if (len + 1 >= sizeof(buf)) {
+		dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n",
+			 reg, len + 1);
+		return -E2BIG;
+	}
+
+	cxd2841er_i2c_debug(priv, i2c_addr, reg, 1, data, len);
+	buf[0] = reg;
+	memcpy(&buf[1], data, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret >= 0 && ret != 1)
+		ret = -EIO;
+	if (ret < 0) {
+		dev_warn(&priv->i2c->dev,
+			"%s: i2c wr failed=%d addr=%02x reg=%02x len=%d\n",
+			KBUILD_MODNAME, ret, i2c_addr, reg, len);
+		return ret;
+	}
+	return 0;
+}
+
+static int cxd2841er_write_reg(struct cxd2841er_priv *priv,
+			       u8 addr, u8 reg, u8 val)
+{
+	return cxd2841er_write_regs(priv, addr, reg, &val, 1);
+}
+
+static int cxd2841er_read_regs(struct cxd2841er_priv *priv,
+			       u8 addr, u8 reg, u8 *val, u32 len)
+{
+	int ret;
+	u8 i2c_addr = (addr == I2C_SLVX ?
+		priv->i2c_addr_slvx : priv->i2c_addr_slvt);
+	struct i2c_msg msg[2] = {
+		{
+			.addr = i2c_addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, &msg[0], 1);
+	if (ret >= 0 && ret != 1)
+		ret = -EIO;
+	if (ret < 0) {
+		dev_warn(&priv->i2c->dev,
+			"%s: i2c rw failed=%d addr=%02x reg=%02x\n",
+			KBUILD_MODNAME, ret, i2c_addr, reg);
+		return ret;
+	}
+	ret = i2c_transfer(priv->i2c, &msg[1], 1);
+	if (ret >= 0 && ret != 1)
+		ret = -EIO;
+	if (ret < 0) {
+		dev_warn(&priv->i2c->dev,
+			"%s: i2c rd failed=%d addr=%02x reg=%02x\n",
+			KBUILD_MODNAME, ret, i2c_addr, reg);
+		return ret;
+	}
+	return 0;
+}
+
+static int cxd2841er_read_reg(struct cxd2841er_priv *priv,
+			      u8 addr, u8 reg, u8 *val)
+{
+	return cxd2841er_read_regs(priv, addr, reg, val, 1);
+}
+
+static int cxd2841er_set_reg_bits(struct cxd2841er_priv *priv,
+				  u8 addr, u8 reg, u8 data, u8 mask)
+{
+	int res;
+	u8 rdata;
+
+	if (mask != 0xff) {
+		res = cxd2841er_read_reg(priv, addr, reg, &rdata);
+		if (res)
+			return res;
+		data = ((data & mask) | (rdata & (mask ^ 0xFF)));
+	}
+	return cxd2841er_write_reg(priv, addr, reg, data);
+}
+
+static int cxd2841er_dvbs2_set_symbol_rate(struct cxd2841er_priv *priv,
+					   u32 symbol_rate)
+{
+	u32 reg_value = 0;
+	u8 data[3] = {0, 0, 0};
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	/*
+	 * regValue = (symbolRateKSps * 2^14 / 1000) + 0.5
+	 *          = ((symbolRateKSps * 2^14) + 500) / 1000
+	 *          = ((symbolRateKSps * 16384) + 500) / 1000
+	 */
+	reg_value = DIV_ROUND_CLOSEST(symbol_rate * 16384, 1000);
+	if ((reg_value == 0) || (reg_value > 0xFFFFF)) {
+		dev_err(&priv->i2c->dev,
+			"%s(): reg_value is out of range\n", __func__);
+		return -EINVAL;
+	}
+	data[0] = (u8)((reg_value >> 16) & 0x0F);
+	data[1] = (u8)((reg_value >>  8) & 0xFF);
+	data[2] = (u8)(reg_value & 0xFF);
+	/* Set SLV-T Bank : 0xAE */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xae);
+	cxd2841er_write_regs(priv, I2C_SLVT, 0x20, data, 3);
+	return 0;
+}
+
+static void cxd2841er_set_ts_clock_mode(struct cxd2841er_priv *priv,
+					u8 system);
+
+static int cxd2841er_sleep_s_to_active_s(struct cxd2841er_priv *priv,
+					 u8 system, u32 symbol_rate)
+{
+	int ret;
+	u8 data[4] = { 0, 0, 0, 0 };
+
+	if (priv->state != STATE_SLEEP_S) {
+		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, (int)priv->state);
+		return -EINVAL;
+	}
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_set_ts_clock_mode(priv, SYS_DVBS);
+	/* Set demod mode */
+	if (system == SYS_DVBS) {
+		data[0] = 0x0A;
+	} else if (system == SYS_DVBS2) {
+		data[0] = 0x0B;
+	} else {
+		dev_err(&priv->i2c->dev, "%s(): invalid delsys %d\n",
+			__func__, system);
+		return -EINVAL;
+	}
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, data[0]);
+	/* DVB-S/S2 */
+	data[0] = 0x00;
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Enable S/S2 auto detection 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2d, data[0]);
+	/* Set SLV-T Bank : 0xAE */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xae);
+	/* Enable S/S2 auto detection 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, data[0]);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Enable demod clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01);
+	/* Enable ADC clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x31, 0x01);
+	/* Enable ADC 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x63, 0x16);
+	/* Enable ADC 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x65, 0x3f);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Enable ADC 3 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00);
+	/* Set SLV-T Bank : 0xA3 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa3);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xac, 0x00);
+	data[0] = 0x07;
+	data[1] = 0x3B;
+	data[2] = 0x08;
+	data[3] = 0xC5;
+	/* Set SLV-T Bank : 0xAB */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xab);
+	cxd2841er_write_regs(priv, I2C_SLVT, 0x98, data, 4);
+	data[0] = 0x05;
+	data[1] = 0x80;
+	data[2] = 0x0A;
+	data[3] = 0x80;
+	cxd2841er_write_regs(priv, I2C_SLVT, 0xa8, data, 4);
+	data[0] = 0x0C;
+	data[1] = 0xCC;
+	cxd2841er_write_regs(priv, I2C_SLVT, 0xc3, data, 2);
+	/* Set demod parameter */
+	ret = cxd2841er_dvbs2_set_symbol_rate(priv, symbol_rate);
+	if (ret != 0)
+		return ret;
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* disable Hi-Z setting 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x10);
+	/* disable Hi-Z setting 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00);
+	priv->state = STATE_ACTIVE_S;
+	return 0;
+}
+
+static int cxd2841er_sleep_tc_to_active_t_band(struct cxd2841er_priv *priv,
+					       u32 bandwidth);
+
+static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv,
+						u32 bandwidth);
+
+static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv,
+					       u32 bandwidth);
+
+static int cxd2841er_retune_active(struct cxd2841er_priv *priv,
+				   struct dtv_frontend_properties *p)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_ACTIVE_S &&
+			priv->state != STATE_ACTIVE_TC) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* disable TS output */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
+	if (priv->state == STATE_ACTIVE_S)
+		return cxd2841er_dvbs2_set_symbol_rate(
+				priv, p->symbol_rate / 1000);
+	else if (priv->state == STATE_ACTIVE_TC) {
+		switch (priv->system) {
+		case SYS_DVBT:
+			return cxd2841er_sleep_tc_to_active_t_band(
+					priv, p->bandwidth_hz);
+		case SYS_DVBT2:
+			return cxd2841er_sleep_tc_to_active_t2_band(
+					priv, p->bandwidth_hz);
+		case SYS_DVBC_ANNEX_A:
+			return cxd2841er_sleep_tc_to_active_c_band(
+					priv, 8000000);
+		}
+	}
+	dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n",
+		__func__, priv->system);
+	return -EINVAL;
+}
+
+static int cxd2841er_active_s_to_sleep_s(struct cxd2841er_priv *priv)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_ACTIVE_S) {
+		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* disable TS output */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
+	/* enable Hi-Z setting 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x1f);
+	/* enable Hi-Z setting 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* disable ADC 1 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* disable ADC clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x31, 0x00);
+	/* disable ADC 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x63, 0x16);
+	/* disable ADC 3 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x65, 0x27);
+	/* SADC Bias ON */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x69, 0x06);
+	/* disable demod clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00);
+	/* Set SLV-T Bank : 0xAE */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xae);
+	/* disable S/S2 auto detection1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* disable S/S2 auto detection2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2d, 0x00);
+	priv->state = STATE_SLEEP_S;
+	return 0;
+}
+
+static int cxd2841er_sleep_s_to_shutdown(struct cxd2841er_priv *priv)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_SLEEP_S) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Disable DSQOUT */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f);
+	/* Disable DSQIN */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x9c, 0x00);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Disable oscillator */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x15, 0x01);
+	/* Set demod mode */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x01);
+	priv->state = STATE_SHUTDOWN;
+	return 0;
+}
+
+static int cxd2841er_sleep_tc_to_shutdown(struct cxd2841er_priv *priv)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_SLEEP_TC) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Disable oscillator */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x15, 0x01);
+	/* Set demod mode */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x01);
+	priv->state = STATE_SHUTDOWN;
+	return 0;
+}
+
+static int cxd2841er_active_t_to_sleep_tc(struct cxd2841er_priv *priv)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* disable TS output */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
+	/* enable Hi-Z setting 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f);
+	/* enable Hi-Z setting 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* disable ADC 1 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Disable ADC 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
+	/* Disable ADC 3 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
+	/* Disable ADC clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
+	/* Disable RF level monitor */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
+	/* Disable demod clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00);
+	priv->state = STATE_SLEEP_TC;
+	return 0;
+}
+
+static int cxd2841er_active_t2_to_sleep_tc(struct cxd2841er_priv *priv)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* disable TS output */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
+	/* enable Hi-Z setting 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f);
+	/* enable Hi-Z setting 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff);
+	/* Cancel DVB-T2 setting */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x83, 0x40);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x86, 0x21);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x9e, 0x09, 0x0f);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x9f, 0xfb);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2a);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x38, 0x00, 0x0f);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x11, 0x00, 0x3f);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* disable ADC 1 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Disable ADC 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
+	/* Disable ADC 3 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
+	/* Disable ADC clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
+	/* Disable RF level monitor */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
+	/* Disable demod clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00);
+	priv->state = STATE_SLEEP_TC;
+	return 0;
+}
+
+static int cxd2841er_active_c_to_sleep_tc(struct cxd2841er_priv *priv)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* disable TS output */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01);
+	/* enable Hi-Z setting 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f);
+	/* enable Hi-Z setting 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff);
+	/* Cancel DVB-C setting */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa3, 0x00, 0x1f);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* disable ADC 1 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Disable ADC 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
+	/* Disable ADC 3 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
+	/* Disable ADC clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
+	/* Disable RF level monitor */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
+	/* Disable demod clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00);
+	priv->state = STATE_SLEEP_TC;
+	return 0;
+}
+
+static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_SHUTDOWN) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Clear all demodulator registers */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x02, 0x00);
+	usleep_range(3000, 5000);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Set demod SW reset */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01);
+	/* Set X'tal clock to 20.5Mhz */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00);
+	/* Set demod mode */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x0a);
+	/* Clear demod SW reset */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x00);
+	usleep_range(1000, 2000);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* enable DSQOUT */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x1F);
+	/* enable DSQIN */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x9C, 0x40);
+	/* TADC Bias On */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
+	/* SADC Bias On */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x63, 0x16);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x65, 0x27);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x69, 0x06);
+	priv->state = STATE_SLEEP_S;
+	return 0;
+}
+
+static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_SHUTDOWN) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Clear all demodulator registers */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x02, 0x00);
+	usleep_range(3000, 5000);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Set demod SW reset */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01);
+	/* Set X'tal clock to 20.5Mhz */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x13, 0x00);
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00);
+	/* Clear demod SW reset */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x00);
+	usleep_range(1000, 2000);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* TADC Bias On */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a);
+	/* SADC Bias On */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x63, 0x16);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x65, 0x27);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x69, 0x06);
+	priv->state = STATE_SLEEP_TC;
+	return 0;
+}
+
+static int cxd2841er_tune_done(struct cxd2841er_priv *priv)
+{
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0, 0);
+	/* SW Reset */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xfe, 0x01);
+	/* Enable TS output */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x00);
+	return 0;
+}
+
+/* Set TS parallel mode */
+static void cxd2841er_set_ts_clock_mode(struct cxd2841er_priv *priv,
+					u8 system)
+{
+	u8 serial_ts, ts_rate_ctrl_off, ts_in_off;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	cxd2841er_read_reg(priv, I2C_SLVT, 0xc4, &serial_ts);
+	cxd2841er_read_reg(priv, I2C_SLVT, 0xd3, &ts_rate_ctrl_off);
+	cxd2841er_read_reg(priv, I2C_SLVT, 0xde, &ts_in_off);
+	dev_dbg(&priv->i2c->dev, "%s(): ser_ts=0x%02x rate_ctrl_off=0x%02x in_off=0x%02x\n",
+		__func__, serial_ts, ts_rate_ctrl_off, ts_in_off);
+
+	/*
+	 * slave    Bank    Addr    Bit    default    Name
+	 * <SLV-T>  00h     D9h     [7:0]  8'h08      OTSCKPERIOD
+	 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xd9, 0x08);
+	/*
+	 * Disable TS IF Clock
+	 * slave    Bank    Addr    Bit    default    Name
+	 * <SLV-T>  00h     32h     [0]    1'b1       OREG_CK_TSIF_EN
+	 */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x32, 0x00, 0x01);
+	/*
+	 * slave    Bank    Addr    Bit    default    Name
+	 * <SLV-T>  00h     33h     [1:0]  2'b01      OREG_CKSEL_TSIF
+	 */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x33, 0x00, 0x03);
+	/*
+	 * Enable TS IF Clock
+	 * slave    Bank    Addr    Bit    default    Name
+	 * <SLV-T>  00h     32h     [0]    1'b1       OREG_CK_TSIF_EN
+	 */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x32, 0x01, 0x01);
+
+	if (system == SYS_DVBT) {
+		/* Enable parity period for DVB-T */
+		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x66, 0x01, 0x01);
+	} else if (system == SYS_DVBC_ANNEX_A) {
+		/* Enable parity period for DVB-C */
+		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
+		cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x66, 0x01, 0x01);
+	}
+}
+
+static u8 cxd2841er_chip_id(struct cxd2841er_priv *priv)
+{
+	u8 chip_id;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0, 0);
+	cxd2841er_read_reg(priv, I2C_SLVT, 0xfd, &chip_id);
+	return chip_id;
+}
+
+static int cxd2841er_read_status_s(struct dvb_frontend *fe,
+				   enum fe_status *status)
+{
+	u8 reg = 0;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	*status = 0;
+	if (priv->state != STATE_ACTIVE_S) {
+		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/* Set SLV-T Bank : 0xA0 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
+	/*
+	 *  slave     Bank      Addr      Bit      Signal name
+	 * <SLV-T>    A0h       11h       [2]      ITSLOCK
+	 */
+	cxd2841er_read_reg(priv, I2C_SLVT, 0x11, &reg);
+	if (reg & 0x04) {
+		*status = FE_HAS_SIGNAL
+			| FE_HAS_CARRIER
+			| FE_HAS_VITERBI
+			| FE_HAS_SYNC
+			| FE_HAS_LOCK;
+	}
+	dev_dbg(&priv->i2c->dev, "%s(): result 0x%x\n", __func__, *status);
+	return 0;
+}
+
+static int cxd2841er_read_status_t_t2(struct cxd2841er_priv *priv,
+				      u8 *sync, u8 *tslock, u8 *unlock)
+{
+	u8 data = 0;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_ACTIVE_TC)
+		return -EINVAL;
+	if (priv->system == SYS_DVBT) {
+		/* Set SLV-T Bank : 0x10 */
+		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	} else {
+		/* Set SLV-T Bank : 0x20 */
+		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
+	}
+	cxd2841er_read_reg(priv, I2C_SLVT, 0x10, &data);
+	if ((data & 0x07) == 0x07) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): invalid hardware state detected\n", __func__);
+		*sync = 0;
+		*tslock = 0;
+		*unlock = 0;
+	} else {
+		*sync = ((data & 0x07) == 0x6 ? 1 : 0);
+		*tslock = ((data & 0x20) ? 1 : 0);
+		*unlock = ((data & 0x10) ? 1 : 0);
+	}
+	return 0;
+}
+
+static int cxd2841er_read_status_c(struct cxd2841er_priv *priv, u8 *tslock)
+{
+	u8 data;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_ACTIVE_TC)
+		return -EINVAL;
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
+	cxd2841er_read_reg(priv, I2C_SLVT, 0x88, &data);
+	if ((data & 0x01) == 0) {
+		*tslock = 0;
+	} else {
+		cxd2841er_read_reg(priv, I2C_SLVT, 0x10, &data);
+		*tslock = ((data & 0x20) ? 1 : 0);
+	}
+	return 0;
+}
+
+static int cxd2841er_read_status_tc(struct dvb_frontend *fe,
+				    enum fe_status *status)
+{
+	int ret = 0;
+	u8 sync = 0;
+	u8 tslock = 0;
+	u8 unlock = 0;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	*status = 0;
+	if (priv->state == STATE_ACTIVE_TC) {
+		if (priv->system == SYS_DVBT || priv->system == SYS_DVBT2) {
+			ret = cxd2841er_read_status_t_t2(
+				priv, &sync, &tslock, &unlock);
+			if (ret)
+				goto done;
+			if (unlock)
+				goto done;
+			if (sync)
+				*status = FE_HAS_SIGNAL |
+					FE_HAS_CARRIER |
+					FE_HAS_VITERBI |
+					FE_HAS_SYNC;
+			if (tslock)
+				*status |= FE_HAS_LOCK;
+		} else if (priv->system == SYS_DVBC_ANNEX_A) {
+			ret = cxd2841er_read_status_c(priv, &tslock);
+			if (ret)
+				goto done;
+			if (tslock)
+				*status = FE_HAS_SIGNAL |
+					FE_HAS_CARRIER |
+					FE_HAS_VITERBI |
+					FE_HAS_SYNC |
+					FE_HAS_LOCK;
+		}
+	}
+done:
+	dev_dbg(&priv->i2c->dev, "%s(): status 0x%x\n", __func__, *status);
+	return ret;
+}
+
+static int cxd2841er_get_carrier_offset_s_s2(struct cxd2841er_priv *priv,
+					     int *offset)
+{
+	u8 data[3];
+	u8 is_hs_mode;
+	s32 cfrl_ctrlval;
+	s32 temp_div, temp_q, temp_r;
+
+	if (priv->state != STATE_ACTIVE_S) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	/*
+	 * Get High Sampling Rate mode
+	 *  slave     Bank      Addr      Bit      Signal name
+	 * <SLV-T>    A0h       10h       [0]      ITRL_LOCK
+	 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
+	cxd2841er_read_reg(priv, I2C_SLVT, 0x10, &data[0]);
+	if (data[0] & 0x01) {
+		/*
+		 *  slave     Bank      Addr      Bit      Signal name
+		 * <SLV-T>    A0h       50h       [4]      IHSMODE
+		 */
+		cxd2841er_read_reg(priv, I2C_SLVT, 0x50, &data[0]);
+		is_hs_mode = (data[0] & 0x10 ? 1 : 0);
+	} else {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): unable to detect sampling rate mode\n",
+			__func__);
+		return -EINVAL;
+	}
+	/*
+	 *  slave     Bank      Addr      Bit      Signal name
+	 * <SLV-T>    A0h       45h       [4:0]    ICFRL_CTRLVAL[20:16]
+	 * <SLV-T>    A0h       46h       [7:0]    ICFRL_CTRLVAL[15:8]
+	 * <SLV-T>    A0h       47h       [7:0]    ICFRL_CTRLVAL[7:0]
+	 */
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x45, data, 3);
+	cfrl_ctrlval = sign_extend32((((u32)data[0] & 0x1F) << 16) |
+				(((u32)data[1] & 0xFF) <<  8) |
+				((u32)data[2] & 0xFF), 20);
+	temp_div = (is_hs_mode ? 1048576 : 1572864);
+	if (cfrl_ctrlval > 0) {
+		temp_q = div_s64_rem(97375LL * cfrl_ctrlval,
+			temp_div, &temp_r);
+	} else {
+		temp_q = div_s64_rem(-97375LL * cfrl_ctrlval,
+			temp_div, &temp_r);
+	}
+	if (temp_r >= temp_div / 2)
+		temp_q++;
+	if (cfrl_ctrlval > 0)
+		temp_q *= -1;
+	*offset = temp_q;
+	return 0;
+}
+
+static int cxd2841er_get_carrier_offset_t2(struct cxd2841er_priv *priv,
+					   u32 bandwidth, int *offset)
+{
+	u8 data[4];
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	if (priv->system != SYS_DVBT2) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n",
+			__func__, priv->system);
+		return -EINVAL;
+	}
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x4c, data, sizeof(data));
+	*offset = -1 * sign_extend32(
+		((u32)(data[0] & 0x0F) << 24) | ((u32)data[1] << 16) |
+		((u32)data[2] << 8) | (u32)data[3], 27);
+	switch (bandwidth) {
+	case 1712000:
+		*offset /= 582;
+		break;
+	case 5000000:
+	case 6000000:
+	case 7000000:
+	case 8000000:
+		*offset *= (bandwidth / 1000000);
+		*offset /= 940;
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n",
+			__func__, bandwidth);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cxd2841er_get_carrier_offset_c(struct cxd2841er_priv *priv,
+					  int *offset)
+{
+	u8 data[2];
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	if (priv->system != SYS_DVBC_ANNEX_A) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n",
+			__func__, priv->system);
+		return -EINVAL;
+	}
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x15, data, sizeof(data));
+	*offset = div_s64(41000LL * sign_extend32((((u32)data[0] & 0x3f) << 8)
+						| (u32)data[1], 13), 16384);
+	return 0;
+}
+
+static int cxd2841er_read_packet_errors_t(
+		struct cxd2841er_priv *priv, u32 *penum)
+{
+	u8 data[3];
+
+	*penum = 0;
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	cxd2841er_read_regs(priv, I2C_SLVT, 0xea, data, sizeof(data));
+	if (data[2] & 0x01)
+		*penum = ((u32)data[0] << 8) | (u32)data[1];
+	return 0;
+}
+
+static int cxd2841er_read_packet_errors_t2(
+		struct cxd2841er_priv *priv, u32 *penum)
+{
+	u8 data[3];
+
+	*penum = 0;
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x24);
+	cxd2841er_read_regs(priv, I2C_SLVT, 0xfd, data, sizeof(data));
+	if (data[0] & 0x01)
+		*penum = ((u32)data[1] << 8) | (u32)data[2];
+	return 0;
+}
+
+static u32 cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv)
+{
+	u8 data[11];
+	u32 bit_error, bit_count;
+	u32 temp_q, temp_r;
+
+	/* Set SLV-T Bank : 0xA0 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
+	/*
+	 *  slave     Bank      Addr      Bit      Signal name
+	 * <SLV-T>    A0h       35h       [0]      IFVBER_VALID
+	 * <SLV-T>    A0h       36h       [5:0]    IFVBER_BITERR[21:16]
+	 * <SLV-T>    A0h       37h       [7:0]    IFVBER_BITERR[15:8]
+	 * <SLV-T>    A0h       38h       [7:0]    IFVBER_BITERR[7:0]
+	 * <SLV-T>    A0h       3Dh       [5:0]    IFVBER_BITNUM[21:16]
+	 * <SLV-T>    A0h       3Eh       [7:0]    IFVBER_BITNUM[15:8]
+	 * <SLV-T>    A0h       3Fh       [7:0]    IFVBER_BITNUM[7:0]
+	 */
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x35, data, 11);
+	if (data[0] & 0x01) {
+		bit_error = ((u32)(data[1]  & 0x3F) << 16) |
+			((u32)(data[2]  & 0xFF) <<  8) |
+			(u32)(data[3]  & 0xFF);
+		bit_count = ((u32)(data[8]  & 0x3F) << 16) |
+			((u32)(data[9]  & 0xFF) <<  8) |
+			(u32)(data[10] & 0xFF);
+		/*
+		 *	BER = bitError / bitCount
+		 *	= (bitError * 10^7) / bitCount
+		 *	= ((bitError * 625 * 125 * 128) / bitCount
+		 */
+		if ((bit_count == 0) || (bit_error > bit_count)) {
+			dev_dbg(&priv->i2c->dev,
+				"%s(): invalid bit_error %d, bit_count %d\n",
+				__func__, bit_error, bit_count);
+			return 0;
+		}
+		temp_q = div_u64_rem(10000000ULL * bit_error,
+						bit_count, &temp_r);
+		if (bit_count != 1 && temp_r >= bit_count / 2)
+			temp_q++;
+		return temp_q;
+	}
+	dev_dbg(&priv->i2c->dev, "%s(): no data available\n", __func__);
+	return 0;
+}
+
+
+static u32 cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv)
+{
+	u8 data[5];
+	u32 bit_error, period;
+	u32 temp_q, temp_r;
+	u32 result = 0;
+
+	/* Set SLV-T Bank : 0xB2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xb2);
+	/*
+	 *  slave     Bank      Addr      Bit      Signal name
+	 * <SLV-T>    B2h       30h       [0]      IFLBER_VALID
+	 * <SLV-T>    B2h       31h       [3:0]    IFLBER_BITERR[27:24]
+	 * <SLV-T>    B2h       32h       [7:0]    IFLBER_BITERR[23:16]
+	 * <SLV-T>    B2h       33h       [7:0]    IFLBER_BITERR[15:8]
+	 * <SLV-T>    B2h       34h       [7:0]    IFLBER_BITERR[7:0]
+	 */
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x30, data, 5);
+	if (data[0] & 0x01) {
+		/* Bit error count */
+		bit_error = ((u32)(data[1] & 0x0F) << 24) |
+			((u32)(data[2] & 0xFF) << 16) |
+			((u32)(data[3] & 0xFF) <<  8) |
+			(u32)(data[4] & 0xFF);
+
+		/* Set SLV-T Bank : 0xA0 */
+		cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
+		cxd2841er_read_reg(priv, I2C_SLVT, 0x7a, data);
+		/* Measurement period */
+		period = (u32)(1 << (data[0] & 0x0F));
+		if (period == 0) {
+			dev_dbg(&priv->i2c->dev,
+				"%s(): period is 0\n", __func__);
+			return 0;
+		}
+		if (bit_error > (period * 64800)) {
+			dev_dbg(&priv->i2c->dev,
+				"%s(): invalid bit_err 0x%x period 0x%x\n",
+				__func__, bit_error, period);
+			return 0;
+		}
+		/*
+		 * BER = bitError / (period * 64800)
+		 *	= (bitError * 10^7) / (period * 64800)
+		 *	= (bitError * 10^5) / (period * 648)
+		 *	= (bitError * 12500) / (period * 81)
+		 *	= (bitError * 10) * 1250 / (period * 81)
+		 */
+		temp_q = div_u64_rem(12500ULL * bit_error,
+					period * 81, &temp_r);
+		if (temp_r >= period * 40)
+			temp_q++;
+		result = temp_q;
+	} else {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): no data available\n", __func__);
+	}
+	return result;
+}
+
+static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber)
+{
+	u8 data[4];
+	u32 div, q, r;
+	u32 bit_err, period_exp, n_ldpc;
+
+	*ber = 0;
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): invalid state %d\n", __func__, priv->state);
+		return -EINVAL;
+	}
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x39, data, sizeof(data));
+	if (!(data[0] & 0x10)) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): no valid BER data\n", __func__);
+		return 0;
+	}
+	bit_err = ((u32)(data[0] & 0x0f) << 24) |
+		((u32)data[1] << 16) |
+		((u32)data[2] << 8) |
+		(u32)data[3];
+	cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data);
+	period_exp = data[0] & 0x0f;
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x22);
+	cxd2841er_read_reg(priv, I2C_SLVT, 0x5e, data);
+	n_ldpc = ((data[0] & 0x03) == 0 ? 16200 : 64800);
+	if (bit_err > ((1U << period_exp) * n_ldpc)) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): invalid BER value\n", __func__);
+		return -EINVAL;
+	}
+	if (period_exp >= 4) {
+		div = (1U << (period_exp - 4)) * (n_ldpc / 200);
+		q = div_u64_rem(3125ULL * bit_err, div, &r);
+	} else {
+		div = (1U << period_exp) * (n_ldpc / 200);
+		q = div_u64_rem(50000ULL * bit_err, div, &r);
+	}
+	*ber = (r >= div / 2) ? q + 1 : q;
+	return 0;
+}
+
+static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, u32 *ber)
+{
+	u8 data[2];
+	u32 div, q, r;
+	u32 bit_err, period;
+
+	*ber = 0;
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): invalid state %d\n", __func__, priv->state);
+		return -EINVAL;
+	}
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	cxd2841er_read_reg(priv, I2C_SLVT, 0x39, data);
+	if (!(data[0] & 0x01)) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): no valid BER data\n", __func__);
+		return 0;
+	}
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x22, data, sizeof(data));
+	bit_err = ((u32)data[0] << 8) | (u32)data[1];
+	cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data);
+	period = ((data[0] & 0x07) == 0) ? 256 : (4096 << (data[0] & 0x07));
+	div = period / 128;
+	q = div_u64_rem(78125ULL * bit_err, div, &r);
+	*ber = (r >= div / 2) ? q + 1 : q;
+	return 0;
+}
+
+static u32 cxd2841er_dvbs_read_snr(struct cxd2841er_priv *priv, u8 delsys)
+{
+	u8 data[3];
+	u32 res = 0, value;
+	int min_index, max_index, index;
+	static const struct cxd2841er_cnr_data *cn_data;
+
+	/* Set SLV-T Bank : 0xA1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa1);
+	/*
+	 *  slave     Bank      Addr      Bit     Signal name
+	 * <SLV-T>    A1h       10h       [0]     ICPM_QUICKRDY
+	 * <SLV-T>    A1h       11h       [4:0]   ICPM_QUICKCNDT[12:8]
+	 * <SLV-T>    A1h       12h       [7:0]   ICPM_QUICKCNDT[7:0]
+	 */
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x10, data, 3);
+	if (data[0] & 0x01) {
+		value = ((u32)(data[1] & 0x1F) << 8) | (u32)(data[2] & 0xFF);
+		min_index = 0;
+		if (delsys == SYS_DVBS) {
+			cn_data = s_cn_data;
+			max_index = sizeof(s_cn_data) /
+				sizeof(s_cn_data[0]) - 1;
+		} else {
+			cn_data = s2_cn_data;
+			max_index = sizeof(s2_cn_data) /
+				sizeof(s2_cn_data[0]) - 1;
+		}
+		if (value >= cn_data[min_index].value) {
+			res = cn_data[min_index].cnr_x1000;
+			goto done;
+		}
+		if (value <= cn_data[max_index].value) {
+			res = cn_data[max_index].cnr_x1000;
+			goto done;
+		}
+		while ((max_index - min_index) > 1) {
+			index = (max_index + min_index) / 2;
+			if (value == cn_data[index].value) {
+				res = cn_data[index].cnr_x1000;
+				goto done;
+			} else if (value > cn_data[index].value)
+				max_index = index;
+			else
+				min_index = index;
+			if ((max_index - min_index) <= 1) {
+				if (value == cn_data[max_index].value) {
+					res = cn_data[max_index].cnr_x1000;
+					goto done;
+				} else {
+					res = cn_data[min_index].cnr_x1000;
+					goto done;
+				}
+			}
+		}
+	} else {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): no data available\n", __func__);
+	}
+done:
+	return res;
+}
+
+static int cxd2841er_read_snr_t(struct cxd2841er_priv *priv, u32 *snr)
+{
+	u32 reg;
+	u8 data[2];
+
+	*snr = 0;
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): invalid state %d\n", __func__, priv->state);
+		return -EINVAL;
+	}
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data));
+	reg = ((u32)data[0] << 8) | (u32)data[1];
+	if (reg == 0) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): reg value out of range\n", __func__);
+		return 0;
+	}
+	if (reg > 4996)
+		reg = 4996;
+	*snr = 10000 * ((intlog10(reg) - intlog10(5350 - reg)) >> 24) + 28500;
+	return 0;
+}
+
+static int cxd2841er_read_snr_t2(struct cxd2841er_priv *priv, u32 *snr)
+{
+	u32 reg;
+	u8 data[2];
+
+	*snr = 0;
+	if (priv->state != STATE_ACTIVE_TC) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): invalid state %d\n", __func__, priv->state);
+		return -EINVAL;
+	}
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data));
+	reg = ((u32)data[0] << 8) | (u32)data[1];
+	if (reg == 0) {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): reg value out of range\n", __func__);
+		return 0;
+	}
+	if (reg > 10876)
+		reg = 10876;
+	*snr = 10000 * ((intlog10(reg) -
+		intlog10(12600 - reg)) >> 24) + 32000;
+	return 0;
+}
+
+static u16 cxd2841er_read_agc_gain_t_t2(struct cxd2841er_priv *priv,
+					u8 delsys)
+{
+	u8 data[2];
+
+	cxd2841er_write_reg(
+		priv, I2C_SLVT, 0x00, (delsys == SYS_DVBT ? 0x10 : 0x20));
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x26, data, 2);
+	return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4;
+}
+
+static u16 cxd2841er_read_agc_gain_s(struct cxd2841er_priv *priv)
+{
+	u8 data[2];
+
+	/* Set SLV-T Bank : 0xA0 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
+	/*
+	 *  slave     Bank      Addr      Bit       Signal name
+	 * <SLV-T>    A0h       1Fh       [4:0]     IRFAGC_GAIN[12:8]
+	 * <SLV-T>    A0h       20h       [7:0]     IRFAGC_GAIN[7:0]
+	 */
+	cxd2841er_read_regs(priv, I2C_SLVT, 0x1f, data, 2);
+	return ((((u16)data[0] & 0x1F) << 8) | (u16)(data[1] & 0xFF)) << 3;
+}
+
+static int cxd2841er_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	*ber = 0;
+	switch (p->delivery_system) {
+	case SYS_DVBS:
+		*ber = cxd2841er_mon_read_ber_s(priv);
+		break;
+	case SYS_DVBS2:
+		*ber = cxd2841er_mon_read_ber_s2(priv);
+		break;
+	case SYS_DVBT:
+		return cxd2841er_read_ber_t(priv, ber);
+	case SYS_DVBT2:
+		return cxd2841er_read_ber_t2(priv, ber);
+	default:
+		*ber = 0;
+		break;
+	}
+	return 0;
+}
+
+static int cxd2841er_read_signal_strength(struct dvb_frontend *fe,
+					  u16 *strength)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	switch (p->delivery_system) {
+	case SYS_DVBT:
+	case SYS_DVBT2:
+		*strength = 65535 - cxd2841er_read_agc_gain_t_t2(
+			priv, p->delivery_system);
+		break;
+	case SYS_DVBS:
+	case SYS_DVBS2:
+		*strength = 65535 - cxd2841er_read_agc_gain_s(priv);
+		break;
+	default:
+		*strength = 0;
+		break;
+	}
+	return 0;
+}
+
+static int cxd2841er_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	u32 tmp = 0;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	switch (p->delivery_system) {
+	case SYS_DVBT:
+		cxd2841er_read_snr_t(priv, &tmp);
+		break;
+	case SYS_DVBT2:
+		cxd2841er_read_snr_t2(priv, &tmp);
+		break;
+	case SYS_DVBS:
+	case SYS_DVBS2:
+		tmp = cxd2841er_dvbs_read_snr(priv, p->delivery_system);
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s(): unknown delivery system %d\n",
+			__func__, p->delivery_system);
+		break;
+	}
+	*snr = tmp & 0xffff;
+	return 0;
+}
+
+static int cxd2841er_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	switch (p->delivery_system) {
+	case SYS_DVBT:
+		cxd2841er_read_packet_errors_t(priv, ucblocks);
+		break;
+	case SYS_DVBT2:
+		cxd2841er_read_packet_errors_t2(priv, ucblocks);
+		break;
+	default:
+		*ucblocks = 0;
+		break;
+	}
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	return 0;
+}
+
+static int cxd2841er_dvbt2_set_profile(
+	struct cxd2841er_priv *priv, enum cxd2841er_dvbt2_profile_t profile)
+{
+	u8 tune_mode;
+	u8 seq_not2d_time;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	switch (profile) {
+	case DVBT2_PROFILE_BASE:
+		tune_mode = 0x01;
+		seq_not2d_time = 12;
+		break;
+	case DVBT2_PROFILE_LITE:
+		tune_mode = 0x05;
+		seq_not2d_time = 40;
+		break;
+	case DVBT2_PROFILE_ANY:
+		tune_mode = 0x00;
+		seq_not2d_time = 40;
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* Set SLV-T Bank : 0x2E */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2e);
+	/* Set profile and tune mode */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x10, tune_mode, 0x07);
+	/* Set SLV-T Bank : 0x2B */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b);
+	/* Set early unlock detection time */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x9d, seq_not2d_time);
+	return 0;
+}
+
+static int cxd2841er_dvbt2_set_plp_config(struct cxd2841er_priv *priv,
+					  u8 is_auto, u8 plp_id)
+{
+	if (is_auto) {
+		dev_dbg(&priv->i2c->dev,
+			"%s() using auto PLP selection\n", __func__);
+	} else {
+		dev_dbg(&priv->i2c->dev,
+			"%s() using manual PLP selection, ID %d\n",
+			__func__, plp_id);
+	}
+	/* Set SLV-T Bank : 0x23 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x23);
+	if (!is_auto) {
+		/* Manual PLP selection mode. Set the data PLP Id. */
+		cxd2841er_write_reg(priv, I2C_SLVT, 0xaf, plp_id);
+	}
+	/* Auto PLP select (Scanning mode = 0x00). Data PLP select = 0x01. */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xad, (is_auto ? 0x00 : 0x01));
+	return 0;
+}
+
+static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv,
+						u32 bandwidth)
+{
+	u32 iffreq;
+	u8 b20_9f[5];
+	u8 b10_a6[14];
+	u8 b10_b6[3];
+	u8 b10_d7;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	switch (bandwidth) {
+	case 8000000:
+		/* bank 0x20, reg 0x9f */
+		b20_9f[0] = 0x11;
+		b20_9f[1] = 0xf0;
+		b20_9f[2] = 0x00;
+		b20_9f[3] = 0x00;
+		b20_9f[4] = 0x00;
+		/* bank 0x10, reg 0xa6 */
+		b10_a6[0] = 0x26;
+		b10_a6[1] = 0xaf;
+		b10_a6[2] = 0x06;
+		b10_a6[3] = 0xcd;
+		b10_a6[4] = 0x13;
+		b10_a6[5] = 0xbb;
+		b10_a6[6] = 0x28;
+		b10_a6[7] = 0xba;
+		b10_a6[8] = 0x23;
+		b10_a6[9] = 0xa9;
+		b10_a6[10] = 0x1f;
+		b10_a6[11] = 0xa8;
+		b10_a6[12] = 0x2c;
+		b10_a6[13] = 0xc8;
+		iffreq = MAKE_IFFREQ_CONFIG(4.80);
+		b10_d7 = 0x00;
+		break;
+	case 7000000:
+		/* bank 0x20, reg 0x9f */
+		b20_9f[0] = 0x14;
+		b20_9f[1] = 0x80;
+		b20_9f[2] = 0x00;
+		b20_9f[3] = 0x00;
+		b20_9f[4] = 0x00;
+		/* bank 0x10, reg 0xa6 */
+		b10_a6[0] = 0x2C;
+		b10_a6[1] = 0xBD;
+		b10_a6[2] = 0x02;
+		b10_a6[3] = 0xCF;
+		b10_a6[4] = 0x04;
+		b10_a6[5] = 0xF8;
+		b10_a6[6] = 0x23;
+		b10_a6[7] = 0xA6;
+		b10_a6[8] = 0x29;
+		b10_a6[9] = 0xB0;
+		b10_a6[10] = 0x26;
+		b10_a6[11] = 0xA9;
+		b10_a6[12] = 0x21;
+		b10_a6[13] = 0xA5;
+		iffreq = MAKE_IFFREQ_CONFIG(4.2);
+		b10_d7 = 0x02;
+		break;
+	case 6000000:
+		/* bank 0x20, reg 0x9f */
+		b20_9f[0] = 0x17;
+		b20_9f[1] = 0xEA;
+		b20_9f[2] = 0xAA;
+		b20_9f[3] = 0xAA;
+		b20_9f[4] = 0xAA;
+		/* bank 0x10, reg 0xa6 */
+		b10_a6[0] = 0x27;
+		b10_a6[1] = 0xA7;
+		b10_a6[2] = 0x28;
+		b10_a6[3] = 0xB3;
+		b10_a6[4] = 0x02;
+		b10_a6[5] = 0xF0;
+		b10_a6[6] = 0x01;
+		b10_a6[7] = 0xE8;
+		b10_a6[8] = 0x00;
+		b10_a6[9] = 0xCF;
+		b10_a6[10] = 0x00;
+		b10_a6[11] = 0xE6;
+		b10_a6[12] = 0x23;
+		b10_a6[13] = 0xA4;
+		iffreq = MAKE_IFFREQ_CONFIG(3.6);
+		b10_d7 = 0x04;
+		break;
+	case 5000000:
+		/* bank 0x20, reg 0x9f */
+		b20_9f[0] = 0x1C;
+		b20_9f[1] = 0xB3;
+		b20_9f[2] = 0x33;
+		b20_9f[3] = 0x33;
+		b20_9f[4] = 0x33;
+		/* bank 0x10, reg 0xa6 */
+		b10_a6[0] = 0x27;
+		b10_a6[1] = 0xA7;
+		b10_a6[2] = 0x28;
+		b10_a6[3] = 0xB3;
+		b10_a6[4] = 0x02;
+		b10_a6[5] = 0xF0;
+		b10_a6[6] = 0x01;
+		b10_a6[7] = 0xE8;
+		b10_a6[8] = 0x00;
+		b10_a6[9] = 0xCF;
+		b10_a6[10] = 0x00;
+		b10_a6[11] = 0xE6;
+		b10_a6[12] = 0x23;
+		b10_a6[13] = 0xA4;
+		iffreq = MAKE_IFFREQ_CONFIG(3.6);
+		b10_d7 = 0x06;
+		break;
+	case 1712000:
+		/* bank 0x20, reg 0x9f */
+		b20_9f[0] = 0x58;
+		b20_9f[1] = 0xE2;
+		b20_9f[2] = 0xAF;
+		b20_9f[3] = 0xE0;
+		b20_9f[4] = 0xBC;
+		/* bank 0x10, reg 0xa6 */
+		b10_a6[0] = 0x25;
+		b10_a6[1] = 0xA0;
+		b10_a6[2] = 0x36;
+		b10_a6[3] = 0x8D;
+		b10_a6[4] = 0x2E;
+		b10_a6[5] = 0x94;
+		b10_a6[6] = 0x28;
+		b10_a6[7] = 0x9B;
+		b10_a6[8] = 0x32;
+		b10_a6[9] = 0x90;
+		b10_a6[10] = 0x2C;
+		b10_a6[11] = 0x9D;
+		b10_a6[12] = 0x29;
+		b10_a6[13] = 0x99;
+		iffreq = MAKE_IFFREQ_CONFIG(3.5);
+		b10_d7 = 0x03;
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* Set SLV-T Bank : 0x20 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x20);
+	cxd2841er_write_regs(priv, I2C_SLVT, 0x9f, b20_9f, sizeof(b20_9f));
+	/* Set SLV-T Bank : 0x27 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27);
+	cxd2841er_set_reg_bits(
+		priv, I2C_SLVT, 0x7a,
+		(bandwidth == 1712000 ? 0x03 : 0x00), 0x0f);
+	/* Set SLV-T Bank : 0x10 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	/* Group delay equaliser sett. for ASCOT2E */
+	cxd2841er_write_regs(priv, I2C_SLVT, 0xa6, b10_a6, sizeof(b10_a6));
+	/* <IF freq setting> */
+	b10_b6[0] = (u8) ((iffreq >> 16) & 0xff);
+	b10_b6[1] = (u8)((iffreq >> 8) & 0xff);
+	b10_b6[2] = (u8)(iffreq & 0xff);
+	cxd2841er_write_regs(priv, I2C_SLVT, 0xb6, b10_b6, sizeof(b10_b6));
+	/* System bandwidth setting */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, b10_d7, 0x07);
+	return 0;
+}
+
+static int cxd2841er_sleep_tc_to_active_t_band(
+		struct cxd2841er_priv *priv, u32 bandwidth)
+{
+	u8 b13_9c[2] = { 0x01, 0x14 };
+	u8 bw8mhz_b10_9f[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
+	u8 bw8mhz_b10_a6[] = { 0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB,
+			0x28, 0xBA, 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8 };
+	u8 bw8mhz_b10_d9[] = { 0x01, 0xE0 };
+	u8 bw8mhz_b17_38[] = { 0x01, 0x02 };
+	u8 bw7mhz_b10_9f[] = { 0x14, 0x80, 0x00, 0x00, 0x00 };
+	u8 bw7mhz_b10_a6[] = { 0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8,
+			0x23, 0xA6, 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5 };
+	u8 bw7mhz_b10_d9[] = { 0x12, 0xF8 };
+	u8 bw7mhz_b17_38[] = { 0x00, 0x03 };
+	u8 bw6mhz_b10_9f[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
+	u8 bw6mhz_b10_a6[] = { 0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0,
+			0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4 };
+	u8 bw6mhz_b10_d9[] = { 0x1F, 0xDC };
+	u8 bw6mhz_b17_38[] = { 0x00, 0x03 };
+	u8 bw5mhz_b10_9f[] = { 0x1C, 0xB3, 0x33, 0x33, 0x33 };
+	u8 bw5mhz_b10_a6[] = { 0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0,
+			0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4 };
+	u8 bw5mhz_b10_d9[] = { 0x26, 0x3C };
+	u8 bw5mhz_b17_38[] = { 0x00, 0x03 };
+	u8 b10_b6[3];
+	u8 d7val;
+	u32 iffreq;
+	u8 *b10_9f;
+	u8 *b10_a6;
+	u8 *b10_d9;
+	u8 *b17_38;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13);
+	/* Echo performance optimization setting */
+	cxd2841er_write_regs(priv, I2C_SLVT, 0x9c, b13_9c, sizeof(b13_9c));
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+
+	switch (bandwidth) {
+	case 8000000:
+		b10_9f = bw8mhz_b10_9f;
+		b10_a6 = bw8mhz_b10_a6;
+		b10_d9 = bw8mhz_b10_d9;
+		b17_38 = bw8mhz_b17_38;
+		d7val = 0;
+		iffreq = MAKE_IFFREQ_CONFIG(4.80);
+		break;
+	case 7000000:
+		b10_9f = bw7mhz_b10_9f;
+		b10_a6 = bw7mhz_b10_a6;
+		b10_d9 = bw7mhz_b10_d9;
+		b17_38 = bw7mhz_b17_38;
+		d7val = 2;
+		iffreq = MAKE_IFFREQ_CONFIG(4.20);
+		break;
+	case 6000000:
+		b10_9f = bw6mhz_b10_9f;
+		b10_a6 = bw6mhz_b10_a6;
+		b10_d9 = bw6mhz_b10_d9;
+		b17_38 = bw6mhz_b17_38;
+		d7val = 4;
+		iffreq = MAKE_IFFREQ_CONFIG(3.60);
+		break;
+	case 5000000:
+		b10_9f = bw5mhz_b10_9f;
+		b10_a6 = bw5mhz_b10_a6;
+		b10_d9 = bw5mhz_b10_d9;
+		b17_38 = bw5mhz_b17_38;
+		d7val = 6;
+		iffreq = MAKE_IFFREQ_CONFIG(3.60);
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n",
+			__func__, bandwidth);
+		return -EINVAL;
+	}
+	/* <IF freq setting> */
+	b10_b6[0] = (u8) ((iffreq >> 16) & 0xff);
+	b10_b6[1] = (u8)((iffreq >> 8) & 0xff);
+	b10_b6[2] = (u8)(iffreq & 0xff);
+	cxd2841er_write_regs(
+		priv, I2C_SLVT, 0x9f, b10_9f, sizeof(bw8mhz_b10_9f));
+	cxd2841er_write_regs(
+		priv, I2C_SLVT, 0xa6, b10_a6, sizeof(bw8mhz_b10_a6));
+	cxd2841er_write_regs(priv, I2C_SLVT, 0xb6, b10_b6, sizeof(b10_b6));
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, d7val, 0x7);
+	cxd2841er_write_regs(
+		priv, I2C_SLVT, 0xd9, b10_d9, sizeof(bw8mhz_b10_d9));
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17);
+	cxd2841er_write_regs(
+		priv, I2C_SLVT, 0x38, b17_38, sizeof(bw8mhz_b17_38));
+	return 0;
+}
+
+static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv,
+					       u32 bandwidth)
+{
+	u8 bw7_8mhz_b10_a6[] = {
+		0x2D, 0xC7, 0x04, 0xF4, 0x07, 0xC5, 0x2A, 0xB8,
+		0x27, 0x9E, 0x27, 0xA4, 0x29, 0xAB };
+	u8 bw6mhz_b10_a6[] = {
+		0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8,
+		0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4 };
+	u8 b10_b6[3];
+	u32 iffreq;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	switch (bandwidth) {
+	case 8000000:
+	case 7000000:
+		cxd2841er_write_regs(
+			priv, I2C_SLVT, 0xa6,
+			bw7_8mhz_b10_a6, sizeof(bw7_8mhz_b10_a6));
+		iffreq = MAKE_IFFREQ_CONFIG(4.9);
+		break;
+	case 6000000:
+		cxd2841er_write_regs(
+			priv, I2C_SLVT, 0xa6,
+			bw6mhz_b10_a6, sizeof(bw6mhz_b10_a6));
+		iffreq = MAKE_IFFREQ_CONFIG(3.7);
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s(): unsupported bandwidth %d\n",
+			__func__, bandwidth);
+		return -EINVAL;
+	}
+	/* <IF freq setting> */
+	b10_b6[0] = (u8) ((iffreq >> 16) & 0xff);
+	b10_b6[1] = (u8)((iffreq >> 8) & 0xff);
+	b10_b6[2] = (u8)(iffreq & 0xff);
+	cxd2841er_write_regs(priv, I2C_SLVT, 0xb6, b10_b6, sizeof(b10_b6));
+	/* Set SLV-T Bank : 0x11 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
+	switch (bandwidth) {
+	case 8000000:
+	case 7000000:
+		cxd2841er_set_reg_bits(
+			priv, I2C_SLVT, 0xa3, 0x00, 0x1f);
+		break;
+	case 6000000:
+		cxd2841er_set_reg_bits(
+			priv, I2C_SLVT, 0xa3, 0x14, 0x1f);
+		break;
+	}
+	/* Set SLV-T Bank : 0x40 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
+	switch (bandwidth) {
+	case 8000000:
+		cxd2841er_set_reg_bits(
+			priv, I2C_SLVT, 0x26, 0x0b, 0x0f);
+		cxd2841er_write_reg(priv, I2C_SLVT,  0x27, 0x3e);
+		break;
+	case 7000000:
+		cxd2841er_set_reg_bits(
+			priv, I2C_SLVT, 0x26, 0x09, 0x0f);
+		cxd2841er_write_reg(priv, I2C_SLVT,  0x27, 0xd6);
+		break;
+	case 6000000:
+		cxd2841er_set_reg_bits(
+			priv, I2C_SLVT, 0x26, 0x08, 0x0f);
+		cxd2841er_write_reg(priv, I2C_SLVT,  0x27, 0x6e);
+		break;
+	}
+	return 0;
+}
+
+static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv,
+					  u32 bandwidth)
+{
+	u8 data[2] = { 0x09, 0x54 };
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_set_ts_clock_mode(priv, SYS_DVBT);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Set demod mode */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x01);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Enable demod clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01);
+	/* Disable RF level monitor */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
+	/* Enable ADC clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
+	/* Enable ADC 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a);
+	/* xtal freq 20.5MHz */
+	cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2);
+	/* Enable ADC 4 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00);
+	/* Set SLV-T Bank : 0x10 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	/* IFAGC gain settings */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd2, 0x0c, 0x1f);
+	/* Set SLV-T Bank : 0x11 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
+	/* BBAGC TARGET level setting */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x6a, 0x50);
+	/* Set SLV-T Bank : 0x10 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	/* ASCOT setting ON */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa5, 0x01, 0x01);
+	/* Set SLV-T Bank : 0x18 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x18);
+	/* Pre-RS BER moniter setting */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x36, 0x40, 0x07);
+	/* FEC Auto Recovery setting */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x30, 0x01, 0x01);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x31, 0x01, 0x01);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* TSIF setting */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01);
+	cxd2841er_sleep_tc_to_active_t_band(priv, bandwidth);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Disable HiZ Setting 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x28);
+	/* Disable HiZ Setting 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00);
+	priv->state = STATE_ACTIVE_TC;
+	return 0;
+}
+
+static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv,
+					   u32 bandwidth)
+{
+	u8 data[2] = { 0x09, 0x54 };
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_set_ts_clock_mode(priv, SYS_DVBT2);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Set demod mode */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x02);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Enable demod clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01);
+	/* Disable RF level monitor */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
+	/* Enable ADC clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
+	/* Enable ADC 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a);
+	/* xtal freq 20.5MHz */
+	cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2);
+	/* Enable ADC 4 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00);
+	/* Set SLV-T Bank : 0x10 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	/* IFAGC gain settings */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd2, 0x0c, 0x1f);
+	/* Set SLV-T Bank : 0x11 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
+	/* BBAGC TARGET level setting */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x6a, 0x50);
+	/* Set SLV-T Bank : 0x10 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	/* ASCOT setting ON */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa5, 0x01, 0x01);
+	/* Set SLV-T Bank : 0x20 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20);
+	/* Acquisition optimization setting */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x8b, 0x3c);
+	/* Set SLV-T Bank : 0x2b */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x76, 0x20, 0x70);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* TSIF setting */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01);
+	/* DVB-T2 initial setting */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x83, 0x10);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x86, 0x34);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x9e, 0x09, 0x0f);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x9f, 0xd8);
+	/* Set SLV-T Bank : 0x2a */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2a);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x38, 0x04, 0x0f);
+	/* Set SLV-T Bank : 0x2b */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x11, 0x20, 0x3f);
+
+	cxd2841er_sleep_tc_to_active_t2_band(priv, bandwidth);
+
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Disable HiZ Setting 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x28);
+	/* Disable HiZ Setting 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00);
+	priv->state = STATE_ACTIVE_TC;
+	return 0;
+}
+
+static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv,
+					  u32 bandwidth)
+{
+	u8 data[2] = { 0x09, 0x54 };
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_set_ts_clock_mode(priv, SYS_DVBC_ANNEX_A);
+	/* Set SLV-X Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00);
+	/* Set demod mode */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x04);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Enable demod clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01);
+	/* Disable RF level monitor */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00);
+	/* Enable ADC clock */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00);
+	/* Enable ADC 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a);
+	/* xtal freq 20.5MHz */
+	cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2);
+	/* Enable ADC 4 */
+	cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00);
+	/* Set SLV-T Bank : 0x10 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	/* IFAGC gain settings */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd2, 0x09, 0x1f);
+	/* Set SLV-T Bank : 0x11 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11);
+	/* BBAGC TARGET level setting */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x6a, 0x48);
+	/* Set SLV-T Bank : 0x10 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	/* ASCOT setting ON */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa5, 0x01, 0x01);
+	/* Set SLV-T Bank : 0x40 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40);
+	/* Demod setting */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xc3, 0x00, 0x04);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* TSIF setting */
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01);
+
+	cxd2841er_sleep_tc_to_active_c_band(priv, 8000000);
+	/* Set SLV-T Bank : 0x00 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	/* Disable HiZ Setting 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x28);
+	/* Disable HiZ Setting 2 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00);
+	priv->state = STATE_ACTIVE_TC;
+	return 0;
+}
+
+static int cxd2841er_get_frontend(struct dvb_frontend *fe)
+{
+	enum fe_status status = 0;
+	u16 strength = 0, snr = 0;
+	u32 errors = 0, ber = 0;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state == STATE_ACTIVE_S)
+		cxd2841er_read_status_s(fe, &status);
+	else if (priv->state == STATE_ACTIVE_TC)
+		cxd2841er_read_status_tc(fe, &status);
+
+	if (status & FE_HAS_LOCK) {
+		cxd2841er_read_signal_strength(fe, &strength);
+		p->strength.len = 1;
+		p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+		p->strength.stat[0].uvalue = strength;
+		cxd2841er_read_snr(fe, &snr);
+		p->cnr.len = 1;
+		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		p->cnr.stat[0].svalue = snr;
+		cxd2841er_read_ucblocks(fe, &errors);
+		p->block_error.len = 1;
+		p->block_error.stat[0].scale = FE_SCALE_COUNTER;
+		p->block_error.stat[0].uvalue = errors;
+		cxd2841er_read_ber(fe, &ber);
+		p->post_bit_error.len = 1;
+		p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		p->post_bit_error.stat[0].uvalue = ber;
+	} else {
+		p->strength.len = 1;
+		p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		p->cnr.len = 1;
+		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		p->block_error.len = 1;
+		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		p->post_bit_error.len = 1;
+		p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
+	return 0;
+}
+
+static int cxd2841er_set_frontend_s(struct dvb_frontend *fe)
+{
+	int ret = 0, i, timeout, carr_offset;
+	enum fe_status status;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 symbol_rate = p->symbol_rate/1000;
+
+	dev_dbg(&priv->i2c->dev, "%s(): %s frequency=%d symbol_rate=%d\n",
+		__func__,
+		(p->delivery_system == SYS_DVBS ? "DVB-S" : "DVB-S2"),
+		 p->frequency, symbol_rate);
+	switch (priv->state) {
+	case STATE_SLEEP_S:
+		ret = cxd2841er_sleep_s_to_active_s(
+			priv, p->delivery_system, symbol_rate);
+		break;
+	case STATE_ACTIVE_S:
+		ret = cxd2841er_retune_active(priv, p);
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		ret = -EINVAL;
+		goto done;
+	}
+	if (ret) {
+		dev_dbg(&priv->i2c->dev, "%s(): tune failed\n", __func__);
+		goto done;
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	cxd2841er_tune_done(priv);
+	timeout = ((3000000 + (symbol_rate - 1)) / symbol_rate) + 150;
+	for (i = 0; i < timeout / CXD2841ER_DVBS_POLLING_INVL; i++) {
+		usleep_range(CXD2841ER_DVBS_POLLING_INVL*1000,
+			(CXD2841ER_DVBS_POLLING_INVL + 2) * 1000);
+		cxd2841er_read_status_s(fe, &status);
+		if (status & FE_HAS_LOCK)
+			break;
+	}
+	if (status & FE_HAS_LOCK) {
+		if (cxd2841er_get_carrier_offset_s_s2(
+				priv, &carr_offset)) {
+			ret = -EINVAL;
+			goto done;
+		}
+		dev_dbg(&priv->i2c->dev, "%s(): carrier_offset=%d\n",
+			__func__, carr_offset);
+	}
+done:
+	return ret;
+}
+
+static int cxd2841er_set_frontend_tc(struct dvb_frontend *fe)
+{
+	int ret = 0, timeout;
+	enum fe_status status;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (p->delivery_system == SYS_DVBT) {
+		priv->system = SYS_DVBT;
+		switch (priv->state) {
+		case STATE_SLEEP_TC:
+			ret = cxd2841er_sleep_tc_to_active_t(
+				priv, p->bandwidth_hz);
+			break;
+		case STATE_ACTIVE_TC:
+			ret = cxd2841er_retune_active(priv, p);
+			break;
+		default:
+			dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+				__func__, priv->state);
+			ret = -EINVAL;
+		}
+	} else if (p->delivery_system == SYS_DVBT2) {
+		priv->system = SYS_DVBT2;
+		cxd2841er_dvbt2_set_plp_config(priv,
+			(int)(p->stream_id > 255), p->stream_id);
+		cxd2841er_dvbt2_set_profile(priv, DVBT2_PROFILE_BASE);
+		switch (priv->state) {
+		case STATE_SLEEP_TC:
+			ret = cxd2841er_sleep_tc_to_active_t2(priv,
+				p->bandwidth_hz);
+			break;
+		case STATE_ACTIVE_TC:
+			ret = cxd2841er_retune_active(priv, p);
+			break;
+		default:
+			dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+				__func__, priv->state);
+			ret = -EINVAL;
+		}
+	} else if (p->delivery_system == SYS_DVBC_ANNEX_A ||
+			p->delivery_system == SYS_DVBC_ANNEX_C) {
+		priv->system = SYS_DVBC_ANNEX_A;
+		switch (priv->state) {
+		case STATE_SLEEP_TC:
+			ret = cxd2841er_sleep_tc_to_active_c(
+				priv, p->bandwidth_hz);
+			break;
+		case STATE_ACTIVE_TC:
+			ret = cxd2841er_retune_active(priv, p);
+			break;
+		default:
+			dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n",
+				__func__, priv->state);
+			ret = -EINVAL;
+		}
+	} else {
+		dev_dbg(&priv->i2c->dev,
+			"%s(): invalid delivery system %d\n",
+			__func__, p->delivery_system);
+		ret = -EINVAL;
+	}
+	if (ret)
+		goto done;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	cxd2841er_tune_done(priv);
+	timeout = 2500;
+	while (timeout > 0) {
+		ret = cxd2841er_read_status_tc(fe, &status);
+		if (ret)
+			goto done;
+		if (status & FE_HAS_LOCK)
+			break;
+		msleep(20);
+		timeout -= 20;
+	}
+	if (timeout < 0)
+		dev_dbg(&priv->i2c->dev,
+			"%s(): LOCK wait timeout\n", __func__);
+done:
+	return ret;
+}
+
+static int cxd2841er_tune_s(struct dvb_frontend *fe,
+			    bool re_tune,
+			    unsigned int mode_flags,
+			    unsigned int *delay,
+			    enum fe_status *status)
+{
+	int ret, carrier_offset;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	dev_dbg(&priv->i2c->dev, "%s() re_tune=%d\n", __func__, re_tune);
+	if (re_tune) {
+		ret = cxd2841er_set_frontend_s(fe);
+		if (ret)
+			return ret;
+		cxd2841er_read_status_s(fe, status);
+		if (*status & FE_HAS_LOCK) {
+			if (cxd2841er_get_carrier_offset_s_s2(
+					priv, &carrier_offset))
+				return -EINVAL;
+			p->frequency += carrier_offset;
+			ret = cxd2841er_set_frontend_s(fe);
+			if (ret)
+				return ret;
+		}
+	}
+	*delay = HZ / 5;
+	return cxd2841er_read_status_s(fe, status);
+}
+
+static int cxd2841er_tune_tc(struct dvb_frontend *fe,
+			     bool re_tune,
+			     unsigned int mode_flags,
+			     unsigned int *delay,
+			     enum fe_status *status)
+{
+	int ret, carrier_offset;
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+	dev_dbg(&priv->i2c->dev, "%s(): re_tune %d\n", __func__, re_tune);
+	if (re_tune) {
+		ret = cxd2841er_set_frontend_tc(fe);
+		if (ret)
+			return ret;
+		cxd2841er_read_status_tc(fe, status);
+		if (*status & FE_HAS_LOCK) {
+			switch (priv->system) {
+			case SYS_DVBT:
+			case SYS_DVBT2:
+				ret = cxd2841er_get_carrier_offset_t2(
+					priv, p->bandwidth_hz,
+					&carrier_offset);
+				break;
+			case SYS_DVBC_ANNEX_A:
+				ret = cxd2841er_get_carrier_offset_c(
+					priv, &carrier_offset);
+				break;
+			default:
+				dev_dbg(&priv->i2c->dev,
+					"%s(): invalid delivery system %d\n",
+					__func__, priv->system);
+				return -EINVAL;
+			}
+			if (ret)
+				return ret;
+			dev_dbg(&priv->i2c->dev, "%s(): carrier offset %d\n",
+				__func__, carrier_offset);
+			p->frequency += carrier_offset;
+			ret = cxd2841er_set_frontend_tc(fe);
+			if (ret)
+				return ret;
+		}
+	}
+	*delay = HZ / 5;
+	return cxd2841er_read_status_tc(fe, status);
+}
+
+static int cxd2841er_sleep_s(struct dvb_frontend *fe)
+{
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_active_s_to_sleep_s(fe->demodulator_priv);
+	cxd2841er_sleep_s_to_shutdown(fe->demodulator_priv);
+	return 0;
+}
+
+static int cxd2841er_sleep_tc(struct dvb_frontend *fe)
+{
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state == STATE_ACTIVE_TC) {
+		switch (priv->system) {
+		case SYS_DVBT:
+			cxd2841er_active_t_to_sleep_tc(priv);
+			break;
+		case SYS_DVBT2:
+			cxd2841er_active_t2_to_sleep_tc(priv);
+			break;
+		case SYS_DVBC_ANNEX_A:
+			cxd2841er_active_c_to_sleep_tc(priv);
+			break;
+		default:
+			dev_warn(&priv->i2c->dev,
+				"%s(): unknown delivery system %d\n",
+				__func__, priv->system);
+		}
+	}
+	if (priv->state != STATE_SLEEP_TC) {
+		dev_err(&priv->i2c->dev, "%s(): invalid state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	cxd2841er_sleep_tc_to_shutdown(priv);
+	return 0;
+}
+
+static int cxd2841er_send_burst(struct dvb_frontend *fe,
+				enum fe_sec_mini_cmd burst)
+{
+	u8 data;
+	struct cxd2841er_priv *priv  = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s(): burst mode %s\n", __func__,
+		(burst == SEC_MINI_A ? "A" : "B"));
+	if (priv->state != STATE_SLEEP_S &&
+			priv->state != STATE_ACTIVE_S) {
+		dev_err(&priv->i2c->dev, "%s(): invalid demod state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	data = (burst == SEC_MINI_A ? 0 : 1);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xbb);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x34, 0x01);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x35, data);
+	return 0;
+}
+
+static int cxd2841er_set_tone(struct dvb_frontend *fe,
+			      enum fe_sec_tone_mode tone)
+{
+	u8 data;
+	struct cxd2841er_priv *priv  = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s(): tone %s\n", __func__,
+		(tone == SEC_TONE_ON ? "On" : "Off"));
+	if (priv->state != STATE_SLEEP_S &&
+			priv->state != STATE_ACTIVE_S) {
+		dev_err(&priv->i2c->dev, "%s(): invalid demod state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	data = (tone == SEC_TONE_ON ? 1 : 0);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xbb);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x36, data);
+	return 0;
+}
+
+static int cxd2841er_send_diseqc_msg(struct dvb_frontend *fe,
+				     struct dvb_diseqc_master_cmd *cmd)
+{
+	int i;
+	u8 data[12];
+	struct cxd2841er_priv *priv  = fe->demodulator_priv;
+
+	if (priv->state != STATE_SLEEP_S &&
+			priv->state != STATE_ACTIVE_S) {
+		dev_err(&priv->i2c->dev, "%s(): invalid demod state %d\n",
+			__func__, priv->state);
+		return -EINVAL;
+	}
+	dev_dbg(&priv->i2c->dev,
+		"%s(): cmd->len %d\n", __func__, cmd->msg_len);
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xbb);
+	/* DiDEqC enable */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x33, 0x01);
+	/* cmd1 length & data */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x3d, cmd->msg_len);
+	memset(data, 0, sizeof(data));
+	for (i = 0; i < cmd->msg_len && i < sizeof(data); i++)
+		data[i] = cmd->msg[i];
+	cxd2841er_write_regs(priv, I2C_SLVT, 0x3e, data, sizeof(data));
+	/* repeat count for cmd1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x37, 1);
+	/* repeat count for cmd2: always 0 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x38, 0);
+	/* start transmit */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x32, 0x01);
+	/* wait for 1 sec timeout */
+	for (i = 0; i < 50; i++) {
+		cxd2841er_read_reg(priv, I2C_SLVT, 0x10, data);
+		if (!data[0]) {
+			dev_dbg(&priv->i2c->dev,
+				"%s(): DiSEqC cmd has been sent\n", __func__);
+			return 0;
+		}
+		msleep(20);
+	}
+	dev_dbg(&priv->i2c->dev,
+		"%s(): DiSEqC cmd transmit timeout\n", __func__);
+	return -ETIMEDOUT;
+}
+
+static void cxd2841er_release(struct dvb_frontend *fe)
+{
+	struct cxd2841er_priv *priv  = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	kfree(priv);
+}
+
+static int cxd2841er_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s(): enable=%d\n", __func__, enable);
+	cxd2841er_set_reg_bits(
+		priv, I2C_SLVX, 0x8, (enable ? 0x01 : 0x00), 0x01);
+	return 0;
+}
+
+static enum dvbfe_algo cxd2841er_get_algo(struct dvb_frontend *fe)
+{
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	return DVBFE_ALGO_HW;
+}
+
+static int cxd2841er_init_s(struct dvb_frontend *fe)
+{
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_shutdown_to_sleep_s(priv);
+	/* SONY_DEMOD_CONFIG_SAT_IFAGCNEG set to 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xb9, 0x01, 0x01);
+	return 0;
+}
+
+static int cxd2841er_init_tc(struct dvb_frontend *fe)
+{
+	struct cxd2841er_priv *priv = fe->demodulator_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	cxd2841er_shutdown_to_sleep_tc(priv);
+	/* SONY_DEMOD_CONFIG_IFAGCNEG = 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcb, 0x40, 0x40);
+	/* SONY_DEMOD_CONFIG_IFAGC_ADC_FS = 0 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0xcd, 0x50);
+	/* SONY_DEMOD_CONFIG_PARALLEL_SEL = 1 */
+	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00);
+	cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xc4, 0x00, 0x80);
+	return 0;
+}
+
+static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops;
+static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops;
+static struct dvb_frontend_ops cxd2841er_dvbc_ops;
+
+static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg,
+					     struct i2c_adapter *i2c,
+					     u8 system)
+{
+	u8 chip_id = 0;
+	const char *type;
+	struct cxd2841er_priv *priv = NULL;
+
+	/* allocate memory for the internal state */
+	priv = kzalloc(sizeof(struct cxd2841er_priv), GFP_KERNEL);
+	if (!priv)
+		return NULL;
+	priv->i2c = i2c;
+	priv->config = cfg;
+	priv->i2c_addr_slvx = (cfg->i2c_addr + 4) >> 1;
+	priv->i2c_addr_slvt = (cfg->i2c_addr) >> 1;
+	/* create dvb_frontend */
+	switch (system) {
+	case SYS_DVBS:
+		memcpy(&priv->frontend.ops,
+			&cxd2841er_dvbs_s2_ops,
+			sizeof(struct dvb_frontend_ops));
+		type = "S/S2";
+		break;
+	case SYS_DVBT:
+		memcpy(&priv->frontend.ops,
+			&cxd2841er_dvbt_t2_ops,
+			sizeof(struct dvb_frontend_ops));
+		type = "T/T2";
+		break;
+	case SYS_DVBC_ANNEX_A:
+		memcpy(&priv->frontend.ops,
+			&cxd2841er_dvbc_ops,
+			sizeof(struct dvb_frontend_ops));
+		type = "C/C2";
+		break;
+	default:
+		kfree(priv);
+		return NULL;
+	}
+	priv->frontend.demodulator_priv = priv;
+	dev_info(&priv->i2c->dev,
+		"%s(): attaching CXD2841ER DVB-%s frontend\n",
+		__func__, type);
+	dev_info(&priv->i2c->dev,
+		"%s(): I2C adapter %p SLVX addr %x SLVT addr %x\n",
+		__func__, priv->i2c,
+		priv->i2c_addr_slvx, priv->i2c_addr_slvt);
+	chip_id = cxd2841er_chip_id(priv);
+	if (chip_id != CXD2841ER_CHIP_ID) {
+		dev_err(&priv->i2c->dev, "%s(): invalid chip ID 0x%02x\n",
+			__func__, chip_id);
+		priv->frontend.demodulator_priv = NULL;
+		kfree(priv);
+		return NULL;
+	}
+	dev_info(&priv->i2c->dev, "%s(): chip ID 0x%02x OK.\n",
+		__func__, chip_id);
+	return &priv->frontend;
+}
+
+struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg,
+					struct i2c_adapter *i2c)
+{
+	return cxd2841er_attach(cfg, i2c, SYS_DVBS);
+}
+EXPORT_SYMBOL(cxd2841er_attach_s);
+
+struct dvb_frontend *cxd2841er_attach_t(struct cxd2841er_config *cfg,
+					struct i2c_adapter *i2c)
+{
+	return cxd2841er_attach(cfg, i2c, SYS_DVBT);
+}
+EXPORT_SYMBOL(cxd2841er_attach_t);
+
+struct dvb_frontend *cxd2841er_attach_c(struct cxd2841er_config *cfg,
+					struct i2c_adapter *i2c)
+{
+	return cxd2841er_attach(cfg, i2c, SYS_DVBC_ANNEX_A);
+}
+EXPORT_SYMBOL(cxd2841er_attach_c);
+
+static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2 },
+	.info = {
+		.name		= "Sony CXD2841ER DVB-S/S2 demodulator",
+		.frequency_min	= 500000,
+		.frequency_max	= 2500000,
+		.frequency_stepsize	= 0,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.symbol_rate_tolerance = 500,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK,
+	},
+	.init = cxd2841er_init_s,
+	.sleep = cxd2841er_sleep_s,
+	.release = cxd2841er_release,
+	.set_frontend = cxd2841er_set_frontend_s,
+	.get_frontend = cxd2841er_get_frontend,
+	.read_status = cxd2841er_read_status_s,
+	.i2c_gate_ctrl = cxd2841er_i2c_gate_ctrl,
+	.get_frontend_algo = cxd2841er_get_algo,
+	.set_tone = cxd2841er_set_tone,
+	.diseqc_send_burst = cxd2841er_send_burst,
+	.diseqc_send_master_cmd = cxd2841er_send_diseqc_msg,
+	.tune = cxd2841er_tune_s
+};
+
+static struct  dvb_frontend_ops cxd2841er_dvbt_t2_ops = {
+	.delsys = { SYS_DVBT, SYS_DVBT2 },
+	.info = {
+		.name	= "Sony CXD2841ER DVB-T/T2 demodulator",
+		.caps = FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_32 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 |
+			FE_CAN_QAM_256 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_MUTE_TS |
+			FE_CAN_2G_MODULATION,
+		.frequency_min = 42000000,
+		.frequency_max = 1002000000
+	},
+	.init = cxd2841er_init_tc,
+	.sleep = cxd2841er_sleep_tc,
+	.release = cxd2841er_release,
+	.set_frontend = cxd2841er_set_frontend_tc,
+	.get_frontend = cxd2841er_get_frontend,
+	.read_status = cxd2841er_read_status_tc,
+	.tune = cxd2841er_tune_tc,
+	.i2c_gate_ctrl = cxd2841er_i2c_gate_ctrl,
+	.get_frontend_algo = cxd2841er_get_algo
+};
+
+static struct  dvb_frontend_ops cxd2841er_dvbc_ops = {
+	.delsys = { SYS_DVBC_ANNEX_A },
+	.info = {
+		.name	= "Sony CXD2841ER DVB-C demodulator",
+		.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_QAM_16 |
+			FE_CAN_QAM_32 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 |
+			FE_CAN_QAM_256 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_INVERSION_AUTO,
+		.frequency_min = 42000000,
+		.frequency_max = 1002000000
+	},
+	.init = cxd2841er_init_tc,
+	.sleep = cxd2841er_sleep_tc,
+	.release = cxd2841er_release,
+	.set_frontend = cxd2841er_set_frontend_tc,
+	.get_frontend = cxd2841er_get_frontend,
+	.read_status = cxd2841er_read_status_tc,
+	.tune = cxd2841er_tune_tc,
+	.i2c_gate_ctrl = cxd2841er_i2c_gate_ctrl,
+	.get_frontend_algo = cxd2841er_get_algo,
+};
+
+MODULE_DESCRIPTION("Sony CXD2841ER DVB-C/C2/T/T2/S/S2 demodulator driver");
+MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>");
+MODULE_LICENSE("GPL");

+ 65 - 0
drivers/media/dvb-frontends/cxd2841er.h

@@ -0,0 +1,65 @@
+/*
+ * cxd2841er.h
+ *
+ * Sony CXD2441ER digital demodulator driver public definitions
+ *
+ * Copyright 2012 Sony Corporation
+ * Copyright (C) 2014 NetUP Inc.
+ * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
+ * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+  */
+
+#ifndef CXD2841ER_H
+#define CXD2841ER_H
+
+#include <linux/kconfig.h>
+#include <linux/dvb/frontend.h>
+
+struct cxd2841er_config {
+	u8	i2c_addr;
+};
+
+#if IS_REACHABLE(CONFIG_DVB_CXD2841ER)
+extern struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg,
+					       struct i2c_adapter *i2c);
+
+extern struct dvb_frontend *cxd2841er_attach_t(struct cxd2841er_config *cfg,
+					       struct i2c_adapter *i2c);
+
+extern struct dvb_frontend *cxd2841er_attach_c(struct cxd2841er_config *cfg,
+					       struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *cxd2841er_attach_s(
+					struct cxd2841er_config *cfg,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct dvb_frontend *cxd2841er_attach_t(
+		struct cxd2841er_config *cfg, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct dvb_frontend *cxd2841er_attach_c(
+		struct cxd2841er_config *cfg, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif

+ 43 - 0
drivers/media/dvb-frontends/cxd2841er_priv.h

@@ -0,0 +1,43 @@
+/*
+ * cxd2841er_priv.h
+ *
+ * Sony CXD2441ER digital demodulator driver internal definitions
+ *
+ * Copyright 2012 Sony Corporation
+ * Copyright (C) 2014 NetUP Inc.
+ * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
+ * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CXD2841ER_PRIV_H
+#define CXD2841ER_PRIV_H
+
+#define I2C_SLVX			0
+#define I2C_SLVT			1
+
+#define CXD2841ER_CHIP_ID		0xa7
+
+#define CXD2841ER_DVBS_POLLING_INVL	10
+
+struct cxd2841er_cnr_data {
+	u32 value;
+	int cnr_x1000;
+};
+
+enum cxd2841er_dvbt2_profile_t {
+	DVBT2_PROFILE_ANY = 0,
+	DVBT2_PROFILE_BASE = 1,
+	DVBT2_PROFILE_LITE = 2
+};
+
+#endif

+ 25 - 25
drivers/media/dvb-frontends/dvb-pll.c

@@ -34,7 +34,7 @@ struct dvb_pll_priv {
 	struct i2c_adapter *i2c;
 
 	/* the PLL descriptor */
-	struct dvb_pll_desc *pll_desc;
+	const struct dvb_pll_desc *pll_desc;
 
 	/* cached frequency/bandwidth */
 	u32 frequency;
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)");
 /* ----------------------------------------------------------- */
 
 struct dvb_pll_desc {
-	char *name;
+	const char *name;
 	u32  min;
 	u32  max;
 	u32  iffreq;
@@ -71,13 +71,13 @@ struct dvb_pll_desc {
 		u32 stepsize;
 		u8  config;
 		u8  cb;
-	} entries[12];
+	} entries[];
 };
 
 /* ----------------------------------------------------------- */
 /* descriptions                                                */
 
-static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+static const struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
 	.name  = "Thomson dtt7579",
 	.min   = 177000000,
 	.max   = 858000000,
@@ -99,7 +99,7 @@ static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf)
 		buf[3] |= 0x10;
 }
 
-static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+static const struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
 	.name  = "Thomson dtt759x",
 	.min   = 177000000,
 	.max   = 896000000,
@@ -123,7 +123,7 @@ static void thomson_dtt7520x_bw(struct dvb_frontend *fe, u8 *buf)
 		buf[3] ^= 0x10;
 }
 
-static struct dvb_pll_desc dvb_pll_thomson_dtt7520x = {
+static const struct dvb_pll_desc dvb_pll_thomson_dtt7520x = {
 	.name  = "Thomson dtt7520x",
 	.min   = 185000000,
 	.max   = 900000000,
@@ -141,7 +141,7 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7520x = {
 	},
 };
 
-static struct dvb_pll_desc dvb_pll_lg_z201 = {
+static const struct dvb_pll_desc dvb_pll_lg_z201 = {
 	.name  = "LG z201",
 	.min   = 174000000,
 	.max   = 862000000,
@@ -157,7 +157,7 @@ static struct dvb_pll_desc dvb_pll_lg_z201 = {
 	},
 };
 
-static struct dvb_pll_desc dvb_pll_unknown_1 = {
+static const struct dvb_pll_desc dvb_pll_unknown_1 = {
 	.name  = "unknown 1", /* used by dntv live dvb-t */
 	.min   = 174000000,
 	.max   = 862000000,
@@ -179,7 +179,7 @@ static struct dvb_pll_desc dvb_pll_unknown_1 = {
 /* Infineon TUA6010XS
  * used in Thomson Cable Tuner
  */
-static struct dvb_pll_desc dvb_pll_tua6010xs = {
+static const struct dvb_pll_desc dvb_pll_tua6010xs = {
 	.name  = "Infineon TUA6010XS",
 	.min   =  44250000,
 	.max   = 858000000,
@@ -193,7 +193,7 @@ static struct dvb_pll_desc dvb_pll_tua6010xs = {
 };
 
 /* Panasonic env57h1xd5 (some Philips PLL ?) */
-static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+static const struct dvb_pll_desc dvb_pll_env57h1xd5 = {
 	.name  = "Panasonic ENV57H1XD5",
 	.min   =  44250000,
 	.max   = 858000000,
@@ -217,7 +217,7 @@ static void tda665x_bw(struct dvb_frontend *fe, u8 *buf)
 		buf[3] |= 0x08;
 }
 
-static struct dvb_pll_desc dvb_pll_tda665x = {
+static const struct dvb_pll_desc dvb_pll_tda665x = {
 	.name  = "Philips TDA6650/TDA6651",
 	.min   =  44250000,
 	.max   = 858000000,
@@ -251,7 +251,7 @@ static void tua6034_bw(struct dvb_frontend *fe, u8 *buf)
 		buf[3] |= 0x08;
 }
 
-static struct dvb_pll_desc dvb_pll_tua6034 = {
+static const struct dvb_pll_desc dvb_pll_tua6034 = {
 	.name  = "Infineon TUA6034",
 	.min   =  44250000,
 	.max   = 858000000,
@@ -275,7 +275,7 @@ static void tded4_bw(struct dvb_frontend *fe, u8 *buf)
 		buf[3] |= 0x04;
 }
 
-static struct dvb_pll_desc dvb_pll_tded4 = {
+static const struct dvb_pll_desc dvb_pll_tded4 = {
 	.name = "ALPS TDED4",
 	.min = 47000000,
 	.max = 863000000,
@@ -293,7 +293,7 @@ static struct dvb_pll_desc dvb_pll_tded4 = {
 /* ALPS TDHU2
  * used in AverTVHD MCE A180
  */
-static struct dvb_pll_desc dvb_pll_tdhu2 = {
+static const struct dvb_pll_desc dvb_pll_tdhu2 = {
 	.name = "ALPS TDHU2",
 	.min = 54000000,
 	.max = 864000000,
@@ -310,7 +310,7 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = {
 /* Samsung TBMV30111IN / TBMV30712IN1
  * used in Air2PC ATSC - 2nd generation (nxt2002)
  */
-static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
+static const struct dvb_pll_desc dvb_pll_samsung_tbmv = {
 	.name = "Samsung TBMV30111IN / TBMV30712IN1",
 	.min = 54000000,
 	.max = 860000000,
@@ -329,7 +329,7 @@ static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
 /*
  * Philips SD1878 Tuner.
  */
-static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
+static const struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
 	.name  = "Philips SD1878",
 	.min   =  950000,
 	.max   = 2150000,
@@ -395,7 +395,7 @@ static void opera1_bw(struct dvb_frontend *fe, u8 *buf)
 	return;
 }
 
-static struct dvb_pll_desc dvb_pll_opera1 = {
+static const struct dvb_pll_desc dvb_pll_opera1 = {
 	.name  = "Opera Tuner",
 	.min   =  900000,
 	.max   = 2250000,
@@ -442,7 +442,7 @@ static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf)
 }
 
 /* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
-static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
+static const struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
 	.name   = "Samsung DTOS403IH102A",
 	.min    =  44250000,
 	.max    = 858000000,
@@ -462,7 +462,7 @@ static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
 };
 
 /* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */
-static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
+static const struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
 	.name	= "Samsung TDTC9251DH0",
 	.min	=  48000000,
 	.max	= 863000000,
@@ -476,7 +476,7 @@ static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
 };
 
 /* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */
-static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
+static const struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
 	.name = "Samsung TBDU18132",
 	.min	=  950000,
 	.max	= 2150000, /* guesses */
@@ -497,7 +497,7 @@ static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
 };
 
 /* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */
-static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
+static const struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
 	.name = "Samsung TBMU24112",
 	.min	=  950000,
 	.max	= 2150000, /* guesses */
@@ -518,7 +518,7 @@ static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
  * 153 - 430   0  *  0   0   0   0   1   0   0x02
  * 430 - 822   0  *  0   0   1   0   0   0   0x08
  * 822 - 862   1  *  0   0   1   0   0   0   0x88 */
-static struct dvb_pll_desc dvb_pll_alps_tdee4 = {
+static const struct dvb_pll_desc dvb_pll_alps_tdee4 = {
 	.name = "ALPS TDEE4",
 	.min	=  47000000,
 	.max	= 862000000,
@@ -534,7 +534,7 @@ static struct dvb_pll_desc dvb_pll_alps_tdee4 = {
 
 /* ----------------------------------------------------------- */
 
-static struct dvb_pll_desc *pll_list[] = {
+static const struct dvb_pll_desc *pll_list[] = {
 	[DVB_PLL_UNDEFINED]              = NULL,
 	[DVB_PLL_THOMSON_DTT7579]        = &dvb_pll_thomson_dtt7579,
 	[DVB_PLL_THOMSON_DTT759X]        = &dvb_pll_thomson_dtt759x,
@@ -564,7 +564,7 @@ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
 			     const u32 frequency)
 {
 	struct dvb_pll_priv *priv = fe->tuner_priv;
-	struct dvb_pll_desc *desc = priv->pll_desc;
+	const struct dvb_pll_desc *desc = priv->pll_desc;
 	u32 div;
 	int i;
 
@@ -758,7 +758,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
 			       .buf = b1, .len = 1 };
 	struct dvb_pll_priv *priv = NULL;
 	int ret;
-	struct dvb_pll_desc *desc;
+	const struct dvb_pll_desc *desc;
 
 	if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
 	    (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))

+ 430 - 0
drivers/media/dvb-frontends/horus3a.c

@@ -0,0 +1,430 @@
+/*
+ * horus3a.h
+ *
+ * Sony Horus3A DVB-S/S2 tuner driver
+ *
+ * Copyright 2012 Sony Corporation
+ * Copyright (C) 2014 NetUP Inc.
+ * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
+ * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <linux/types.h>
+#include "horus3a.h"
+#include "dvb_frontend.h"
+
+#define MAX_WRITE_REGSIZE      5
+
+enum horus3a_state {
+	STATE_UNKNOWN,
+	STATE_SLEEP,
+	STATE_ACTIVE
+};
+
+struct horus3a_priv {
+	u32			frequency;
+	u8			i2c_address;
+	struct i2c_adapter	*i2c;
+	enum horus3a_state	state;
+	void			*set_tuner_data;
+	int			(*set_tuner)(void *, int);
+};
+
+static void horus3a_i2c_debug(struct horus3a_priv *priv,
+			      u8 reg, u8 write, const u8 *data, u32 len)
+{
+	dev_dbg(&priv->i2c->dev, "horus3a: I2C %s reg 0x%02x size %d\n",
+		(write == 0 ? "read" : "write"), reg, len);
+	print_hex_dump_bytes("horus3a: I2C data: ",
+		DUMP_PREFIX_OFFSET, data, len);
+}
+
+static int horus3a_write_regs(struct horus3a_priv *priv,
+			      u8 reg, const u8 *data, u32 len)
+{
+	int ret;
+	u8 buf[MAX_WRITE_REGSIZE + 1];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->i2c_address,
+			.flags = 0,
+			.len = len + 1,
+			.buf = buf,
+		}
+	};
+
+	if (len + 1 >= sizeof(buf)) {
+		dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n",
+			 reg, len + 1);
+		return -E2BIG;
+	}
+
+	horus3a_i2c_debug(priv, reg, 1, data, len);
+	buf[0] = reg;
+	memcpy(&buf[1], data, len);
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret >= 0 && ret != 1)
+		ret = -EREMOTEIO;
+	if (ret < 0) {
+		dev_warn(&priv->i2c->dev,
+			"%s: i2c wr failed=%d reg=%02x len=%d\n",
+			KBUILD_MODNAME, ret, reg, len);
+		return ret;
+	}
+	return 0;
+}
+
+static int horus3a_write_reg(struct horus3a_priv *priv, u8 reg, u8 val)
+{
+	return horus3a_write_regs(priv, reg, &val, 1);
+}
+
+static int horus3a_enter_power_save(struct horus3a_priv *priv)
+{
+	u8 data[2];
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state == STATE_SLEEP)
+		return 0;
+	/* IQ Generator disable */
+	horus3a_write_reg(priv, 0x2a, 0x79);
+	/* MDIV_EN = 0 */
+	horus3a_write_reg(priv, 0x29, 0x70);
+	/* VCO disable preparation */
+	horus3a_write_reg(priv, 0x28, 0x3e);
+	/* VCO buffer disable */
+	horus3a_write_reg(priv, 0x2a, 0x19);
+	/* VCO calibration disable */
+	horus3a_write_reg(priv, 0x1c, 0x00);
+	/* Power save setting (xtal is not stopped) */
+	data[0] = 0xC0;
+	/* LNA is Disabled */
+	data[1] = 0xA7;
+	/* 0x11 - 0x12 */
+	horus3a_write_regs(priv, 0x11, data, sizeof(data));
+	priv->state = STATE_SLEEP;
+	return 0;
+}
+
+static int horus3a_leave_power_save(struct horus3a_priv *priv)
+{
+	u8 data[2];
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	if (priv->state == STATE_ACTIVE)
+		return 0;
+	/* Leave power save */
+	data[0] = 0x00;
+	/* LNA is Disabled */
+	data[1] = 0xa7;
+	/* 0x11 - 0x12 */
+	horus3a_write_regs(priv, 0x11, data, sizeof(data));
+	/* VCO buffer enable */
+	horus3a_write_reg(priv, 0x2a, 0x79);
+	/* VCO calibration enable */
+	horus3a_write_reg(priv, 0x1c, 0xc0);
+	/* MDIV_EN = 1 */
+	horus3a_write_reg(priv, 0x29, 0x71);
+	usleep_range(5000, 7000);
+	priv->state = STATE_ACTIVE;
+	return 0;
+}
+
+static int horus3a_init(struct dvb_frontend *fe)
+{
+	struct horus3a_priv *priv = fe->tuner_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	return 0;
+}
+
+static int horus3a_release(struct dvb_frontend *fe)
+{
+	struct horus3a_priv *priv = fe->tuner_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int horus3a_sleep(struct dvb_frontend *fe)
+{
+	struct horus3a_priv *priv = fe->tuner_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	horus3a_enter_power_save(priv);
+	return 0;
+}
+
+static int horus3a_set_params(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct horus3a_priv *priv = fe->tuner_priv;
+	u32 frequency = p->frequency;
+	u32 symbol_rate = p->symbol_rate/1000;
+	u8 mixdiv = 0;
+	u8 mdiv = 0;
+	u32 ms = 0;
+	u8 f_ctl = 0;
+	u8 g_ctl = 0;
+	u8 fc_lpf = 0;
+	u8 data[5];
+
+	dev_dbg(&priv->i2c->dev, "%s(): frequency %dkHz symbol_rate %dksps\n",
+		__func__, frequency, symbol_rate);
+	if (priv->set_tuner)
+		priv->set_tuner(priv->set_tuner_data, 0);
+	if (priv->state == STATE_SLEEP)
+		horus3a_leave_power_save(priv);
+
+	/* frequency should be X MHz (X : integer) */
+	frequency = DIV_ROUND_CLOSEST(frequency, 1000) * 1000;
+	if (frequency <= 1155000) {
+		mixdiv = 4;
+		mdiv = 1;
+	} else {
+		mixdiv = 2;
+		mdiv = 0;
+	}
+	/* Assumed that fREF == 1MHz (1000kHz) */
+	ms = DIV_ROUND_CLOSEST((frequency * mixdiv) / 2, 1000);
+	if (ms > 0x7FFF) { /* 15 bit */
+		dev_err(&priv->i2c->dev, "horus3a: invalid frequency %d\n",
+			frequency);
+		return -EINVAL;
+	}
+	if (frequency < 975000) {
+		/* F_CTL=11100 G_CTL=001 */
+		f_ctl = 0x1C;
+		g_ctl = 0x01;
+	} else if (frequency < 1050000) {
+		/* F_CTL=11000 G_CTL=010 */
+		f_ctl = 0x18;
+		g_ctl = 0x02;
+	} else if (frequency < 1150000) {
+		/* F_CTL=10100 G_CTL=010 */
+		f_ctl = 0x14;
+		g_ctl = 0x02;
+	} else if (frequency < 1250000) {
+		/* F_CTL=10000 G_CTL=011 */
+		f_ctl = 0x10;
+		g_ctl = 0x03;
+	} else if (frequency < 1350000) {
+		/* F_CTL=01100 G_CTL=100 */
+		f_ctl = 0x0C;
+		g_ctl = 0x04;
+	} else if (frequency < 1450000) {
+		/* F_CTL=01010 G_CTL=100 */
+		f_ctl = 0x0A;
+		g_ctl = 0x04;
+	} else if (frequency < 1600000) {
+		/* F_CTL=00111 G_CTL=101 */
+		f_ctl = 0x07;
+		g_ctl = 0x05;
+	} else if (frequency < 1800000) {
+		/* F_CTL=00100 G_CTL=010 */
+		f_ctl = 0x04;
+		g_ctl = 0x02;
+	} else if (frequency < 2000000) {
+		/* F_CTL=00010 G_CTL=001 */
+		f_ctl = 0x02;
+		g_ctl = 0x01;
+	} else {
+		/* F_CTL=00000 G_CTL=000 */
+		f_ctl = 0x00;
+		g_ctl = 0x00;
+	}
+	/* LPF cutoff frequency setting */
+	if (p->delivery_system == SYS_DVBS) {
+		/*
+		 * rolloff = 0.35
+		 * SR <= 4.3
+		 * fc_lpf = 5
+		 * 4.3 < SR <= 10
+		 * fc_lpf = SR * (1 + rolloff) / 2 + SR / 2 =
+		 *	SR * 1.175 = SR * (47/40)
+		 * 10 < SR
+		 * fc_lpf = SR * (1 + rolloff) / 2 + 5 =
+		 *	SR * 0.675 + 5 = SR * (27/40) + 5
+		 * NOTE: The result should be round up.
+		 */
+		if (symbol_rate <= 4300)
+			fc_lpf = 5;
+		else if (symbol_rate <= 10000)
+			fc_lpf = (u8)DIV_ROUND_UP(symbol_rate * 47, 40000);
+		else
+			fc_lpf = (u8)DIV_ROUND_UP(symbol_rate * 27, 40000) + 5;
+		/* 5 <= fc_lpf <= 36 */
+		if (fc_lpf > 36)
+			fc_lpf = 36;
+	} else if (p->delivery_system == SYS_DVBS2) {
+		int rolloff;
+
+		switch (p->rolloff) {
+		case ROLLOFF_35:
+			rolloff = 35;
+			break;
+		case ROLLOFF_25:
+			rolloff = 25;
+			break;
+		case ROLLOFF_20:
+			rolloff = 20;
+			break;
+		case ROLLOFF_AUTO:
+		default:
+			dev_err(&priv->i2c->dev,
+				"horus3a: auto roll-off is not supported\n");
+			return -EINVAL;
+		}
+		/*
+		 * SR <= 4.5:
+		 * fc_lpf = 5
+		 * 4.5 < SR <= 10:
+		 * fc_lpf = SR * (1 + rolloff) / 2 + SR / 2
+		 * 10 < SR:
+		 * fc_lpf = SR * (1 + rolloff) / 2 + 5
+		 * NOTE: The result should be round up.
+		 */
+		if (symbol_rate <= 4500)
+			fc_lpf = 5;
+		else if (symbol_rate <= 10000)
+			fc_lpf = (u8)DIV_ROUND_UP(
+				symbol_rate * (200 + rolloff), 200000);
+		else
+			fc_lpf = (u8)DIV_ROUND_UP(
+				symbol_rate * (100 + rolloff), 200000) + 5;
+		/* 5 <= fc_lpf <= 36 is valid */
+		if (fc_lpf > 36)
+			fc_lpf = 36;
+	} else {
+		dev_err(&priv->i2c->dev,
+			"horus3a: invalid delivery system %d\n",
+			p->delivery_system);
+		return -EINVAL;
+	}
+	/* 0x00 - 0x04 */
+	data[0] = (u8)((ms >> 7) & 0xFF);
+	data[1] = (u8)((ms << 1) & 0xFF);
+	data[2] = 0x00;
+	data[3] = 0x00;
+	data[4] = (u8)(mdiv << 7);
+	horus3a_write_regs(priv, 0x00, data, sizeof(data));
+	/* Write G_CTL, F_CTL */
+	horus3a_write_reg(priv, 0x09, (u8)((g_ctl << 5) | f_ctl));
+	/* Write LPF cutoff frequency */
+	horus3a_write_reg(priv, 0x37, (u8)(0x80 | (fc_lpf << 1)));
+	/* Start Calibration */
+	horus3a_write_reg(priv, 0x05, 0x80);
+	/* IQ Generator enable */
+	horus3a_write_reg(priv, 0x2a, 0x7b);
+	/* tuner stabilization time */
+	msleep(60);
+	/* Store tuned frequency to the struct */
+	priv->frequency = ms * 2 * 1000 / mixdiv;
+	return 0;
+}
+
+static int horus3a_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct horus3a_priv *priv = fe->tuner_priv;
+
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops horus3a_tuner_ops = {
+	.info = {
+		.name = "Sony Horus3a",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_step = 1000,
+	},
+	.init = horus3a_init,
+	.release = horus3a_release,
+	.sleep = horus3a_sleep,
+	.set_params = horus3a_set_params,
+	.get_frequency = horus3a_get_frequency,
+};
+
+struct dvb_frontend *horus3a_attach(struct dvb_frontend *fe,
+				    const struct horus3a_config *config,
+				    struct i2c_adapter *i2c)
+{
+	u8 buf[3], val;
+	struct horus3a_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct horus3a_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	priv->i2c_address = (config->i2c_address >> 1);
+	priv->i2c = i2c;
+	priv->set_tuner_data = config->set_tuner_priv;
+	priv->set_tuner = config->set_tuner_callback;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* wait 4ms after power on */
+	usleep_range(4000, 6000);
+	/* IQ Generator disable */
+	horus3a_write_reg(priv, 0x2a, 0x79);
+	/* REF_R = Xtal Frequency */
+	buf[0] = config->xtal_freq_mhz;
+	buf[1] = config->xtal_freq_mhz;
+	buf[2] = 0;
+	/* 0x6 - 0x8 */
+	horus3a_write_regs(priv, 0x6, buf, 3);
+	/* IQ Out = Single Ended */
+	horus3a_write_reg(priv, 0x0a, 0x40);
+	switch (config->xtal_freq_mhz) {
+	case 27:
+		val = 0x1f;
+		break;
+	case 24:
+		val = 0x10;
+		break;
+	case 16:
+		val = 0xc;
+		break;
+	default:
+		val = 0;
+		dev_warn(&priv->i2c->dev,
+			"horus3a: invalid xtal frequency %dMHz\n",
+			config->xtal_freq_mhz);
+		break;
+	}
+	val <<= 2;
+	horus3a_write_reg(priv, 0x0e, val);
+	horus3a_enter_power_save(priv);
+	usleep_range(3000, 5000);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	memcpy(&fe->ops.tuner_ops, &horus3a_tuner_ops,
+				sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = priv;
+	dev_info(&priv->i2c->dev,
+		"Sony HORUS3A attached on addr=%x at I2C adapter %p\n",
+		priv->i2c_address, priv->i2c);
+	return fe;
+}
+EXPORT_SYMBOL(horus3a_attach);
+
+MODULE_DESCRIPTION("Sony HORUS3A sattelite tuner driver");
+MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>");
+MODULE_LICENSE("GPL");

+ 58 - 0
drivers/media/dvb-frontends/horus3a.h

@@ -0,0 +1,58 @@
+/*
+ * horus3a.h
+ *
+ * Sony Horus3A DVB-S/S2 tuner driver
+ *
+ * Copyright 2012 Sony Corporation
+ * Copyright (C) 2014 NetUP Inc.
+ * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
+ * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+  */
+
+#ifndef __DVB_HORUS3A_H__
+#define __DVB_HORUS3A_H__
+
+#include <linux/kconfig.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+/**
+ * struct horus3a_config - the configuration of Horus3A tuner driver
+ * @i2c_address:    I2C address of the tuner
+ * @xtal_freq_mhz:  Oscillator frequency, MHz
+ * @set_tuner_priv: Callback function private context
+ * @set_tuner_callback: Callback function that notifies the parent driver
+ *          which tuner is active now
+ */
+struct horus3a_config {
+	u8	i2c_address;
+	u8	xtal_freq_mhz;
+	void	*set_tuner_priv;
+	int	(*set_tuner_callback)(void *, int);
+};
+
+#if IS_REACHABLE(CONFIG_DVB_HORUS3A)
+extern struct dvb_frontend *horus3a_attach(struct dvb_frontend *fe,
+					const struct horus3a_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *horus3a_attach(
+					const struct cxd2820r_config *config,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif

+ 189 - 0
drivers/media/dvb-frontends/lnbh25.c

@@ -0,0 +1,189 @@
+/*
+ * lnbh25.c
+ *
+ * Driver for LNB supply and control IC LNBH25
+ *
+ * Copyright (C) 2014 NetUP Inc.
+ * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
+ * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbh25.h"
+
+/**
+ * struct lnbh25_priv - LNBH25 driver private data
+ * @i2c:		pointer to the I2C adapter structure
+ * @i2c_address:	I2C address of LNBH25 SEC chip
+ * @config:		Registers configuration:
+ *			offset 0: 1st register address, always 0x02 (DATA1)
+ *			offset 1: DATA1 register value
+ *			offset 2: DATA2 register value
+ */
+struct lnbh25_priv {
+	struct i2c_adapter	*i2c;
+	u8			i2c_address;
+	u8			config[3];
+};
+
+#define LNBH25_STATUS_OFL	0x1
+#define LNBH25_STATUS_VMON	0x4
+#define LNBH25_VSEL_13		0x03
+#define LNBH25_VSEL_18		0x0a
+
+static int lnbh25_read_vmon(struct lnbh25_priv *priv)
+{
+	int i, ret;
+	u8 addr = 0x00;
+	u8 status[6];
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->i2c_address,
+			.flags = 0,
+			.len = 1,
+			.buf = &addr
+		}, {
+			.addr = priv->i2c_address,
+			.flags = I2C_M_RD,
+			.len = sizeof(status),
+			.buf = status
+		}
+	};
+
+	for (i = 0; i < 2; i++) {
+		ret = i2c_transfer(priv->i2c, &msg[i], 1);
+		if (ret >= 0 && ret != 1)
+			ret = -EIO;
+		if (ret < 0) {
+			dev_dbg(&priv->i2c->dev,
+				"%s(): I2C transfer %d failed (%d)\n",
+				__func__, i, ret);
+			return ret;
+		}
+	}
+	print_hex_dump_bytes("lnbh25_read_vmon: ",
+		DUMP_PREFIX_OFFSET, status, sizeof(status));
+	if ((status[0] & (LNBH25_STATUS_OFL | LNBH25_STATUS_VMON)) != 0) {
+		dev_err(&priv->i2c->dev,
+			"%s(): voltage in failure state, status reg 0x%x\n",
+			__func__, status[0]);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int lnbh25_set_voltage(struct dvb_frontend *fe,
+			      enum fe_sec_voltage voltage)
+{
+	int ret;
+	u8 data1_reg;
+	const char *vsel;
+	struct lnbh25_priv *priv = fe->sec_priv;
+	struct i2c_msg msg = {
+		.addr = priv->i2c_address,
+		.flags = 0,
+		.len = sizeof(priv->config),
+		.buf = priv->config
+	};
+
+	switch (voltage) {
+	case SEC_VOLTAGE_OFF:
+		data1_reg = 0x00;
+		vsel = "Off";
+		break;
+	case SEC_VOLTAGE_13:
+		data1_reg = LNBH25_VSEL_13;
+		vsel = "13V";
+		break;
+	case SEC_VOLTAGE_18:
+		data1_reg = LNBH25_VSEL_18;
+		vsel = "18V";
+		break;
+	default:
+		return -EINVAL;
+	}
+	priv->config[1] = data1_reg;
+	dev_dbg(&priv->i2c->dev,
+		"%s(): %s, I2C 0x%x write [ %02x %02x %02x ]\n",
+		__func__, vsel, priv->i2c_address,
+		priv->config[0], priv->config[1], priv->config[2]);
+	ret = i2c_transfer(priv->i2c, &msg, 1);
+	if (ret >= 0 && ret != 1)
+		ret = -EIO;
+	if (ret < 0) {
+		dev_err(&priv->i2c->dev, "%s(): I2C transfer error (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+	if (voltage != SEC_VOLTAGE_OFF) {
+		msleep(120);
+		ret = lnbh25_read_vmon(priv);
+	} else {
+		msleep(20);
+		ret = 0;
+	}
+	return ret;
+}
+
+static void lnbh25_release(struct dvb_frontend *fe)
+{
+	struct lnbh25_priv *priv = fe->sec_priv;
+
+	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
+	lnbh25_set_voltage(fe, SEC_VOLTAGE_OFF);
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *lnbh25_attach(struct dvb_frontend *fe,
+				   struct lnbh25_config *cfg,
+				   struct i2c_adapter *i2c)
+{
+	struct lnbh25_priv *priv;
+
+	dev_dbg(&i2c->dev, "%s()\n", __func__);
+	priv = kzalloc(sizeof(struct lnbh25_priv), GFP_KERNEL);
+	if (!priv)
+		return NULL;
+	priv->i2c_address = (cfg->i2c_address >> 1);
+	priv->i2c = i2c;
+	priv->config[0] = 0x02;
+	priv->config[1] = 0x00;
+	priv->config[2] = cfg->data2_config;
+	fe->sec_priv = priv;
+	if (lnbh25_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		dev_err(&i2c->dev,
+			"%s(): no LNBH25 found at I2C addr 0x%02x\n",
+			__func__, priv->i2c_address);
+		kfree(priv);
+		fe->sec_priv = NULL;
+		return NULL;
+	}
+
+	fe->ops.release_sec = lnbh25_release;
+	fe->ops.set_voltage = lnbh25_set_voltage;
+
+	dev_err(&i2c->dev, "%s(): attached at I2C addr 0x%02x\n",
+		__func__, priv->i2c_address);
+	return fe;
+}
+EXPORT_SYMBOL(lnbh25_attach);
+
+MODULE_DESCRIPTION("ST LNBH25 driver");
+MODULE_AUTHOR("info@netup.ru");
+MODULE_LICENSE("GPL");

+ 56 - 0
drivers/media/dvb-frontends/lnbh25.h

@@ -0,0 +1,56 @@
+/*
+ * lnbh25.c
+ *
+ * Driver for LNB supply and control IC LNBH25
+ *
+ * Copyright (C) 2014 NetUP Inc.
+ * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
+ * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef LNBH25_H
+#define LNBH25_H
+
+#include <linux/i2c.h>
+#include <linux/kconfig.h>
+#include <linux/dvb/frontend.h>
+
+/* 22 kHz tone enabled. Tone output controlled by DSQIN pin */
+#define	LNBH25_TEN	0x01
+/* Low power mode activated (used only with 22 kHz tone output disabled) */
+#define LNBH25_LPM	0x02
+/* DSQIN input pin is set to receive external 22 kHz TTL signal source */
+#define LNBH25_EXTM	0x04
+
+struct lnbh25_config {
+	u8	i2c_address;
+	u8	data2_config;
+};
+
+#if IS_REACHABLE(CONFIG_DVB_LNBH25)
+struct dvb_frontend *lnbh25_attach(
+	struct dvb_frontend *fe,
+	struct lnbh25_config *cfg,
+	struct i2c_adapter *i2c);
+#else
+static inline dvb_frontend *lnbh25_attach(
+	struct dvb_frontend *fe,
+	struct lnbh25_config *cfg,
+	struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif

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

@@ -1495,7 +1495,6 @@ MODULE_DEVICE_TABLE(i2c, m88ds3103_id_table);
 
 static struct i2c_driver m88ds3103_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "m88ds3103",
 		.suppress_bind_attrs = true,
 	},

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

@@ -915,7 +915,6 @@ MODULE_DEVICE_TABLE(i2c, rtl2830_id_table);
 
 static struct i2c_driver rtl2830_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "rtl2830",
 	},
 	.probe		= rtl2830_probe,

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

@@ -1319,7 +1319,6 @@ MODULE_DEVICE_TABLE(i2c, rtl2832_id_table);
 
 static struct i2c_driver rtl2832_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "rtl2832",
 	},
 	.probe		= rtl2832_probe,

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

@@ -1538,7 +1538,6 @@ static int rtl2832_sdr_remove(struct platform_device *pdev)
 static struct platform_driver rtl2832_sdr_driver = {
 	.driver = {
 		.name   = "rtl2832_sdr",
-		.owner  = THIS_MODULE,
 	},
 	.probe          = rtl2832_sdr_probe,
 	.remove         = rtl2832_sdr_remove,

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

@@ -466,7 +466,7 @@ static int s921_tune(struct dvb_frontend *fe,
 
 static int s921_get_algo(struct dvb_frontend *fe)
 {
-	return 1; /* FE_ALGO_HW */
+	return DVBFE_ALGO_HW;
 }
 
 static void s921_release(struct dvb_frontend *fe)

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

@@ -757,7 +757,6 @@ MODULE_DEVICE_TABLE(i2c, si2168_id_table);
 
 static struct i2c_driver si2168_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "si2168",
 	},
 	.probe		= si2168_probe,

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

@@ -426,7 +426,6 @@ MODULE_DEVICE_TABLE(i2c, sp2_id);
 
 static struct i2c_driver sp2_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "sp2",
 	},
 	.probe		= sp2_probe,

+ 13 - 4
drivers/media/dvb-frontends/stv0367.c

@@ -791,11 +791,13 @@ int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len)
 	memcpy(buf + 2, data, len);
 
 	if (i2cdebug)
-		printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, buf[2]);
+		printk(KERN_DEBUG "%s: [%02x] %02x: %02x\n", __func__,
+			state->config->demod_address, reg, buf[2]);
 
 	ret = i2c_transfer(state->i2c, &msg, 1);
 	if (ret != 1)
-		printk(KERN_ERR "%s: i2c write error!\n", __func__);
+		printk(KERN_ERR "%s: i2c write error! ([%02x] %02x: %02x)\n",
+			__func__, state->config->demod_address, reg, buf[2]);
 
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
@@ -829,10 +831,12 @@ static u8 stv0367_readreg(struct stv0367_state *state, u16 reg)
 
 	ret = i2c_transfer(state->i2c, msg, 2);
 	if (ret != 2)
-		printk(KERN_ERR "%s: i2c read error\n", __func__);
+		printk(KERN_ERR "%s: i2c read error ([%02x] %02x: %02x)\n",
+			__func__, state->config->demod_address, reg, b1[0]);
 
 	if (i2cdebug)
-		printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, b1[0]);
+		printk(KERN_DEBUG "%s: [%02x] %02x: %02x\n", __func__,
+			state->config->demod_address, reg, b1[0]);
 
 	return b1[0];
 }
@@ -1550,6 +1554,11 @@ static int stv0367ter_init(struct dvb_frontend *fe)
 
 	switch (state->config->xtal) {
 		/*set internal freq to 53.125MHz */
+	case 16000000:
+		stv0367_writereg(state, R367TER_PLLMDIV, 0x2);
+		stv0367_writereg(state, R367TER_PLLNDIV, 0x1b);
+		stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
+		break;
 	case 25000000:
 		stv0367_writereg(state, R367TER_PLLMDIV, 0xa);
 		stv0367_writereg(state, R367TER_PLLNDIV, 0x55);

+ 333 - 492
drivers/media/dvb-frontends/tda10071.c

@@ -20,102 +20,15 @@
 
 #include "tda10071_priv.h"
 
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  64
-
 static struct dvb_frontend_ops tda10071_ops;
 
-/* write multiple registers */
-static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
-	int len)
-{
-	int ret;
-	u8 buf[MAX_XFER_SIZE];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg.demod_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;
-	}
-	return ret;
-}
-
-/* read multiple registers */
-static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
-	int len)
-{
-	int ret;
-	u8 buf[MAX_XFER_SIZE];
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg.demod_i2c_addr,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = priv->cfg.demod_i2c_addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = buf,
-		}
-	};
-
-	if (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;
-	}
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		memcpy(val, buf, len);
-		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;
-	}
-	return ret;
-}
-
-/* write single register */
-static int tda10071_wr_reg(struct tda10071_priv *priv, u8 reg, u8 val)
-{
-	return tda10071_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int tda10071_rd_reg(struct tda10071_priv *priv, u8 reg, u8 *val)
-{
-	return tda10071_rd_regs(priv, reg, val, 1);
-}
-
+/*
+ * XXX: regmap_update_bits() does not fit our needs as it does not support
+ * partially volatile registers. Also it performs register read even mask is as
+ * wide as register value.
+ */
 /* write single register with mask */
-static int tda10071_wr_reg_mask(struct tda10071_priv *priv,
+static int tda10071_wr_reg_mask(struct tda10071_dev *dev,
 				u8 reg, u8 val, u8 mask)
 {
 	int ret;
@@ -123,7 +36,7 @@ static int tda10071_wr_reg_mask(struct tda10071_priv *priv,
 
 	/* no need for read if whole reg is written */
 	if (mask != 0xff) {
-		ret = tda10071_rd_regs(priv, reg, &tmp, 1);
+		ret = regmap_bulk_read(dev->regmap, reg, &tmp, 1);
 		if (ret)
 			return ret;
 
@@ -132,64 +45,45 @@ static int tda10071_wr_reg_mask(struct tda10071_priv *priv,
 		val |= tmp;
 	}
 
-	return tda10071_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register with mask */
-static int tda10071_rd_reg_mask(struct tda10071_priv *priv,
-				u8 reg, u8 *val, u8 mask)
-{
-	int ret, i;
-	u8 tmp;
-
-	ret = tda10071_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;
+	return regmap_bulk_write(dev->regmap, reg, &val, 1);
 }
 
 /* execute firmware command */
-static int tda10071_cmd_execute(struct tda10071_priv *priv,
+static int tda10071_cmd_execute(struct tda10071_dev *dev,
 	struct tda10071_cmd *cmd)
 {
+	struct i2c_client *client = dev->client;
 	int ret, i;
-	u8 tmp;
+	unsigned int uitmp;
 
-	if (!priv->warm) {
+	if (!dev->warm) {
 		ret = -EFAULT;
 		goto error;
 	}
 
+	mutex_lock(&dev->cmd_execute_mutex);
+
 	/* write cmd and args for firmware */
-	ret = tda10071_wr_regs(priv, 0x00, cmd->args, cmd->len);
+	ret = regmap_bulk_write(dev->regmap, 0x00, cmd->args, cmd->len);
 	if (ret)
-		goto error;
+		goto error_mutex_unlock;
 
 	/* start cmd execution */
-	ret = tda10071_wr_reg(priv, 0x1f, 1);
+	ret = regmap_write(dev->regmap, 0x1f, 1);
 	if (ret)
-		goto error;
+		goto error_mutex_unlock;
 
 	/* wait cmd execution terminate */
-	for (i = 1000, tmp = 1; i && tmp; i--) {
-		ret = tda10071_rd_reg(priv, 0x1f, &tmp);
+	for (i = 1000, uitmp = 1; i && uitmp; i--) {
+		ret = regmap_read(dev->regmap, 0x1f, &uitmp);
 		if (ret)
-			goto error;
+			goto error_mutex_unlock;
 
 		usleep_range(200, 5000);
 	}
 
-	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+	mutex_unlock(&dev->cmd_execute_mutex);
+	dev_dbg(&client->dev, "loop=%d\n", i);
 
 	if (i == 0) {
 		ret = -ETIMEDOUT;
@@ -197,26 +91,28 @@ static int tda10071_cmd_execute(struct tda10071_priv *priv,
 	}
 
 	return ret;
+error_mutex_unlock:
+	mutex_unlock(&dev->cmd_execute_mutex);
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int tda10071_set_tone(struct dvb_frontend *fe,
 	enum fe_sec_tone_mode fe_sec_tone_mode)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct tda10071_cmd cmd;
 	int ret;
 	u8 tone;
 
-	if (!priv->warm) {
+	if (!dev->warm) {
 		ret = -EFAULT;
 		goto error;
 	}
 
-	dev_dbg(&priv->i2c->dev, "%s: tone_mode=%d\n", __func__,
-			fe_sec_tone_mode);
+	dev_dbg(&client->dev, "tone_mode=%d\n", fe_sec_tone_mode);
 
 	switch (fe_sec_tone_mode) {
 	case SEC_TONE_ON:
@@ -226,8 +122,7 @@ static int tda10071_set_tone(struct dvb_frontend *fe,
 		tone = 0;
 		break;
 	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_tone_mode\n",
-				__func__);
+		dev_dbg(&client->dev, "invalid fe_sec_tone_mode\n");
 		ret = -EINVAL;
 		goto error;
 	}
@@ -238,30 +133,31 @@ static int tda10071_set_tone(struct dvb_frontend *fe,
 	cmd.args[3] = 0x00;
 	cmd.args[4] = tone;
 	cmd.len = 5;
-	ret = tda10071_cmd_execute(priv, &cmd);
+	ret = tda10071_cmd_execute(dev, &cmd);
 	if (ret)
 		goto error;
 
 	return ret;
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int tda10071_set_voltage(struct dvb_frontend *fe,
 	enum fe_sec_voltage fe_sec_voltage)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct tda10071_cmd cmd;
 	int ret;
 	u8 voltage;
 
-	if (!priv->warm) {
+	if (!dev->warm) {
 		ret = -EFAULT;
 		goto error;
 	}
 
-	dev_dbg(&priv->i2c->dev, "%s: voltage=%d\n", __func__, fe_sec_voltage);
+	dev_dbg(&client->dev, "voltage=%d\n", fe_sec_voltage);
 
 	switch (fe_sec_voltage) {
 	case SEC_VOLTAGE_13:
@@ -274,8 +170,7 @@ static int tda10071_set_voltage(struct dvb_frontend *fe,
 		voltage = 0;
 		break;
 	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n",
-				__func__);
+		dev_dbg(&client->dev, "invalid fe_sec_voltage\n");
 		ret = -EINVAL;
 		goto error;
 	}
@@ -284,31 +179,31 @@ static int tda10071_set_voltage(struct dvb_frontend *fe,
 	cmd.args[1] = 0;
 	cmd.args[2] = voltage;
 	cmd.len = 3;
-	ret = tda10071_cmd_execute(priv, &cmd);
+	ret = tda10071_cmd_execute(dev, &cmd);
 	if (ret)
 		goto error;
 
 	return ret;
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe,
 	struct dvb_diseqc_master_cmd *diseqc_cmd)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct tda10071_cmd cmd;
 	int ret, i;
-	u8 tmp;
+	unsigned int uitmp;
 
-	if (!priv->warm) {
+	if (!dev->warm) {
 		ret = -EFAULT;
 		goto error;
 	}
 
-	dev_dbg(&priv->i2c->dev, "%s: msg_len=%d\n", __func__,
-			diseqc_cmd->msg_len);
+	dev_dbg(&client->dev, "msg_len=%d\n", diseqc_cmd->msg_len);
 
 	if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) {
 		ret = -EINVAL;
@@ -316,22 +211,22 @@ static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe,
 	}
 
 	/* wait LNB TX */
-	for (i = 500, tmp = 0; i && !tmp; i--) {
-		ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01);
+	for (i = 500, uitmp = 0; i && !uitmp; i--) {
+		ret = regmap_read(dev->regmap, 0x47, &uitmp);
 		if (ret)
 			goto error;
-
+		uitmp = (uitmp >> 0) & 1;
 		usleep_range(10000, 20000);
 	}
 
-	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+	dev_dbg(&client->dev, "loop=%d\n", i);
 
 	if (i == 0) {
 		ret = -ETIMEDOUT;
 		goto error;
 	}
 
-	ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01);
+	ret = regmap_update_bits(dev->regmap, 0x47, 0x01, 0x00);
 	if (ret)
 		goto error;
 
@@ -344,41 +239,42 @@ static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe,
 	cmd.args[6] = diseqc_cmd->msg_len;
 	memcpy(&cmd.args[7], diseqc_cmd->msg, diseqc_cmd->msg_len);
 	cmd.len = 7 + diseqc_cmd->msg_len;
-	ret = tda10071_cmd_execute(priv, &cmd);
+	ret = tda10071_cmd_execute(dev, &cmd);
 	if (ret)
 		goto error;
 
 	return ret;
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
 	struct dvb_diseqc_slave_reply *reply)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct tda10071_cmd cmd;
 	int ret, i;
-	u8 tmp;
+	unsigned int uitmp;
 
-	if (!priv->warm) {
+	if (!dev->warm) {
 		ret = -EFAULT;
 		goto error;
 	}
 
-	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+	dev_dbg(&client->dev, "\n");
 
 	/* wait LNB RX */
-	for (i = 500, tmp = 0; i && !tmp; i--) {
-		ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x02);
+	for (i = 500, uitmp = 0; i && !uitmp; i--) {
+		ret = regmap_read(dev->regmap, 0x47, &uitmp);
 		if (ret)
 			goto error;
-
+		uitmp = (uitmp >> 1) & 1;
 		usleep_range(10000, 20000);
 	}
 
-	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+	dev_dbg(&client->dev, "loop=%d\n", i);
 
 	if (i == 0) {
 		ret = -ETIMEDOUT;
@@ -386,11 +282,11 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
 	}
 
 	/* reply len */
-	ret = tda10071_rd_reg(priv, 0x46, &tmp);
+	ret = regmap_read(dev->regmap, 0x46, &uitmp);
 	if (ret)
 		goto error;
 
-	reply->msg_len = tmp & 0x1f; /* [4:0] */
+	reply->msg_len = uitmp & 0x1f; /* [4:0] */
 	if (reply->msg_len > sizeof(reply->msg))
 		reply->msg_len = sizeof(reply->msg); /* truncate API max */
 
@@ -398,35 +294,37 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
 	cmd.args[0] = CMD_LNB_UPDATE_REPLY;
 	cmd.args[1] = 0;
 	cmd.len = 2;
-	ret = tda10071_cmd_execute(priv, &cmd);
+	ret = tda10071_cmd_execute(dev, &cmd);
 	if (ret)
 		goto error;
 
-	ret = tda10071_rd_regs(priv, cmd.len, reply->msg, reply->msg_len);
+	ret = regmap_bulk_read(dev->regmap, cmd.len, reply->msg,
+			       reply->msg_len);
 	if (ret)
 		goto error;
 
 	return ret;
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
 	enum fe_sec_mini_cmd fe_sec_mini_cmd)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct tda10071_cmd cmd;
 	int ret, i;
-	u8 tmp, burst;
+	unsigned int uitmp;
+	u8 burst;
 
-	if (!priv->warm) {
+	if (!dev->warm) {
 		ret = -EFAULT;
 		goto error;
 	}
 
-	dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__,
-			fe_sec_mini_cmd);
+	dev_dbg(&client->dev, "fe_sec_mini_cmd=%d\n", fe_sec_mini_cmd);
 
 	switch (fe_sec_mini_cmd) {
 	case SEC_MINI_A:
@@ -436,29 +334,28 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
 		burst = 1;
 		break;
 	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_mini_cmd\n",
-				__func__);
+		dev_dbg(&client->dev, "invalid fe_sec_mini_cmd\n");
 		ret = -EINVAL;
 		goto error;
 	}
 
 	/* wait LNB TX */
-	for (i = 500, tmp = 0; i && !tmp; i--) {
-		ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01);
+	for (i = 500, uitmp = 0; i && !uitmp; i--) {
+		ret = regmap_read(dev->regmap, 0x47, &uitmp);
 		if (ret)
 			goto error;
-
+		uitmp = (uitmp >> 0) & 1;
 		usleep_range(10000, 20000);
 	}
 
-	dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+	dev_dbg(&client->dev, "loop=%d\n", i);
 
 	if (i == 0) {
 		ret = -ETIMEDOUT;
 		goto error;
 	}
 
-	ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01);
+	ret = regmap_update_bits(dev->regmap, 0x47, 0x01, 0x00);
 	if (ret)
 		goto error;
 
@@ -466,219 +363,217 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
 	cmd.args[1] = 0;
 	cmd.args[2] = burst;
 	cmd.len = 3;
-	ret = tda10071_cmd_execute(priv, &cmd);
+	ret = tda10071_cmd_execute(dev, &cmd);
 	if (ret)
 		goto error;
 
 	return ret;
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int tda10071_read_status(struct dvb_frontend *fe, enum fe_status *status)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct tda10071_cmd cmd;
 	int ret;
-	u8 tmp;
+	unsigned int uitmp;
+	u8 buf[8];
 
 	*status = 0;
 
-	if (!priv->warm) {
+	if (!dev->warm) {
 		ret = 0;
 		goto error;
 	}
 
-	ret = tda10071_rd_reg(priv, 0x39, &tmp);
+	ret = regmap_read(dev->regmap, 0x39, &uitmp);
 	if (ret)
 		goto error;
 
 	/* 0x39[0] tuner PLL */
-	if (tmp & 0x02) /* demod PLL */
+	if (uitmp & 0x02) /* demod PLL */
 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
-	if (tmp & 0x04) /* viterbi or LDPC*/
+	if (uitmp & 0x04) /* viterbi or LDPC*/
 		*status |= FE_HAS_VITERBI;
-	if (tmp & 0x08) /* RS or BCH */
+	if (uitmp & 0x08) /* RS or BCH */
 		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
 
-	priv->fe_status = *status;
+	dev->fe_status = *status;
 
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
+	/* signal strength */
+	if (dev->fe_status & FE_HAS_SIGNAL) {
+		cmd.args[0] = CMD_GET_AGCACC;
+		cmd.args[1] = 0;
+		cmd.len = 2;
+		ret = tda10071_cmd_execute(dev, &cmd);
+		if (ret)
+			goto error;
 
-static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	int ret;
-	u8 buf[2];
+		/* input power estimate dBm */
+		ret = regmap_read(dev->regmap, 0x50, &uitmp);
+		if (ret)
+			goto error;
 
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
-		*snr = 0;
-		ret = 0;
-		goto error;
+		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+		c->strength.stat[0].svalue = (int) (uitmp - 256) * 1000;
+	} else {
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 	}
 
-	ret = tda10071_rd_regs(priv, 0x3a, buf, 2);
-	if (ret)
-		goto error;
+	/* CNR */
+	if (dev->fe_status & FE_HAS_VITERBI) {
+		/* Es/No */
+		ret = regmap_bulk_read(dev->regmap, 0x3a, buf, 2);
+		if (ret)
+			goto error;
 
-	/* Es/No dBx10 */
-	*snr = buf[0] << 8 | buf[1];
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = (buf[0] << 8 | buf[1] << 0) * 100;
+	} else {
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
 
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
-}
+	/* UCB/PER/BER */
+	if (dev->fe_status & FE_HAS_LOCK) {
+		/* TODO: report total bits/packets */
+		u8 delivery_system, reg, len;
 
-static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret;
-	u8 tmp;
+		switch (dev->delivery_system) {
+		case SYS_DVBS:
+			reg = 0x4c;
+			len = 8;
+			delivery_system = 1;
+			break;
+		case SYS_DVBS2:
+			reg = 0x4d;
+			len = 4;
+			delivery_system = 0;
+			break;
+		default:
+			ret = -EINVAL;
+			goto error;
+		}
 
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
-		*strength = 0;
-		ret = 0;
-		goto error;
-	}
+		ret = regmap_read(dev->regmap, reg, &uitmp);
+		if (ret)
+			goto error;
 
-	cmd.args[0] = CMD_GET_AGCACC;
-	cmd.args[1] = 0;
-	cmd.len = 2;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
+		if (dev->meas_count == uitmp) {
+			dev_dbg(&client->dev, "meas not ready=%02x\n", uitmp);
+			ret = 0;
+			goto error;
+		} else {
+			dev->meas_count = uitmp;
+		}
 
-	/* input power estimate dBm */
-	ret = tda10071_rd_reg(priv, 0x50, &tmp);
-	if (ret)
-		goto error;
+		cmd.args[0] = CMD_BER_UPDATE_COUNTERS;
+		cmd.args[1] = 0;
+		cmd.args[2] = delivery_system;
+		cmd.len = 3;
+		ret = tda10071_cmd_execute(dev, &cmd);
+		if (ret)
+			goto error;
 
-	if (tmp < 181)
-		tmp = 181; /* -75 dBm */
-	else if (tmp > 236)
-		tmp = 236; /* -20 dBm */
+		ret = regmap_bulk_read(dev->regmap, cmd.len, buf, len);
+		if (ret)
+			goto error;
 
-	/* scale value to 0x0000-0xffff */
-	*strength = (tmp-181) * 0xffff / (236-181);
+		if (dev->delivery_system == SYS_DVBS) {
+			dev->dvbv3_ber = buf[0] << 24 | buf[1] << 16 |
+					 buf[2] << 8 | buf[3] << 0;
+			dev->post_bit_error += buf[0] << 24 | buf[1] << 16 |
+					       buf[2] << 8 | buf[3] << 0;
+			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
+			dev->block_error += buf[4] << 8 | buf[5] << 0;
+			c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->block_error.stat[0].uvalue = dev->block_error;
+		} else {
+			dev->dvbv3_ber = buf[0] << 8 | buf[1] << 0;
+			dev->post_bit_error += buf[0] << 8 | buf[1] << 0;
+			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
+			c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		}
+	} else {
+		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
 
 	return ret;
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
-static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
+static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	struct tda10071_cmd cmd;
-	int ret, i, len;
-	u8 tmp, reg, buf[8];
-
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
-		*ber = priv->ber = 0;
-		ret = 0;
-		goto error;
-	}
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-	switch (priv->delivery_system) {
-	case SYS_DVBS:
-		reg = 0x4c;
-		len = 8;
-		i = 1;
-		break;
-	case SYS_DVBS2:
-		reg = 0x4d;
-		len = 4;
-		i = 0;
-		break;
-	default:
-		*ber = priv->ber = 0;
-		return 0;
-	}
+	if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
+		*snr = div_s64(c->cnr.stat[0].svalue, 100);
+	else
+		*snr = 0;
+	return 0;
+}
 
-	ret = tda10071_rd_reg(priv, reg, &tmp);
-	if (ret)
-		goto error;
+static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	unsigned int uitmp;
 
-	if (priv->meas_count[i] == tmp) {
-		dev_dbg(&priv->i2c->dev, "%s: meas not ready=%02x\n", __func__,
-				tmp);
-		*ber = priv->ber;
-		return 0;
+	if (c->strength.stat[0].scale == FE_SCALE_DECIBEL) {
+		uitmp = div_s64(c->strength.stat[0].svalue, 1000) + 256;
+		uitmp = clamp(uitmp, 181U, 236U); /* -75dBm - -20dBm */
+		/* scale value to 0x0000-0xffff */
+		*strength = (uitmp-181) * 0xffff / (236-181);
 	} else {
-		priv->meas_count[i] = tmp;
+		*strength = 0;
 	}
+	return 0;
+}
 
-	cmd.args[0] = CMD_BER_UPDATE_COUNTERS;
-	cmd.args[1] = 0;
-	cmd.args[2] = i;
-	cmd.len = 3;
-	ret = tda10071_cmd_execute(priv, &cmd);
-	if (ret)
-		goto error;
-
-	ret = tda10071_rd_regs(priv, cmd.len, buf, len);
-	if (ret)
-		goto error;
-
-	if (priv->delivery_system == SYS_DVBS) {
-		*ber = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-		priv->ucb += (buf[4] << 8) | buf[5];
-	} else {
-		*ber = (buf[0] << 8) | buf[1];
-	}
-	priv->ber = *ber;
+static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct tda10071_dev *dev = fe->demodulator_priv;
 
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
+	*ber = dev->dvbv3_ber;
+	return 0;
 }
 
 static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	int ret = 0;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
+	if (c->block_error.stat[0].scale == FE_SCALE_COUNTER)
+		*ucblocks = c->block_error.stat[0].uvalue;
+	else
 		*ucblocks = 0;
-		goto error;
-	}
-
-	/* UCB is updated when BER is read. Assume BER is read anyway. */
-
-	*ucblocks = priv->ucb;
-
-	return ret;
-error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-	return ret;
+	return 0;
 }
 
 static int tda10071_set_frontend(struct dvb_frontend *fe)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct tda10071_cmd cmd;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret, i;
 	u8 mode, rolloff, pilot, inversion, div;
 	enum fe_modulation modulation;
 
-	dev_dbg(&priv->i2c->dev,
-			"%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
-			__func__, c->delivery_system, c->modulation,
-			c->frequency, c->symbol_rate, c->inversion, c->pilot,
-			c->rolloff);
+	dev_dbg(&client->dev,
+		"delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
+		c->delivery_system, c->modulation, c->frequency, c->symbol_rate,
+		c->inversion, c->pilot, c->rolloff);
 
-	priv->delivery_system = SYS_UNDEFINED;
+	dev->delivery_system = SYS_UNDEFINED;
 
-	if (!priv->warm) {
+	if (!dev->warm) {
 		ret = -EFAULT;
 		goto error;
 	}
@@ -696,7 +591,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
 		inversion = 3;
 		break;
 	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n", __func__);
+		dev_dbg(&client->dev, "invalid inversion\n");
 		ret = -EINVAL;
 		goto error;
 	}
@@ -722,8 +617,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
 			break;
 		case ROLLOFF_AUTO:
 		default:
-			dev_dbg(&priv->i2c->dev, "%s: invalid rolloff\n",
-					__func__);
+			dev_dbg(&client->dev, "invalid rolloff\n");
 			ret = -EINVAL;
 			goto error;
 		}
@@ -739,15 +633,13 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
 			pilot = 2;
 			break;
 		default:
-			dev_dbg(&priv->i2c->dev, "%s: invalid pilot\n",
-					__func__);
+			dev_dbg(&client->dev, "invalid pilot\n");
 			ret = -EINVAL;
 			goto error;
 		}
 		break;
 	default:
-		dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
-				__func__);
+		dev_dbg(&client->dev, "invalid delivery_system\n");
 		ret = -EINVAL;
 		goto error;
 	}
@@ -757,15 +649,13 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
 			modulation == TDA10071_MODCOD[i].modulation &&
 			c->fec_inner == TDA10071_MODCOD[i].fec) {
 			mode = TDA10071_MODCOD[i].val;
-			dev_dbg(&priv->i2c->dev, "%s: mode found=%02x\n",
-					__func__, mode);
+			dev_dbg(&client->dev, "mode found=%02x\n", mode);
 			break;
 		}
 	}
 
 	if (mode == 0xff) {
-		dev_dbg(&priv->i2c->dev, "%s: invalid parameter combination\n",
-				__func__);
+		dev_dbg(&client->dev, "invalid parameter combination\n");
 		ret = -EINVAL;
 		goto error;
 	}
@@ -775,11 +665,11 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
 	else
 		div = 4;
 
-	ret = tda10071_wr_reg(priv, 0x81, div);
+	ret = regmap_write(dev->regmap, 0x81, div);
 	if (ret)
 		goto error;
 
-	ret = tda10071_wr_reg(priv, 0xe3, div);
+	ret = regmap_write(dev->regmap, 0xe3, div);
 	if (ret)
 		goto error;
 
@@ -799,31 +689,32 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
 	cmd.args[13] = 0x00;
 	cmd.args[14] = 0x00;
 	cmd.len = 15;
-	ret = tda10071_cmd_execute(priv, &cmd);
+	ret = tda10071_cmd_execute(dev, &cmd);
 	if (ret)
 		goto error;
 
-	priv->delivery_system = c->delivery_system;
+	dev->delivery_system = c->delivery_system;
 
 	return ret;
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int tda10071_get_frontend(struct dvb_frontend *fe)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret, i;
 	u8 buf[5], tmp;
 
-	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
-		ret = -EFAULT;
+	if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) {
+		ret = 0;
 		goto error;
 	}
 
-	ret = tda10071_rd_regs(priv, 0x30, buf, 5);
+	ret = regmap_bulk_read(dev->regmap, 0x30, buf, 5);
 	if (ret)
 		goto error;
 
@@ -856,7 +747,7 @@ static int tda10071_get_frontend(struct dvb_frontend *fe)
 
 	c->frequency = (buf[2] << 16) | (buf[3] << 8) | (buf[4] << 0);
 
-	ret = tda10071_rd_regs(priv, 0x52, buf, 3);
+	ret = regmap_bulk_read(dev->regmap, 0x52, buf, 3);
 	if (ret)
 		goto error;
 
@@ -864,15 +755,18 @@ static int tda10071_get_frontend(struct dvb_frontend *fe)
 
 	return ret;
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int tda10071_init(struct dvb_frontend *fe)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct tda10071_cmd cmd;
 	int ret, i, len, remaining, fw_size;
+	unsigned int uitmp;
 	const struct firmware *fw;
 	u8 *fw_file = TDA10071_FIRMWARE;
 	u8 tmp, buf[4];
@@ -890,7 +784,7 @@ static int tda10071_init(struct dvb_frontend *fe)
 	};
 	struct tda10071_reg_val_mask tab2[] = {
 		{ 0xf1, 0x70, 0xff },
-		{ 0x88, priv->cfg.pll_multiplier, 0x3f },
+		{ 0x88, dev->pll_multiplier, 0x3f },
 		{ 0x89, 0x00, 0x10 },
 		{ 0x89, 0x10, 0x10 },
 		{ 0xc0, 0x01, 0x01 },
@@ -934,11 +828,11 @@ static int tda10071_init(struct dvb_frontend *fe)
 		{ 0xd5, 0x03, 0x03 },
 	};
 
-	if (priv->warm) {
+	if (dev->warm) {
 		/* warm state - wake up device from sleep */
 
 		for (i = 0; i < ARRAY_SIZE(tab); i++) {
-			ret = tda10071_wr_reg_mask(priv, tab[i].reg,
+			ret = tda10071_wr_reg_mask(dev, tab[i].reg,
 				tab[i].val, tab[i].mask);
 			if (ret)
 				goto error;
@@ -948,78 +842,76 @@ static int tda10071_init(struct dvb_frontend *fe)
 		cmd.args[1] = 0;
 		cmd.args[2] = 0;
 		cmd.len = 3;
-		ret = tda10071_cmd_execute(priv, &cmd);
+		ret = tda10071_cmd_execute(dev, &cmd);
 		if (ret)
 			goto error;
 	} else {
 		/* cold state - try to download firmware */
 
 		/* request the firmware, this will block and timeout */
-		ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
+		ret = request_firmware(&fw, fw_file, &client->dev);
 		if (ret) {
-			dev_err(&priv->i2c->dev,
-					"%s: did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)\n",
-					KBUILD_MODNAME, fw_file, ret);
+			dev_err(&client->dev,
+				"did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)\n",
+				fw_file, ret);
 			goto error;
 		}
 
 		/* init */
 		for (i = 0; i < ARRAY_SIZE(tab2); i++) {
-			ret = tda10071_wr_reg_mask(priv, tab2[i].reg,
+			ret = tda10071_wr_reg_mask(dev, tab2[i].reg,
 				tab2[i].val, tab2[i].mask);
 			if (ret)
 				goto error_release_firmware;
 		}
 
 		/*  download firmware */
-		ret = tda10071_wr_reg(priv, 0xe0, 0x7f);
+		ret = regmap_write(dev->regmap, 0xe0, 0x7f);
 		if (ret)
 			goto error_release_firmware;
 
-		ret = tda10071_wr_reg(priv, 0xf7, 0x81);
+		ret = regmap_write(dev->regmap, 0xf7, 0x81);
 		if (ret)
 			goto error_release_firmware;
 
-		ret = tda10071_wr_reg(priv, 0xf8, 0x00);
+		ret = regmap_write(dev->regmap, 0xf8, 0x00);
 		if (ret)
 			goto error_release_firmware;
 
-		ret = tda10071_wr_reg(priv, 0xf9, 0x00);
+		ret = regmap_write(dev->regmap, 0xf9, 0x00);
 		if (ret)
 			goto error_release_firmware;
 
-		dev_info(&priv->i2c->dev,
-				"%s: found a '%s' in cold state, will try to load a firmware\n",
-				KBUILD_MODNAME, tda10071_ops.info.name);
-		dev_info(&priv->i2c->dev,
-				"%s: downloading firmware from file '%s'\n",
-				KBUILD_MODNAME, fw_file);
+		dev_info(&client->dev,
+			 "found a '%s' in cold state, will try to load a firmware\n",
+			 tda10071_ops.info.name);
+		dev_info(&client->dev, "downloading firmware from file '%s'\n",
+			 fw_file);
 
 		/* do not download last byte */
 		fw_size = fw->size - 1;
 
 		for (remaining = fw_size; remaining > 0;
-			remaining -= (priv->cfg.i2c_wr_max - 1)) {
+			remaining -= (dev->i2c_wr_max - 1)) {
 			len = remaining;
-			if (len > (priv->cfg.i2c_wr_max - 1))
-				len = (priv->cfg.i2c_wr_max - 1);
+			if (len > (dev->i2c_wr_max - 1))
+				len = (dev->i2c_wr_max - 1);
 
-			ret = tda10071_wr_regs(priv, 0xfa,
+			ret = regmap_bulk_write(dev->regmap, 0xfa,
 				(u8 *) &fw->data[fw_size - remaining], len);
 			if (ret) {
-				dev_err(&priv->i2c->dev,
-						"%s: firmware download failed=%d\n",
-						KBUILD_MODNAME, ret);
+				dev_err(&client->dev,
+					"firmware download failed=%d\n", ret);
 				goto error_release_firmware;
 			}
 		}
 		release_firmware(fw);
 
-		ret = tda10071_wr_reg(priv, 0xf7, 0x0c);
+		ret = regmap_write(dev->regmap, 0xf7, 0x0c);
 		if (ret)
 			goto error;
 
-		ret = tda10071_wr_reg(priv, 0xe0, 0x00);
+		ret = regmap_write(dev->regmap, 0xe0, 0x00);
 		if (ret)
 			goto error;
 
@@ -1027,53 +919,52 @@ static int tda10071_init(struct dvb_frontend *fe)
 		msleep(250);
 
 		/* firmware status */
-		ret = tda10071_rd_reg(priv, 0x51, &tmp);
+		ret = regmap_read(dev->regmap, 0x51, &uitmp);
 		if (ret)
 			goto error;
 
-		if (tmp) {
-			dev_info(&priv->i2c->dev, "%s: firmware did not run\n",
-					KBUILD_MODNAME);
+		if (uitmp) {
+			dev_info(&client->dev, "firmware did not run\n");
 			ret = -EFAULT;
 			goto error;
 		} else {
-			priv->warm = true;
+			dev->warm = true;
 		}
 
 		cmd.args[0] = CMD_GET_FW_VERSION;
 		cmd.len = 1;
-		ret = tda10071_cmd_execute(priv, &cmd);
+		ret = tda10071_cmd_execute(dev, &cmd);
 		if (ret)
 			goto error;
 
-		ret = tda10071_rd_regs(priv, cmd.len, buf, 4);
+		ret = regmap_bulk_read(dev->regmap, cmd.len, buf, 4);
 		if (ret)
 			goto error;
 
-		dev_info(&priv->i2c->dev, "%s: firmware version %d.%d.%d.%d\n",
-				KBUILD_MODNAME, buf[0], buf[1], buf[2], buf[3]);
-		dev_info(&priv->i2c->dev, "%s: found a '%s' in warm state\n",
-				KBUILD_MODNAME, tda10071_ops.info.name);
+		dev_info(&client->dev, "firmware version %d.%d.%d.%d\n",
+			 buf[0], buf[1], buf[2], buf[3]);
+		dev_info(&client->dev, "found a '%s' in warm state\n",
+			 tda10071_ops.info.name);
 
-		ret = tda10071_rd_regs(priv, 0x81, buf, 2);
+		ret = regmap_bulk_read(dev->regmap, 0x81, buf, 2);
 		if (ret)
 			goto error;
 
 		cmd.args[0] = CMD_DEMOD_INIT;
-		cmd.args[1] = ((priv->cfg.xtal / 1000) >> 8) & 0xff;
-		cmd.args[2] = ((priv->cfg.xtal / 1000) >> 0) & 0xff;
+		cmd.args[1] = ((dev->clk / 1000) >> 8) & 0xff;
+		cmd.args[2] = ((dev->clk / 1000) >> 0) & 0xff;
 		cmd.args[3] = buf[0];
 		cmd.args[4] = buf[1];
-		cmd.args[5] = priv->cfg.pll_multiplier;
-		cmd.args[6] = priv->cfg.spec_inv;
+		cmd.args[5] = dev->pll_multiplier;
+		cmd.args[6] = dev->spec_inv;
 		cmd.args[7] = 0x00;
 		cmd.len = 8;
-		ret = tda10071_cmd_execute(priv, &cmd);
+		ret = tda10071_cmd_execute(dev, &cmd);
 		if (ret)
 			goto error;
 
-		if (priv->cfg.tuner_i2c_addr)
-			tmp = priv->cfg.tuner_i2c_addr;
+		if (dev->tuner_i2c_addr)
+			tmp = dev->tuner_i2c_addr;
 		else
 			tmp = 0x14;
 
@@ -1093,22 +984,22 @@ static int tda10071_init(struct dvb_frontend *fe)
 		cmd.args[13] = 0x00;
 		cmd.args[14] = 0x00;
 		cmd.len = 15;
-		ret = tda10071_cmd_execute(priv, &cmd);
+		ret = tda10071_cmd_execute(dev, &cmd);
 		if (ret)
 			goto error;
 
 		cmd.args[0] = CMD_MPEG_CONFIG;
 		cmd.args[1] = 0;
-		cmd.args[2] = priv->cfg.ts_mode;
+		cmd.args[2] = dev->ts_mode;
 		cmd.args[3] = 0x00;
 		cmd.args[4] = 0x04;
 		cmd.args[5] = 0x00;
 		cmd.len = 6;
-		ret = tda10071_cmd_execute(priv, &cmd);
+		ret = tda10071_cmd_execute(dev, &cmd);
 		if (ret)
 			goto error;
 
-		ret = tda10071_wr_reg_mask(priv, 0xf0, 0x01, 0x01);
+		ret = regmap_update_bits(dev->regmap, 0xf0, 0x01, 0x01);
 		if (ret)
 			goto error;
 
@@ -1124,7 +1015,7 @@ static int tda10071_init(struct dvb_frontend *fe)
 		cmd.args[9] = 30;
 		cmd.args[10] = 30;
 		cmd.len = 11;
-		ret = tda10071_cmd_execute(priv, &cmd);
+		ret = tda10071_cmd_execute(dev, &cmd);
 		if (ret)
 			goto error;
 
@@ -1133,22 +1024,33 @@ static int tda10071_init(struct dvb_frontend *fe)
 		cmd.args[2] = 14;
 		cmd.args[3] = 14;
 		cmd.len = 4;
-		ret = tda10071_cmd_execute(priv, &cmd);
+		ret = tda10071_cmd_execute(dev, &cmd);
 		if (ret)
 			goto error;
 	}
 
+	/* 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->block_error.len = 1;
+	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
 	return ret;
 error_release_firmware:
 	release_firmware(fw);
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int tda10071_sleep(struct dvb_frontend *fe)
 {
-	struct tda10071_priv *priv = fe->demodulator_priv;
+	struct tda10071_dev *dev = fe->demodulator_priv;
+	struct i2c_client *client = dev->client;
 	struct tda10071_cmd cmd;
 	int ret, i;
 	struct tda10071_reg_val_mask tab[] = {
@@ -1164,7 +1066,7 @@ static int tda10071_sleep(struct dvb_frontend *fe)
 		{ 0xce, 0x10, 0x10 },
 	};
 
-	if (!priv->warm) {
+	if (!dev->warm) {
 		ret = -EFAULT;
 		goto error;
 	}
@@ -1173,12 +1075,12 @@ static int tda10071_sleep(struct dvb_frontend *fe)
 	cmd.args[1] = 0;
 	cmd.args[2] = 1;
 	cmd.len = 3;
-	ret = tda10071_cmd_execute(priv, &cmd);
+	ret = tda10071_cmd_execute(dev, &cmd);
 	if (ret)
 		goto error;
 
 	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = tda10071_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+		ret = tda10071_wr_reg_mask(dev, tab[i].reg, tab[i].val,
 			tab[i].mask);
 		if (ret)
 			goto error;
@@ -1186,7 +1088,7 @@ static int tda10071_sleep(struct dvb_frontend *fe)
 
 	return ret;
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -1200,71 +1102,6 @@ static int tda10071_get_tune_settings(struct dvb_frontend *fe,
 	return 0;
 }
 
-static void tda10071_release(struct dvb_frontend *fe)
-{
-	struct tda10071_priv *priv = fe->demodulator_priv;
-	kfree(priv);
-}
-
-struct dvb_frontend *tda10071_attach(const struct tda10071_config *config,
-	struct i2c_adapter *i2c)
-{
-	int ret;
-	struct tda10071_priv *priv = NULL;
-	u8 tmp;
-
-	/* allocate memory for the internal priv */
-	priv = kzalloc(sizeof(struct tda10071_priv), GFP_KERNEL);
-	if (priv == NULL) {
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	/* make sure demod i2c address is specified */
-	if (!config->demod_i2c_addr) {
-		dev_dbg(&i2c->dev, "%s: invalid demod i2c address\n", __func__);
-		ret = -EINVAL;
-		goto error;
-	}
-
-	/* make sure tuner i2c address is specified */
-	if (!config->tuner_i2c_addr) {
-		dev_dbg(&i2c->dev, "%s: invalid tuner i2c address\n", __func__);
-		ret = -EINVAL;
-		goto error;
-	}
-
-	/* setup the priv */
-	priv->i2c = i2c;
-	memcpy(&priv->cfg, config, sizeof(struct tda10071_config));
-
-	/* chip ID */
-	ret = tda10071_rd_reg(priv, 0xff, &tmp);
-	if (ret || tmp != 0x0f)
-		goto error;
-
-	/* chip type */
-	ret = tda10071_rd_reg(priv, 0xdd, &tmp);
-	if (ret || tmp != 0x00)
-		goto error;
-
-	/* chip version */
-	ret = tda10071_rd_reg(priv, 0xfe, &tmp);
-	if (ret || tmp != 0x01)
-		goto error;
-
-	/* create dvb_frontend */
-	memcpy(&priv->fe.ops, &tda10071_ops, sizeof(struct dvb_frontend_ops));
-	priv->fe.demodulator_priv = priv;
-
-	return &priv->fe;
-error:
-	dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
-	kfree(priv);
-	return NULL;
-}
-EXPORT_SYMBOL(tda10071_attach);
-
 static struct dvb_frontend_ops tda10071_ops = {
 	.delsys = { SYS_DVBS, SYS_DVBS2 },
 	.info = {
@@ -1289,8 +1126,6 @@ static struct dvb_frontend_ops tda10071_ops = {
 			FE_CAN_2G_MODULATION
 	},
 
-	.release = tda10071_release,
-
 	.get_tune_settings = tda10071_get_tune_settings,
 
 	.init = tda10071_init,
@@ -1315,7 +1150,7 @@ static struct dvb_frontend_ops tda10071_ops = {
 
 static struct dvb_frontend *tda10071_get_dvb_frontend(struct i2c_client *client)
 {
-	struct tda10071_priv *dev = i2c_get_clientdata(client);
+	struct tda10071_dev *dev = i2c_get_clientdata(client);
 
 	dev_dbg(&client->dev, "\n");
 
@@ -1325,10 +1160,14 @@ static struct dvb_frontend *tda10071_get_dvb_frontend(struct i2c_client *client)
 static int tda10071_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
-	struct tda10071_priv *dev;
+	struct tda10071_dev *dev;
 	struct tda10071_platform_data *pdata = client->dev.platform_data;
 	int ret;
-	u8 u8tmp;
+	unsigned int uitmp;
+	static const struct regmap_config regmap_config = {
+		.reg_bits = 8,
+		.val_bits = 8,
+	};
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev) {
@@ -1337,45 +1176,48 @@ static int tda10071_probe(struct i2c_client *client,
 	}
 
 	dev->client = client;
-	dev->i2c = client->adapter;
-	dev->cfg.demod_i2c_addr = client->addr;
-	dev->cfg.i2c_wr_max = pdata->i2c_wr_max;
-	dev->cfg.ts_mode = pdata->ts_mode;
-	dev->cfg.spec_inv = pdata->spec_inv;
-	dev->cfg.xtal = pdata->clk;
-	dev->cfg.pll_multiplier = pdata->pll_multiplier;
-	dev->cfg.tuner_i2c_addr = pdata->tuner_i2c_addr;
+	mutex_init(&dev->cmd_execute_mutex);
+	dev->clk = pdata->clk;
+	dev->i2c_wr_max = pdata->i2c_wr_max;
+	dev->ts_mode = pdata->ts_mode;
+	dev->spec_inv = pdata->spec_inv;
+	dev->pll_multiplier = pdata->pll_multiplier;
+	dev->tuner_i2c_addr = pdata->tuner_i2c_addr;
+	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
+	if (IS_ERR(dev->regmap)) {
+		ret = PTR_ERR(dev->regmap);
+		goto err_kfree;
+	}
 
 	/* chip ID */
-	ret = tda10071_rd_reg(dev, 0xff, &u8tmp);
+	ret = regmap_read(dev->regmap, 0xff, &uitmp);
 	if (ret)
 		goto err_kfree;
-	if (u8tmp != 0x0f) {
+	if (uitmp != 0x0f) {
 		ret = -ENODEV;
 		goto err_kfree;
 	}
 
 	/* chip type */
-	ret = tda10071_rd_reg(dev, 0xdd, &u8tmp);
+	ret = regmap_read(dev->regmap, 0xdd, &uitmp);
 	if (ret)
 		goto err_kfree;
-	if (u8tmp != 0x00) {
+	if (uitmp != 0x00) {
 		ret = -ENODEV;
 		goto err_kfree;
 	}
 
 	/* chip version */
-	ret = tda10071_rd_reg(dev, 0xfe, &u8tmp);
+	ret = regmap_read(dev->regmap, 0xfe, &uitmp);
 	if (ret)
 		goto err_kfree;
-	if (u8tmp != 0x01) {
+	if (uitmp != 0x01) {
 		ret = -ENODEV;
 		goto err_kfree;
 	}
 
 	/* create dvb_frontend */
 	memcpy(&dev->fe.ops, &tda10071_ops, sizeof(struct dvb_frontend_ops));
-	dev->fe.ops.release = NULL;
 	dev->fe.demodulator_priv = dev;
 	i2c_set_clientdata(client, dev);
 
@@ -1409,7 +1251,6 @@ MODULE_DEVICE_TABLE(i2c, tda10071_id_table);
 
 static struct i2c_driver tda10071_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "tda10071",
 		.suppress_bind_attrs = true,
 	},

+ 1 - 62
drivers/media/dvb-frontends/tda10071.h

@@ -21,12 +21,11 @@
 #ifndef TDA10071_H
 #define TDA10071_H
 
-#include <linux/kconfig.h>
 #include <linux/dvb/frontend.h>
 
 /*
  * I2C address
- * 0x55,
+ * 0x05, 0x55,
  */
 
 /**
@@ -53,64 +52,4 @@ struct tda10071_platform_data {
 	struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
 };
 
-struct tda10071_config {
-	/* Demodulator I2C address.
-	 * Default: none, must set
-	 * Values: 0x55,
-	 */
-	u8 demod_i2c_addr;
-
-	/* Tuner I2C address.
-	 * Default: none, must set
-	 * Values: 0x14, 0x54, ...
-	 */
-	u8 tuner_i2c_addr;
-
-	/* Max bytes I2C provider can write at once.
-	 * Note: Buffer is taken from the stack currently!
-	 * Default: none, must set
-	 * Values:
-	 */
-	u16 i2c_wr_max;
-
-	/* TS output mode.
-	 * Default: TDA10071_TS_SERIAL
-	 * Values:
-	 */
-#define TDA10071_TS_SERIAL        0
-#define TDA10071_TS_PARALLEL      1
-	u8 ts_mode;
-
-	/* Input spectrum inversion.
-	 * Default: 0
-	 * Values: 0, 1
-	 */
-	bool spec_inv;
-
-	/* Xtal frequency Hz
-	 * Default: none, must set
-	 * Values:
-	 */
-	u32 xtal;
-
-	/* PLL multiplier.
-	 * Default: none, must set
-	 * Values:
-	 */
-	u8 pll_multiplier;
-};
-
-
-#if IS_REACHABLE(CONFIG_DVB_TDA10071)
-extern struct dvb_frontend *tda10071_attach(
-	const struct tda10071_config *config, struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *tda10071_attach(
-	const struct tda10071_config *config, struct i2c_adapter *i2c)
-{
-	dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
-
 #endif /* TDA10071_H */

+ 14 - 6
drivers/media/dvb-frontends/tda10071_priv.h

@@ -24,19 +24,27 @@
 #include "dvb_frontend.h"
 #include "tda10071.h"
 #include <linux/firmware.h>
+#include <linux/regmap.h>
 
-struct tda10071_priv {
-	struct i2c_adapter *i2c;
+struct tda10071_dev {
 	struct dvb_frontend fe;
 	struct i2c_client *client;
-	struct tda10071_config cfg;
+	struct regmap *regmap;
+	struct mutex cmd_execute_mutex;
+	u32 clk;
+	u16 i2c_wr_max;
+	u8 ts_mode;
+	bool spec_inv;
+	u8 pll_multiplier;
+	u8 tuner_i2c_addr;
 
-	u8 meas_count[2];
-	u32 ber;
-	u32 ucb;
+	u8 meas_count;
+	u32 dvbv3_ber;
 	enum fe_status fe_status;
 	enum fe_delivery_system delivery_system;
 	bool warm; /* FW running */
+	u64 post_bit_error;
+	u64 block_error;
 };
 
 static struct tda10071_modcod {

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

@@ -726,7 +726,6 @@ MODULE_DEVICE_TABLE(i2c, ts2020_id_table);
 
 static struct i2c_driver ts2020_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "ts2020",
 	},
 	.probe		= ts2020_probe,

+ 13 - 2
drivers/media/i2c/Kconfig

@@ -22,7 +22,7 @@ config VIDEO_IR_I2C
 #
 
 menu "Encoders, decoders, sensors and other helper chips"
-	visible if !MEDIA_SUBDRV_AUTOSELECT
+	visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST
 
 comment "Audio decoders, processors and mixers"
 
@@ -196,7 +196,8 @@ config VIDEO_ADV7183
 
 config VIDEO_ADV7604
 	tristate "Analog Devices ADV7604 decoder"
-	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && GPIOLIB
+	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+	depends on GPIOLIB || COMPILE_TEST
 	select HDMI
 	---help---
 	  Support for the Analog Devices ADV7604 video decoder.
@@ -286,6 +287,16 @@ config VIDEO_SAA711X
 	  To compile this driver as a module, choose M here: the
 	  module will be called saa7115.
 
+config VIDEO_TC358743
+	tristate "Toshiba TC358743 decoder"
+	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+	select HDMI
+	---help---
+	  Support for the Toshiba TC358743 HDMI to MIPI CSI-2 bridge.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tc358743.
+
 config VIDEO_TVP514X
 	tristate "Texas Instruments TVP514x video decoder"
 	depends on VIDEO_V4L2 && I2C

+ 1 - 0
drivers/media/i2c/Makefile

@@ -78,3 +78,4 @@ obj-$(CONFIG_VIDEO_AK881X)		+= ak881x.o
 obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_ML86V7667)	+= ml86v7667.o
 obj-$(CONFIG_VIDEO_OV2659)	+= ov2659.o
+obj-$(CONFIG_VIDEO_TC358743)	+= tc358743.o

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

@@ -401,7 +401,6 @@ MODULE_DEVICE_TABLE(i2c, adv7170_id);
 
 static struct i2c_driver adv7170_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "adv7170",
 	},
 	.probe		= adv7170_probe,

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

@@ -455,7 +455,6 @@ MODULE_DEVICE_TABLE(i2c, adv7175_id);
 
 static struct i2c_driver adv7175_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "adv7175",
 	},
 	.probe		= adv7175_probe,

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

@@ -25,6 +25,7 @@
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
@@ -1324,11 +1325,20 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
 #define ADV7180_PM_OPS NULL
 #endif
 
+#ifdef CONFIG_OF
+static const struct of_device_id adv7180_of_id[] = {
+	{ .compatible = "adi,adv7180", },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, adv7180_of_id);
+#endif
+
 static struct i2c_driver adv7180_driver = {
 	.driver = {
-		   .owner = THIS_MODULE,
 		   .name = KBUILD_MODNAME,
 		   .pm = ADV7180_PM_OPS,
+		   .of_match_table = of_match_ptr(adv7180_of_id),
 		   },
 	.probe = adv7180_probe,
 	.remove = adv7180_remove,

+ 0 - 8
drivers/media/i2c/adv7343.c

@@ -319,13 +319,6 @@ static const struct v4l2_ctrl_ops adv7343_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops adv7343_core_ops = {
 	.log_status = adv7343_log_status,
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
 };
 
 static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
@@ -529,7 +522,6 @@ MODULE_DEVICE_TABLE(of, adv7343_of_match);
 static struct i2c_driver adv7343_driver = {
 	.driver = {
 		.of_match_table = of_match_ptr(adv7343_of_match),
-		.owner	= THIS_MODULE,
 		.name	= "adv7343",
 	},
 	.probe		= adv7343_probe,

+ 0 - 7
drivers/media/i2c/adv7393.c

@@ -306,13 +306,6 @@ static const struct v4l2_ctrl_ops adv7393_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops adv7393_core_ops = {
 	.log_status = adv7393_log_status,
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
 };
 
 static int adv7393_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)

+ 1 - 2
drivers/media/i2c/adv7511.c

@@ -40,7 +40,7 @@ MODULE_PARM_DESC(debug, "debug level (0-2)");
 
 MODULE_DESCRIPTION("Analog Devices ADV7511 HDMI Transmitter Device Driver");
 MODULE_AUTHOR("Hans Verkuil");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 
 #define MASK_ADV7511_EDID_RDY_INT   0x04
 #define MASK_ADV7511_MSEN_INT       0x40
@@ -1576,7 +1576,6 @@ MODULE_DEVICE_TABLE(i2c, adv7511_id);
 
 static struct i2c_driver adv7511_driver = {
 	.driver = {
-		.owner = THIS_MODULE,
 		.name = "adv7511",
 	},
 	.probe = adv7511_probe,

+ 381 - 105
drivers/media/i2c/adv7604.c

@@ -37,10 +37,12 @@
 #include <linux/v4l2-dv-timings.h>
 #include <linux/videodev2.h>
 #include <linux/workqueue.h>
+#include <linux/regmap.h>
 
 #include <media/adv7604.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-dv-timings.h>
 #include <media/v4l2-of.h>
 
@@ -81,6 +83,7 @@ MODULE_LICENSE("GPL");
 enum adv76xx_type {
 	ADV7604,
 	ADV7611,
+	ADV7612,
 };
 
 struct adv76xx_reg_seq {
@@ -188,6 +191,9 @@ struct adv76xx_state {
 	/* i2c clients */
 	struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX];
 
+	/* Regmaps */
+	struct regmap *regmap[ADV76XX_PAGE_MAX];
+
 	/* controls */
 	struct v4l2_ctrl *detect_tx_5v_ctrl;
 	struct v4l2_ctrl *analog_sampling_phase_ctrl;
@@ -373,66 +379,39 @@ static inline unsigned vtotal(const struct v4l2_bt_timings *t)
 
 /* ----------------------------------------------------------------------- */
 
-static s32 adv_smbus_read_byte_data_check(struct i2c_client *client,
-		u8 command, bool check)
-{
-	union i2c_smbus_data data;
-
-	if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags,
-			I2C_SMBUS_READ, command,
-			I2C_SMBUS_BYTE_DATA, &data))
-		return data.byte;
-	if (check)
-		v4l_err(client, "error reading %02x, %02x\n",
-				client->addr, command);
-	return -EIO;
-}
-
-static s32 adv_smbus_read_byte_data(struct adv76xx_state *state,
-				    enum adv76xx_page page, u8 command)
+static int adv76xx_read_check(struct adv76xx_state *state,
+			     int client_page, u8 reg)
 {
-	return adv_smbus_read_byte_data_check(state->i2c_clients[page],
-					      command, true);
-}
-
-static s32 adv_smbus_write_byte_data(struct adv76xx_state *state,
-				     enum adv76xx_page page, u8 command,
-				     u8 value)
-{
-	struct i2c_client *client = state->i2c_clients[page];
-	union i2c_smbus_data data;
+	struct i2c_client *client = state->i2c_clients[client_page];
 	int err;
-	int i;
+	unsigned int val;
 
-	data.byte = value;
-	for (i = 0; i < 3; i++) {
-		err = i2c_smbus_xfer(client->adapter, client->addr,
-				client->flags,
-				I2C_SMBUS_WRITE, command,
-				I2C_SMBUS_BYTE_DATA, &data);
-		if (!err)
-			break;
+	err = regmap_read(state->regmap[client_page], reg, &val);
+
+	if (err) {
+		v4l_err(client, "error reading %02x, %02x\n",
+				client->addr, reg);
+		return err;
 	}
-	if (err < 0)
-		v4l_err(client, "error writing %02x, %02x, %02x\n",
-				client->addr, command, value);
-	return err;
+	return val;
 }
 
-static s32 adv_smbus_write_i2c_block_data(struct adv76xx_state *state,
-					  enum adv76xx_page page, u8 command,
-					  unsigned length, const u8 *values)
+/* adv76xx_write_block(): Write raw data with a maximum of I2C_SMBUS_BLOCK_MAX
+ * size to one or more registers.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int adv76xx_write_block(struct adv76xx_state *state, int client_page,
+			      unsigned int init_reg, const void *val,
+			      size_t val_len)
 {
-	struct i2c_client *client = state->i2c_clients[page];
-	union i2c_smbus_data data;
+	struct regmap *regmap = state->regmap[client_page];
+
+	if (val_len > I2C_SMBUS_BLOCK_MAX)
+		val_len = I2C_SMBUS_BLOCK_MAX;
 
-	if (length > I2C_SMBUS_BLOCK_MAX)
-		length = I2C_SMBUS_BLOCK_MAX;
-	data.block[0] = length;
-	memcpy(data.block + 1, values, length);
-	return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
-			      I2C_SMBUS_WRITE, command,
-			      I2C_SMBUS_I2C_BLOCK_DATA, &data);
+	return regmap_raw_write(regmap, init_reg, val, val_len);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -441,14 +420,14 @@ static inline int io_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV76XX_PAGE_IO, reg);
+	return adv76xx_read_check(state, ADV76XX_PAGE_IO, reg);
 }
 
 static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_IO, reg, val);
+	return regmap_write(state->regmap[ADV76XX_PAGE_IO], reg, val);
 }
 
 static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
@@ -460,71 +439,70 @@ static inline int avlink_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV7604_PAGE_AVLINK, reg);
+	return adv76xx_read_check(state, ADV7604_PAGE_AVLINK, reg);
 }
 
 static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV7604_PAGE_AVLINK, reg, val);
+	return regmap_write(state->regmap[ADV7604_PAGE_AVLINK], reg, val);
 }
 
 static inline int cec_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CEC, reg);
+	return adv76xx_read_check(state, ADV76XX_PAGE_CEC, reg);
 }
 
 static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CEC, reg, val);
+	return regmap_write(state->regmap[ADV76XX_PAGE_CEC], reg, val);
 }
 
 static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV76XX_PAGE_INFOFRAME, reg);
+	return adv76xx_read_check(state, ADV76XX_PAGE_INFOFRAME, reg);
 }
 
 static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_INFOFRAME,
-					 reg, val);
+	return regmap_write(state->regmap[ADV76XX_PAGE_INFOFRAME], reg, val);
 }
 
 static inline int afe_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV76XX_PAGE_AFE, reg);
+	return adv76xx_read_check(state, ADV76XX_PAGE_AFE, reg);
 }
 
 static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_AFE, reg, val);
+	return regmap_write(state->regmap[ADV76XX_PAGE_AFE], reg, val);
 }
 
 static inline int rep_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV76XX_PAGE_REP, reg);
+	return adv76xx_read_check(state, ADV76XX_PAGE_REP, reg);
 }
 
 static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_REP, reg, val);
+	return regmap_write(state->regmap[ADV76XX_PAGE_REP], reg, val);
 }
 
 static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
@@ -536,28 +514,37 @@ static inline int edid_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV76XX_PAGE_EDID, reg);
+	return adv76xx_read_check(state, ADV76XX_PAGE_EDID, reg);
 }
 
 static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_EDID, reg, val);
+	return regmap_write(state->regmap[ADV76XX_PAGE_EDID], reg, val);
 }
 
 static inline int edid_write_block(struct v4l2_subdev *sd,
-					unsigned len, const u8 *val)
+					unsigned int total_len, const u8 *val)
 {
 	struct adv76xx_state *state = to_state(sd);
 	int err = 0;
-	int i;
+	int i = 0;
+	int len = 0;
+
+	v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n",
+				__func__, total_len);
 
-	v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len);
+	while (!err && i < total_len) {
+		len = (total_len - i) > I2C_SMBUS_BLOCK_MAX ?
+				I2C_SMBUS_BLOCK_MAX :
+				(total_len - i);
+
+		err = adv76xx_write_block(state, ADV76XX_PAGE_EDID,
+				i, val + i, len);
+		i += len;
+	}
 
-	for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX)
-		err = adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_EDID,
-				i, I2C_SMBUS_BLOCK_MAX, val + i);
 	return err;
 }
 
@@ -587,7 +574,7 @@ static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV76XX_PAGE_HDMI, reg);
+	return adv76xx_read_check(state, ADV76XX_PAGE_HDMI, reg);
 }
 
 static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask)
@@ -599,7 +586,7 @@ static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_HDMI, reg, val);
+	return regmap_write(state->regmap[ADV76XX_PAGE_HDMI], reg, val);
 }
 
 static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
@@ -611,14 +598,14 @@ static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_TEST, reg, val);
+	return regmap_write(state->regmap[ADV76XX_PAGE_TEST], reg, val);
 }
 
 static inline int cp_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CP, reg);
+	return adv76xx_read_check(state, ADV76XX_PAGE_CP, reg);
 }
 
 static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask)
@@ -630,7 +617,7 @@ static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CP, reg, val);
+	return regmap_write(state->regmap[ADV76XX_PAGE_CP], reg, val);
 }
 
 static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
@@ -642,14 +629,14 @@ static inline int vdp_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_read_byte_data(state, ADV7604_PAGE_VDP, reg);
+	return adv76xx_read_check(state, ADV7604_PAGE_VDP, reg);
 }
 
 static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
 	struct adv76xx_state *state = to_state(sd);
 
-	return adv_smbus_write_byte_data(state, ADV7604_PAGE_VDP, reg, val);
+	return regmap_write(state->regmap[ADV7604_PAGE_VDP], reg, val);
 }
 
 #define ADV76XX_REG(page, offset)	(((page) << 8) | (offset))
@@ -660,13 +647,16 @@ static int adv76xx_read_reg(struct v4l2_subdev *sd, unsigned int reg)
 {
 	struct adv76xx_state *state = to_state(sd);
 	unsigned int page = reg >> 8;
+	unsigned int val;
+	int err;
 
 	if (!(BIT(page) & state->info->page_mask))
 		return -EINVAL;
 
 	reg &= 0xff;
+	err = regmap_read(state->regmap[page], reg, &val);
 
-	return adv_smbus_read_byte_data(state, page, reg);
+	return err ? err : val;
 }
 #endif
 
@@ -680,7 +670,7 @@ static int adv76xx_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val)
 
 	reg &= 0xff;
 
-	return adv_smbus_write_byte_data(state, page, reg, val);
+	return regmap_write(state->regmap[page], reg, val);
 }
 
 static void adv76xx_write_reg_seq(struct v4l2_subdev *sd,
@@ -766,6 +756,23 @@ static const struct adv76xx_format_info adv7611_formats[] = {
 	  ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT },
 };
 
+static const struct adv76xx_format_info adv7612_formats[] = {
+	{ MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false,
+	  ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false,
+	  ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true,
+	  ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT },
+	{ MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false,
+	  ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+	{ MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true,
+	  ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+	{ MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false,
+	  ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+	{ MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true,
+	  ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT },
+};
+
 static const struct adv76xx_format_info *
 adv76xx_format_info(struct adv76xx_state *state, u32 code)
 {
@@ -870,6 +877,16 @@ static unsigned int adv7611_read_cable_det(struct v4l2_subdev *sd)
 	return value & 1;
 }
 
+static unsigned int adv7612_read_cable_det(struct v4l2_subdev *sd)
+{
+	/*  Reads CABLE_DET_A_RAW. For input B support, need to
+	 *  account for bit 7 [MSB] of 0x6a (ie. CABLE_DET_B_RAW)
+	 */
+	u8 value = io_read(sd, 0x6f);
+
+	return value & 1;
+}
+
 static int adv76xx_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)
 {
 	struct adv76xx_state *state = to_state(sd);
@@ -976,8 +993,8 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
 		/* Should only be set in auto-graphics mode [REF_02, p. 91-92] */
 		/* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */
 		/* IO-map reg. 0x16 and 0x17 should be written in sequence */
-		if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_IO,
-						   0x16, 2, pll))
+		if (regmap_raw_write(state->regmap[ADV76XX_PAGE_IO],
+					0x16, pll, 2))
 			v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n");
 
 		/* active video - horizontal timing */
@@ -1028,8 +1045,8 @@ static void adv76xx_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off
 	offset_buf[3] = offset_c & 0x0ff;
 
 	/* Registers must be written in this order with no i2c access in between */
-	if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP,
-					   0x77, 4, offset_buf))
+	if (regmap_raw_write(state->regmap[ADV76XX_PAGE_CP],
+			0x77, offset_buf, 4))
 		v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__);
 }
 
@@ -1058,8 +1075,8 @@ static void adv76xx_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a,
 	gain_buf[3] = ((gain_c & 0x0ff));
 
 	/* Registers must be written in this order with no i2c access in between */
-	if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP,
-					   0x73, 4, gain_buf))
+	if (regmap_raw_write(state->regmap[ADV76XX_PAGE_CP],
+			     0x73, gain_buf, 4))
 		v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__);
 }
 
@@ -1328,7 +1345,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
 		}
 	}
 
-	if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs,
+	if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0,
 			(stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
 			(stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
 			false, timings))
@@ -1760,8 +1777,8 @@ static int adv76xx_s_routing(struct v4l2_subdev *sd,
 	select_input(sd);
 	enable_input(sd);
 
-	v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT,
-			   (void *)&adv76xx_ev_fmt);
+	v4l2_subdev_notify_event(sd, &adv76xx_ev_fmt);
+
 	return 0;
 }
 
@@ -1928,8 +1945,7 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 			"%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n",
 			__func__, fmt_change, fmt_change_digital);
 
-		v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT,
-				   (void *)&adv76xx_ev_fmt);
+		v4l2_subdev_notify_event(sd, &adv76xx_ev_fmt);
 
 		if (handled)
 			*handled = true;
@@ -2347,6 +2363,20 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
 	return 0;
 }
 
+static int adv76xx_subscribe_event(struct v4l2_subdev *sd,
+				   struct v4l2_fh *fh,
+				   struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
+	default:
+		return -EINVAL;
+	}
+}
+
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = {
@@ -2356,6 +2386,8 @@ static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = {
 static const struct v4l2_subdev_core_ops adv76xx_core_ops = {
 	.log_status = adv76xx_log_status,
 	.interrupt_service_routine = adv76xx_isr,
+	.subscribe_event = adv76xx_subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.g_register = adv76xx_g_register,
 	.s_register = adv76xx_s_register,
@@ -2510,6 +2542,11 @@ static void adv7611_setup_irqs(struct v4l2_subdev *sd)
 	io_write(sd, 0x41, 0xd0); /* STDI irq for any change, disable INT2 */
 }
 
+static void adv7612_setup_irqs(struct v4l2_subdev *sd)
+{
+	io_write(sd, 0x41, 0xd0); /* disable INT2 */
+}
+
 static void adv76xx_unregister_clients(struct adv76xx_state *state)
 {
 	unsigned int i;
@@ -2597,6 +2634,19 @@ static const struct adv76xx_reg_seq adv7611_recommended_settings_hdmi[] = {
 	{ ADV76XX_REG_SEQ_TERM, 0 },
 };
 
+static const struct adv76xx_reg_seq adv7612_recommended_settings_hdmi[] = {
+	{ ADV76XX_REG(ADV76XX_PAGE_CP, 0x6c), 0x00 },
+	{ ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x9b), 0x03 },
+	{ ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x6f), 0x08 },
+	{ ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x85), 0x1f },
+	{ ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x87), 0x70 },
+	{ ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xda },
+	{ ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x01 },
+	{ ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x03), 0x98 },
+	{ ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4c), 0x44 },
+	{ ADV76XX_REG_SEQ_TERM, 0 },
+};
+
 static const struct adv76xx_chip_info adv76xx_chip_info[] = {
 	[ADV7604] = {
 		.type = ADV7604,
@@ -2685,17 +2735,60 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = {
 		.field1_vsync_mask = 0x3fff,
 		.field1_vbackporch_mask = 0x3fff,
 	},
+	[ADV7612] = {
+		.type = ADV7612,
+		.has_afe = false,
+		.max_port = ADV76XX_PAD_HDMI_PORT_A,	/* B not supported */
+		.num_dv_ports = 1,			/* normally 2 */
+		.edid_enable_reg = 0x74,
+		.edid_status_reg = 0x76,
+		.lcf_reg = 0xa3,
+		.tdms_lock_mask = 0x43,
+		.cable_det_mask = 0x01,
+		.fmt_change_digital_mask = 0x03,
+		.cp_csc = 0xf4,
+		.formats = adv7612_formats,
+		.nformats = ARRAY_SIZE(adv7612_formats),
+		.set_termination = adv7611_set_termination,
+		.setup_irqs = adv7612_setup_irqs,
+		.read_hdmi_pixelclock = adv7611_read_hdmi_pixelclock,
+		.read_cable_det = adv7612_read_cable_det,
+		.recommended_settings = {
+		    [1] = adv7612_recommended_settings_hdmi,
+		},
+		.num_recommended_settings = {
+		    [1] = ARRAY_SIZE(adv7612_recommended_settings_hdmi),
+		},
+		.page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV76XX_PAGE_CEC) |
+			BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV76XX_PAGE_AFE) |
+			BIT(ADV76XX_PAGE_REP) |  BIT(ADV76XX_PAGE_EDID) |
+			BIT(ADV76XX_PAGE_HDMI) | BIT(ADV76XX_PAGE_CP),
+		.linewidth_mask = 0x1fff,
+		.field0_height_mask = 0x1fff,
+		.field1_height_mask = 0x1fff,
+		.hfrontporch_mask = 0x1fff,
+		.hsync_mask = 0x1fff,
+		.hbackporch_mask = 0x1fff,
+		.field0_vfrontporch_mask = 0x3fff,
+		.field0_vsync_mask = 0x3fff,
+		.field0_vbackporch_mask = 0x3fff,
+		.field1_vfrontporch_mask = 0x3fff,
+		.field1_vsync_mask = 0x3fff,
+		.field1_vbackporch_mask = 0x3fff,
+	},
 };
 
 static const struct i2c_device_id adv76xx_i2c_id[] = {
 	{ "adv7604", (kernel_ulong_t)&adv76xx_chip_info[ADV7604] },
 	{ "adv7611", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] },
+	{ "adv7612", (kernel_ulong_t)&adv76xx_chip_info[ADV7612] },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adv76xx_i2c_id);
 
 static const struct of_device_id adv76xx_of_id[] __maybe_unused = {
 	{ .compatible = "adi,adv7611", .data = &adv76xx_chip_info[ADV7611] },
+	{ .compatible = "adi,adv7612", .data = &adv76xx_chip_info[ADV7612] },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, adv76xx_of_id);
@@ -2706,6 +2799,7 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
 	struct device_node *endpoint;
 	struct device_node *np;
 	unsigned int flags;
+	u32 v;
 
 	np = state->i2c_clients[ADV76XX_PAGE_IO]->dev.of_node;
 
@@ -2715,6 +2809,12 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
 		return -EINVAL;
 
 	v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+
+	if (!of_property_read_u32(endpoint, "default-input", &v))
+		state->pdata.default_input = v;
+	else
+		state->pdata.default_input = -1;
+
 	of_node_put(endpoint);
 
 	flags = bus_cfg.bus.parallel.flags;
@@ -2753,7 +2853,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
 	/* Hardcode the remaining platform data fields. */
 	state->pdata.disable_pwrdnb = 0;
 	state->pdata.disable_cable_det_rst = 0;
-	state->pdata.default_input = -1;
 	state->pdata.blank_data = 1;
 	state->pdata.alt_data_sat = 1;
 	state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0;
@@ -2762,6 +2861,148 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
 	return 0;
 }
 
+static const struct regmap_config adv76xx_regmap_cnf[] = {
+	{
+		.name			= "io",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "avlink",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "cec",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "infoframe",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "esdp",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "epp",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "afe",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "rep",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "edid",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+
+	{
+		.name			= "hdmi",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "test",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "cp",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+	{
+		.name			= "vdp",
+		.reg_bits		= 8,
+		.val_bits		= 8,
+
+		.max_register		= 0xff,
+		.cache_type		= REGCACHE_NONE,
+	},
+};
+
+static int configure_regmap(struct adv76xx_state *state, int region)
+{
+	int err;
+
+	if (!state->i2c_clients[region])
+		return -ENODEV;
+
+	state->regmap[region] =
+		devm_regmap_init_i2c(state->i2c_clients[region],
+				     &adv76xx_regmap_cnf[region]);
+
+	if (IS_ERR(state->regmap[region])) {
+		err = PTR_ERR(state->regmap[region]);
+		v4l_err(state->i2c_clients[region],
+			"Error initializing regmap %d with error %d\n",
+			region, err);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int configure_regmaps(struct adv76xx_state *state)
+{
+	int i, err;
+
+	for (i = ADV7604_PAGE_AVLINK ; i < ADV76XX_PAGE_MAX; i++) {
+		err = configure_regmap(state, i);
+		if (err && (err != -ENODEV))
+			return err;
+	}
+	return 0;
+}
+
 static int adv76xx_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
@@ -2771,7 +3012,7 @@ static int adv76xx_probe(struct i2c_client *client,
 	struct v4l2_ctrl_handler *hdl;
 	struct v4l2_subdev *sd;
 	unsigned int i;
-	u16 val;
+	unsigned int val, val2;
 	int err;
 
 	/* Check if the adapter supports the needed features */
@@ -2833,28 +3074,59 @@ static int adv76xx_probe(struct i2c_client *client,
 	snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
 		id->name, i2c_adapter_id(client->adapter),
 		client->addr);
-	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+
+	/* Configure IO Regmap region */
+	err = configure_regmap(state, ADV76XX_PAGE_IO);
+
+	if (err) {
+		v4l2_err(sd, "Error configuring IO regmap region\n");
+		return -ENODEV;
+	}
 
 	/*
 	 * Verify that the chip is present. On ADV7604 the RD_INFO register only
 	 * identifies the revision, while on ADV7611 it identifies the model as
 	 * well. Use the HDMI slave address on ADV7604 and RD_INFO on ADV7611.
 	 */
-	if (state->info->type == ADV7604) {
-		val = adv_smbus_read_byte_data_check(client, 0xfb, false);
+	switch (state->info->type) {
+	case ADV7604:
+		err = regmap_read(state->regmap[ADV76XX_PAGE_IO], 0xfb, &val);
+		if (err) {
+			v4l2_err(sd, "Error %d reading IO Regmap\n", err);
+			return -ENODEV;
+		}
 		if (val != 0x68) {
-			v4l2_info(sd, "not an adv7604 on address 0x%x\n",
+			v4l2_err(sd, "not an adv7604 on address 0x%x\n",
 					client->addr << 1);
 			return -ENODEV;
 		}
-	} else {
-		val = (adv_smbus_read_byte_data_check(client, 0xea, false) << 8)
-		    | (adv_smbus_read_byte_data_check(client, 0xeb, false) << 0);
-		if (val != 0x2051) {
-			v4l2_info(sd, "not an adv7611 on address 0x%x\n",
+		break;
+	case ADV7611:
+	case ADV7612:
+		err = regmap_read(state->regmap[ADV76XX_PAGE_IO],
+				0xea,
+				&val);
+		if (err) {
+			v4l2_err(sd, "Error %d reading IO Regmap\n", err);
+			return -ENODEV;
+		}
+		val2 = val << 8;
+		err = regmap_read(state->regmap[ADV76XX_PAGE_IO],
+			    0xeb,
+			    &val);
+		if (err) {
+			v4l2_err(sd, "Error %d reading IO Regmap\n", err);
+			return -ENODEV;
+		}
+		val |= val2;
+		if ((state->info->type == ADV7611 && val != 0x2051) ||
+			(state->info->type == ADV7612 && val != 0x2041)) {
+			v4l2_err(sd, "not an adv761x on address 0x%x\n",
 					client->addr << 1);
 			return -ENODEV;
 		}
+		break;
 	}
 
 	/* control handlers */
@@ -2941,6 +3213,11 @@ static int adv76xx_probe(struct i2c_client *client,
 	if (err)
 		goto err_work_queues;
 
+	/* Configure regmaps */
+	err = configure_regmaps(state);
+	if (err)
+		goto err_entity;
+
 	err = adv76xx_core_init(sd);
 	if (err)
 		goto err_entity;
@@ -2985,7 +3262,6 @@ static int adv76xx_remove(struct i2c_client *client)
 
 static struct i2c_driver adv76xx_driver = {
 	.driver = {
-		.owner = THIS_MODULE,
 		.name = "adv7604",
 		.of_match_table = of_match_ptr(adv76xx_of_id),
 	},

+ 21 - 7
drivers/media/i2c/adv7842.c

@@ -40,6 +40,7 @@
 #include <linux/v4l2-dv-timings.h>
 #include <linux/hdmi.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-dv-timings.h>
 #include <media/adv7842.h>
@@ -1442,7 +1443,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
 		}
 	}
 
-	if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs,
+	if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0,
 			(stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
 			(stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
 			false, timings))
@@ -1980,8 +1981,7 @@ static int adv7842_s_routing(struct v4l2_subdev *sd,
 	select_input(sd, state->vid_std_select);
 	enable_input(sd);
 
-	v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT,
-			   (void *)&adv7842_ev_fmt);
+	v4l2_subdev_notify_event(sd, &adv7842_ev_fmt);
 
 	return 0;
 }
@@ -2214,8 +2214,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 			 "%s: fmt_change_cp = 0x%x, fmt_change_digital = 0x%x, fmt_change_sdp = 0x%x\n",
 			 __func__, fmt_change_cp, fmt_change_digital,
 			 fmt_change_sdp);
-		v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT,
-				   (void *)&adv7842_ev_fmt);
+		v4l2_subdev_notify_event(sd, &adv7842_ev_fmt);
 		if (handled)
 			*handled = true;
 	}
@@ -3005,6 +3004,20 @@ static long adv7842_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 	return -ENOTTY;
 }
 
+static int adv7842_subscribe_event(struct v4l2_subdev *sd,
+				   struct v4l2_fh *fh,
+				   struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
+	default:
+		return -EINVAL;
+	}
+}
+
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops adv7842_ctrl_ops = {
@@ -3015,6 +3028,8 @@ static const struct v4l2_subdev_core_ops adv7842_core_ops = {
 	.log_status = adv7842_log_status,
 	.ioctl = adv7842_ioctl,
 	.interrupt_service_routine = adv7842_isr,
+	.subscribe_event = adv7842_subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.g_register = adv7842_g_register,
 	.s_register = adv7842_s_register,
@@ -3210,7 +3225,7 @@ static int adv7842_probe(struct i2c_client *client,
 
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &adv7842_ops);
-	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 	state->mode = pdata->mode;
 
 	state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A;
@@ -3348,7 +3363,6 @@ MODULE_DEVICE_TABLE(i2c, adv7842_id);
 
 static struct i2c_driver adv7842_driver = {
 	.driver = {
-		.owner = THIS_MODULE,
 		.name = "adv7842",
 	},
 	.probe = adv7842_probe,

+ 4 - 4
drivers/media/i2c/ak881x.c

@@ -156,12 +156,12 @@ static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
 	} else if (std == V4L2_STD_PAL_60) {
 		vp1 = 7;
 		ak881x->lines = 480;
-	} else if (std && !(std & ~V4L2_STD_PAL)) {
-		vp1 = 0xf;
-		ak881x->lines = 576;
-	} else if (std && !(std & ~V4L2_STD_NTSC)) {
+	} else if (std & V4L2_STD_NTSC) {
 		vp1 = 0;
 		ak881x->lines = 480;
+	} else if (std & V4L2_STD_PAL) {
+		vp1 = 0xf;
+		ak881x->lines = 576;
 	} else {
 		/* No SECAM or PAL_N/Nc supported */
 		return -EINVAL;

+ 0 - 12
drivers/media/i2c/bt819.c

@@ -379,16 +379,6 @@ static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
 	.s_ctrl = bt819_s_ctrl,
 };
 
-static const struct v4l2_subdev_core_ops bt819_core_ops = {
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
-};
-
 static const struct v4l2_subdev_video_ops bt819_video_ops = {
 	.s_std = bt819_s_std,
 	.s_routing = bt819_s_routing,
@@ -398,7 +388,6 @@ static const struct v4l2_subdev_video_ops bt819_video_ops = {
 };
 
 static const struct v4l2_subdev_ops bt819_ops = {
-	.core = &bt819_core_ops,
 	.video = &bt819_video_ops,
 };
 
@@ -492,7 +481,6 @@ MODULE_DEVICE_TABLE(i2c, bt819_id);
 
 static struct i2c_driver bt819_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "bt819",
 	},
 	.probe		= bt819_probe,

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

@@ -252,7 +252,6 @@ MODULE_DEVICE_TABLE(i2c, bt856_id);
 
 static struct i2c_driver bt856_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "bt856",
 	},
 	.probe		= bt856_probe,

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

@@ -218,7 +218,6 @@ MODULE_DEVICE_TABLE(i2c, bt866_id);
 
 static struct i2c_driver bt866_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "bt866",
 	},
 	.probe		= bt866_probe,

+ 0 - 8
drivers/media/i2c/cs5345.c

@@ -132,13 +132,6 @@ static const struct v4l2_ctrl_ops cs5345_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops cs5345_core_ops = {
 	.log_status = cs5345_log_status,
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.g_register = cs5345_g_register,
 	.s_register = cs5345_s_register,
@@ -218,7 +211,6 @@ MODULE_DEVICE_TABLE(i2c, cs5345_id);
 
 static struct i2c_driver cs5345_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "cs5345",
 	},
 	.probe		= cs5345_probe,

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

@@ -228,7 +228,6 @@ MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
 
 static struct i2c_driver cs53l32a_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "cs53l32a",
 	},
 	.probe		= cs53l32a_probe,

+ 0 - 1
drivers/media/i2c/cx25840/cx25840-core.c

@@ -5348,7 +5348,6 @@ MODULE_DEVICE_TABLE(i2c, cx25840_id);
 
 static struct i2c_driver cx25840_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "cx25840",
 	},
 	.probe		= cx25840_probe,

+ 1 - 0
drivers/media/i2c/ir-kbd-i2c.c

@@ -478,6 +478,7 @@ static const struct i2c_device_id ir_kbd_id[] = {
 	{ "ir_rx_z8f0811_hdpvr", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c, ir_kbd_id);
 
 static struct i2c_driver ir_kbd_driver = {
 	.driver = {

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

@@ -708,7 +708,6 @@ MODULE_DEVICE_TABLE(i2c, ks0127_id);
 
 static struct i2c_driver ks0127_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "ks0127",
 	},
 	.probe		= ks0127_probe,

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

@@ -185,7 +185,6 @@ MODULE_DEVICE_TABLE(i2c, m52790_id);
 
 static struct i2c_driver m52790_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "m52790",
 	},
 	.probe		= m52790_probe,

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

@@ -894,7 +894,6 @@ MODULE_DEVICE_TABLE(i2c, msp_id);
 
 static struct i2c_driver msp_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "msp3400",
 		.pm	= &msp3400_pm_ops,
 	},

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

@@ -583,7 +583,6 @@ MODULE_DEVICE_TABLE(i2c, mt9v011_id);
 
 static struct i2c_driver mt9v011_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "mt9v011",
 	},
 	.probe		= mt9v011_probe,

+ 1 - 1
drivers/media/i2c/mt9v032.c

@@ -882,7 +882,7 @@ static const struct regmap_config mt9v032_regmap_config = {
 static struct mt9v032_platform_data *
 mt9v032_get_pdata(struct i2c_client *client)
 {
-	struct mt9v032_platform_data *pdata;
+	struct mt9v032_platform_data *pdata = NULL;
 	struct v4l2_of_endpoint endpoint;
 	struct device_node *np;
 	struct property *prop;

+ 0 - 4
drivers/media/i2c/ov2659.c

@@ -909,7 +909,6 @@ static void ov2659_pll_calc_params(struct ov2659 *ov2659)
 	u8 ctrl1_reg = 0, ctrl2_reg = 0, ctrl3_reg = 0;
 	struct i2c_client *client = ov2659->client;
 	unsigned int desired = pdata->link_frequency;
-	u32 s_prediv = 1, s_postdiv = 1, s_mult = 1;
 	u32 prediv, postdiv, mult;
 	u32 bestdelta = -1;
 	u32 delta, actual;
@@ -929,9 +928,6 @@ static void ov2659_pll_calc_params(struct ov2659 *ov2659)
 
 				if ((delta < bestdelta) || (bestdelta == -1)) {
 					bestdelta = delta;
-					s_mult    = mult;
-					s_prediv  = prediv;
-					s_postdiv = postdiv;
 					ctrl1_reg = ctrl1[i].reg;
 					ctrl2_reg = mult;
 					ctrl3_reg = ctrl3[j].reg;

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

@@ -94,7 +94,6 @@ MODULE_DEVICE_TABLE(i2c, ov7640_id);
 
 static struct i2c_driver ov7640_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "ov7640",
 	},
 	.probe = ov7640_probe,

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

@@ -1674,7 +1674,6 @@ MODULE_DEVICE_TABLE(i2c, ov7670_id);
 
 static struct i2c_driver ov7670_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "ov7670",
 	},
 	.probe		= ov7670_probe,

+ 1 - 1
drivers/media/i2c/ov9650.c

@@ -1436,7 +1436,7 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd)
 	int ret;
 
 	mutex_lock(&ov965x->lock);
-	 __ov965x_set_power(ov965x, 1);
+	__ov965x_set_power(ov965x, 1);
 	usleep_range(25000, 26000);
 
 	/* Check sensor revision */

+ 0 - 1
drivers/media/i2c/s5c73m3/s5c73m3-spi.c

@@ -149,7 +149,6 @@ int s5c73m3_register_spi_driver(struct s5c73m3 *state)
 	spidrv->remove = s5c73m3_spi_remove;
 	spidrv->probe = s5c73m3_spi_probe;
 	spidrv->driver.name = S5C73M3_SPI_DRV_NAME;
-	spidrv->driver.bus = &spi_bus_type;
 	spidrv->driver.owner = THIS_MODULE;
 	spidrv->driver.of_match_table = s5c73m3_spi_ids;
 

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

@@ -363,6 +363,7 @@ static int s5k6a3_remove(struct i2c_client *client)
 static const struct i2c_device_id s5k6a3_ids[] = {
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c, s5k6a3_ids);
 
 #ifdef CONFIG_OF
 static const struct of_device_id s5k6a3_of_match[] = {

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

@@ -301,9 +301,7 @@ static void saa6588_i2c_poll(struct saa6588 *s)
 	   first and the last of the 3 bytes block.
 	 */
 
-	tmp = tmpbuf[2];
-	tmpbuf[2] = tmpbuf[0];
-	tmpbuf[0] = tmp;
+	swap(tmpbuf[2], tmpbuf[0]);
 
 	/* Map 'Invalid block E' to 'Invalid Block' */
 	if (blocknum == 6)
@@ -520,7 +518,6 @@ MODULE_DEVICE_TABLE(i2c, saa6588_id);
 
 static struct i2c_driver saa6588_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "saa6588",
 	},
 	.probe		= saa6588_probe,

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

@@ -793,7 +793,6 @@ MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
 
 static struct i2c_driver saa6752hs_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "saa6752hs",
 	},
 	.probe		= saa6752hs_probe,

+ 0 - 12
drivers/media/i2c/saa7110.c

@@ -357,16 +357,6 @@ static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
 	.s_ctrl = saa7110_s_ctrl,
 };
 
-static const struct v4l2_subdev_core_ops saa7110_core_ops = {
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
-};
-
 static const struct v4l2_subdev_video_ops saa7110_video_ops = {
 	.s_std = saa7110_s_std,
 	.s_routing = saa7110_s_routing,
@@ -376,7 +366,6 @@ static const struct v4l2_subdev_video_ops saa7110_video_ops = {
 };
 
 static const struct v4l2_subdev_ops saa7110_ops = {
-	.core = &saa7110_core_ops,
 	.video = &saa7110_video_ops,
 };
 
@@ -472,7 +461,6 @@ MODULE_DEVICE_TABLE(i2c, saa7110_id);
 
 static struct i2c_driver saa7110_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "saa7110",
 	},
 	.probe		= saa7110_probe,

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

@@ -1929,7 +1929,6 @@ MODULE_DEVICE_TABLE(i2c, saa711x_id);
 
 static struct i2c_driver saa711x_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "saa7115",
 	},
 	.probe		= saa711x_probe,

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

@@ -822,7 +822,6 @@ MODULE_DEVICE_TABLE(i2c, saa7127_id);
 
 static struct i2c_driver saa7127_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "saa7127",
 	},
 	.probe		= saa7127_probe,

+ 0 - 8
drivers/media/i2c/saa717x.c

@@ -1204,13 +1204,6 @@ static const struct v4l2_subdev_core_ops saa717x_core_ops = {
 	.g_register = saa717x_g_register,
 	.s_register = saa717x_s_register,
 #endif
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
 	.log_status = saa717x_log_status,
 };
 
@@ -1363,7 +1356,6 @@ MODULE_DEVICE_TABLE(i2c, saa717x_id);
 
 static struct i2c_driver saa717x_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "saa717x",
 	},
 	.probe		= saa717x_probe,

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

@@ -356,7 +356,6 @@ MODULE_DEVICE_TABLE(i2c, saa7185_id);
 
 static struct i2c_driver saa7185_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "saa7185",
 	},
 	.probe		= saa7185_probe,

+ 4 - 4
drivers/media/i2c/soc_camera/mt9t112.c

@@ -104,22 +104,22 @@ struct mt9t112_priv {
 static const struct mt9t112_format mt9t112_cfmts[] = {
 	{
 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
-		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
 		.fmt		= 1,
 		.order		= 0,
 	}, {
 		.code		= MEDIA_BUS_FMT_VYUY8_2X8,
-		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
 		.fmt		= 1,
 		.order		= 1,
 	}, {
 		.code		= MEDIA_BUS_FMT_YUYV8_2X8,
-		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
 		.fmt		= 1,
 		.order		= 2,
 	}, {
 		.code		= MEDIA_BUS_FMT_YVYU8_2X8,
-		.colorspace	= V4L2_COLORSPACE_JPEG,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
 		.fmt		= 1,
 		.order		= 3,
 	}, {

+ 31 - 4
drivers/media/i2c/soc_camera/tw9910.c

@@ -510,13 +510,39 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct tw9910_priv *priv = to_tw9910(client);
+	const unsigned hact = 720;
+	const unsigned hdelay = 15;
+	unsigned vact;
+	unsigned vdelay;
+	int ret;
 
 	if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL)))
 		return -EINVAL;
 
 	priv->norm = norm;
+	if (norm & V4L2_STD_525_60) {
+		vact = 240;
+		vdelay = 18;
+		ret = tw9910_mask_set(client, VVBI, 0x10, 0x10);
+	} else {
+		vact = 288;
+		vdelay = 24;
+		ret = tw9910_mask_set(client, VVBI, 0x10, 0x00);
+	}
+	if (!ret)
+		ret = i2c_smbus_write_byte_data(client, CROP_HI,
+			((vdelay >> 2) & 0xc0) |
+			((vact >> 4) & 0x30) |
+			((hdelay >> 6) & 0x0c) |
+			((hact >> 8) & 0x03));
+	if (!ret)
+		ret = i2c_smbus_write_byte_data(client, VDELAY_LO,
+			vdelay & 0xff);
+	if (!ret)
+		ret = i2c_smbus_write_byte_data(client, VACTIVE_LO,
+			vact & 0xff);
 
-	return 0;
+	return ret;
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -711,7 +737,7 @@ static int tw9910_get_fmt(struct v4l2_subdev *sd,
 	mf->width	= priv->scale->width;
 	mf->height	= priv->scale->height;
 	mf->code	= MEDIA_BUS_FMT_UYVY8_2X8;
-	mf->colorspace	= V4L2_COLORSPACE_JPEG;
+	mf->colorspace	= V4L2_COLORSPACE_SMPTE170M;
 	mf->field	= V4L2_FIELD_INTERLACED_BT;
 
 	return 0;
@@ -732,7 +758,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
 	if (mf->code != MEDIA_BUS_FMT_UYVY8_2X8)
 		return -EINVAL;
 
-	mf->colorspace = V4L2_COLORSPACE_JPEG;
+	mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
 	ret = tw9910_set_frame(sd, &width, &height);
 	if (!ret) {
@@ -762,7 +788,7 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd,
 	}
 
 	mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
-	mf->colorspace = V4L2_COLORSPACE_JPEG;
+	mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
 	/*
 	 * select suitable norm
@@ -820,6 +846,7 @@ static int tw9910_video_probe(struct i2c_client *client)
 		 "tw9910 Product ID %0x:%0x\n", id, priv->revision);
 
 	priv->norm = V4L2_STD_NTSC;
+	priv->scale = &tw9910_ntsc_scales[0];
 
 done:
 	tw9910_s_power(&priv->subdev, 0);

+ 0 - 1
drivers/media/i2c/sony-btf-mpx.c

@@ -388,7 +388,6 @@ MODULE_DEVICE_TABLE(i2c, sony_btf_mpx_id);
 
 static struct i2c_driver sony_btf_mpx_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "sony-btf-mpx",
 	},
 	.probe = sony_btf_mpx_probe,

+ 2 - 13
drivers/media/i2c/sr030pc30.c

@@ -489,18 +489,14 @@ static int sr030pc30_get_fmt(struct v4l2_subdev *sd,
 {
 	struct v4l2_mbus_framefmt *mf;
 	struct sr030pc30_info *info = to_sr030pc30(sd);
-	int ret;
 
 	if (!format || format->pad)
 		return -EINVAL;
 
 	mf = &format->format;
 
-	if (!info->curr_win || !info->curr_fmt) {
-		ret = sr030pc30_set_params(sd);
-		if (ret)
-			return ret;
-	}
+	if (!info->curr_win || !info->curr_fmt)
+		return -EINVAL;
 
 	mf->width	= info->curr_win->width;
 	mf->height	= info->curr_win->height;
@@ -636,13 +632,6 @@ static const struct v4l2_ctrl_ops sr030pc30_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
 	.s_power	= sr030pc30_s_power,
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
 };
 
 static const struct v4l2_subdev_pad_ops sr030pc30_pad_ops = {

+ 1979 - 0
drivers/media/i2c/tc358743.c

@@ -0,0 +1,1979 @@
+/*
+ * tc358743 - Toshiba HDMI to CSI-2 bridge
+ *
+ * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
+ * reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/*
+ * References (c = chapter, p = page):
+ * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60
+ * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <linux/v4l2-dv-timings.h>
+#include <linux/hdmi.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-of.h>
+#include <media/tc358743.h>
+
+#include "tc358743_regs.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-3)");
+
+MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver");
+MODULE_AUTHOR("Ramakrishnan Muthukrishnan <ram@rkrishnan.org>");
+MODULE_AUTHOR("Mikhail Khelik <mkhelik@cisco.com>");
+MODULE_AUTHOR("Mats Randgaard <matrandg@cisco.com>");
+MODULE_LICENSE("GPL");
+
+#define EDID_NUM_BLOCKS_MAX 8
+#define EDID_BLOCK_SIZE 128
+
+/* Max transfer size done by I2C transfer functions */
+#define MAX_XFER_SIZE  (EDID_NUM_BLOCKS_MAX * EDID_BLOCK_SIZE + 2)
+
+static const struct v4l2_dv_timings_cap tc358743_timings_cap = {
+	.type = V4L2_DV_BT_656_1120,
+	/* keep this initialization for compatibility with GCC < 4.4.6 */
+	.reserved = { 0 },
+	/* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */
+	V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000,
+			V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+			V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
+			V4L2_DV_BT_CAP_PROGRESSIVE |
+			V4L2_DV_BT_CAP_REDUCED_BLANKING |
+			V4L2_DV_BT_CAP_CUSTOM)
+};
+
+struct tc358743_state {
+	struct tc358743_platform_data pdata;
+	struct v4l2_of_bus_mipi_csi2 bus;
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	struct v4l2_ctrl_handler hdl;
+	struct i2c_client *i2c_client;
+	/* CONFCTL is modified in ops and tc358743_hdmi_sys_int_handler */
+	struct mutex confctl_mutex;
+
+	/* controls */
+	struct v4l2_ctrl *detect_tx_5v_ctrl;
+	struct v4l2_ctrl *audio_sampling_rate_ctrl;
+	struct v4l2_ctrl *audio_present_ctrl;
+
+	/* work queues */
+	struct workqueue_struct *work_queues;
+	struct delayed_work delayed_work_enable_hotplug;
+
+	/* edid  */
+	u8 edid_blocks_written;
+
+	/* used by i2c_wr() */
+	u8 wr_data[MAX_XFER_SIZE];
+
+	struct v4l2_dv_timings timings;
+	u32 mbus_fmt_code;
+
+	struct gpio_desc *reset_gpio;
+};
+
+static void tc358743_enable_interrupts(struct v4l2_subdev *sd,
+		bool cable_connected);
+static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd);
+
+static inline struct tc358743_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct tc358743_state, sd);
+}
+
+/* --------------- I2C --------------- */
+
+static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct i2c_client *client = state->i2c_client;
+	int err;
+	u8 buf[2] = { reg >> 8, reg & 0xff };
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 2,
+			.buf = buf,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = n,
+			.buf = values,
+		},
+	};
+
+	err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (err != ARRAY_SIZE(msgs)) {
+		v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n",
+				__func__, reg, client->addr);
+	}
+}
+
+static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct i2c_client *client = state->i2c_client;
+	u8 *data = state->wr_data;
+	int err, i;
+	struct i2c_msg msg;
+
+	if ((2 + n) > sizeof(state->wr_data))
+		v4l2_warn(sd, "i2c wr reg=%04x: len=%d is too big!\n",
+			  reg, 2 + n);
+
+	msg.addr = client->addr;
+	msg.buf = data;
+	msg.len = 2 + n;
+	msg.flags = 0;
+
+	data[0] = reg >> 8;
+	data[1] = reg & 0xff;
+
+	for (i = 0; i < n; i++)
+		data[2 + i] = values[i];
+
+	err = i2c_transfer(client->adapter, &msg, 1);
+	if (err != 1) {
+		v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n",
+				__func__, reg, client->addr);
+		return;
+	}
+
+	if (debug < 3)
+		return;
+
+	switch (n) {
+	case 1:
+		v4l2_info(sd, "I2C write 0x%04x = 0x%02x",
+				reg, data[2]);
+		break;
+	case 2:
+		v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x",
+				reg, data[3], data[2]);
+		break;
+	case 4:
+		v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x",
+				reg, data[5], data[4], data[3], data[2]);
+		break;
+	default:
+		v4l2_info(sd, "I2C write %d bytes from address 0x%04x\n",
+				n, reg);
+	}
+}
+
+static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg)
+{
+	u8 val;
+
+	i2c_rd(sd, reg, &val, 1);
+
+	return val;
+}
+
+static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val)
+{
+	i2c_wr(sd, reg, &val, 1);
+}
+
+static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg,
+		u8 mask, u8 val)
+{
+	i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val);
+}
+
+static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg)
+{
+	u16 val;
+
+	i2c_rd(sd, reg, (u8 *)&val, 2);
+
+	return val;
+}
+
+static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
+{
+	i2c_wr(sd, reg, (u8 *)&val, 2);
+}
+
+static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val)
+{
+	i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val);
+}
+
+static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg)
+{
+	u32 val;
+
+	i2c_rd(sd, reg, (u8 *)&val, 4);
+
+	return val;
+}
+
+static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val)
+{
+	i2c_wr(sd, reg, (u8 *)&val, 4);
+}
+
+/* --------------- STATUS --------------- */
+
+static inline bool is_hdmi(struct v4l2_subdev *sd)
+{
+	return i2c_rd8(sd, SYS_STATUS) & MASK_S_HDMI;
+}
+
+static inline bool tx_5v_power_present(struct v4l2_subdev *sd)
+{
+	return i2c_rd8(sd, SYS_STATUS) & MASK_S_DDC5V;
+}
+
+static inline bool no_signal(struct v4l2_subdev *sd)
+{
+	return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_TMDS);
+}
+
+static inline bool no_sync(struct v4l2_subdev *sd)
+{
+	return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_SYNC);
+}
+
+static inline bool audio_present(struct v4l2_subdev *sd)
+{
+	return i2c_rd8(sd, AU_STATUS0) & MASK_S_A_SAMPLE;
+}
+
+static int get_audio_sampling_rate(struct v4l2_subdev *sd)
+{
+	static const int code_to_rate[] = {
+		44100, 0, 48000, 32000, 22050, 384000, 24000, 352800,
+		88200, 768000, 96000, 705600, 176400, 0, 192000, 0
+	};
+
+	/* Register FS_SET is not cleared when the cable is disconnected */
+	if (no_signal(sd))
+		return 0;
+
+	return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS];
+}
+
+static unsigned tc358743_num_csi_lanes_in_use(struct v4l2_subdev *sd)
+{
+	return ((i2c_rd32(sd, CSI_CONTROL) & MASK_NOL) >> 1) + 1;
+}
+
+/* --------------- TIMINGS --------------- */
+
+static inline unsigned fps(const struct v4l2_bt_timings *t)
+{
+	if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t))
+		return 0;
+
+	return DIV_ROUND_CLOSEST((unsigned)t->pixelclock,
+			V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t));
+}
+
+static int tc358743_get_detected_timings(struct v4l2_subdev *sd,
+				     struct v4l2_dv_timings *timings)
+{
+	struct v4l2_bt_timings *bt = &timings->bt;
+	unsigned width, height, frame_width, frame_height, frame_interval, fps;
+
+	memset(timings, 0, sizeof(struct v4l2_dv_timings));
+
+	if (no_signal(sd)) {
+		v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__);
+		return -ENOLINK;
+	}
+	if (no_sync(sd)) {
+		v4l2_dbg(1, debug, sd, "%s: no sync on signal\n", __func__);
+		return -ENOLCK;
+	}
+
+	timings->type = V4L2_DV_BT_656_1120;
+	bt->interlaced = i2c_rd8(sd, VI_STATUS1) & MASK_S_V_INTERLACE ?
+		V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
+
+	width = ((i2c_rd8(sd, DE_WIDTH_H_HI) & 0x1f) << 8) +
+		i2c_rd8(sd, DE_WIDTH_H_LO);
+	height = ((i2c_rd8(sd, DE_WIDTH_V_HI) & 0x1f) << 8) +
+		i2c_rd8(sd, DE_WIDTH_V_LO);
+	frame_width = ((i2c_rd8(sd, H_SIZE_HI) & 0x1f) << 8) +
+		i2c_rd8(sd, H_SIZE_LO);
+	frame_height = (((i2c_rd8(sd, V_SIZE_HI) & 0x3f) << 8) +
+		i2c_rd8(sd, V_SIZE_LO)) / 2;
+	/* frame interval in milliseconds * 10
+	 * Require SYS_FREQ0 and SYS_FREQ1 are precisely set */
+	frame_interval = ((i2c_rd8(sd, FV_CNT_HI) & 0x3) << 8) +
+		i2c_rd8(sd, FV_CNT_LO);
+	fps = (frame_interval > 0) ?
+		DIV_ROUND_CLOSEST(10000, frame_interval) : 0;
+
+	bt->width = width;
+	bt->height = height;
+	bt->vsync = frame_height - height;
+	bt->hsync = frame_width - width;
+	bt->pixelclock = frame_width * frame_height * fps;
+	if (bt->interlaced == V4L2_DV_INTERLACED) {
+		bt->height *= 2;
+		bt->il_vsync = bt->vsync + 1;
+		bt->pixelclock /= 2;
+	}
+
+	return 0;
+}
+
+/* --------------- HOTPLUG / HDCP / EDID --------------- */
+
+static void tc358743_delayed_work_enable_hotplug(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct tc358743_state *state = container_of(dwork,
+			struct tc358743_state, delayed_work_enable_hotplug);
+	struct v4l2_subdev *sd = &state->sd;
+
+	v4l2_dbg(2, debug, sd, "%s:\n", __func__);
+
+	i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, MASK_HPD_OUT0);
+}
+
+static void tc358743_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable)
+{
+	v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ?
+				"enable" : "disable");
+
+	i2c_wr8_and_or(sd, HDCP_REG1,
+			~(MASK_AUTH_UNAUTH_SEL | MASK_AUTH_UNAUTH),
+			MASK_AUTH_UNAUTH_SEL_16_FRAMES | MASK_AUTH_UNAUTH_AUTO);
+
+	i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET,
+			SET_AUTO_P3_RESET_FRAMES(0x0f));
+
+	/* HDCP is disabled by configuring the receiver as HDCP repeater. The
+	 * repeater mode require software support to work, so HDCP
+	 * authentication will fail.
+	 */
+	i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, enable ? KEY_RD_CMD : 0);
+	i2c_wr8_and_or(sd, HDCP_MODE, ~(MASK_AUTO_CLR | MASK_MODE_RST_TN),
+			enable ?  (MASK_AUTO_CLR | MASK_MODE_RST_TN) : 0);
+
+	/* Apple MacBook Pro gen.8 has a bug that makes it freeze every fifth
+	 * second when HDCP is disabled, but the MAX_EXCED bit is handled
+	 * correctly and HDCP is disabled on the HDMI output.
+	 */
+	i2c_wr8_and_or(sd, BSTATUS1, ~MASK_MAX_EXCED,
+			enable ? 0 : MASK_MAX_EXCED);
+	i2c_wr8_and_or(sd, BCAPS, ~(MASK_REPEATER | MASK_READY),
+			enable ? 0 : MASK_REPEATER | MASK_READY);
+}
+
+static void tc358743_disable_edid(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	v4l2_dbg(2, debug, sd, "%s:\n", __func__);
+
+	cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
+
+	/* DDC access to EDID is also disabled when hotplug is disabled. See
+	 * register DDC_CTL */
+	i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, 0x0);
+}
+
+static void tc358743_enable_edid(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	if (state->edid_blocks_written == 0) {
+		v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__);
+		return;
+	}
+
+	v4l2_dbg(2, debug, sd, "%s:\n", __func__);
+
+	/* Enable hotplug after 100 ms. DDC access to EDID is also enabled when
+	 * hotplug is enabled. See register DDC_CTL */
+	queue_delayed_work(state->work_queues,
+			   &state->delayed_work_enable_hotplug, HZ / 10);
+
+	tc358743_enable_interrupts(sd, true);
+	tc358743_s_ctrl_detect_tx_5v(sd);
+}
+
+static void tc358743_erase_bksv(struct v4l2_subdev *sd)
+{
+	int i;
+
+	for (i = 0; i < 5; i++)
+		i2c_wr8(sd, BKSV + i, 0);
+}
+
+/* --------------- AVI infoframe --------------- */
+
+static void print_avi_infoframe(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct device *dev = &client->dev;
+	union hdmi_infoframe frame;
+	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
+
+	if (!is_hdmi(sd)) {
+		v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n");
+		return;
+	}
+
+	i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
+
+	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+		v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
+		return;
+	}
+
+	hdmi_infoframe_log(KERN_INFO, dev, &frame);
+}
+
+/* --------------- CTRLS --------------- */
+
+static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl,
+			tx_5v_power_present(sd));
+}
+
+static int tc358743_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	return v4l2_ctrl_s_ctrl(state->audio_sampling_rate_ctrl,
+			get_audio_sampling_rate(sd));
+}
+
+static int tc358743_s_ctrl_audio_present(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	return v4l2_ctrl_s_ctrl(state->audio_present_ctrl,
+			audio_present(sd));
+}
+
+static int tc358743_update_controls(struct v4l2_subdev *sd)
+{
+	int ret = 0;
+
+	ret |= tc358743_s_ctrl_detect_tx_5v(sd);
+	ret |= tc358743_s_ctrl_audio_sampling_rate(sd);
+	ret |= tc358743_s_ctrl_audio_present(sd);
+
+	return ret;
+}
+
+/* --------------- INIT --------------- */
+
+static void tc358743_reset_phy(struct v4l2_subdev *sd)
+{
+	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
+	i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, 0);
+	i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, MASK_RESET_CTRL);
+}
+
+static void tc358743_reset(struct v4l2_subdev *sd, uint16_t mask)
+{
+	u16 sysctl = i2c_rd16(sd, SYSCTL);
+
+	i2c_wr16(sd, SYSCTL, sysctl | mask);
+	i2c_wr16(sd, SYSCTL, sysctl & ~mask);
+}
+
+static inline void tc358743_sleep_mode(struct v4l2_subdev *sd, bool enable)
+{
+	i2c_wr16_and_or(sd, SYSCTL, ~MASK_SLEEP,
+			enable ? MASK_SLEEP : 0);
+}
+
+static inline void enable_stream(struct v4l2_subdev *sd, bool enable)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	v4l2_dbg(3, debug, sd, "%s: %sable\n",
+			__func__, enable ? "en" : "dis");
+
+	if (enable) {
+		/* It is critical for CSI receiver to see lane transition
+		 * LP11->HS. Set to non-continuous mode to enable clock lane
+		 * LP11 state. */
+		i2c_wr32(sd, TXOPTIONCNTRL, 0);
+		/* Set to continuous mode to trigger LP11->HS transition */
+		i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE);
+		/* Unmute video */
+		i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE);
+	} else {
+		/* Mute video so that all data lanes go to LSP11 state.
+		 * No data is output to CSI Tx block. */
+		i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE | MASK_VI_MUTE);
+	}
+
+	mutex_lock(&state->confctl_mutex);
+	i2c_wr16_and_or(sd, CONFCTL, ~(MASK_VBUFEN | MASK_ABUFEN),
+			enable ? (MASK_VBUFEN | MASK_ABUFEN) : 0x0);
+	mutex_unlock(&state->confctl_mutex);
+}
+
+static void tc358743_set_pll(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct tc358743_platform_data *pdata = &state->pdata;
+	u16 pllctl0 = i2c_rd16(sd, PLLCTL0);
+	u16 pllctl1 = i2c_rd16(sd, PLLCTL1);
+	u16 pllctl0_new = SET_PLL_PRD(pdata->pll_prd) |
+		SET_PLL_FBD(pdata->pll_fbd);
+	u32 hsck = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd;
+
+	v4l2_dbg(2, debug, sd, "%s:\n", __func__);
+
+	/* Only rewrite when needed (new value or disabled), since rewriting
+	 * triggers another format change event. */
+	if ((pllctl0 != pllctl0_new) || ((pllctl1 & MASK_PLL_EN) == 0)) {
+		u16 pll_frs;
+
+		if (hsck > 500000000)
+			pll_frs = 0x0;
+		else if (hsck > 250000000)
+			pll_frs = 0x1;
+		else if (hsck > 125000000)
+			pll_frs = 0x2;
+		else
+			pll_frs = 0x3;
+
+		v4l2_dbg(1, debug, sd, "%s: updating PLL clock\n", __func__);
+		tc358743_sleep_mode(sd, true);
+		i2c_wr16(sd, PLLCTL0, pllctl0_new);
+		i2c_wr16_and_or(sd, PLLCTL1,
+				~(MASK_PLL_FRS | MASK_RESETB | MASK_PLL_EN),
+				(SET_PLL_FRS(pll_frs) | MASK_RESETB |
+				 MASK_PLL_EN));
+		udelay(10); /* REF_02, Sheet "Source HDMI" */
+		i2c_wr16_and_or(sd, PLLCTL1, ~MASK_CKEN, MASK_CKEN);
+		tc358743_sleep_mode(sd, false);
+	}
+}
+
+static void tc358743_set_ref_clk(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct tc358743_platform_data *pdata = &state->pdata;
+	u32 sys_freq;
+	u32 lockdet_ref;
+	u16 fh_min;
+	u16 fh_max;
+
+	BUG_ON(!(pdata->refclk_hz == 26000000 ||
+		 pdata->refclk_hz == 27000000 ||
+		 pdata->refclk_hz == 42000000));
+
+	sys_freq = pdata->refclk_hz / 10000;
+	i2c_wr8(sd, SYS_FREQ0, sys_freq & 0x00ff);
+	i2c_wr8(sd, SYS_FREQ1, (sys_freq & 0xff00) >> 8);
+
+	i2c_wr8_and_or(sd, PHY_CTL0, ~MASK_PHY_SYSCLK_IND,
+			(pdata->refclk_hz == 42000000) ?
+			MASK_PHY_SYSCLK_IND : 0x0);
+
+	fh_min = pdata->refclk_hz / 100000;
+	i2c_wr8(sd, FH_MIN0, fh_min & 0x00ff);
+	i2c_wr8(sd, FH_MIN1, (fh_min & 0xff00) >> 8);
+
+	fh_max = (fh_min * 66) / 10;
+	i2c_wr8(sd, FH_MAX0, fh_max & 0x00ff);
+	i2c_wr8(sd, FH_MAX1, (fh_max & 0xff00) >> 8);
+
+	lockdet_ref = pdata->refclk_hz / 100;
+	i2c_wr8(sd, LOCKDET_REF0, lockdet_ref & 0x0000ff);
+	i2c_wr8(sd, LOCKDET_REF1, (lockdet_ref & 0x00ff00) >> 8);
+	i2c_wr8(sd, LOCKDET_REF2, (lockdet_ref & 0x0f0000) >> 16);
+
+	i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD,
+			(pdata->refclk_hz == 27000000) ?
+			MASK_NCO_F0_MOD_27MHZ : 0x0);
+}
+
+static void tc358743_set_csi_color_space(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	switch (state->mbus_fmt_code) {
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+		v4l2_dbg(2, debug, sd, "%s: YCbCr 422 16-bit\n", __func__);
+		i2c_wr8_and_or(sd, VOUT_SET2,
+				~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff,
+				MASK_SEL422 | MASK_VOUT_422FIL_100);
+		i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff,
+				MASK_VOUT_COLOR_601_YCBCR_LIMITED);
+		mutex_lock(&state->confctl_mutex);
+		i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT,
+				MASK_YCBCRFMT_422_8_BIT);
+		mutex_unlock(&state->confctl_mutex);
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		v4l2_dbg(2, debug, sd, "%s: RGB 888 24-bit\n", __func__);
+		i2c_wr8_and_or(sd, VOUT_SET2,
+				~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff,
+				0x00);
+		i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff,
+				MASK_VOUT_COLOR_RGB_FULL);
+		mutex_lock(&state->confctl_mutex);
+		i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 0);
+		mutex_unlock(&state->confctl_mutex);
+		break;
+	default:
+		v4l2_dbg(2, debug, sd, "%s: Unsupported format code 0x%x\n",
+				__func__, state->mbus_fmt_code);
+	}
+}
+
+static unsigned tc358743_num_csi_lanes_needed(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct v4l2_bt_timings *bt = &state->timings.bt;
+	struct tc358743_platform_data *pdata = &state->pdata;
+	u32 bits_pr_pixel =
+		(state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16) ?  16 : 24;
+	u32 bps = bt->width * bt->height * fps(bt) * bits_pr_pixel;
+	u32 bps_pr_lane = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd;
+
+	return DIV_ROUND_UP(bps, bps_pr_lane);
+}
+
+static void tc358743_set_csi(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct tc358743_platform_data *pdata = &state->pdata;
+	unsigned lanes = tc358743_num_csi_lanes_needed(sd);
+
+	v4l2_dbg(3, debug, sd, "%s:\n", __func__);
+
+	tc358743_reset(sd, MASK_CTXRST);
+
+	if (lanes < 1)
+		i2c_wr32(sd, CLW_CNTRL, MASK_CLW_LANEDISABLE);
+	if (lanes < 1)
+		i2c_wr32(sd, D0W_CNTRL, MASK_D0W_LANEDISABLE);
+	if (lanes < 2)
+		i2c_wr32(sd, D1W_CNTRL, MASK_D1W_LANEDISABLE);
+	if (lanes < 3)
+		i2c_wr32(sd, D2W_CNTRL, MASK_D2W_LANEDISABLE);
+	if (lanes < 4)
+		i2c_wr32(sd, D3W_CNTRL, MASK_D3W_LANEDISABLE);
+
+	i2c_wr32(sd, LINEINITCNT, pdata->lineinitcnt);
+	i2c_wr32(sd, LPTXTIMECNT, pdata->lptxtimecnt);
+	i2c_wr32(sd, TCLK_HEADERCNT, pdata->tclk_headercnt);
+	i2c_wr32(sd, TCLK_TRAILCNT, pdata->tclk_trailcnt);
+	i2c_wr32(sd, THS_HEADERCNT, pdata->ths_headercnt);
+	i2c_wr32(sd, TWAKEUP, pdata->twakeup);
+	i2c_wr32(sd, TCLK_POSTCNT, pdata->tclk_postcnt);
+	i2c_wr32(sd, THS_TRAILCNT, pdata->ths_trailcnt);
+	i2c_wr32(sd, HSTXVREGCNT, pdata->hstxvregcnt);
+
+	i2c_wr32(sd, HSTXVREGEN,
+			((lanes > 0) ? MASK_CLM_HSTXVREGEN : 0x0) |
+			((lanes > 0) ? MASK_D0M_HSTXVREGEN : 0x0) |
+			((lanes > 1) ? MASK_D1M_HSTXVREGEN : 0x0) |
+			((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) |
+			((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0));
+
+	i2c_wr32(sd, TXOPTIONCNTRL, (state->bus.flags &
+		 V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) ? MASK_CONTCLKMODE : 0);
+	i2c_wr32(sd, STARTCNTRL, MASK_START);
+	i2c_wr32(sd, CSI_START, MASK_STRT);
+
+	i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET |
+			MASK_ADDRESS_CSI_CONTROL |
+			MASK_CSI_MODE |
+			MASK_TXHSMD |
+			((lanes == 4) ? MASK_NOL_4 :
+			 (lanes == 3) ? MASK_NOL_3 :
+			 (lanes == 2) ? MASK_NOL_2 : MASK_NOL_1));
+
+	i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET |
+			MASK_ADDRESS_CSI_ERR_INTENA | MASK_TXBRK | MASK_QUNK |
+			MASK_WCER | MASK_INER);
+
+	i2c_wr32(sd, CSI_CONFW, MASK_MODE_CLEAR |
+			MASK_ADDRESS_CSI_ERR_HALT | MASK_TXBRK | MASK_QUNK);
+
+	i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET |
+			MASK_ADDRESS_CSI_INT_ENA | MASK_INTER);
+}
+
+static void tc358743_set_hdmi_phy(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct tc358743_platform_data *pdata = &state->pdata;
+
+	/* Default settings from REF_02, sheet "Source HDMI"
+	 * and custom settings as platform data */
+	i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, 0x0);
+	i2c_wr8(sd, PHY_CTL1, SET_PHY_AUTO_RST1_US(1600) |
+			SET_FREQ_RANGE_MODE_CYCLES(1));
+	i2c_wr8_and_or(sd, PHY_CTL2, ~MASK_PHY_AUTO_RSTn,
+			(pdata->hdmi_phy_auto_reset_tmds_detected ?
+			 MASK_PHY_AUTO_RST2 : 0) |
+			(pdata->hdmi_phy_auto_reset_tmds_in_range ?
+			 MASK_PHY_AUTO_RST3 : 0) |
+			(pdata->hdmi_phy_auto_reset_tmds_valid ?
+			 MASK_PHY_AUTO_RST4 : 0));
+	i2c_wr8(sd, PHY_BIAS, 0x40);
+	i2c_wr8(sd, PHY_CSQ, SET_CSQ_CNT_LEVEL(0x0a));
+	i2c_wr8(sd, AVM_CTL, 45);
+	i2c_wr8_and_or(sd, HDMI_DET, ~MASK_HDMI_DET_V,
+			pdata->hdmi_detection_delay << 4);
+	i2c_wr8_and_or(sd, HV_RST, ~(MASK_H_PI_RST | MASK_V_PI_RST),
+			(pdata->hdmi_phy_auto_reset_hsync_out_of_range ?
+			 MASK_H_PI_RST : 0) |
+			(pdata->hdmi_phy_auto_reset_vsync_out_of_range ?
+			 MASK_V_PI_RST : 0));
+	i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, MASK_ENABLE_PHY);
+}
+
+static void tc358743_set_hdmi_audio(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	/* Default settings from REF_02, sheet "Source HDMI" */
+	i2c_wr8(sd, FORCE_MUTE, 0x00);
+	i2c_wr8(sd, AUTO_CMD0, MASK_AUTO_MUTE7 | MASK_AUTO_MUTE6 |
+			MASK_AUTO_MUTE5 | MASK_AUTO_MUTE4 |
+			MASK_AUTO_MUTE1 | MASK_AUTO_MUTE0);
+	i2c_wr8(sd, AUTO_CMD1, MASK_AUTO_MUTE9);
+	i2c_wr8(sd, AUTO_CMD2, MASK_AUTO_PLAY3 | MASK_AUTO_PLAY2);
+	i2c_wr8(sd, BUFINIT_START, SET_BUFINIT_START_MS(500));
+	i2c_wr8(sd, FS_MUTE, 0x00);
+	i2c_wr8(sd, FS_IMODE, MASK_NLPCM_SMODE | MASK_FS_SMODE);
+	i2c_wr8(sd, ACR_MODE, MASK_CTS_MODE);
+	i2c_wr8(sd, ACR_MDF0, MASK_ACR_L2MDF_1976_PPM | MASK_ACR_L1MDF_976_PPM);
+	i2c_wr8(sd, ACR_MDF1, MASK_ACR_L3MDF_3906_PPM);
+	i2c_wr8(sd, SDO_MODE1, MASK_SDO_FMT_I2S);
+	i2c_wr8(sd, DIV_MODE, SET_DIV_DLY_MS(100));
+
+	mutex_lock(&state->confctl_mutex);
+	i2c_wr16_and_or(sd, CONFCTL, 0xffff, MASK_AUDCHNUM_2 |
+			MASK_AUDOUTSEL_I2S | MASK_AUTOINDEX);
+	mutex_unlock(&state->confctl_mutex);
+}
+
+static void tc358743_set_hdmi_info_frame_mode(struct v4l2_subdev *sd)
+{
+	/* Default settings from REF_02, sheet "Source HDMI" */
+	i2c_wr8(sd, PK_INT_MODE, MASK_ISRC2_INT_MODE | MASK_ISRC_INT_MODE |
+			MASK_ACP_INT_MODE | MASK_VS_INT_MODE |
+			MASK_SPD_INT_MODE | MASK_MS_INT_MODE |
+			MASK_AUD_INT_MODE | MASK_AVI_INT_MODE);
+	i2c_wr8(sd, NO_PKT_LIMIT, 0x2c);
+	i2c_wr8(sd, NO_PKT_CLR, 0x53);
+	i2c_wr8(sd, ERR_PK_LIMIT, 0x01);
+	i2c_wr8(sd, NO_PKT_LIMIT2, 0x30);
+	i2c_wr8(sd, NO_GDB_LIMIT, 0x10);
+}
+
+static void tc358743_initial_setup(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct tc358743_platform_data *pdata = &state->pdata;
+
+	/* CEC and IR are not supported by this driver */
+	i2c_wr16_and_or(sd, SYSCTL, ~(MASK_CECRST | MASK_IRRST),
+			(MASK_CECRST | MASK_IRRST));
+
+	tc358743_reset(sd, MASK_CTXRST | MASK_HDMIRST);
+	tc358743_sleep_mode(sd, false);
+
+	i2c_wr16(sd, FIFOCTL, pdata->fifo_level);
+
+	tc358743_set_ref_clk(sd);
+
+	i2c_wr8_and_or(sd, DDC_CTL, ~MASK_DDC5V_MODE,
+			pdata->ddc5v_delay & MASK_DDC5V_MODE);
+	i2c_wr8_and_or(sd, EDID_MODE, ~MASK_EDID_MODE, MASK_EDID_MODE_E_DDC);
+
+	tc358743_set_hdmi_phy(sd);
+	tc358743_set_hdmi_hdcp(sd, pdata->enable_hdcp);
+	tc358743_set_hdmi_audio(sd);
+	tc358743_set_hdmi_info_frame_mode(sd);
+
+	/* All CE and IT formats are detected as RGB full range in DVI mode */
+	i2c_wr8_and_or(sd, VI_MODE, ~MASK_RGB_DVI, 0);
+
+	i2c_wr8_and_or(sd, VOUT_SET2, ~MASK_VOUTCOLORMODE,
+			MASK_VOUTCOLORMODE_AUTO);
+	i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT);
+}
+
+/* --------------- IRQ --------------- */
+
+static void tc358743_format_change(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct v4l2_dv_timings timings;
+	const struct v4l2_event tc358743_ev_fmt = {
+		.type = V4L2_EVENT_SOURCE_CHANGE,
+		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+	};
+
+	if (tc358743_get_detected_timings(sd, &timings)) {
+		enable_stream(sd, false);
+
+		v4l2_dbg(1, debug, sd, "%s: Format changed. No signal\n",
+				__func__);
+	} else {
+		if (!v4l2_match_dv_timings(&state->timings, &timings, 0))
+			enable_stream(sd, false);
+
+		v4l2_print_dv_timings(sd->name,
+				"tc358743_format_change: Format changed. New format: ",
+				&timings, false);
+	}
+
+	if (sd->devnode)
+		v4l2_subdev_notify_event(sd, &tc358743_ev_fmt);
+}
+
+static void tc358743_init_interrupts(struct v4l2_subdev *sd)
+{
+	u16 i;
+
+	/* clear interrupt status registers */
+	for (i = SYS_INT; i <= KEY_INT; i++)
+		i2c_wr8(sd, i, 0xff);
+
+	i2c_wr16(sd, INTSTATUS, 0xffff);
+}
+
+static void tc358743_enable_interrupts(struct v4l2_subdev *sd,
+		bool cable_connected)
+{
+	v4l2_dbg(2, debug, sd, "%s: cable connected = %d\n", __func__,
+			cable_connected);
+
+	if (cable_connected) {
+		i2c_wr8(sd, SYS_INTM, ~(MASK_M_DDC | MASK_M_DVI_DET |
+					MASK_M_HDMI_DET) & 0xff);
+		i2c_wr8(sd, CLK_INTM, ~MASK_M_IN_DE_CHG);
+		i2c_wr8(sd, CBIT_INTM, ~(MASK_M_CBIT_FS | MASK_M_AF_LOCK |
+					MASK_M_AF_UNLOCK) & 0xff);
+		i2c_wr8(sd, AUDIO_INTM, ~MASK_M_BUFINIT_END);
+		i2c_wr8(sd, MISC_INTM, ~MASK_M_SYNC_CHG);
+	} else {
+		i2c_wr8(sd, SYS_INTM, ~MASK_M_DDC & 0xff);
+		i2c_wr8(sd, CLK_INTM, 0xff);
+		i2c_wr8(sd, CBIT_INTM, 0xff);
+		i2c_wr8(sd, AUDIO_INTM, 0xff);
+		i2c_wr8(sd, MISC_INTM, 0xff);
+	}
+}
+
+static void tc358743_hdmi_audio_int_handler(struct v4l2_subdev *sd,
+		bool *handled)
+{
+	u8 audio_int_mask = i2c_rd8(sd, AUDIO_INTM);
+	u8 audio_int = i2c_rd8(sd, AUDIO_INT) & ~audio_int_mask;
+
+	i2c_wr8(sd, AUDIO_INT, audio_int);
+
+	v4l2_dbg(3, debug, sd, "%s: AUDIO_INT = 0x%02x\n", __func__, audio_int);
+
+	tc358743_s_ctrl_audio_sampling_rate(sd);
+	tc358743_s_ctrl_audio_present(sd);
+}
+
+static void tc358743_csi_err_int_handler(struct v4l2_subdev *sd, bool *handled)
+{
+	v4l2_err(sd, "%s: CSI_ERR = 0x%x\n", __func__, i2c_rd32(sd, CSI_ERR));
+
+	i2c_wr32(sd, CSI_INT_CLR, MASK_ICRER);
+}
+
+static void tc358743_hdmi_misc_int_handler(struct v4l2_subdev *sd,
+		bool *handled)
+{
+	u8 misc_int_mask = i2c_rd8(sd, MISC_INTM);
+	u8 misc_int = i2c_rd8(sd, MISC_INT) & ~misc_int_mask;
+
+	i2c_wr8(sd, MISC_INT, misc_int);
+
+	v4l2_dbg(3, debug, sd, "%s: MISC_INT = 0x%02x\n", __func__, misc_int);
+
+	if (misc_int & MASK_I_SYNC_CHG) {
+		/* Reset the HDMI PHY to try to trigger proper lock on the
+		 * incoming video format. Erase BKSV to prevent that old keys
+		 * are used when a new source is connected. */
+		if (no_sync(sd) || no_signal(sd)) {
+			tc358743_reset_phy(sd);
+			tc358743_erase_bksv(sd);
+		}
+
+		tc358743_format_change(sd);
+
+		misc_int &= ~MASK_I_SYNC_CHG;
+		if (handled)
+			*handled = true;
+	}
+
+	if (misc_int) {
+		v4l2_err(sd, "%s: Unhandled MISC_INT interrupts: 0x%02x\n",
+				__func__, misc_int);
+	}
+}
+
+static void tc358743_hdmi_cbit_int_handler(struct v4l2_subdev *sd,
+		bool *handled)
+{
+	u8 cbit_int_mask = i2c_rd8(sd, CBIT_INTM);
+	u8 cbit_int = i2c_rd8(sd, CBIT_INT) & ~cbit_int_mask;
+
+	i2c_wr8(sd, CBIT_INT, cbit_int);
+
+	v4l2_dbg(3, debug, sd, "%s: CBIT_INT = 0x%02x\n", __func__, cbit_int);
+
+	if (cbit_int & MASK_I_CBIT_FS) {
+
+		v4l2_dbg(1, debug, sd, "%s: Audio sample rate changed\n",
+				__func__);
+		tc358743_s_ctrl_audio_sampling_rate(sd);
+
+		cbit_int &= ~MASK_I_CBIT_FS;
+		if (handled)
+			*handled = true;
+	}
+
+	if (cbit_int & (MASK_I_AF_LOCK | MASK_I_AF_UNLOCK)) {
+
+		v4l2_dbg(1, debug, sd, "%s: Audio present changed\n",
+				__func__);
+		tc358743_s_ctrl_audio_present(sd);
+
+		cbit_int &= ~(MASK_I_AF_LOCK | MASK_I_AF_UNLOCK);
+		if (handled)
+			*handled = true;
+	}
+
+	if (cbit_int) {
+		v4l2_err(sd, "%s: Unhandled CBIT_INT interrupts: 0x%02x\n",
+				__func__, cbit_int);
+	}
+}
+
+static void tc358743_hdmi_clk_int_handler(struct v4l2_subdev *sd, bool *handled)
+{
+	u8 clk_int_mask = i2c_rd8(sd, CLK_INTM);
+	u8 clk_int = i2c_rd8(sd, CLK_INT) & ~clk_int_mask;
+
+	/* Bit 7 and bit 6 are set even when they are masked */
+	i2c_wr8(sd, CLK_INT, clk_int | 0x80 | MASK_I_OUT_H_CHG);
+
+	v4l2_dbg(3, debug, sd, "%s: CLK_INT = 0x%02x\n", __func__, clk_int);
+
+	if (clk_int & (MASK_I_IN_DE_CHG)) {
+
+		v4l2_dbg(1, debug, sd, "%s: DE size or position has changed\n",
+				__func__);
+
+		/* If the source switch to a new resolution with the same pixel
+		 * frequency as the existing (e.g. 1080p25 -> 720p50), the
+		 * I_SYNC_CHG interrupt is not always triggered, while the
+		 * I_IN_DE_CHG interrupt seems to work fine. Format change
+		 * notifications are only sent when the signal is stable to
+		 * reduce the number of notifications. */
+		if (!no_signal(sd) && !no_sync(sd))
+			tc358743_format_change(sd);
+
+		clk_int &= ~(MASK_I_IN_DE_CHG);
+		if (handled)
+			*handled = true;
+	}
+
+	if (clk_int) {
+		v4l2_err(sd, "%s: Unhandled CLK_INT interrupts: 0x%02x\n",
+				__func__, clk_int);
+	}
+}
+
+static void tc358743_hdmi_sys_int_handler(struct v4l2_subdev *sd, bool *handled)
+{
+	struct tc358743_state *state = to_state(sd);
+	u8 sys_int_mask = i2c_rd8(sd, SYS_INTM);
+	u8 sys_int = i2c_rd8(sd, SYS_INT) & ~sys_int_mask;
+
+	i2c_wr8(sd, SYS_INT, sys_int);
+
+	v4l2_dbg(3, debug, sd, "%s: SYS_INT = 0x%02x\n", __func__, sys_int);
+
+	if (sys_int & MASK_I_DDC) {
+		bool tx_5v = tx_5v_power_present(sd);
+
+		v4l2_dbg(1, debug, sd, "%s: Tx 5V power present: %s\n",
+				__func__, tx_5v ?  "yes" : "no");
+
+		if (tx_5v) {
+			tc358743_enable_edid(sd);
+		} else {
+			tc358743_enable_interrupts(sd, false);
+			tc358743_disable_edid(sd);
+			memset(&state->timings, 0, sizeof(state->timings));
+			tc358743_erase_bksv(sd);
+			tc358743_update_controls(sd);
+		}
+
+		sys_int &= ~MASK_I_DDC;
+		if (handled)
+			*handled = true;
+	}
+
+	if (sys_int & MASK_I_DVI) {
+		v4l2_dbg(1, debug, sd, "%s: HDMI->DVI change detected\n",
+				__func__);
+
+		/* Reset the HDMI PHY to try to trigger proper lock on the
+		 * incoming video format. Erase BKSV to prevent that old keys
+		 * are used when a new source is connected. */
+		if (no_sync(sd) || no_signal(sd)) {
+			tc358743_reset_phy(sd);
+			tc358743_erase_bksv(sd);
+		}
+
+		sys_int &= ~MASK_I_DVI;
+		if (handled)
+			*handled = true;
+	}
+
+	if (sys_int & MASK_I_HDMI) {
+		v4l2_dbg(1, debug, sd, "%s: DVI->HDMI change detected\n",
+				__func__);
+
+		/* Register is reset in DVI mode (REF_01, c. 6.6.41) */
+		i2c_wr8(sd, ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON);
+
+		sys_int &= ~MASK_I_HDMI;
+		if (handled)
+			*handled = true;
+	}
+
+	if (sys_int) {
+		v4l2_err(sd, "%s: Unhandled SYS_INT interrupts: 0x%02x\n",
+				__func__, sys_int);
+	}
+}
+
+/* --------------- CORE OPS --------------- */
+
+static int tc358743_log_status(struct v4l2_subdev *sd)
+{
+	struct tc358743_state *state = to_state(sd);
+	struct v4l2_dv_timings timings;
+	uint8_t hdmi_sys_status =  i2c_rd8(sd, SYS_STATUS);
+	uint16_t sysctl = i2c_rd16(sd, SYSCTL);
+	u8 vi_status3 =  i2c_rd8(sd, VI_STATUS3);
+	const int deep_color_mode[4] = { 8, 10, 12, 16 };
+	static const char * const input_color_space[] = {
+		"RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)",
+		"xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601",
+		"NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"};
+
+	v4l2_info(sd, "-----Chip status-----\n");
+	v4l2_info(sd, "Chip ID: 0x%02x\n",
+			(i2c_rd16(sd, CHIPID) & MASK_CHIPID) >> 8);
+	v4l2_info(sd, "Chip revision: 0x%02x\n",
+			i2c_rd16(sd, CHIPID) & MASK_REVID);
+	v4l2_info(sd, "Reset: IR: %d, CEC: %d, CSI TX: %d, HDMI: %d\n",
+			!!(sysctl & MASK_IRRST),
+			!!(sysctl & MASK_CECRST),
+			!!(sysctl & MASK_CTXRST),
+			!!(sysctl & MASK_HDMIRST));
+	v4l2_info(sd, "Sleep mode: %s\n", sysctl & MASK_SLEEP ? "on" : "off");
+	v4l2_info(sd, "Cable detected (+5V power): %s\n",
+			hdmi_sys_status & MASK_S_DDC5V ? "yes" : "no");
+	v4l2_info(sd, "DDC lines enabled: %s\n",
+			(i2c_rd8(sd, EDID_MODE) & MASK_EDID_MODE_E_DDC) ?
+			"yes" : "no");
+	v4l2_info(sd, "Hotplug enabled: %s\n",
+			(i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0) ?
+			"yes" : "no");
+	v4l2_info(sd, "CEC enabled: %s\n",
+			(i2c_rd16(sd, CECEN) & MASK_CECEN) ?  "yes" : "no");
+	v4l2_info(sd, "-----Signal status-----\n");
+	v4l2_info(sd, "TMDS signal detected: %s\n",
+			hdmi_sys_status & MASK_S_TMDS ? "yes" : "no");
+	v4l2_info(sd, "Stable sync signal: %s\n",
+			hdmi_sys_status & MASK_S_SYNC ? "yes" : "no");
+	v4l2_info(sd, "PHY PLL locked: %s\n",
+			hdmi_sys_status & MASK_S_PHY_PLL ? "yes" : "no");
+	v4l2_info(sd, "PHY DE detected: %s\n",
+			hdmi_sys_status & MASK_S_PHY_SCDT ? "yes" : "no");
+
+	if (tc358743_get_detected_timings(sd, &timings)) {
+		v4l2_info(sd, "No video detected\n");
+	} else {
+		v4l2_print_dv_timings(sd->name, "Detected format: ", &timings,
+				true);
+	}
+	v4l2_print_dv_timings(sd->name, "Configured format: ", &state->timings,
+			true);
+
+	v4l2_info(sd, "-----CSI-TX status-----\n");
+	v4l2_info(sd, "Lanes needed: %d\n",
+			tc358743_num_csi_lanes_needed(sd));
+	v4l2_info(sd, "Lanes in use: %d\n",
+			tc358743_num_csi_lanes_in_use(sd));
+	v4l2_info(sd, "Waiting for particular sync signal: %s\n",
+			(i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ?
+			"yes" : "no");
+	v4l2_info(sd, "Transmit mode: %s\n",
+			(i2c_rd16(sd, CSI_STATUS) & MASK_S_TXACT) ?
+			"yes" : "no");
+	v4l2_info(sd, "Receive mode: %s\n",
+			(i2c_rd16(sd, CSI_STATUS) & MASK_S_RXACT) ?
+			"yes" : "no");
+	v4l2_info(sd, "Stopped: %s\n",
+			(i2c_rd16(sd, CSI_STATUS) & MASK_S_HLT) ?
+			"yes" : "no");
+	v4l2_info(sd, "Color space: %s\n",
+			state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16 ?
+			"YCbCr 422 16-bit" :
+			state->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24 ?
+			"RGB 888 24-bit" : "Unsupported");
+
+	v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D");
+	v4l2_info(sd, "HDCP encrypted content: %s\n",
+			hdmi_sys_status & MASK_S_HDCP ? "yes" : "no");
+	v4l2_info(sd, "Input color space: %s %s range\n",
+			input_color_space[(vi_status3 & MASK_S_V_COLOR) >> 1],
+			(vi_status3 & MASK_LIMITED) ? "limited" : "full");
+	if (!is_hdmi(sd))
+		return 0;
+	v4l2_info(sd, "AV Mute: %s\n", hdmi_sys_status & MASK_S_AVMUTE ? "on" :
+			"off");
+	v4l2_info(sd, "Deep color mode: %d-bits per channel\n",
+			deep_color_mode[(i2c_rd8(sd, VI_STATUS1) &
+				MASK_S_DEEPCOLOR) >> 2]);
+	print_avi_infoframe(sd);
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static void tc358743_print_register_map(struct v4l2_subdev *sd)
+{
+	v4l2_info(sd, "0x0000–0x00FF: Global Control Register\n");
+	v4l2_info(sd, "0x0100–0x01FF: CSI2-TX PHY Register\n");
+	v4l2_info(sd, "0x0200–0x03FF: CSI2-TX PPI Register\n");
+	v4l2_info(sd, "0x0400–0x05FF: Reserved\n");
+	v4l2_info(sd, "0x0600–0x06FF: CEC Register\n");
+	v4l2_info(sd, "0x0700–0x84FF: Reserved\n");
+	v4l2_info(sd, "0x8500–0x85FF: HDMIRX System Control Register\n");
+	v4l2_info(sd, "0x8600–0x86FF: HDMIRX Audio Control Register\n");
+	v4l2_info(sd, "0x8700–0x87FF: HDMIRX InfoFrame packet data Register\n");
+	v4l2_info(sd, "0x8800–0x88FF: HDMIRX HDCP Port Register\n");
+	v4l2_info(sd, "0x8900–0x89FF: HDMIRX Video Output Port & 3D Register\n");
+	v4l2_info(sd, "0x8A00–0x8BFF: Reserved\n");
+	v4l2_info(sd, "0x8C00–0x8FFF: HDMIRX EDID-RAM (1024bytes)\n");
+	v4l2_info(sd, "0x9000–0x90FF: HDMIRX GBD Extraction Control\n");
+	v4l2_info(sd, "0x9100–0x92FF: HDMIRX GBD RAM read\n");
+	v4l2_info(sd, "0x9300-      : Reserved\n");
+}
+
+static int tc358743_get_reg_size(u16 address)
+{
+	/* REF_01 p. 66-72 */
+	if (address <= 0x00ff)
+		return 2;
+	else if ((address >= 0x0100) && (address <= 0x06FF))
+		return 4;
+	else if ((address >= 0x0700) && (address <= 0x84ff))
+		return 2;
+	else
+		return 1;
+}
+
+static int tc358743_g_register(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_register *reg)
+{
+	if (reg->reg > 0xffff) {
+		tc358743_print_register_map(sd);
+		return -EINVAL;
+	}
+
+	reg->size = tc358743_get_reg_size(reg->reg);
+
+	i2c_rd(sd, reg->reg, (u8 *)&reg->val, reg->size);
+
+	return 0;
+}
+
+static int tc358743_s_register(struct v4l2_subdev *sd,
+			       const struct v4l2_dbg_register *reg)
+{
+	if (reg->reg > 0xffff) {
+		tc358743_print_register_map(sd);
+		return -EINVAL;
+	}
+
+	/* It should not be possible for the user to enable HDCP with a simple
+	 * v4l2-dbg command.
+	 *
+	 * DO NOT REMOVE THIS unless all other issues with HDCP have been
+	 * resolved.
+	 */
+	if (reg->reg == HDCP_MODE ||
+	    reg->reg == HDCP_REG1 ||
+	    reg->reg == HDCP_REG2 ||
+	    reg->reg == HDCP_REG3 ||
+	    reg->reg == BCAPS)
+		return 0;
+
+	i2c_wr(sd, (u16)reg->reg, (u8 *)&reg->val,
+			tc358743_get_reg_size(reg->reg));
+
+	return 0;
+}
+#endif
+
+static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
+{
+	u16 intstatus = i2c_rd16(sd, INTSTATUS);
+
+	v4l2_dbg(1, debug, sd, "%s: IntStatus = 0x%04x\n", __func__, intstatus);
+
+	if (intstatus & MASK_HDMI_INT) {
+		u8 hdmi_int0 = i2c_rd8(sd, HDMI_INT0);
+		u8 hdmi_int1 = i2c_rd8(sd, HDMI_INT1);
+
+		if (hdmi_int0 & MASK_I_MISC)
+			tc358743_hdmi_misc_int_handler(sd, handled);
+		if (hdmi_int1 & MASK_I_CBIT)
+			tc358743_hdmi_cbit_int_handler(sd, handled);
+		if (hdmi_int1 & MASK_I_CLK)
+			tc358743_hdmi_clk_int_handler(sd, handled);
+		if (hdmi_int1 & MASK_I_SYS)
+			tc358743_hdmi_sys_int_handler(sd, handled);
+		if (hdmi_int1 & MASK_I_AUD)
+			tc358743_hdmi_audio_int_handler(sd, handled);
+
+		i2c_wr16(sd, INTSTATUS, MASK_HDMI_INT);
+		intstatus &= ~MASK_HDMI_INT;
+	}
+
+	if (intstatus & MASK_CSI_INT) {
+		u32 csi_int = i2c_rd32(sd, CSI_INT);
+
+		if (csi_int & MASK_INTER)
+			tc358743_csi_err_int_handler(sd, handled);
+
+		i2c_wr16(sd, INTSTATUS, MASK_CSI_INT);
+		intstatus &= ~MASK_CSI_INT;
+	}
+
+	intstatus = i2c_rd16(sd, INTSTATUS);
+	if (intstatus) {
+		v4l2_dbg(1, debug, sd,
+				"%s: Unhandled IntStatus interrupts: 0x%02x\n",
+				__func__, intstatus);
+	}
+
+	return 0;
+}
+
+static irqreturn_t tc358743_irq_handler(int irq, void *dev_id)
+{
+	struct tc358743_state *state = dev_id;
+	bool handled;
+
+	tc358743_isr(&state->sd, 0, &handled);
+
+	return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int tc358743_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+				    struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
+	default:
+		return -EINVAL;
+	}
+}
+
+/* --------------- VIDEO OPS --------------- */
+
+static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	*status = 0;
+	*status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0;
+	*status |= no_sync(sd) ? V4L2_IN_ST_NO_SYNC : 0;
+
+	v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status);
+
+	return 0;
+}
+
+static int tc358743_s_dv_timings(struct v4l2_subdev *sd,
+				 struct v4l2_dv_timings *timings)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	if (!timings)
+		return -EINVAL;
+
+	if (debug)
+		v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ",
+				timings, false);
+
+	if (v4l2_match_dv_timings(&state->timings, timings, 0)) {
+		v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
+		return 0;
+	}
+
+	if (!v4l2_valid_dv_timings(timings,
+				&tc358743_timings_cap, NULL, NULL)) {
+		v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__);
+		return -ERANGE;
+	}
+
+	state->timings = *timings;
+
+	enable_stream(sd, false);
+	tc358743_set_pll(sd);
+	tc358743_set_csi(sd);
+
+	return 0;
+}
+
+static int tc358743_g_dv_timings(struct v4l2_subdev *sd,
+				 struct v4l2_dv_timings *timings)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	*timings = state->timings;
+
+	return 0;
+}
+
+static int tc358743_enum_dv_timings(struct v4l2_subdev *sd,
+				    struct v4l2_enum_dv_timings *timings)
+{
+	if (timings->pad != 0)
+		return -EINVAL;
+
+	return v4l2_enum_dv_timings_cap(timings,
+			&tc358743_timings_cap, NULL, NULL);
+}
+
+static int tc358743_query_dv_timings(struct v4l2_subdev *sd,
+		struct v4l2_dv_timings *timings)
+{
+	int ret;
+
+	ret = tc358743_get_detected_timings(sd, timings);
+	if (ret)
+		return ret;
+
+	if (debug)
+		v4l2_print_dv_timings(sd->name, "tc358743_query_dv_timings: ",
+				timings, false);
+
+	if (!v4l2_valid_dv_timings(timings,
+				&tc358743_timings_cap, NULL, NULL)) {
+		v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__);
+		return -ERANGE;
+	}
+
+	return 0;
+}
+
+static int tc358743_dv_timings_cap(struct v4l2_subdev *sd,
+		struct v4l2_dv_timings_cap *cap)
+{
+	if (cap->pad != 0)
+		return -EINVAL;
+
+	*cap = tc358743_timings_cap;
+
+	return 0;
+}
+
+static int tc358743_g_mbus_config(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_config *cfg)
+{
+	cfg->type = V4L2_MBUS_CSI2;
+
+	/* Support for non-continuous CSI-2 clock is missing in the driver */
+	cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+	switch (tc358743_num_csi_lanes_in_use(sd)) {
+	case 1:
+		cfg->flags |= V4L2_MBUS_CSI2_1_LANE;
+		break;
+	case 2:
+		cfg->flags |= V4L2_MBUS_CSI2_2_LANE;
+		break;
+	case 3:
+		cfg->flags |= V4L2_MBUS_CSI2_3_LANE;
+		break;
+	case 4:
+		cfg->flags |= V4L2_MBUS_CSI2_4_LANE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tc358743_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	enable_stream(sd, enable);
+
+	return 0;
+}
+
+/* --------------- PAD OPS --------------- */
+
+static int tc358743_get_fmt(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_format *format)
+{
+	struct tc358743_state *state = to_state(sd);
+	u8 vi_rep = i2c_rd8(sd, VI_REP);
+
+	if (format->pad != 0)
+		return -EINVAL;
+
+	format->format.code = state->mbus_fmt_code;
+	format->format.width = state->timings.bt.width;
+	format->format.height = state->timings.bt.height;
+	format->format.field = V4L2_FIELD_NONE;
+
+	switch (vi_rep & MASK_VOUT_COLOR_SEL) {
+	case MASK_VOUT_COLOR_RGB_FULL:
+	case MASK_VOUT_COLOR_RGB_LIMITED:
+		format->format.colorspace = V4L2_COLORSPACE_SRGB;
+		break;
+	case MASK_VOUT_COLOR_601_YCBCR_LIMITED:
+	case MASK_VOUT_COLOR_601_YCBCR_FULL:
+		format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
+		break;
+	case MASK_VOUT_COLOR_709_YCBCR_FULL:
+	case MASK_VOUT_COLOR_709_YCBCR_LIMITED:
+		format->format.colorspace = V4L2_COLORSPACE_REC709;
+		break;
+	default:
+		format->format.colorspace = 0;
+		break;
+	}
+
+	return 0;
+}
+
+static int tc358743_set_fmt(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_format *format)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	u32 code = format->format.code; /* is overwritten by get_fmt */
+	int ret = tc358743_get_fmt(sd, cfg, format);
+
+	format->format.code = code;
+
+	if (ret)
+		return ret;
+
+	switch (code) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	state->mbus_fmt_code = format->format.code;
+
+	enable_stream(sd, false);
+	tc358743_set_pll(sd);
+	tc358743_set_csi(sd);
+	tc358743_set_csi_color_space(sd);
+
+	return 0;
+}
+
+static int tc358743_g_edid(struct v4l2_subdev *sd,
+		struct v4l2_subdev_edid *edid)
+{
+	struct tc358743_state *state = to_state(sd);
+
+	if (edid->pad != 0)
+		return -EINVAL;
+
+	if (edid->start_block == 0 && edid->blocks == 0) {
+		edid->blocks = state->edid_blocks_written;
+		return 0;
+	}
+
+	if (state->edid_blocks_written == 0)
+		return -ENODATA;
+
+	if (edid->start_block >= state->edid_blocks_written ||
+			edid->blocks == 0)
+		return -EINVAL;
+
+	if (edid->start_block + edid->blocks > state->edid_blocks_written)
+		edid->blocks = state->edid_blocks_written - edid->start_block;
+
+	i2c_rd(sd, EDID_RAM + (edid->start_block * EDID_BLOCK_SIZE), edid->edid,
+			edid->blocks * EDID_BLOCK_SIZE);
+
+	return 0;
+}
+
+static int tc358743_s_edid(struct v4l2_subdev *sd,
+				struct v4l2_subdev_edid *edid)
+{
+	struct tc358743_state *state = to_state(sd);
+	u16 edid_len = edid->blocks * EDID_BLOCK_SIZE;
+
+	v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n",
+		 __func__, edid->pad, edid->start_block, edid->blocks);
+
+	if (edid->pad != 0)
+		return -EINVAL;
+
+	if (edid->start_block != 0)
+		return -EINVAL;
+
+	if (edid->blocks > EDID_NUM_BLOCKS_MAX) {
+		edid->blocks = EDID_NUM_BLOCKS_MAX;
+		return -E2BIG;
+	}
+
+	tc358743_disable_edid(sd);
+
+	i2c_wr8(sd, EDID_LEN1, edid_len & 0xff);
+	i2c_wr8(sd, EDID_LEN2, edid_len >> 8);
+
+	if (edid->blocks == 0) {
+		state->edid_blocks_written = 0;
+		return 0;
+	}
+
+	i2c_wr(sd, EDID_RAM, edid->edid, edid_len);
+
+	state->edid_blocks_written = edid->blocks;
+
+	if (tx_5v_power_present(sd))
+		tc358743_enable_edid(sd);
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tc358743_core_ops = {
+	.log_status = tc358743_log_status,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = tc358743_g_register,
+	.s_register = tc358743_s_register,
+#endif
+	.interrupt_service_routine = tc358743_isr,
+	.subscribe_event = tc358743_subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops tc358743_video_ops = {
+	.g_input_status = tc358743_g_input_status,
+	.s_dv_timings = tc358743_s_dv_timings,
+	.g_dv_timings = tc358743_g_dv_timings,
+	.query_dv_timings = tc358743_query_dv_timings,
+	.g_mbus_config = tc358743_g_mbus_config,
+	.s_stream = tc358743_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops tc358743_pad_ops = {
+	.set_fmt = tc358743_set_fmt,
+	.get_fmt = tc358743_get_fmt,
+	.get_edid = tc358743_g_edid,
+	.set_edid = tc358743_s_edid,
+	.enum_dv_timings = tc358743_enum_dv_timings,
+	.dv_timings_cap = tc358743_dv_timings_cap,
+};
+
+static const struct v4l2_subdev_ops tc358743_ops = {
+	.core = &tc358743_core_ops,
+	.video = &tc358743_video_ops,
+	.pad = &tc358743_pad_ops,
+};
+
+/* --------------- CUSTOM CTRLS --------------- */
+
+static const struct v4l2_ctrl_config tc358743_ctrl_audio_sampling_rate = {
+	.id = TC358743_CID_AUDIO_SAMPLING_RATE,
+	.name = "Audio sampling rate",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = 768000,
+	.step = 1,
+	.def = 0,
+	.flags = V4L2_CTRL_FLAG_READ_ONLY,
+};
+
+static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = {
+	.id = TC358743_CID_AUDIO_PRESENT,
+	.name = "Audio present",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+	.def = 0,
+	.flags = V4L2_CTRL_FLAG_READ_ONLY,
+};
+
+/* --------------- PROBE / REMOVE --------------- */
+
+#ifdef CONFIG_OF
+static void tc358743_gpio_reset(struct tc358743_state *state)
+{
+	usleep_range(5000, 10000);
+	gpiod_set_value(state->reset_gpio, 1);
+	usleep_range(1000, 2000);
+	gpiod_set_value(state->reset_gpio, 0);
+	msleep(20);
+}
+
+static int tc358743_probe_of(struct tc358743_state *state)
+{
+	struct device *dev = &state->i2c_client->dev;
+	struct v4l2_of_endpoint *endpoint;
+	struct device_node *ep;
+	struct clk *refclk;
+	u32 bps_pr_lane;
+	int ret = -EINVAL;
+
+	refclk = devm_clk_get(dev, "refclk");
+	if (IS_ERR(refclk)) {
+		if (PTR_ERR(refclk) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get refclk: %ld\n",
+				PTR_ERR(refclk));
+		return PTR_ERR(refclk);
+	}
+
+	ep = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (!ep) {
+		dev_err(dev, "missing endpoint node\n");
+		return -EINVAL;
+	}
+
+	endpoint = v4l2_of_alloc_parse_endpoint(ep);
+	if (IS_ERR(endpoint)) {
+		dev_err(dev, "failed to parse endpoint\n");
+		return PTR_ERR(endpoint);
+	}
+
+	if (endpoint->bus_type != V4L2_MBUS_CSI2 ||
+	    endpoint->bus.mipi_csi2.num_data_lanes == 0 ||
+	    endpoint->nr_of_link_frequencies == 0) {
+		dev_err(dev, "missing CSI-2 properties in endpoint\n");
+		goto free_endpoint;
+	}
+
+	state->bus = endpoint->bus.mipi_csi2;
+
+	clk_prepare_enable(refclk);
+
+	state->pdata.refclk_hz = clk_get_rate(refclk);
+	state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS;
+	state->pdata.enable_hdcp = false;
+	/* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */
+	state->pdata.fifo_level = 16;
+	/*
+	 * The PLL input clock is obtained by dividing refclk by pll_prd.
+	 * It must be between 6 MHz and 40 MHz, lower frequency is better.
+	 */
+	switch (state->pdata.refclk_hz) {
+	case 26000000:
+	case 27000000:
+	case 42000000:
+		state->pdata.pll_prd = state->pdata.refclk_hz / 6000000;
+		break;
+	default:
+		dev_err(dev, "unsupported refclk rate: %u Hz\n",
+			state->pdata.refclk_hz);
+		goto disable_clk;
+	}
+
+	/*
+	 * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
+	 * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60.
+	 */
+	bps_pr_lane = 2 * endpoint->link_frequencies[0];
+	if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
+		dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane);
+		goto disable_clk;
+	}
+
+	/* The CSI speed per lane is refclk / pll_prd * pll_fbd */
+	state->pdata.pll_fbd = bps_pr_lane /
+			       state->pdata.refclk_hz * state->pdata.pll_prd;
+
+	/*
+	 * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz
+	 * link frequency). In principle it should be possible to calculate
+	 * them based on link frequency and resolution.
+	 */
+	if (bps_pr_lane != 594000000U)
+		dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane);
+	state->pdata.lineinitcnt = 0xe80;
+	state->pdata.lptxtimecnt = 0x003;
+	/* tclk-preparecnt: 3, tclk-zerocnt: 20 */
+	state->pdata.tclk_headercnt = 0x1403;
+	state->pdata.tclk_trailcnt = 0x00;
+	/* ths-preparecnt: 3, ths-zerocnt: 1 */
+	state->pdata.ths_headercnt = 0x0103;
+	state->pdata.twakeup = 0x4882;
+	state->pdata.tclk_postcnt = 0x008;
+	state->pdata.ths_trailcnt = 0x2;
+	state->pdata.hstxvregcnt = 0;
+
+	state->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						    GPIOD_OUT_LOW);
+	if (IS_ERR(state->reset_gpio)) {
+		dev_err(dev, "failed to get reset gpio\n");
+		ret = PTR_ERR(state->reset_gpio);
+		goto disable_clk;
+	}
+
+	if (state->reset_gpio)
+		tc358743_gpio_reset(state);
+
+	ret = 0;
+	goto free_endpoint;
+
+disable_clk:
+	clk_disable_unprepare(refclk);
+free_endpoint:
+	v4l2_of_free_endpoint(endpoint);
+	return ret;
+}
+#else
+static inline int tc358743_probe_of(struct tc358743_state *state)
+{
+	return -ENODEV;
+}
+#endif
+
+static int tc358743_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	static struct v4l2_dv_timings default_timing =
+		V4L2_DV_BT_CEA_640X480P59_94;
+	struct tc358743_state *state;
+	struct tc358743_platform_data *pdata = client->dev.platform_data;
+	struct v4l2_subdev *sd;
+	int err;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+	v4l_dbg(1, debug, client, "chip found @ 0x%x (%s)\n",
+		client->addr << 1, client->adapter->name);
+
+	state = devm_kzalloc(&client->dev, sizeof(struct tc358743_state),
+			GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	state->i2c_client = client;
+
+	/* platform data */
+	if (pdata) {
+		state->pdata = *pdata;
+		state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+	} else {
+		err = tc358743_probe_of(state);
+		if (err == -ENODEV)
+			v4l_err(client, "No platform data!\n");
+		if (err)
+			return err;
+	}
+
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &tc358743_ops);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+
+	/* i2c access */
+	if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) {
+		v4l2_info(sd, "not a TC358743 on address 0x%x\n",
+			  client->addr << 1);
+		return -ENODEV;
+	}
+
+	/* control handlers */
+	v4l2_ctrl_handler_init(&state->hdl, 3);
+
+	/* private controls */
+	state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL,
+			V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0);
+
+	/* custom controls */
+	state->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&state->hdl,
+			&tc358743_ctrl_audio_sampling_rate, NULL);
+
+	state->audio_present_ctrl = v4l2_ctrl_new_custom(&state->hdl,
+			&tc358743_ctrl_audio_present, NULL);
+
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		err = state->hdl.error;
+		goto err_hdl;
+	}
+
+	if (tc358743_update_controls(sd)) {
+		err = -ENODEV;
+		goto err_hdl;
+	}
+
+	/* work queues */
+	state->work_queues = create_singlethread_workqueue(client->name);
+	if (!state->work_queues) {
+		v4l2_err(sd, "Could not create work queue\n");
+		err = -ENOMEM;
+		goto err_hdl;
+	}
+
+	state->pad.flags = MEDIA_PAD_FL_SOURCE;
+	err = media_entity_init(&sd->entity, 1, &state->pad, 0);
+	if (err < 0)
+		goto err_hdl;
+
+	sd->dev = &client->dev;
+	err = v4l2_async_register_subdev(sd);
+	if (err < 0)
+		goto err_hdl;
+
+	mutex_init(&state->confctl_mutex);
+
+	INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,
+			tc358743_delayed_work_enable_hotplug);
+
+	tc358743_initial_setup(sd);
+
+	tc358743_s_dv_timings(sd, &default_timing);
+
+	state->mbus_fmt_code = MEDIA_BUS_FMT_RGB888_1X24;
+	tc358743_set_csi_color_space(sd);
+
+	tc358743_init_interrupts(sd);
+
+	if (state->i2c_client->irq) {
+		err = devm_request_threaded_irq(&client->dev,
+						state->i2c_client->irq,
+						NULL, tc358743_irq_handler,
+						IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+						"tc358743", state);
+		if (err)
+			goto err_work_queues;
+	}
+
+	tc358743_enable_interrupts(sd, tx_5v_power_present(sd));
+	i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff);
+
+	err = v4l2_ctrl_handler_setup(sd->ctrl_handler);
+	if (err)
+		goto err_work_queues;
+
+	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
+		  client->addr << 1, client->adapter->name);
+
+	return 0;
+
+err_work_queues:
+	cancel_delayed_work(&state->delayed_work_enable_hotplug);
+	destroy_workqueue(state->work_queues);
+	mutex_destroy(&state->confctl_mutex);
+err_hdl:
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(&state->hdl);
+	return err;
+}
+
+static int tc358743_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct tc358743_state *state = to_state(sd);
+
+	cancel_delayed_work(&state->delayed_work_enable_hotplug);
+	destroy_workqueue(state->work_queues);
+	v4l2_async_unregister_subdev(sd);
+	v4l2_device_unregister_subdev(sd);
+	mutex_destroy(&state->confctl_mutex);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(&state->hdl);
+
+	return 0;
+}
+
+static struct i2c_device_id tc358743_id[] = {
+	{"tc358743", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tc358743_id);
+
+static struct i2c_driver tc358743_driver = {
+	.driver = {
+		.name = "tc358743",
+	},
+	.probe = tc358743_probe,
+	.remove = tc358743_remove,
+	.id_table = tc358743_id,
+};
+
+module_i2c_driver(tc358743_driver);

+ 681 - 0
drivers/media/i2c/tc358743_regs.h

@@ -0,0 +1,681 @@
+/*
+ * tc358743 - Toshiba HDMI to CSI-2 bridge - register names and bit masks
+ *
+ * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
+ * reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/*
+ * References (c = chapter, p = page):
+ * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60
+ */
+
+/* Bit masks has prefix 'MASK_' and options after '_'. */
+
+#ifndef __TC358743_REGS_H
+#define __TC358743_REGS_H
+
+#define CHIPID                                0x0000
+#define MASK_CHIPID                           0xff00
+#define MASK_REVID                            0x00ff
+
+#define SYSCTL                                0x0002
+#define MASK_IRRST                            0x0800
+#define MASK_CECRST                           0x0400
+#define MASK_CTXRST                           0x0200
+#define MASK_HDMIRST                          0x0100
+#define MASK_SLEEP                            0x0001
+
+#define CONFCTL                               0x0004
+#define MASK_PWRISO                           0x8000
+#define MASK_ACLKOPT                          0x1000
+#define MASK_AUDCHNUM                         0x0c00
+#define MASK_AUDCHNUM_8                       0x0000
+#define MASK_AUDCHNUM_6                       0x0400
+#define MASK_AUDCHNUM_4                       0x0800
+#define MASK_AUDCHNUM_2                       0x0c00
+#define MASK_AUDCHSEL                         0x0200
+#define MASK_I2SDLYOPT                        0x0100
+#define MASK_YCBCRFMT                         0x00c0
+#define MASK_YCBCRFMT_444                     0x0000
+#define MASK_YCBCRFMT_422_12_BIT              0x0040
+#define MASK_YCBCRFMT_COLORBAR                0x0080
+#define MASK_YCBCRFMT_422_8_BIT               0x00c0
+#define MASK_INFRMEN                          0x0020
+#define MASK_AUDOUTSEL                        0x0018
+#define MASK_AUDOUTSEL_CSI                    0x0000
+#define MASK_AUDOUTSEL_I2S                    0x0010
+#define MASK_AUDOUTSEL_TDM                    0x0018
+#define MASK_AUTOINDEX                        0x0004
+#define MASK_ABUFEN                           0x0002
+#define MASK_VBUFEN                           0x0001
+
+#define FIFOCTL                               0x0006
+
+#define INTSTATUS                             0x0014
+#define MASK_AMUTE_INT                        0x0400
+#define MASK_HDMI_INT                         0x0200
+#define MASK_CSI_INT                          0x0100
+#define MASK_SYS_INT                          0x0020
+#define MASK_CEC_EINT                         0x0010
+#define MASK_CEC_TINT                         0x0008
+#define MASK_CEC_RINT                         0x0004
+#define MASK_IR_EINT                          0x0002
+#define MASK_IR_DINT                          0x0001
+
+#define INTMASK                               0x0016
+#define MASK_AMUTE_MSK                        0x0400
+#define MASK_HDMI_MSK                         0x0200
+#define MASK_CSI_MSK                          0x0100
+#define MASK_SYS_MSK                          0x0020
+#define MASK_CEC_EMSK                         0x0010
+#define MASK_CEC_TMSK                         0x0008
+#define MASK_CEC_RMSK                         0x0004
+#define MASK_IR_EMSK                          0x0002
+#define MASK_IR_DMSK                          0x0001
+
+#define INTFLAG                               0x0018
+#define INTSYSSTATUS                          0x001A
+
+#define PLLCTL0                               0x0020
+#define MASK_PLL_PRD                          0xf000
+#define SET_PLL_PRD(prd)                      ((((prd) - 1) << 12) &\
+						MASK_PLL_PRD)
+#define MASK_PLL_FBD                          0x01ff
+#define SET_PLL_FBD(fbd)                      (((fbd) - 1) & MASK_PLL_FBD)
+
+#define PLLCTL1                               0x0022
+#define MASK_PLL_FRS                          0x0c00
+#define SET_PLL_FRS(frs)                      (((frs) << 10) & MASK_PLL_FRS)
+#define MASK_PLL_LBWS                         0x0300
+#define MASK_LFBREN                           0x0040
+#define MASK_BYPCKEN                          0x0020
+#define MASK_CKEN                             0x0010
+#define MASK_RESETB                           0x0002
+#define MASK_PLL_EN                           0x0001
+
+#define CLW_CNTRL                             0x0140
+#define MASK_CLW_LANEDISABLE                  0x0001
+
+#define D0W_CNTRL                             0x0144
+#define MASK_D0W_LANEDISABLE                  0x0001
+
+#define D1W_CNTRL                             0x0148
+#define MASK_D1W_LANEDISABLE                  0x0001
+
+#define D2W_CNTRL                             0x014C
+#define MASK_D2W_LANEDISABLE                  0x0001
+
+#define D3W_CNTRL                             0x0150
+#define MASK_D3W_LANEDISABLE                  0x0001
+
+#define STARTCNTRL                            0x0204
+#define MASK_START                            0x00000001
+
+#define LINEINITCNT                           0x0210
+#define LPTXTIMECNT                           0x0214
+#define TCLK_HEADERCNT                        0x0218
+#define TCLK_TRAILCNT                         0x021C
+#define THS_HEADERCNT                         0x0220
+#define TWAKEUP                               0x0224
+#define TCLK_POSTCNT                          0x0228
+#define THS_TRAILCNT                          0x022C
+#define HSTXVREGCNT                           0x0230
+
+#define HSTXVREGEN                            0x0234
+#define MASK_D3M_HSTXVREGEN                   0x0010
+#define MASK_D2M_HSTXVREGEN                   0x0008
+#define MASK_D1M_HSTXVREGEN                   0x0004
+#define MASK_D0M_HSTXVREGEN                   0x0002
+#define MASK_CLM_HSTXVREGEN                   0x0001
+
+
+#define TXOPTIONCNTRL                         0x0238
+#define MASK_CONTCLKMODE                      0x00000001
+
+#define CSI_CONTROL                           0x040C
+#define MASK_CSI_MODE                         0x8000
+#define MASK_HTXTOEN                          0x0400
+#define MASK_TXHSMD                           0x0080
+#define MASK_HSCKMD                           0x0020
+#define MASK_NOL                              0x0006
+#define MASK_NOL_1                            0x0000
+#define MASK_NOL_2                            0x0002
+#define MASK_NOL_3                            0x0004
+#define MASK_NOL_4                            0x0006
+#define MASK_EOTDIS                           0x0001
+
+#define CSI_INT                               0x0414
+#define MASK_INTHLT                           0x00000008
+#define MASK_INTER                            0x00000004
+
+#define CSI_INT_ENA                           0x0418
+#define MASK_IENHLT                           0x00000008
+#define MASK_IENER                            0x00000004
+
+#define CSI_ERR                               0x044C
+#define MASK_INER                             0x00000200
+#define MASK_WCER                             0x00000100
+#define MASK_QUNK                             0x00000010
+#define MASK_TXBRK                            0x00000002
+
+#define CSI_ERR_INTENA                        0x0450
+#define CSI_ERR_HALT                          0x0454
+
+#define CSI_CONFW                             0x0500
+#define MASK_MODE                             0xe0000000
+#define MASK_MODE_SET                         0xa0000000
+#define MASK_MODE_CLEAR                       0xc0000000
+#define MASK_ADDRESS                          0x1f000000
+#define MASK_ADDRESS_CSI_CONTROL              0x03000000
+#define MASK_ADDRESS_CSI_INT_ENA              0x06000000
+#define MASK_ADDRESS_CSI_ERR_INTENA           0x14000000
+#define MASK_ADDRESS_CSI_ERR_HALT             0x15000000
+#define MASK_DATA                             0x0000ffff
+
+#define CSI_INT_CLR                           0x050C
+#define MASK_ICRER                            0x00000004
+
+#define CSI_START                             0x0518
+#define MASK_STRT                             0x00000001
+
+#define CECEN                                 0x0600
+#define MASK_CECEN                            0x0001
+
+#define HDMI_INT0                             0x8500
+#define MASK_I_KEY                            0x80
+#define MASK_I_MISC                           0x02
+#define MASK_I_PHYERR                         0x01
+
+#define HDMI_INT1                             0x8501
+#define MASK_I_GBD                            0x80
+#define MASK_I_HDCP                           0x40
+#define MASK_I_ERR                            0x20
+#define MASK_I_AUD                            0x10
+#define MASK_I_CBIT                           0x08
+#define MASK_I_PACKET                         0x04
+#define MASK_I_CLK                            0x02
+#define MASK_I_SYS                            0x01
+
+#define SYS_INT                               0x8502
+#define MASK_I_ACR_CTS                        0x80
+#define MASK_I_ACRN                           0x40
+#define MASK_I_DVI                            0x20
+#define MASK_I_HDMI                           0x10
+#define MASK_I_NOPMBDET                       0x08
+#define MASK_I_DPMBDET                        0x04
+#define MASK_I_TMDS                           0x02
+#define MASK_I_DDC                            0x01
+
+#define CLK_INT                               0x8503
+#define MASK_I_OUT_H_CHG                      0x40
+#define MASK_I_IN_DE_CHG                      0x20
+#define MASK_I_IN_HV_CHG                      0x10
+#define MASK_I_DC_CHG                         0x08
+#define MASK_I_PXCLK_CHG                      0x04
+#define MASK_I_PHYCLK_CHG                     0x02
+#define MASK_I_TMDSCLK_CHG                    0x01
+
+#define CBIT_INT                              0x8505
+#define MASK_I_AF_LOCK                        0x80
+#define MASK_I_AF_UNLOCK                      0x40
+#define MASK_I_CBIT_FS                        0x02
+
+#define AUDIO_INT                             0x8506
+
+#define ERR_INT                               0x8507
+#define MASK_I_EESS_ERR                       0x80
+
+#define HDCP_INT                              0x8508
+#define MASK_I_AVM_SET                        0x80
+#define MASK_I_AVM_CLR                        0x40
+#define MASK_I_LINKERR                        0x20
+#define MASK_I_SHA_END                        0x10
+#define MASK_I_R0_END                         0x08
+#define MASK_I_KM_END                         0x04
+#define MASK_I_AKSV_END                       0x02
+#define MASK_I_AN_END                         0x01
+
+#define MISC_INT                              0x850B
+#define MASK_I_AS_LAYOUT                      0x10
+#define MASK_I_NO_SPD                         0x08
+#define MASK_I_NO_VS                          0x03
+#define MASK_I_SYNC_CHG                       0x02
+#define MASK_I_AUDIO_MUTE                     0x01
+
+#define KEY_INT                               0x850F
+
+#define SYS_INTM                              0x8512
+#define MASK_M_ACR_CTS                        0x80
+#define MASK_M_ACR_N                          0x40
+#define MASK_M_DVI_DET                        0x20
+#define MASK_M_HDMI_DET                       0x10
+#define MASK_M_NOPMBDET                       0x08
+#define MASK_M_BPMBDET                        0x04
+#define MASK_M_TMDS                           0x02
+#define MASK_M_DDC                            0x01
+
+#define CLK_INTM                              0x8513
+#define MASK_M_OUT_H_CHG                      0x40
+#define MASK_M_IN_DE_CHG                      0x20
+#define MASK_M_IN_HV_CHG                      0x10
+#define MASK_M_DC_CHG                         0x08
+#define MASK_M_PXCLK_CHG                      0x04
+#define MASK_M_PHYCLK_CHG                     0x02
+#define MASK_M_TMDS_CHG                       0x01
+
+#define PACKET_INTM                           0x8514
+
+#define CBIT_INTM                             0x8515
+#define MASK_M_AF_LOCK                        0x80
+#define MASK_M_AF_UNLOCK                      0x40
+#define MASK_M_CBIT_FS                        0x02
+
+#define AUDIO_INTM                            0x8516
+#define MASK_M_BUFINIT_END                    0x01
+
+#define ERR_INTM                              0x8517
+#define MASK_M_EESS_ERR                       0x80
+
+#define HDCP_INTM                             0x8518
+#define MASK_M_AVM_SET                        0x80
+#define MASK_M_AVM_CLR                        0x40
+#define MASK_M_LINKERR                        0x20
+#define MASK_M_SHA_END                        0x10
+#define MASK_M_R0_END                         0x08
+#define MASK_M_KM_END                         0x04
+#define MASK_M_AKSV_END                       0x02
+#define MASK_M_AN_END                         0x01
+
+#define MISC_INTM                             0x851B
+#define MASK_M_AS_LAYOUT                      0x10
+#define MASK_M_NO_SPD                         0x08
+#define MASK_M_NO_VS                          0x03
+#define MASK_M_SYNC_CHG                       0x02
+#define MASK_M_AUDIO_MUTE                     0x01
+
+#define KEY_INTM                              0x851F
+
+#define SYS_STATUS                            0x8520
+#define MASK_S_SYNC                           0x80
+#define MASK_S_AVMUTE                         0x40
+#define MASK_S_HDCP                           0x20
+#define MASK_S_HDMI                           0x10
+#define MASK_S_PHY_SCDT                       0x08
+#define MASK_S_PHY_PLL                        0x04
+#define MASK_S_TMDS                           0x02
+#define MASK_S_DDC5V                          0x01
+
+#define CSI_STATUS                            0x0410
+#define MASK_S_WSYNC                          0x0400
+#define MASK_S_TXACT                          0x0200
+#define MASK_S_RXACT                          0x0100
+#define MASK_S_HLT                            0x0001
+
+#define VI_STATUS1                            0x8522
+#define MASK_S_V_GBD                          0x08
+#define MASK_S_DEEPCOLOR                      0x0c
+#define MASK_S_V_422                          0x02
+#define MASK_S_V_INTERLACE                    0x01
+
+#define AU_STATUS0                            0x8523
+#define MASK_S_A_SAMPLE                       0x01
+
+#define VI_STATUS3                            0x8528
+#define MASK_S_V_COLOR                        0x1e
+#define MASK_LIMITED                          0x01
+
+#define PHY_CTL0                              0x8531
+#define MASK_PHY_SYSCLK_IND                   0x02
+#define MASK_PHY_CTL                          0x01
+
+
+#define PHY_CTL1                              0x8532 /* Not in REF_01 */
+#define MASK_PHY_AUTO_RST1                    0xf0
+#define MASK_PHY_AUTO_RST1_OFF                0x00
+#define SET_PHY_AUTO_RST1_US(us)             ((((us) / 200) << 4) & \
+						MASK_PHY_AUTO_RST1)
+#define MASK_FREQ_RANGE_MODE                  0x0f
+#define SET_FREQ_RANGE_MODE_CYCLES(cycles)   (((cycles) - 1) & \
+						MASK_FREQ_RANGE_MODE)
+
+#define PHY_CTL2                              0x8533 /* Not in REF_01 */
+#define MASK_PHY_AUTO_RST4                    0x04
+#define MASK_PHY_AUTO_RST3                    0x02
+#define MASK_PHY_AUTO_RST2                    0x01
+#define MASK_PHY_AUTO_RSTn                    (MASK_PHY_AUTO_RST4 | \
+						MASK_PHY_AUTO_RST3 | \
+						MASK_PHY_AUTO_RST2)
+
+#define PHY_EN                                0x8534
+#define MASK_ENABLE_PHY                       0x01
+
+#define PHY_RST                               0x8535
+#define MASK_RESET_CTRL                       0x01   /* Reset active low */
+
+#define PHY_BIAS                              0x8536 /* Not in REF_01 */
+
+#define PHY_CSQ                               0x853F /* Not in REF_01 */
+#define MASK_CSQ_CNT                          0x0f
+#define SET_CSQ_CNT_LEVEL(n)                 (n & MASK_CSQ_CNT)
+
+#define SYS_FREQ0                             0x8540
+#define SYS_FREQ1                             0x8541
+
+#define SYS_CLK                               0x8542 /* Not in REF_01 */
+#define MASK_CLK_DIFF                         0x0C
+#define MASK_CLK_DIV                          0x03
+
+#define DDC_CTL                               0x8543
+#define MASK_DDC_ACK_POL                      0x08
+#define MASK_DDC_ACTION                       0x04
+#define MASK_DDC5V_MODE                       0x03
+#define MASK_DDC5V_MODE_0MS                   0x00
+#define MASK_DDC5V_MODE_50MS                  0x01
+#define MASK_DDC5V_MODE_100MS                 0x02
+#define MASK_DDC5V_MODE_200MS                 0x03
+
+#define HPD_CTL                               0x8544
+#define MASK_HPD_CTL0                         0x10
+#define MASK_HPD_OUT0                         0x01
+
+#define ANA_CTL                               0x8545
+#define MASK_APPL_PCSX                        0x30
+#define MASK_APPL_PCSX_HIZ                    0x00
+#define MASK_APPL_PCSX_L_FIX                  0x10
+#define MASK_APPL_PCSX_H_FIX                  0x20
+#define MASK_APPL_PCSX_NORMAL                 0x30
+#define MASK_ANALOG_ON                        0x01
+
+#define AVM_CTL                               0x8546
+
+#define INIT_END                              0x854A
+#define MASK_INIT_END                         0x01
+
+#define HDMI_DET                              0x8552 /* Not in REF_01 */
+#define MASK_HDMI_DET_MOD1                    0x80
+#define MASK_HDMI_DET_MOD0                    0x40
+#define MASK_HDMI_DET_V                       0x30
+#define MASK_HDMI_DET_V_SYNC                  0x00
+#define MASK_HDMI_DET_V_ASYNC_25MS            0x10
+#define MASK_HDMI_DET_V_ASYNC_50MS            0x20
+#define MASK_HDMI_DET_V_ASYNC_100MS           0x30
+#define MASK_HDMI_DET_NUM                     0x0f
+
+#define HDCP_MODE                             0x8560
+#define MASK_MODE_RST_TN                      0x20
+#define MASK_LINE_REKEY                       0x10
+#define MASK_AUTO_CLR                         0x04
+
+#define HDCP_REG1                             0x8563 /* Not in REF_01 */
+#define MASK_AUTH_UNAUTH_SEL                  0x70
+#define MASK_AUTH_UNAUTH_SEL_12_FRAMES        0x70
+#define MASK_AUTH_UNAUTH_SEL_8_FRAMES         0x60
+#define MASK_AUTH_UNAUTH_SEL_4_FRAMES         0x50
+#define MASK_AUTH_UNAUTH_SEL_2_FRAMES         0x40
+#define MASK_AUTH_UNAUTH_SEL_64_FRAMES        0x30
+#define MASK_AUTH_UNAUTH_SEL_32_FRAMES        0x20
+#define MASK_AUTH_UNAUTH_SEL_16_FRAMES        0x10
+#define MASK_AUTH_UNAUTH_SEL_ONCE             0x00
+#define MASK_AUTH_UNAUTH                      0x01
+#define MASK_AUTH_UNAUTH_AUTO                 0x01
+
+#define HDCP_REG2                             0x8564 /* Not in REF_01 */
+#define MASK_AUTO_P3_RESET                    0x0F
+#define SET_AUTO_P3_RESET_FRAMES(n)          (n & MASK_AUTO_P3_RESET)
+#define MASK_AUTO_P3_RESET_OFF                0x00
+
+#define VI_MODE                               0x8570
+#define MASK_RGB_DVI                          0x08 /* Not in REF_01 */
+
+#define VOUT_SET2                             0x8573
+#define MASK_SEL422                           0x80
+#define MASK_VOUT_422FIL_100                  0x40
+#define MASK_VOUTCOLORMODE                    0x03
+#define MASK_VOUTCOLORMODE_THROUGH            0x00
+#define MASK_VOUTCOLORMODE_AUTO               0x01
+#define MASK_VOUTCOLORMODE_MANUAL             0x03
+
+#define VOUT_SET3                             0x8574
+#define MASK_VOUT_EXTCNT                      0x08
+
+#define VI_REP                                0x8576
+#define MASK_VOUT_COLOR_SEL                   0xe0
+#define MASK_VOUT_COLOR_RGB_FULL              0x00
+#define MASK_VOUT_COLOR_RGB_LIMITED           0x20
+#define MASK_VOUT_COLOR_601_YCBCR_FULL        0x40
+#define MASK_VOUT_COLOR_601_YCBCR_LIMITED     0x60
+#define MASK_VOUT_COLOR_709_YCBCR_FULL        0x80
+#define MASK_VOUT_COLOR_709_YCBCR_LIMITED     0xa0
+#define MASK_VOUT_COLOR_FULL_TO_LIMITED       0xc0
+#define MASK_VOUT_COLOR_LIMITED_TO_FULL       0xe0
+#define MASK_IN_REP_HEN                       0x10
+#define MASK_IN_REP                           0x0f
+
+#define VI_MUTE                               0x857F
+#define MASK_AUTO_MUTE                        0xc0
+#define MASK_VI_MUTE                          0x10
+
+#define DE_WIDTH_H_LO                         0x8582 /* Not in REF_01 */
+#define DE_WIDTH_H_HI                         0x8583 /* Not in REF_01 */
+#define DE_WIDTH_V_LO                         0x8588 /* Not in REF_01 */
+#define DE_WIDTH_V_HI                         0x8589 /* Not in REF_01 */
+#define H_SIZE_LO                             0x858A /* Not in REF_01 */
+#define H_SIZE_HI                             0x858B /* Not in REF_01 */
+#define V_SIZE_LO                             0x858C /* Not in REF_01 */
+#define V_SIZE_HI                             0x858D /* Not in REF_01 */
+#define FV_CNT_LO                             0x85A1 /* Not in REF_01 */
+#define FV_CNT_HI                             0x85A2 /* Not in REF_01 */
+
+#define FH_MIN0                               0x85AA /* Not in REF_01 */
+#define FH_MIN1                               0x85AB /* Not in REF_01 */
+#define FH_MAX0                               0x85AC /* Not in REF_01 */
+#define FH_MAX1                               0x85AD /* Not in REF_01 */
+
+#define HV_RST                                0x85AF /* Not in REF_01 */
+#define MASK_H_PI_RST                         0x20
+#define MASK_V_PI_RST                         0x10
+
+#define EDID_MODE                             0x85C7
+#define MASK_EDID_SPEED                       0x40
+#define MASK_EDID_MODE                        0x03
+#define MASK_EDID_MODE_DISABLE                0x00
+#define MASK_EDID_MODE_DDC2B                  0x01
+#define MASK_EDID_MODE_E_DDC                  0x02
+
+#define EDID_LEN1                             0x85CA
+#define EDID_LEN2                             0x85CB
+
+#define HDCP_REG3                             0x85D1 /* Not in REF_01 */
+#define KEY_RD_CMD                            0x01
+
+#define FORCE_MUTE                            0x8600
+#define MASK_FORCE_AMUTE                      0x10
+#define MASK_FORCE_DMUTE                      0x01
+
+#define CMD_AUD                               0x8601
+#define MASK_CMD_BUFINIT                      0x04
+#define MASK_CMD_LOCKDET                      0x02
+#define MASK_CMD_MUTE                         0x01
+
+#define AUTO_CMD0                             0x8602
+#define MASK_AUTO_MUTE7                       0x80
+#define MASK_AUTO_MUTE6                       0x40
+#define MASK_AUTO_MUTE5                       0x20
+#define MASK_AUTO_MUTE4                       0x10
+#define MASK_AUTO_MUTE3                       0x08
+#define MASK_AUTO_MUTE2                       0x04
+#define MASK_AUTO_MUTE1                       0x02
+#define MASK_AUTO_MUTE0                       0x01
+
+#define AUTO_CMD1                             0x8603
+#define MASK_AUTO_MUTE10                      0x04
+#define MASK_AUTO_MUTE9                       0x02
+#define MASK_AUTO_MUTE8                       0x01
+
+#define AUTO_CMD2                             0x8604
+#define MASK_AUTO_PLAY3                       0x08
+#define MASK_AUTO_PLAY2                       0x04
+
+#define BUFINIT_START                         0x8606
+#define SET_BUFINIT_START_MS(milliseconds)   ((milliseconds) / 100)
+
+#define FS_MUTE                               0x8607
+#define MASK_FS_ELSE_MUTE                     0x80
+#define MASK_FS22_MUTE                        0x40
+#define MASK_FS24_MUTE                        0x20
+#define MASK_FS88_MUTE                        0x10
+#define MASK_FS96_MUTE                        0x08
+#define MASK_FS176_MUTE                       0x04
+#define MASK_FS192_MUTE                       0x02
+#define MASK_FS_NO_MUTE                       0x01
+
+#define FS_IMODE                              0x8620
+#define MASK_NLPCM_HMODE                      0x40
+#define MASK_NLPCM_SMODE                      0x20
+#define MASK_NLPCM_IMODE                      0x10
+#define MASK_FS_HMODE                         0x08
+#define MASK_FS_AMODE                         0x04
+#define MASK_FS_SMODE                         0x02
+#define MASK_FS_IMODE                         0x01
+
+#define FS_SET                                0x8621
+#define MASK_FS                               0x0f
+
+#define LOCKDET_REF0                          0x8630
+#define LOCKDET_REF1                          0x8631
+#define LOCKDET_REF2                          0x8632
+
+#define ACR_MODE                              0x8640
+#define MASK_ACR_LOAD                         0x10
+#define MASK_N_MODE                           0x04
+#define MASK_CTS_MODE                         0x01
+
+#define ACR_MDF0                              0x8641
+#define MASK_ACR_L2MDF                        0x70
+#define MASK_ACR_L2MDF_0_PPM                  0x00
+#define MASK_ACR_L2MDF_61_PPM                 0x10
+#define MASK_ACR_L2MDF_122_PPM                0x20
+#define MASK_ACR_L2MDF_244_PPM                0x30
+#define MASK_ACR_L2MDF_488_PPM                0x40
+#define MASK_ACR_L2MDF_976_PPM                0x50
+#define MASK_ACR_L2MDF_1976_PPM               0x60
+#define MASK_ACR_L2MDF_3906_PPM               0x70
+#define MASK_ACR_L1MDF                        0x07
+#define MASK_ACR_L1MDF_0_PPM                  0x00
+#define MASK_ACR_L1MDF_61_PPM                 0x01
+#define MASK_ACR_L1MDF_122_PPM                0x02
+#define MASK_ACR_L1MDF_244_PPM                0x03
+#define MASK_ACR_L1MDF_488_PPM                0x04
+#define MASK_ACR_L1MDF_976_PPM                0x05
+#define MASK_ACR_L1MDF_1976_PPM               0x06
+#define MASK_ACR_L1MDF_3906_PPM               0x07
+
+#define ACR_MDF1                              0x8642
+#define MASK_ACR_L3MDF                        0x07
+#define MASK_ACR_L3MDF_0_PPM                  0x00
+#define MASK_ACR_L3MDF_61_PPM                 0x01
+#define MASK_ACR_L3MDF_122_PPM                0x02
+#define MASK_ACR_L3MDF_244_PPM                0x03
+#define MASK_ACR_L3MDF_488_PPM                0x04
+#define MASK_ACR_L3MDF_976_PPM                0x05
+#define MASK_ACR_L3MDF_1976_PPM               0x06
+#define MASK_ACR_L3MDF_3906_PPM               0x07
+
+#define SDO_MODE1                             0x8652
+#define MASK_SDO_BIT_LENG                     0x70
+#define MASK_SDO_FMT                          0x03
+#define MASK_SDO_FMT_RIGHT                    0x00
+#define MASK_SDO_FMT_LEFT                     0x01
+#define MASK_SDO_FMT_I2S                      0x02
+
+#define DIV_MODE                              0x8665 /* Not in REF_01 */
+#define MASK_DIV_DLY                          0xf0
+#define SET_DIV_DLY_MS(milliseconds)         ((((milliseconds) / 100) << 4) & \
+						MASK_DIV_DLY)
+#define MASK_DIV_MODE                         0x01
+
+#define NCO_F0_MOD                            0x8670
+#define MASK_NCO_F0_MOD                       0x03
+#define MASK_NCO_F0_MOD_42MHZ                 0x00
+#define MASK_NCO_F0_MOD_27MHZ                 0x01
+
+#define PK_INT_MODE                           0x8709
+#define MASK_ISRC2_INT_MODE                   0x80
+#define MASK_ISRC_INT_MODE                    0x40
+#define MASK_ACP_INT_MODE                     0x20
+#define MASK_VS_INT_MODE                      0x10
+#define MASK_SPD_INT_MODE                     0x08
+#define MASK_MS_INT_MODE                      0x04
+#define MASK_AUD_INT_MODE                     0x02
+#define MASK_AVI_INT_MODE                     0x01
+
+#define NO_PKT_LIMIT                          0x870B
+#define MASK_NO_ACP_LIMIT                     0xf0
+#define SET_NO_ACP_LIMIT_MS(milliseconds)    ((((milliseconds) / 80) << 4) & \
+						MASK_NO_ACP_LIMIT)
+#define MASK_NO_AVI_LIMIT                     0x0f
+#define SET_NO_AVI_LIMIT_MS(milliseconds)    (((milliseconds) / 80) & \
+						MASK_NO_AVI_LIMIT)
+
+#define NO_PKT_CLR                            0x870C
+#define MASK_NO_VS_CLR                        0x40
+#define MASK_NO_SPD_CLR                       0x20
+#define MASK_NO_ACP_CLR                       0x10
+#define MASK_NO_AVI_CLR1                      0x02
+#define MASK_NO_AVI_CLR0                      0x01
+
+#define ERR_PK_LIMIT                          0x870D
+#define NO_PKT_LIMIT2                         0x870E
+#define PK_AVI_0HEAD                          0x8710
+#define PK_AVI_1HEAD                          0x8711
+#define PK_AVI_2HEAD                          0x8712
+#define PK_AVI_0BYTE                          0x8713
+#define PK_AVI_1BYTE                          0x8714
+#define PK_AVI_2BYTE                          0x8715
+#define PK_AVI_3BYTE                          0x8716
+#define PK_AVI_4BYTE                          0x8717
+#define PK_AVI_5BYTE                          0x8718
+#define PK_AVI_6BYTE                          0x8719
+#define PK_AVI_7BYTE                          0x871A
+#define PK_AVI_8BYTE                          0x871B
+#define PK_AVI_9BYTE                          0x871C
+#define PK_AVI_10BYTE                         0x871D
+#define PK_AVI_11BYTE                         0x871E
+#define PK_AVI_12BYTE                         0x871F
+#define PK_AVI_13BYTE                         0x8720
+#define PK_AVI_14BYTE                         0x8721
+#define PK_AVI_15BYTE                         0x8722
+#define PK_AVI_16BYTE                         0x8723
+
+#define BKSV                                  0x8800
+
+#define BCAPS                                 0x8840
+#define MASK_HDMI_RSVD                        0x80
+#define MASK_REPEATER                         0x40
+#define MASK_READY                            0x20
+#define MASK_FASTI2C                          0x10
+#define MASK_1_1_FEA                          0x02
+#define MASK_FAST_REAU                        0x01
+
+#define BSTATUS1                              0x8842
+#define MASK_MAX_EXCED                        0x08
+
+#define EDID_RAM                              0x8C00
+#define NO_GDB_LIMIT                          0x9007
+
+#endif

+ 0 - 8
drivers/media/i2c/tda7432.c

@@ -331,13 +331,6 @@ static const struct v4l2_ctrl_ops tda7432_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops tda7432_core_ops = {
 	.log_status = tda7432_log_status,
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
 };
 
 static const struct v4l2_subdev_ops tda7432_ops = {
@@ -416,7 +409,6 @@ MODULE_DEVICE_TABLE(i2c, tda7432_id);
 
 static struct i2c_driver tda7432_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "tda7432",
 	},
 	.probe		= tda7432_probe,

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

@@ -199,7 +199,6 @@ MODULE_DEVICE_TABLE(i2c, tda9840_id);
 
 static struct i2c_driver tda9840_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "tda9840",
 	},
 	.probe		= tda9840_probe,

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

@@ -162,7 +162,6 @@ MODULE_DEVICE_TABLE(i2c, tea6415c_id);
 
 static struct i2c_driver tea6415c_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "tea6415c",
 	},
 	.probe		= tea6415c_probe,

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

@@ -144,7 +144,6 @@ MODULE_DEVICE_TABLE(i2c, tea6420_id);
 
 static struct i2c_driver tea6420_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "tea6420",
 	},
 	.probe		= tea6420_probe,

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

@@ -377,7 +377,6 @@ MODULE_DEVICE_TABLE(i2c, ths7303_id);
 
 static struct i2c_driver ths7303_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
 		.name	= "ths73x3",
 	},
 	.probe		= ths7303_probe,

+ 0 - 7
drivers/media/i2c/tlv320aic23b.c

@@ -122,13 +122,6 @@ static const struct v4l2_ctrl_ops tlv320aic23b_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
 	.log_status = tlv320aic23b_log_status,
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
 };
 
 static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = {

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